aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorYuan Fu2022-06-14 15:59:46 -0700
committerYuan Fu2022-06-14 15:59:46 -0700
commit98bfb240818bae14cd87a1ffeb8fae7cb7846e05 (patch)
tree16e8ab06875ed54e110cf98ccdbd7e78f15905c6 /src
parent184d212042ffa5a4f02c92085d9b6e8346d66e99 (diff)
parent787c4ad8b0776280305a220d6669c956d9ed8a5d (diff)
downloademacs-98bfb240818bae14cd87a1ffeb8fae7cb7846e05.tar.gz
emacs-98bfb240818bae14cd87a1ffeb8fae7cb7846e05.zip
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)
1036 return; 1036 return;
1037 1037
1038 MALLOC_BLOCK_INPUT; 1038 MALLOC_BLOCK_INPUT;
1039#ifndef GC_MALLOC_CHECK
1040 struct mem_node *m = mem_find (block);
1041#endif
1039 free (block); 1042 free (block);
1040#ifndef GC_MALLOC_CHECK 1043#ifndef GC_MALLOC_CHECK
1041 mem_delete (mem_find (block)); 1044 mem_delete (m);
1042#endif 1045#endif
1043 MALLOC_UNBLOCK_INPUT; 1046 MALLOC_UNBLOCK_INPUT;
1044} 1047}
@@ -6197,6 +6200,7 @@ garbage_collect (void)
6197 6200
6198 mark_pinned_objects (); 6201 mark_pinned_objects ();
6199 mark_pinned_symbols (); 6202 mark_pinned_symbols ();
6203 mark_lread ();
6200 mark_terminals (); 6204 mark_terminals ();
6201 mark_kboards (); 6205 mark_kboards ();
6202 mark_threads (); 6206 mark_threads ();
@@ -6319,7 +6323,7 @@ where each entry has the form (NAME SIZE USED FREE), where:
6319 to return them to the OS). 6323 to return them to the OS).
6320 6324
6321However, if there was overflow in pure space, and Emacs was dumped 6325However, if there was overflow in pure space, and Emacs was dumped
6322using the 'unexec' method, `garbage-collect' returns nil, because 6326using the \"unexec\" method, `garbage-collect' returns nil, because
6323real GC can't be done. 6327real GC can't be done.
6324 6328
6325Note that calling this function does not guarantee that absolutely all 6329Note 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/>. */
18 18
19#include <config.h> 19#include <config.h>
20 20
21#ifdef WINDOWSNT
22#define raise(s) w32_raise(s)
23#endif
24
21#include "lisp.h" 25#include "lisp.h"
22#include "keyboard.h" 26#include "keyboard.h"
23#include "syssignal.h" 27#include "syssignal.h"
@@ -297,11 +301,6 @@ set_alarm (void)
297{ 301{
298 if (atimers) 302 if (atimers)
299 { 303 {
300#ifdef HAVE_SETITIMER
301 struct itimerval it;
302#endif
303 struct timespec now, interval;
304
305#ifdef HAVE_ITIMERSPEC 304#ifdef HAVE_ITIMERSPEC
306 if (0 <= timerfd || alarm_timer_ok) 305 if (0 <= timerfd || alarm_timer_ok)
307 { 306 {
@@ -337,20 +336,24 @@ set_alarm (void)
337 } 336 }
338#endif 337#endif
339 338
340 /* Determine interval till the next timer is ripe. 339 /* Determine interval till the next timer is ripe. */
341 Don't set the interval to 0; this disables the timer. */ 340 struct timespec now = current_timespec ();
342 now = current_timespec (); 341 if (timespec_cmp (atimers->expiration, now) <= 0)
343 interval = (timespec_cmp (atimers->expiration, now) <= 0 342 {
344 ? make_timespec (0, 1000 * 1000) 343 /* Timer is (over)due -- just trigger the signal right way. */
345 : timespec_sub (atimers->expiration, now)); 344 raise (SIGALRM);
345 }
346 else
347 {
348 struct timespec interval = timespec_sub (atimers->expiration, now);
346 349
347#ifdef HAVE_SETITIMER 350#ifdef HAVE_SETITIMER
348 351 struct itimerval it = {.it_value = make_timeval (interval)};
349 memset (&it, 0, sizeof it); 352 setitimer (ITIMER_REAL, &it, 0);
350 it.it_value = make_timeval (interval); 353#else
351 setitimer (ITIMER_REAL, &it, 0); 354 alarm (max (interval.tv_sec, 1));
352#endif /* not HAVE_SETITIMER */ 355#endif
353 alarm (max (interval.tv_sec, 1)); 356 }
354 } 357 }
355} 358}
356 359
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. */)
1218{ 1218{
1219 register Lisp_Object result = buffer_local_value (variable, buffer); 1219 register Lisp_Object result = buffer_local_value (variable, buffer);
1220 1220
1221 if (EQ (result, Qunbound)) 1221 if (BASE_EQ (result, Qunbound))
1222 xsignal1 (Qvoid_variable, variable); 1222 xsignal1 (Qvoid_variable, variable);
1223 1223
1224 return result; 1224 return result;
@@ -1313,7 +1313,7 @@ buffer_lisp_local_variables (struct buffer *buf, bool clone)
1313 if (buf != current_buffer) 1313 if (buf != current_buffer)
1314 val = XCDR (elt); 1314 val = XCDR (elt);
1315 1315
1316 result = Fcons (!clone && EQ (val, Qunbound) 1316 result = Fcons (!clone && BASE_EQ (val, Qunbound)
1317 ? XCAR (elt) 1317 ? XCAR (elt)
1318 : Fcons (XCAR (elt), val), 1318 : Fcons (XCAR (elt), val),
1319 result); 1319 result);
@@ -1336,7 +1336,7 @@ buffer_local_variables_1 (struct buffer *buf, int offset, Lisp_Object sym)
1336 { 1336 {
1337 sym = NILP (sym) ? PER_BUFFER_SYMBOL (offset) : sym; 1337 sym = NILP (sym) ? PER_BUFFER_SYMBOL (offset) : sym;
1338 Lisp_Object val = per_buffer_value (buf, offset); 1338 Lisp_Object val = per_buffer_value (buf, offset);
1339 return EQ (val, Qunbound) ? sym : Fcons (sym, val); 1339 return BASE_EQ (val, Qunbound) ? sym : Fcons (sym, val);
1340 } 1340 }
1341 return Qnil; 1341 return Qnil;
1342} 1342}
@@ -1376,12 +1376,23 @@ No argument or nil as argument means use current buffer as BUFFER. */)
1376 1376
1377DEFUN ("buffer-modified-p", Fbuffer_modified_p, Sbuffer_modified_p, 1377DEFUN ("buffer-modified-p", Fbuffer_modified_p, Sbuffer_modified_p,
1378 0, 1, 0, 1378 0, 1, 0,
1379 doc: /* Return t if BUFFER was modified since its file was last read or saved. 1379 doc: /* Return non-nil if BUFFER was modified since its file was last read or saved.
1380No argument or nil as argument means use current buffer as BUFFER. */) 1380No argument or nil as argument means use current buffer as BUFFER.
1381
1382If BUFFER was autosaved since it was last modified, this function
1383returns the symbol `autosaved'. */)
1381 (Lisp_Object buffer) 1384 (Lisp_Object buffer)
1382{ 1385{
1383 struct buffer *buf = decode_buffer (buffer); 1386 struct buffer *buf = decode_buffer (buffer);
1384 return BUF_SAVE_MODIFF (buf) < BUF_MODIFF (buf) ? Qt : Qnil; 1387 if (BUF_SAVE_MODIFF (buf) < BUF_MODIFF (buf))
1388 {
1389 if (BUF_AUTOSAVE_MODIFF (buf) == BUF_MODIFF (buf))
1390 return Qautosaved;
1391 else
1392 return Qt;
1393 }
1394 else
1395 return Qnil;
1385} 1396}
1386 1397
1387DEFUN ("force-mode-line-update", Fforce_mode_line_update, 1398DEFUN ("force-mode-line-update", Fforce_mode_line_update,
@@ -1436,6 +1447,11 @@ and `buffer-file-truename' are non-nil. */)
1436DEFUN ("restore-buffer-modified-p", Frestore_buffer_modified_p, 1447DEFUN ("restore-buffer-modified-p", Frestore_buffer_modified_p,
1437 Srestore_buffer_modified_p, 1, 1, 0, 1448 Srestore_buffer_modified_p, 1, 1, 0,
1438 doc: /* Like `set-buffer-modified-p', but doesn't redisplay buffer's mode line. 1449 doc: /* Like `set-buffer-modified-p', but doesn't redisplay buffer's mode line.
1450A nil FLAG means to mark the buffer as unmodified. A non-nil FLAG
1451means mark the buffer as modified. A special value of `autosaved'
1452will mark the buffer as modified and also as autosaved since it was
1453last modified.
1454
1439This function also locks or unlocks the file visited by the buffer, 1455This function also locks or unlocks the file visited by the buffer,
1440if both `buffer-file-truename' and `buffer-file-name' are non-nil. 1456if both `buffer-file-truename' and `buffer-file-name' are non-nil.
1441 1457
@@ -1475,16 +1491,19 @@ state of the current buffer. Use with care. */)
1475 recent-auto-save-p from t to nil. 1491 recent-auto-save-p from t to nil.
1476 Vice versa, if FLAG is non-nil and SAVE_MODIFF>=auto_save_modified 1492 Vice versa, if FLAG is non-nil and SAVE_MODIFF>=auto_save_modified
1477 we risk changing recent-auto-save-p from nil to t. */ 1493 we risk changing recent-auto-save-p from nil to t. */
1478 SAVE_MODIFF = (NILP (flag) 1494 if (NILP (flag))
1479 /* FIXME: This unavoidably sets recent-auto-save-p to nil. */ 1495 /* This unavoidably sets recent-auto-save-p to nil. */
1480 ? MODIFF 1496 SAVE_MODIFF = MODIFF;
1481 /* Let's try to preserve recent-auto-save-p. */ 1497 else
1482 : SAVE_MODIFF < MODIFF ? SAVE_MODIFF 1498 {
1483 /* If SAVE_MODIFF == auto_save_modified == MODIFF, 1499 /* If SAVE_MODIFF == auto_save_modified == MODIFF, we can either
1484 we can either decrease SAVE_MODIFF and auto_save_modified 1500 decrease SAVE_MODIFF and auto_save_modified or increase
1485 or increase MODIFF. */ 1501 MODIFF. */
1486 : modiff_incr (&MODIFF)); 1502 if (SAVE_MODIFF >= MODIFF)
1487 1503 SAVE_MODIFF = modiff_incr (&MODIFF);
1504 if (EQ (flag, Qautosaved))
1505 BUF_AUTOSAVE_MODIFF (b) = MODIFF;
1506 }
1488 return flag; 1507 return flag;
1489} 1508}
1490 1509
@@ -1499,6 +1518,18 @@ use current buffer as BUFFER. */)
1499 return modiff_to_integer (BUF_MODIFF (decode_buffer (buffer))); 1518 return modiff_to_integer (BUF_MODIFF (decode_buffer (buffer)));
1500} 1519}
1501 1520
1521DEFUN ("internal--set-buffer-modified-tick",
1522 Finternal__set_buffer_modified_tick, Sinternal__set_buffer_modified_tick,
1523 1, 2, 0,
1524 doc: /* Set BUFFER's tick counter to TICK.
1525No argument or nil as argument means use current buffer as BUFFER. */)
1526 (Lisp_Object tick, Lisp_Object buffer)
1527{
1528 CHECK_FIXNUM (tick);
1529 BUF_MODIFF (decode_buffer (buffer)) = XFIXNUM (tick);
1530 return Qnil;
1531}
1532
1502DEFUN ("buffer-chars-modified-tick", Fbuffer_chars_modified_tick, 1533DEFUN ("buffer-chars-modified-tick", Fbuffer_chars_modified_tick,
1503 Sbuffer_chars_modified_tick, 0, 1, 0, 1534 Sbuffer_chars_modified_tick, 0, 1, 0,
1504 doc: /* Return BUFFER's character-change tick counter. 1535 doc: /* Return BUFFER's character-change tick counter.
@@ -1634,16 +1665,7 @@ exists, return the buffer `*scratch*' (creating it if necessary). */)
1634 if (!NILP (notsogood)) 1665 if (!NILP (notsogood))
1635 return notsogood; 1666 return notsogood;
1636 else 1667 else
1637 { 1668 return safe_call (1, Qget_scratch_buffer_create);
1638 AUTO_STRING (scratch, "*scratch*");
1639 buf = Fget_buffer (scratch);
1640 if (NILP (buf))
1641 {
1642 buf = Fget_buffer_create (scratch, Qnil);
1643 Fset_buffer_major_mode (buf);
1644 }
1645 return buf;
1646 }
1647} 1669}
1648 1670
1649/* The following function is a safe variant of Fother_buffer: It doesn't 1671/* The following function is a safe variant of Fother_buffer: It doesn't
@@ -1659,15 +1681,7 @@ other_buffer_safely (Lisp_Object buffer)
1659 if (candidate_buffer (buf, buffer)) 1681 if (candidate_buffer (buf, buffer))
1660 return buf; 1682 return buf;
1661 1683
1662 AUTO_STRING (scratch, "*scratch*"); 1684 return safe_call (1, Qget_scratch_buffer_create);
1663 buf = Fget_buffer (scratch);
1664 if (NILP (buf))
1665 {
1666 buf = Fget_buffer_create (scratch, Qnil);
1667 Fset_buffer_major_mode (buf);
1668 }
1669
1670 return buf;
1671} 1685}
1672 1686
1673DEFUN ("buffer-enable-undo", Fbuffer_enable_undo, Sbuffer_enable_undo, 1687DEFUN ("buffer-enable-undo", Fbuffer_enable_undo, Sbuffer_enable_undo,
@@ -4093,7 +4107,7 @@ buffer. */)
4093 n_end = marker_position (OVERLAY_END (overlay)); 4107 n_end = marker_position (OVERLAY_END (overlay));
4094 4108
4095 /* If the overlay has changed buffers, do a thorough redisplay. */ 4109 /* If the overlay has changed buffers, do a thorough redisplay. */
4096 if (!EQ (buffer, obuffer)) 4110 if (!BASE_EQ (buffer, obuffer))
4097 { 4111 {
4098 /* Redisplay where the overlay was. */ 4112 /* Redisplay where the overlay was. */
4099 if (ob) 4113 if (ob)
@@ -5552,6 +5566,7 @@ syms_of_buffer (void)
5552 DEFSYM (Qbefore_change_functions, "before-change-functions"); 5566 DEFSYM (Qbefore_change_functions, "before-change-functions");
5553 DEFSYM (Qafter_change_functions, "after-change-functions"); 5567 DEFSYM (Qafter_change_functions, "after-change-functions");
5554 DEFSYM (Qkill_buffer_query_functions, "kill-buffer-query-functions"); 5568 DEFSYM (Qkill_buffer_query_functions, "kill-buffer-query-functions");
5569 DEFSYM (Qget_scratch_buffer_create, "get-scratch-buffer-create");
5555 5570
5556 DEFSYM (Qvertical_scroll_bar, "vertical-scroll-bar"); 5571 DEFSYM (Qvertical_scroll_bar, "vertical-scroll-bar");
5557 Fput (Qvertical_scroll_bar, Qchoice, list4 (Qnil, Qt, Qleft, Qright)); 5572 Fput (Qvertical_scroll_bar, Qchoice, list4 (Qnil, Qt, Qleft, Qright));
@@ -5583,8 +5598,11 @@ the mode line appears at the bottom. */);
5583 &BVAR (current_buffer, header_line_format), 5598 &BVAR (current_buffer, header_line_format),
5584 Qnil, 5599 Qnil,
5585 doc: /* Analogous to `mode-line-format', but controls the header line. 5600 doc: /* Analogous to `mode-line-format', but controls the header line.
5586The header line appears, optionally, at the top of a window; 5601The header line appears, optionally, at the top of a window; the mode
5587the mode line appears at the bottom. */); 5602line appears at the bottom.
5603
5604Also see `header-line-indent-mode' if `display-line-number-mode' is
5605used. */);
5588 5606
5589 DEFVAR_PER_BUFFER ("mode-line-format", &BVAR (current_buffer, mode_line_format), 5607 DEFVAR_PER_BUFFER ("mode-line-format", &BVAR (current_buffer, mode_line_format),
5590 Qnil, 5608 Qnil,
@@ -6418,6 +6436,7 @@ will run for `clone-indirect-buffer' calls as well. */);
6418 defsubr (&Sforce_mode_line_update); 6436 defsubr (&Sforce_mode_line_update);
6419 defsubr (&Sset_buffer_modified_p); 6437 defsubr (&Sset_buffer_modified_p);
6420 defsubr (&Sbuffer_modified_tick); 6438 defsubr (&Sbuffer_modified_tick);
6439 defsubr (&Sinternal__set_buffer_modified_tick);
6421 defsubr (&Sbuffer_chars_modified_tick); 6440 defsubr (&Sbuffer_chars_modified_tick);
6422 defsubr (&Srename_buffer); 6441 defsubr (&Srename_buffer);
6423 defsubr (&Sother_buffer); 6442 defsubr (&Sother_buffer);
@@ -6452,5 +6471,7 @@ will run for `clone-indirect-buffer' calls as well. */);
6452 defsubr (&Soverlay_put); 6471 defsubr (&Soverlay_put);
6453 defsubr (&Srestore_buffer_modified_p); 6472 defsubr (&Srestore_buffer_modified_p);
6454 6473
6474 DEFSYM (Qautosaved, "autosaved");
6475
6455 Fput (intern_c_string ("erase-buffer"), Qdisabled, Qt); 6476 Fput (intern_c_string ("erase-buffer"), Qdisabled, Qt);
6456} 6477}
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,
627 Lisp_Object v1 = vectorp[op], v2; 627 Lisp_Object v1 = vectorp[op], v2;
628 if (!SYMBOLP (v1) 628 if (!SYMBOLP (v1)
629 || XSYMBOL (v1)->u.s.redirect != SYMBOL_PLAINVAL 629 || XSYMBOL (v1)->u.s.redirect != SYMBOL_PLAINVAL
630 || (v2 = SYMBOL_VAL (XSYMBOL (v1)), EQ (v2, Qunbound))) 630 || (v2 = SYMBOL_VAL (XSYMBOL (v1)), BASE_EQ (v2, Qunbound)))
631 v2 = Fsymbol_value (v1); 631 v2 = Fsymbol_value (v1);
632 PUSH (v2); 632 PUSH (v2);
633 NEXT; 633 NEXT;
@@ -694,7 +694,7 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template,
694 694
695 /* Inline the most common case. */ 695 /* Inline the most common case. */
696 if (SYMBOLP (sym) 696 if (SYMBOLP (sym)
697 && !EQ (val, Qunbound) 697 && !BASE_EQ (val, Qunbound)
698 && XSYMBOL (sym)->u.s.redirect == SYMBOL_PLAINVAL 698 && XSYMBOL (sym)->u.s.redirect == SYMBOL_PLAINVAL
699 && !SYMBOL_TRAPPED_WRITE_P (sym)) 699 && !SYMBOL_TRAPPED_WRITE_P (sym))
700 SET_SYMBOL_VAL (XSYMBOL (sym), val); 700 SET_SYMBOL_VAL (XSYMBOL (sym), val);
@@ -1209,7 +1209,7 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template,
1209 Lisp_Object v2 = POP; 1209 Lisp_Object v2 = POP;
1210 Lisp_Object v1 = TOP; 1210 Lisp_Object v1 = TOP;
1211 if (FIXNUMP (v1) && FIXNUMP (v2)) 1211 if (FIXNUMP (v1) && FIXNUMP (v2))
1212 TOP = BASE_EQ(v1, v2) ? Qt : Qnil; 1212 TOP = BASE_EQ (v1, v2) ? Qt : Qnil;
1213 else 1213 else
1214 TOP = arithcompare (v1, v2, ARITH_EQUAL); 1214 TOP = arithcompare (v1, v2, ARITH_EQUAL);
1215 NEXT; 1215 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)
170 of VALUES to do its job. */ 170 of VALUES to do its job. */
171 171
172static void 172static void
173fix_command (Lisp_Object input, Lisp_Object values) 173fix_command (Lisp_Object input, Lisp_Object function, Lisp_Object values)
174{ 174{
175 /* FIXME: Instead of this ugly hack, we should provide a way for an 175 /* FIXME: Instead of this ugly hack, we should provide a way for an
176 interactive spec to return an expression/function that will re-build the 176 interactive spec to return an expression/function that will re-build the
@@ -230,6 +230,37 @@ fix_command (Lisp_Object input, Lisp_Object values)
230 } 230 }
231 } 231 }
232 } 232 }
233
234 /* If the list contains a bunch of trailing nil values, and they are
235 optional, remove them from the list. This makes navigating the
236 history less confusing, since it doesn't contain a lot of
237 parameters that aren't used. */
238 if (CONSP (values))
239 {
240 Lisp_Object arity = Ffunc_arity (function);
241 /* We don't want to do this simplification if we have an &rest
242 function, because (cl-defun foo (a &optional (b 'zot)) ..)
243 etc. */
244 if (FIXNUMP (XCAR (arity)) && FIXNUMP (XCDR (arity)))
245 {
246 Lisp_Object final = Qnil;
247 ptrdiff_t final_i = 0, i = 0;
248 for (Lisp_Object tail = values;
249 CONSP (tail);
250 tail = XCDR (tail), ++i)
251 {
252 if (!NILP (XCAR (tail)))
253 {
254 final = tail;
255 final_i = i;
256 }
257 }
258
259 /* Chop the trailing optional values. */
260 if (final_i > 0 && final_i >= XFIXNUM (XCAR (arity)) - 1)
261 XSETCDR (final, Qnil);
262 }
263 }
233} 264}
234 265
235/* Helper function to call `read-file-name' from C. */ 266/* Helper function to call `read-file-name' from C. */
@@ -340,7 +371,7 @@ invoke it (via an `interactive' spec that contains, for instance, an
340 Make a copy of the list of values, for the command history, 371 Make a copy of the list of values, for the command history,
341 and turn them into things we can eval. */ 372 and turn them into things we can eval. */
342 Lisp_Object values = quotify_args (Fcopy_sequence (specs)); 373 Lisp_Object values = quotify_args (Fcopy_sequence (specs));
343 fix_command (input, values); 374 fix_command (input, function, values);
344 call4 (intern ("add-to-history"), intern ("command-history"), 375 call4 (intern ("add-to-history"), intern ("command-history"),
345 Fcons (function, values), Qnil, Qt); 376 Fcons (function, values), Qnil, Qt);
346 } 377 }
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/>. */
35#include "coding.h" 35#include "coding.h"
36#include "keyboard.h" 36#include "keyboard.h"
37 37
38/* Avoid GCC 12 bug <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105784>. */
39#if GNUC_PREREQ (12, 0, 0)
40# pragma GCC diagnostic ignored "-Wanalyzer-use-of-uninitialized-value"
41#endif
42
38/* Table of registered CCL programs. Each element is a vector of 43/* Table of registered CCL programs. Each element is a vector of
39 NAME, CCL_PROG, RESOLVEDP, and UPDATEDP, where NAME (symbol) is the 44 NAME, CCL_PROG, RESOLVEDP, and UPDATEDP, where NAME (symbol) is the
40 name of the program, CCL_PROG (vector) is the compiled code of the 45 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)
6528 if (EQ (CODING_ATTR_TYPE (CODING_ID_ATTRS (coding->id)), Qundecided)) 6528 if (EQ (CODING_ATTR_TYPE (CODING_ID_ATTRS (coding->id)), Qundecided))
6529 { 6529 {
6530 int c, i; 6530 int c, i;
6531 struct coding_detection_info detect_info; 6531 struct coding_detection_info detect_info = {0};
6532 bool null_byte_found = 0, eight_bit_found = 0; 6532 bool null_byte_found = 0, eight_bit_found = 0;
6533 bool inhibit_nbd = inhibit_flag (coding->spec.undecided.inhibit_nbd, 6533 bool inhibit_nbd = inhibit_flag (coding->spec.undecided.inhibit_nbd,
6534 inhibit_null_byte_detection); 6534 inhibit_null_byte_detection);
@@ -6537,7 +6537,6 @@ detect_coding (struct coding_system *coding)
6537 bool prefer_utf_8 = coding->spec.undecided.prefer_utf_8; 6537 bool prefer_utf_8 = coding->spec.undecided.prefer_utf_8;
6538 6538
6539 coding->head_ascii = 0; 6539 coding->head_ascii = 0;
6540 detect_info.checked = detect_info.found = detect_info.rejected = 0;
6541 for (src = coding->source; src < src_end; src++) 6540 for (src = coding->source; src < src_end; src++)
6542 { 6541 {
6543 c = *src; 6542 c = *src;
@@ -6712,12 +6711,8 @@ detect_coding (struct coding_system *coding)
6712 else if (XFIXNUM (CODING_ATTR_CATEGORY (CODING_ID_ATTRS (coding->id))) 6711 else if (XFIXNUM (CODING_ATTR_CATEGORY (CODING_ID_ATTRS (coding->id)))
6713 == coding_category_utf_8_auto) 6712 == coding_category_utf_8_auto)
6714 { 6713 {
6715 Lisp_Object coding_systems; 6714 Lisp_Object coding_systems
6716 struct coding_detection_info detect_info;
6717
6718 coding_systems
6719 = AREF (CODING_ID_ATTRS (coding->id), coding_attr_utf_bom); 6715 = AREF (CODING_ID_ATTRS (coding->id), coding_attr_utf_bom);
6720 detect_info.found = detect_info.rejected = 0;
6721 if (check_ascii (coding) == coding->src_bytes) 6716 if (check_ascii (coding) == coding->src_bytes)
6722 { 6717 {
6723 if (CONSP (coding_systems)) 6718 if (CONSP (coding_systems))
@@ -6725,6 +6720,7 @@ detect_coding (struct coding_system *coding)
6725 } 6720 }
6726 else 6721 else
6727 { 6722 {
6723 struct coding_detection_info detect_info = {0};
6728 if (CONSP (coding_systems) 6724 if (CONSP (coding_systems)
6729 && detect_coding_utf_8 (coding, &detect_info)) 6725 && detect_coding_utf_8 (coding, &detect_info))
6730 { 6726 {
@@ -6738,20 +6734,19 @@ detect_coding (struct coding_system *coding)
6738 else if (XFIXNUM (CODING_ATTR_CATEGORY (CODING_ID_ATTRS (coding->id))) 6734 else if (XFIXNUM (CODING_ATTR_CATEGORY (CODING_ID_ATTRS (coding->id)))
6739 == coding_category_utf_16_auto) 6735 == coding_category_utf_16_auto)
6740 { 6736 {
6741 Lisp_Object coding_systems; 6737 Lisp_Object coding_systems
6742 struct coding_detection_info detect_info;
6743
6744 coding_systems
6745 = AREF (CODING_ID_ATTRS (coding->id), coding_attr_utf_bom); 6738 = AREF (CODING_ID_ATTRS (coding->id), coding_attr_utf_bom);
6746 detect_info.found = detect_info.rejected = 0;
6747 coding->head_ascii = 0; 6739 coding->head_ascii = 0;
6748 if (CONSP (coding_systems) 6740 if (CONSP (coding_systems))
6749 && detect_coding_utf_16 (coding, &detect_info))
6750 { 6741 {
6751 if (detect_info.found & CATEGORY_MASK_UTF_16_LE) 6742 struct coding_detection_info detect_info = {0};
6752 found = XCAR (coding_systems); 6743 if (detect_coding_utf_16 (coding, &detect_info))
6753 else if (detect_info.found & CATEGORY_MASK_UTF_16_BE) 6744 {
6754 found = XCDR (coding_systems); 6745 if (detect_info.found & CATEGORY_MASK_UTF_16_LE)
6746 found = XCAR (coding_systems);
6747 else if (detect_info.found & CATEGORY_MASK_UTF_16_BE)
6748 found = XCDR (coding_systems);
6749 }
6755 } 6750 }
6756 } 6751 }
6757 6752
@@ -8639,7 +8634,7 @@ detect_coding_system (const unsigned char *src,
8639 Lisp_Object val = Qnil; 8634 Lisp_Object val = Qnil;
8640 struct coding_system coding; 8635 struct coding_system coding;
8641 ptrdiff_t id; 8636 ptrdiff_t id;
8642 struct coding_detection_info detect_info; 8637 struct coding_detection_info detect_info = {0};
8643 enum coding_category base_category; 8638 enum coding_category base_category;
8644 bool null_byte_found = 0, eight_bit_found = 0; 8639 bool null_byte_found = 0, eight_bit_found = 0;
8645 8640
@@ -8658,8 +8653,6 @@ detect_coding_system (const unsigned char *src,
8658 coding.mode |= CODING_MODE_LAST_BLOCK; 8653 coding.mode |= CODING_MODE_LAST_BLOCK;
8659 coding.head_ascii = 0; 8654 coding.head_ascii = 0;
8660 8655
8661 detect_info.checked = detect_info.found = detect_info.rejected = 0;
8662
8663 /* At first, detect text-format if necessary. */ 8656 /* At first, detect text-format if necessary. */
8664 base_category = XFIXNUM (CODING_ATTR_CATEGORY (attrs)); 8657 base_category = XFIXNUM (CODING_ATTR_CATEGORY (attrs));
8665 if (base_category == coding_category_undecided) 8658 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)
756 756
757DEFUN ("comp--subr-signature", Fcomp__subr_signature, 757DEFUN ("comp--subr-signature", Fcomp__subr_signature,
758 Scomp__subr_signature, 1, 1, 0, 758 Scomp__subr_signature, 1, 1, 0,
759 doc: /* Support function to 'hash_native_abi'. 759 doc: /* Support function to hash_native_abi.
760For internal use. */) 760For internal use. */)
761 (Lisp_Object subr) 761 (Lisp_Object subr)
762{ 762{
763 return concat2 (Fsubr_name (subr), 763 return concat2 (Fsubr_name (subr),
764 Fprin1_to_string (Fsubr_arity (subr), Qnil)); 764 Fprin1_to_string (Fsubr_arity (subr), Qnil, Qnil));
765} 765}
766 766
767/* Produce a key hashing Vcomp_subr_list. */ 767/* Produce a key hashing Vcomp_subr_list. */
@@ -1707,7 +1707,7 @@ static gcc_jit_lvalue *
1707emit_lisp_obj_reloc_lval (Lisp_Object obj) 1707emit_lisp_obj_reloc_lval (Lisp_Object obj)
1708{ 1708{
1709 emit_comment (format_string ("l-value for lisp obj: %s", 1709 emit_comment (format_string ("l-value for lisp obj: %s",
1710 SSDATA (Fprin1_to_string (obj, Qnil)))); 1710 SSDATA (Fprin1_to_string (obj, Qnil, Qnil))));
1711 1711
1712 imm_reloc_t reloc = obj_to_reloc (obj); 1712 imm_reloc_t reloc = obj_to_reloc (obj);
1713 return gcc_jit_context_new_array_access (comp.ctxt, 1713 return gcc_jit_context_new_array_access (comp.ctxt,
@@ -1720,7 +1720,7 @@ static gcc_jit_rvalue *
1720emit_lisp_obj_rval (Lisp_Object obj) 1720emit_lisp_obj_rval (Lisp_Object obj)
1721{ 1721{
1722 emit_comment (format_string ("const lisp obj: %s", 1722 emit_comment (format_string ("const lisp obj: %s",
1723 SSDATA (Fprin1_to_string (obj, Qnil)))); 1723 SSDATA (Fprin1_to_string (obj, Qnil, Qnil))));
1724 1724
1725 if (NILP (obj)) 1725 if (NILP (obj))
1726 { 1726 {
@@ -1968,7 +1968,7 @@ emit_mvar_rval (Lisp_Object mvar)
1968 SSDATA ( 1968 SSDATA (
1969 Fprin1_to_string ( 1969 Fprin1_to_string (
1970 NILP (func) ? value : CALL1I (comp-func-c-name, func), 1970 NILP (func) ? value : CALL1I (comp-func-c-name, func),
1971 Qnil))); 1971 Qnil, Qnil)));
1972 } 1972 }
1973 if (FIXNUMP (value)) 1973 if (FIXNUMP (value))
1974 { 1974 {
@@ -2471,7 +2471,7 @@ emit_limple_insn (Lisp_Object insn)
2471 else if (EQ (op, Qsetimm)) 2471 else if (EQ (op, Qsetimm))
2472 { 2472 {
2473 /* Ex: (setimm #s(comp-mvar 9 1 t 3 nil) a). */ 2473 /* Ex: (setimm #s(comp-mvar 9 1 t 3 nil) a). */
2474 emit_comment (SSDATA (Fprin1_to_string (arg[1], Qnil))); 2474 emit_comment (SSDATA (Fprin1_to_string (arg[1], Qnil, Qnil)));
2475 imm_reloc_t reloc = obj_to_reloc (arg[1]); 2475 imm_reloc_t reloc = obj_to_reloc (arg[1]);
2476 emit_frame_assignment ( 2476 emit_frame_assignment (
2477 arg[0], 2477 arg[0],
@@ -2647,7 +2647,7 @@ emit_static_object (const char *name, Lisp_Object obj)
2647 specbind (intern_c_string ("print-quoted"), Qt); 2647 specbind (intern_c_string ("print-quoted"), Qt);
2648 specbind (intern_c_string ("print-gensym"), Qt); 2648 specbind (intern_c_string ("print-gensym"), Qt);
2649 specbind (intern_c_string ("print-circle"), Qt); 2649 specbind (intern_c_string ("print-circle"), Qt);
2650 Lisp_Object str = Fprin1_to_string (obj, Qnil); 2650 Lisp_Object str = Fprin1_to_string (obj, Qnil, Qnil);
2651 unbind_to (count, Qnil); 2651 unbind_to (count, Qnil);
2652 2652
2653 ptrdiff_t len = SBYTES (str); 2653 ptrdiff_t len = SBYTES (str);
@@ -4262,7 +4262,7 @@ compile_function (Lisp_Object func)
4262 { 4262 {
4263 Lisp_Object block_name = HASH_KEY (ht, i); 4263 Lisp_Object block_name = HASH_KEY (ht, i);
4264 if (!EQ (block_name, Qentry) 4264 if (!EQ (block_name, Qentry)
4265 && !EQ (block_name, Qunbound)) 4265 && !BASE_EQ (block_name, Qunbound))
4266 declare_block (block_name); 4266 declare_block (block_name);
4267 } 4267 }
4268 4268
@@ -4275,7 +4275,7 @@ compile_function (Lisp_Object func)
4275 for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (ht); i++) 4275 for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (ht); i++)
4276 { 4276 {
4277 Lisp_Object block_name = HASH_KEY (ht, i); 4277 Lisp_Object block_name = HASH_KEY (ht, i);
4278 if (!EQ (block_name, Qunbound)) 4278 if (!BASE_EQ (block_name, Qunbound))
4279 { 4279 {
4280 Lisp_Object block = HASH_VALUE (ht, i); 4280 Lisp_Object block = HASH_VALUE (ht, i);
4281 Lisp_Object insns = CALL1I (comp-block-insns, block); 4281 Lisp_Object insns = CALL1I (comp-block-insns, block);
@@ -4890,12 +4890,12 @@ DEFUN ("comp--compile-ctxt-to-file", Fcomp__compile_ctxt_to_file,
4890 struct Lisp_Hash_Table *func_h = 4890 struct Lisp_Hash_Table *func_h =
4891 XHASH_TABLE (CALL1I (comp-ctxt-funcs-h, Vcomp_ctxt)); 4891 XHASH_TABLE (CALL1I (comp-ctxt-funcs-h, Vcomp_ctxt));
4892 for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (func_h); i++) 4892 for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (func_h); i++)
4893 if (!EQ (HASH_VALUE (func_h, i), Qunbound)) 4893 if (!BASE_EQ (HASH_VALUE (func_h, i), Qunbound))
4894 declare_function (HASH_VALUE (func_h, i)); 4894 declare_function (HASH_VALUE (func_h, i));
4895 /* Compile all functions. Can't be done before because the 4895 /* Compile all functions. Can't be done before because the
4896 relocation structs has to be already defined. */ 4896 relocation structs has to be already defined. */
4897 for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (func_h); i++) 4897 for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (func_h); i++)
4898 if (!EQ (HASH_VALUE (func_h, i), Qunbound)) 4898 if (!BASE_EQ (HASH_VALUE (func_h, i), Qunbound))
4899 compile_function (HASH_VALUE (func_h, i)); 4899 compile_function (HASH_VALUE (func_h, i));
4900 4900
4901 /* Work around bug#46495 (GCC PR99126). */ 4901 /* Work around bug#46495 (GCC PR99126). */
@@ -5342,7 +5342,7 @@ load_comp_unit (struct Lisp_Native_Comp_Unit *comp_u, bool loading_dump,
5342 are necessary exclusively during the first load. Once these 5342 are necessary exclusively during the first load. Once these
5343 are collected we don't have to maintain them in the heap 5343 are collected we don't have to maintain them in the heap
5344 forever. */ 5344 forever. */
5345 Lisp_Object volatile data_ephemeral_vec; 5345 Lisp_Object volatile data_ephemeral_vec = Qnil;
5346 /* In case another load of the same CU is active on the stack 5346 /* In case another load of the same CU is active on the stack
5347 all ephemeral data is hold by that frame. Re-writing 5347 all ephemeral data is hold by that frame. Re-writing
5348 'data_ephemeral_vec' would be not only a waste of cycles but 5348 '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)
688 { 688 {
689 Lisp_Object k = HASH_KEY (h, i); 689 Lisp_Object k = HASH_KEY (h, i);
690 690
691 if (!EQ (k, Qunbound)) 691 if (!BASE_EQ (k, Qunbound))
692 { 692 {
693 Lisp_Object gstring = HASH_VALUE (h, i); 693 Lisp_Object gstring = HASH_VALUE (h, i);
694 694
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. */)
705 default: emacs_abort (); 705 default: emacs_abort ();
706 } 706 }
707 707
708 return (EQ (valcontents, Qunbound) ? Qnil : Qt); 708 return (BASE_EQ (valcontents, Qunbound) ? Qnil : Qt);
709} 709}
710 710
711/* It has been previously suggested to make this function an alias for 711/* It has been previously suggested to make this function an alias for
@@ -1591,7 +1591,7 @@ global value outside of any lexical scope. */)
1591 Lisp_Object val; 1591 Lisp_Object val;
1592 1592
1593 val = find_symbol_value (symbol); 1593 val = find_symbol_value (symbol);
1594 if (!EQ (val, Qunbound)) 1594 if (!BASE_EQ (val, Qunbound))
1595 return val; 1595 return val;
1596 1596
1597 xsignal1 (Qvoid_variable, symbol); 1597 xsignal1 (Qvoid_variable, symbol);
@@ -1618,7 +1618,7 @@ void
1618set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where, 1618set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where,
1619 enum Set_Internal_Bind bindflag) 1619 enum Set_Internal_Bind bindflag)
1620{ 1620{
1621 bool voide = EQ (newval, Qunbound); 1621 bool voide = BASE_EQ (newval, Qunbound);
1622 1622
1623 /* If restoring in a dead buffer, do nothing. */ 1623 /* If restoring in a dead buffer, do nothing. */
1624 /* if (BUFFERP (where) && NILP (XBUFFER (where)->name)) 1624 /* if (BUFFERP (where) && NILP (XBUFFER (where)->name))
@@ -1945,15 +1945,15 @@ default_value (Lisp_Object symbol)
1945 1945
1946DEFUN ("default-boundp", Fdefault_boundp, Sdefault_boundp, 1, 1, 0, 1946DEFUN ("default-boundp", Fdefault_boundp, Sdefault_boundp, 1, 1, 0,
1947 doc: /* Return t if SYMBOL has a non-void default value. 1947 doc: /* Return t if SYMBOL has a non-void default value.
1948A variable may have a buffer-local or a `let'-bound local value. This 1948A variable may have a buffer-local value. This function says whether
1949function says whether the variable has a non-void value outside of the 1949the variable has a non-void value outside of the current buffer
1950current context. Also see `default-value'. */) 1950context. Also see `default-value'. */)
1951 (Lisp_Object symbol) 1951 (Lisp_Object symbol)
1952{ 1952{
1953 register Lisp_Object value; 1953 register Lisp_Object value;
1954 1954
1955 value = default_value (symbol); 1955 value = default_value (symbol);
1956 return (EQ (value, Qunbound) ? Qnil : Qt); 1956 return (BASE_EQ (value, Qunbound) ? Qnil : Qt);
1957} 1957}
1958 1958
1959DEFUN ("default-value", Fdefault_value, Sdefault_value, 1, 1, 0, 1959DEFUN ("default-value", Fdefault_value, Sdefault_value, 1, 1, 0,
@@ -1964,7 +1964,7 @@ local bindings in certain buffers. */)
1964 (Lisp_Object symbol) 1964 (Lisp_Object symbol)
1965{ 1965{
1966 Lisp_Object value = default_value (symbol); 1966 Lisp_Object value = default_value (symbol);
1967 if (!EQ (value, Qunbound)) 1967 if (!BASE_EQ (value, Qunbound))
1968 return value; 1968 return value;
1969 1969
1970 xsignal1 (Qvoid_variable, symbol); 1970 xsignal1 (Qvoid_variable, symbol);
@@ -2144,7 +2144,7 @@ See also `defvar-local'. */)
2144 case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start; 2144 case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start;
2145 case SYMBOL_PLAINVAL: 2145 case SYMBOL_PLAINVAL:
2146 forwarded = 0; valcontents.value = SYMBOL_VAL (sym); 2146 forwarded = 0; valcontents.value = SYMBOL_VAL (sym);
2147 if (EQ (valcontents.value, Qunbound)) 2147 if (BASE_EQ (valcontents.value, Qunbound))
2148 valcontents.value = Qnil; 2148 valcontents.value = Qnil;
2149 break; 2149 break;
2150 case SYMBOL_LOCALIZED: 2150 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)
1690 value = Fgethash (key, Vdbus_registered_objects_table, Qnil); 1690 value = Fgethash (key, Vdbus_registered_objects_table, Qnil);
1691 1691
1692 /* Loop over the registered functions. Construct an event. */ 1692 /* Loop over the registered functions. Construct an event. */
1693 while (!NILP (value)) 1693 for (; !NILP (value); value = CDR_SAFE (value))
1694 { 1694 {
1695 key = CAR_SAFE (value); 1695 key = CAR_SAFE (value);
1696 Lisp_Object key_uname = CAR_SAFE (key);
1696 /* key has the structure (UNAME SERVICE PATH HANDLER). */ 1697 /* key has the structure (UNAME SERVICE PATH HANDLER). */
1697 if (((uname == NULL) 1698 if (uname && !NILP (key_uname)
1698 || (NILP (CAR_SAFE (key))) 1699 && strcmp (uname, SSDATA (key_uname)) != 0)
1699 || (strcmp (uname, SSDATA (CAR_SAFE (key))) == 0)) 1700 continue;
1700 && ((path == NULL) 1701 Lisp_Object key_service_etc = CDR_SAFE (key);
1701 || (NILP (CAR_SAFE (CDR_SAFE (CDR_SAFE (key))))) 1702 Lisp_Object key_path_etc = CDR_SAFE (key_service_etc);
1702 || (strcmp (path, 1703 Lisp_Object key_path = CAR_SAFE (key_path_etc);
1703 SSDATA (CAR_SAFE (CDR_SAFE (CDR_SAFE (key))))) 1704 if (path && !NILP (key_path)
1704 == 0)) 1705 && strcmp (path, SSDATA (key_path)) != 0)
1705 && (!NILP (CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (key))))))) 1706 continue;
1706 { 1707 Lisp_Object handler = CAR_SAFE (CDR_SAFE (key_path_etc));
1707 EVENT_INIT (event); 1708 if (NILP (handler))
1708 event.kind = DBUS_EVENT; 1709 continue;
1709 event.frame_or_window = Qnil; 1710
1710 /* Handler. */ 1711 /* Construct an event and exit the loop. */
1711 event.arg 1712 EVENT_INIT (event);
1712 = Fcons (CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (key)))), args); 1713 event.kind = DBUS_EVENT;
1713 break; 1714 event.frame_or_window = Qnil;
1714 } 1715 event.arg = Fcons (handler, args);
1715 value = CDR_SAFE (value); 1716 break;
1716 } 1717 }
1717 1718
1718 if (NILP (value)) 1719 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
1075 right-to-left paragraph. */ 1075 right-to-left paragraph. */
1076 bool_bf reversed_p : 1; 1076 bool_bf reversed_p : 1;
1077 1077
1078 /* Whether or not a stipple was drawn in this row at some point. */
1079 bool_bf stipple_p : 1;
1080
1078 /* Continuation lines width at the start of the row. */ 1081 /* Continuation lines width at the start of the row. */
1079 int continuation_lines_width; 1082 int continuation_lines_width;
1080 1083
@@ -3467,6 +3470,7 @@ extern void expose_frame (struct frame *, int, int, int, int);
3467extern bool gui_intersect_rectangles (const Emacs_Rectangle *, 3470extern bool gui_intersect_rectangles (const Emacs_Rectangle *,
3468 const Emacs_Rectangle *, 3471 const Emacs_Rectangle *,
3469 Emacs_Rectangle *); 3472 Emacs_Rectangle *);
3473extern void gui_consider_frame_title (Lisp_Object);
3470#endif /* HAVE_WINDOW_SYSTEM */ 3474#endif /* HAVE_WINDOW_SYSTEM */
3471 3475
3472extern void note_mouse_highlight (struct frame *, int, int); 3476extern void note_mouse_highlight (struct frame *, int, int);
@@ -3612,6 +3616,9 @@ void gamma_correct (struct frame *, XColor *);
3612#ifdef HAVE_NTGUI 3616#ifdef HAVE_NTGUI
3613void gamma_correct (struct frame *, COLORREF *); 3617void gamma_correct (struct frame *, COLORREF *);
3614#endif 3618#endif
3619#ifdef HAVE_HAIKU
3620void gamma_correct (struct frame *, Emacs_Color *);
3621#endif
3615 3622
3616#ifdef HAVE_WINDOW_SYSTEM 3623#ifdef HAVE_WINDOW_SYSTEM
3617 3624
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)
1837 if (FRAME_WINDOW_P (f)) 1837 if (FRAME_WINDOW_P (f))
1838 adjust_frame_glyphs_for_window_redisplay (f); 1838 adjust_frame_glyphs_for_window_redisplay (f);
1839 else 1839 else
1840 adjust_frame_glyphs_for_frame_redisplay (f); 1840 {
1841 adjust_frame_glyphs_for_frame_redisplay (f);
1842 eassert (FRAME_INITIAL_P (f)
1843 || noninteractive
1844 || !initialized
1845 || (f->current_matrix
1846 && f->current_matrix->nrows > 0
1847 && f->current_matrix->rows
1848 && f->desired_matrix
1849 && f->desired_matrix->nrows > 0
1850 && f->desired_matrix->rows));
1851 }
1841 1852
1842 /* Don't forget the buffer for decode_mode_spec. */ 1853 /* Don't forget the buffer for decode_mode_spec. */
1843 adjust_decode_mode_spec_buffer (f); 1854 adjust_decode_mode_spec_buffer (f);
@@ -2119,6 +2130,19 @@ adjust_frame_glyphs_for_frame_redisplay (struct frame *f)
2119 SET_FRAME_GARBAGED (f); 2130 SET_FRAME_GARBAGED (f);
2120 } 2131 }
2121 } 2132 }
2133 else if (!FRAME_INITIAL_P (f) && !noninteractive && initialized)
2134 {
2135 if (!f->desired_matrix->nrows || !f->desired_matrix->rows)
2136 {
2137 adjust_glyph_matrix (NULL, f->desired_matrix, 0, 0, matrix_dim);
2138 SET_FRAME_GARBAGED (f);
2139 }
2140 if (!f->current_matrix->nrows || !f->current_matrix->rows)
2141 {
2142 adjust_glyph_matrix (NULL, f->current_matrix, 0, 0, matrix_dim);
2143 SET_FRAME_GARBAGED (f);
2144 }
2145 }
2122} 2146}
2123 2147
2124 2148
@@ -3907,7 +3931,8 @@ update_marginal_area (struct window *w, struct glyph_row *updated_row,
3907 Value is true if display has changed. */ 3931 Value is true if display has changed. */
3908 3932
3909static bool 3933static bool
3910update_text_area (struct window *w, struct glyph_row *updated_row, int vpos) 3934update_text_area (struct window *w, struct glyph_row *updated_row, int vpos,
3935 bool *partial_p)
3911{ 3936{
3912 struct glyph_row *current_row = MATRIX_ROW (w->current_matrix, vpos); 3937 struct glyph_row *current_row = MATRIX_ROW (w->current_matrix, vpos);
3913 struct glyph_row *desired_row = MATRIX_ROW (w->desired_matrix, vpos); 3938 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)
4013 { 4038 {
4014 x += desired_glyph->pixel_width; 4039 x += desired_glyph->pixel_width;
4015 ++desired_glyph, ++current_glyph, ++i; 4040 ++desired_glyph, ++current_glyph, ++i;
4041
4042 /* Say that only a partial update was performed of
4043 the current row (i.e. not all the glyphs were
4044 drawn). This is used to preserve the stipple_p
4045 flag of the current row inside
4046 update_window_line. */
4047 *partial_p = true;
4016 } 4048 }
4017 4049
4018 /* Consider the case that the current row contains "xxx 4050 /* 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)
4084 rif->write_glyphs (w, updated_row, start, 4116 rif->write_glyphs (w, updated_row, start,
4085 TEXT_AREA, i - start_hpos); 4117 TEXT_AREA, i - start_hpos);
4086 changed_p = 1; 4118 changed_p = 1;
4119 *partial_p = true;
4087 } 4120 }
4088 } 4121 }
4089 4122
4123 /* This means we will draw from the start, so no partial update
4124 is being performed. */
4125 if (!i)
4126 *partial_p = false;
4127
4090 /* Write the rest. */ 4128 /* Write the rest. */
4091 if (i < desired_row->used[TEXT_AREA]) 4129 if (i < desired_row->used[TEXT_AREA])
4092 { 4130 {
@@ -4159,7 +4197,9 @@ update_window_line (struct window *w, int vpos, bool *mouse_face_overwritten_p)
4159 struct glyph_row *current_row = MATRIX_ROW (w->current_matrix, vpos); 4197 struct glyph_row *current_row = MATRIX_ROW (w->current_matrix, vpos);
4160 struct glyph_row *desired_row = MATRIX_ROW (w->desired_matrix, vpos); 4198 struct glyph_row *desired_row = MATRIX_ROW (w->desired_matrix, vpos);
4161 struct redisplay_interface *rif = FRAME_RIF (XFRAME (WINDOW_FRAME (w))); 4199 struct redisplay_interface *rif = FRAME_RIF (XFRAME (WINDOW_FRAME (w)));
4162 bool changed_p = 0; 4200
4201 /* partial_p is true if not all of desired_row was drawn. */
4202 bool changed_p = 0, partial_p = 0, was_stipple;
4163 4203
4164 /* A row can be completely invisible in case a desired matrix was 4204 /* A row can be completely invisible in case a desired matrix was
4165 built with a vscroll and then make_cursor_line_fully_visible shifts 4205 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)
4183 } 4223 }
4184 4224
4185 /* Update the display of the text area. */ 4225 /* Update the display of the text area. */
4186 if (update_text_area (w, desired_row, vpos)) 4226 if (update_text_area (w, desired_row, vpos, &partial_p))
4187 { 4227 {
4188 changed_p = 1; 4228 changed_p = 1;
4189 if (current_row->mouse_face_p) 4229 if (current_row->mouse_face_p)
@@ -4212,7 +4252,17 @@ update_window_line (struct window *w, int vpos, bool *mouse_face_overwritten_p)
4212 } 4252 }
4213 4253
4214 /* Update current_row from desired_row. */ 4254 /* Update current_row from desired_row. */
4255 was_stipple = current_row->stipple_p;
4215 make_current (w->desired_matrix, w->current_matrix, vpos); 4256 make_current (w->desired_matrix, w->current_matrix, vpos);
4257
4258 /* If only a partial update was performed, any stipple already
4259 displayed in MATRIX_ROW (w->current_matrix, vpos) might still be
4260 there, so don't hurry to clear that flag if it's not in
4261 desired_row. */
4262
4263 if (partial_p && was_stipple)
4264 current_row->stipple_p = true;
4265
4216 return changed_p; 4266 return changed_p;
4217} 4267}
4218 4268
@@ -4392,7 +4442,6 @@ add_row_entry (struct glyph_row *row)
4392 return entry; 4442 return entry;
4393} 4443}
4394 4444
4395
4396/* Try to reuse part of the current display of W by scrolling lines. 4445/* Try to reuse part of the current display of W by scrolling lines.
4397 HEADER_LINE_P means W has a header line. 4446 HEADER_LINE_P means W has a header line.
4398 4447
@@ -4438,6 +4487,14 @@ scrolling_window (struct window *w, int tab_line_p)
4438 struct glyph_row *d = MATRIX_ROW (desired_matrix, i); 4487 struct glyph_row *d = MATRIX_ROW (desired_matrix, i);
4439 struct glyph_row *c = MATRIX_ROW (current_matrix, i); 4488 struct glyph_row *c = MATRIX_ROW (current_matrix, i);
4440 4489
4490 /* If there is a row with a stipple currently on the glass, give
4491 up. Stipples look different depending on where on the
4492 display they are drawn, so scrolling the display will produce
4493 incorrect results. */
4494
4495 if (c->stipple_p)
4496 return 0;
4497
4441 if (c->enabled_p 4498 if (c->enabled_p
4442 && d->enabled_p 4499 && d->enabled_p
4443 && !d->redraw_fringe_bitmaps_p 4500 && !d->redraw_fringe_bitmaps_p
@@ -4467,6 +4524,16 @@ scrolling_window (struct window *w, int tab_line_p)
4467 4524
4468 first_old = first_new = i; 4525 first_old = first_new = i;
4469 4526
4527 while (i < current_matrix->nrows - 1)
4528 {
4529 /* If there is a stipple after the first change, give up as
4530 well. */
4531 if (MATRIX_ROW (current_matrix, i)->stipple_p)
4532 return 0;
4533
4534 ++i;
4535 }
4536
4470 /* Set last_new to the index + 1 of the row that reaches the 4537 /* Set last_new to the index + 1 of the row that reaches the
4471 bottom boundary in the desired matrix. Give up if we find a 4538 bottom boundary in the desired matrix. Give up if we find a
4472 disabled row before we reach the bottom boundary. */ 4539 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'. */)
569 if (p) 569 if (p)
570 { 570 {
571 end = strchr (p, '\n'); 571 end = strchr (p, '\n');
572 if (!end)
573 error ("DOC file invalid at position %"pI"d", pos);
572 574
573 /* We used to skip files not in build_files, so that when a 575 /* We used to skip files not in build_files, so that when a
574 function was defined several times in different files 576 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)
3327 if (EQ (arg, args[n])) 3327 if (EQ (arg, args[n]))
3328 { 3328 {
3329 Lisp_Object noescape = conversion == 'S' ? Qnil : Qt; 3329 Lisp_Object noescape = conversion == 'S' ? Qnil : Qt;
3330 spec->argument = arg = Fprin1_to_string (arg, noescape); 3330 spec->argument = arg = Fprin1_to_string (arg, noescape, Qnil);
3331 if (STRING_MULTIBYTE (arg) && ! multibyte) 3331 if (STRING_MULTIBYTE (arg) && ! multibyte)
3332 { 3332 {
3333 multibyte = true; 3333 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)
411 reference that's identical to some global reference. */ 411 reference that's identical to some global reference. */
412 for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i) 412 for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i)
413 { 413 {
414 if (!EQ (HASH_KEY (h, i), Qunbound) 414 if (!BASE_EQ (HASH_KEY (h, i), Qunbound)
415 && &XMODULE_GLOBAL_REFERENCE (HASH_VALUE (h, i))->value == v) 415 && &XMODULE_GLOBAL_REFERENCE (HASH_VALUE (h, i))->value == v)
416 return true; 416 return true;
417 } 417 }
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)
1409 related to the GUI system, like -font, -geometry, and -title, and 1409 related to the GUI system, like -font, -geometry, and -title, and
1410 then processes the rest of arguments whose priority is below 1410 then processes the rest of arguments whose priority is below
1411 those that are related to the GUI system. The arguments 1411 those that are related to the GUI system. The arguments
1412 porcessed by 'command-line' are removed from 'command-line-args'; 1412 processed by 'command-line' are removed from 'command-line-args';
1413 the arguments processed by 'command-line-1' aren't, they are only 1413 the arguments processed by 'command-line-1' aren't, they are only
1414 removed from 'command-line-args-left'. 1414 removed from 'command-line-args-left'.
1415 1415
@@ -1419,54 +1419,19 @@ main (int argc, char **argv)
1419 should be explicitly recognized, ignored, and removed from 1419 should be explicitly recognized, ignored, and removed from
1420 'command-line-args-left' in 'command-line-1'. */ 1420 'command-line-args-left' in 'command-line-1'. */
1421 1421
1422 bool only_version = false;
1422 sort_args (argc, argv); 1423 sort_args (argc, argv);
1423 argc = 0; 1424 argc = 0;
1424 while (argv[argc]) argc++; 1425 while (argv[argc]) argc++;
1425 1426
1426 skip_args = 0; 1427 skip_args = 0;
1427 if (argmatch (argv, argc, "-version", "--version", 3, NULL, &skip_args)) 1428 if (argmatch (argv, argc, "-version", "--version", 3, NULL, &skip_args))
1428 { 1429 only_version = true;
1429 const char *version, *copyright;
1430 if (initialized)
1431 {
1432 Lisp_Object tem, tem2;
1433 tem = Fsymbol_value (intern_c_string ("emacs-version"));
1434 tem2 = Fsymbol_value (intern_c_string ("emacs-copyright"));
1435 if (!STRINGP (tem))
1436 {
1437 fputs ("Invalid value of 'emacs-version'\n", stderr);
1438 exit (1);
1439 }
1440 if (!STRINGP (tem2))
1441 {
1442 fputs ("Invalid value of 'emacs-copyright'\n", stderr);
1443 exit (1);
1444 }
1445 else
1446 {
1447 version = SSDATA (tem);
1448 copyright = SSDATA (tem2);
1449 }
1450 }
1451 else
1452 {
1453 version = emacs_version;
1454 copyright = emacs_copyright;
1455 }
1456 printf (("%s %s\n"
1457 "%s\n"
1458 "%s comes with ABSOLUTELY NO WARRANTY.\n"
1459 "You may redistribute copies of %s\n"
1460 "under the terms of the GNU General Public License.\n"
1461 "For more information about these matters, "
1462 "see the file named COPYING.\n"),
1463 PACKAGE_NAME, version, copyright, PACKAGE_NAME, PACKAGE_NAME);
1464 exit (0);
1465 }
1466 1430
1467#ifdef HAVE_PDUMPER 1431#ifdef HAVE_PDUMPER
1468 if (argmatch (argv, argc, "-fingerprint", "--fingerprint", 4, 1432 if (argmatch (argv, argc, "-fingerprint", "--fingerprint", 4,
1469 NULL, &skip_args)) 1433 NULL, &skip_args)
1434 && !only_version)
1470 { 1435 {
1471 if (initialized) 1436 if (initialized)
1472 { 1437 {
@@ -1491,7 +1456,8 @@ main (int argc, char **argv)
1491 pdumper_record_wd (emacs_wd); 1456 pdumper_record_wd (emacs_wd);
1492#endif 1457#endif
1493 1458
1494 if (argmatch (argv, argc, "-chdir", "--chdir", 4, &ch_to_dir, &skip_args)) 1459 if (argmatch (argv, argc, "-chdir", "--chdir", 4, &ch_to_dir, &skip_args)
1460 && !only_version)
1495 { 1461 {
1496#ifdef WINDOWSNT 1462#ifdef WINDOWSNT
1497 /* argv[] array is kept in its original ANSI codepage encoding, 1463 /* argv[] array is kept in its original ANSI codepage encoding,
@@ -1617,7 +1583,7 @@ main (int argc, char **argv)
1617 inhibit_window_system = 0; 1583 inhibit_window_system = 0;
1618 1584
1619 /* Handle the -t switch, which specifies filename to use as terminal. */ 1585 /* Handle the -t switch, which specifies filename to use as terminal. */
1620 while (1) 1586 while (!only_version)
1621 { 1587 {
1622 char *term; 1588 char *term;
1623 if (argmatch (argv, argc, "-t", "--terminal", 4, &term, &skip_args)) 1589 if (argmatch (argv, argc, "-t", "--terminal", 4, &term, &skip_args))
@@ -1655,7 +1621,8 @@ main (int argc, char **argv)
1655 1621
1656 /* Handle the -batch switch, which means don't do interactive display. */ 1622 /* Handle the -batch switch, which means don't do interactive display. */
1657 noninteractive = 0; 1623 noninteractive = 0;
1658 if (argmatch (argv, argc, "-batch", "--batch", 5, NULL, &skip_args)) 1624 if (argmatch (argv, argc, "-batch", "--batch", 5, NULL, &skip_args)
1625 || only_version)
1659 { 1626 {
1660 noninteractive = 1; 1627 noninteractive = 1;
1661 Vundo_outer_limit = Qnil; 1628 Vundo_outer_limit = Qnil;
@@ -1672,7 +1639,8 @@ main (int argc, char **argv)
1672 } 1639 }
1673 1640
1674 /* Handle the --help option, which gives a usage message. */ 1641 /* Handle the --help option, which gives a usage message. */
1675 if (argmatch (argv, argc, "-help", "--help", 3, NULL, &skip_args)) 1642 if (argmatch (argv, argc, "-help", "--help", 3, NULL, &skip_args)
1643 && !only_version)
1676 { 1644 {
1677 int i; 1645 int i;
1678 printf ("Usage: %s [OPTION-OR-FILENAME]...\n", argv[0]); 1646 printf ("Usage: %s [OPTION-OR-FILENAME]...\n", argv[0]);
@@ -1693,20 +1661,27 @@ main (int argc, char **argv)
1693 1661
1694 int sockfd = -1; 1662 int sockfd = -1;
1695 1663
1696 if (argmatch (argv, argc, "-fg-daemon", "--fg-daemon", 10, NULL, &skip_args) 1664 if (!only_version)
1697 || argmatch (argv, argc, "-fg-daemon", "--fg-daemon", 10, &dname_arg, &skip_args))
1698 { 1665 {
1699 daemon_type = 1; /* foreground */ 1666 if (argmatch (argv, argc, "-fg-daemon", "--fg-daemon", 10, NULL,
1700 } 1667 &skip_args)
1701 else if (argmatch (argv, argc, "-daemon", "--daemon", 5, NULL, &skip_args) 1668 || argmatch (argv, argc, "-fg-daemon", "--fg-daemon", 10, &dname_arg,
1702 || argmatch (argv, argc, "-daemon", "--daemon", 5, &dname_arg, &skip_args) 1669 &skip_args))
1703 || argmatch (argv, argc, "-bg-daemon", "--bg-daemon", 10, NULL, &skip_args) 1670 {
1704 || argmatch (argv, argc, "-bg-daemon", "--bg-daemon", 10, &dname_arg, &skip_args)) 1671 daemon_type = 1; /* foreground */
1705 { 1672 }
1706 daemon_type = 2; /* background */ 1673 else if (argmatch (argv, argc, "-daemon", "--daemon", 5, NULL, &skip_args)
1674 || argmatch (argv, argc, "-daemon", "--daemon", 5, &dname_arg,
1675 &skip_args)
1676 || argmatch (argv, argc, "-bg-daemon", "--bg-daemon", 10, NULL,
1677 &skip_args)
1678 || argmatch (argv, argc, "-bg-daemon", "--bg-daemon", 10,
1679 &dname_arg, &skip_args))
1680 {
1681 daemon_type = 2; /* background */
1682 }
1707 } 1683 }
1708 1684
1709
1710 if (daemon_type > 0) 1685 if (daemon_type > 0)
1711 { 1686 {
1712#ifndef DOS_NT 1687#ifndef DOS_NT
@@ -1956,15 +1931,11 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1956 init_threads (); 1931 init_threads ();
1957 init_eval (); 1932 init_eval ();
1958#ifdef HAVE_PGTK 1933#ifdef HAVE_PGTK
1959 init_pgtkterm (); /* before init_atimer(). */ 1934 init_pgtkterm (); /* Must come before `init_atimer'. */
1960#endif 1935#endif
1961 running_asynch_code = 0; 1936 running_asynch_code = 0;
1962 init_random (); 1937 init_random ();
1963 1938 init_xfaces ();
1964#ifdef HAVE_PDUMPER
1965 if (dumped_with_pdumper_p ())
1966 init_xfaces ();
1967#endif
1968 1939
1969#if defined HAVE_JSON && !defined WINDOWSNT 1940#if defined HAVE_JSON && !defined WINDOWSNT
1970 init_json (); 1941 init_json ();
@@ -1986,7 +1957,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1986 bool module_assertions 1957 bool module_assertions
1987 = argmatch (argv, argc, "-module-assertions", "--module-assertions", 15, 1958 = argmatch (argv, argc, "-module-assertions", "--module-assertions", 15,
1988 NULL, &skip_args); 1959 NULL, &skip_args);
1989 if (will_dump_p () && module_assertions) 1960 if (will_dump_p () && module_assertions && !only_version)
1990 { 1961 {
1991 fputs ("Module assertions are not supported during dumping\n", stderr); 1962 fputs ("Module assertions are not supported during dumping\n", stderr);
1992 exit (1); 1963 exit (1);
@@ -2034,7 +2005,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
2034 int count_before = skip_args; 2005 int count_before = skip_args;
2035 2006
2036 /* Skip any number of -d options, but only use the last one. */ 2007 /* Skip any number of -d options, but only use the last one. */
2037 while (1) 2008 while (!only_version)
2038 { 2009 {
2039 int count_before_this = skip_args; 2010 int count_before_this = skip_args;
2040 2011
@@ -2176,6 +2147,72 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
2176 init_callproc (); /* Must follow init_cmdargs but not init_sys_modes. */ 2147 init_callproc (); /* Must follow init_cmdargs but not init_sys_modes. */
2177 init_fileio (); 2148 init_fileio ();
2178 init_lread (); 2149 init_lread ();
2150
2151 /* If "-version" was specified, produce version information and
2152 exit. We do it here because the code below needs to call Lisp
2153 primitives, which cannot be done safely before we call all the
2154 init_FOO initialization functions above. */
2155 if (only_version)
2156 {
2157 const char *version, *copyright;
2158
2159 if (initialized)
2160 {
2161 Lisp_Object tem = Fsymbol_value (intern_c_string ("emacs-version"));
2162 Lisp_Object tem2 = Fsymbol_value (intern_c_string ("emacs-copyright"));
2163 if (!STRINGP (tem))
2164 {
2165 fputs ("Invalid value of 'emacs-version'\n", stderr);
2166 exit (1);
2167 }
2168 if (!STRINGP (tem2))
2169 {
2170 fputs ("Invalid value of 'emacs-copyright'\n", stderr);
2171 exit (1);
2172 }
2173 else
2174 {
2175 version = SSDATA (tem);
2176 copyright = SSDATA (tem2);
2177 }
2178 }
2179 else
2180 {
2181 version = emacs_version;
2182 copyright = emacs_copyright;
2183 }
2184 printf ("%s %s\n", PACKAGE_NAME, version);
2185
2186 if (initialized)
2187 {
2188 Lisp_Object rversion, rbranch, rtime;
2189
2190 rversion
2191 = Fsymbol_value (intern_c_string ("emacs-repository-version"));
2192 rbranch
2193 = Fsymbol_value (intern_c_string ("emacs-repository-branch"));
2194 rtime
2195 = Fsymbol_value (intern_c_string ("emacs-build-time"));
2196
2197 if (!NILP (rversion) && !NILP (rbranch) && !NILP (rtime))
2198 printf ("Development version %s on %s branch; build date %s.\n",
2199 SSDATA (Fsubstring (rversion, make_fixnum (0),
2200 make_fixnum (12))),
2201 SSDATA (rbranch),
2202 SSDATA (Fformat_time_string (build_string ("%Y-%m-%d"),
2203 rtime, Qnil)));
2204 }
2205
2206 printf (("%s\n"
2207 "%s comes with ABSOLUTELY NO WARRANTY.\n"
2208 "You may redistribute copies of %s\n"
2209 "under the terms of the GNU General Public License.\n"
2210 "For more information about these matters, "
2211 "see the file named COPYING.\n"),
2212 copyright, PACKAGE_NAME, PACKAGE_NAME);
2213 exit (0);
2214 }
2215
2179#ifdef WINDOWSNT 2216#ifdef WINDOWSNT
2180 /* Check to see if Emacs has been installed correctly. */ 2217 /* Check to see if Emacs has been installed correctly. */
2181 check_windows_init_file (); 2218 check_windows_init_file ();
@@ -2954,6 +2991,10 @@ shut_down_emacs (int sig, Lisp_Object stuff)
2954 check_message_stack (); 2991 check_message_stack ();
2955 } 2992 }
2956 2993
2994#ifdef HAVE_NATIVE_COMP
2995 eln_load_path_final_clean_up ();
2996#endif
2997
2957#ifdef MSDOS 2998#ifdef MSDOS
2958 dos_cleanup (); 2999 dos_cleanup ();
2959#endif 3000#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
707 union specbinding *binding = default_toplevel_binding (symbol); 707 union specbinding *binding = default_toplevel_binding (symbol);
708 Lisp_Object value 708 Lisp_Object value
709 = binding ? specpdl_old_value (binding) : Fdefault_value (symbol); 709 = binding ? specpdl_old_value (binding) : Fdefault_value (symbol);
710 if (!EQ (value, Qunbound)) 710 if (!BASE_EQ (value, Qunbound))
711 return value; 711 return value;
712 xsignal1 (Qvoid_variable, symbol); 712 xsignal1 (Qvoid_variable, symbol);
713} 713}
@@ -741,7 +741,9 @@ value. */)
741 and where the `foo` package only gets loaded when <foo-function> 741 and where the `foo` package only gets loaded when <foo-function>
742 is called, so the outer `let` incorrectly made the binding lexical 742 is called, so the outer `let` incorrectly made the binding lexical
743 because the <foo-var> wasn't yet declared as dynamic at that point. */ 743 because the <foo-var> wasn't yet declared as dynamic at that point. */
744 error ("Defining as dynamic an already lexical var"); 744 xsignal2 (Qerror,
745 build_string ("Defining as dynamic an already lexical var"),
746 symbol);
745 747
746 XSYMBOL (symbol)->u.s.declared_special = true; 748 XSYMBOL (symbol)->u.s.declared_special = true;
747 if (!NILP (doc)) 749 if (!NILP (doc))
@@ -754,6 +756,33 @@ value. */)
754 return Qnil; 756 return Qnil;
755} 757}
756 758
759static Lisp_Object
760defvar (Lisp_Object sym, Lisp_Object initvalue, Lisp_Object docstring, bool eval)
761{
762 Lisp_Object tem;
763
764 CHECK_SYMBOL (sym);
765
766 tem = Fdefault_boundp (sym);
767
768 /* Do it before evaluating the initial value, for self-references. */
769 Finternal__define_uninitialized_variable (sym, docstring);
770
771 if (NILP (tem))
772 Fset_default (sym, eval ? eval_sub (initvalue) : initvalue);
773 else
774 { /* Check if there is really a global binding rather than just a let
775 binding that shadows the global unboundness of the var. */
776 union specbinding *binding = default_toplevel_binding (sym);
777 if (binding && BASE_EQ (specpdl_old_value (binding), Qunbound))
778 {
779 set_specpdl_old_value (binding,
780 eval ? eval_sub (initvalue) : initvalue);
781 }
782 }
783 return sym;
784}
785
757DEFUN ("defvar", Fdefvar, Sdefvar, 1, UNEVALLED, 0, 786DEFUN ("defvar", Fdefvar, Sdefvar, 1, UNEVALLED, 0,
758 doc: /* Define SYMBOL as a variable, and return SYMBOL. 787 doc: /* Define SYMBOL as a variable, and return SYMBOL.
759You are not required to define a variable in order to use it, but 788You 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;
768buffer-local values are not affected. If INITVALUE is missing, 797buffer-local values are not affected. If INITVALUE is missing,
769SYMBOL's value is not set. 798SYMBOL's value is not set.
770 799
771If SYMBOL has a local binding, then this form affects the local 800If SYMBOL is let-bound, then this form does not affect the local let
772binding. This is usually not what you want. Thus, if you need to 801binding but the toplevel default binding instead, like
773load a file defining variables, with this form or with `defconst' or 802`set-toplevel-default-binding`.
774`defcustom', you should always load that file _outside_ any bindings 803(`defcustom' behaves similarly in this respect.)
775for these variables. (`defconst' and `defcustom' behave similarly in
776this respect.)
777 804
778The optional argument DOCSTRING is a documentation string for the 805The optional argument DOCSTRING is a documentation string for the
779variable. 806variable.
@@ -784,7 +811,7 @@ To define a buffer-local variable, use `defvar-local'.
784usage: (defvar SYMBOL &optional INITVALUE DOCSTRING) */) 811usage: (defvar SYMBOL &optional INITVALUE DOCSTRING) */)
785 (Lisp_Object args) 812 (Lisp_Object args)
786{ 813{
787 Lisp_Object sym, tem, tail; 814 Lisp_Object sym, tail;
788 815
789 sym = XCAR (args); 816 sym = XCAR (args);
790 tail = XCDR (args); 817 tail = XCDR (args);
@@ -796,24 +823,8 @@ usage: (defvar SYMBOL &optional INITVALUE DOCSTRING) */)
796 if (!NILP (XCDR (tail)) && !NILP (XCDR (XCDR (tail)))) 823 if (!NILP (XCDR (tail)) && !NILP (XCDR (XCDR (tail))))
797 error ("Too many arguments"); 824 error ("Too many arguments");
798 Lisp_Object exp = XCAR (tail); 825 Lisp_Object exp = XCAR (tail);
799
800 tem = Fdefault_boundp (sym);
801 tail = XCDR (tail); 826 tail = XCDR (tail);
802 827 return defvar (sym, exp, CAR (tail), true);
803 /* Do it before evaluating the initial value, for self-references. */
804 Finternal__define_uninitialized_variable (sym, CAR (tail));
805
806 if (NILP (tem))
807 Fset_default (sym, eval_sub (exp));
808 else
809 { /* Check if there is really a global binding rather than just a let
810 binding that shadows the global unboundness of the var. */
811 union specbinding *binding = default_toplevel_binding (sym);
812 if (binding && EQ (specpdl_old_value (binding), Qunbound))
813 {
814 set_specpdl_old_value (binding, eval_sub (exp));
815 }
816 }
817 } 828 }
818 else if (!NILP (Vinternal_interpreter_environment) 829 else if (!NILP (Vinternal_interpreter_environment)
819 && (SYMBOLP (sym) && !XSYMBOL (sym)->u.s.declared_special)) 830 && (SYMBOLP (sym) && !XSYMBOL (sym)->u.s.declared_special))
@@ -832,6 +843,14 @@ usage: (defvar SYMBOL &optional INITVALUE DOCSTRING) */)
832 return sym; 843 return sym;
833} 844}
834 845
846DEFUN ("defvar-1", Fdefvar_1, Sdefvar_1, 2, 3, 0,
847 doc: /* Like `defvar' but as a function.
848More specifically behaves like (defvar SYM 'INITVALUE DOCSTRING). */)
849 (Lisp_Object sym, Lisp_Object initvalue, Lisp_Object docstring)
850{
851 return defvar (sym, initvalue, docstring, false);
852}
853
835DEFUN ("defconst", Fdefconst, Sdefconst, 2, UNEVALLED, 0, 854DEFUN ("defconst", Fdefconst, Sdefconst, 2, UNEVALLED, 0,
836 doc: /* Define SYMBOL as a constant variable. 855 doc: /* Define SYMBOL as a constant variable.
837This declares that neither programs nor users should ever change the 856This declares that neither programs nor users should ever change the
@@ -861,9 +880,18 @@ usage: (defconst SYMBOL INITVALUE [DOCSTRING]) */)
861 error ("Too many arguments"); 880 error ("Too many arguments");
862 docstring = XCAR (XCDR (XCDR (args))); 881 docstring = XCAR (XCDR (XCDR (args)));
863 } 882 }
883 tem = eval_sub (XCAR (XCDR (args)));
884 return Fdefconst_1 (sym, tem, docstring);
885}
864 886
887DEFUN ("defconst-1", Fdefconst_1, Sdefconst_1, 2, 3, 0,
888 doc: /* Like `defconst' but as a function.
889More specifically, behaves like (defconst SYM 'INITVALUE DOCSTRING). */)
890 (Lisp_Object sym, Lisp_Object initvalue, Lisp_Object docstring)
891{
892 CHECK_SYMBOL (sym);
893 Lisp_Object tem = initvalue;
865 Finternal__define_uninitialized_variable (sym, docstring); 894 Finternal__define_uninitialized_variable (sym, docstring);
866 tem = eval_sub (XCAR (XCDR (args)));
867 if (!NILP (Vpurify_flag)) 895 if (!NILP (Vpurify_flag))
868 tem = Fpurecopy (tem); 896 tem = Fpurecopy (tem);
869 Fset_default (sym, tem); /* FIXME: set-default-toplevel-value? */ 897 Fset_default (sym, tem); /* FIXME: set-default-toplevel-value? */
@@ -1223,6 +1251,13 @@ unwind_to_catch (struct handler *catch, enum nonlocal_exit type,
1223 set_poll_suppress_count (catch->poll_suppress_count); 1251 set_poll_suppress_count (catch->poll_suppress_count);
1224 unblock_input_to (catch->interrupt_input_blocked); 1252 unblock_input_to (catch->interrupt_input_blocked);
1225 1253
1254#ifdef HAVE_X_WINDOWS
1255 /* Restore the X error handler stack. This is important because
1256 otherwise a display disconnect won't unwind the stack of error
1257 traps to the right depth. */
1258 x_unwind_errors_to (catch->x_error_handler_depth);
1259#endif
1260
1226 do 1261 do
1227 { 1262 {
1228 /* Unwind the specpdl stack, and then restore the proper set of 1263 /* 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,
1341 && (SYMBOLP (XCAR (tem)) 1376 && (SYMBOLP (XCAR (tem))
1342 || CONSP (XCAR (tem)))))) 1377 || CONSP (XCAR (tem))))))
1343 error ("Invalid condition handler: %s", 1378 error ("Invalid condition handler: %s",
1344 SDATA (Fprin1_to_string (tem, Qt))); 1379 SDATA (Fprin1_to_string (tem, Qt, Qnil)));
1345 if (CONSP (tem) && EQ (XCAR (tem), QCsuccess)) 1380 if (CONSP (tem) && EQ (XCAR (tem), QCsuccess))
1346 success_handler = XCDR (tem); 1381 success_handler = XCDR (tem);
1347 else 1382 else
@@ -1597,6 +1632,9 @@ push_handler_nosignal (Lisp_Object tag_ch_val, enum handlertype handlertype)
1597 c->act_rec = get_act_rec (current_thread); 1632 c->act_rec = get_act_rec (current_thread);
1598 c->poll_suppress_count = poll_suppress_count; 1633 c->poll_suppress_count = poll_suppress_count;
1599 c->interrupt_input_blocked = interrupt_input_blocked; 1634 c->interrupt_input_blocked = interrupt_input_blocked;
1635#ifdef HAVE_X_WINDOWS
1636 c->x_error_handler_depth = x_error_message_count;
1637#endif
1600 handlerlist = c; 1638 handlerlist = c;
1601 return c; 1639 return c;
1602} 1640}
@@ -2740,7 +2778,7 @@ run_hook_with_args (ptrdiff_t nargs, Lisp_Object *args,
2740 sym = args[0]; 2778 sym = args[0];
2741 val = find_symbol_value (sym); 2779 val = find_symbol_value (sym);
2742 2780
2743 if (EQ (val, Qunbound) || NILP (val)) 2781 if (BASE_EQ (val, Qunbound) || NILP (val))
2744 return ret; 2782 return ret;
2745 else if (!CONSP (val) || FUNCTIONP (val)) 2783 else if (!CONSP (val) || FUNCTIONP (val))
2746 { 2784 {
@@ -2816,7 +2854,13 @@ apply1 (Lisp_Object fn, Lisp_Object arg)
2816} 2854}
2817 2855
2818DEFUN ("functionp", Ffunctionp, Sfunctionp, 1, 1, 0, 2856DEFUN ("functionp", Ffunctionp, Sfunctionp, 1, 1, 0,
2819 doc: /* Return t if OBJECT is a function. */) 2857 doc: /* Return t if OBJECT is a function.
2858
2859An object is a function if it is callable via `funcall'; this includes
2860symbols with function bindings, but excludes macros and special forms.
2861
2862Ordinarily return nil if OBJECT is not a function, although t might be
2863returned in rare cases. */)
2820 (Lisp_Object object) 2864 (Lisp_Object object)
2821{ 2865{
2822 if (FUNCTIONP (object)) 2866 if (FUNCTIONP (object))
@@ -4338,9 +4382,11 @@ alist of active lexical bindings. */);
4338 defsubr (&Sdefault_toplevel_value); 4382 defsubr (&Sdefault_toplevel_value);
4339 defsubr (&Sset_default_toplevel_value); 4383 defsubr (&Sset_default_toplevel_value);
4340 defsubr (&Sdefvar); 4384 defsubr (&Sdefvar);
4385 defsubr (&Sdefvar_1);
4341 defsubr (&Sdefvaralias); 4386 defsubr (&Sdefvaralias);
4342 DEFSYM (Qdefvaralias, "defvaralias"); 4387 DEFSYM (Qdefvaralias, "defvaralias");
4343 defsubr (&Sdefconst); 4388 defsubr (&Sdefconst);
4389 defsubr (&Sdefconst_1);
4344 defsubr (&Sinternal__define_uninitialized_variable); 4390 defsubr (&Sinternal__define_uninitialized_variable);
4345 defsubr (&Smake_var_non_special); 4391 defsubr (&Smake_var_non_special);
4346 defsubr (&Slet); 4392 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. */)
2718 : Qnil); 2718 : Qnil);
2719 if (!NILP (symlink_target)) 2719 if (!NILP (symlink_target))
2720 Fmake_symbolic_link (symlink_target, newname, ok_if_already_exists); 2720 Fmake_symbolic_link (symlink_target, newname, ok_if_already_exists);
2721 else if (S_ISFIFO (file_st.st_mode))
2722 {
2723 /* If it's a FIFO, calling `copy-file' will hang if it's a
2724 inter-file system move, so do it here. (It will signal
2725 an error in that case, but it won't hang in any case.) */
2726 if (!NILP (ok_if_already_exists))
2727 barf_or_query_if_file_exists (newname, false,
2728 "rename to it",
2729 FIXNUMP (ok_if_already_exists),
2730 false);
2731 if (rename (SSDATA (encoded_file), SSDATA (encoded_newname)) != 0)
2732 report_file_errno ("Renaming", list2 (file, newname), errno);
2733 return Qnil;
2734 }
2721 else 2735 else
2722 Fcopy_file (file, newname, ok_if_already_exists, Qt, Qt, Qt); 2736 Fcopy_file (file, newname, ok_if_already_exists, Qt, Qt, Qt);
2723 } 2737 }
@@ -3884,6 +3898,10 @@ The optional third and fourth arguments BEG and END specify what portion
3884of the file to insert. These arguments count bytes in the file, not 3898of the file to insert. These arguments count bytes in the file, not
3885characters in the buffer. If VISIT is non-nil, BEG and END must be nil. 3899characters in the buffer. If VISIT is non-nil, BEG and END must be nil.
3886 3900
3901When inserting data from a special file (e.g., /dev/urandom), you
3902can't specify VISIT or BEG, and END should be specified to avoid
3903inserting unlimited data into the buffer.
3904
3887If optional fifth argument REPLACE is non-nil, replace the current 3905If optional fifth argument REPLACE is non-nil, replace the current
3888buffer contents (in the accessible portion) with the file contents. 3906buffer contents (in the accessible portion) with the file contents.
3889This is better than simply deleting and inserting the whole thing 3907This is better than simply deleting and inserting the whole thing
@@ -3911,7 +3929,7 @@ by calling `format-decode', which see. */)
3911 Lisp_Object handler, val, insval, orig_filename, old_undo; 3929 Lisp_Object handler, val, insval, orig_filename, old_undo;
3912 Lisp_Object p; 3930 Lisp_Object p;
3913 ptrdiff_t total = 0; 3931 ptrdiff_t total = 0;
3914 bool not_regular = 0; 3932 bool regular = true;
3915 int save_errno = 0; 3933 int save_errno = 0;
3916 char read_buf[READ_BUF_SIZE]; 3934 char read_buf[READ_BUF_SIZE];
3917 struct coding_system coding; 3935 struct coding_system coding;
@@ -3934,6 +3952,7 @@ by calling `format-decode', which see. */)
3934 /* SAME_AT_END_CHARPOS counts characters, because 3952 /* SAME_AT_END_CHARPOS counts characters, because
3935 restore_window_points needs the old character count. */ 3953 restore_window_points needs the old character count. */
3936 ptrdiff_t same_at_end_charpos = ZV; 3954 ptrdiff_t same_at_end_charpos = ZV;
3955 bool seekable = true;
3937 3956
3938 if (current_buffer->base_buffer && ! NILP (visit)) 3957 if (current_buffer->base_buffer && ! NILP (visit))
3939 error ("Cannot do file visiting in an indirect buffer"); 3958 error ("Cannot do file visiting in an indirect buffer");
@@ -4007,7 +4026,8 @@ by calling `format-decode', which see. */)
4007 least signal an error. */ 4026 least signal an error. */
4008 if (!S_ISREG (st.st_mode)) 4027 if (!S_ISREG (st.st_mode))
4009 { 4028 {
4010 not_regular = 1; 4029 regular = false;
4030 seekable = lseek (fd, 0, SEEK_CUR) < 0;
4011 4031
4012 if (! NILP (visit)) 4032 if (! NILP (visit))
4013 { 4033 {
@@ -4015,7 +4035,12 @@ by calling `format-decode', which see. */)
4015 goto notfound; 4035 goto notfound;
4016 } 4036 }
4017 4037
4018 if (! NILP (replace) || ! NILP (beg) || ! NILP (end)) 4038 if (!NILP (beg) && !seekable)
4039 xsignal2 (Qfile_error,
4040 build_string ("cannot use a start position in a non-seekable file/device"),
4041 orig_filename);
4042
4043 if (!NILP (replace))
4019 xsignal2 (Qfile_error, 4044 xsignal2 (Qfile_error,
4020 build_string ("not a regular file"), orig_filename); 4045 build_string ("not a regular file"), orig_filename);
4021 } 4046 }
@@ -4037,7 +4062,7 @@ by calling `format-decode', which see. */)
4037 end_offset = file_offset (end); 4062 end_offset = file_offset (end);
4038 else 4063 else
4039 { 4064 {
4040 if (not_regular) 4065 if (!regular)
4041 end_offset = TYPE_MAXIMUM (off_t); 4066 end_offset = TYPE_MAXIMUM (off_t);
4042 else 4067 else
4043 { 4068 {
@@ -4059,7 +4084,7 @@ by calling `format-decode', which see. */)
4059 /* Check now whether the buffer will become too large, 4084 /* Check now whether the buffer will become too large,
4060 in the likely case where the file's length is not changing. 4085 in the likely case where the file's length is not changing.
4061 This saves a lot of needless work before a buffer overflow. */ 4086 This saves a lot of needless work before a buffer overflow. */
4062 if (! not_regular) 4087 if (regular)
4063 { 4088 {
4064 /* The likely offset where we will stop reading. We could read 4089 /* The likely offset where we will stop reading. We could read
4065 more (or less), if the file grows (or shrinks) as we read it. */ 4090 more (or less), if the file grows (or shrinks) as we read it. */
@@ -4097,7 +4122,7 @@ by calling `format-decode', which see. */)
4097 { 4122 {
4098 /* Don't try looking inside a file for a coding system 4123 /* Don't try looking inside a file for a coding system
4099 specification if it is not seekable. */ 4124 specification if it is not seekable. */
4100 if (! not_regular && ! NILP (Vset_auto_coding_function)) 4125 if (regular && !NILP (Vset_auto_coding_function))
4101 { 4126 {
4102 /* Find a coding system specified in the heading two 4127 /* Find a coding system specified in the heading two
4103 lines or in the tailing several lines of the file. 4128 lines or in the tailing several lines of the file.
@@ -4559,7 +4584,7 @@ by calling `format-decode', which see. */)
4559 goto handled; 4584 goto handled;
4560 } 4585 }
4561 4586
4562 if (! not_regular) 4587 if (seekable || !NILP (end))
4563 total = end_offset - beg_offset; 4588 total = end_offset - beg_offset;
4564 else 4589 else
4565 /* For a special file, all we can do is guess. */ 4590 /* For a special file, all we can do is guess. */
@@ -4605,7 +4630,7 @@ by calling `format-decode', which see. */)
4605 ptrdiff_t trytry = min (total - how_much, READ_BUF_SIZE); 4630 ptrdiff_t trytry = min (total - how_much, READ_BUF_SIZE);
4606 ptrdiff_t this; 4631 ptrdiff_t this;
4607 4632
4608 if (not_regular) 4633 if (!seekable && NILP (end))
4609 { 4634 {
4610 Lisp_Object nbytes; 4635 Lisp_Object nbytes;
4611 4636
@@ -4656,7 +4681,7 @@ by calling `format-decode', which see. */)
4656 For a special file, where TOTAL is just a buffer size, 4681 For a special file, where TOTAL is just a buffer size,
4657 so don't bother counting in HOW_MUCH. 4682 so don't bother counting in HOW_MUCH.
4658 (INSERTED is where we count the number of characters inserted.) */ 4683 (INSERTED is where we count the number of characters inserted.) */
4659 if (! not_regular) 4684 if (seekable || !NILP (end))
4660 how_much += this; 4685 how_much += this;
4661 inserted += this; 4686 inserted += this;
4662 } 4687 }
@@ -4834,7 +4859,7 @@ by calling `format-decode', which see. */)
4834 Funlock_file (BVAR (current_buffer, file_truename)); 4859 Funlock_file (BVAR (current_buffer, file_truename));
4835 Funlock_file (filename); 4860 Funlock_file (filename);
4836 } 4861 }
4837 if (not_regular) 4862 if (!regular)
4838 xsignal2 (Qfile_error, 4863 xsignal2 (Qfile_error,
4839 build_string ("not a regular file"), orig_filename); 4864 build_string ("not a regular file"), orig_filename);
4840 } 4865 }
@@ -5958,14 +5983,19 @@ do_auto_save_eh (Lisp_Object ignore)
5958 5983
5959DEFUN ("do-auto-save", Fdo_auto_save, Sdo_auto_save, 0, 2, "", 5984DEFUN ("do-auto-save", Fdo_auto_save, Sdo_auto_save, 0, 2, "",
5960 doc: /* Auto-save all buffers that need it. 5985 doc: /* Auto-save all buffers that need it.
5961This is all buffers that have auto-saving enabled 5986This auto-saves all buffers that have auto-saving enabled and
5962and are changed since last auto-saved. 5987were changed since last auto-saved.
5963Auto-saving writes the buffer into a file 5988
5964so that your editing is not lost if the system crashes. 5989Auto-saving writes the buffer into a file so that your edits are
5965This file is not the file you visited; that changes only when you save. 5990not lost if the system crashes.
5991
5992The auto-save file is not the file you visited; that changes only
5993when you save.
5994
5966Normally, run the normal hook `auto-save-hook' before saving. 5995Normally, run the normal hook `auto-save-hook' before saving.
5967 5996
5968A non-nil NO-MESSAGE argument means do not print any message if successful. 5997A non-nil NO-MESSAGE argument means do not print any message if successful.
5998
5969A non-nil CURRENT-ONLY argument means save only current buffer. */) 5999A non-nil CURRENT-ONLY argument means save only current buffer. */)
5970 (Lisp_Object no_message, Lisp_Object current_only) 6000 (Lisp_Object no_message, Lisp_Object current_only)
5971{ 6001{
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/>. */
29 29
30 C99 and C11 require the following math.h functions in addition to 30 C99 and C11 require the following math.h functions in addition to
31 the C89 functions. Of these, Emacs currently exports only the 31 the C89 functions. Of these, Emacs currently exports only the
32 starred ones to Lisp, since we haven't found a use for the others: 32 starred ones to Lisp, since we haven't found a use for the others.
33 acosh, atanh, cbrt, *copysign, erf, erfc, exp2, expm1, fdim, fma, 33 Also, it uses the ones marked "+" internally:
34 fmax, fmin, fpclassify, hypot, ilogb, isfinite, isgreater, 34 acosh, atanh, cbrt, copysign (implemented by signbit), erf, erfc,
35 isgreaterequal, isinf, isless, islessequal, islessgreater, *isnan, 35 exp2, expm1, fdim, fma, fmax, fmin, fpclassify, hypot, +ilogb,
36 isnormal, isunordered, lgamma, log1p, *log2 [via (log X 2)], *logb 36 isfinite, isgreater, isgreaterequal, isinf, isless, islessequal,
37 (approximately), lrint/llrint, lround/llround, nan, nearbyint, 37 islessgreater, *isnan, isnormal, isunordered, lgamma, log1p, *log2
38 nextafter, nexttoward, remainder, remquo, *rint, round, scalbln, 38 [via (log X 2)], logb (approximately; implemented by frexp),
39 scalbn, signbit, tgamma, *trunc. 39 +lrint/llrint, +lround/llround, nan, nearbyint, nextafter,
40 nexttoward, remainder, remquo, *rint, round, scalbln, +scalbn,
41 +signbit, tgamma, *trunc.
42
43 The C standard also requires functions for float and long double
44 that are not listed above. Of these functions, Emacs uses only the
45 following internally: fabsf, powf, sprintf.
40 */ 46 */
41 47
42#include <config.h> 48#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,
2519 if (SYMBOL_WITH_POS_P (o2)) 2519 if (SYMBOL_WITH_POS_P (o2))
2520 o2 = SYMBOL_WITH_POS_SYM (o2); 2520 o2 = SYMBOL_WITH_POS_SYM (o2);
2521 2521
2522 if (EQ (o1, o2)) 2522 if (BASE_EQ (o1, o2))
2523 return true; 2523 return true;
2524 if (XTYPE (o1) != XTYPE (o2)) 2524 if (XTYPE (o1) != XTYPE (o2))
2525 return false; 2525 return false;
@@ -4113,7 +4113,7 @@ hash_table_user_defined_call (ptrdiff_t nargs, Lisp_Object *args,
4113 return unbind_to (count, Ffuncall (nargs, args)); 4113 return unbind_to (count, Ffuncall (nargs, args));
4114} 4114}
4115 4115
4116/* Ignore HT and compare KEY1 and KEY2 using 'eql'. 4116/* Ignore H and compare KEY1 and KEY2 using 'eql'.
4117 Value is true if KEY1 and KEY2 are the same. */ 4117 Value is true if KEY1 and KEY2 are the same. */
4118 4118
4119static Lisp_Object 4119static Lisp_Object
@@ -4122,7 +4122,7 @@ cmpfn_eql (Lisp_Object key1, Lisp_Object key2, struct Lisp_Hash_Table *h)
4122 return Feql (key1, key2); 4122 return Feql (key1, key2);
4123} 4123}
4124 4124
4125/* Ignore HT and compare KEY1 and KEY2 using 'equal'. 4125/* Ignore H and compare KEY1 and KEY2 using 'equal'.
4126 Value is true if KEY1 and KEY2 are the same. */ 4126 Value is true if KEY1 and KEY2 are the same. */
4127 4127
4128static Lisp_Object 4128static Lisp_Object
@@ -4132,7 +4132,7 @@ cmpfn_equal (Lisp_Object key1, Lisp_Object key2, struct Lisp_Hash_Table *h)
4132} 4132}
4133 4133
4134 4134
4135/* Given HT, compare KEY1 and KEY2 using HT->user_cmp_function. 4135/* Given H, compare KEY1 and KEY2 using H->user_cmp_function.
4136 Value is true if KEY1 and KEY2 are the same. */ 4136 Value is true if KEY1 and KEY2 are the same. */
4137 4137
4138static Lisp_Object 4138static Lisp_Object
@@ -4143,8 +4143,7 @@ cmpfn_user_defined (Lisp_Object key1, Lisp_Object key2,
4143 return hash_table_user_defined_call (ARRAYELTS (args), args, h); 4143 return hash_table_user_defined_call (ARRAYELTS (args), args, h);
4144} 4144}
4145 4145
4146/* Ignore HT and return a hash code for KEY which uses 'eq' to compare 4146/* Ignore H and return a hash code for KEY which uses 'eq' to compare keys. */
4147 keys. */
4148 4147
4149static Lisp_Object 4148static Lisp_Object
4150hashfn_eq (Lisp_Object key, struct Lisp_Hash_Table *h) 4149hashfn_eq (Lisp_Object key, struct Lisp_Hash_Table *h)
@@ -4154,7 +4153,7 @@ hashfn_eq (Lisp_Object key, struct Lisp_Hash_Table *h)
4154 return make_ufixnum (XHASH (key) ^ XTYPE (key)); 4153 return make_ufixnum (XHASH (key) ^ XTYPE (key));
4155} 4154}
4156 4155
4157/* Ignore HT and return a hash code for KEY which uses 'equal' to compare keys. 4156/* Ignore H and return a hash code for KEY which uses 'equal' to compare keys.
4158 The hash code is at most INTMASK. */ 4157 The hash code is at most INTMASK. */
4159 4158
4160static Lisp_Object 4159static Lisp_Object
@@ -4163,7 +4162,7 @@ hashfn_equal (Lisp_Object key, struct Lisp_Hash_Table *h)
4163 return make_ufixnum (sxhash (key)); 4162 return make_ufixnum (sxhash (key));
4164} 4163}
4165 4164
4166/* Ignore HT and return a hash code for KEY which uses 'eql' to compare keys. 4165/* Ignore H and return a hash code for KEY which uses 'eql' to compare keys.
4167 The hash code is at most INTMASK. */ 4166 The hash code is at most INTMASK. */
4168 4167
4169static Lisp_Object 4168static Lisp_Object
@@ -4172,7 +4171,7 @@ hashfn_eql (Lisp_Object key, struct Lisp_Hash_Table *h)
4172 return (FLOATP (key) || BIGNUMP (key) ? hashfn_equal : hashfn_eq) (key, h); 4171 return (FLOATP (key) || BIGNUMP (key) ? hashfn_equal : hashfn_eq) (key, h);
4173} 4172}
4174 4173
4175/* Given HT, return a hash code for KEY which uses a user-defined 4174/* Given H, return a hash code for KEY which uses a user-defined
4176 function to compare keys. */ 4175 function to compare keys. */
4177 4176
4178Lisp_Object 4177Lisp_Object
@@ -4479,7 +4478,7 @@ hash_put (struct Lisp_Hash_Table *h, Lisp_Object key, Lisp_Object value,
4479 /* Store key/value in the key_and_value vector. */ 4478 /* Store key/value in the key_and_value vector. */
4480 i = h->next_free; 4479 i = h->next_free;
4481 eassert (NILP (HASH_HASH (h, i))); 4480 eassert (NILP (HASH_HASH (h, i)));
4482 eassert (EQ (Qunbound, (HASH_KEY (h, i)))); 4481 eassert (BASE_EQ (Qunbound, (HASH_KEY (h, i))));
4483 h->next_free = HASH_NEXT (h, i); 4482 h->next_free = HASH_NEXT (h, i);
4484 set_hash_key_slot (h, i, key); 4483 set_hash_key_slot (h, i, key);
4485 set_hash_value_slot (h, i, value); 4484 set_hash_value_slot (h, i, value);
@@ -5220,7 +5219,7 @@ FUNCTION is called with two arguments, KEY and VALUE.
5220 for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i) 5219 for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i)
5221 { 5220 {
5222 Lisp_Object k = HASH_KEY (h, i); 5221 Lisp_Object k = HASH_KEY (h, i);
5223 if (!EQ (k, Qunbound)) 5222 if (!BASE_EQ (k, Qunbound))
5224 call2 (function, k, HASH_VALUE (h, i)); 5223 call2 (function, k, HASH_VALUE (h, i));
5225 } 5224 }
5226 5225
@@ -5870,9 +5869,12 @@ from the absolute start of the buffer, disregarding the narrowing. */)
5870 if (!NILP (absolute)) 5869 if (!NILP (absolute))
5871 start = BEG_BYTE; 5870 start = BEG_BYTE;
5872 5871
5873 /* Check that POSITION is in the accessible range of the buffer. */ 5872 /* Check that POSITION is in the accessible range of the buffer, or,
5874 if (pos < BEGV || pos > ZV) 5873 if we're reporting absolute positions, in the buffer. */
5874 if (NILP (absolute) && (pos < BEGV || pos > ZV))
5875 args_out_of_range_3 (make_int (pos), make_int (BEGV), make_int (ZV)); 5875 args_out_of_range_3 (make_int (pos), make_int (BEGV), make_int (ZV));
5876 else if (!NILP (absolute) && (pos < 1 || pos > Z))
5877 args_out_of_range_3 (make_int (pos), make_int (1), make_int (Z));
5876 5878
5877 return make_int (count_lines (start, CHAR_TO_BYTE (pos)) + 1); 5879 return make_int (count_lines (start, CHAR_TO_BYTE (pos)) + 1);
5878} 5880}
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)
731 { 731 {
732 Lisp_Object prev = Qnil; 732 Lisp_Object prev = Qnil;
733 733
734 if (EQ (val, Qunbound)) 734 if (BASE_EQ (val, Qunbound))
735 return val; 735 return val;
736 while (CONSP (extra) 736 while (CONSP (extra)
737 && NILP (Fstring_lessp (prop, XCAR (XCAR (extra))))) 737 && NILP (Fstring_lessp (prop, XCAR (XCAR (extra)))))
@@ -745,7 +745,7 @@ font_put_extra (Lisp_Object font, Lisp_Object prop, Lisp_Object val)
745 return val; 745 return val;
746 } 746 }
747 XSETCDR (slot, val); 747 XSETCDR (slot, val);
748 if (EQ (val, Qunbound)) 748 if (BASE_EQ (val, Qunbound))
749 ASET (font, FONT_EXTRA_INDEX, Fdelq (slot, extra)); 749 ASET (font, FONT_EXTRA_INDEX, Fdelq (slot, extra));
750 return val; 750 return val;
751} 751}
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
1572 if (! FRAME_MINIBUF_ONLY_P (XFRAME (selected_frame))) 1572 if (! FRAME_MINIBUF_ONLY_P (XFRAME (selected_frame)))
1573 last_nonminibuf_frame = XFRAME (selected_frame); 1573 last_nonminibuf_frame = XFRAME (selected_frame);
1574 1574
1575 /* If the selected window in the target frame is its mini-window, we move
1576 to a different window, the most recently used one, unless there is a
1577 valid active minibuffer in the mini-window. */
1578 if (EQ (f->selected_window, f->minibuffer_window)
1579 /* The following test might fail if the mini-window contains a
1580 non-active minibuffer. */
1581 && NILP (Fminibufferp (XWINDOW (f->minibuffer_window)->contents, Qt)))
1582 {
1583 Lisp_Object w = call1 (Qget_mru_window, frame);
1584 if (WINDOW_LIVE_P (w)) /* W can be nil in minibuffer-only frames. */
1585 Fset_frame_selected_window (frame, w, Qnil);
1586 }
1587
1575 Fselect_window (f->selected_window, norecord); 1588 Fselect_window (f->selected_window, norecord);
1576 1589
1577 /* We want to make sure that the next event generates a frame-switch 1590 /* 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)
1988 error ("Attempt to delete the only frame"); 2001 error ("Attempt to delete the only frame");
1989 } 2002 }
1990#ifdef HAVE_X_WINDOWS 2003#ifdef HAVE_X_WINDOWS
1991 else if (x_dnd_in_progress && f == x_dnd_frame) 2004 else if ((x_dnd_in_progress && f == x_dnd_frame)
2005 || (x_dnd_waiting_for_finish && f == x_dnd_finish_frame))
1992 error ("Attempt to delete the drop source frame"); 2006 error ("Attempt to delete the drop source frame");
1993#endif 2007#endif
1994#ifdef HAVE_HAIKU 2008#ifdef HAVE_HAIKU
@@ -2333,7 +2347,8 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
2333 kset_default_minibuffer_frame (kb, Qnil); 2347 kset_default_minibuffer_frame (kb, Qnil);
2334 } 2348 }
2335 2349
2336 /* Cause frame titles to update--necessary if we now have just one frame. */ 2350 /* Cause frame titles to update--necessary if we now have just one
2351 frame. */
2337 if (!is_tooltip_frame) 2352 if (!is_tooltip_frame)
2338 update_mode_lines = 15; 2353 update_mode_lines = 15;
2339 2354
@@ -3642,7 +3657,7 @@ DEFUN ("frame-fringe-width", Ffringe_width, Sfringe_width, 0, 1, 0,
3642 3657
3643DEFUN ("frame-child-frame-border-width", Fframe_child_frame_border_width, Sframe_child_frame_border_width, 0, 1, 0, 3658DEFUN ("frame-child-frame-border-width", Fframe_child_frame_border_width, Sframe_child_frame_border_width, 0, 1, 0,
3644 doc: /* Return width of FRAME's child-frame border in pixels. 3659 doc: /* Return width of FRAME's child-frame border in pixels.
3645 If FRAME's 'child-frame-border-width' parameter is nil, return FRAME's 3660 If FRAME's `child-frame-border-width' parameter is nil, return FRAME's
3646 internal border width instead. */) 3661 internal border width instead. */)
3647 (Lisp_Object frame) 3662 (Lisp_Object frame)
3648{ 3663{
@@ -4276,7 +4291,7 @@ gui_set_frame_parameters (struct frame *f, Lisp_Object alist)
4276 } 4291 }
4277 4292
4278 /* Don't die if just one of these was set. */ 4293 /* Don't die if just one of these was set. */
4279 if (EQ (left, Qunbound)) 4294 if (BASE_EQ (left, Qunbound))
4280 { 4295 {
4281 left_no_change = 1; 4296 left_no_change = 1;
4282 if (f->left_pos < 0) 4297 if (f->left_pos < 0)
@@ -4284,7 +4299,7 @@ gui_set_frame_parameters (struct frame *f, Lisp_Object alist)
4284 else 4299 else
4285 XSETINT (left, f->left_pos); 4300 XSETINT (left, f->left_pos);
4286 } 4301 }
4287 if (EQ (top, Qunbound)) 4302 if (BASE_EQ (top, Qunbound))
4288 { 4303 {
4289 top_no_change = 1; 4304 top_no_change = 1;
4290 if (f->top_pos < 0) 4305 if (f->top_pos < 0)
@@ -5442,7 +5457,7 @@ gui_frame_get_and_record_arg (struct frame *f, Lisp_Object alist,
5442 5457
5443 value = gui_display_get_arg (FRAME_DISPLAY_INFO (f), alist, param, 5458 value = gui_display_get_arg (FRAME_DISPLAY_INFO (f), alist, param,
5444 attribute, class, type); 5459 attribute, class, type);
5445 if (! NILP (value) && ! EQ (value, Qunbound)) 5460 if (! NILP (value) && ! BASE_EQ (value, Qunbound))
5446 store_frame_param (f, param, value); 5461 store_frame_param (f, param, value);
5447 5462
5448 return value; 5463 return value;
@@ -5463,7 +5478,7 @@ gui_default_parameter (struct frame *f, Lisp_Object alist, Lisp_Object prop,
5463 Lisp_Object tem; 5478 Lisp_Object tem;
5464 5479
5465 tem = gui_frame_get_arg (f, alist, prop, xprop, xclass, type); 5480 tem = gui_frame_get_arg (f, alist, prop, xprop, xclass, type);
5466 if (EQ (tem, Qunbound)) 5481 if (BASE_EQ (tem, Qunbound))
5467 tem = deflt; 5482 tem = deflt;
5468 AUTO_FRAME_ARG (arg, prop, tem); 5483 AUTO_FRAME_ARG (arg, prop, tem);
5469 gui_set_frame_parameters (f, arg); 5484 gui_set_frame_parameters (f, arg);
@@ -5725,9 +5740,9 @@ gui_figure_window_size (struct frame *f, Lisp_Object parms, bool tabbar_p,
5725 5740
5726 height = gui_display_get_arg (dpyinfo, parms, Qheight, 0, 0, RES_TYPE_NUMBER); 5741 height = gui_display_get_arg (dpyinfo, parms, Qheight, 0, 0, RES_TYPE_NUMBER);
5727 width = gui_display_get_arg (dpyinfo, parms, Qwidth, 0, 0, RES_TYPE_NUMBER); 5742 width = gui_display_get_arg (dpyinfo, parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
5728 if (!EQ (width, Qunbound) || !EQ (height, Qunbound)) 5743 if (!BASE_EQ (width, Qunbound) || !BASE_EQ (height, Qunbound))
5729 { 5744 {
5730 if (!EQ (width, Qunbound)) 5745 if (!BASE_EQ (width, Qunbound))
5731 { 5746 {
5732 if (CONSP (width) && EQ (XCAR (width), Qtext_pixels)) 5747 if (CONSP (width) && EQ (XCAR (width), Qtext_pixels))
5733 { 5748 {
@@ -5763,7 +5778,7 @@ gui_figure_window_size (struct frame *f, Lisp_Object parms, bool tabbar_p,
5763 } 5778 }
5764 } 5779 }
5765 5780
5766 if (!EQ (height, Qunbound)) 5781 if (!BASE_EQ (height, Qunbound))
5767 { 5782 {
5768 if (CONSP (height) && EQ (XCAR (height), Qtext_pixels)) 5783 if (CONSP (height) && EQ (XCAR (height), Qtext_pixels))
5769 { 5784 {
@@ -5801,7 +5816,7 @@ gui_figure_window_size (struct frame *f, Lisp_Object parms, bool tabbar_p,
5801 5816
5802 user_size = gui_display_get_arg (dpyinfo, parms, Quser_size, 0, 0, 5817 user_size = gui_display_get_arg (dpyinfo, parms, Quser_size, 0, 0,
5803 RES_TYPE_NUMBER); 5818 RES_TYPE_NUMBER);
5804 if (!NILP (user_size) && !EQ (user_size, Qunbound)) 5819 if (!NILP (user_size) && !BASE_EQ (user_size, Qunbound))
5805 window_prompting |= USSize; 5820 window_prompting |= USSize;
5806 else 5821 else
5807 window_prompting |= PSize; 5822 window_prompting |= PSize;
@@ -5814,7 +5829,7 @@ gui_figure_window_size (struct frame *f, Lisp_Object parms, bool tabbar_p,
5814 left = gui_display_get_arg (dpyinfo, parms, Qleft, 0, 0, RES_TYPE_NUMBER); 5829 left = gui_display_get_arg (dpyinfo, parms, Qleft, 0, 0, RES_TYPE_NUMBER);
5815 user_position = gui_display_get_arg (dpyinfo, parms, Quser_position, 0, 0, 5830 user_position = gui_display_get_arg (dpyinfo, parms, Quser_position, 0, 0,
5816 RES_TYPE_NUMBER); 5831 RES_TYPE_NUMBER);
5817 if (! EQ (top, Qunbound) || ! EQ (left, Qunbound)) 5832 if (! BASE_EQ (top, Qunbound) || ! BASE_EQ (left, Qunbound))
5818 { 5833 {
5819 if (EQ (top, Qminus)) 5834 if (EQ (top, Qminus))
5820 { 5835 {
@@ -5837,7 +5852,7 @@ gui_figure_window_size (struct frame *f, Lisp_Object parms, bool tabbar_p,
5837 else if (FLOATP (top)) 5852 else if (FLOATP (top))
5838 f->top_pos = frame_float (f, top, FRAME_FLOAT_TOP, &parent_done, 5853 f->top_pos = frame_float (f, top, FRAME_FLOAT_TOP, &parent_done,
5839 &outer_done, 0); 5854 &outer_done, 0);
5840 else if (EQ (top, Qunbound)) 5855 else if (BASE_EQ (top, Qunbound))
5841 f->top_pos = 0; 5856 f->top_pos = 0;
5842 else 5857 else
5843 { 5858 {
@@ -5867,7 +5882,7 @@ gui_figure_window_size (struct frame *f, Lisp_Object parms, bool tabbar_p,
5867 else if (FLOATP (left)) 5882 else if (FLOATP (left))
5868 f->left_pos = frame_float (f, left, FRAME_FLOAT_LEFT, &parent_done, 5883 f->left_pos = frame_float (f, left, FRAME_FLOAT_LEFT, &parent_done,
5869 &outer_done, 0); 5884 &outer_done, 0);
5870 else if (EQ (left, Qunbound)) 5885 else if (BASE_EQ (left, Qunbound))
5871 f->left_pos = 0; 5886 f->left_pos = 0;
5872 else 5887 else
5873 { 5888 {
@@ -5876,7 +5891,7 @@ gui_figure_window_size (struct frame *f, Lisp_Object parms, bool tabbar_p,
5876 window_prompting |= XNegative; 5891 window_prompting |= XNegative;
5877 } 5892 }
5878 5893
5879 if (!NILP (user_position) && ! EQ (user_position, Qunbound)) 5894 if (!NILP (user_position) && ! BASE_EQ (user_position, Qunbound))
5880 window_prompting |= USPosition; 5895 window_prompting |= USPosition;
5881 else 5896 else
5882 window_prompting |= PPosition; 5897 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
127 /* This frame's selected window. 127 /* This frame's selected window.
128 Each frame has its own window hierarchy 128 Each frame has its own window hierarchy
129 and one of the windows in it is selected within the frame. 129 and one of the windows in it is selected within the frame.
130 This window may be the mini-window of the frame, if any.
130 The selected window of the selected frame is Emacs's selected window. */ 131 The selected window of the selected frame is Emacs's selected window. */
131 Lisp_Object selected_window; 132 Lisp_Object selected_window;
132 133
@@ -1292,8 +1293,28 @@ SET_FRAME_VISIBLE (struct frame *f, int v)
1292} 1293}
1293 1294
1294/* Set iconified status of frame F. */ 1295/* Set iconified status of frame F. */
1295#define SET_FRAME_ICONIFIED(f, i) \ 1296INLINE void
1296 (f)->iconified = (eassert (0 <= (i) && (i) <= 1), (i)) 1297SET_FRAME_ICONIFIED (struct frame *f, int i)
1298{
1299#ifdef HAVE_WINDOW_SYSTEM
1300 Lisp_Object frame;
1301#endif
1302
1303 eassert (0 <= (i) && (i) <= 1);
1304
1305 f->iconified = i;
1306
1307#ifdef HAVE_WINDOW_SYSTEM
1308 /* Iconifying a frame might cause the frame title to change if no
1309 title was explicitly specified. Force the frame title to be
1310 recomputed. */
1311
1312 XSETFRAME (frame, f);
1313
1314 if (FRAME_WINDOW_P (f))
1315 gui_consider_frame_title (frame);
1316#endif
1317}
1297 1318
1298extern Lisp_Object selected_frame; 1319extern Lisp_Object selected_frame;
1299extern Lisp_Object old_selected_frame; 1320extern 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/>. */
37#include "font.h" 37#include "font.h"
38#include "ftfont.h" 38#include "ftfont.h"
39#include "pdumper.h" 39#include "pdumper.h"
40#ifdef HAVE_PGTK
41#include "xsettings.h"
42#endif
40 43
41#ifdef USE_BE_CAIRO 44#ifdef USE_BE_CAIRO
42#define RED_FROM_ULONG(color) (((color) >> 16) & 0xff) 45#define RED_FROM_ULONG(color) (((color) >> 16) & 0xff)
@@ -168,7 +171,12 @@ ftcrfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
168 cairo_matrix_t font_matrix, ctm; 171 cairo_matrix_t font_matrix, ctm;
169 cairo_matrix_init_scale (&font_matrix, pixel_size, pixel_size); 172 cairo_matrix_init_scale (&font_matrix, pixel_size, pixel_size);
170 cairo_matrix_init_identity (&ctm); 173 cairo_matrix_init_identity (&ctm);
174
175#ifdef HAVE_PGTK
176 cairo_font_options_t *options = xsettings_get_font_options ();
177#else
171 cairo_font_options_t *options = cairo_font_options_create (); 178 cairo_font_options_t *options = cairo_font_options_create ();
179#endif
172#ifdef USE_BE_CAIRO 180#ifdef USE_BE_CAIRO
173 if (be_use_subpixel_antialiasing ()) 181 if (be_use_subpixel_antialiasing ())
174 cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_SUBPIXEL); 182 cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_SUBPIXEL);
@@ -624,6 +632,28 @@ ftcrfont_draw (struct glyph_string *s,
624 return len; 632 return len;
625} 633}
626 634
635#ifdef HAVE_PGTK
636/* Determine if FONT_OBJECT is a valid cached font for ENTITY by
637 comparing the options used to open it with the user's current
638 preferences specified via GSettings. */
639static bool
640ftcrfont_cached_font_ok (struct frame *f, Lisp_Object font_object,
641 Lisp_Object entity)
642{
643 struct font_info *info = (struct font_info *) XFONT_OBJECT (font_object);
644
645 cairo_font_options_t *options = cairo_font_options_create ();
646 cairo_scaled_font_get_font_options (info->cr_scaled_font, options);
647 cairo_font_options_t *gsettings_options = xsettings_get_font_options ();
648
649 bool equal = cairo_font_options_equal (options, gsettings_options);
650 cairo_font_options_destroy (options);
651 cairo_font_options_destroy (gsettings_options);
652
653 return equal;
654}
655#endif
656
627#ifdef HAVE_HARFBUZZ 657#ifdef HAVE_HARFBUZZ
628 658
629static Lisp_Object 659static Lisp_Object
@@ -694,6 +724,9 @@ struct font_driver const ftcrfont_driver =
694#endif 724#endif
695 .filter_properties = ftfont_filter_properties, 725 .filter_properties = ftfont_filter_properties,
696 .combining_capability = ftfont_combining_capability, 726 .combining_capability = ftfont_combining_capability,
727#ifdef HAVE_PGTK
728 .cached_font_ok = ftcrfont_cached_font_ok
729#endif
697 }; 730 };
698#ifdef HAVE_HARFBUZZ 731#ifdef HAVE_HARFBUZZ
699struct font_driver ftcrhbfont_driver; 732struct 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)
645 return spec; 645 return spec;
646} 646}
647 647
648#if defined HAVE_XFT && defined FC_COLOR
649static bool
650xft_color_font_whitelisted_p (const char *family)
651{
652 Lisp_Object tem, name;
653
654 tem = Vxft_color_font_whitelist;
655
656 FOR_EACH_TAIL_SAFE (tem)
657 {
658 name = XCAR (tem);
659
660 if (STRINGP (name) && !strcmp (family, SSDATA (name)))
661 return true;
662 }
663
664 return false;
665}
666#endif
667
648static FcPattern * 668static FcPattern *
649ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname) 669ftfont_spec_pattern (Lisp_Object spec, char *otlayout,
670 struct OpenTypeSpec **otspec, const char **langname)
650{ 671{
651 Lisp_Object tmp, extra; 672 Lisp_Object tmp, extra;
652 FcPattern *pattern = NULL; 673 FcPattern *pattern = NULL;
@@ -785,6 +806,8 @@ ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **ots
785 /* We really don't like color fonts, they cause Xft crashes. See 806 /* We really don't like color fonts, they cause Xft crashes. See
786 Bug#30874. */ 807 Bug#30874. */
787 if (xft_ignore_color_fonts 808 if (xft_ignore_color_fonts
809 && (NILP (AREF (spec, FONT_FAMILY_INDEX))
810 || NILP (Vxft_color_font_whitelist))
788 && ! FcPatternAddBool (pattern, FC_COLOR, FcFalse)) 811 && ! FcPatternAddBool (pattern, FC_COLOR, FcFalse))
789 goto err; 812 goto err;
790#endif 813#endif
@@ -930,7 +953,12 @@ ftfont_list (struct frame *f, Lisp_Object spec)
930 returns them even when it shouldn't really do so, so we 953 returns them even when it shouldn't really do so, so we
931 need to manually skip them here (Bug#37786). */ 954 need to manually skip them here (Bug#37786). */
932 FcBool b; 955 FcBool b;
956 FcChar8 *str;
957
933 if (xft_ignore_color_fonts 958 if (xft_ignore_color_fonts
959 && (FcPatternGetString (fontset->fonts[i], FC_FAMILY,
960 0, &str) != FcResultMatch
961 || !xft_color_font_whitelisted_p ((char *) str))
934 && FcPatternGetBool (fontset->fonts[i], FC_COLOR, 0, &b) 962 && FcPatternGetBool (fontset->fonts[i], FC_COLOR, 0, &b)
935 == FcResultMatch && b != FcFalse) 963 == FcResultMatch && b != FcFalse)
936 continue; 964 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,
736 const char *color_name, 736 const char *color_name,
737 Emacs_Color *color) 737 Emacs_Color *color)
738{ 738{
739 bool success_p = 0; 739 bool success_p;
740 bool get_bg = strcmp ("gtk_selection_bg_color", color_name) == 0; 740 bool get_bg;
741 bool get_fg = !get_bg && strcmp ("gtk_selection_fg_color", color_name) == 0; 741 bool get_fg;
742#ifdef HAVE_GTK3
743 GtkStyleContext *gsty;
744 GdkRGBA col;
745 char buf[sizeof "rgb://rrrr/gggg/bbbb"];
746 int state;
747 GdkRGBA *c;
748 unsigned short r, g, b;
749#else
750 GtkStyle *gsty;
751 GdkColor *grgb;
752#endif
753
754 get_bg = !strcmp ("gtk_selection_bg_color", color_name);
755 get_fg = !get_bg && !strcmp ("gtk_selection_fg_color", color_name);
756 success_p = false;
742 757
743 if (! FRAME_GTK_WIDGET (f) || ! (get_bg || get_fg)) 758#ifdef HAVE_PGTK
759 while (FRAME_PARENT_FRAME (f))
760 f = FRAME_PARENT_FRAME (f);
761#endif
762
763 if (!FRAME_GTK_WIDGET (f) || !(get_bg || get_fg))
744 return success_p; 764 return success_p;
745 765
746 block_input (); 766 block_input ();
747 {
748#ifdef HAVE_GTK3 767#ifdef HAVE_GTK3
749#ifndef HAVE_PGTK 768 gsty = gtk_widget_get_style_context (FRAME_GTK_OUTER_WIDGET (f));
750 GtkStyleContext *gsty 769 state = GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_FOCUSED;
751 = gtk_widget_get_style_context (FRAME_GTK_OUTER_WIDGET (f));
752#else
753 GtkStyleContext *gsty
754 = gtk_widget_get_style_context (FRAME_WIDGET (f));
755#endif
756 GdkRGBA col;
757 char buf[sizeof "rgb://rrrr/gggg/bbbb"];
758 int state = GTK_STATE_FLAG_SELECTED|GTK_STATE_FLAG_FOCUSED;
759 if (get_fg)
760 gtk_style_context_get_color (gsty, state, &col);
761 else
762 {
763 GdkRGBA *c;
764 /* FIXME: Retrieving the background color is deprecated in
765 GTK+ 3.16. New versions of GTK+ don't use the concept of a
766 single background color any more, so we shouldn't query for
767 it. */
768 gtk_style_context_get (gsty, state,
769 GTK_STYLE_PROPERTY_BACKGROUND_COLOR, &c,
770 NULL);
771 col = *c;
772 gdk_rgba_free (c);
773 }
774 770
775 unsigned short 771 if (get_fg)
776 r = col.red * 65535, 772 gtk_style_context_get_color (gsty, state, &col);
777 g = col.green * 65535, 773 else
778 b = col.blue * 65535; 774 {
775 /* FIXME: Retrieving the background color is deprecated in
776 GTK+ 3.16. New versions of GTK+ don't use the concept of a
777 single background color any more, so we shouldn't query for
778 it. */
779 gtk_style_context_get (gsty, state,
780 GTK_STYLE_PROPERTY_BACKGROUND_COLOR, &c,
781 NULL);
782 col = *c;
783 gdk_rgba_free (c);
784 }
785
786 r = col.red * 65535;
787 g = col.green * 65535;
788 b = col.blue * 65535;
779#ifndef HAVE_PGTK 789#ifndef HAVE_PGTK
780 sprintf (buf, "rgb:%04x/%04x/%04x", r, g, b); 790 sprintf (buf, "rgb:%04x/%04x/%04x", r, g, b);
781 success_p = x_parse_color (f, buf, color) != 0; 791 success_p = x_parse_color (f, buf, color) != 0;
782#else 792#else
783 sprintf (buf, "#%04x%04x%04x", r, g, b); 793 sprintf (buf, "#%04x%04x%04x", r, g, b);
784 success_p = pgtk_parse_color (f, buf, color) != 0; 794 success_p = pgtk_parse_color (f, buf, color) != 0;
785#endif 795#endif
786#else 796#else
787 GtkStyle *gsty = gtk_widget_get_style (FRAME_GTK_WIDGET (f)); 797 gsty = gtk_widget_get_style (FRAME_GTK_WIDGET (f));
788 GdkColor *grgb = get_bg 798 grgb = (get_bg ? &gsty->bg[GTK_STATE_SELECTED]
789 ? &gsty->bg[GTK_STATE_SELECTED] 799 : &gsty->fg[GTK_STATE_SELECTED]);
790 : &gsty->fg[GTK_STATE_SELECTED];
791 800
792 color->red = grgb->red; 801 color->red = grgb->red;
793 color->green = grgb->green; 802 color->green = grgb->green;
794 color->blue = grgb->blue; 803 color->blue = grgb->blue;
795 color->pixel = grgb->pixel; 804 color->pixel = grgb->pixel;
796 success_p = 1; 805 success_p = 1;
797#endif 806#endif
798
799 }
800 unblock_input (); 807 unblock_input ();
801 return success_p; 808 return success_p;
802} 809}
@@ -6395,6 +6402,9 @@ xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event,
6395 if (!f) 6402 if (!f)
6396 return true; 6403 return true;
6397 6404
6405 if (popup_activated ())
6406 return true;
6407
6398#ifdef HAVE_XINPUT2 6408#ifdef HAVE_XINPUT2
6399 pending_keystroke_time 6409 pending_keystroke_time
6400 = FRAME_DISPLAY_INFO (f)->pending_keystroke_time; 6410 = 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,
285 BView *vw = get_view (view); 285 BView *vw = get_view (view);
286 BBitmap *bm = (BBitmap *) bitmap; 286 BBitmap *bm = (BBitmap *) bitmap;
287 287
288 vw->PushState ();
289 vw->SetDrawingMode (B_OP_OVER); 288 vw->SetDrawingMode (B_OP_OVER);
290 vw->DrawBitmap (bm, BRect (x, y, x + width - 1, y + height - 1), 289 vw->DrawBitmap (bm, BRect (x, y, x + width - 1, y + height - 1),
291 BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1)); 290 BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1));
292 vw->PopState (); 291 vw->SetDrawingMode (B_OP_COPY);
292}
293
294void
295BView_DrawBitmapTiled (void *view, void *bitmap, int x, int y,
296 int width, int height, int vx, int vy,
297 int vwidth, int vheight)
298{
299 BView *vw = get_view (view);
300 BBitmap *bm = (BBitmap *) bitmap;
301 BRect bounds = bm->Bounds ();
302
303 if (width == -1)
304 width = BE_RECT_WIDTH (bounds);
305
306 if (height == -1)
307 height = BE_RECT_HEIGHT (bounds);
308
309 vw->SetDrawingMode (B_OP_OVER);
310 vw->DrawBitmap (bm, BRect (x, y, x + width - 1, y + height - 1),
311 BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1),
312 B_TILE_BITMAP);
313 vw->SetDrawingMode (B_OP_COPY);
293} 314}
294 315
295void 316void
@@ -300,17 +321,22 @@ BView_DrawBitmapWithEraseOp (void *view, void *bitmap, int x,
300 BBitmap *bm = (BBitmap *) bitmap; 321 BBitmap *bm = (BBitmap *) bitmap;
301 BBitmap bc (bm->Bounds (), B_RGBA32); 322 BBitmap bc (bm->Bounds (), B_RGBA32);
302 BRect rect (x, y, x + width - 1, y + height - 1); 323 BRect rect (x, y, x + width - 1, y + height - 1);
324 uint32_t *bits;
325 size_t stride;
326 rgb_color low_color;
327 BRect bounds;
303 328
304 if (bc.InitCheck () != B_OK || bc.ImportBits (bm) != B_OK) 329 if (bc.InitCheck () != B_OK || bc.ImportBits (bm) != B_OK)
305 return; 330 return;
306 331
307 uint32_t *bits = (uint32_t *) bc.Bits (); 332 bits = (uint32_t *) bc.Bits ();
308 size_t stride = bc.BytesPerRow (); 333 stride = bc.BytesPerRow ();
309 334
310 if (bm->ColorSpace () == B_GRAY1) 335 if (bm->ColorSpace () == B_GRAY1)
311 { 336 {
312 rgb_color low_color = vw->LowColor (); 337 low_color = vw->LowColor ();
313 BRect bounds = bc.Bounds (); 338 bounds = bc.Bounds ();
339
314 for (int y = 0; y < BE_RECT_HEIGHT (bounds); ++y) 340 for (int y = 0; y < BE_RECT_HEIGHT (bounds); ++y)
315 { 341 {
316 for (int x = 0; x < BE_RECT_WIDTH (bounds); ++x) 342 for (int x = 0; x < BE_RECT_WIDTH (bounds); ++x)
@@ -323,10 +349,11 @@ BView_DrawBitmapWithEraseOp (void *view, void *bitmap, int x,
323 } 349 }
324 } 350 }
325 351
326 vw->PushState (); 352 vw->SetDrawingMode ((bm->ColorSpace ()
327 vw->SetDrawingMode (bm->ColorSpace () == B_GRAY1 ? B_OP_OVER : B_OP_ERASE); 353 == B_GRAY1)
354 ? B_OP_OVER : B_OP_ERASE);
328 vw->DrawBitmap (&bc, rect); 355 vw->DrawBitmap (&bc, rect);
329 vw->PopState (); 356 vw->SetDrawingMode (B_OP_COPY);
330} 357}
331 358
332void 359void
@@ -357,6 +384,7 @@ BView_DrawMask (void *src, void *view,
357 vw->SetDrawingMode (B_OP_OVER); 384 vw->SetDrawingMode (B_OP_OVER);
358 vw->DrawBitmap (&bm, BRect (x, y, x + width - 1, y + height - 1), 385 vw->DrawBitmap (&bm, BRect (x, y, x + width - 1, y + height - 1),
359 BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1)); 386 BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1));
387 vw->SetDrawingMode (B_OP_COPY);
360} 388}
361 389
362static BBitmap * 390static BBitmap *
@@ -475,3 +503,40 @@ BView_InvertRect (void *view, int x, int y, int width, int height)
475 503
476 vw->InvertRect (BRect (x, y, x + width - 1, y + height - 1)); 504 vw->InvertRect (BRect (x, y, x + width - 1, y + height - 1));
477} 505}
506
507static void
508be_draw_cross_on_pixmap_1 (BBitmap *bitmap, int x, int y, int width,
509 int height, uint32_t color)
510{
511 BBitmap dest (bitmap->Bounds (),
512 bitmap->ColorSpace (),
513 true, false);
514 BView view (bitmap->Bounds (), NULL, B_FOLLOW_NONE, 0);
515 rgb_color high_color;
516
517 rgb32_to_rgb_color (color, &high_color);
518 dest.ImportBits (bitmap);
519
520 if (!dest.Lock ())
521 return;
522
523 dest.AddChild (&view);
524
525 view.SetHighColor (high_color);
526 view.StrokeLine (BPoint (x, y),
527 BPoint (x + width - 1, y + height - 1));
528 view.StrokeLine (BPoint (x, y + height - 1),
529 BPoint (x + width - 1, y));
530 view.RemoveSelf ();
531 bitmap->ImportBits (&dest);
532}
533
534void
535be_draw_cross_on_pixmap (void *bitmap, int x, int y, int width,
536 int height, uint32_t color)
537{
538 BBitmap *target = (BBitmap *) bitmap;
539
540 be_draw_cross_on_pixmap_1 (target, x, y, width, height,
541 color);
542}
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)
105 return sizeof (struct haiku_menu_bar_left_event); 105 return sizeof (struct haiku_menu_bar_left_event);
106 case SCROLL_BAR_PART_EVENT: 106 case SCROLL_BAR_PART_EVENT:
107 return sizeof (struct haiku_scroll_bar_part_event); 107 return sizeof (struct haiku_scroll_bar_part_event);
108 case SCREEN_CHANGED_EVENT:
109 return sizeof (struct haiku_screen_changed_event);
108 } 110 }
109 111
110 emacs_abort (); 112 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/>. */
28 28
29#include "haikuselect.h" 29#include "haikuselect.h"
30 30
31/* The clipboard object representing the primary selection. */
31static BClipboard *primary = NULL; 32static BClipboard *primary = NULL;
33
34/* The clipboard object representing the secondary selection. */
32static BClipboard *secondary = NULL; 35static BClipboard *secondary = NULL;
36
37/* The clipboard object used by other programs, representing the
38 clipboard. */
33static BClipboard *system_clipboard = NULL; 39static BClipboard *system_clipboard = NULL;
40
41/* The number of times the system clipboard has changed. */
34static int64 count_clipboard = -1; 42static int64 count_clipboard = -1;
43
44/* The number of times the primary selection has changed. */
35static int64 count_primary = -1; 45static int64 count_primary = -1;
46
47/* The number of times the secondary selection has changed. */
36static int64 count_secondary = -1; 48static int64 count_secondary = -1;
37 49
50static BClipboard *
51get_clipboard_object (enum haiku_clipboard clipboard)
52{
53 switch (clipboard)
54 {
55 case CLIPBOARD_PRIMARY:
56 return primary;
57
58 case CLIPBOARD_SECONDARY:
59 return secondary;
60
61 case CLIPBOARD_CLIPBOARD:
62 return system_clipboard;
63 }
64
65 abort ();
66}
67
38static char * 68static char *
39BClipboard_find_data (BClipboard *cb, const char *type, ssize_t *len) 69be_find_clipboard_data_1 (BClipboard *cb, const char *type, ssize_t *len)
40{ 70{
71 BMessage *data;
72 const char *ptr;
73 ssize_t nbytes;
74 void *value;
75
41 if (!cb->Lock ()) 76 if (!cb->Lock ())
42 return 0; 77 return NULL;
78
79 data = cb->Data ();
43 80
44 BMessage *dat = cb->Data (); 81 if (!data)
45 if (!dat)
46 { 82 {
47 cb->Unlock (); 83 cb->Unlock ();
48 return 0; 84 return NULL;
49 } 85 }
50 86
51 const char *ptr; 87 data->FindData (type, B_MIME_TYPE, (const void **) &ptr,
52 ssize_t bt; 88 &nbytes);
53 dat->FindData (type, B_MIME_TYPE, (const void **) &ptr, &bt);
54 89
55 if (!ptr) 90 if (!ptr)
56 { 91 {
@@ -59,9 +94,9 @@ BClipboard_find_data (BClipboard *cb, const char *type, ssize_t *len)
59 } 94 }
60 95
61 if (len) 96 if (len)
62 *len = bt; 97 *len = nbytes;
63 98
64 void *data = malloc (bt); 99 value = malloc (nbytes);
65 100
66 if (!data) 101 if (!data)
67 { 102 {
@@ -69,13 +104,14 @@ BClipboard_find_data (BClipboard *cb, const char *type, ssize_t *len)
69 return NULL; 104 return NULL;
70 } 105 }
71 106
72 memcpy (data, ptr, bt); 107 memcpy (value, ptr, nbytes);
73 cb->Unlock (); 108 cb->Unlock ();
74 return (char *) data; 109
110 return (char *) value;
75} 111}
76 112
77static void 113static void
78BClipboard_get_targets (BClipboard *cb, char **buf, int buf_size) 114be_get_clipboard_targets_1 (BClipboard *cb, char **buf, int buf_size)
79{ 115{
80 BMessage *data; 116 BMessage *data;
81 char *name; 117 char *name;
@@ -122,142 +158,125 @@ BClipboard_get_targets (BClipboard *cb, char **buf, int buf_size)
122} 158}
123 159
124static void 160static void
125BClipboard_set_data (BClipboard *cb, const char *type, const char *dat, 161be_set_clipboard_data_1 (BClipboard *cb, const char *type, const char *data,
126 ssize_t len, bool clear) 162 ssize_t len, bool clear)
127{ 163{
164 BMessage *message_data;
165
128 if (!cb->Lock ()) 166 if (!cb->Lock ())
129 return; 167 return;
130 168
131 if (clear) 169 if (clear)
132 cb->Clear (); 170 cb->Clear ();
133 171
134 BMessage *mdat = cb->Data (); 172 message_data = cb->Data ();
135 if (!mdat) 173
174 if (!message_data)
136 { 175 {
137 cb->Unlock (); 176 cb->Unlock ();
138 return; 177 return;
139 } 178 }
140 179
141 if (dat) 180 if (data)
142 { 181 {
143 if (mdat->ReplaceData (type, B_MIME_TYPE, dat, len) 182 if (message_data->ReplaceData (type, B_MIME_TYPE, data, len)
144 == B_NAME_NOT_FOUND) 183 == B_NAME_NOT_FOUND)
145 mdat->AddData (type, B_MIME_TYPE, dat, len); 184 message_data->AddData (type, B_MIME_TYPE, data, len);
146 } 185 }
147 else 186 else
148 mdat->RemoveName (type); 187 message_data->RemoveName (type);
188
149 cb->Commit (); 189 cb->Commit ();
150 cb->Unlock (); 190 cb->Unlock ();
151} 191}
152 192
153char *
154BClipboard_find_system_data (const char *type, ssize_t *len)
155{
156 if (!system_clipboard)
157 return 0;
158
159 return BClipboard_find_data (system_clipboard, type, len);
160}
161
162char *
163BClipboard_find_primary_selection_data (const char *type, ssize_t *len)
164{
165 if (!primary)
166 return 0;
167
168 return BClipboard_find_data (primary, type, len);
169}
170
171char *
172BClipboard_find_secondary_selection_data (const char *type, ssize_t *len)
173{
174 if (!secondary)
175 return 0;
176
177 return BClipboard_find_data (secondary, type, len);
178}
179
180void
181BClipboard_set_system_data (const char *type, const char *data,
182 ssize_t len, bool clear)
183{
184 if (!system_clipboard)
185 return;
186
187 count_clipboard = system_clipboard->SystemCount ();
188 BClipboard_set_data (system_clipboard, type, data, len, clear);
189}
190
191void 193void
192BClipboard_set_primary_selection_data (const char *type, const char *data, 194be_update_clipboard_count (enum haiku_clipboard id)
193 ssize_t len, bool clear)
194{ 195{
195 if (!primary) 196 switch (id)
196 return; 197 {
198 case CLIPBOARD_CLIPBOARD:
199 count_clipboard = system_clipboard->SystemCount ();
200 break;
197 201
198 count_primary = primary->SystemCount (); 202 case CLIPBOARD_PRIMARY:
199 BClipboard_set_data (primary, type, data, len, clear); 203 count_primary = primary->SystemCount ();
200} 204 break;
201 205
202void 206 case CLIPBOARD_SECONDARY:
203BClipboard_set_secondary_selection_data (const char *type, const char *data, 207 count_secondary = secondary->SystemCount ();
204 ssize_t len, bool clear) 208 break;
205{ 209 }
206 if (!secondary)
207 return;
208
209 count_secondary = secondary->SystemCount ();
210 BClipboard_set_data (secondary, type, data, len, clear);
211} 210}
212 211
213void 212char *
214BClipboard_free_data (void *ptr) 213be_find_clipboard_data (enum haiku_clipboard id, const char *type,
214 ssize_t *len)
215{ 215{
216 std::free (ptr); 216 return be_find_clipboard_data_1 (get_clipboard_object (id),
217 type, len);
217} 218}
218 219
219void 220void
220BClipboard_system_targets (char **buf, int len) 221be_set_clipboard_data (enum haiku_clipboard id, const char *type,
222 const char *data, ssize_t len, bool clear)
221{ 223{
222 BClipboard_get_targets (system_clipboard, buf, len); 224 be_update_clipboard_count (id);
223}
224 225
225void 226 be_set_clipboard_data_1 (get_clipboard_object (id), type,
226BClipboard_primary_targets (char **buf, int len) 227 data, len, clear);
227{
228 BClipboard_get_targets (primary, buf, len);
229} 228}
230 229
231void 230void
232BClipboard_secondary_targets (char **buf, int len) 231be_get_clipboard_targets (enum haiku_clipboard id, char **targets,
232 int len)
233{ 233{
234 BClipboard_get_targets (secondary, buf, len); 234 be_get_clipboard_targets_1 (get_clipboard_object (id), targets,
235 len);
235} 236}
236 237
237bool 238static bool
238BClipboard_owns_clipboard (void) 239clipboard_owner_p (void)
239{ 240{
240 return (count_clipboard >= 0 241 return (count_clipboard >= 0
241 && (count_clipboard + 1 242 && (count_clipboard + 1
242 == system_clipboard->SystemCount ())); 243 == system_clipboard->SystemCount ()));
243} 244}
244 245
245bool 246static bool
246BClipboard_owns_primary (void) 247primary_owner_p (void)
247{ 248{
248 return (count_primary >= 0 249 return (count_primary >= 0
249 && (count_primary + 1 250 && (count_primary + 1
250 == primary->SystemCount ())); 251 == primary->SystemCount ()));
251} 252}
252 253
253bool 254static bool
254BClipboard_owns_secondary (void) 255secondary_owner_p (void)
255{ 256{
256 return (count_secondary >= 0 257 return (count_secondary >= 0
257 && (count_secondary + 1 258 && (count_secondary + 1
258 == secondary->SystemCount ())); 259 == secondary->SystemCount ()));
259} 260}
260 261
262bool
263be_clipboard_owner_p (enum haiku_clipboard clipboard)
264{
265 switch (clipboard)
266 {
267 case CLIPBOARD_PRIMARY:
268 return primary_owner_p ();
269
270 case CLIPBOARD_SECONDARY:
271 return secondary_owner_p ();
272
273 case CLIPBOARD_CLIPBOARD:
274 return clipboard_owner_p ();
275 }
276
277 abort ();
278}
279
261void 280void
262init_haiku_select (void) 281init_haiku_select (void)
263{ 282{
@@ -443,12 +462,7 @@ be_lock_clipboard_message (enum haiku_clipboard clipboard,
443{ 462{
444 BClipboard *board; 463 BClipboard *board;
445 464
446 if (clipboard == CLIPBOARD_PRIMARY) 465 board = get_clipboard_object (clipboard);
447 board = primary;
448 else if (clipboard == CLIPBOARD_SECONDARY)
449 board = secondary;
450 else
451 board = system_clipboard;
452 466
453 if (!board->Lock ()) 467 if (!board->Lock ())
454 return 1; 468 return 1;
@@ -465,12 +479,7 @@ be_unlock_clipboard (enum haiku_clipboard clipboard, bool discard)
465{ 479{
466 BClipboard *board; 480 BClipboard *board;
467 481
468 if (clipboard == CLIPBOARD_PRIMARY) 482 board = get_clipboard_object (clipboard);
469 board = primary;
470 else if (clipboard == CLIPBOARD_SECONDARY)
471 board = secondary;
472 else
473 board = system_clipboard;
474 483
475 if (discard) 484 if (discard)
476 board->Revert (); 485 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
17along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ 17along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
18 18
19#include <config.h> 19#include <config.h>
20#include <attribute.h>
20 21
21#include <app/Application.h> 22#include <app/Application.h>
22#include <app/Cursor.h> 23#include <app/Cursor.h>
23#include <app/Messenger.h> 24#include <app/Messenger.h>
25#include <app/Roster.h>
24 26
25#include <interface/GraphicsDefs.h> 27#include <interface/GraphicsDefs.h>
26#include <interface/InterfaceDefs.h> 28#include <interface/InterfaceDefs.h>
@@ -81,8 +83,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
81#include <csignal> 83#include <csignal>
82#include <cfloat> 84#include <cfloat>
83 85
84#include <pthread.h>
85
86#ifdef USE_BE_CAIRO 86#ifdef USE_BE_CAIRO
87#include <cairo.h> 87#include <cairo.h>
88#endif 88#endif
@@ -107,6 +107,7 @@ enum
107 SET_FONT_INDICES = 3012, 107 SET_FONT_INDICES = 3012,
108 SET_PREVIEW_DIALOG = 3013, 108 SET_PREVIEW_DIALOG = 3013,
109 UPDATE_PREVIEW_DIALOG = 3014, 109 UPDATE_PREVIEW_DIALOG = 3014,
110 SEND_MOVE_FRAME_EVENT = 3015,
110 }; 111 };
111 112
112/* X11 keysyms that we use. */ 113/* X11 keysyms that we use. */
@@ -142,7 +143,7 @@ struct font_selection_dialog_message
142 /* Whether or not font selection was cancelled. */ 143 /* Whether or not font selection was cancelled. */
143 bool_bf cancel : 1; 144 bool_bf cancel : 1;
144 145
145 /* Whether or not a size was explictly specified. */ 146 /* Whether or not a size was explicitly specified. */
146 bool_bf size_specified : 1; 147 bool_bf size_specified : 1;
147 148
148 /* The index of the selected font family. */ 149 /* The index of the selected font family. */
@@ -155,44 +156,45 @@ struct font_selection_dialog_message
155 int size; 156 int size;
156}; 157};
157 158
159/* The color space of the main screen. B_NO_COLOR_SPACE means it has
160 not yet been computed. */
158static color_space dpy_color_space = B_NO_COLOR_SPACE; 161static color_space dpy_color_space = B_NO_COLOR_SPACE;
159static key_map *key_map = NULL; 162
160static char *key_chars = NULL; 163/* The keymap, or NULL if it has not been initialized. */
164static key_map *key_map;
165
166/* Indices of characters into the keymap. */
167static char *key_chars;
168
169/* Lock around keymap data, since it's touched from different
170 threads. */
161static BLocker key_map_lock; 171static BLocker key_map_lock;
162 172
163/* The locking semantics of BWindows running in multiple threads are 173/* The locking semantics of BWindows running in multiple threads are
164 so complex that child frame state (which is the only state that is 174 so complex that child frame state (which is the only state that is
165 shared between different BWindows at runtime) does best with a 175 shared between different BWindows at runtime) does best with a
166 single global lock. */ 176 single global lock. */
167
168static BLocker child_frame_lock; 177static BLocker child_frame_lock;
169 178
170/* A LeaveNotify event (well, the closest equivalent on Haiku, which 179/* Variable where the popup menu thread returns the chosen menu
171 is a B_MOUSE_MOVED event with `transit' set to B_EXITED_VIEW) might 180 item. */
172 be sent out-of-order with regards to motion events from other
173 windows, such as when the mouse pointer rapidly moves from an
174 undecorated child frame to its parent. This can cause a failure to
175 clear the mouse face on the former if an event for the latter is
176 read by Emacs first and ends up showing the mouse face there.
177
178 While this lock doesn't really ensure that the events will be
179 delivered in the correct order, it makes them arrive in the correct
180 order "most of the time" on my machine, which is good enough and
181 preferable to adding a lot of extra complexity to the event
182 handling code to sort motion events by their timestamps.
183
184 Obviously this depends on the number of execution units that are
185 available, and the scheduling priority of each thread involved in
186 the input handling, but it will be good enough for most people. */
187
188static BLocker movement_locker;
189
190static BMessage volatile *popup_track_message; 181static BMessage volatile *popup_track_message;
182
183/* Variable in which alert dialog threads return the selected button
184 number. */
191static int32 volatile alert_popup_value; 185static int32 volatile alert_popup_value;
186
187/* The current window ID. This is increased every time a frame is
188 created. */
192static int current_window_id; 189static int current_window_id;
193 190
194static void *grab_view = NULL; 191/* The view that has the passive grab. */
192static void *grab_view;
193
194/* The locker for that variable. */
195static BLocker grab_view_locker; 195static BLocker grab_view_locker;
196
197/* Whether or not a drag-and-drop operation is in progress. */
196static bool drag_and_drop_in_progress; 198static bool drag_and_drop_in_progress;
197 199
198/* Many places require us to lock the child frame data, and then lock 200/* 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)
448 key_map_lock.Unlock (); 450 key_map_lock.Unlock ();
449} 451}
450 452
453static BRect
454get_zoom_rect (BWindow *window)
455{
456 BScreen screen;
457 BDeskbar deskbar;
458 BRect screen_frame;
459 BRect frame;
460 BRect deskbar_frame;
461 BRect window_frame;
462 BRect decorator_frame;
463
464 if (!screen.IsValid ())
465 gui_abort ("Failed to calculate screen rect");
466
467 screen_frame = frame = screen.Frame ();
468 deskbar_frame = deskbar.Frame ();
469
470 if (!(modifiers () & B_SHIFT_KEY) && !deskbar.IsAutoHide ())
471 {
472 switch (deskbar.Location ())
473 {
474 case B_DESKBAR_TOP:
475 frame.top = deskbar_frame.bottom + 2;
476 break;
477
478 case B_DESKBAR_BOTTOM:
479 case B_DESKBAR_LEFT_BOTTOM:
480 case B_DESKBAR_RIGHT_BOTTOM:
481 frame.bottom = deskbar_frame.top - 2;
482 break;
483
484 case B_DESKBAR_LEFT_TOP:
485 if (!deskbar.IsExpanded ())
486 frame.top = deskbar_frame.bottom + 2;
487 else if (!deskbar.IsAlwaysOnTop ()
488 && !deskbar.IsAutoRaise ())
489 frame.left = deskbar_frame.right + 2;
490 break;
491
492 default:
493 if (deskbar.IsExpanded ()
494 && !deskbar.IsAlwaysOnTop ()
495 && !deskbar.IsAutoRaise ())
496 frame.right = deskbar_frame.left - 2;
497 }
498 }
499
500 if (window)
501 {
502 window_frame = window->Frame ();
503 decorator_frame = window->DecoratorFrame ();
504
505 frame.top += (window_frame.top
506 - decorator_frame.top);
507 frame.bottom -= (decorator_frame.bottom
508 - window_frame.bottom);
509 frame.left += (window_frame.left
510 - decorator_frame.left);
511 frame.right -= (decorator_frame.right
512 - window_frame.right);
513
514 if (frame.top > deskbar_frame.bottom
515 || frame.bottom < deskbar_frame.top)
516 {
517 frame.left = screen_frame.left + (window_frame.left
518 - decorator_frame.left);
519 frame.right = screen_frame.right - (decorator_frame.right
520 - window_frame.right);
521 }
522 }
523
524 return frame;
525}
526
527/* Invisible window used to get B_SCREEN_CHANGED events. */
528class EmacsScreenChangeMonitor : public BWindow
529{
530 BRect previous_screen_frame;
531
532public:
533 EmacsScreenChangeMonitor (void) : BWindow (BRect (-100, -100, 0, 0), "",
534 B_NO_BORDER_WINDOW_LOOK,
535 B_FLOATING_ALL_WINDOW_FEEL,
536 B_AVOID_FRONT | B_AVOID_FOCUS)
537 {
538 BScreen screen (this);
539
540 if (!screen.IsValid ())
541 return;
542
543 previous_screen_frame = screen.Frame ();
544
545 /* Immediately show this window upon creation. It will not steal
546 the focus or become visible. */
547 Show ();
548
549 if (!LockLooper ())
550 return;
551
552 Hide ();
553 UnlockLooper ();
554 }
555
556 void
557 DispatchMessage (BMessage *msg, BHandler *handler)
558 {
559 struct haiku_screen_changed_event rq;
560 BRect frame;
561
562 if (msg->what == B_SCREEN_CHANGED)
563 {
564 if (msg->FindInt64 ("when", &rq.when) != B_OK)
565 rq.when = 0;
566
567 if (msg->FindRect ("frame", &frame) != B_OK
568 || frame != previous_screen_frame)
569 {
570 haiku_write (SCREEN_CHANGED_EVENT, &rq);
571
572 if (frame.IsValid ())
573 previous_screen_frame = frame;
574 }
575 }
576
577 BWindow::DispatchMessage (msg, handler);
578 }
579};
580
451class Emacs : public BApplication 581class Emacs : public BApplication
452{ 582{
453public: 583public:
454 BMessage settings; 584 BMessage settings;
455 bool settings_valid_p = false; 585 bool settings_valid_p;
586 EmacsScreenChangeMonitor *monitor;
456 587
457 Emacs () : BApplication ("application/x-vnd.GNU-emacs") 588 Emacs (void) : BApplication ("application/x-vnd.GNU-emacs"),
589 settings_valid_p (false)
458 { 590 {
459 BPath settings_path; 591 BPath settings_path;
460 592
@@ -470,6 +602,15 @@ public:
470 return; 602 return;
471 603
472 settings_valid_p = true; 604 settings_valid_p = true;
605 monitor = new EmacsScreenChangeMonitor;
606 }
607
608 ~Emacs (void)
609 {
610 if (monitor->LockLooper ())
611 monitor->Quit ();
612 else
613 delete monitor;
473 } 614 }
474 615
475 void 616 void
@@ -518,33 +659,42 @@ public:
518 struct child_frame *next; 659 struct child_frame *next;
519 int xoff, yoff; 660 int xoff, yoff;
520 EmacsWindow *window; 661 EmacsWindow *window;
521 } *subset_windows = NULL; 662 } *subset_windows;
522 663
523 EmacsWindow *parent = NULL; 664 EmacsWindow *parent;
524 BRect pre_fullscreen_rect; 665 BRect pre_fullscreen_rect;
525 BRect pre_zoom_rect; 666 BRect pre_zoom_rect;
526 int x_before_zoom = INT_MIN; 667 int x_before_zoom;
527 int y_before_zoom = INT_MIN; 668 int y_before_zoom;
528 bool fullscreen_p = false; 669 bool shown_flag;
529 bool zoomed_p = false; 670 volatile bool was_shown_p;
530 bool shown_flag = false; 671 bool menu_bar_active_p;
531 volatile int was_shown_p = 0; 672 bool override_redirect_p;
532 bool menu_bar_active_p = false;
533 bool override_redirect_p = false;
534 window_look pre_override_redirect_look; 673 window_look pre_override_redirect_look;
535 window_feel pre_override_redirect_feel; 674 window_feel pre_override_redirect_feel;
536 uint32 pre_override_redirect_workspaces; 675 uint32 pre_override_redirect_workspaces;
537 int window_id; 676 int window_id;
538 bool *menus_begun = NULL; 677 bool *menus_begun;
539 enum haiku_z_group z_group; 678 enum haiku_z_group z_group;
540 bool tooltip_p = false; 679 bool tooltip_p;
680 enum haiku_fullscreen_mode fullscreen_mode;
541 681
542 EmacsWindow () : BWindow (BRect (0, 0, 0, 0), "", B_TITLED_WINDOW_LOOK, 682 EmacsWindow () : BWindow (BRect (0, 0, 0, 0), "", B_TITLED_WINDOW_LOOK,
543 B_NORMAL_WINDOW_FEEL, B_NO_SERVER_SIDE_WINDOW_MODIFIERS) 683 B_NORMAL_WINDOW_FEEL, B_NO_SERVER_SIDE_WINDOW_MODIFIERS),
684 subset_windows (NULL),
685 parent (NULL),
686 x_before_zoom (INT_MIN),
687 y_before_zoom (INT_MIN),
688 shown_flag (false),
689 was_shown_p (false),
690 menu_bar_active_p (false),
691 override_redirect_p (false),
692 window_id (current_window_id),
693 menus_begun (NULL),
694 z_group (Z_GROUP_NONE),
695 tooltip_p (false),
696 fullscreen_mode (FULLSCREEN_MODE_NONE)
544 { 697 {
545 window_id = current_window_id++;
546 z_group = Z_GROUP_NONE;
547
548 /* This pulse rate is used by scroll bars for repeating a button 698 /* This pulse rate is used by scroll bars for repeating a button
549 action while a button is held down. */ 699 action while a button is held down. */
550 SetPulseRate (30000); 700 SetPulseRate (30000);
@@ -583,77 +733,6 @@ public:
583 SetFeel (B_NORMAL_WINDOW_FEEL); 733 SetFeel (B_NORMAL_WINDOW_FEEL);
584 } 734 }
585 735
586 BRect
587 CalculateZoomRect (void)
588 {
589 BScreen screen (this);
590 BDeskbar deskbar;
591 BRect screen_frame;
592 BRect frame;
593 BRect deskbar_frame;
594 BRect window_frame;
595 BRect decorator_frame;
596
597 if (!screen.IsValid ())
598 gui_abort ("Failed to calculate screen rect");
599
600 screen_frame = frame = screen.Frame ();
601 deskbar_frame = deskbar.Frame ();
602
603 if (!(modifiers () & B_SHIFT_KEY) && !deskbar.IsAutoHide ())
604 {
605 switch (deskbar.Location ())
606 {
607 case B_DESKBAR_TOP:
608 frame.top = deskbar_frame.bottom + 2;
609 break;
610
611 case B_DESKBAR_BOTTOM:
612 case B_DESKBAR_LEFT_BOTTOM:
613 case B_DESKBAR_RIGHT_BOTTOM:
614 frame.bottom = deskbar_frame.top - 2;
615 break;
616
617 case B_DESKBAR_LEFT_TOP:
618 if (!deskbar.IsExpanded ())
619 frame.top = deskbar_frame.bottom + 2;
620 else if (!deskbar.IsAlwaysOnTop ()
621 && !deskbar.IsAutoRaise ())
622 frame.left = deskbar_frame.right + 2;
623 break;
624
625 default:
626 if (deskbar.IsExpanded ()
627 && !deskbar.IsAlwaysOnTop ()
628 && !deskbar.IsAutoRaise ())
629 frame.right = deskbar_frame.left - 2;
630 }
631 }
632
633 window_frame = Frame ();
634 decorator_frame = DecoratorFrame ();
635
636 frame.top += (window_frame.top
637 - decorator_frame.top);
638 frame.bottom -= (decorator_frame.bottom
639 - window_frame.bottom);
640 frame.left += (window_frame.left
641 - decorator_frame.left);
642 frame.right -= (decorator_frame.right
643 - window_frame.right);
644
645 if (frame.top > deskbar_frame.bottom
646 || frame.bottom < deskbar_frame.top)
647 {
648 frame.left = screen_frame.left + (window_frame.left
649 - decorator_frame.left);
650 frame.right = screen_frame.right - (decorator_frame.right
651 - window_frame.right);
652 }
653
654 return frame;
655 }
656
657 void 736 void
658 UpwardsSubset (EmacsWindow *w) 737 UpwardsSubset (EmacsWindow *w)
659 { 738 {
@@ -711,12 +790,6 @@ public:
711 RecomputeFeel (); 790 RecomputeFeel ();
712 UpwardsUnSubsetChildren (parent); 791 UpwardsUnSubsetChildren (parent);
713 this->RemoveFromSubset (this); 792 this->RemoveFromSubset (this);
714
715 if (fullscreen_p)
716 {
717 fullscreen_p = 0;
718 MakeFullscreen (1);
719 }
720 child_frame_lock.Unlock (); 793 child_frame_lock.Unlock ();
721 } 794 }
722 795
@@ -766,11 +839,6 @@ public:
766 this->AddToSubset (this); 839 this->AddToSubset (this);
767 if (!IsHidden () && this->parent) 840 if (!IsHidden () && this->parent)
768 UpwardsSubsetChildren (parent); 841 UpwardsSubsetChildren (parent);
769 if (fullscreen_p)
770 {
771 fullscreen_p = 0;
772 MakeFullscreen (1);
773 }
774 window->LinkChild (this); 842 window->LinkChild (this);
775 843
776 child_frame_lock.Unlock (); 844 child_frame_lock.Unlock ();
@@ -797,11 +865,23 @@ public:
797 } 865 }
798 866
799 void 867 void
868 MoveToIncludingFrame (int x, int y)
869 {
870 BRect decorator, frame;
871
872 decorator = DecoratorFrame ();
873 frame = Frame ();
874
875 MoveTo (x + frame.left - decorator.left,
876 y + frame.top - decorator.top);
877 }
878
879 void
800 DoMove (struct child_frame *f) 880 DoMove (struct child_frame *f)
801 { 881 {
802 BRect frame = this->Frame (); 882 BRect frame = this->Frame ();
803 f->window->MoveTo (frame.left + f->xoff, 883 f->window->MoveToIncludingFrame (frame.left + f->xoff,
804 frame.top + f->yoff); 884 frame.top + f->yoff);
805 } 885 }
806 886
807 void 887 void
@@ -982,6 +1062,15 @@ public:
982 haiku_write (WHEEL_MOVE_EVENT, &rq); 1062 haiku_write (WHEEL_MOVE_EVENT, &rq);
983 }; 1063 };
984 } 1064 }
1065 else if (msg->what == SEND_MOVE_FRAME_EVENT)
1066 FrameMoved (Frame ().LeftTop ());
1067 else if (msg->what == B_SCREEN_CHANGED)
1068 {
1069 if (fullscreen_mode != FULLSCREEN_MODE_NONE)
1070 SetFullscreen (fullscreen_mode);
1071
1072 BWindow::DispatchMessage (msg, handler);
1073 }
985 else 1074 else
986 BWindow::DispatchMessage (msg, handler); 1075 BWindow::DispatchMessage (msg, handler);
987 } 1076 }
@@ -1015,41 +1104,66 @@ public:
1015 { 1104 {
1016 struct haiku_resize_event rq; 1105 struct haiku_resize_event rq;
1017 rq.window = this; 1106 rq.window = this;
1018 rq.px_heightf = newHeight + 1.0f; 1107 rq.width = newWidth + 1.0f;
1019 rq.px_widthf = newWidth + 1.0f; 1108 rq.height = newHeight + 1.0f;
1020 1109
1021 haiku_write (FRAME_RESIZED, &rq); 1110 haiku_write (FRAME_RESIZED, &rq);
1022 BWindow::FrameResized (newWidth, newHeight); 1111 BWindow::FrameResized (newWidth, newHeight);
1023 } 1112 }
1024 1113
1025 void 1114 void
1026 FrameMoved (BPoint newPosition) 1115 FrameMoved (BPoint new_position)
1027 { 1116 {
1028 struct haiku_move_event rq; 1117 struct haiku_move_event rq;
1118 BRect frame, decorator_frame;
1119 struct child_frame *f;
1120
1121 if (fullscreen_mode == FULLSCREEN_MODE_WIDTH
1122 && new_position.x != 0)
1123 {
1124 MoveTo (0, new_position.y);
1125 return;
1126 }
1127
1128 if (fullscreen_mode == FULLSCREEN_MODE_HEIGHT
1129 && new_position.y != 0)
1130 {
1131 MoveTo (new_position.x, 0);
1132 return;
1133 }
1134
1029 rq.window = this; 1135 rq.window = this;
1030 rq.x = std::lrint (newPosition.x); 1136 rq.x = std::lrint (new_position.x);
1031 rq.y = std::lrint (newPosition.y); 1137 rq.y = std::lrint (new_position.y);
1138
1139 frame = Frame ();
1140 decorator_frame = DecoratorFrame ();
1141
1142 rq.decorator_width
1143 = std::lrint (frame.left - decorator_frame.left);
1144 rq.decorator_height
1145 = std::lrint (frame.top - decorator_frame.top);
1032 1146
1033 haiku_write (MOVE_EVENT, &rq); 1147 haiku_write (MOVE_EVENT, &rq);
1034 1148
1035 CHILD_FRAME_LOCK_INSIDE_LOOPER_CALLBACK 1149 CHILD_FRAME_LOCK_INSIDE_LOOPER_CALLBACK
1036 { 1150 {
1037 for (struct child_frame *f = subset_windows; 1151 for (f = subset_windows; f; f = f->next)
1038 f; f = f->next)
1039 DoMove (f); 1152 DoMove (f);
1040 child_frame_lock.Unlock (); 1153 child_frame_lock.Unlock ();
1041 1154
1042 BWindow::FrameMoved (newPosition); 1155 BWindow::FrameMoved (new_position);
1043 } 1156 }
1044 } 1157 }
1045 1158
1046 void 1159 void
1047 WorkspacesChanged (uint32_t old, uint32_t n) 1160 WorkspacesChanged (uint32_t old, uint32_t n)
1048 { 1161 {
1162 struct child_frame *f;
1163
1049 CHILD_FRAME_LOCK_INSIDE_LOOPER_CALLBACK 1164 CHILD_FRAME_LOCK_INSIDE_LOOPER_CALLBACK
1050 { 1165 {
1051 for (struct child_frame *f = subset_windows; 1166 for (f = subset_windows; f; f = f->next)
1052 f; f = f->next)
1053 DoUpdateWorkspace (f); 1167 DoUpdateWorkspace (f);
1054 1168
1055 child_frame_lock.Unlock (); 1169 child_frame_lock.Unlock ();
@@ -1063,7 +1177,7 @@ public:
1063 gui_abort ("Failed to lock child frame state lock"); 1177 gui_abort ("Failed to lock child frame state lock");
1064 1178
1065 if (!this->parent) 1179 if (!this->parent)
1066 this->MoveTo (x, y); 1180 this->MoveToIncludingFrame (x, y);
1067 else 1181 else
1068 this->parent->MoveChild (this, x, y, 0); 1182 this->parent->MoveChild (this, x, y, 0);
1069 child_frame_lock.Unlock (); 1183 child_frame_lock.Unlock ();
@@ -1135,66 +1249,113 @@ public:
1135 child_frame_lock.Unlock (); 1249 child_frame_lock.Unlock ();
1136 } 1250 }
1137 1251
1138 void 1252 BRect
1139 Zoom (BPoint o, float w, float h) 1253 ClearFullscreen (enum haiku_fullscreen_mode target_mode)
1140 { 1254 {
1141 struct haiku_zoom_event rq; 1255 BRect original_frame;
1142 BRect rect;
1143 rq.window = this;
1144
1145 if (fullscreen_p)
1146 MakeFullscreen (0);
1147 1256
1148 if (!zoomed_p) 1257 switch (fullscreen_mode)
1149 {
1150 pre_zoom_rect = Frame ();
1151 zoomed_p = true;
1152 rect = CalculateZoomRect ();
1153 }
1154 else
1155 { 1258 {
1156 zoomed_p = false; 1259 case FULLSCREEN_MODE_MAXIMIZED:
1157 rect = pre_zoom_rect; 1260 original_frame = pre_zoom_rect;
1158 }
1159 1261
1160 rq.zoomed = zoomed_p; 1262 if (target_mode == FULLSCREEN_MODE_NONE)
1161 haiku_write (ZOOM_EVENT, &rq); 1263 BWindow::Zoom (pre_zoom_rect.LeftTop (),
1264 BE_RECT_WIDTH (pre_zoom_rect) - 1,
1265 BE_RECT_HEIGHT (pre_zoom_rect) - 1);
1266 break;
1267
1268 case FULLSCREEN_MODE_BOTH:
1269 case FULLSCREEN_MODE_HEIGHT:
1270 case FULLSCREEN_MODE_WIDTH:
1271 original_frame = pre_fullscreen_rect;
1272 SetFlags (Flags () & ~(B_NOT_MOVABLE
1273 | B_NOT_ZOOMABLE
1274 | B_NOT_RESIZABLE));
1275
1276 if (target_mode != FULLSCREEN_MODE_NONE)
1277 goto out;
1278
1279 MoveTo (pre_fullscreen_rect.LeftTop ());
1280 ResizeTo (BE_RECT_WIDTH (pre_fullscreen_rect) - 1,
1281 BE_RECT_HEIGHT (pre_fullscreen_rect) - 1);
1282 break;
1283
1284 case FULLSCREEN_MODE_NONE:
1285 original_frame = Frame ();
1286 break;
1287 }
1162 1288
1163 BWindow::Zoom (rect.LeftTop (), BE_RECT_WIDTH (rect) - 1, 1289 out:
1164 BE_RECT_HEIGHT (rect) - 1); 1290 fullscreen_mode = FULLSCREEN_MODE_NONE;
1291 return original_frame;
1165 } 1292 }
1166 1293
1167 void 1294 BRect
1168 UnZoom (void) 1295 FullscreenRectForMode (enum haiku_fullscreen_mode mode)
1169 { 1296 {
1170 if (!zoomed_p) 1297 BScreen screen (this);
1171 return; 1298 BRect frame;
1299
1300 if (!screen.IsValid ())
1301 return BRect (0, 0, 0, 0);
1302
1303 frame = screen.Frame ();
1304
1305 if (mode == FULLSCREEN_MODE_HEIGHT)
1306 frame.right -= BE_RECT_WIDTH (frame) / 2;
1307 else if (mode == FULLSCREEN_MODE_WIDTH)
1308 frame.bottom -= BE_RECT_HEIGHT (frame) / 2;
1172 1309
1173 BWindow::Zoom (); 1310 return frame;
1174 } 1311 }
1175 1312
1176 void 1313 void
1177 GetParentWidthHeight (int *width, int *height) 1314 SetFullscreen (enum haiku_fullscreen_mode mode)
1178 { 1315 {
1179 if (!child_frame_lock.Lock ()) 1316 BRect zoom_rect, frame;
1180 gui_abort ("Failed to lock child frame state lock");
1181 1317
1182 if (parent) 1318 frame = ClearFullscreen (mode);
1183 { 1319
1184 BRect frame = parent->Frame (); 1320 switch (mode)
1185 *width = BE_RECT_WIDTH (frame);
1186 *height = BE_RECT_HEIGHT (frame);
1187 }
1188 else
1189 { 1321 {
1190 BScreen s (this); 1322 case FULLSCREEN_MODE_MAXIMIZED:
1191 BRect frame = s.Frame (); 1323 pre_zoom_rect = frame;
1324 zoom_rect = get_zoom_rect (this);
1325 BWindow::Zoom (zoom_rect.LeftTop (),
1326 BE_RECT_WIDTH (zoom_rect) - 1,
1327 BE_RECT_HEIGHT (zoom_rect) - 1);
1328 break;
1329
1330 case FULLSCREEN_MODE_BOTH:
1331 SetFlags (Flags () | B_NOT_MOVABLE);
1332 FALLTHROUGH;
1333
1334 case FULLSCREEN_MODE_HEIGHT:
1335 case FULLSCREEN_MODE_WIDTH:
1336 SetFlags (Flags () | B_NOT_ZOOMABLE | B_NOT_RESIZABLE);
1337 pre_fullscreen_rect = frame;
1338 zoom_rect = FullscreenRectForMode (mode);
1339 ResizeTo (BE_RECT_WIDTH (zoom_rect) - 1,
1340 BE_RECT_HEIGHT (zoom_rect) - 1);
1341 MoveTo (zoom_rect.left, zoom_rect.top);
1342 break;
1192 1343
1193 *width = BE_RECT_WIDTH (frame); 1344 case FULLSCREEN_MODE_NONE:
1194 *height = BE_RECT_HEIGHT (frame); 1345 break;
1195 } 1346 }
1196 1347
1197 child_frame_lock.Unlock (); 1348 fullscreen_mode = mode;
1349 }
1350
1351 void
1352 Zoom (BPoint origin, float width, float height)
1353 {
1354 struct haiku_zoom_event rq;
1355
1356 rq.window = this;
1357 rq.fullscreen_mode = fullscreen_mode;
1358 haiku_write (ZOOM_EVENT, &rq);
1198 } 1359 }
1199 1360
1200 void 1361 void
@@ -1217,53 +1378,6 @@ public:
1217 child_frame_lock.Lock (); 1378 child_frame_lock.Lock ();
1218 gui_abort ("Trying to calculate offsets for a child frame that doesn't exist"); 1379 gui_abort ("Trying to calculate offsets for a child frame that doesn't exist");
1219 } 1380 }
1220
1221 void
1222 MakeFullscreen (int make_fullscreen_p)
1223 {
1224 BScreen screen (this);
1225
1226 if (!screen.IsValid ())
1227 gui_abort ("Trying to make a window fullscreen without a screen");
1228
1229 UnZoom ();
1230
1231 if (make_fullscreen_p == fullscreen_p)
1232 return;
1233
1234 fullscreen_p = make_fullscreen_p;
1235 uint32 flags = Flags ();
1236 if (fullscreen_p)
1237 {
1238 if (zoomed_p)
1239 UnZoom ();
1240
1241 flags |= B_NOT_MOVABLE | B_NOT_ZOOMABLE;
1242 pre_fullscreen_rect = Frame ();
1243
1244 if (!child_frame_lock.Lock ())
1245 gui_abort ("Failed to lock child frame state lock");
1246
1247 if (parent)
1248 parent->OffsetChildRect (&pre_fullscreen_rect, this);
1249
1250 child_frame_lock.Unlock ();
1251
1252 int w, h;
1253 EmacsMoveTo (0, 0);
1254 GetParentWidthHeight (&w, &h);
1255 ResizeTo (w - 1, h - 1);
1256 }
1257 else
1258 {
1259 flags &= ~(B_NOT_MOVABLE | B_NOT_ZOOMABLE);
1260 EmacsMoveTo (pre_fullscreen_rect.left,
1261 pre_fullscreen_rect.top);
1262 ResizeTo (BE_RECT_WIDTH (pre_fullscreen_rect) - 1,
1263 BE_RECT_HEIGHT (pre_fullscreen_rect) - 1);
1264 }
1265 SetFlags (flags);
1266 }
1267}; 1381};
1268 1382
1269class EmacsMenuBar : public BMenuBar 1383class EmacsMenuBar : public BMenuBar
@@ -1322,11 +1436,7 @@ public:
1322 rq.y = std::lrint (point.y); 1436 rq.y = std::lrint (point.y);
1323 rq.window = this->Window (); 1437 rq.window = this->Window ();
1324 1438
1325 if (movement_locker.Lock ()) 1439 haiku_write (MENU_BAR_LEFT, &rq);
1326 {
1327 haiku_write (MENU_BAR_LEFT, &rq);
1328 movement_locker.Unlock ();
1329 }
1330 } 1440 }
1331 1441
1332 BMenuBar::MouseMoved (point, transit, msg); 1442 BMenuBar::MouseMoved (point, transit, msg);
@@ -1383,25 +1493,36 @@ public:
1383class EmacsView : public BView 1493class EmacsView : public BView
1384{ 1494{
1385public: 1495public:
1386 uint32_t previous_buttons = 0; 1496 uint32_t previous_buttons;
1387 int looper_locked_count = 0; 1497 int looper_locked_count;
1388 BRegion sb_region; 1498 BRegion sb_region;
1389 BRegion invalid_region; 1499 BRegion invalid_region;
1390 1500
1391 BView *offscreen_draw_view = NULL; 1501 BView *offscreen_draw_view;
1392 BBitmap *offscreen_draw_bitmap_1 = NULL; 1502 BBitmap *offscreen_draw_bitmap_1;
1393 BBitmap *copy_bitmap = NULL; 1503 BBitmap *copy_bitmap;
1394 1504
1395#ifdef USE_BE_CAIRO 1505#ifdef USE_BE_CAIRO
1396 cairo_surface_t *cr_surface = NULL; 1506 cairo_surface_t *cr_surface;
1397 cairo_t *cr_context = NULL; 1507 cairo_t *cr_context;
1398 BLocker cr_surface_lock; 1508 BLocker cr_surface_lock;
1399#endif 1509#endif
1400 1510
1401 BPoint tt_absl_pos; 1511 BPoint tt_absl_pos;
1402 BMessage *wait_for_release_message = NULL; 1512 BMessage *wait_for_release_message;
1403 1513
1404 EmacsView () : BView (BRect (0, 0, 0, 0), "Emacs", B_FOLLOW_NONE, B_WILL_DRAW) 1514 EmacsView () : BView (BRect (0, 0, 0, 0), "Emacs",
1515 B_FOLLOW_NONE, B_WILL_DRAW),
1516 previous_buttons (0),
1517 looper_locked_count (0),
1518 offscreen_draw_view (NULL),
1519 offscreen_draw_bitmap_1 (NULL),
1520 copy_bitmap (NULL),
1521#ifdef USE_BE_CAIRO
1522 cr_surface (NULL),
1523 cr_context (NULL),
1524#endif
1525 wait_for_release_message (NULL)
1405 { 1526 {
1406 1527
1407 } 1528 }
@@ -1549,9 +1670,7 @@ public:
1549#endif 1670#endif
1550 1671
1551 if (looper_locked_count) 1672 if (looper_locked_count)
1552 { 1673 offscreen_draw_bitmap_1->Lock ();
1553 offscreen_draw_bitmap_1->Lock ();
1554 }
1555 1674
1556 UnlockLooper (); 1675 UnlockLooper ();
1557 } 1676 }
@@ -1618,16 +1737,17 @@ public:
1618 copy_bitmap = NULL; 1737 copy_bitmap = NULL;
1619 } 1738 }
1620 if (!copy_bitmap) 1739 if (!copy_bitmap)
1621 copy_bitmap = new BBitmap (offscreen_draw_bitmap_1); 1740 {
1741 copy_bitmap = new BBitmap (offscreen_draw_bitmap_1);
1742 SetViewBitmap (copy_bitmap, Frame (),
1743 Frame (), B_FOLLOW_NONE, 0);
1744 }
1622 else 1745 else
1623 copy_bitmap->ImportBits (offscreen_draw_bitmap_1); 1746 copy_bitmap->ImportBits (offscreen_draw_bitmap_1);
1624 1747
1625 if (copy_bitmap->InitCheck () != B_OK) 1748 if (copy_bitmap->InitCheck () != B_OK)
1626 gui_abort ("Failed to init copy bitmap during buffer flip"); 1749 gui_abort ("Failed to init copy bitmap during buffer flip");
1627 1750
1628 SetViewBitmap (copy_bitmap,
1629 Frame (), Frame (), B_FOLLOW_NONE, 0);
1630
1631 Invalidate (&invalid_region); 1751 Invalidate (&invalid_region);
1632 invalid_region.MakeEmpty (); 1752 invalid_region.MakeEmpty ();
1633 UnlockLooper (); 1753 UnlockLooper ();
@@ -1668,8 +1788,11 @@ public:
1668 struct haiku_mouse_motion_event rq; 1788 struct haiku_mouse_motion_event rq;
1669 int32 windowid; 1789 int32 windowid;
1670 EmacsWindow *window; 1790 EmacsWindow *window;
1791 BToolTip *tooltip;
1671 1792
1672 window = (EmacsWindow *) Window (); 1793 window = (EmacsWindow *) Window ();
1794 tooltip = ToolTip ();
1795
1673 rq.just_exited_p = transit == B_EXITED_VIEW; 1796 rq.just_exited_p = transit == B_EXITED_VIEW;
1674 rq.x = point.x; 1797 rq.x = point.x;
1675 rq.y = point.y; 1798 rq.y = point.y;
@@ -1684,9 +1807,9 @@ public:
1684 else 1807 else
1685 rq.dnd_message = false; 1808 rq.dnd_message = false;
1686 1809
1687 if (ToolTip ()) 1810 if (tooltip)
1688 ToolTip ()->SetMouseRelativeLocation (BPoint (-(point.x - tt_absl_pos.x), 1811 tooltip->SetMouseRelativeLocation (BPoint (-(point.x - tt_absl_pos.x),
1689 -(point.y - tt_absl_pos.y))); 1812 -(point.y - tt_absl_pos.y)));
1690 1813
1691 if (!grab_view_locker.Lock ()) 1814 if (!grab_view_locker.Lock ())
1692 gui_abort ("Couldn't lock grab view locker"); 1815 gui_abort ("Couldn't lock grab view locker");
@@ -1699,18 +1822,14 @@ public:
1699 1822
1700 grab_view_locker.Unlock (); 1823 grab_view_locker.Unlock ();
1701 1824
1702 if (movement_locker.Lock ()) 1825 haiku_write (MOUSE_MOTION, &rq);
1703 {
1704 haiku_write (MOUSE_MOTION, &rq);
1705 movement_locker.Unlock ();
1706 }
1707 } 1826 }
1708 1827
1709 void 1828 void
1710 MouseDown (BPoint point) 1829 BasicMouseDown (BPoint point, BView *scroll_bar)
1711 { 1830 {
1712 struct haiku_button_event rq; 1831 struct haiku_button_event rq;
1713 uint32 buttons; 1832 uint32 mods, buttons;
1714 1833
1715 this->GetMouse (&point, &buttons, false); 1834 this->GetMouse (&point, &buttons, false);
1716 1835
@@ -1721,6 +1840,7 @@ public:
1721 grab_view_locker.Unlock (); 1840 grab_view_locker.Unlock ();
1722 1841
1723 rq.window = this->Window (); 1842 rq.window = this->Window ();
1843 rq.scroll_bar = scroll_bar;
1724 1844
1725 if (!(previous_buttons & B_PRIMARY_MOUSE_BUTTON) 1845 if (!(previous_buttons & B_PRIMARY_MOUSE_BUTTON)
1726 && (buttons & B_PRIMARY_MOUSE_BUTTON)) 1846 && (buttons & B_PRIMARY_MOUSE_BUTTON))
@@ -1739,7 +1859,7 @@ public:
1739 rq.x = point.x; 1859 rq.x = point.x;
1740 rq.y = point.y; 1860 rq.y = point.y;
1741 1861
1742 uint32_t mods = modifiers (); 1862 mods = modifiers ();
1743 1863
1744 rq.modifiers = 0; 1864 rq.modifiers = 0;
1745 if (mods & B_SHIFT_KEY) 1865 if (mods & B_SHIFT_KEY)
@@ -1754,18 +1874,25 @@ public:
1754 if (mods & B_OPTION_KEY) 1874 if (mods & B_OPTION_KEY)
1755 rq.modifiers |= HAIKU_MODIFIER_SUPER; 1875 rq.modifiers |= HAIKU_MODIFIER_SUPER;
1756 1876
1757 SetMouseEventMask (B_POINTER_EVENTS, (B_LOCK_WINDOW_FOCUS 1877 if (!scroll_bar)
1758 | B_NO_POINTER_HISTORY)); 1878 SetMouseEventMask (B_POINTER_EVENTS, (B_LOCK_WINDOW_FOCUS
1879 | B_NO_POINTER_HISTORY));
1759 1880
1760 rq.time = system_time (); 1881 rq.time = system_time ();
1761 haiku_write (BUTTON_DOWN, &rq); 1882 haiku_write (BUTTON_DOWN, &rq);
1762 } 1883 }
1763 1884
1764 void 1885 void
1765 MouseUp (BPoint point) 1886 MouseDown (BPoint point)
1887 {
1888 BasicMouseDown (point, NULL);
1889 }
1890
1891 void
1892 BasicMouseUp (BPoint point, BView *scroll_bar)
1766 { 1893 {
1767 struct haiku_button_event rq; 1894 struct haiku_button_event rq;
1768 uint32 buttons; 1895 uint32 buttons, mods;
1769 1896
1770 this->GetMouse (&point, &buttons, false); 1897 this->GetMouse (&point, &buttons, false);
1771 1898
@@ -1786,6 +1913,7 @@ public:
1786 } 1913 }
1787 1914
1788 rq.window = this->Window (); 1915 rq.window = this->Window ();
1916 rq.scroll_bar = scroll_bar;
1789 1917
1790 if ((previous_buttons & B_PRIMARY_MOUSE_BUTTON) 1918 if ((previous_buttons & B_PRIMARY_MOUSE_BUTTON)
1791 && !(buttons & B_PRIMARY_MOUSE_BUTTON)) 1919 && !(buttons & B_PRIMARY_MOUSE_BUTTON))
@@ -1804,7 +1932,7 @@ public:
1804 rq.x = point.x; 1932 rq.x = point.x;
1805 rq.y = point.y; 1933 rq.y = point.y;
1806 1934
1807 uint32_t mods = modifiers (); 1935 mods = modifiers ();
1808 1936
1809 rq.modifiers = 0; 1937 rq.modifiers = 0;
1810 if (mods & B_SHIFT_KEY) 1938 if (mods & B_SHIFT_KEY)
@@ -1819,37 +1947,48 @@ public:
1819 if (mods & B_OPTION_KEY) 1947 if (mods & B_OPTION_KEY)
1820 rq.modifiers |= HAIKU_MODIFIER_SUPER; 1948 rq.modifiers |= HAIKU_MODIFIER_SUPER;
1821 1949
1822 if (!buttons)
1823 SetMouseEventMask (0, 0);
1824
1825 rq.time = system_time (); 1950 rq.time = system_time ();
1826 haiku_write (BUTTON_UP, &rq); 1951 haiku_write (BUTTON_UP, &rq);
1827 } 1952 }
1953
1954 void
1955 MouseUp (BPoint point)
1956 {
1957 BasicMouseUp (point, NULL);
1958 }
1828}; 1959};
1829 1960
1830class EmacsScrollBar : public BScrollBar 1961class EmacsScrollBar : public BScrollBar
1831{ 1962{
1832public: 1963public:
1833 int dragging = 0; 1964 int dragging;
1834 bool horizontal; 1965 bool horizontal;
1835 enum haiku_scroll_bar_part current_part; 1966 enum haiku_scroll_bar_part current_part;
1836 float old_value; 1967 float old_value;
1837 scroll_bar_info info; 1968 scroll_bar_info info;
1838 1969
1839 /* True if button events should be passed to the parent. */ 1970 /* True if button events should be passed to the parent. */
1840 bool handle_button = false; 1971 bool handle_button;
1841 bool in_overscroll = false; 1972 bool in_overscroll;
1842 bool can_overscroll = false; 1973 bool can_overscroll;
1843 bool maybe_overscroll = false; 1974 bool maybe_overscroll;
1844 BPoint last_overscroll; 1975 BPoint last_overscroll;
1845 int last_reported_overscroll_value; 1976 int last_reported_overscroll_value;
1846 int max_value, real_max_value; 1977 int max_value, real_max_value;
1847 int overscroll_start_value; 1978 int overscroll_start_value;
1848 bigtime_t repeater_start; 1979 bigtime_t repeater_start;
1849 1980 EmacsView *parent;
1850 EmacsScrollBar (int x, int y, int x1, int y1, bool horizontal_p) : 1981
1851 BScrollBar (BRect (x, y, x1, y1), NULL, NULL, 0, 0, horizontal_p ? 1982 EmacsScrollBar (int x, int y, int x1, int y1, bool horizontal_p,
1852 B_HORIZONTAL : B_VERTICAL) 1983 EmacsView *parent)
1984 : BScrollBar (BRect (x, y, x1, y1), NULL, NULL, 0, 0, horizontal_p ?
1985 B_HORIZONTAL : B_VERTICAL),
1986 dragging (0),
1987 handle_button (false),
1988 in_overscroll (false),
1989 can_overscroll (false),
1990 maybe_overscroll (false),
1991 parent (parent)
1853 { 1992 {
1854 BView *vw = (BView *) this; 1993 BView *vw = (BView *) this;
1855 vw->SetResizingMode (B_FOLLOW_NONE); 1994 vw->SetResizingMode (B_FOLLOW_NONE);
@@ -2050,7 +2189,6 @@ public:
2050 BLooper *looper; 2189 BLooper *looper;
2051 BMessage *message; 2190 BMessage *message;
2052 int32 buttons, mods; 2191 int32 buttons, mods;
2053 BView *parent;
2054 2192
2055 looper = Looper (); 2193 looper = Looper ();
2056 message = NULL; 2194 message = NULL;
@@ -2071,8 +2209,9 @@ public:
2071 { 2209 {
2072 /* Allow C-mouse-3 to split the window on a scroll bar. */ 2210 /* Allow C-mouse-3 to split the window on a scroll bar. */
2073 handle_button = true; 2211 handle_button = true;
2074 parent = Parent (); 2212 SetMouseEventMask (B_POINTER_EVENTS, (B_SUSPEND_VIEW_FOCUS
2075 parent->MouseDown (ConvertToParent (pt)); 2213 | B_LOCK_WINDOW_FOCUS));
2214 parent->BasicMouseDown (ConvertToParent (pt), this);
2076 2215
2077 return; 2216 return;
2078 } 2217 }
@@ -2135,7 +2274,6 @@ public:
2135 MouseUp (BPoint pt) 2274 MouseUp (BPoint pt)
2136 { 2275 {
2137 struct haiku_scroll_bar_drag_event rq; 2276 struct haiku_scroll_bar_drag_event rq;
2138 BView *parent;
2139 2277
2140 in_overscroll = false; 2278 in_overscroll = false;
2141 maybe_overscroll = false; 2279 maybe_overscroll = false;
@@ -2143,8 +2281,7 @@ public:
2143 if (handle_button) 2281 if (handle_button)
2144 { 2282 {
2145 handle_button = false; 2283 handle_button = false;
2146 parent = Parent (); 2284 parent->BasicMouseUp (ConvertToParent (pt), this);
2147 parent->MouseUp (ConvertToParent (pt));
2148 2285
2149 return; 2286 return;
2150 } 2287 }
@@ -2179,11 +2316,7 @@ public:
2179 rq.y = std::lrint (conv.y); 2316 rq.y = std::lrint (conv.y);
2180 rq.window = this->Window (); 2317 rq.window = this->Window ();
2181 2318
2182 if (movement_locker.Lock ()) 2319 haiku_write (MENU_BAR_LEFT, &rq);
2183 {
2184 haiku_write (MENU_BAR_LEFT, &rq);
2185 movement_locker.Unlock ();
2186 }
2187 } 2320 }
2188 2321
2189 if (in_overscroll) 2322 if (in_overscroll)
@@ -2280,30 +2413,26 @@ public:
2280class EmacsMenuItem : public BMenuItem 2413class EmacsMenuItem : public BMenuItem
2281{ 2414{
2282public: 2415public:
2283 int menu_bar_id = -1; 2416 int menu_bar_id;
2284 void *menu_ptr = NULL; 2417 void *menu_ptr;
2285 void *wind_ptr = NULL; 2418 void *wind_ptr;
2286 char *key = NULL; 2419 char *key;
2287 char *help = NULL; 2420 char *help;
2288 2421
2289 EmacsMenuItem (const char *ky, 2422 EmacsMenuItem (const char *key_label, const char *label,
2290 const char *str, 2423 const char *help, BMessage *message = NULL)
2291 const char *help, 2424 : BMenuItem (label, message),
2292 BMessage *message = NULL) : BMenuItem (str, message) 2425 menu_bar_id (-1),
2426 menu_ptr (NULL),
2427 wind_ptr (NULL),
2428 key (NULL),
2429 help (NULL)
2293 { 2430 {
2294 if (ky) 2431 if (key_label)
2295 { 2432 key = strdup (key_label);
2296 key = strdup (ky);
2297 if (!key)
2298 gui_abort ("strdup failed");
2299 }
2300 2433
2301 if (help) 2434 if (help)
2302 { 2435 this->help = strdup (help);
2303 this->help = strdup (help);
2304 if (!this->help)
2305 gui_abort ("strdup failed");
2306 }
2307 } 2436 }
2308 2437
2309 ~EmacsMenuItem () 2438 ~EmacsMenuItem ()
@@ -2383,22 +2512,6 @@ public:
2383 } 2512 }
2384}; 2513};
2385 2514
2386class EmacsPopUpMenu : public BPopUpMenu
2387{
2388public:
2389 EmacsPopUpMenu (const char *name) : BPopUpMenu (name, 0)
2390 {
2391
2392 }
2393
2394 void
2395 FrameResized (float w, float h)
2396 {
2397 Invalidate ();
2398 BPopUpMenu::FrameResized (w, h);
2399 }
2400};
2401
2402class EmacsFontPreviewDialog : public BWindow 2515class EmacsFontPreviewDialog : public BWindow
2403{ 2516{
2404 BStringView text_view; 2517 BStringView text_view;
@@ -2618,13 +2731,22 @@ class EmacsFontSelectionDialog : public BWindow
2618 void 2731 void
2619 UpdateStylesForIndex (int idx) 2732 UpdateStylesForIndex (int idx)
2620 { 2733 {
2621 int n, i; 2734 int n, i, previous_selection;
2622 uint32 flags; 2735 uint32 flags;
2623 font_family family; 2736 font_family family;
2624 font_style style; 2737 font_style style;
2625 BStringItem *item; 2738 BStringItem *item;
2739 char *current_style;
2626 2740
2627 n = all_styles.CountItems (); 2741 n = all_styles.CountItems ();
2742 current_style = NULL;
2743 previous_selection = font_style_pane.CurrentSelection ();
2744
2745 if (previous_selection >= 0)
2746 {
2747 item = all_styles.ItemAt (previous_selection);
2748 current_style = strdup (item->Text ());
2749 }
2628 2750
2629 font_style_pane.MakeEmpty (); 2751 font_style_pane.MakeEmpty ();
2630 all_styles.MakeEmpty (); 2752 all_styles.MakeEmpty ();
@@ -2640,6 +2762,10 @@ class EmacsFontSelectionDialog : public BWindow
2640 else 2762 else
2641 item = new BStringItem ("<error>"); 2763 item = new BStringItem ("<error>");
2642 2764
2765 if (current_style && pending_selection_idx < 0
2766 && !strcmp (current_style, style))
2767 pending_selection_idx = i;
2768
2643 font_style_pane.AddItem (item); 2769 font_style_pane.AddItem (item);
2644 all_styles.AddItem (item); 2770 all_styles.AddItem (item);
2645 } 2771 }
@@ -2653,6 +2779,9 @@ class EmacsFontSelectionDialog : public BWindow
2653 2779
2654 pending_selection_idx = -1; 2780 pending_selection_idx = -1;
2655 UpdateForSelectedStyle (); 2781 UpdateForSelectedStyle ();
2782
2783 if (current_style)
2784 free (current_style);
2656 } 2785 }
2657 2786
2658 bool 2787 bool
@@ -3361,56 +3490,28 @@ BView_resize_to (void *view, int width, int height)
3361 vw->UnlockLooper (); 3490 vw->UnlockLooper ();
3362} 3491}
3363 3492
3364void * 3493void
3365BCursor_create_default (void) 3494be_delete_cursor (void *cursor)
3366{
3367 return new BCursor (B_CURSOR_ID_SYSTEM_DEFAULT);
3368}
3369
3370void *
3371BCursor_create_modeline (void)
3372{
3373 return new BCursor (B_CURSOR_ID_CONTEXT_MENU);
3374}
3375
3376void *
3377BCursor_from_id (enum haiku_cursor cursor)
3378{
3379 return new BCursor ((enum BCursorID) cursor);
3380}
3381
3382void *
3383BCursor_create_i_beam (void)
3384{
3385 return new BCursor (B_CURSOR_ID_I_BEAM);
3386}
3387
3388void *
3389BCursor_create_progress_cursor (void)
3390{ 3495{
3391 return new BCursor (B_CURSOR_ID_PROGRESS); 3496 if (cursor)
3497 delete (BCursor *) cursor;
3392} 3498}
3393 3499
3394void * 3500void *
3395BCursor_create_grab (void) 3501be_create_cursor_from_id (int id)
3396{
3397 return new BCursor (B_CURSOR_ID_GRAB);
3398}
3399
3400void
3401BCursor_delete (void *cursor)
3402{ 3502{
3403 if (cursor) 3503 return new BCursor ((enum BCursorID) id);
3404 delete (BCursor *) cursor;
3405} 3504}
3406 3505
3407void 3506void
3408BView_set_view_cursor (void *view, void *cursor) 3507BView_set_view_cursor (void *view, void *cursor)
3409{ 3508{
3410 if (!((BView *) view)->LockLooper ()) 3509 BView *v = (BView *) view;
3510
3511 if (!v->LockLooper ())
3411 gui_abort ("Failed to lock view setting cursor"); 3512 gui_abort ("Failed to lock view setting cursor");
3412 ((BView *) view)->SetViewCursor ((BCursor *) cursor); 3513 v->SetViewCursor ((BCursor *) cursor);
3413 ((BView *) view)->UnlockLooper (); 3514 v->UnlockLooper ();
3414} 3515}
3415 3516
3416void 3517void
@@ -3421,20 +3522,22 @@ BWindow_Flush (void *window)
3421 3522
3422/* Make a scrollbar, attach it to VIEW's window, and return it. */ 3523/* Make a scrollbar, attach it to VIEW's window, and return it. */
3423void * 3524void *
3424BScrollBar_make_for_view (void *view, int horizontal_p, 3525be_make_scroll_bar_for_view (void *view, int horizontal_p,
3425 int x, int y, int x1, int y1, 3526 int x, int y, int x1, int y1)
3426 void *scroll_bar_ptr)
3427{ 3527{
3428 EmacsScrollBar *sb = new EmacsScrollBar (x, y, x1, y1, horizontal_p); 3528 EmacsScrollBar *scroll_bar;
3429 BView *vw = (BView *) view; 3529 BView *vw = (BView *) view;
3430 BView *sv = (BView *) sb;
3431 3530
3432 if (!vw->LockLooper ()) 3531 if (!vw->LockLooper ())
3433 gui_abort ("Failed to lock scrollbar owner"); 3532 gui_abort ("Failed to lock scrollbar owner");
3434 vw->AddChild ((BView *) sb); 3533
3435 sv->WindowActivated (vw->Window ()->IsActive ()); 3534 scroll_bar = new EmacsScrollBar (x, y, x1, y1, horizontal_p,
3535 (EmacsView *) vw);
3536
3537 vw->AddChild (scroll_bar);
3436 vw->UnlockLooper (); 3538 vw->UnlockLooper ();
3437 return sb; 3539
3540 return scroll_bar;
3438} 3541}
3439 3542
3440void 3543void
@@ -3599,17 +3702,6 @@ BBitmap_import_fringe_bitmap (void *bitmap, unsigned short *bits, int wd, int h)
3599 } 3702 }
3600} 3703}
3601 3704
3602void
3603BBitmap_import_mono_bits (void *bitmap, void *bits, int wd, int h)
3604{
3605 BBitmap *bmp = (BBitmap *) bitmap;
3606
3607 if (wd % 8)
3608 wd += 8 - (wd % 8);
3609
3610 bmp->ImportBits (bits, wd / 8 * h, wd / 8, 0, B_GRAY1);
3611}
3612
3613/* Make a scrollbar at X, Y known to the view VIEW. */ 3705/* Make a scrollbar at X, Y known to the view VIEW. */
3614void 3706void
3615BView_publish_scroll_bar (void *view, int x, int y, int width, int height) 3707BView_publish_scroll_bar (void *view, int x, int y, int width, int height)
@@ -3768,7 +3860,8 @@ BView_emacs_delete (void *view)
3768void * 3860void *
3769BPopUpMenu_new (const char *name) 3861BPopUpMenu_new (const char *name)
3770{ 3862{
3771 BPopUpMenu *menu = new EmacsPopUpMenu (name); 3863 BPopUpMenu *menu = new BPopUpMenu (name);
3864
3772 menu->SetRadioMode (0); 3865 menu->SetRadioMode (0);
3773 return menu; 3866 return menu;
3774} 3867}
@@ -3778,9 +3871,11 @@ BPopUpMenu_new (const char *name)
3778void 3871void
3779BMenu_add_title (void *menu, const char *text) 3872BMenu_add_title (void *menu, const char *text)
3780{ 3873{
3781 EmacsTitleMenuItem *it = new EmacsTitleMenuItem (text); 3874 BMenu *be_menu = (BMenu *) menu;
3782 BMenu *mn = (BMenu *) menu; 3875 EmacsTitleMenuItem *it;
3783 mn->AddItem (it); 3876
3877 it = new EmacsTitleMenuItem (text);
3878 be_menu->AddItem (it);
3784} 3879}
3785 3880
3786/* Add an item to the menu MENU. */ 3881/* 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,
4522 return file_name; 4617 return file_name;
4523} 4618}
4524 4619
4525/* Zoom WINDOW. */
4526void
4527BWindow_zoom (void *window)
4528{
4529 BWindow *w = (BWindow *) window;
4530 w->Zoom ();
4531}
4532
4533/* Make WINDOW fullscreen if FULLSCREEN_P. */
4534void
4535EmacsWindow_make_fullscreen (void *window, int fullscreen_p)
4536{
4537 EmacsWindow *w = (EmacsWindow *) window;
4538 w->MakeFullscreen (fullscreen_p);
4539}
4540
4541/* Unzoom (maximize) WINDOW. */
4542void
4543EmacsWindow_unzoom (void *window)
4544{
4545 EmacsWindow *w = (EmacsWindow *) window;
4546 w->UnZoom ();
4547}
4548
4549/* Move the pointer into MBAR and start tracking. Return whether the 4620/* Move the pointer into MBAR and start tracking. Return whether the
4550 menu bar was opened correctly. */ 4621 menu bar was opened correctly. */
4551bool 4622bool
@@ -5082,3 +5153,172 @@ BWindow_set_sticky (void *window, bool sticky)
5082 w->UnlockLooper (); 5153 w->UnlockLooper ();
5083 } 5154 }
5084} 5155}
5156
5157status_t
5158be_roster_launch (const char *type, const char *file, char **cargs,
5159 ptrdiff_t nargs, void *message, team_id *team_id)
5160{
5161 BEntry entry;
5162 entry_ref ref;
5163
5164 if (type)
5165 {
5166 if (message)
5167 return be_roster->Launch (type, (BMessage *) message,
5168 team_id);
5169
5170 return be_roster->Launch (type, (nargs > INT_MAX
5171 ? INT_MAX : nargs),
5172 cargs, team_id);
5173 }
5174
5175 if (entry.SetTo (file) != B_OK)
5176 return B_ERROR;
5177
5178 if (entry.GetRef (&ref) != B_OK)
5179 return B_ERROR;
5180
5181 if (message)
5182 return be_roster->Launch (&ref, (BMessage *) message,
5183 team_id);
5184
5185 return be_roster->Launch (&ref, (nargs > INT_MAX
5186 ? INT_MAX : nargs),
5187 cargs, team_id);
5188}
5189
5190void *
5191be_create_pixmap_cursor (void *bitmap, int x, int y)
5192{
5193 BBitmap *bm;
5194 BCursor *cursor;
5195
5196 bm = (BBitmap *) bitmap;
5197 cursor = new BCursor (bm, BPoint (x, y));
5198
5199 if (cursor->InitCheck () != B_OK)
5200 {
5201 delete cursor;
5202 return NULL;
5203 }
5204
5205 return cursor;
5206}
5207
5208void
5209be_get_window_decorator_dimensions (void *window, int *left, int *top,
5210 int *right, int *bottom)
5211{
5212 BWindow *wnd;
5213 BRect frame, window_frame;
5214
5215 wnd = (BWindow *) window;
5216
5217 if (!wnd->LockLooper ())
5218 gui_abort ("Failed to lock window looper frame");
5219
5220 frame = wnd->DecoratorFrame ();
5221 window_frame = wnd->Frame ();
5222
5223 if (left)
5224 *left = window_frame.left - frame.left;
5225
5226 if (top)
5227 *top = window_frame.top - frame.top;
5228
5229 if (right)
5230 *right = frame.right - window_frame.right;
5231
5232 if (bottom)
5233 *bottom = frame.bottom - window_frame.bottom;
5234
5235 wnd->UnlockLooper ();
5236}
5237
5238void
5239be_get_window_decorator_frame (void *window, int *left, int *top,
5240 int *width, int *height)
5241{
5242 BWindow *wnd;
5243 BRect frame;
5244
5245 wnd = (BWindow *) window;
5246
5247 if (!wnd->LockLooper ())
5248 gui_abort ("Failed to lock window looper frame");
5249
5250 frame = wnd->DecoratorFrame ();
5251
5252 *left = frame.left;
5253 *top = frame.top;
5254 *width = BE_RECT_WIDTH (frame);
5255 *height = BE_RECT_HEIGHT (frame);
5256
5257 wnd->UnlockLooper ();
5258}
5259
5260/* Request that a MOVE_EVENT be sent for WINDOW. This is so that
5261 frame offsets can be updated after a frame parameter affecting
5262 decorators changes. Sending an event instead of updating the
5263 offsets directly avoids race conditions where events with older
5264 information are received after the update happens. */
5265void
5266be_send_move_frame_event (void *window)
5267{
5268 BWindow *wnd = (BWindow *) window;
5269 BMessenger msg (wnd);
5270
5271 msg.SendMessage (SEND_MOVE_FRAME_EVENT);
5272}
5273
5274void
5275be_lock_window (void *window)
5276{
5277 BWindow *wnd = (BWindow *) window;
5278
5279 if (!wnd->LockLooper ())
5280 gui_abort ("Failed to lock window looper");
5281}
5282
5283void
5284be_unlock_window (void *window)
5285{
5286 BWindow *wnd = (BWindow *) window;
5287
5288 wnd->UnlockLooper ();
5289}
5290
5291void
5292be_set_window_fullscreen_mode (void *window, enum haiku_fullscreen_mode mode)
5293{
5294 EmacsWindow *w = (EmacsWindow *) window;
5295
5296 if (!w->LockLooper ())
5297 gui_abort ("Failed to lock window to set fullscreen mode");
5298
5299 w->SetFullscreen (mode);
5300 w->UnlockLooper ();
5301}
5302
5303bool
5304be_get_explicit_workarea (int *x, int *y, int *width, int *height)
5305{
5306 BDeskbar deskbar;
5307 BRect zoom;
5308 deskbar_location location;
5309
5310 location = deskbar.Location ();
5311
5312 if (location != B_DESKBAR_TOP
5313 && location != B_DESKBAR_BOTTOM)
5314 return false;
5315
5316 zoom = get_zoom_rect (NULL);
5317
5318 *x = zoom.left;
5319 *y = zoom.top;
5320 *width = BE_RECT_WIDTH (zoom);
5321 *height = BE_RECT_HEIGHT (zoom);
5322
5323 return true;
5324}
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/>. */
38 38
39enum haiku_cursor 39enum haiku_cursor
40 { 40 {
41 CURSOR_ID_SYSTEM_DEFAULT = 1,
42 CURSOR_ID_CONTEXT_MENU = 3,
43 CURSOR_ID_COPY = 4,
44 CURSOR_ID_CREATE_LINK = 29,
45 CURSOR_ID_CROSS_HAIR = 5,
46 CURSOR_ID_FOLLOW_LINK = 6,
47 CURSOR_ID_GRAB = 7,
48 CURSOR_ID_GRABBING = 8,
49 CURSOR_ID_HELP = 9,
50 CURSOR_ID_I_BEAM = 2,
51 CURSOR_ID_I_BEAM_HORIZONTAL = 10,
52 CURSOR_ID_MOVE = 11,
41 CURSOR_ID_NO_CURSOR = 12, 53 CURSOR_ID_NO_CURSOR = 12,
54 CURSOR_ID_NOT_ALLOWED = 13,
55 CURSOR_ID_PROGRESS = 14,
42 CURSOR_ID_RESIZE_NORTH = 15, 56 CURSOR_ID_RESIZE_NORTH = 15,
43 CURSOR_ID_RESIZE_EAST = 16, 57 CURSOR_ID_RESIZE_EAST = 16,
44 CURSOR_ID_RESIZE_SOUTH = 17, 58 CURSOR_ID_RESIZE_SOUTH = 17,
@@ -50,7 +64,9 @@ enum haiku_cursor
50 CURSOR_ID_RESIZE_NORTH_SOUTH = 23, 64 CURSOR_ID_RESIZE_NORTH_SOUTH = 23,
51 CURSOR_ID_RESIZE_EAST_WEST = 24, 65 CURSOR_ID_RESIZE_EAST_WEST = 24,
52 CURSOR_ID_RESIZE_NORTH_EAST_SOUTH_WEST = 25, 66 CURSOR_ID_RESIZE_NORTH_EAST_SOUTH_WEST = 25,
53 CURSOR_ID_RESIZE_NORTH_WEST_SOUTH_EAST = 26 67 CURSOR_ID_RESIZE_NORTH_WEST_SOUTH_EAST = 26,
68 CURSOR_ID_ZOOM_IN = 27,
69 CURSOR_ID_ZOOM_OUT = 28
54 }; 70 };
55 71
56enum haiku_z_group 72enum haiku_z_group
@@ -96,9 +112,15 @@ enum haiku_event_type
96 DRAG_AND_DROP_EVENT, 112 DRAG_AND_DROP_EVENT,
97 APP_QUIT_REQUESTED_EVENT, 113 APP_QUIT_REQUESTED_EVENT,
98 DUMMY_EVENT, 114 DUMMY_EVENT,
99 MENU_BAR_LEFT 115 SCREEN_CHANGED_EVENT,
116 MENU_BAR_LEFT,
100 }; 117 };
101 118
119struct haiku_screen_changed_event
120{
121 bigtime_t when;
122};
123
102struct haiku_quit_requested_event 124struct haiku_quit_requested_event
103{ 125{
104 void *window; 126 void *window;
@@ -107,8 +129,8 @@ struct haiku_quit_requested_event
107struct haiku_resize_event 129struct haiku_resize_event
108{ 130{
109 void *window; 131 void *window;
110 float px_heightf; 132 float width;
111 float px_widthf; 133 float height;
112}; 134};
113 135
114struct haiku_expose_event 136struct haiku_expose_event
@@ -187,6 +209,7 @@ struct haiku_menu_bar_click_event
187struct haiku_button_event 209struct haiku_button_event
188{ 210{
189 void *window; 211 void *window;
212 void *scroll_bar;
190 int btn_no; 213 int btn_no;
191 int modifiers; 214 int modifiers;
192 int x; 215 int x;
@@ -203,8 +226,9 @@ struct haiku_iconification_event
203struct haiku_move_event 226struct haiku_move_event
204{ 227{
205 void *window; 228 void *window;
206 int x; 229 int x, y;
207 int y; 230 int decorator_width;
231 int decorator_height;
208}; 232};
209 233
210struct haiku_wheel_move_event 234struct haiku_wheel_move_event
@@ -232,7 +256,7 @@ struct haiku_menu_bar_help_event
232struct haiku_zoom_event 256struct haiku_zoom_event
233{ 257{
234 void *window; 258 void *window;
235 bool zoomed; 259 int fullscreen_mode;
236}; 260};
237 261
238enum haiku_font_specification 262enum haiku_font_specification
@@ -299,6 +323,15 @@ enum haiku_font_weight
299 HAIKU_MEDIUM = 2000, 323 HAIKU_MEDIUM = 2000,
300 }; 324 };
301 325
326enum haiku_fullscreen_mode
327 {
328 FULLSCREEN_MODE_NONE,
329 FULLSCREEN_MODE_WIDTH,
330 FULLSCREEN_MODE_HEIGHT,
331 FULLSCREEN_MODE_BOTH,
332 FULLSCREEN_MODE_MAXIMIZED,
333 };
334
302struct haiku_font_pattern 335struct haiku_font_pattern
303{ 336{
304 /* Bitmask indicating which fields are set. */ 337 /* Bitmask indicating which fields are set. */
@@ -421,32 +454,14 @@ struct haiku_session_manager_reply
421 dimensions of a BRect, instead of relying on the broken Width and 454 dimensions of a BRect, instead of relying on the broken Width and
422 Height functions. */ 455 Height functions. */
423 456
424#define BE_RECT_HEIGHT(rect) (ceil (((rect).bottom - (rect).top) + 1)) 457#define BE_RECT_HEIGHT(rect) (ceil (((rect).bottom - (rect).top) + 1))
425#define BE_RECT_WIDTH(rect) (ceil (((rect).right - (rect).left) + 1)) 458#define BE_RECT_WIDTH(rect) (ceil (((rect).right - (rect).left) + 1))
426#endif /* __cplusplus */ 459#endif /* __cplusplus */
427 460
428/* C++ code cannot include lisp.h, but file dialogs need to be able
429 to bind to the specpdl and handle quitting correctly. */
430
431#ifdef __cplusplus
432#if SIZE_MAX > 0xffffffff
433#define WRAP_SPECPDL_REF 1
434#endif
435#ifdef WRAP_SPECPDL_REF
436typedef struct { ptrdiff_t bytes; } specpdl_ref;
437#else
438typedef ptrdiff_t specpdl_ref;
439#endif
440
441#else
442#include "lisp.h"
443#endif
444
445#ifdef __cplusplus 461#ifdef __cplusplus
446extern "C" 462extern "C"
447{ 463{
448#endif 464#endif
449#include <pthread.h>
450#include <OS.h> 465#include <OS.h>
451 466
452#ifdef __cplusplus 467#ifdef __cplusplus
@@ -477,6 +492,8 @@ extern void hsl_color_rgb (double, double, double, uint32_t *);
477extern void *BBitmap_new (int, int, int); 492extern void *BBitmap_new (int, int, int);
478extern void *BBitmap_data (void *); 493extern void *BBitmap_data (void *);
479extern int BBitmap_convert (void *, void **); 494extern int BBitmap_convert (void *, void **);
495extern void be_draw_cross_on_pixmap (void *, int, int, int, int,
496 uint32_t);
480 497
481extern void BBitmap_free (void *); 498extern void BBitmap_free (void *);
482 499
@@ -496,7 +513,6 @@ extern void BWindow_center_on_screen (void *);
496extern void BWindow_change_decoration (void *, int); 513extern void BWindow_change_decoration (void *, int);
497extern void BWindow_set_tooltip_decoration (void *); 514extern void BWindow_set_tooltip_decoration (void *);
498extern void BWindow_set_avoid_focus (void *, int); 515extern void BWindow_set_avoid_focus (void *, int);
499extern void BWindow_zoom (void *);
500extern void BWindow_set_size_alignment (void *, int, int); 516extern void BWindow_set_size_alignment (void *, int, int);
501extern void BWindow_sync (void *); 517extern void BWindow_sync (void *);
502extern void BWindow_send_behind (void *, void *); 518extern void BWindow_send_behind (void *, void *);
@@ -541,6 +557,8 @@ extern void BView_DrawBitmap (void *, void *, int, int, int, int, int, int,
541extern void BView_DrawBitmapWithEraseOp (void *, void *, int, int, int, int); 557extern void BView_DrawBitmapWithEraseOp (void *, void *, int, int, int, int);
542extern void BView_DrawMask (void *, void *, int, int, int, int, int, int, 558extern void BView_DrawMask (void *, void *, int, int, int, int, int, int,
543 int, int, uint32_t); 559 int, int, uint32_t);
560extern void BView_DrawBitmapTiled (void *, void *, int, int,
561 int, int, int, int, int, int);
544 562
545extern void BView_resize_to (void *, int, int); 563extern void BView_resize_to (void *, int, int);
546extern void BView_set_view_cursor (void *, void *); 564extern void BView_set_view_cursor (void *, void *);
@@ -554,15 +572,11 @@ extern void be_get_display_resolution (double *, double *);
554extern void be_get_screen_dimensions (int *, int *); 572extern void be_get_screen_dimensions (int *, int *);
555 573
556/* Functions for creating and freeing cursors. */ 574/* Functions for creating and freeing cursors. */
557extern void *BCursor_create_default (void); 575extern void *be_create_cursor_from_id (int);
558extern void *BCursor_from_id (enum haiku_cursor); 576extern void *be_create_pixmap_cursor (void *, int, int);
559extern void *BCursor_create_modeline (void); 577extern void be_delete_cursor (void *);
560extern void *BCursor_create_i_beam (void); 578
561extern void *BCursor_create_progress_cursor (void); 579extern void *be_make_scroll_bar_for_view (void *, int, int, int, int, int);
562extern void *BCursor_create_grab (void);
563extern void BCursor_delete (void *);
564
565extern void *BScrollBar_make_for_view (void *, int, int, int, int, int, void *);
566extern void BScrollBar_delete (void *); 580extern void BScrollBar_delete (void *);
567extern int BScrollBar_default_size (int); 581extern int BScrollBar_default_size (int);
568 582
@@ -570,9 +584,7 @@ extern void BView_invalidate (void *);
570extern void BView_draw_lock (void *, bool, int, int, int, int); 584extern void BView_draw_lock (void *, bool, int, int, int, int);
571extern void BView_invalidate_region (void *, int, int, int, int); 585extern void BView_invalidate_region (void *, int, int, int, int);
572extern void BView_draw_unlock (void *); 586extern void BView_draw_unlock (void *);
573
574extern void BBitmap_import_fringe_bitmap (void *, unsigned short *, int, int); 587extern void BBitmap_import_fringe_bitmap (void *, unsigned short *, int, int);
575extern void BBitmap_import_mono_bits (void *, void *, int, int);
576 588
577extern void haiku_font_pattern_free (struct haiku_font_pattern *); 589extern void haiku_font_pattern_free (struct haiku_font_pattern *);
578 590
@@ -628,8 +640,6 @@ extern void BAlert_delete (void *);
628extern void EmacsWindow_parent_to (void *, void *); 640extern void EmacsWindow_parent_to (void *, void *);
629extern void EmacsWindow_unparent (void *); 641extern void EmacsWindow_unparent (void *);
630extern void EmacsWindow_move_weak_child (void *, void *, int, int); 642extern void EmacsWindow_move_weak_child (void *, void *, int, int);
631extern void EmacsWindow_make_fullscreen (void *, int);
632extern void EmacsWindow_unzoom (void *);
633 643
634extern void be_get_version_string (char *, int); 644extern void be_get_version_string (char *, int);
635extern int be_get_display_planes (void); 645extern int be_get_display_planes (void);
@@ -690,6 +700,16 @@ extern bool be_select_font (void (*) (void), bool (*) (void),
690 int *, bool, int, int, int); 700 int *, bool, int, int, int);
691 701
692extern int be_find_font_indices (struct haiku_font_pattern *, int *, int *); 702extern int be_find_font_indices (struct haiku_font_pattern *, int *, int *);
703extern status_t be_roster_launch (const char *, const char *, char **,
704 ptrdiff_t, void *, team_id *);
705extern void be_get_window_decorator_dimensions (void *, int *, int *, int *, int *);
706extern void be_get_window_decorator_frame (void *, int *, int *, int *, int *);
707extern void be_send_move_frame_event (void *);
708extern void be_set_window_fullscreen_mode (void *, enum haiku_fullscreen_mode);
709
710extern void be_lock_window (void *);
711extern void be_unlock_window (void *);
712extern bool be_get_explicit_workarea (int *, int *, int *, int *);
693#ifdef __cplusplus 713#ifdef __cplusplus
694} 714}
695 715
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/>. */
34#include "haiku_support.h" 34#include "haiku_support.h"
35#include "termhooks.h" 35#include "termhooks.h"
36 36
37#include "bitmaps/leftptr.xbm"
38#include "bitmaps/leftpmsk.xbm"
39
37#include <stdlib.h> 40#include <stdlib.h>
38 41
39#include <kernel/OS.h> 42#include <kernel/OS.h>
@@ -47,6 +50,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
47/* The frame of the currently visible tooltip. */ 50/* The frame of the currently visible tooltip. */
48Lisp_Object tip_frame; 51Lisp_Object tip_frame;
49 52
53/* The X and Y deltas of the last call to `x-show-tip'. */
54Lisp_Object tip_dx, tip_dy;
55
50/* The window-system window corresponding to the frame of the 56/* The window-system window corresponding to the frame of the
51 currently visible tooltip. */ 57 currently visible tooltip. */
52static Window tip_window; 58static Window tip_window;
@@ -93,7 +99,7 @@ get_geometry_from_preferences (struct haiku_display_info *dpyinfo,
93 Lisp_Object value 99 Lisp_Object value
94 = gui_display_get_arg (dpyinfo, parms, r[i].tem, r[i].val, r[i].cls, 100 = gui_display_get_arg (dpyinfo, parms, r[i].tem, r[i].val, r[i].cls,
95 RES_TYPE_NUMBER); 101 RES_TYPE_NUMBER);
96 if (! EQ (value, Qunbound)) 102 if (! BASE_EQ (value, Qunbound))
97 parms = Fcons (Fcons (r[i].tem, value), parms); 103 parms = Fcons (Fcons (r[i].tem, value), parms);
98 } 104 }
99 } 105 }
@@ -101,6 +107,22 @@ get_geometry_from_preferences (struct haiku_display_info *dpyinfo,
101 return parms; 107 return parms;
102} 108}
103 109
110/* Update the left and top offsets of F after its decorators
111 change. */
112static void
113haiku_update_after_decoration_change (struct frame *f)
114{
115 /* Don't reset offsets during initial frame creation, since the
116 contents of f->left_pos and f->top_pos won't be applied to the
117 window until `x-create-frame' finishes, so setting them here will
118 overwrite the offsets that the window should be moved to. */
119
120 if (!FRAME_OUTPUT_DATA (f)->configury_done)
121 return;
122
123 be_send_move_frame_event (FRAME_HAIKU_WINDOW (f));
124}
125
104void 126void
105haiku_change_tool_bar_height (struct frame *f, int height) 127haiku_change_tool_bar_height (struct frame *f, int height)
106{ 128{
@@ -249,6 +271,22 @@ haiku_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
249 haiku_change_tab_bar_height (f, nlines * FRAME_LINE_HEIGHT (f)); 271 haiku_change_tab_bar_height (f, nlines * FRAME_LINE_HEIGHT (f));
250} 272}
251 273
274void
275gamma_correct (struct frame *f, Emacs_Color *color)
276{
277 if (f->gamma)
278 {
279 color->red = (pow (color->red / 65535.0, f->gamma)
280 * 65535.0 + 0.5);
281 color->green = (pow (color->green / 65535.0, f->gamma)
282 * 65535.0 + 0.5);
283 color->blue = (pow (color->blue / 65535.0, f->gamma)
284 * 65535.0 + 0.5);
285 color->pixel = RGB_TO_ULONG (color->red / 256,
286 color->green / 256,
287 color->blue / 256);
288 }
289}
252 290
253int 291int
254haiku_get_color (const char *name, Emacs_Color *color) 292haiku_get_color (const char *name, Emacs_Color *color)
@@ -323,12 +361,12 @@ haiku_display_info_for_name (Lisp_Object name)
323{ 361{
324 CHECK_STRING (name); 362 CHECK_STRING (name);
325 363
326 if (!NILP (Fstring_equal (name, build_string ("be")))) 364 if (!strcmp (SSDATA (name), "be"))
327 { 365 {
328 if (!x_display_list) 366 if (x_display_list)
329 return x_display_list; 367 return x_display_list;
330 368
331 error ("Haiku windowing not initialized"); 369 return haiku_term_init ();
332 } 370 }
333 371
334 error ("Haiku displays can only be named \"be\""); 372 error ("Haiku displays can only be named \"be\"");
@@ -498,8 +536,12 @@ haiku_set_z_group (struct frame *f, Lisp_Object new_value,
498 rc = 0; 536 rc = 0;
499 537
500 unblock_input (); 538 unblock_input ();
539
501 if (!rc) 540 if (!rc)
502 error ("Invalid z-group specification"); 541 error ("Invalid z-group specification");
542
543 /* Setting the Z-group can change the frame's decorator. */
544 haiku_update_after_decoration_change (f);
503} 545}
504 546
505static void 547static void
@@ -578,37 +620,34 @@ unwind_create_tip_frame (Lisp_Object frame)
578 tip_frame = Qnil; 620 tip_frame = Qnil;
579} 621}
580 622
581static void 623static unsigned long
582haiku_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) 624haiku_decode_color (struct frame *f, Lisp_Object color_name)
583{ 625{
584 struct haiku_output *output = FRAME_OUTPUT_DATA (f); 626 Emacs_Color cdef;
585 unsigned long old_fg;
586 627
587 Emacs_Color color; 628 CHECK_STRING (color_name);
588 629
589 if (haiku_get_color (SSDATA (arg), &color)) 630 if (!haiku_get_color (SSDATA (color_name), &cdef))
590 { 631 return cdef.pixel;
591 store_frame_param (f, Qforeground_color, oldval); 632
592 unblock_input (); 633 signal_error ("Undefined color", color_name);
593 error ("Bad color"); 634}
594 }
595 635
636static void
637haiku_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
638{
639 struct haiku_output *output;
640 unsigned long fg, old_fg;
641
642 fg = haiku_decode_color (f, arg);
596 old_fg = FRAME_FOREGROUND_PIXEL (f); 643 old_fg = FRAME_FOREGROUND_PIXEL (f);
597 FRAME_FOREGROUND_PIXEL (f) = color.pixel; 644 FRAME_FOREGROUND_PIXEL (f) = fg;
645 output = FRAME_OUTPUT_DATA (f);
598 646
599 if (FRAME_HAIKU_WINDOW (f)) 647 if (FRAME_HAIKU_WINDOW (f))
600 { 648 {
601
602 block_input ();
603 if (output->cursor_color.pixel == old_fg) 649 if (output->cursor_color.pixel == old_fg)
604 { 650 haiku_query_color (fg, &output->cursor_color);
605 output->cursor_color.pixel = old_fg;
606 output->cursor_color.red = RED_FROM_ULONG (old_fg);
607 output->cursor_color.green = GREEN_FROM_ULONG (old_fg);
608 output->cursor_color.blue = BLUE_FROM_ULONG (old_fg);
609 }
610
611 unblock_input ();
612 651
613 update_face_from_frame_parameter (f, Qforeground_color, arg); 652 update_face_from_frame_parameter (f, Qforeground_color, arg);
614 653
@@ -648,7 +687,7 @@ haiku_create_frame (Lisp_Object parms)
648 687
649 display = gui_display_get_arg (dpyinfo, parms, Qterminal, 0, 0, 688 display = gui_display_get_arg (dpyinfo, parms, Qterminal, 0, 0,
650 RES_TYPE_STRING); 689 RES_TYPE_STRING);
651 if (EQ (display, Qunbound)) 690 if (BASE_EQ (display, Qunbound))
652 display = Qnil; 691 display = Qnil;
653 dpyinfo = check_haiku_display_info (display); 692 dpyinfo = check_haiku_display_info (display);
654 kb = dpyinfo->terminal->kboard; 693 kb = dpyinfo->terminal->kboard;
@@ -659,7 +698,7 @@ haiku_create_frame (Lisp_Object parms)
659 name = gui_display_get_arg (dpyinfo, parms, Qname, 0, 0, 698 name = gui_display_get_arg (dpyinfo, parms, Qname, 0, 0,
660 RES_TYPE_STRING); 699 RES_TYPE_STRING);
661 if (!STRINGP (name) 700 if (!STRINGP (name)
662 && ! EQ (name, Qunbound) 701 && ! BASE_EQ (name, Qunbound)
663 && ! NILP (name)) 702 && ! NILP (name))
664 error ("Invalid frame name--not a string or nil"); 703 error ("Invalid frame name--not a string or nil");
665 704
@@ -707,7 +746,7 @@ haiku_create_frame (Lisp_Object parms)
707 746
708 /* Set the name; the functions to which we pass f expect the name to 747 /* Set the name; the functions to which we pass f expect the name to
709 be set. */ 748 be set. */
710 if (EQ (name, Qunbound) || NILP (name) || ! STRINGP (name)) 749 if (BASE_EQ (name, Qunbound) || NILP (name) || ! STRINGP (name))
711 { 750 {
712 fset_name (f, Vinvocation_name); 751 fset_name (f, Vinvocation_name);
713 f->explicit_name = 0; 752 f->explicit_name = 0;
@@ -763,6 +802,8 @@ haiku_create_frame (Lisp_Object parms)
763 "foreground", "Foreground", RES_TYPE_STRING); 802 "foreground", "Foreground", RES_TYPE_STRING);
764 gui_default_parameter (f, parms, Qbackground_color, build_string ("white"), 803 gui_default_parameter (f, parms, Qbackground_color, build_string ("white"),
765 "background", "Background", RES_TYPE_STRING); 804 "background", "Background", RES_TYPE_STRING);
805 gui_default_parameter (f, parms, Qmouse_color, build_string ("font-color"),
806 "pointerColor", "Foreground", RES_TYPE_STRING);
766 gui_default_parameter (f, parms, Qline_spacing, Qnil, 807 gui_default_parameter (f, parms, Qline_spacing, Qnil,
767 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER); 808 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
768 gui_default_parameter (f, parms, Qleft_fringe, Qnil, 809 gui_default_parameter (f, parms, Qleft_fringe, Qnil,
@@ -818,36 +859,11 @@ haiku_create_frame (Lisp_Object parms)
818 859
819 tem = gui_display_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, 860 tem = gui_display_get_arg (dpyinfo, parms, Qunsplittable, 0, 0,
820 RES_TYPE_BOOLEAN); 861 RES_TYPE_BOOLEAN);
821 f->no_split = minibuffer_only || (!EQ (tem, Qunbound) && !NILP (tem)); 862 f->no_split = minibuffer_only || (!BASE_EQ (tem, Qunbound) && !NILP (tem));
822
823 block_input ();
824#define ASSIGN_CURSOR(cursor) \
825 (FRAME_OUTPUT_DATA (f)->cursor = dpyinfo->cursor)
826
827 ASSIGN_CURSOR (text_cursor);
828 ASSIGN_CURSOR (nontext_cursor);
829 ASSIGN_CURSOR (modeline_cursor);
830 ASSIGN_CURSOR (hand_cursor);
831 ASSIGN_CURSOR (hourglass_cursor);
832 ASSIGN_CURSOR (horizontal_drag_cursor);
833 ASSIGN_CURSOR (vertical_drag_cursor);
834 ASSIGN_CURSOR (left_edge_cursor);
835 ASSIGN_CURSOR (top_left_corner_cursor);
836 ASSIGN_CURSOR (top_edge_cursor);
837 ASSIGN_CURSOR (top_right_corner_cursor);
838 ASSIGN_CURSOR (right_edge_cursor);
839 ASSIGN_CURSOR (bottom_right_corner_cursor);
840 ASSIGN_CURSOR (bottom_edge_cursor);
841 ASSIGN_CURSOR (bottom_left_corner_cursor);
842 ASSIGN_CURSOR (no_cursor);
843
844 FRAME_OUTPUT_DATA (f)->current_cursor = dpyinfo->text_cursor;
845#undef ASSIGN_CURSOR
846 863
847 f->terminal->reference_count++; 864 f->terminal->reference_count++;
848 865
849 FRAME_OUTPUT_DATA (f)->window = BWindow_new (&FRAME_OUTPUT_DATA (f)->view); 866 FRAME_OUTPUT_DATA (f)->window = BWindow_new (&FRAME_OUTPUT_DATA (f)->view);
850 unblock_input ();
851 867
852 if (!FRAME_OUTPUT_DATA (f)->window) 868 if (!FRAME_OUTPUT_DATA (f)->window)
853 xsignal1 (Qerror, build_unibyte_string ("Could not create window")); 869 xsignal1 (Qerror, build_unibyte_string ("Could not create window"));
@@ -859,10 +875,11 @@ haiku_create_frame (Lisp_Object parms)
859 875
860 Vframe_list = Fcons (frame, Vframe_list); 876 Vframe_list = Fcons (frame, Vframe_list);
861 877
862 Lisp_Object parent_frame = gui_display_get_arg (dpyinfo, parms, Qparent_frame, NULL, NULL, 878 Lisp_Object parent_frame = gui_display_get_arg (dpyinfo, parms,
879 Qparent_frame, NULL, NULL,
863 RES_TYPE_SYMBOL); 880 RES_TYPE_SYMBOL);
864 881
865 if (EQ (parent_frame, Qunbound) 882 if (BASE_EQ (parent_frame, Qunbound)
866 || NILP (parent_frame) 883 || NILP (parent_frame)
867 || !FRAMEP (parent_frame) 884 || !FRAMEP (parent_frame)
868 || !FRAME_LIVE_P (XFRAME (parent_frame))) 885 || !FRAME_LIVE_P (XFRAME (parent_frame)))
@@ -916,7 +933,7 @@ haiku_create_frame (Lisp_Object parms)
916 933
917 visibility = gui_display_get_arg (dpyinfo, parms, Qvisibility, 0, 0, 934 visibility = gui_display_get_arg (dpyinfo, parms, Qvisibility, 0, 0,
918 RES_TYPE_SYMBOL); 935 RES_TYPE_SYMBOL);
919 if (EQ (visibility, Qunbound)) 936 if (BASE_EQ (visibility, Qunbound))
920 visibility = Qt; 937 visibility = Qt;
921 if (EQ (visibility, Qicon)) 938 if (EQ (visibility, Qicon))
922 haiku_iconify_frame (f); 939 haiku_iconify_frame (f);
@@ -989,7 +1006,7 @@ haiku_create_tip_frame (Lisp_Object parms)
989 name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name", 1006 name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name",
990 RES_TYPE_STRING); 1007 RES_TYPE_STRING);
991 if (!STRINGP (name) 1008 if (!STRINGP (name)
992 && !EQ (name, Qunbound) 1009 && !BASE_EQ (name, Qunbound)
993 && !NILP (name)) 1010 && !NILP (name))
994 error ("Invalid frame name--not a string or nil"); 1011 error ("Invalid frame name--not a string or nil");
995 1012
@@ -1018,7 +1035,7 @@ haiku_create_tip_frame (Lisp_Object parms)
1018 1035
1019 /* Set the name; the functions to which we pass f expect the name to 1036 /* Set the name; the functions to which we pass f expect the name to
1020 be set. */ 1037 be set. */
1021 if (EQ (name, Qunbound) || NILP (name)) 1038 if (BASE_EQ (name, Qunbound) || NILP (name))
1022 f->explicit_name = false; 1039 f->explicit_name = false;
1023 else 1040 else
1024 { 1041 {
@@ -1056,7 +1073,7 @@ haiku_create_tip_frame (Lisp_Object parms)
1056 value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width, 1073 value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width,
1057 "internalBorder", "internalBorder", 1074 "internalBorder", "internalBorder",
1058 RES_TYPE_NUMBER); 1075 RES_TYPE_NUMBER);
1059 if (! EQ (value, Qunbound)) 1076 if (! BASE_EQ (value, Qunbound))
1060 parms = Fcons (Fcons (Qinternal_border_width, value), 1077 parms = Fcons (Fcons (Qinternal_border_width, value),
1061 parms); 1078 parms);
1062 } 1079 }
@@ -1076,7 +1093,10 @@ haiku_create_tip_frame (Lisp_Object parms)
1076 1093
1077 gui_default_parameter (f, parms, Qbackground_color, build_string ("white"), 1094 gui_default_parameter (f, parms, Qbackground_color, build_string ("white"),
1078 "background", "Background", RES_TYPE_STRING); 1095 "background", "Background", RES_TYPE_STRING);
1079 gui_default_parameter (f, parms, Qmouse_color, build_string ("black"), 1096
1097 /* FIXME: is there a better method to tell Emacs to not recolor the
1098 cursors other than setting the color to a special value? */
1099 gui_default_parameter (f, parms, Qmouse_color, build_string ("font-color"),
1080 "pointerColor", "Foreground", RES_TYPE_STRING); 1100 "pointerColor", "Foreground", RES_TYPE_STRING);
1081 gui_default_parameter (f, parms, Qcursor_color, build_string ("black"), 1101 gui_default_parameter (f, parms, Qcursor_color, build_string ("black"),
1082 "cursorColor", "Foreground", RES_TYPE_STRING); 1102 "cursorColor", "Foreground", RES_TYPE_STRING);
@@ -1133,6 +1153,23 @@ haiku_create_tip_frame (Lisp_Object parms)
1133 /* FIXME - can this be done in a similar way to normal frames? 1153 /* FIXME - can this be done in a similar way to normal frames?
1134 https://lists.gnu.org/r/emacs-devel/2007-10/msg00641.html */ 1154 https://lists.gnu.org/r/emacs-devel/2007-10/msg00641.html */
1135 1155
1156 {
1157 Lisp_Object disptype;
1158
1159 if (be_get_display_planes () == 1)
1160 disptype = Qmono;
1161 else if (be_is_display_grayscale ())
1162 disptype = Qgrayscale;
1163 else
1164 disptype = Qcolor;
1165
1166 if (NILP (Fframe_parameter (frame, Qdisplay_type)))
1167 {
1168 AUTO_FRAME_ARG (arg, Qdisplay_type, disptype);
1169 Fmodify_frame_parameters (frame, arg);
1170 }
1171 }
1172
1136 /* Set up faces after all frame parameters are known. This call 1173 /* Set up faces after all frame parameters are known. This call
1137 also merges in face attributes specified for new frames. 1174 also merges in face attributes specified for new frames.
1138 1175
@@ -1312,6 +1349,8 @@ haiku_set_undecorated (struct frame *f, Lisp_Object new_value,
1312 FRAME_UNDECORATED (f) = !NILP (new_value); 1349 FRAME_UNDECORATED (f) = !NILP (new_value);
1313 BWindow_change_decoration (FRAME_HAIKU_WINDOW (f), NILP (new_value)); 1350 BWindow_change_decoration (FRAME_HAIKU_WINDOW (f), NILP (new_value));
1314 unblock_input (); 1351 unblock_input ();
1352
1353 haiku_update_after_decoration_change (f);
1315} 1354}
1316 1355
1317static void 1356static void
@@ -1326,6 +1365,8 @@ haiku_set_override_redirect (struct frame *f, Lisp_Object new_value,
1326 !NILP (new_value)); 1365 !NILP (new_value));
1327 FRAME_OVERRIDE_REDIRECT (f) = !NILP (new_value); 1366 FRAME_OVERRIDE_REDIRECT (f) = !NILP (new_value);
1328 unblock_input (); 1367 unblock_input ();
1368
1369 haiku_update_after_decoration_change (f);
1329} 1370}
1330 1371
1331static void 1372static void
@@ -1372,122 +1413,129 @@ haiku_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval
1372static Lisp_Object 1413static Lisp_Object
1373frame_geometry (Lisp_Object frame, Lisp_Object attribute) 1414frame_geometry (Lisp_Object frame, Lisp_Object attribute)
1374{ 1415{
1375 struct frame *f = decode_live_frame (frame); 1416 struct frame *f, *parent;
1376 check_window_system (f); 1417 void *window;
1418 int outer_x, outer_y, outer_width, outer_height;
1419 int right_off, bottom_off, top_off;
1420 int native_x, native_y;
1421
1422 f = decode_window_system_frame (frame);
1423 parent = FRAME_PARENT_FRAME (f);
1424 window = FRAME_HAIKU_WINDOW (f);
1425
1426 be_lock_window (window);
1427 be_get_window_decorator_frame (window, &outer_x, &outer_y,
1428 &outer_width, &outer_height);
1429 be_get_window_decorator_dimensions (window, NULL, &top_off,
1430 &right_off, &bottom_off);
1431 be_unlock_window (window);
1432
1433 native_x = FRAME_OUTPUT_DATA (f)->frame_x;
1434 native_y = FRAME_OUTPUT_DATA (f)->frame_y;
1435
1436 if (parent)
1437 {
1438 /* Adjust all the coordinates by the coordinates of the parent
1439 frame. */
1440 outer_x -= FRAME_OUTPUT_DATA (parent)->frame_x;
1441 outer_y -= FRAME_OUTPUT_DATA (parent)->frame_y;
1442 native_x -= FRAME_OUTPUT_DATA (parent)->frame_x;
1443 native_y -= FRAME_OUTPUT_DATA (parent)->frame_y;
1444 }
1377 1445
1378 if (EQ (attribute, Qouter_edges)) 1446 if (EQ (attribute, Qouter_edges))
1379 return list4i (f->left_pos, f->top_pos, 1447 return list4i (outer_x, outer_y,
1380 f->left_pos, f->top_pos); 1448 outer_x + outer_width,
1449 outer_y + outer_height);
1381 else if (EQ (attribute, Qnative_edges)) 1450 else if (EQ (attribute, Qnative_edges))
1382 return list4i (f->left_pos, f->top_pos, 1451 return list4i (native_x, native_y,
1383 f->left_pos + FRAME_PIXEL_WIDTH (f), 1452 native_x + FRAME_PIXEL_WIDTH (f),
1384 f->top_pos + FRAME_PIXEL_HEIGHT (f)); 1453 native_y + FRAME_PIXEL_HEIGHT (f));
1385 else if (EQ (attribute, Qinner_edges)) 1454 else if (EQ (attribute, Qinner_edges))
1386 return list4i (f->left_pos + FRAME_INTERNAL_BORDER_WIDTH (f), 1455 return list4i (native_x + FRAME_INTERNAL_BORDER_WIDTH (f),
1387 f->top_pos + FRAME_INTERNAL_BORDER_WIDTH (f) + 1456 native_y + FRAME_INTERNAL_BORDER_WIDTH (f)
1388 FRAME_MENU_BAR_HEIGHT (f) + FRAME_TOOL_BAR_HEIGHT (f), 1457 + FRAME_MENU_BAR_HEIGHT (f) + FRAME_TOOL_BAR_HEIGHT (f),
1389 f->left_pos - FRAME_INTERNAL_BORDER_WIDTH (f) + 1458 native_x - FRAME_INTERNAL_BORDER_WIDTH (f)
1390 FRAME_PIXEL_WIDTH (f), 1459 + FRAME_PIXEL_WIDTH (f),
1391 f->top_pos + FRAME_PIXEL_HEIGHT (f) - 1460 native_y + FRAME_PIXEL_HEIGHT (f)
1392 FRAME_INTERNAL_BORDER_WIDTH (f)); 1461 - FRAME_INTERNAL_BORDER_WIDTH (f));
1393 1462
1394 else 1463 else
1395 return 1464 return list (Fcons (Qouter_position,
1396 list (Fcons (Qouter_position, 1465 Fcons (make_fixnum (outer_x),
1397 Fcons (make_fixnum (f->left_pos), 1466 make_fixnum (outer_y))),
1398 make_fixnum (f->top_pos))), 1467 Fcons (Qouter_size,
1399 Fcons (Qouter_size, 1468 Fcons (make_fixnum (outer_width),
1400 Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f)), 1469 make_fixnum (outer_height))),
1401 make_fixnum (FRAME_PIXEL_HEIGHT (f)))), 1470 Fcons (Qexternal_border_size,
1402 Fcons (Qexternal_border_size, 1471 Fcons (make_fixnum (right_off),
1403 Fcons (make_fixnum (0), make_fixnum (0))), 1472 make_fixnum (bottom_off))),
1404 Fcons (Qtitle_bar_size, 1473 Fcons (Qtitle_bar_size,
1405 Fcons (make_fixnum (0), make_fixnum (0))), 1474 Fcons (make_fixnum (outer_width),
1406 Fcons (Qmenu_bar_external, Qnil), 1475 make_fixnum (top_off))),
1407 Fcons (Qmenu_bar_size, Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f) - 1476 Fcons (Qmenu_bar_external, Qnil),
1408 (FRAME_INTERNAL_BORDER_WIDTH (f) * 2)), 1477 Fcons (Qmenu_bar_size,
1409 make_fixnum (FRAME_MENU_BAR_HEIGHT (f)))), 1478 Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f)
1410 Fcons (Qtool_bar_external, Qnil), 1479 - (FRAME_INTERNAL_BORDER_WIDTH (f) * 2)),
1411 Fcons (Qtool_bar_position, Qtop), 1480 make_fixnum (FRAME_MENU_BAR_HEIGHT (f)))),
1412 Fcons (Qtool_bar_size, Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f) - 1481 Fcons (Qtool_bar_external, Qnil),
1413 (FRAME_INTERNAL_BORDER_WIDTH (f) * 2)), 1482 Fcons (Qtool_bar_position, Qtop),
1414 make_fixnum (FRAME_TOOL_BAR_HEIGHT (f)))), 1483 Fcons (Qtool_bar_size,
1415 Fcons (Qinternal_border_width, make_fixnum (FRAME_INTERNAL_BORDER_WIDTH (f)))); 1484 Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f)
1485 - (FRAME_INTERNAL_BORDER_WIDTH (f) * 2)),
1486 make_fixnum (FRAME_TOOL_BAR_HEIGHT (f)))),
1487 Fcons (Qinternal_border_width,
1488 make_fixnum (FRAME_INTERNAL_BORDER_WIDTH (f))));
1416} 1489}
1417 1490
1418void 1491void
1419haiku_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) 1492haiku_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
1420{ 1493{
1421 Emacs_Color color; 1494 unsigned long background;
1422 struct face *defface;
1423 1495
1424 CHECK_STRING (arg); 1496 background = haiku_decode_color (f, arg);
1425 1497
1426 block_input (); 1498 FRAME_OUTPUT_DATA (f)->cursor_fg = background;
1427 if (haiku_get_color (SSDATA (arg), &color)) 1499 FRAME_BACKGROUND_PIXEL (f) = background;
1428 {
1429 store_frame_param (f, Qbackground_color, oldval);
1430 unblock_input ();
1431 error ("Bad color");
1432 }
1433
1434 FRAME_OUTPUT_DATA (f)->cursor_fg = color.pixel;
1435 FRAME_BACKGROUND_PIXEL (f) = color.pixel;
1436 1500
1437 if (FRAME_HAIKU_VIEW (f)) 1501 if (FRAME_HAIKU_VIEW (f))
1438 { 1502 {
1439 BView_draw_lock (FRAME_HAIKU_VIEW (f), false, 0, 0, 0, 0); 1503 BView_draw_lock (FRAME_HAIKU_VIEW (f), false, 0, 0, 0, 0);
1440 BView_SetViewColor (FRAME_HAIKU_VIEW (f), color.pixel); 1504 BView_SetViewColor (FRAME_HAIKU_VIEW (f), background);
1441 BView_draw_unlock (FRAME_HAIKU_VIEW (f)); 1505 BView_draw_unlock (FRAME_HAIKU_VIEW (f));
1442 1506
1443 defface = FACE_FROM_ID_OR_NULL (f, DEFAULT_FACE_ID); 1507 FRAME_OUTPUT_DATA (f)->cursor_fg = background;
1444 if (defface) 1508 update_face_from_frame_parameter (f, Qbackground_color, arg);
1445 {
1446 defface->background = color.pixel;
1447 update_face_from_frame_parameter (f, Qbackground_color, arg);
1448 clear_frame (f);
1449 }
1450 }
1451 1509
1452 if (FRAME_VISIBLE_P (f)) 1510 if (FRAME_VISIBLE_P (f))
1453 SET_FRAME_GARBAGED (f); 1511 redraw_frame (f);
1454 unblock_input (); 1512 }
1455} 1513}
1456 1514
1457void 1515void
1458haiku_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) 1516haiku_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
1459{ 1517{
1460 Emacs_Color color, fore_pixel; 1518 unsigned long fore_pixel, pixel;
1461
1462 CHECK_STRING (arg);
1463 block_input ();
1464
1465 if (haiku_get_color (SSDATA (arg), &color))
1466 {
1467 store_frame_param (f, Qcursor_color, oldval);
1468 unblock_input ();
1469 error ("Bad color");
1470 }
1471 1519
1472 FRAME_CURSOR_COLOR (f) = color; 1520 pixel = haiku_decode_color (f, arg);
1473 1521
1474 if (STRINGP (Vx_cursor_fore_pixel)) 1522 if (!NILP (Vx_cursor_fore_pixel))
1475 { 1523 {
1476 if (haiku_get_color (SSDATA (Vx_cursor_fore_pixel), 1524 fore_pixel = haiku_decode_color (f, Vx_cursor_fore_pixel);
1477 &fore_pixel)) 1525 FRAME_OUTPUT_DATA (f)->cursor_fg = fore_pixel;
1478 error ("Bad color %s", SSDATA (Vx_cursor_fore_pixel));
1479 FRAME_OUTPUT_DATA (f)->cursor_fg = fore_pixel.pixel;
1480 } 1526 }
1481 else 1527 else
1482 FRAME_OUTPUT_DATA (f)->cursor_fg = FRAME_BACKGROUND_PIXEL (f); 1528 FRAME_OUTPUT_DATA (f)->cursor_fg = FRAME_BACKGROUND_PIXEL (f);
1483 1529
1530 haiku_query_color (pixel, &FRAME_CURSOR_COLOR (f));
1531
1484 if (FRAME_VISIBLE_P (f)) 1532 if (FRAME_VISIBLE_P (f))
1485 { 1533 {
1486 gui_update_cursor (f, 0); 1534 gui_update_cursor (f, false);
1487 gui_update_cursor (f, 1); 1535 gui_update_cursor (f, true);
1488 } 1536 }
1537
1489 update_face_from_frame_parameter (f, Qcursor_color, arg); 1538 update_face_from_frame_parameter (f, Qcursor_color, arg);
1490 unblock_input ();
1491} 1539}
1492 1540
1493void 1541void
@@ -1567,6 +1615,7 @@ haiku_free_frame_resources (struct frame *f)
1567 dpyinfo = FRAME_DISPLAY_INFO (f); 1615 dpyinfo = FRAME_DISPLAY_INFO (f);
1568 1616
1569 free_frame_faces (f); 1617 free_frame_faces (f);
1618 haiku_free_custom_cursors (f);
1570 1619
1571 /* Free scroll bars */ 1620 /* Free scroll bars */
1572 for (bar = FRAME_SCROLL_BARS (f); !NILP (bar); bar = b->next) 1621 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,
1792 unblock_input (); 1841 unblock_input ();
1793} 1842}
1794 1843
1844struct user_cursor_info
1845{
1846 /* A pointer to the Lisp_Object describing the cursor. */
1847 Lisp_Object *lisp_cursor;
1848
1849 /* The offset of the cursor in the `struct haiku_output' of each
1850 frame. */
1851 ptrdiff_t output_offset;
1852
1853 /* The offset of the default value of the cursor in the display
1854 info structure. */
1855 ptrdiff_t default_offset;
1856};
1857
1858struct user_cursor_bitmap_info
1859{
1860 /* A bitmap to use instead of the font cursor to create cursors in a
1861 certain color. */
1862 const void *bits;
1863
1864 /* The mask for that bitmap. */
1865 const void *mask;
1866
1867 /* The dimensions of the cursor bitmap. */
1868 int width, height;
1869
1870 /* The position inside the cursor bitmap corresponding to the
1871 position of the mouse pointer. */
1872 int x, y;
1873};
1874
1875#define INIT_USER_CURSOR(lisp, cursor) \
1876 { (lisp), offsetof (struct haiku_output, cursor), \
1877 offsetof (struct haiku_display_info, cursor) }
1878
1879struct user_cursor_info custom_cursors[] =
1880 {
1881 INIT_USER_CURSOR (&Vx_pointer_shape, text_cursor),
1882 INIT_USER_CURSOR (NULL, nontext_cursor),
1883 INIT_USER_CURSOR (NULL, modeline_cursor),
1884 INIT_USER_CURSOR (&Vx_sensitive_text_pointer_shape, hand_cursor),
1885 INIT_USER_CURSOR (&Vx_hourglass_pointer_shape, hourglass_cursor),
1886 INIT_USER_CURSOR (NULL, horizontal_drag_cursor),
1887 INIT_USER_CURSOR (NULL, vertical_drag_cursor),
1888 INIT_USER_CURSOR (NULL, left_edge_cursor),
1889 INIT_USER_CURSOR (NULL, top_left_corner_cursor),
1890 INIT_USER_CURSOR (NULL, top_edge_cursor),
1891 INIT_USER_CURSOR (NULL, top_right_corner_cursor),
1892 INIT_USER_CURSOR (NULL, right_edge_cursor),
1893 INIT_USER_CURSOR (NULL, bottom_right_corner_cursor),
1894 INIT_USER_CURSOR (NULL, bottom_edge_cursor),
1895 INIT_USER_CURSOR (NULL, bottom_left_corner_cursor),
1896 INIT_USER_CURSOR (NULL, no_cursor),
1897 };
1898
1899struct user_cursor_bitmap_info cursor_bitmaps[] =
1900 {
1901 { ibeam_ptr_bits, ibeam_ptrmask_bits, 15, 15, 7, 7 }, /* text_cursor */
1902 { left_ptr_bits, left_ptrmsk_bits, 16, 16, 3, 1 }, /* nontext_cursor */
1903 { left_ptr_bits, left_ptrmsk_bits, 16, 16, 3, 1 }, /* modeline_cursor */
1904 { hand_ptr_bits, hand_ptrmask_bits, 15, 15, 4, 3 }, /* hand_cursor */
1905 { hourglass_bits, hourglass_mask_bits, 15, 15, 7, 7 }, /* hourglass_cursor */
1906 { horizd_ptr_bits, horizd_ptrmask_bits, 15, 15, 7, 7 }, /* horizontal_drag_cursor */
1907 { vertd_ptr_bits, vertd_ptrmask_bits, 15, 15, 7, 7 }, /* vertical_drag_cursor */
1908 { NULL, NULL, 0, 0, 0, 0 }, /* left_edge_cursor */
1909 { NULL, NULL, 0, 0, 0, 0 }, /* top_left_corner_cursor */
1910 { NULL, NULL, 0, 0, 0, 0 }, /* top_edge_cursor */
1911 { NULL, NULL, 0, 0, 0, 0 }, /* top_right_corner_cursor */
1912 { NULL, NULL, 0, 0, 0, 0 }, /* right_edge_cursor */
1913 { NULL, NULL, 0, 0, 0, 0 }, /* bottom_right_corner_cursor */
1914 { NULL, NULL, 0, 0, 0, 0 }, /* bottom_edge_cursor */
1915 { NULL, NULL, 0, 0, 0, 0 }, /* bottom_left_corner_cursor */
1916 { NULL, NULL, 0, 0, 0, 0 }, /* no_cursor */
1917 };
1918
1919/* Array of cursor bitmaps for each system cursor ID. This is used to
1920 color in user-specified cursors. */
1921struct user_cursor_bitmap_info cursor_bitmaps_for_id[28] =
1922 {
1923 { NULL, NULL, 0, 0, 0, 0 },
1924 { left_ptr_bits, left_ptrmsk_bits, 16, 16, 3, 1 },
1925 { ibeam_ptr_bits, ibeam_ptrmask_bits, 15, 15, 7, 7 },
1926 { NULL, NULL, 0, 0, 0, 0 },
1927 { NULL, NULL, 0, 0, 0, 0 },
1928 { cross_ptr_bits, cross_ptrmask_bits, 30, 30, 15, 15 },
1929 { NULL, NULL, 0, 0, 0, 0 },
1930 { hand_ptr_bits, hand_ptrmask_bits, 15, 15, 4, 3 },
1931 { NULL, NULL, 0, 0, 0, 0 },
1932 { NULL, NULL, 0, 0, 0, 0 },
1933 { NULL, NULL, 0, 0, 0, 0 },
1934 { NULL, NULL, 0, 0, 0, 0 },
1935 { NULL, NULL, 0, 0, 0, 0 },
1936 { NULL, NULL, 0, 0, 0, 0 },
1937 { hourglass_bits, hourglass_mask_bits, 15, 15, 7, 7 },
1938 { NULL, NULL, 0, 0, 0, 0 },
1939 { NULL, NULL, 0, 0, 0, 0 },
1940 { NULL, NULL, 0, 0, 0, 0 },
1941 { NULL, NULL, 0, 0, 0, 0 },
1942 { NULL, NULL, 0, 0, 0, 0 },
1943 { NULL, NULL, 0, 0, 0, 0 },
1944 { NULL, NULL, 0, 0, 0, 0 },
1945 { NULL, NULL, 0, 0, 0, 0 },
1946 { horizd_ptr_bits, horizd_ptrmask_bits, 15, 15, 7, 7 },
1947 { vertd_ptr_bits, vertd_ptrmask_bits, 15, 15, 7, 7 },
1948 { NULL, NULL, 0, 0, 0, 0 },
1949 { NULL, NULL, 0, 0, 0, 0 },
1950 { NULL, NULL, 0, 0, 0, 0 },
1951 };
1952
1953static void *
1954haiku_create_colored_cursor (struct user_cursor_bitmap_info *info,
1955 uint32_t foreground, uint32_t background)
1956{
1957 const char *bits, *mask;
1958 void *bitmap, *cursor;
1959 int width, height, bytes_per_line, x, y;
1960
1961 bits = info->bits;
1962 mask = info->mask;
1963 width = info->width;
1964 height = info->height;
1965 bytes_per_line = (width + 7) / 8;
1966
1967 bitmap = BBitmap_new (width, height, false);
1968
1969 if (!bitmap)
1970 memory_full (SIZE_MAX);
1971
1972 for (y = 0; y < height; ++y)
1973 {
1974 for (x = 0; x < width; ++x)
1975 {
1976 if (mask[x / 8] >> (x % 8) & 1)
1977 haiku_put_pixel (bitmap, x, y,
1978 (bits[x / 8] >> (x % 8) & 1
1979 ? (foreground | 255u << 24)
1980 : (background | 255u << 24)));
1981 else
1982 haiku_put_pixel (bitmap, x, y, 0);
1983 }
1984
1985 mask += bytes_per_line;
1986 bits += bytes_per_line;
1987 }
1988
1989 cursor = be_create_pixmap_cursor (bitmap, info->x, info->y);
1990 BBitmap_free (bitmap);
1991
1992 return cursor;
1993}
1994
1995/* Free all cursors on F that were allocated specifically for the
1996 frame. */
1997void
1998haiku_free_custom_cursors (struct frame *f)
1999{
2000 struct user_cursor_info *cursor;
2001 struct haiku_output *output;
2002 struct haiku_display_info *dpyinfo;
2003 Emacs_Cursor *frame_cursor;
2004 Emacs_Cursor *display_cursor;
2005 int i;
2006
2007 output = FRAME_OUTPUT_DATA (f);
2008 dpyinfo = FRAME_DISPLAY_INFO (f);
2009
2010 for (i = 0; i < ARRAYELTS (custom_cursors); ++i)
2011 {
2012 cursor = &custom_cursors[i];
2013 frame_cursor = (Emacs_Cursor *) ((char *) output
2014 + cursor->output_offset);
2015 display_cursor = (Emacs_Cursor *) ((char *) dpyinfo
2016 + cursor->default_offset);
2017
2018 if (*frame_cursor != *display_cursor && *frame_cursor)
2019 {
2020 if (output->current_cursor == *frame_cursor)
2021 output->current_cursor = *display_cursor;
2022
2023 be_delete_cursor (*frame_cursor);
2024 }
2025
2026 *frame_cursor = *display_cursor;
2027 }
2028}
2029
2030static void
2031haiku_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
2032{
2033 struct haiku_output *output;
2034 Emacs_Cursor *frame_cursor, old, *recolored;
2035 int i, n, rc;
2036 bool color_specified_p;
2037 Emacs_Color color;
2038
2039 CHECK_STRING (arg);
2040 color_specified_p = true;
2041
2042 if (!strcmp (SSDATA (arg), "font-color"))
2043 color_specified_p = false;
2044 else
2045 rc = haiku_get_color (SSDATA (arg), &color);
2046
2047 if (color_specified_p && rc)
2048 signal_error ("Undefined color", arg);
2049
2050 output = FRAME_OUTPUT_DATA (f);
2051
2052 /* This will also reset all the cursors back to their default
2053 values. */
2054 haiku_free_custom_cursors (f);
2055
2056 for (i = 0; i < ARRAYELTS (custom_cursors); ++i)
2057 {
2058 frame_cursor = (Emacs_Cursor *) ((char *) output
2059 + custom_cursors[i].output_offset);
2060 old = *frame_cursor;
2061
2062 if (custom_cursors[i].lisp_cursor
2063 && FIXNUMP (*custom_cursors[i].lisp_cursor))
2064 {
2065 if (!RANGED_FIXNUMP (0, *custom_cursors[i].lisp_cursor,
2066 28)) /* 28 is the largest Haiku cursor ID. */
2067 signal_error ("Invalid cursor",
2068 *custom_cursors[i].lisp_cursor);
2069
2070 n = XFIXNUM (*custom_cursors[i].lisp_cursor);
2071
2072 if (color_specified_p && cursor_bitmaps_for_id[n].bits)
2073 {
2074 recolored
2075 = haiku_create_colored_cursor (&cursor_bitmaps_for_id[n],
2076 color.pixel,
2077 FRAME_BACKGROUND_PIXEL (f));
2078
2079 if (recolored)
2080 {
2081 *frame_cursor = recolored;
2082 continue;
2083 }
2084 }
2085
2086 /* Create and set the custom cursor. */
2087 *frame_cursor = be_create_cursor_from_id (n);
2088 }
2089 else if (color_specified_p && cursor_bitmaps[i].bits)
2090 {
2091 recolored
2092 = haiku_create_colored_cursor (&cursor_bitmaps[i], color.pixel,
2093 FRAME_BACKGROUND_PIXEL (f));
2094
2095 if (recolored)
2096 *frame_cursor = recolored;
2097 }
2098 }
2099
2100 /* This function can be called before the frame's window is
2101 created. */
2102 if (FRAME_HAIKU_WINDOW (f))
2103 {
2104 if (output->current_cursor == old
2105 && old != *frame_cursor)
2106 {
2107 output->current_cursor = *frame_cursor;
2108
2109 BView_set_view_cursor (FRAME_HAIKU_VIEW (f),
2110 *frame_cursor);
2111 }
2112 }
2113
2114 update_face_from_frame_parameter (f, Qmouse_color, arg);
2115}
2116
1795 2117
1796 2118
1797DEFUN ("haiku-set-mouse-absolute-pixel-position", 2119DEFUN ("haiku-set-mouse-absolute-pixel-position",
@@ -1890,34 +2212,28 @@ DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
1890} 2212}
1891 2213
1892DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection, 2214DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
1893 1, 3, 0, 2215 1, 3, 0, doc: /* SKIP: real doc in xfns.c. */)
1894 doc: /* SKIP: real doc in xfns.c. */)
1895 (Lisp_Object display, Lisp_Object resource_string, Lisp_Object must_succeed) 2216 (Lisp_Object display, Lisp_Object resource_string, Lisp_Object must_succeed)
1896{ 2217{
1897 struct haiku_display_info *dpyinfo;
1898 CHECK_STRING (display); 2218 CHECK_STRING (display);
1899 2219
1900 if (NILP (Fstring_equal (display, build_string ("be")))) 2220 if (NILP (Fstring_equal (display, build_string ("be"))))
1901 { 2221 {
1902 if (!NILP (must_succeed)) 2222 if (!NILP (must_succeed))
1903 fatal ("Bad display"); 2223 fatal ("Invalid display %s", SDATA (display));
1904 else 2224 else
1905 error ("Bad display"); 2225 signal_error ("Invalid display", display);
1906 } 2226 }
1907 2227
1908 if (x_display_list) 2228 if (x_display_list)
1909 return Qnil;
1910
1911 dpyinfo = haiku_term_init ();
1912
1913 if (!dpyinfo)
1914 { 2229 {
1915 if (!NILP (must_succeed)) 2230 if (!NILP (must_succeed))
1916 fatal ("Display not responding"); 2231 fatal ("A display is already open");
1917 else 2232 else
1918 error ("Display not responding"); 2233 error ("A display is already open");
1919 } 2234 }
1920 2235
2236 haiku_term_init ();
1921 return Qnil; 2237 return Qnil;
1922} 2238}
1923 2239
@@ -1944,7 +2260,7 @@ DEFUN ("x-display-pixel-height", Fx_display_pixel_height, Sx_display_pixel_heigh
1944 check_haiku_display_info (terminal); 2260 check_haiku_display_info (terminal);
1945 2261
1946 be_get_screen_dimensions (&width, &height); 2262 be_get_screen_dimensions (&width, &height);
1947 return make_fixnum (width); 2263 return make_fixnum (height);
1948} 2264}
1949 2265
1950DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0, 2266DEFUN ("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,
2039 else 2355 else
2040 CHECK_FIXNUM (dy); 2356 CHECK_FIXNUM (dy);
2041 2357
2358 tip_dx = dx;
2359 tip_dy = dy;
2360
2042 if (use_system_tooltips) 2361 if (use_system_tooltips)
2043 { 2362 {
2044 int root_x, root_y; 2363 int root_x, root_y;
@@ -2579,6 +2898,7 @@ Frames are listed from topmost (first) to bottommost (last). */)
2579 2898
2580 if (NILP (sel)) 2899 if (NILP (sel))
2581 return frames; 2900 return frames;
2901
2582 return Fcons (sel, frames); 2902 return Fcons (sel, frames);
2583} 2903}
2584 2904
@@ -2683,6 +3003,57 @@ call this function yourself. */)
2683 return Qnil; 3003 return Qnil;
2684} 3004}
2685 3005
3006DEFUN ("haiku-display-monitor-attributes-list",
3007 Fhaiku_display_monitor_attributes_list,
3008 Shaiku_display_monitor_attributes_list,
3009 0, 1, 0,
3010 doc: /* Return a list of physical monitor attributes on the display TERMINAL.
3011
3012The optional argument TERMINAL specifies which display to ask about.
3013TERMINAL should be a terminal object, a frame or a display name (a string).
3014If omitted or nil, that stands for the selected frame's display.
3015
3016Internal use only, use `display-monitor-attributes-list' instead. */)
3017 (Lisp_Object terminal)
3018{
3019 struct MonitorInfo monitor;
3020 struct haiku_display_info *dpyinfo;
3021 Lisp_Object frames, tail, tem;
3022
3023 dpyinfo = check_haiku_display_info (terminal);
3024 frames = Qnil;
3025
3026 FOR_EACH_FRAME (tail, tem)
3027 {
3028 maybe_quit ();
3029
3030 if (FRAME_HAIKU_P (XFRAME (tem))
3031 && !FRAME_TOOLTIP_P (XFRAME (tem)))
3032 frames = Fcons (tem, frames);
3033 }
3034
3035 monitor.geom.x = 0;
3036 monitor.geom.y = 0;
3037 be_get_screen_dimensions ((int *) &monitor.geom.width,
3038 (int *) &monitor.geom.height);
3039
3040 monitor.mm_width = (monitor.geom.width
3041 / (dpyinfo->resx / 25.4));
3042 monitor.mm_height = (monitor.geom.height
3043 / (dpyinfo->resy / 25.4));
3044 monitor.name = (char *) "BeOS monitor";
3045
3046 if (!be_get_explicit_workarea ((int *) &monitor.work.x,
3047 (int *) &monitor.work.y,
3048 (int *) &monitor.work.width,
3049 (int *) &monitor.work.height))
3050 monitor.work = monitor.geom;
3051
3052 return make_monitor_attribute_list (&monitor, 1, 0,
3053 make_vector (1, frames),
3054 "fallback");
3055}
3056
2686frame_parm_handler haiku_frame_parm_handlers[] = 3057frame_parm_handler haiku_frame_parm_handlers[] =
2687 { 3058 {
2688 gui_set_autoraise, 3059 gui_set_autoraise,
@@ -2701,7 +3072,7 @@ frame_parm_handler haiku_frame_parm_handlers[] =
2701 gui_set_right_divider_width, 3072 gui_set_right_divider_width,
2702 gui_set_bottom_divider_width, 3073 gui_set_bottom_divider_width,
2703 haiku_set_menu_bar_lines, 3074 haiku_set_menu_bar_lines,
2704 NULL, /* set mouse color */ 3075 haiku_set_mouse_color,
2705 haiku_explicitly_set_name, 3076 haiku_explicitly_set_name,
2706 gui_set_scroll_bar_width, 3077 gui_set_scroll_bar_width,
2707 gui_set_scroll_bar_height, 3078 gui_set_scroll_bar_height,
@@ -2751,6 +3122,9 @@ syms_of_haikufns (void)
2751 DEFSYM (Qstatic_color, "static-color"); 3122 DEFSYM (Qstatic_color, "static-color");
2752 DEFSYM (Qstatic_gray, "static-gray"); 3123 DEFSYM (Qstatic_gray, "static-gray");
2753 DEFSYM (Qtrue_color, "true-color"); 3124 DEFSYM (Qtrue_color, "true-color");
3125 DEFSYM (Qmono, "mono");
3126 DEFSYM (Qgrayscale, "grayscale");
3127 DEFSYM (Qcolor, "color");
2754 3128
2755 defsubr (&Sx_hide_tip); 3129 defsubr (&Sx_hide_tip);
2756 defsubr (&Sxw_display_color_p); 3130 defsubr (&Sxw_display_color_p);
@@ -2785,6 +3159,7 @@ syms_of_haikufns (void)
2785 defsubr (&Sx_display_save_under); 3159 defsubr (&Sx_display_save_under);
2786 defsubr (&Shaiku_frame_restack); 3160 defsubr (&Shaiku_frame_restack);
2787 defsubr (&Shaiku_save_session_reply); 3161 defsubr (&Shaiku_save_session_reply);
3162 defsubr (&Shaiku_display_monitor_attributes_list);
2788 3163
2789 tip_timer = Qnil; 3164 tip_timer = Qnil;
2790 staticpro (&tip_timer); 3165 staticpro (&tip_timer);
@@ -2796,6 +3171,10 @@ syms_of_haikufns (void)
2796 staticpro (&tip_last_string); 3171 staticpro (&tip_last_string);
2797 tip_last_parms = Qnil; 3172 tip_last_parms = Qnil;
2798 staticpro (&tip_last_parms); 3173 staticpro (&tip_last_parms);
3174 tip_dx = Qnil;
3175 staticpro (&tip_dx);
3176 tip_dy = Qnil;
3177 staticpro (&tip_dy);
2799 3178
2800 DEFVAR_LISP ("x-max-tooltip-size", Vx_max_tooltip_size, 3179 DEFVAR_LISP ("x-max-tooltip-size", Vx_max_tooltip_size,
2801 doc: /* SKIP: real doc in xfns.c. */); 3180 doc: /* SKIP: real doc in xfns.c. */);
@@ -2805,6 +3184,19 @@ syms_of_haikufns (void)
2805 doc: /* SKIP: real doc in xfns.c. */); 3184 doc: /* SKIP: real doc in xfns.c. */);
2806 Vx_cursor_fore_pixel = Qnil; 3185 Vx_cursor_fore_pixel = Qnil;
2807 3186
3187 DEFVAR_LISP ("x-pointer-shape", Vx_pointer_shape,
3188 doc: /* SKIP: real doc in xfns.c. */);
3189 Vx_pointer_shape = Qnil;
3190
3191 DEFVAR_LISP ("x-hourglass-pointer-shape", Vx_hourglass_pointer_shape,
3192 doc: /* SKIP: real doc in xfns.c. */);
3193 Vx_hourglass_pointer_shape = Qnil;
3194
3195 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
3196 Vx_sensitive_text_pointer_shape,
3197 doc: /* SKIP: real doc in xfns.c. */);
3198 Vx_sensitive_text_pointer_shape = Qnil;
3199
2808 DEFVAR_LISP ("haiku-allowed-ui-colors", Vhaiku_allowed_ui_colors, 3200 DEFVAR_LISP ("haiku-allowed-ui-colors", Vhaiku_allowed_ui_colors,
2809 doc: /* Vector of UI colors that Emacs can look up from the system. 3201 doc: /* Vector of UI colors that Emacs can look up from the system.
2810If this is set up incorrectly, Emacs can crash when encoutering an 3202If 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,
1084 s->first_glyph->slice.glyphless.lower_yoff 1084 s->first_glyph->slice.glyphless.lower_yoff
1085 - s->first_glyph->slice.glyphless.upper_yoff; 1085 - s->first_glyph->slice.glyphless.upper_yoff;
1086 1086
1087 BView_SetHighColor (view, background); 1087 haiku_draw_background_rect (s, s->face, x, y - ascent,
1088 BView_FillRectangle (view, x, y - ascent, s->width, height); 1088 s->width, height);
1089 s->background_filled_p = 1; 1089 s->background_filled_p = 1;
1090 } 1090 }
1091 1091
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;
95typedef haiku Window; 95typedef haiku Window;
96typedef int Display; 96typedef int Display;
97 97
98/* Cursor bitmaps. These are only used to create colored cursors when
99 the user specifies a mouse color. */
100
101MAYBE_UNUSED static unsigned char cross_ptr_bits[] =
102 {
103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
104 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
105 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
106 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
108 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0xf0, 0x1f, 0x00, 0x00,
109 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
110 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
111 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
112 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
113 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
115 };
116
117MAYBE_UNUSED static unsigned char cross_ptrmask_bits[] =
118 {
119 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01,
120 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0,
121 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
122 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
123 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124 0x00, 0xfc, 0x07, 0xf0, 0x1f, 0xfe, 0x0f, 0xf8, 0x3f, 0xfc, 0x07,
125 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
127 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01,
128 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0,
129 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
130 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
131 };
132
133MAYBE_UNUSED static unsigned char ibeam_ptr_bits[] =
134 {
135 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0xc0, 0x01, 0xc0, 0x01, 0xc0,
136 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01,
137 0xc0, 0x01, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00
138 };
139
140MAYBE_UNUSED static unsigned char ibeam_ptrmask_bits[] =
141 {
142 0x00, 0x00, 0xfc, 0x1f, 0xfe, 0x3f, 0xfc, 0x1f, 0xe0, 0x03, 0xe0,
143 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03,
144 0xfc, 0x1f, 0xfe, 0x3f, 0xfc, 0x1f, 0x00, 0x00
145 };
146
147MAYBE_UNUSED static unsigned char hand_ptr_bits[] =
148 {
149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0xa0, 0x02, 0xa0,
150 0x02, 0xf0, 0x07, 0xf0, 0x07, 0xf0, 0x07, 0xf0, 0x07, 0xf0, 0x07,
151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
152 };
153
154MAYBE_UNUSED static unsigned char hand_ptrmask_bits[] =
155 {
156 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0xf0, 0x07, 0xf0, 0x07, 0xf8,
157 0x0f, 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f,
158 0xf0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
159 };
160
161MAYBE_UNUSED static unsigned char horizd_ptr_bits[] =
162 {
163 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x04, 0x28,
164 0x0a, 0xf4, 0x17, 0x02, 0x20, 0xf4, 0x17, 0x28, 0x0a, 0x10, 0x04,
165 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
166 };
167
168MAYBE_UNUSED static unsigned char horizd_ptrmask_bits[] =
169 {
170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x04, 0x38,
171 0x0e, 0xfc, 0x1f, 0xfe, 0x3f, 0xfc, 0x1f, 0x38, 0x0e, 0x10, 0x04,
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
173 };
174
175MAYBE_UNUSED static unsigned char vertd_ptr_bits[] =
176 {
177 0x00, 0x00, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, 0x50, 0x05, 0x60,
178 0x03, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x60, 0x03, 0x50, 0x05,
179 0x20, 0x02, 0x40, 0x01, 0x80, 0x00, 0x00, 0x00
180 };
181
182MAYBE_UNUSED static unsigned char vertd_ptrmask_bits[] =
183 {
184 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xe0,
185 0x03, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07,
186 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00
187 };
188
189MAYBE_UNUSED static unsigned char hourglass_bits[] =
190 {
191 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x10, 0x04, 0x08, 0x08, 0x24,
192 0x10, 0x44, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x88, 0x08,
193 0x10, 0x04, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00
194 };
195
196MAYBE_UNUSED static unsigned char hourglass_mask_bits[] =
197 {
198 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc,
199 0x1f, 0xfc, 0x1f, 0xfc, 0x1f, 0xfc, 0x1f, 0xfc, 0x1f, 0xf8, 0x0f,
200 0xf0, 0x07, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00
201 };
202
98#endif /* _HAIKU_GUI_H_ */ 203#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;
35 35
36static void 36static void
37digest_menu_items (void *first_menu, int start, int menu_items_used, 37digest_menu_items (void *first_menu, int start, int menu_items_used,
38 int mbar_p) 38 bool is_menu_bar)
39{ 39{
40 void **menus, **panes; 40 void **menus, **panes;
41 ssize_t menu_len = (menu_items_used + 1 - start) * sizeof *menus; 41 ssize_t menu_len;
42 ssize_t pane_len = (menu_items_used + 1 - start) * sizeof *panes; 42 ssize_t pane_len;
43 int i, menu_depth;
44 void *menu, *window, *view;
45 Lisp_Object pane_name, prefix;
46 const char *pane_string;
47 Lisp_Object item_name, enable, descrip, def, selected, help;
43 48
44 menus = alloca (menu_len); 49 USE_SAFE_ALLOCA;
45 panes = alloca (pane_len);
46 50
47 int i = start, menu_depth = 0; 51 menu_len = (menu_items_used + 1 - start) * sizeof *menus;
52 pane_len = (menu_items_used + 1 - start) * sizeof *panes;
53 menu = first_menu;
48 54
55 i = start;
56 menu_depth = 0;
57
58 menus = SAFE_ALLOCA (menu_len);
59 panes = SAFE_ALLOCA (pane_len);
49 memset (menus, 0, menu_len); 60 memset (menus, 0, menu_len);
50 memset (panes, 0, pane_len); 61 memset (panes, 0, pane_len);
51
52 void *menu = first_menu;
53
54 menus[0] = first_menu; 62 menus[0] = first_menu;
55 63
56 void *window = NULL; 64 window = NULL;
57 void *view = NULL; 65 view = NULL;
66
58 if (FRAMEP (Vmenu_updating_frame) && 67 if (FRAMEP (Vmenu_updating_frame) &&
59 FRAME_LIVE_P (XFRAME (Vmenu_updating_frame)) && 68 FRAME_LIVE_P (XFRAME (Vmenu_updating_frame)) &&
60 FRAME_HAIKU_P (XFRAME (Vmenu_updating_frame))) 69 FRAME_HAIKU_P (XFRAME (Vmenu_updating_frame)))
@@ -83,9 +92,6 @@ digest_menu_items (void *first_menu, int start, int menu_items_used,
83 i += 1; 92 i += 1;
84 else if (EQ (AREF (menu_items, i), Qt)) 93 else if (EQ (AREF (menu_items, i), Qt))
85 { 94 {
86 Lisp_Object pane_name, prefix;
87 const char *pane_string;
88
89 if (menu_items_n_panes == 1) 95 if (menu_items_n_panes == 1)
90 { 96 {
91 i += MENU_ITEMS_PANE_LENGTH; 97 i += MENU_ITEMS_PANE_LENGTH;
@@ -116,7 +122,6 @@ digest_menu_items (void *first_menu, int start, int menu_items_used,
116 } 122 }
117 else 123 else
118 { 124 {
119 Lisp_Object item_name, enable, descrip, def, selected, help;
120 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME); 125 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
121 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE); 126 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
122 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY); 127 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,
144 menu = BMenu_new_submenu (menu, SSDATA (item_name), !NILP (enable)); 149 menu = BMenu_new_submenu (menu, SSDATA (item_name), !NILP (enable));
145 else if (NILP (def) && menu_separator_name_p (SSDATA (item_name))) 150 else if (NILP (def) && menu_separator_name_p (SSDATA (item_name)))
146 BMenu_add_separator (menu); 151 BMenu_add_separator (menu);
147 else if (!mbar_p) 152 else if (!is_menu_bar)
148 { 153 {
149 if (!use_system_tooltips || NILP (Fsymbol_value (Qtooltip_mode))) 154 if (!use_system_tooltips || NILP (Fsymbol_value (Qtooltip_mode)))
150 BMenu_add_item (menu, SSDATA (item_name), 155 BMenu_add_item (menu, SSDATA (item_name),
@@ -178,6 +183,8 @@ digest_menu_items (void *first_menu, int start, int menu_items_used,
178 183
179 if (view) 184 if (view)
180 BView_draw_unlock (view); 185 BView_draw_unlock (view);
186
187 SAFE_FREE ();
181} 188}
182 189
183static Lisp_Object 190static Lisp_Object
@@ -376,12 +383,18 @@ Lisp_Object
376haiku_menu_show (struct frame *f, int x, int y, int menuflags, 383haiku_menu_show (struct frame *f, int x, int y, int menuflags,
377 Lisp_Object title, const char **error_name) 384 Lisp_Object title, const char **error_name)
378{ 385{
379 int i = 0, submenu_depth = 0; 386 int i, submenu_depth, j;
380 void *view = FRAME_HAIKU_VIEW (f); 387 void *view, *menu;
381 void *menu; 388 Lisp_Object *subprefix_stack;
389 Lisp_Object prefix, entry;
382 390
383 Lisp_Object *subprefix_stack = 391 USE_SAFE_ALLOCA;
384 alloca (menu_items_used * sizeof (Lisp_Object)); 392
393 view = FRAME_HAIKU_VIEW (f);
394 i = 0;
395 submenu_depth = 0;
396 subprefix_stack
397 = SAFE_ALLOCA (menu_items_used * sizeof (Lisp_Object));
385 398
386 eassert (FRAME_HAIKU_P (f)); 399 eassert (FRAME_HAIKU_P (f));
387 400
@@ -390,6 +403,8 @@ haiku_menu_show (struct frame *f, int x, int y, int menuflags,
390 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH) 403 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
391 { 404 {
392 *error_name = "Empty menu"; 405 *error_name = "Empty menu";
406
407 SAFE_FREE ();
393 return Qnil; 408 return Qnil;
394 } 409 }
395 410
@@ -417,8 +432,6 @@ haiku_menu_show (struct frame *f, int x, int y, int menuflags,
417 432
418 if (menu_item_selection) 433 if (menu_item_selection)
419 { 434 {
420 Lisp_Object prefix, entry;
421
422 prefix = entry = Qnil; 435 prefix = entry = Qnil;
423 i = 0; 436 i = 0;
424 while (i < menu_items_used) 437 while (i < menu_items_used)
@@ -452,8 +465,6 @@ haiku_menu_show (struct frame *f, int x, int y, int menuflags,
452 { 465 {
453 if (menuflags & MENU_KEYMAPS) 466 if (menuflags & MENU_KEYMAPS)
454 { 467 {
455 int j;
456
457 entry = list1 (entry); 468 entry = list1 (entry);
458 if (!NILP (prefix)) 469 if (!NILP (prefix))
459 entry = Fcons (prefix, entry); 470 entry = Fcons (prefix, entry);
@@ -464,6 +475,8 @@ haiku_menu_show (struct frame *f, int x, int y, int menuflags,
464 block_input (); 475 block_input ();
465 BPopUpMenu_delete (menu); 476 BPopUpMenu_delete (menu);
466 unblock_input (); 477 unblock_input ();
478
479 SAFE_FREE ();
467 return entry; 480 return entry;
468 } 481 }
469 i += MENU_ITEMS_ITEM_LENGTH; 482 i += MENU_ITEMS_ITEM_LENGTH;
@@ -480,6 +493,8 @@ haiku_menu_show (struct frame *f, int x, int y, int menuflags,
480 block_input (); 493 block_input ();
481 BPopUpMenu_delete (menu); 494 BPopUpMenu_delete (menu);
482 unblock_input (); 495 unblock_input ();
496
497 SAFE_FREE ();
483 return Qnil; 498 return Qnil;
484} 499}
485 500
@@ -728,7 +743,7 @@ run_menu_bar_help_event (struct frame *f, int mb_idx)
728 743
729 vec = f->menu_bar_vector; 744 vec = f->menu_bar_vector;
730 if ((mb_idx + MENU_ITEMS_ITEM_HELP) >= ASIZE (vec)) 745 if ((mb_idx + MENU_ITEMS_ITEM_HELP) >= ASIZE (vec))
731 emacs_abort (); 746 return;
732 747
733 help = AREF (vec, mb_idx + MENU_ITEMS_ITEM_HELP); 748 help = AREF (vec, mb_idx + MENU_ITEMS_ITEM_HELP);
734 if (STRINGP (help) || NILP (help)) 749 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/>. */
33 the nested event loop inside be_drag_message. */ 33 the nested event loop inside be_drag_message. */
34struct frame *haiku_dnd_frame; 34struct frame *haiku_dnd_frame;
35 35
36/* Whether or not to move the tip frame during drag-and-drop. */
37bool haiku_dnd_follow_tooltip;
38
36static void haiku_lisp_to_message (Lisp_Object, void *); 39static void haiku_lisp_to_message (Lisp_Object, void *);
37 40
41static enum haiku_clipboard
42haiku_get_clipboard_name (Lisp_Object clipboard)
43{
44 if (EQ (clipboard, QPRIMARY))
45 return CLIPBOARD_PRIMARY;
46
47 if (EQ (clipboard, QSECONDARY))
48 return CLIPBOARD_SECONDARY;
49
50 if (EQ (clipboard, QCLIPBOARD))
51 return CLIPBOARD_CLIPBOARD;
52
53 signal_error ("Invalid clipboard", clipboard);
54}
55
38DEFUN ("haiku-selection-data", Fhaiku_selection_data, Shaiku_selection_data, 56DEFUN ("haiku-selection-data", Fhaiku_selection_data, Shaiku_selection_data,
39 2, 2, 0, 57 2, 2, 0,
40 doc: /* Retrieve content typed as NAME from the clipboard 58 doc: /* Retrieve content typed as NAME from the clipboard
@@ -53,22 +71,15 @@ message in the format accepted by `haiku-drag-message', which see. */)
53 int rc; 71 int rc;
54 72
55 CHECK_SYMBOL (clipboard); 73 CHECK_SYMBOL (clipboard);
56 74 clipboard_name = haiku_get_clipboard_name (clipboard);
57 if (!EQ (clipboard, QPRIMARY) && !EQ (clipboard, QSECONDARY)
58 && !EQ (clipboard, QCLIPBOARD))
59 signal_error ("Invalid clipboard", clipboard);
60 75
61 if (!NILP (name)) 76 if (!NILP (name))
62 { 77 {
63 CHECK_STRING (name); 78 CHECK_STRING (name);
64 79
65 block_input (); 80 block_input ();
66 if (EQ (clipboard, QPRIMARY)) 81 dat = be_find_clipboard_data (clipboard_name,
67 dat = BClipboard_find_primary_selection_data (SSDATA (name), &len); 82 SSDATA (name), &len);
68 else if (EQ (clipboard, QSECONDARY))
69 dat = BClipboard_find_secondary_selection_data (SSDATA (name), &len);
70 else
71 dat = BClipboard_find_system_data (SSDATA (name), &len);
72 unblock_input (); 83 unblock_input ();
73 84
74 if (!dat) 85 if (!dat)
@@ -83,18 +94,11 @@ message in the format accepted by `haiku-drag-message', which see. */)
83 Qforeign_selection, Qt, str); 94 Qforeign_selection, Qt, str);
84 95
85 block_input (); 96 block_input ();
86 BClipboard_free_data (dat); 97 free (dat);
87 unblock_input (); 98 unblock_input ();
88 } 99 }
89 else 100 else
90 { 101 {
91 if (EQ (clipboard, QPRIMARY))
92 clipboard_name = CLIPBOARD_PRIMARY;
93 else if (EQ (clipboard, QSECONDARY))
94 clipboard_name = CLIPBOARD_SECONDARY;
95 else
96 clipboard_name = CLIPBOARD_CLIPBOARD;
97
98 block_input (); 102 block_input ();
99 rc = be_lock_clipboard_message (clipboard_name, &message, false); 103 rc = be_lock_clipboard_message (clipboard_name, &message, false);
100 unblock_input (); 104 unblock_input ();
@@ -139,16 +143,12 @@ In that case, the arguments after NAME are ignored. */)
139 int rc; 143 int rc;
140 void *message; 144 void *message;
141 145
146 CHECK_SYMBOL (clipboard);
147 clipboard_name = haiku_get_clipboard_name (clipboard);
148
142 if (CONSP (name) || NILP (name)) 149 if (CONSP (name) || NILP (name))
143 { 150 {
144 if (EQ (clipboard, QPRIMARY)) 151 be_update_clipboard_count (clipboard_name);
145 clipboard_name = CLIPBOARD_PRIMARY;
146 else if (EQ (clipboard, QSECONDARY))
147 clipboard_name = CLIPBOARD_SECONDARY;
148 else if (EQ (clipboard, QCLIPBOARD))
149 clipboard_name = CLIPBOARD_CLIPBOARD;
150 else
151 signal_error ("Invalid clipboard", clipboard);
152 152
153 rc = be_lock_clipboard_message (clipboard_name, 153 rc = be_lock_clipboard_message (clipboard_name,
154 &message, true); 154 &message, true);
@@ -164,7 +164,6 @@ In that case, the arguments after NAME are ignored. */)
164 return unbind_to (ref, Qnil); 164 return unbind_to (ref, Qnil);
165 } 165 }
166 166
167 CHECK_SYMBOL (clipboard);
168 CHECK_STRING (name); 167 CHECK_STRING (name);
169 if (!NILP (data)) 168 if (!NILP (data))
170 CHECK_STRING (data); 169 CHECK_STRING (data);
@@ -172,20 +171,8 @@ In that case, the arguments after NAME are ignored. */)
172 dat = !NILP (data) ? SSDATA (data) : NULL; 171 dat = !NILP (data) ? SSDATA (data) : NULL;
173 len = !NILP (data) ? SBYTES (data) : 0; 172 len = !NILP (data) ? SBYTES (data) : 0;
174 173
175 if (EQ (clipboard, QPRIMARY)) 174 be_set_clipboard_data (clipboard_name, SSDATA (name), dat, len,
176 BClipboard_set_primary_selection_data (SSDATA (name), dat, len, 175 !NILP (clear));
177 !NILP (clear));
178 else if (EQ (clipboard, QSECONDARY))
179 BClipboard_set_secondary_selection_data (SSDATA (name), dat, len,
180 !NILP (clear));
181 else if (EQ (clipboard, QCLIPBOARD))
182 BClipboard_set_system_data (SSDATA (name), dat, len, !NILP (clear));
183 else
184 {
185 unblock_input ();
186 signal_error ("Bad clipboard", clipboard);
187 }
188
189 return Qnil; 176 return Qnil;
190} 177}
191 178
@@ -193,27 +180,15 @@ DEFUN ("haiku-selection-owner-p", Fhaiku_selection_owner_p, Shaiku_selection_own
193 0, 1, 0, 180 0, 1, 0,
194 doc: /* Whether the current Emacs process owns the given SELECTION. 181 doc: /* Whether the current Emacs process owns the given SELECTION.
195The arg should be the name of the selection in question, typically one 182The arg should be the name of the selection in question, typically one
196of the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'. For 183of the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'. */)
197convenience, the symbol nil is the same as `PRIMARY', and t is the
198same as `SECONDARY'. */)
199 (Lisp_Object selection) 184 (Lisp_Object selection)
200{ 185{
201 bool value; 186 bool value;
202 187 enum haiku_clipboard name;
203 if (NILP (selection))
204 selection = QPRIMARY;
205 else if (EQ (selection, Qt))
206 selection = QSECONDARY;
207 188
208 block_input (); 189 block_input ();
209 if (EQ (selection, QPRIMARY)) 190 name = haiku_get_clipboard_name (selection);
210 value = BClipboard_owns_primary (); 191 value = be_clipboard_owner_p (name);
211 else if (EQ (selection, QSECONDARY))
212 value = BClipboard_owns_secondary ();
213 else if (EQ (selection, QCLIPBOARD))
214 value = BClipboard_owns_clipboard ();
215 else
216 value = false;
217 unblock_input (); 192 unblock_input ();
218 193
219 return value ? Qt : Qnil; 194 return value ? Qt : Qnil;
@@ -275,7 +250,7 @@ haiku_message_to_lisp (void *message)
275 if (!pbuf) 250 if (!pbuf)
276 memory_full (SIZE_MAX); 251 memory_full (SIZE_MAX);
277 252
278 t1 = build_string (pbuf); 253 t1 = DECODE_FILE (build_string (pbuf));
279 254
280 free (pbuf); 255 free (pbuf);
281 break; 256 break;
@@ -320,6 +295,14 @@ haiku_message_to_lisp (void *message)
320 t1 = make_int ((intmax_t) *(ssize_t *) buf); 295 t1 = make_int ((intmax_t) *(ssize_t *) buf);
321 break; 296 break;
322 297
298 case 'DBLE':
299 t1 = make_float (*(double *) buf);
300 break;
301
302 case 'FLOT':
303 t1 = make_float (*(float *) buf);
304 break;
305
323 default: 306 default:
324 t1 = make_uninit_string (buf_size); 307 t1 = make_uninit_string (buf_size);
325 memcpy (SDATA (t1), buf, buf_size); 308 memcpy (SDATA (t1), buf, buf_size);
@@ -378,6 +361,14 @@ haiku_message_to_lisp (void *message)
378 t2 = Qpoint; 361 t2 = Qpoint;
379 break; 362 break;
380 363
364 case 'DBLE':
365 t2 = Qdouble;
366 break;
367
368 case 'FLOT':
369 t2 = Qfloat;
370 break;
371
381 default: 372 default:
382 t2 = make_int (type_code); 373 t2 = make_int (type_code);
383 } 374 }
@@ -423,6 +414,10 @@ lisp_to_type_code (Lisp_Object obj)
423 return 'SSZT'; 414 return 'SSZT';
424 else if (EQ (obj, Qpoint)) 415 else if (EQ (obj, Qpoint))
425 return 'BPNT'; 416 return 'BPNT';
417 else if (EQ (obj, Qfloat))
418 return 'FLOT';
419 else if (EQ (obj, Qdouble))
420 return 'DBLE';
426 else 421 else
427 return -1; 422 return -1;
428} 423}
@@ -441,7 +436,8 @@ haiku_lisp_to_message (Lisp_Object obj, void *message)
441 ssize_t ssizet_data; 436 ssize_t ssizet_data;
442 intmax_t t4; 437 intmax_t t4;
443 uintmax_t t5; 438 uintmax_t t5;
444 float t6, t7; 439 float t6, t7, float_data;
440 double double_data;
445 int rc; 441 int rc;
446 specpdl_ref ref; 442 specpdl_ref ref;
447 443
@@ -526,7 +522,8 @@ haiku_lisp_to_message (Lisp_Object obj, void *message)
526 case 'RREF': 522 case 'RREF':
527 CHECK_STRING (data); 523 CHECK_STRING (data);
528 524
529 if (be_add_refs_data (message, SSDATA (name), SSDATA (data)) 525 if (be_add_refs_data (message, SSDATA (name),
526 SSDATA (ENCODE_FILE (data)))
530 && haiku_signal_invalid_refs) 527 && haiku_signal_invalid_refs)
531 signal_error ("Invalid file name", data); 528 signal_error ("Invalid file name", data);
532 break; 529 break;
@@ -544,6 +541,30 @@ haiku_lisp_to_message (Lisp_Object obj, void *message)
544 signal_error ("Invalid point", data); 541 signal_error ("Invalid point", data);
545 break; 542 break;
546 543
544 case 'FLOT':
545 CHECK_NUMBER (data);
546 float_data = XFLOATINT (data);
547
548 rc = be_add_message_data (message, SSDATA (name),
549 type_code, &float_data,
550 sizeof float_data);
551
552 if (rc)
553 signal_error ("Failed to add float", data);
554 break;
555
556 case 'DBLE':
557 CHECK_NUMBER (data);
558 double_data = XFLOATINT (data);
559
560 rc = be_add_message_data (message, SSDATA (name),
561 type_code, &double_data,
562 sizeof double_data);
563
564 if (rc)
565 signal_error ("Failed to add double", data);
566 break;
567
547 case 'SHRT': 568 case 'SHRT':
548 if (!TYPE_RANGED_FIXNUMP (int16, data)) 569 if (!TYPE_RANGED_FIXNUMP (int16, data))
549 signal_error ("Invalid value", data); 570 signal_error ("Invalid value", data);
@@ -737,7 +758,7 @@ haiku_unwind_drag_message (void *message)
737} 758}
738 759
739DEFUN ("haiku-drag-message", Fhaiku_drag_message, Shaiku_drag_message, 760DEFUN ("haiku-drag-message", Fhaiku_drag_message, Shaiku_drag_message,
740 2, 3, 0, 761 2, 4, 0,
741 doc: /* Begin dragging MESSAGE from FRAME. 762 doc: /* Begin dragging MESSAGE from FRAME.
742 763
743MESSAGE an alist of strings, denoting message field names, to a list 764MESSAGE 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
758values from -1 to the maximum value of the C data type `ssize_t' on 779values from -1 to the maximum value of the C data type `ssize_t' on
759the current system. If TYPE is `point', then DATA is a cons of float 780the current system. If TYPE is `point', then DATA is a cons of float
760values describing the X and Y coordinates of an on-screen location. 781values describing the X and Y coordinates of an on-screen location.
782If TYPE is `float', then DATA is a low-precision floating point
783number, whose exact precision is not guaranteed. If TYPE is `double',
784then DATA is a floating point number that can represent any value a
785Lisp float can represent.
761 786
762If the field name is not a string but the symbol `type', then it 787If the field name is not a string but the symbol `type', then it
763associates to a 32-bit unsigned integer describing the type of the 788associates 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
767drag will originate. 792drag will originate.
768 793
769ALLOW-SAME-FRAME, if nil or not specified, means that MESSAGE will be 794ALLOW-SAME-FRAME, if nil or not specified, means that MESSAGE will be
770ignored if it is dropped on top of FRAME. */) 795ignored if it is dropped on top of FRAME.
771 (Lisp_Object frame, Lisp_Object message, Lisp_Object allow_same_frame) 796
797FOLLOW-TOOLTIP, if non-nil, will cause any non-system tooltip
798currently being displayed to move along with the mouse pointer. */)
799 (Lisp_Object frame, Lisp_Object message, Lisp_Object allow_same_frame,
800 Lisp_Object follow_tooltip)
772{ 801{
773 specpdl_ref idx; 802 specpdl_ref idx;
774 void *be_message; 803 void *be_message;
@@ -782,23 +811,167 @@ ignored if it is dropped on top of FRAME. */)
782 error ("Frame is invisible"); 811 error ("Frame is invisible");
783 812
784 haiku_dnd_frame = f; 813 haiku_dnd_frame = f;
814 haiku_dnd_follow_tooltip = !NILP (follow_tooltip);
785 be_message = be_create_simple_message (); 815 be_message = be_create_simple_message ();
786 816
787 record_unwind_protect_ptr (haiku_unwind_drag_message, be_message); 817 record_unwind_protect_ptr (haiku_unwind_drag_message, be_message);
788 haiku_lisp_to_message (message, be_message); 818 haiku_lisp_to_message (message, be_message);
819
789 rc = be_drag_message (FRAME_HAIKU_VIEW (f), be_message, 820 rc = be_drag_message (FRAME_HAIKU_VIEW (f), be_message,
790 !NILP (allow_same_frame), 821 !NILP (allow_same_frame),
791 block_input, unblock_input, 822 block_input, unblock_input,
792 process_pending_signals, 823 process_pending_signals,
793 haiku_should_quit_drag); 824 haiku_should_quit_drag);
794 FRAME_DISPLAY_INFO (f)->grabbed = 0;
795 825
826 /* Don't clear the mouse grab if the user decided to quit instead
827 of the drop finishing. */
796 if (rc) 828 if (rc)
797 quit (); 829 quit ();
798 830
831 /* Now dismiss the tooltip, since the drop presumably succeeded. */
832 if (!NILP (follow_tooltip))
833 Fx_hide_tip ();
834
835 FRAME_DISPLAY_INFO (f)->grabbed = 0;
836
799 return unbind_to (idx, Qnil); 837 return unbind_to (idx, Qnil);
800} 838}
801 839
840DEFUN ("haiku-roster-launch", Fhaiku_roster_launch, Shaiku_roster_launch,
841 2, 2, 0,
842 doc: /* Launch an application associated with FILE-OR-TYPE.
843Return the process ID of any process created, the symbol
844`already-running' if ARGS was sent to a program that's already
845running, or nil if launching the application failed because no
846application was found for FILE-OR-TYPE.
847
848Signal an error if FILE-OR-TYPE is invalid, or if ARGS is a message
849but the application doesn't accept messages.
850
851FILE-OR-TYPE can either be a string denoting a MIME type, or a list
852with one argument FILE, denoting a file whose associated application
853will be launched.
854
855ARGS can either be a vector of strings containing the arguments that
856will be passed to the application, or a system message in the form
857accepted by `haiku-drag-message' that will be sent to the application
858after it starts. */)
859 (Lisp_Object file_or_type, Lisp_Object args)
860{
861 char **cargs;
862 char *type, *file;
863 team_id team_id;
864 status_t rc;
865 ptrdiff_t i, nargs;
866 Lisp_Object tem, canonical;
867 void *message;
868 specpdl_ref depth;
869
870 type = NULL;
871 file = NULL;
872 cargs = NULL;
873 message = NULL;
874 nargs = 0;
875 depth = SPECPDL_INDEX ();
876
877 USE_SAFE_ALLOCA;
878
879 if (STRINGP (file_or_type))
880 SAFE_ALLOCA_STRING (type, file_or_type);
881 else
882 {
883 CHECK_LIST (file_or_type);
884 tem = XCAR (file_or_type);
885 canonical = Fexpand_file_name (tem, Qnil);
886
887 CHECK_STRING (tem);
888 SAFE_ALLOCA_STRING (file, ENCODE_FILE (canonical));
889 CHECK_LIST_END (XCDR (file_or_type), file_or_type);
890 }
891
892 if (VECTORP (args))
893 {
894 nargs = ASIZE (args);
895 cargs = SAFE_ALLOCA (nargs * sizeof *cargs);
896
897 for (i = 0; i < nargs; ++i)
898 {
899 tem = AREF (args, i);
900 CHECK_STRING (tem);
901 maybe_quit ();
902
903 cargs[i] = SAFE_ALLOCA (SBYTES (tem) + 1);
904 memcpy (cargs[i], SDATA (tem), SBYTES (tem) + 1);
905 }
906 }
907 else
908 {
909 message = be_create_simple_message ();
910
911 record_unwind_protect_ptr (BMessage_delete, message);
912 haiku_lisp_to_message (args, message);
913 }
914
915 block_input ();
916 rc = be_roster_launch (type, file, cargs, nargs, message,
917 &team_id);
918 unblock_input ();
919
920 /* `be_roster_launch' can potentially take a while in IO, but
921 signals from async input will interrupt that operation. If the
922 user wanted to quit, act like it. */
923 maybe_quit ();
924
925 if (rc == B_OK)
926 return SAFE_FREE_UNBIND_TO (depth,
927 make_uint (team_id));
928 else if (rc == B_ALREADY_RUNNING)
929 return Qalready_running;
930 else if (rc == B_BAD_VALUE)
931 signal_error ("Invalid type or bad arguments",
932 list2 (file_or_type, args));
933
934 return SAFE_FREE_UNBIND_TO (depth, Qnil);
935}
936
937static void
938haiku_dnd_compute_tip_xy (int *root_x, int *root_y)
939{
940 int min_x, min_y, max_x, max_y;
941 int width, height;
942
943 width = FRAME_PIXEL_WIDTH (XFRAME (tip_frame));
944 height = FRAME_PIXEL_HEIGHT (XFRAME (tip_frame));
945
946 min_x = 0;
947 min_y = 0;
948 be_get_screen_dimensions (&max_x, &max_y);
949
950 if (*root_y + XFIXNUM (tip_dy) <= min_y)
951 *root_y = min_y; /* Can happen for negative dy */
952 else if (*root_y + XFIXNUM (tip_dy) + height <= max_y)
953 /* It fits below the pointer */
954 *root_y += XFIXNUM (tip_dy);
955 else if (height + XFIXNUM (tip_dy) + min_y <= *root_y)
956 /* It fits above the pointer. */
957 *root_y -= height + XFIXNUM (tip_dy);
958 else
959 /* Put it on the top. */
960 *root_y = min_y;
961
962 if (*root_x + XFIXNUM (tip_dx) <= min_x)
963 *root_x = 0; /* Can happen for negative dx */
964 else if (*root_x + XFIXNUM (tip_dx) + width <= max_x)
965 /* It fits to the right of the pointer. */
966 *root_x += XFIXNUM (tip_dx);
967 else if (width + XFIXNUM (tip_dx) + min_x <= *root_x)
968 /* It fits to the left of the pointer. */
969 *root_x -= width + XFIXNUM (tip_dx);
970 else
971 /* Put it left justified on the screen -- it ought to fit that way. */
972 *root_x = min_x;
973}
974
802static Lisp_Object 975static Lisp_Object
803haiku_note_drag_motion_1 (void *data) 976haiku_note_drag_motion_1 (void *data)
804{ 977{
@@ -817,6 +990,26 @@ haiku_note_drag_motion_2 (enum nonlocal_exit exit, Lisp_Object error)
817void 990void
818haiku_note_drag_motion (void) 991haiku_note_drag_motion (void)
819{ 992{
993 struct frame *tip_f;
994 int x, y;
995
996 if (FRAMEP (tip_frame) && haiku_dnd_follow_tooltip
997 && FIXNUMP (tip_dx) && FIXNUMP (tip_dy))
998 {
999 tip_f = XFRAME (tip_frame);
1000
1001 if (FRAME_LIVE_P (tip_f) && FRAME_VISIBLE_P (tip_f))
1002 {
1003 BView_get_mouse (FRAME_HAIKU_VIEW (haiku_dnd_frame),
1004 &x, &y);
1005 BView_convert_to_screen (FRAME_HAIKU_VIEW (haiku_dnd_frame),
1006 &x, &y);
1007
1008 haiku_dnd_compute_tip_xy (&x, &y);
1009 BWindow_set_offset (FRAME_HAIKU_WINDOW (tip_f), x, y);
1010 }
1011 }
1012
820 internal_catch_all (haiku_note_drag_motion_1, NULL, 1013 internal_catch_all (haiku_note_drag_motion_1, NULL,
821 haiku_note_drag_motion_2); 1014 haiku_note_drag_motion_2);
822} 1015}
@@ -855,11 +1048,15 @@ used to retrieve the current position of the mouse. */);
855 DEFSYM (Qsize_t, "size_t"); 1048 DEFSYM (Qsize_t, "size_t");
856 DEFSYM (Qssize_t, "ssize_t"); 1049 DEFSYM (Qssize_t, "ssize_t");
857 DEFSYM (Qpoint, "point"); 1050 DEFSYM (Qpoint, "point");
1051 DEFSYM (Qfloat, "float");
1052 DEFSYM (Qdouble, "double");
1053 DEFSYM (Qalready_running, "already-running");
858 1054
859 defsubr (&Shaiku_selection_data); 1055 defsubr (&Shaiku_selection_data);
860 defsubr (&Shaiku_selection_put); 1056 defsubr (&Shaiku_selection_put);
861 defsubr (&Shaiku_selection_owner_p); 1057 defsubr (&Shaiku_selection_owner_p);
862 defsubr (&Shaiku_drag_message); 1058 defsubr (&Shaiku_drag_message);
1059 defsubr (&Shaiku_roster_launch);
863 1060
864 haiku_dnd_frame = NULL; 1061 haiku_dnd_frame = NULL;
865} 1062}
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
37#ifdef __cplusplus 37#ifdef __cplusplus
38extern "C" 38extern "C"
39{ 39{
40/* Also declared in haikuterm.h for use in emacs.c. */
40extern void init_haiku_select (void); 41extern void init_haiku_select (void);
41#endif 42#endif
42/* Whether or not the selection was recently changed. */ 43/* Whether or not the selection was recently changed. */
43 44
44/* Find a string with the MIME type TYPE in the system clipboard. */ 45extern char *be_find_clipboard_data (enum haiku_clipboard, const char *, ssize_t *);
45extern char *BClipboard_find_system_data (const char *, ssize_t *); 46extern void be_set_clipboard_data (enum haiku_clipboard, const char *, const char *,
46extern char *BClipboard_find_primary_selection_data (const char *, ssize_t *); 47 ssize_t, bool);
47extern char *BClipboard_find_secondary_selection_data (const char *, ssize_t *); 48extern void be_get_clipboard_targets (enum haiku_clipboard, char **, int);
48 49extern bool be_clipboard_owner_p (enum haiku_clipboard);
49extern void BClipboard_set_system_data (const char *, const char *, ssize_t, bool); 50extern void be_update_clipboard_count (enum haiku_clipboard);
50extern void BClipboard_set_primary_selection_data (const char *, const char *,
51 ssize_t, bool);
52extern void BClipboard_set_secondary_selection_data (const char *, const char *,
53 ssize_t, bool);
54
55extern void BClipboard_system_targets (char **, int);
56extern void BClipboard_primary_targets (char **, int);
57extern void BClipboard_secondary_targets (char **, int);
58
59extern bool BClipboard_owns_clipboard (void);
60extern bool BClipboard_owns_primary (void);
61extern bool BClipboard_owns_secondary (void);
62
63/* Free the returned data. */
64extern void BClipboard_free_data (void *);
65 51
66extern int be_enum_message (void *, int32 *, int32, int32 *, const char **); 52extern int be_enum_message (void *, int32 *, int32, int32 *, const char **);
67extern int be_get_message_data (void *, const char *, int32, int32, 53extern 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/>. */
43/* Minimum and maximum values used for Haiku scroll bars. */ 43/* Minimum and maximum values used for Haiku scroll bars. */
44#define BE_SB_MAX 12000000 44#define BE_SB_MAX 12000000
45 45
46struct haiku_display_info *x_display_list = NULL; 46/* The single Haiku display (if any). */
47extern frame_parm_handler haiku_frame_parm_handlers[]; 47struct haiku_display_info *x_display_list;
48 48
49/* This is used to determine when to evict the font lookup cache, 49/* This is used to determine when to evict the font lookup cache,
50 which we do every 50 updates. */ 50 which we do every 50 updates. */
51static int up_to_date_count; 51static int up_to_date_count;
52 52
53/* List of defined fringe bitmaps. */
53static void **fringe_bmps; 54static void **fringe_bmps;
54static int max_fringe_bmp = 0;
55 55
56/* The amount of fringe bitmaps in that list. */
57static int max_fringe_bmp;
58
59/* Alist of resources to their values. */
56static Lisp_Object rdb; 60static Lisp_Object rdb;
61
62/* Non-zero means that a HELP_EVENT has been generated since Emacs
63 start. */
57static bool any_help_event_p; 64static bool any_help_event_p;
58 65
59char * 66char *
@@ -89,14 +96,9 @@ static void
89haiku_coords_from_parent (struct frame *f, int *x, int *y) 96haiku_coords_from_parent (struct frame *f, int *x, int *y)
90{ 97{
91 struct frame *p = FRAME_PARENT_FRAME (f); 98 struct frame *p = FRAME_PARENT_FRAME (f);
92 eassert (p);
93 99
94 for (struct frame *parent = p; parent; 100 *x -= FRAME_OUTPUT_DATA (p)->frame_x;
95 parent = FRAME_PARENT_FRAME (parent)) 101 *y -= FRAME_OUTPUT_DATA (p)->frame_y;
96 {
97 *x -= parent->left_pos;
98 *y -= parent->top_pos;
99 }
100} 102}
101 103
102static void 104static void
@@ -115,7 +117,8 @@ haiku_delete_terminal (struct terminal *terminal)
115} 117}
116 118
117static const char * 119static const char *
118get_string_resource (void *ignored, const char *name, const char *class) 120haiku_get_string_resource (void *ignored, const char *name,
121 const char *class)
119{ 122{
120 const char *native; 123 const char *native;
121 124
@@ -196,6 +199,8 @@ haiku_clip_to_string_exactly (struct glyph_string *s, struct glyph_string *dst)
196{ 199{
197 BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), s->x, s->y, 200 BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), s->x, s->y,
198 s->width, s->height); 201 s->width, s->height);
202 BView_invalidate_region (FRAME_HAIKU_VIEW (s->f), s->x,
203 s->y, s->width, s->height);
199} 204}
200 205
201static void 206static void
@@ -511,6 +516,9 @@ haiku_scroll_bar_from_widget (void *scroll_bar, void *window)
511 if (!frame) 516 if (!frame)
512 return NULL; 517 return NULL;
513 518
519 if (!scroll_bar)
520 return NULL;
521
514 if (!NILP (FRAME_SCROLL_BARS (frame))) 522 if (!NILP (FRAME_SCROLL_BARS (frame)))
515 { 523 {
516 for (tem = FRAME_SCROLL_BARS (frame); !NILP (tem); 524 for (tem = FRAME_SCROLL_BARS (frame); !NILP (tem);
@@ -567,20 +575,24 @@ haiku_query_frame_background_color (struct frame *f, Emacs_Color *bgcolor)
567} 575}
568 576
569static bool 577static bool
570haiku_defined_color (struct frame *f, 578haiku_defined_color (struct frame *f, const char *name,
571 const char *name, 579 Emacs_Color *color, bool alloc, bool make_index)
572 Emacs_Color *color,
573 bool alloc,
574 bool make_index)
575{ 580{
576 return !haiku_get_color (name, color); 581 int rc;
582
583 rc = !haiku_get_color (name, color);
584
585 if (rc && f->gamma && alloc)
586 gamma_correct (f, color);
587
588 return rc;
577} 589}
578 590
579/* Adapted from xterm `x_draw_box_rect'. */ 591/* Adapted from xterm `x_draw_box_rect'. */
580static void 592static void
581haiku_draw_box_rect (struct glyph_string *s, 593haiku_draw_box_rect (struct glyph_string *s, int left_x, int top_y,
582 int left_x, int top_y, int right_x, int bottom_y, int hwidth, 594 int right_x, int bottom_y, int hwidth, int vwidth,
583 int vwidth, bool left_p, bool right_p, struct haiku_rect *clip_rect) 595 bool left_p, bool right_p, struct haiku_rect *clip_rect)
584{ 596{
585 void *view = FRAME_HAIKU_VIEW (s->f); 597 void *view = FRAME_HAIKU_VIEW (s->f);
586 struct face *face = s->face; 598 struct face *face = s->face;
@@ -604,13 +616,19 @@ static void
604haiku_calculate_relief_colors (struct glyph_string *s, uint32_t *rgbout_w, 616haiku_calculate_relief_colors (struct glyph_string *s, uint32_t *rgbout_w,
605 uint32_t *rgbout_b) 617 uint32_t *rgbout_b)
606{ 618{
607 struct face *face = s->face;
608 double h, cs, l; 619 double h, cs, l;
609 uint32_t rgbin; 620 uint32_t rgbin;
610 struct haiku_output *di; 621 struct haiku_output *di;
611 622
612 rgbin = (face->use_box_color_for_shadows_p 623 if (s->face->use_box_color_for_shadows_p)
613 ? face->box_color : face->background); 624 rgbin = s->face->box_color;
625 else if (s->first_glyph->type == IMAGE_GLYPH
626 && s->img->pixmap
627 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
628 rgbin = IMAGE_BACKGROUND (s->img, s->f, 0);
629 else
630 rgbin = s->face->background;
631
614 di = FRAME_OUTPUT_DATA (s->f); 632 di = FRAME_OUTPUT_DATA (s->f);
615 633
616 if (s->hl == DRAW_CURSOR) 634 if (s->hl == DRAW_CURSOR)
@@ -632,30 +650,35 @@ haiku_calculate_relief_colors (struct glyph_string *s, uint32_t *rgbout_w,
632} 650}
633 651
634static void 652static void
635haiku_draw_relief_rect (struct glyph_string *s, 653haiku_draw_relief_rect (struct glyph_string *s, int left_x, int top_y,
636 int left_x, int top_y, int right_x, int bottom_y, 654 int right_x, int bottom_y, int hwidth, int vwidth,
637 int hwidth, int vwidth, bool raised_p, bool top_p, 655 bool raised_p, bool top_p, bool bot_p, bool left_p,
638 bool bot_p, bool left_p, bool right_p, 656 bool right_p, struct haiku_rect *clip_rect)
639 struct haiku_rect *clip_rect, bool fancy_p)
640{ 657{
641 uint32_t color_white, color_black; 658 uint32_t color_white, color_black;
642 void *view; 659 void *view;
643 660
661 view = FRAME_HAIKU_VIEW (s->f);
644 haiku_calculate_relief_colors (s, &color_white, &color_black); 662 haiku_calculate_relief_colors (s, &color_white, &color_black);
645 663
646 view = FRAME_HAIKU_VIEW (s->f);
647 BView_SetHighColor (view, raised_p ? color_white : color_black); 664 BView_SetHighColor (view, raised_p ? color_white : color_black);
665
648 if (clip_rect) 666 if (clip_rect)
649 { 667 {
650 BView_StartClip (view); 668 BView_StartClip (view);
651 haiku_clip_to_string (s); 669 haiku_clip_to_string (s);
652 BView_ClipToRect (view, clip_rect->x, clip_rect->y, clip_rect->width, 670 BView_ClipToRect (view, clip_rect->x, clip_rect->y,
653 clip_rect->height); 671 clip_rect->width, clip_rect->height);
654 } 672 }
673
655 if (top_p) 674 if (top_p)
656 BView_FillRectangle (view, left_x, top_y, right_x - left_x + 1, hwidth); 675 BView_FillRectangle (view, left_x, top_y,
676 right_x - left_x + 1, hwidth);
677
657 if (left_p) 678 if (left_p)
658 BView_FillRectangle (view, left_x, top_y, vwidth, bottom_y - top_y + 1); 679 BView_FillRectangle (view, left_x, top_y,
680 vwidth, bottom_y - top_y + 1);
681
659 BView_SetHighColor (view, !raised_p ? color_white : color_black); 682 BView_SetHighColor (view, !raised_p ? color_white : color_black);
660 683
661 if (bot_p) 684 if (bot_p)
@@ -696,10 +719,10 @@ haiku_draw_relief_rect (struct glyph_string *s,
696 if (vwidth > 1 && right_p) 719 if (vwidth > 1 && right_p)
697 BView_StrokeLine (view, right_x, top_y, right_x, bottom_y); 720 BView_StrokeLine (view, right_x, top_y, right_x, bottom_y);
698 721
699 BView_SetHighColor (view, s->face->background); 722 BView_SetHighColor (view, FRAME_BACKGROUND_PIXEL (s->f));
700 723
701 /* Omit corner pixels. */ 724 /* Omit corner pixels. */
702 if (hwidth > 1 || vwidth > 1) 725 if (hwidth > 1 && vwidth > 1)
703 { 726 {
704 if (left_p && top_p) 727 if (left_p && top_p)
705 BView_FillRectangle (view, left_x, top_y, 1, 1); 728 BView_FillRectangle (view, left_x, top_y, 1, 1);
@@ -716,21 +739,40 @@ haiku_draw_relief_rect (struct glyph_string *s,
716} 739}
717 740
718static void 741static void
742haiku_get_scale_factor (int *scale_x, int *scale_y)
743{
744 struct haiku_display_info *dpyinfo = x_display_list;
745
746 if (dpyinfo->resx > 96)
747 *scale_x = floor (dpyinfo->resx / 96);
748 if (dpyinfo->resy > 96)
749 *scale_y = floor (dpyinfo->resy / 96);
750}
751
752static void
719haiku_draw_underwave (struct glyph_string *s, int width, int x) 753haiku_draw_underwave (struct glyph_string *s, int width, int x)
720{ 754{
721 int wave_height = 3, wave_length = 2; 755 int wave_height, wave_length;
722 int y, dx, dy, odd, xmax; 756 int y, dx, dy, odd, xmax, scale_x, scale_y;
723 float ax, ay, bx, by; 757 float ax, ay, bx, by;
724 void *view = FRAME_HAIKU_VIEW (s->f); 758 void *view;
759
760 scale_x = 1;
761 scale_y = 1;
762 haiku_get_scale_factor (&scale_x, &scale_y);
763 wave_height = 3 * scale_y;
764 wave_length = 2 * scale_x;
725 765
726 dx = wave_length; 766 dx = wave_length;
727 dy = wave_height - 1; 767 dy = wave_height - 1;
728 y = s->ybase - wave_height + 3; 768 y = s->ybase - wave_height + 3;
729 xmax = x + width; 769 xmax = x + width;
770 view = FRAME_HAIKU_VIEW (s->f);
730 771
731 BView_StartClip (view); 772 BView_StartClip (view);
732 haiku_clip_to_string (s); 773 haiku_clip_to_string (s);
733 BView_ClipToRect (view, x, y, width, wave_height); 774 BView_ClipToRect (view, x, y, width, wave_height);
775
734 ax = x - ((int) (x) % dx) + (float) 0.5; 776 ax = x - ((int) (x) % dx) + (float) 0.5;
735 bx = ax + dx; 777 bx = ax + dx;
736 odd = (int) (ax / dx) % 2; 778 odd = (int) (ax / dx) % 2;
@@ -741,6 +783,8 @@ haiku_draw_underwave (struct glyph_string *s, int width, int x)
741 else 783 else
742 by += dy; 784 by += dy;
743 785
786 BView_SetPenSize (view, scale_y);
787
744 while (ax <= xmax) 788 while (ax <= xmax)
745 { 789 {
746 BView_StrokeLine (view, ax, ay, bx, by); 790 BView_StrokeLine (view, ax, ay, bx, by);
@@ -748,6 +792,8 @@ haiku_draw_underwave (struct glyph_string *s, int width, int x)
748 bx += dx, by = y + 0.5 + odd * dy; 792 bx += dx, by = y + 0.5 + odd * dy;
749 odd = !odd; 793 odd = !odd;
750 } 794 }
795
796 BView_SetPenSize (view, 1);
751 BView_EndClip (view); 797 BView_EndClip (view);
752} 798}
753 799
@@ -809,13 +855,13 @@ haiku_draw_text_decoration (struct glyph_string *s, struct face *face,
809 val = (WINDOW_BUFFER_LOCAL_VALUE 855 val = (WINDOW_BUFFER_LOCAL_VALUE
810 (Qx_underline_at_descent_line, s->w)); 856 (Qx_underline_at_descent_line, s->w));
811 underline_at_descent_line 857 underline_at_descent_line
812 = (!(NILP (val) || EQ (val, Qunbound)) 858 = (!(NILP (val) || BASE_EQ (val, Qunbound))
813 || s->face->underline_at_descent_line_p); 859 || s->face->underline_at_descent_line_p);
814 860
815 val = (WINDOW_BUFFER_LOCAL_VALUE 861 val = (WINDOW_BUFFER_LOCAL_VALUE
816 (Qx_use_underline_position_properties, s->w)); 862 (Qx_use_underline_position_properties, s->w));
817 use_underline_position_properties 863 use_underline_position_properties
818 = !(NILP (val) || EQ (val, Qunbound)); 864 = !(NILP (val) || BASE_EQ (val, Qunbound));
819 865
820 /* Get the underline thickness. Default is 1 pixel. */ 866 /* Get the underline thickness. Default is 1 pixel. */
821 if (font && font->underline_thickness > 0) 867 if (font && font->underline_thickness > 0)
@@ -958,15 +1004,16 @@ haiku_draw_string_box (struct glyph_string *s)
958 else 1004 else
959 haiku_draw_relief_rect (s, left_x, top_y, right_x, bottom_y, hwidth, 1005 haiku_draw_relief_rect (s, left_x, top_y, right_x, bottom_y, hwidth,
960 vwidth, raised_p, true, true, left_p, right_p, 1006 vwidth, raised_p, true, true, left_p, right_p,
961 NULL, 1); 1007 NULL);
962} 1008}
963 1009
964static void 1010static void
965haiku_draw_plain_background (struct glyph_string *s, struct face *face, 1011haiku_draw_plain_background (struct glyph_string *s, struct face *face,
966 int box_line_hwidth, int box_line_vwidth) 1012 int x, int y, int width, int height)
967{ 1013{
968 void *view = FRAME_HAIKU_VIEW (s->f); 1014 void *view = FRAME_HAIKU_VIEW (s->f);
969 unsigned long cursor_color; 1015 unsigned long cursor_color;
1016
970 if (s->hl == DRAW_CURSOR) 1017 if (s->hl == DRAW_CURSOR)
971 { 1018 {
972 haiku_merge_cursor_foreground (s, NULL, &cursor_color); 1019 haiku_merge_cursor_foreground (s, NULL, &cursor_color);
@@ -975,18 +1022,92 @@ haiku_draw_plain_background (struct glyph_string *s, struct face *face,
975 else 1022 else
976 BView_SetHighColor (view, face->background_defaulted_p ? 1023 BView_SetHighColor (view, face->background_defaulted_p ?
977 FRAME_BACKGROUND_PIXEL (s->f) : 1024 FRAME_BACKGROUND_PIXEL (s->f) :
978 face->background); 1025 face->background);
1026
1027 BView_FillRectangle (view, x, y, width, height);
1028}
1029
1030static struct haiku_bitmap_record *
1031haiku_get_bitmap_rec (struct frame *f, ptrdiff_t id)
1032{
1033 return &FRAME_DISPLAY_INFO (f)->bitmaps[id - 1];
1034}
1035
1036static void
1037haiku_update_bitmap_rec (struct haiku_bitmap_record *rec,
1038 uint32_t new_foreground,
1039 uint32_t new_background)
1040{
1041 char *bits;
1042 int x, y, bytes_per_line;
1043
1044 if (new_foreground == rec->stipple_foreground
1045 && new_background == rec->stipple_background)
1046 return;
1047
1048 bits = rec->stipple_bits;
1049 bytes_per_line = (rec->width + 7) / 8;
1050
1051 for (y = 0; y < rec->height; y++)
1052 {
1053 for (x = 0; x < rec->width; x++)
1054 haiku_put_pixel (rec->img, x, y,
1055 ((bits[x / 8] >> (x % 8)) & 1
1056 ? new_foreground : new_background));
1057
1058 bits += bytes_per_line;
1059 }
979 1060
980 BView_FillRectangle (view, s->x, 1061 rec->stipple_foreground = new_foreground;
981 s->y + box_line_hwidth, 1062 rec->stipple_background = new_background;
982 s->background_width,
983 s->height - 2 * box_line_hwidth);
984} 1063}
985 1064
986static void 1065static void
987haiku_draw_stipple_background (struct glyph_string *s, struct face *face, 1066haiku_draw_stipple_background (struct glyph_string *s, struct face *face,
988 int box_line_hwidth, int box_line_vwidth) 1067 int x, int y, int width, int height,
1068 bool explicit_colors_p,
1069 uint32 explicit_background,
1070 uint32 explicit_foreground)
989{ 1071{
1072 struct haiku_bitmap_record *rec;
1073 unsigned long foreground, background;
1074 void *view;
1075
1076 view = FRAME_HAIKU_VIEW (s->f);
1077 rec = haiku_get_bitmap_rec (s->f, s->face->stipple);
1078
1079 if (explicit_colors_p)
1080 {
1081 background = explicit_background;
1082 foreground = explicit_foreground;
1083 }
1084 else if (s->hl == DRAW_CURSOR)
1085 haiku_merge_cursor_foreground (s, &foreground, &background);
1086 else
1087 {
1088 foreground = s->face->foreground;
1089 background = s->face->background;
1090 }
1091
1092 haiku_update_bitmap_rec (rec, foreground, background);
1093
1094 BView_StartClip (view);
1095 haiku_clip_to_string (s);
1096 BView_ClipToRect (view, x, y, width, height);
1097 BView_DrawBitmapTiled (view, rec->img, 0, 0, -1, -1,
1098 0, 0, x + width, y + height);
1099 BView_EndClip (view);
1100}
1101
1102void
1103haiku_draw_background_rect (struct glyph_string *s, struct face *face,
1104 int x, int y, int width, int height)
1105{
1106 if (!s->stippled_p)
1107 haiku_draw_plain_background (s, face, x, y, width, height);
1108 else
1109 haiku_draw_stipple_background (s, face, x, y, width, height,
1110 false, 0, 0);
990} 1111}
991 1112
992static void 1113static void
@@ -1002,12 +1123,10 @@ haiku_maybe_draw_background (struct glyph_string *s, int force_p)
1002 || FONT_TOO_HIGH (s->font) 1123 || FONT_TOO_HIGH (s->font)
1003 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p) 1124 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
1004 { 1125 {
1005 if (!face->stipple) 1126 haiku_draw_background_rect (s, s->face, s->x, s->y + box_line_width,
1006 haiku_draw_plain_background (s, face, box_line_width, 1127 s->background_width,
1007 box_vline_width); 1128 s->height - 2 * box_line_width);
1008 else 1129
1009 haiku_draw_stipple_background (s, face, box_line_width,
1010 box_vline_width);
1011 s->background_filled_p = 1; 1130 s->background_filled_p = 1;
1012 } 1131 }
1013 } 1132 }
@@ -1182,9 +1301,8 @@ haiku_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
1182static void 1301static void
1183haiku_draw_stretch_glyph_string (struct glyph_string *s) 1302haiku_draw_stretch_glyph_string (struct glyph_string *s)
1184{ 1303{
1185 eassert (s->first_glyph->type == STRETCH_GLYPH);
1186
1187 struct face *face = s->face; 1304 struct face *face = s->face;
1305 uint32_t bkg;
1188 1306
1189 if (s->hl == DRAW_CURSOR && !x_stretch_cursor_p) 1307 if (s->hl == DRAW_CURSOR && !x_stretch_cursor_p)
1190 { 1308 {
@@ -1232,9 +1350,11 @@ haiku_draw_stretch_glyph_string (struct glyph_string *s)
1232 int y = s->y; 1350 int y = s->y;
1233 int w = background_width - width, h = s->height; 1351 int w = background_width - width, h = s->height;
1234 1352
1353 /* Draw stipples manually because we want the background
1354 part of a stretch glyph to have a stipple even if the
1355 cursor is visible on top. */
1235 if (!face->stipple) 1356 if (!face->stipple)
1236 { 1357 {
1237 uint32_t bkg;
1238 if (s->row->mouse_face_p && cursor_in_mouse_face_p (s->w)) 1358 if (s->row->mouse_face_p && cursor_in_mouse_face_p (s->w))
1239 haiku_mouse_face_colors (s, NULL, &bkg); 1359 haiku_mouse_face_colors (s, NULL, &bkg);
1240 else 1360 else
@@ -1243,6 +1363,16 @@ haiku_draw_stretch_glyph_string (struct glyph_string *s)
1243 BView_SetHighColor (view, bkg); 1363 BView_SetHighColor (view, bkg);
1244 BView_FillRectangle (view, x, y, w, h); 1364 BView_FillRectangle (view, x, y, w, h);
1245 } 1365 }
1366 else
1367 {
1368 if (s->row->mouse_face_p && cursor_in_mouse_face_p (s->w))
1369 haiku_mouse_face_colors (s, NULL, &bkg);
1370 else
1371 bkg = face->background;
1372
1373 haiku_draw_stipple_background (s, s->face, x, y, w, h,
1374 true, bkg, face->foreground);
1375 }
1246 } 1376 }
1247 } 1377 }
1248 else if (!s->background_filled_p) 1378 else if (!s->background_filled_p)
@@ -1260,17 +1390,8 @@ haiku_draw_stretch_glyph_string (struct glyph_string *s)
1260 } 1390 }
1261 1391
1262 if (background_width > 0) 1392 if (background_width > 0)
1263 { 1393 haiku_draw_background_rect (s, s->face, s->x, s->y,
1264 void *view = FRAME_HAIKU_VIEW (s->f); 1394 background_width, s->height);
1265 unsigned long bkg;
1266 if (s->hl == DRAW_CURSOR)
1267 haiku_merge_cursor_foreground (s, NULL, &bkg);
1268 else
1269 bkg = s->face->background;
1270
1271 BView_SetHighColor (view, bkg);
1272 BView_FillRectangle (view, x, s->y, background_width, s->height);
1273 }
1274 } 1395 }
1275 s->background_filled_p = 1; 1396 s->background_filled_p = 1;
1276} 1397}
@@ -1504,19 +1625,20 @@ haiku_draw_image_relief (struct glyph_string *s)
1504 1625
1505 get_glyph_string_clip_rect (s, &r); 1626 get_glyph_string_clip_rect (s, &r);
1506 haiku_draw_relief_rect (s, x, y, x1, y1, thick, thick, raised_p, 1627 haiku_draw_relief_rect (s, x, y, x1, y1, thick, thick, raised_p,
1507 top_p, bot_p, left_p, right_p, &r, 0); 1628 top_p, bot_p, left_p, right_p, &r);
1508} 1629}
1509 1630
1510static void 1631static void
1511haiku_draw_image_glyph_string (struct glyph_string *s) 1632haiku_draw_image_glyph_string (struct glyph_string *s)
1512{ 1633{
1513 struct face *face = s->face; 1634 struct face *face = s->face;
1514 1635 void *view, *bitmap, *mask;
1515 int box_line_hwidth = max (face->box_vertical_line_width, 0); 1636 int box_line_hwidth = max (face->box_vertical_line_width, 0);
1516 int box_line_vwidth = max (face->box_horizontal_line_width, 0); 1637 int box_line_vwidth = max (face->box_horizontal_line_width, 0);
1517 1638 int x, y, height, width, relief;
1518 int x, y; 1639 struct haiku_rect nr;
1519 int height, width; 1640 Emacs_Rectangle cr, ir, r;
1641 unsigned long background;
1520 1642
1521 height = s->height; 1643 height = s->height;
1522 if (s->slice.y == 0) 1644 if (s->slice.y == 0)
@@ -1537,19 +1659,22 @@ haiku_draw_image_glyph_string (struct glyph_string *s)
1537 if (s->slice.y == 0) 1659 if (s->slice.y == 0)
1538 y += box_line_vwidth; 1660 y += box_line_vwidth;
1539 1661
1540 void *view = FRAME_HAIKU_VIEW (s->f); 1662 view = FRAME_HAIKU_VIEW (s->f);
1541 void *bitmap = s->img->pixmap; 1663 bitmap = s->img->pixmap;
1542 1664
1665 /* TODO: implement stipples for images with masks. */
1543 s->stippled_p = face->stipple != 0; 1666 s->stippled_p = face->stipple != 0;
1544 1667
1545 BView_SetHighColor (view, face->background); 1668 if (s->hl == DRAW_CURSOR)
1669 haiku_merge_cursor_foreground (s, NULL, &background);
1670 else
1671 background = face->background;
1672
1673 BView_SetHighColor (view, background);
1546 BView_FillRectangle (view, x, y, width, height); 1674 BView_FillRectangle (view, x, y, width, height);
1547 1675
1548 if (bitmap) 1676 if (bitmap)
1549 { 1677 {
1550 struct haiku_rect nr;
1551 Emacs_Rectangle cr, ir, r;
1552
1553 get_glyph_string_clip_rect (s, &nr); 1678 get_glyph_string_clip_rect (s, &nr);
1554 CONVERT_TO_EMACS_RECT (cr, nr); 1679 CONVERT_TO_EMACS_RECT (cr, nr);
1555 x = s->x; 1680 x = s->x;
@@ -1571,7 +1696,7 @@ haiku_draw_image_glyph_string (struct glyph_string *s)
1571 ir.height = s->slice.height; 1696 ir.height = s->slice.height;
1572 r = ir; 1697 r = ir;
1573 1698
1574 void *mask = s->img->mask; 1699 mask = s->img->mask;
1575 1700
1576 if (gui_intersect_rectangles (&cr, &ir, &r)) 1701 if (gui_intersect_rectangles (&cr, &ir, &r))
1577 { 1702 {
@@ -1605,11 +1730,25 @@ haiku_draw_image_glyph_string (struct glyph_string *s)
1605 BBitmap_free (bitmap); 1730 BBitmap_free (bitmap);
1606 } 1731 }
1607 1732
1608 if (s->hl == DRAW_CURSOR) 1733 if (!s->img->mask)
1609 { 1734 {
1610 BView_SetPenSize (view, 1); 1735 /* When the image has a mask, we can expect that at
1611 BView_SetHighColor (view, FRAME_CURSOR_COLOR (s->f).pixel); 1736 least part of a mouse highlight or a block cursor will
1612 BView_StrokeRectangle (view, r.x, r.y, r.width, r.height); 1737 be visible. If the image doesn't have a mask, make
1738 a block cursor visible by drawing a rectangle around
1739 the image. I believe it's looking better if we do
1740 nothing here for mouse-face. */
1741
1742 if (s->hl == DRAW_CURSOR)
1743 {
1744 relief = eabs (s->img->relief);
1745
1746 BView_SetPenSize (view, 1);
1747 BView_SetHighColor (view, FRAME_CURSOR_COLOR (s->f).pixel);
1748 BView_StrokeRectangle (view, x - relief, y - relief,
1749 s->slice.width + relief * 2,
1750 s->slice.height + relief * 2);
1751 }
1613 } 1752 }
1614 } 1753 }
1615 1754
@@ -1622,16 +1761,14 @@ haiku_draw_image_glyph_string (struct glyph_string *s)
1622static void 1761static void
1623haiku_draw_glyph_string (struct glyph_string *s) 1762haiku_draw_glyph_string (struct glyph_string *s)
1624{ 1763{
1625 void *view; 1764 void *view = FRAME_HAIKU_VIEW (s->f);;
1765 struct face *face = s->face;
1626 1766
1627 block_input (); 1767 block_input ();
1628 view = FRAME_HAIKU_VIEW (s->f);
1629 BView_draw_lock (view, false, 0, 0, 0, 0); 1768 BView_draw_lock (view, false, 0, 0, 0, 0);
1630 prepare_face_for_display (s->f, s->face); 1769 prepare_face_for_display (s->f, s->face);
1631 1770
1632 struct face *face = s->face; 1771 s->stippled_p = s->hl != DRAW_CURSOR && face->stipple;
1633 if (face != s->face)
1634 prepare_face_for_display (s->f, face);
1635 1772
1636 if (s->next && s->right_overhang && !s->for_overlaps) 1773 if (s->next && s->right_overhang && !s->for_overlaps)
1637 { 1774 {
@@ -1643,13 +1780,16 @@ haiku_draw_glyph_string (struct glyph_string *s)
1643 width += next->width, next = next->next) 1780 width += next->width, next = next->next)
1644 if (next->first_glyph->type != IMAGE_GLYPH) 1781 if (next->first_glyph->type != IMAGE_GLYPH)
1645 { 1782 {
1646 prepare_face_for_display (s->f, s->next->face); 1783 prepare_face_for_display (s->f, next->face);
1647 haiku_start_clip (s->next); 1784 next->stippled_p
1648 haiku_clip_to_string (s->next); 1785 = next->hl != DRAW_CURSOR && next->face->stipple;
1786
1787 haiku_start_clip (next);
1788 haiku_clip_to_string (next);
1649 if (next->first_glyph->type != STRETCH_GLYPH) 1789 if (next->first_glyph->type != STRETCH_GLYPH)
1650 haiku_maybe_draw_background (s->next, 1); 1790 haiku_maybe_draw_background (next, true);
1651 else 1791 else
1652 haiku_draw_stretch_glyph_string (s->next); 1792 haiku_draw_stretch_glyph_string (next);
1653 haiku_end_clip (s); 1793 haiku_end_clip (s);
1654 } 1794 }
1655 } 1795 }
@@ -1774,8 +1914,21 @@ haiku_draw_glyph_string (struct glyph_string *s)
1774 } 1914 }
1775 } 1915 }
1776 } 1916 }
1917
1777 haiku_end_clip (s); 1918 haiku_end_clip (s);
1778 BView_draw_unlock (view); 1919 BView_draw_unlock (view);
1920
1921 /* Set the stipple_p flag indicating whether or not a stipple was
1922 drawn in s->row. That is the case either when s is a stretch
1923 glyph string and s->face->stipple is not NULL, or when
1924 s->face->stipple exists and s->hl is not DRAW_CURSOR, and s is
1925 not an image. This is different from X. */
1926 if (s->first_glyph->type != IMAGE_GLYPH
1927 && s->face->stipple
1928 && (s->first_glyph->type == STRETCH_GLYPH
1929 || s->hl != DRAW_CURSOR))
1930 s->row->stipple_p = true;
1931
1779 unblock_input (); 1932 unblock_input ();
1780} 1933}
1781 1934
@@ -1811,8 +1964,9 @@ haiku_after_update_window_line (struct window *w,
1811 void *view = FRAME_HAIKU_VIEW (f); 1964 void *view = FRAME_HAIKU_VIEW (f);
1812 BView_draw_lock (view, false, 0, 0, 0, 0); 1965 BView_draw_lock (view, false, 0, 0, 0, 0);
1813 BView_StartClip (view); 1966 BView_StartClip (view);
1814 BView_SetHighColor (view, face->background_defaulted_p ? 1967 BView_SetHighColor (view, (face->background_defaulted_p
1815 FRAME_BACKGROUND_PIXEL (f) : face->background); 1968 ? FRAME_BACKGROUND_PIXEL (f)
1969 : face->background));
1816 BView_FillRectangle (view, 0, y, width, height); 1970 BView_FillRectangle (view, 0, y, width, height);
1817 BView_FillRectangle (view, FRAME_PIXEL_WIDTH (f) - width, 1971 BView_FillRectangle (view, FRAME_PIXEL_WIDTH (f) - width,
1818 y, width, height); 1972 y, width, height);
@@ -1847,7 +2001,7 @@ haiku_set_window_size (struct frame *f, bool change_gravity,
1847 /* Only do this if the fullscreen status has actually been 2001 /* Only do this if the fullscreen status has actually been
1848 applied. */ 2002 applied. */
1849 && f->want_fullscreen == FULLSCREEN_NONE 2003 && f->want_fullscreen == FULLSCREEN_NONE
1850 /* And if the configury during frame completion has been 2004 /* And if the configury during frame creation has been
1851 completed. Otherwise, there will be no valid "old size" to 2005 completed. Otherwise, there will be no valid "old size" to
1852 go back to. */ 2006 go back to. */
1853 && FRAME_OUTPUT_DATA (f)->configury_done) 2007 && FRAME_OUTPUT_DATA (f)->configury_done)
@@ -1858,134 +2012,215 @@ haiku_set_window_size (struct frame *f, bool change_gravity,
1858 if (FRAME_HAIKU_WINDOW (f)) 2012 if (FRAME_HAIKU_WINDOW (f))
1859 { 2013 {
1860 block_input (); 2014 block_input ();
1861 BWindow_resize (FRAME_HAIKU_WINDOW (f), width, height); 2015 BWindow_resize (FRAME_HAIKU_WINDOW (f),
2016 width, height);
2017
2018 if (FRAME_VISIBLE_P (f)
2019 && (width != FRAME_PIXEL_WIDTH (f)
2020 || height != FRAME_PIXEL_HEIGHT (f)))
2021 haiku_wait_for_event (f, FRAME_RESIZED);
1862 unblock_input (); 2022 unblock_input ();
1863 } 2023 }
2024
2025 do_pending_window_change (false);
1864} 2026}
1865 2027
1866static void 2028static void
1867haiku_draw_window_cursor (struct window *w, 2029haiku_draw_hollow_cursor (struct window *w, struct glyph_row *row)
1868 struct glyph_row *glyph_row,
1869 int x, int y,
1870 enum text_cursor_kinds cursor_type,
1871 int cursor_width, bool on_p, bool active_p)
1872{ 2030{
1873 struct frame *f = XFRAME (WINDOW_FRAME (w)); 2031 struct frame *f;
1874 struct face *face; 2032 int x, y, wd, h;
1875 struct glyph *phys_cursor_glyph;
1876 struct glyph *cursor_glyph; 2033 struct glyph *cursor_glyph;
2034 uint32_t foreground;
2035 void *view;
1877 2036
1878 void *view = FRAME_HAIKU_VIEW (f); 2037 f = XFRAME (WINDOW_FRAME (w));
1879 2038 view = FRAME_HAIKU_VIEW (f);
1880 int fx, fy, h, cursor_height;
1881 2039
1882 if (!on_p) 2040 /* Get the glyph the cursor is on. If we can't tell because
2041 the current matrix is invalid or such, give up. */
2042 cursor_glyph = get_phys_cursor_glyph (w);
2043 if (cursor_glyph == NULL)
1883 return; 2044 return;
1884 2045
1885 if (cursor_type == NO_CURSOR) 2046 /* Compute frame-relative coordinates for phys cursor. */
1886 { 2047 get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h);
1887 w->phys_cursor_width = 0; 2048 wd = w->phys_cursor_width;
1888 return;
1889 }
1890 2049
1891 w->phys_cursor_on_p = true; 2050 /* The foreground of cursor_gc is typically the same as the normal
1892 w->phys_cursor_type = cursor_type; 2051 background color, which can cause the cursor box to be invisible. */
2052 foreground = FRAME_CURSOR_COLOR (f).pixel;
1893 2053
1894 phys_cursor_glyph = get_phys_cursor_glyph (w); 2054 /* When on R2L character, show cursor at the right edge of the
2055 glyph, unless the cursor box is as wide as the glyph or wider
2056 (the latter happens when x-stretch-cursor is non-nil). */
2057 if ((cursor_glyph->resolved_level & 1) != 0
2058 && cursor_glyph->pixel_width > wd)
2059 x += cursor_glyph->pixel_width - wd;
1895 2060
1896 if (!phys_cursor_glyph) 2061 /* Set clipping, draw the rectangle, and reset clipping again.
1897 { 2062 This also marks the region as invalidated. */
1898 if (glyph_row->exact_window_width_line_p 2063
1899 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA]) 2064 BView_draw_lock (view, true, x, y, wd, h);
1900 { 2065 BView_StartClip (view);
1901 glyph_row->cursor_in_fringe_p = 1; 2066 haiku_clip_to_row (w, row, TEXT_AREA);
1902 draw_fringe_bitmap (w, glyph_row, 0);
1903 }
1904 return;
1905 }
1906 2067
1907 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h); 2068 /* Now set the foreground color and pen size. */
2069 BView_SetHighColor (view, foreground);
2070 BView_SetPenSize (view, 1);
1908 2071
1909 if (cursor_type == BAR_CURSOR) 2072 /* Actually draw the rectangle. */
2073 BView_StrokeRectangle (view, x, y, wd, h);
2074
2075 /* Reset clipping. */
2076 BView_EndClip (view);
2077 BView_draw_unlock (view);
2078}
2079
2080static void
2081haiku_draw_bar_cursor (struct window *w, struct glyph_row *row,
2082 int width, enum text_cursor_kinds kind)
2083{
2084 struct frame *f;
2085 struct glyph *cursor_glyph;
2086 struct glyph_row *r;
2087 struct face *face;
2088 uint32_t foreground;
2089 void *view;
2090 int x, y, dummy_x, dummy_y, dummy_h;
2091
2092 f = XFRAME (w->frame);
2093
2094 /* If cursor is out of bounds, don't draw garbage. This can happen
2095 in mini-buffer windows when switching between echo area glyphs
2096 and mini-buffer. */
2097 cursor_glyph = get_phys_cursor_glyph (w);
2098 if (cursor_glyph == NULL)
2099 return;
2100
2101 /* If on an image, draw like a normal cursor. That's usually better
2102 visible than drawing a bar, esp. if the image is large so that
2103 the bar might not be in the window. */
2104 if (cursor_glyph->type == IMAGE_GLYPH)
1910 { 2105 {
1911 if (cursor_width < 1) 2106 r = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
1912 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1); 2107 draw_phys_cursor_glyph (w, r, DRAW_CURSOR);
1913 if (cursor_width < w->phys_cursor_width)
1914 w->phys_cursor_width = cursor_width;
1915 } 2108 }
1916 else if (cursor_type == HBAR_CURSOR) 2109 else
1917 { 2110 {
1918 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width; 2111 view = FRAME_HAIKU_VIEW (f);
1919 if (cursor_height > glyph_row->height) 2112 face = FACE_FROM_ID (f, cursor_glyph->face_id);
1920 cursor_height = glyph_row->height;
1921 if (h > cursor_height)
1922 fy += h - cursor_height;
1923 h = cursor_height;
1924 }
1925 2113
1926 BView_draw_lock (view, false, 0, 0, 0, 0); 2114 /* If the glyph's background equals the color we normally draw
1927 BView_StartClip (view); 2115 the bars cursor in, the bar cursor in its normal color is
2116 invisible. Use the glyph's foreground color instead in this
2117 case, on the assumption that the glyph's colors are chosen so
2118 that the glyph is legible. */
2119 if (face->background == FRAME_CURSOR_COLOR (f).pixel)
2120 foreground = face->foreground;
2121 else
2122 foreground = FRAME_CURSOR_COLOR (f).pixel;
1928 2123
1929 if (cursor_type == BAR_CURSOR) 2124 BView_draw_lock (view, false, 0, 0, 0, 0);
1930 { 2125 BView_StartClip (view);
1931 cursor_glyph = get_phys_cursor_glyph (w); 2126 BView_SetHighColor (view, foreground);
1932 face = FACE_FROM_ID (f, cursor_glyph->face_id); 2127 haiku_clip_to_row (w, row, TEXT_AREA);
1933 }
1934 2128
1935 /* If the glyph's background equals the color we normally draw the 2129 if (kind == BAR_CURSOR)
1936 bar cursor in, our cursor in its normal color is invisible. Use 2130 {
1937 the glyph's foreground color instead in this case, on the 2131 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
1938 assumption that the glyph's colors are chosen so that the glyph 2132 y = WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y);
1939 is legible. */
1940 2133
1941 /* xterm.c only does this for bar cursors, and nobody has 2134 if (width < 0)
1942 complained, so it would be best to do that here as well. */ 2135 width = FRAME_CURSOR_WIDTH (f);
1943 if (cursor_type == BAR_CURSOR 2136 width = min (cursor_glyph->pixel_width, width);
1944 && face->background == FRAME_CURSOR_COLOR (f).pixel)
1945 BView_SetHighColor (view, face->foreground);
1946 else
1947 BView_SetHighColor (view, FRAME_CURSOR_COLOR (f).pixel);
1948 haiku_clip_to_row (w, glyph_row, TEXT_AREA);
1949 2137
1950 switch (cursor_type) 2138 w->phys_cursor_width = width;
1951 { 2139
1952 default: 2140 /* If the character under cursor is R2L, draw the bar cursor
1953 case DEFAULT_CURSOR: 2141 on the right of its glyph, rather than on the left. */
1954 case NO_CURSOR: 2142 if ((cursor_glyph->resolved_level & 1) != 0)
1955 break; 2143 x += cursor_glyph->pixel_width - width;
1956 case HBAR_CURSOR: 2144
1957 BView_FillRectangle (view, fx, fy, w->phys_cursor_width, h); 2145 BView_FillRectangle (view, x, y, width, row->height);
1958 BView_invalidate_region (view, fx, fy, w->phys_cursor_width, h); 2146 BView_invalidate_region (view, x, y, width, row->height);
1959 break; 2147 }
1960 case BAR_CURSOR: 2148 else /* HBAR_CURSOR */
1961 if (cursor_glyph->resolved_level & 1)
1962 { 2149 {
1963 BView_FillRectangle (view, fx + cursor_glyph->pixel_width - w->phys_cursor_width, 2150 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
1964 fy, w->phys_cursor_width, h); 2151 y = WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
1965 BView_invalidate_region (view, fx + cursor_glyph->pixel_width - w->phys_cursor_width, 2152 row->height - width);
1966 fy, w->phys_cursor_width, h); 2153
2154 if (width < 0)
2155 width = row->height;
2156
2157 width = min (row->height, width);
2158
2159 get_phys_cursor_geometry (w, row, cursor_glyph, &dummy_x,
2160 &dummy_y, &dummy_h);
2161
2162 if ((cursor_glyph->resolved_level & 1) != 0
2163 && cursor_glyph->pixel_width > w->phys_cursor_width - 1)
2164 x += cursor_glyph->pixel_width - w->phys_cursor_width + 1;
2165
2166 BView_FillRectangle (view, x, y, w->phys_cursor_width - 1,
2167 width);
2168 BView_invalidate_region (view, x, y, w->phys_cursor_width - 1,
2169 width);
1967 } 2170 }
1968 else
1969 BView_FillRectangle (view, fx, fy, w->phys_cursor_width, h);
1970 2171
1971 BView_invalidate_region (view, fx, fy, w->phys_cursor_width, h); 2172 BView_EndClip (view);
1972 break; 2173 BView_draw_unlock (view);
1973 case HOLLOW_BOX_CURSOR: 2174 }
1974 if (phys_cursor_glyph->type != IMAGE_GLYPH) 2175}
2176
2177static void
2178haiku_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2179 int x, int y, enum text_cursor_kinds cursor_type,
2180 int cursor_width, bool on_p, bool active_p)
2181{
2182 if (on_p)
2183 {
2184 w->phys_cursor_type = cursor_type;
2185 w->phys_cursor_on_p = true;
2186
2187 if (glyph_row->exact_window_width_line_p
2188 && (glyph_row->reversed_p
2189 ? (w->phys_cursor.hpos < 0)
2190 : (w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])))
1975 { 2191 {
1976 BView_SetPenSize (view, 1); 2192 glyph_row->cursor_in_fringe_p = true;
1977 BView_StrokeRectangle (view, fx, fy, w->phys_cursor_width, h); 2193 draw_fringe_bitmap (w, glyph_row, glyph_row->reversed_p);
1978 } 2194 }
1979 else 2195 else
1980 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); 2196 {
2197 switch (cursor_type)
2198 {
2199 case HOLLOW_BOX_CURSOR:
2200 haiku_draw_hollow_cursor (w, glyph_row);
2201 break;
1981 2202
1982 BView_invalidate_region (view, fx, fy, w->phys_cursor_width, h); 2203 case FILLED_BOX_CURSOR:
1983 break; 2204 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
1984 case FILLED_BOX_CURSOR: 2205 break;
1985 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); 2206
2207 case BAR_CURSOR:
2208 haiku_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
2209 break;
2210
2211 case HBAR_CURSOR:
2212 haiku_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
2213 break;
2214
2215 case NO_CURSOR:
2216 w->phys_cursor_width = 0;
2217 break;
2218
2219 default:
2220 emacs_abort ();
2221 }
2222 }
1986 } 2223 }
1987 BView_EndClip (view);
1988 BView_draw_unlock (view);
1989} 2224}
1990 2225
1991static void 2226static void
@@ -2072,19 +2307,25 @@ haiku_draw_vertical_window_border (struct window *w,
2072static void 2307static void
2073haiku_set_scroll_bar_default_width (struct frame *f) 2308haiku_set_scroll_bar_default_width (struct frame *f)
2074{ 2309{
2075 int unit = FRAME_COLUMN_WIDTH (f); 2310 int unit, size;
2076 FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = BScrollBar_default_size (0) + 1; 2311
2077 FRAME_CONFIG_SCROLL_BAR_COLS (f) = 2312 unit = FRAME_COLUMN_WIDTH (f);
2078 (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit; 2313 size = BScrollBar_default_size (0) + 1;
2314
2315 FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = size;
2316 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (size + unit - 1) / unit;
2079} 2317}
2080 2318
2081static void 2319static void
2082haiku_set_scroll_bar_default_height (struct frame *f) 2320haiku_set_scroll_bar_default_height (struct frame *f)
2083{ 2321{
2084 int height = FRAME_LINE_HEIGHT (f); 2322 int height, size;
2085 FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = BScrollBar_default_size (1) + 1; 2323
2086 FRAME_CONFIG_SCROLL_BAR_LINES (f) = 2324 height = FRAME_LINE_HEIGHT (f);
2087 (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height; 2325 size = BScrollBar_default_size (true) + 1;
2326
2327 FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = size;
2328 FRAME_CONFIG_SCROLL_BAR_LINES (f) = (size + height - 1) / height;
2088} 2329}
2089 2330
2090static void 2331static void
@@ -2266,15 +2507,17 @@ static struct scroll_bar *
2266haiku_scroll_bar_create (struct window *w, int left, int top, 2507haiku_scroll_bar_create (struct window *w, int left, int top,
2267 int width, int height, bool horizontal_p) 2508 int width, int height, bool horizontal_p)
2268{ 2509{
2269 struct frame *f = XFRAME (WINDOW_FRAME (w)); 2510 struct frame *f;
2270 Lisp_Object barobj; 2511 Lisp_Object barobj;
2512 struct scroll_bar *bar;
2513 void *scroll_bar;
2514 void *view;
2271 2515
2272 void *sb = NULL; 2516 f = XFRAME (WINDOW_FRAME (w));
2273 void *vw = FRAME_HAIKU_VIEW (f); 2517 view = FRAME_HAIKU_VIEW (f);
2274 2518
2275 block_input (); 2519 block_input ();
2276 struct scroll_bar *bar 2520 bar = ALLOCATE_PSEUDOVECTOR (struct scroll_bar, prev, PVEC_OTHER);
2277 = ALLOCATE_PSEUDOVECTOR (struct scroll_bar, prev, PVEC_OTHER);
2278 2521
2279 XSETWINDOW (bar->window, w); 2522 XSETWINDOW (bar->window, w);
2280 bar->top = top; 2523 bar->top = top;
@@ -2287,15 +2530,14 @@ haiku_scroll_bar_create (struct window *w, int left, int top,
2287 bar->update = -1; 2530 bar->update = -1;
2288 bar->horizontal = horizontal_p; 2531 bar->horizontal = horizontal_p;
2289 2532
2290 sb = BScrollBar_make_for_view (vw, horizontal_p, 2533 scroll_bar = be_make_scroll_bar_for_view (view, horizontal_p,
2291 left, top, left + width - 1, 2534 left, top, left + width - 1,
2292 top + height - 1, bar); 2535 top + height - 1);
2293 2536 BView_publish_scroll_bar (view, left, top, width, height);
2294 BView_publish_scroll_bar (vw, left, top, width, height);
2295 2537
2296 bar->next = FRAME_SCROLL_BARS (f); 2538 bar->next = FRAME_SCROLL_BARS (f);
2297 bar->prev = Qnil; 2539 bar->prev = Qnil;
2298 bar->scroll_bar = sb; 2540 bar->scroll_bar = scroll_bar;
2299 XSETVECTOR (barobj, bar); 2541 XSETVECTOR (barobj, bar);
2300 fset_scroll_bars (f, barobj); 2542 fset_scroll_bars (f, barobj);
2301 2543
@@ -2309,18 +2551,20 @@ haiku_scroll_bar_create (struct window *w, int left, int top,
2309static void 2551static void
2310haiku_set_horizontal_scroll_bar (struct window *w, int portion, int whole, int position) 2552haiku_set_horizontal_scroll_bar (struct window *w, int portion, int whole, int position)
2311{ 2553{
2312 eassert (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w));
2313 Lisp_Object barobj; 2554 Lisp_Object barobj;
2314 struct scroll_bar *bar; 2555 struct scroll_bar *bar;
2315 int top, height, left, width; 2556 int top, height, left, width;
2316 int window_x, window_width; 2557 int window_x, window_width;
2558 void *view;
2317 2559
2560 eassert (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w));
2318 /* Get window dimensions. */ 2561 /* Get window dimensions. */
2319 window_box (w, ANY_AREA, &window_x, 0, &window_width, 0); 2562 window_box (w, ANY_AREA, &window_x, 0, &window_width, 0);
2320 left = window_x; 2563 left = window_x;
2321 width = window_width; 2564 width = window_width;
2322 top = WINDOW_SCROLL_BAR_AREA_Y (w); 2565 top = WINDOW_SCROLL_BAR_AREA_Y (w);
2323 height = WINDOW_CONFIG_SCROLL_BAR_HEIGHT (w); 2566 height = WINDOW_CONFIG_SCROLL_BAR_HEIGHT (w);
2567 view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w));
2324 2568
2325 block_input (); 2569 block_input ();
2326 2570
@@ -2335,15 +2579,15 @@ haiku_set_horizontal_scroll_bar (struct window *w, int portion, int whole, int p
2335 { 2579 {
2336 bar = XSCROLL_BAR (w->horizontal_scroll_bar); 2580 bar = XSCROLL_BAR (w->horizontal_scroll_bar);
2337 2581
2338 if (bar->left != left || bar->top != top || 2582 if (bar->left != left || bar->top != top
2339 bar->width != width || bar->height != height) 2583 || bar->width != width || bar->height != height)
2340 { 2584 {
2341 void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w));
2342 BView_forget_scroll_bar (view, bar->left, bar->top, 2585 BView_forget_scroll_bar (view, bar->left, bar->top,
2343 bar->width, bar->height); 2586 bar->width, bar->height);
2344 BView_move_frame (bar->scroll_bar, left, top, 2587 BView_move_frame (bar->scroll_bar, left, top,
2345 left + width - 1, top + height - 1); 2588 left + width - 1, top + height - 1);
2346 BView_publish_scroll_bar (view, left, top, width, height); 2589 BView_publish_scroll_bar (view, left, top, width, height);
2590
2347 bar->left = left; 2591 bar->left = left;
2348 bar->top = top; 2592 bar->top = top;
2349 bar->width = width; 2593 bar->width = width;
@@ -2360,14 +2604,15 @@ haiku_set_horizontal_scroll_bar (struct window *w, int portion, int whole, int p
2360} 2604}
2361 2605
2362static void 2606static void
2363haiku_set_vertical_scroll_bar (struct window *w, 2607haiku_set_vertical_scroll_bar (struct window *w, int portion, int whole, int position)
2364 int portion, int whole, int position)
2365{ 2608{
2366 eassert (WINDOW_HAS_VERTICAL_SCROLL_BAR (w));
2367 Lisp_Object barobj; 2609 Lisp_Object barobj;
2368 struct scroll_bar *bar; 2610 struct scroll_bar *bar;
2369 int top, height, left, width; 2611 int top, height, left, width;
2370 int window_y, window_height; 2612 int window_y, window_height;
2613 void *view;
2614
2615 eassert (WINDOW_HAS_VERTICAL_SCROLL_BAR (w));
2371 2616
2372 /* Get window dimensions. */ 2617 /* Get window dimensions. */
2373 window_box (w, ANY_AREA, 0, &window_y, 0, &window_height); 2618 window_box (w, ANY_AREA, 0, &window_y, 0, &window_height);
@@ -2377,8 +2622,10 @@ haiku_set_vertical_scroll_bar (struct window *w,
2377 /* Compute the left edge and the width of the scroll bar area. */ 2622 /* Compute the left edge and the width of the scroll bar area. */
2378 left = WINDOW_SCROLL_BAR_AREA_X (w); 2623 left = WINDOW_SCROLL_BAR_AREA_X (w);
2379 width = WINDOW_SCROLL_BAR_AREA_WIDTH (w); 2624 width = WINDOW_SCROLL_BAR_AREA_WIDTH (w);
2380 block_input ();
2381 2625
2626 view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w));
2627
2628 block_input ();
2382 if (NILP (w->vertical_scroll_bar)) 2629 if (NILP (w->vertical_scroll_bar))
2383 { 2630 {
2384 bar = haiku_scroll_bar_create (w, left, top, width, height, false); 2631 bar = haiku_scroll_bar_create (w, left, top, width, height, false);
@@ -2389,15 +2636,15 @@ haiku_set_vertical_scroll_bar (struct window *w,
2389 { 2636 {
2390 bar = XSCROLL_BAR (w->vertical_scroll_bar); 2637 bar = XSCROLL_BAR (w->vertical_scroll_bar);
2391 2638
2392 if (bar->left != left || bar->top != top || 2639 if (bar->left != left || bar->top != top
2393 bar->width != width || bar->height != height) 2640 || bar->width != width || bar->height != height)
2394 { 2641 {
2395 void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w));
2396 BView_forget_scroll_bar (view, bar->left, bar->top, 2642 BView_forget_scroll_bar (view, bar->left, bar->top,
2397 bar->width, bar->height); 2643 bar->width, bar->height);
2398 BView_move_frame (bar->scroll_bar, left, top, 2644 BView_move_frame (bar->scroll_bar, left, top,
2399 left + width - 1, top + height - 1); 2645 left + width - 1, top + height - 1);
2400 BView_publish_scroll_bar (view, left, top, width, height); 2646 BView_publish_scroll_bar (view, left, top, width, height);
2647
2401 bar->left = left; 2648 bar->left = left;
2402 bar->top = top; 2649 bar->top = top;
2403 bar->width = width; 2650 bar->width = width;
@@ -2418,25 +2665,57 @@ static void
2418haiku_draw_fringe_bitmap (struct window *w, struct glyph_row *row, 2665haiku_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2419 struct draw_fringe_bitmap_params *p) 2666 struct draw_fringe_bitmap_params *p)
2420{ 2667{
2421 void *view = FRAME_HAIKU_VIEW (XFRAME (WINDOW_FRAME (w))); 2668 struct face *face;
2422 struct face *face = p->face; 2669 struct frame *f;
2670 struct haiku_bitmap_record *rec;
2671 void *view, *bitmap;
2672 uint32 col;
2673
2674 f = XFRAME (WINDOW_FRAME (w));
2675 view = FRAME_HAIKU_VIEW (f);
2676 face = p->face;
2423 2677
2424 block_input (); 2678 block_input ();
2425 BView_draw_lock (view, true, p->x, p->y, p->wd, p->h); 2679 BView_draw_lock (view, true, 0, 0, 0, 0);
2426 BView_StartClip (view); 2680 BView_StartClip (view);
2427 2681
2682 if (p->wd && p->h)
2683 BView_invalidate_region (view, p->x, p->y, p->wd, p->h);
2684
2428 haiku_clip_to_row (w, row, ANY_AREA); 2685 haiku_clip_to_row (w, row, ANY_AREA);
2686
2429 if (p->bx >= 0 && !p->overlay_p) 2687 if (p->bx >= 0 && !p->overlay_p)
2430 { 2688 {
2431 BView_SetHighColor (view, face->background); 2689 BView_invalidate_region (view, p->bx, p->by, p->nx, p->ny);
2432 BView_FillRectangle (view, p->bx, p->by, p->nx, p->ny); 2690
2691 if (!face->stipple)
2692 {
2693 BView_SetHighColor (view, face->background);
2694 BView_FillRectangle (view, p->bx, p->by, p->nx, p->ny);
2695 }
2696 else
2697 {
2698 rec = haiku_get_bitmap_rec (f, face->stipple);
2699 haiku_update_bitmap_rec (rec, face->foreground,
2700 face->background);
2701
2702 BView_StartClip (view);
2703 haiku_clip_to_row (w, row, ANY_AREA);
2704 BView_ClipToRect (view, p->bx, p->by, p->nx, p->ny);
2705 BView_DrawBitmapTiled (view, rec->img, 0, 0, -1, -1,
2706 0, 0, FRAME_PIXEL_WIDTH (f),
2707 FRAME_PIXEL_HEIGHT (f));
2708 BView_EndClip (view);
2709
2710 row->stipple_p = true;
2711 }
2433 } 2712 }
2434 2713
2435 if (p->which 2714 if (p->which
2436 && p->which < max_fringe_bmp 2715 && p->which < max_fringe_bmp
2437 && p->which < max_used_fringe_bitmap) 2716 && p->which < max_used_fringe_bitmap)
2438 { 2717 {
2439 void *bitmap = fringe_bmps[p->which]; 2718 bitmap = fringe_bmps[p->which];
2440 2719
2441 if (!bitmap) 2720 if (!bitmap)
2442 { 2721 {
@@ -2450,8 +2729,6 @@ haiku_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2450 bitmap = fringe_bmps[p->which]; 2729 bitmap = fringe_bmps[p->which];
2451 } 2730 }
2452 2731
2453 uint32_t col;
2454
2455 if (!p->cursor_p) 2732 if (!p->cursor_p)
2456 col = face->foreground; 2733 col = face->foreground;
2457 else if (p->overlay_p) 2734 else if (p->overlay_p)
@@ -2610,7 +2887,7 @@ haiku_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2610 x_display_list->last_mouse_glyph_frame = f1; 2887 x_display_list->last_mouse_glyph_frame = f1;
2611 2888
2612 *bar_window = Qnil; 2889 *bar_window = Qnil;
2613 *part = scroll_bar_above_handle; 2890 *part = scroll_bar_nowhere;
2614 2891
2615 /* If track-mouse is `drag-source' and the mouse pointer is 2892 /* If track-mouse is `drag-source' and the mouse pointer is
2616 certain to not be actually under the chosen frame, return 2893 certain to not be actually under the chosen frame, return
@@ -2659,20 +2936,13 @@ haiku_define_frame_cursor (struct frame *f, Emacs_Cursor cursor)
2659} 2936}
2660 2937
2661static void 2938static void
2662haiku_update_window_end (struct window *w, bool cursor_on_p,
2663 bool mouse_face_overwritten_p)
2664{
2665
2666}
2667
2668static void
2669haiku_default_font_parameter (struct frame *f, Lisp_Object parms) 2939haiku_default_font_parameter (struct frame *f, Lisp_Object parms)
2670{ 2940{
2671 struct haiku_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); 2941 struct haiku_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2672 Lisp_Object font_param = gui_display_get_arg (dpyinfo, parms, Qfont, NULL, NULL, 2942 Lisp_Object font_param = gui_display_get_arg (dpyinfo, parms, Qfont, NULL, NULL,
2673 RES_TYPE_STRING); 2943 RES_TYPE_STRING);
2674 Lisp_Object font = Qnil; 2944 Lisp_Object font = Qnil;
2675 if (EQ (font_param, Qunbound)) 2945 if (BASE_EQ (font_param, Qunbound))
2676 font_param = Qnil; 2946 font_param = Qnil;
2677 2947
2678 if (NILP (font_param)) 2948 if (NILP (font_param))
@@ -2733,8 +3003,8 @@ static struct redisplay_interface haiku_redisplay_interface =
2733 gui_clear_end_of_line, 3003 gui_clear_end_of_line,
2734 haiku_scroll_run, 3004 haiku_scroll_run,
2735 haiku_after_update_window_line, 3005 haiku_after_update_window_line,
2736 NULL, 3006 NULL, /* update_window_begin */
2737 haiku_update_window_end, 3007 NULL, /* update_window_end */
2738 haiku_flush, 3008 haiku_flush,
2739 gui_clear_window_mouse_face, 3009 gui_clear_window_mouse_face,
2740 gui_get_glyph_overhangs, 3010 gui_get_glyph_overhangs,
@@ -2750,7 +3020,7 @@ static struct redisplay_interface haiku_redisplay_interface =
2750 haiku_draw_window_cursor, 3020 haiku_draw_window_cursor,
2751 haiku_draw_vertical_window_border, 3021 haiku_draw_vertical_window_border,
2752 haiku_draw_window_divider, 3022 haiku_draw_window_divider,
2753 0, /* shift glyphs for insert */ 3023 NULL, /* shift glyphs for insert */
2754 haiku_show_hourglass, 3024 haiku_show_hourglass,
2755 haiku_hide_hourglass, 3025 haiku_hide_hourglass,
2756 haiku_default_font_parameter, 3026 haiku_default_font_parameter,
@@ -2759,11 +3029,20 @@ static struct redisplay_interface haiku_redisplay_interface =
2759static void 3029static void
2760haiku_make_fullscreen_consistent (struct frame *f) 3030haiku_make_fullscreen_consistent (struct frame *f)
2761{ 3031{
2762 Lisp_Object lval = get_frame_param (f, Qfullscreen); 3032 Lisp_Object lval;
2763 3033 struct haiku_output *output;
2764 if (!EQ (lval, Qmaximized) && FRAME_OUTPUT_DATA (f)->zoomed_p) 3034
3035 output = FRAME_OUTPUT_DATA (f);
3036
3037 if (output->fullscreen_mode == FULLSCREEN_MODE_BOTH)
3038 lval = Qfullboth;
3039 else if (output->fullscreen_mode == FULLSCREEN_MODE_WIDTH)
3040 lval = Qfullwidth;
3041 else if (output->fullscreen_mode == FULLSCREEN_MODE_HEIGHT)
3042 lval = Qfullheight;
3043 else if (output->fullscreen_mode == FULLSCREEN_MODE_MAXIMIZED)
2765 lval = Qmaximized; 3044 lval = Qmaximized;
2766 else if (EQ (lval, Qmaximized) && !FRAME_OUTPUT_DATA (f)->zoomed_p) 3045 else
2767 lval = Qnil; 3046 lval = Qnil;
2768 3047
2769 store_frame_param (f, Qfullscreen, lval); 3048 store_frame_param (f, Qfullscreen, lval);
@@ -2778,7 +3057,7 @@ haiku_flush_dirty_back_buffer_on (struct frame *f)
2778 haiku_flip_buffers (f); 3057 haiku_flip_buffers (f);
2779} 3058}
2780 3059
2781/* N.B. that support for TYPE must be explictly added to 3060/* N.B. that support for TYPE must be explicitly added to
2782 haiku_read_socket. */ 3061 haiku_read_socket. */
2783void 3062void
2784haiku_wait_for_event (struct frame *f, int type) 3063haiku_wait_for_event (struct frame *f, int type)
@@ -2816,7 +3095,7 @@ static int
2816haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit) 3095haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
2817{ 3096{
2818 int message_count; 3097 int message_count;
2819 static void *buf; 3098 void *buf;
2820 ssize_t b_size; 3099 ssize_t b_size;
2821 int button_or_motion_p, do_help; 3100 int button_or_motion_p, do_help;
2822 enum haiku_event_type type; 3101 enum haiku_event_type type;
@@ -2825,11 +3104,10 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
2825 message_count = 0; 3104 message_count = 0;
2826 button_or_motion_p = 0; 3105 button_or_motion_p = 0;
2827 do_help = 0; 3106 do_help = 0;
2828 buf = NULL; 3107
3108 buf = alloca (200);
2829 3109
2830 block_input (); 3110 block_input ();
2831 if (!buf)
2832 buf = xmalloc (200);
2833 haiku_read_size (&b_size, false); 3111 haiku_read_size (&b_size, false);
2834 while (b_size >= 0) 3112 while (b_size >= 0)
2835 { 3113 {
@@ -2868,8 +3146,12 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
2868 if (!f) 3146 if (!f)
2869 continue; 3147 continue;
2870 3148
2871 int width = lrint (b->px_widthf); 3149 int width = lrint (b->width);
2872 int height = lrint (b->px_heightf); 3150 int height = lrint (b->height);
3151
3152 if (FRAME_OUTPUT_DATA (f)->wait_for_event_type
3153 == FRAME_RESIZED)
3154 FRAME_OUTPUT_DATA (f)->wait_for_event_type = -1;
2873 3155
2874 if (FRAME_TOOLTIP_P (f)) 3156 if (FRAME_TOOLTIP_P (f))
2875 { 3157 {
@@ -2899,6 +3181,7 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
2899 cancel_mouse_face (f); 3181 cancel_mouse_face (f);
2900 haiku_clear_under_internal_border (f); 3182 haiku_clear_under_internal_border (f);
2901 } 3183 }
3184
2902 break; 3185 break;
2903 } 3186 }
2904 case FRAME_EXPOSED: 3187 case FRAME_EXPOSED:
@@ -3006,10 +3289,18 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3006 if (FRAME_TOOLTIP_P (f)) 3289 if (FRAME_TOOLTIP_P (f))
3007 { 3290 {
3008 /* Dismiss the tooltip if the mouse moves onto a 3291 /* Dismiss the tooltip if the mouse moves onto a
3009 tooltip frame. FIXME: for some reason we don't get 3292 tooltip frame (except when drag-and-drop is in
3010 leave notification events for this. */ 3293 progress and we are trying to move the tooltip
3011 3294 along with the mouse pointer). FIXME: for some
3012 if (any_help_event_p) 3295 reason we don't get leave notification events for
3296 this. */
3297
3298 if (any_help_event_p
3299 && !(be_drag_and_drop_in_progress ()
3300 && haiku_dnd_follow_tooltip)
3301 && !((EQ (track_mouse, Qdrag_source)
3302 || EQ (track_mouse, Qdropping))
3303 && gui_mouse_grabbed (x_display_list)))
3013 do_help = -1; 3304 do_help = -1;
3014 break; 3305 break;
3015 } 3306 }
@@ -3056,7 +3347,10 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3056 3347
3057 haiku_new_focus_frame (x_display_list->focused_frame); 3348 haiku_new_focus_frame (x_display_list->focused_frame);
3058 3349
3059 if (any_help_event_p) 3350 if (any_help_event_p
3351 && !((EQ (track_mouse, Qdrag_source)
3352 || EQ (track_mouse, Qdropping))
3353 && gui_mouse_grabbed (x_display_list)))
3060 do_help = -1; 3354 do_help = -1;
3061 } 3355 }
3062 else 3356 else
@@ -3081,18 +3375,17 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3081 previous_help_echo_string = help_echo_string; 3375 previous_help_echo_string = help_echo_string;
3082 help_echo_string = Qnil; 3376 help_echo_string = Qnil;
3083 3377
3084 /* A LeaveNotify event (well, the closest equivalent on Haiku, which 3378 /* A crossing event might be sent out-of-order with
3085 is a B_MOUSE_MOVED event with `transit' set to B_EXITED_VIEW) might 3379 regard to motion events from other windows, such as
3086 be sent out-of-order with regards to motion events from other 3380 when the mouse pointer rapidly moves from an
3087 windows, such as when the mouse pointer rapidly moves from an 3381 undecorated child frame to its parent. This can
3088 undecorated child frame to its parent. This can cause a failure to 3382 cause a failure to clear the mouse face on the
3089 clear the mouse face on the former if an event for the latter is 3383 former if an event for the latter is read by Emacs
3090 read by Emacs first and ends up showing the mouse face there. 3384 first and ends up showing the mouse face there.
3091 3385
3092 In case the `movement_locker' (also see the comment 3386 Work around the problem by clearing the mouse face
3093 there) doesn't take care of the problem, work 3387 now if it is currently shown on a different
3094 around it by clearing the mouse face now, if it is 3388 frame. */
3095 currently shown on a different frame. */
3096 3389
3097 if (hlinfo->mouse_face_hidden 3390 if (hlinfo->mouse_face_hidden
3098 || (f != hlinfo->mouse_face_mouse_frame 3391 || (f != hlinfo->mouse_face_mouse_frame
@@ -3181,13 +3474,13 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3181 Lisp_Object tab_bar_arg = Qnil; 3474 Lisp_Object tab_bar_arg = Qnil;
3182 int tab_bar_p = 0, tool_bar_p = 0; 3475 int tab_bar_p = 0, tool_bar_p = 0;
3183 bool up_okay_p = false; 3476 bool up_okay_p = false;
3477 struct scroll_bar *bar;
3184 3478
3185 if (popup_activated_p || !f) 3479 if (popup_activated_p || !f)
3186 continue; 3480 continue;
3187 3481
3188 struct haiku_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
3189
3190 inev.modifiers = haiku_modifiers_to_emacs (b->modifiers); 3482 inev.modifiers = haiku_modifiers_to_emacs (b->modifiers);
3483 bar = haiku_scroll_bar_from_widget (b->scroll_bar, b->window);
3191 3484
3192 x_display_list->last_mouse_glyph_frame = 0; 3485 x_display_list->last_mouse_glyph_frame = 0;
3193 x_display_list->last_mouse_movement_time = b->time / 1000; 3486 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)
3235 if (type == BUTTON_UP) 3528 if (type == BUTTON_UP)
3236 { 3529 {
3237 inev.modifiers |= up_modifier; 3530 inev.modifiers |= up_modifier;
3238 up_okay_p = (dpyinfo->grabbed & (1 << b->btn_no)); 3531 up_okay_p = (x_display_list->grabbed & (1 << b->btn_no));
3239 dpyinfo->grabbed &= ~(1 << b->btn_no); 3532 x_display_list->grabbed &= ~(1 << b->btn_no);
3240 } 3533 }
3241 else 3534 else
3242 { 3535 {
3243 up_okay_p = true; 3536 up_okay_p = true;
3244 inev.modifiers |= down_modifier; 3537 inev.modifiers |= down_modifier;
3245 dpyinfo->last_mouse_frame = f; 3538 x_display_list->last_mouse_frame = f;
3246 dpyinfo->grabbed |= (1 << b->btn_no); 3539 x_display_list->grabbed |= (1 << b->btn_no);
3247 if (f && !tab_bar_p) 3540 if (f && !tab_bar_p)
3248 f->last_tab_bar_item = -1; 3541 f->last_tab_bar_item = -1;
3249 if (f && !tool_bar_p) 3542 if (f && !tool_bar_p)
3250 f->last_tool_bar_item = -1; 3543 f->last_tool_bar_item = -1;
3251 } 3544 }
3252 3545
3253 if (up_okay_p 3546 if (bar)
3254 && !(tab_bar_p && NILP (tab_bar_arg)) 3547 {
3255 && !tool_bar_p) 3548 inev.kind = (bar->horizontal
3549 ? HORIZONTAL_SCROLL_BAR_CLICK_EVENT
3550 : SCROLL_BAR_CLICK_EVENT);
3551 inev.part = (bar->horizontal
3552 ? scroll_bar_horizontal_handle
3553 : scroll_bar_handle);
3554 }
3555 else if (up_okay_p
3556 && !(tab_bar_p && NILP (tab_bar_arg))
3557 && !tool_bar_p)
3256 inev.kind = MOUSE_CLICK_EVENT; 3558 inev.kind = MOUSE_CLICK_EVENT;
3559
3257 inev.arg = tab_bar_arg; 3560 inev.arg = tab_bar_arg;
3258 inev.code = b->btn_no; 3561 inev.code = b->btn_no;
3259 3562
3260 f->mouse_moved = false; 3563 f->mouse_moved = false;
3261 3564
3262 XSETINT (inev.x, b->x); 3565 if (bar)
3263 XSETINT (inev.y, b->y); 3566 {
3567 if (bar->horizontal)
3568 {
3569 XSETINT (inev.x, min (max (0, b->x - bar->left),
3570 bar->width));
3571 XSETINT (inev.y, bar->width);
3572 }
3573 else
3574 {
3575 XSETINT (inev.x, min (max (0, b->y - bar->top),
3576 bar->height));
3577 XSETINT (inev.y, bar->height);
3578 }
3579
3580 inev.frame_or_window = bar->window;
3581 }
3582 else
3583 {
3584 XSETINT (inev.x, b->x);
3585 XSETINT (inev.y, b->y);
3586 XSETFRAME (inev.frame_or_window, f);
3587 }
3264 3588
3265 XSETFRAME (inev.frame_or_window, f);
3266 break; 3589 break;
3267 } 3590 }
3268 case ICONIFICATION: 3591 case ICONIFICATION:
@@ -3279,7 +3602,6 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3279 SET_FRAME_ICONIFIED (f, 0); 3602 SET_FRAME_ICONIFIED (f, 0);
3280 inev.kind = DEICONIFY_EVENT; 3603 inev.kind = DEICONIFY_EVENT;
3281 3604
3282
3283 /* Haiku doesn't expose frames on deiconification, but 3605 /* Haiku doesn't expose frames on deiconification, but
3284 if we are double-buffered, the previous screen 3606 if we are double-buffered, the previous screen
3285 contents should have been preserved. */ 3607 contents should have been preserved. */
@@ -3303,30 +3625,36 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3303 { 3625 {
3304 struct haiku_move_event *b = buf; 3626 struct haiku_move_event *b = buf;
3305 struct frame *f = haiku_window_to_frame (b->window); 3627 struct frame *f = haiku_window_to_frame (b->window);
3628 int top, left;
3629 struct frame *p;
3306 3630
3307 if (!f) 3631 if (!f)
3308 continue; 3632 continue;
3309 3633
3634 FRAME_OUTPUT_DATA (f)->frame_x = b->x;
3635 FRAME_OUTPUT_DATA (f)->frame_y = b->y;
3636
3310 if (FRAME_PARENT_FRAME (f)) 3637 if (FRAME_PARENT_FRAME (f))
3311 haiku_coords_from_parent (f, &b->x, &b->y); 3638 haiku_coords_from_parent (f, &b->x, &b->y);
3312 3639
3313 if (b->x != f->left_pos || b->y != f->top_pos) 3640 left = b->x - b->decorator_width;
3641 top = b->y - b->decorator_height;
3642
3643 if (left != f->left_pos || top != f->top_pos)
3314 { 3644 {
3315 inev.kind = MOVE_FRAME_EVENT; 3645 inev.kind = MOVE_FRAME_EVENT;
3316 3646
3317 XSETINT (inev.x, b->x); 3647 XSETINT (inev.x, left);
3318 XSETINT (inev.y, b->y); 3648 XSETINT (inev.y, top);
3319 3649
3320 f->left_pos = b->x; 3650 f->left_pos = left;
3321 f->top_pos = b->y; 3651 f->top_pos = top;
3322 3652
3323 struct frame *p; 3653 p = FRAME_PARENT_FRAME (f);
3324 3654
3325 if ((p = FRAME_PARENT_FRAME (f))) 3655 if (p)
3326 { 3656 EmacsWindow_move_weak_child (FRAME_HAIKU_WINDOW (p),
3327 void *window = FRAME_HAIKU_WINDOW (p); 3657 b->window, left, top);
3328 EmacsWindow_move_weak_child (window, b->window, b->x, b->y);
3329 }
3330 3658
3331 XSETFRAME (inev.frame_or_window, f); 3659 XSETFRAME (inev.frame_or_window, f);
3332 } 3660 }
@@ -3357,8 +3685,9 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3357 inev.kind = (bar->horizontal 3685 inev.kind = (bar->horizontal
3358 ? HORIZONTAL_SCROLL_BAR_CLICK_EVENT : 3686 ? HORIZONTAL_SCROLL_BAR_CLICK_EVENT :
3359 SCROLL_BAR_CLICK_EVENT); 3687 SCROLL_BAR_CLICK_EVENT);
3360 inev.part = bar->horizontal ? 3688 inev.part = (bar->horizontal
3361 scroll_bar_horizontal_handle : scroll_bar_handle; 3689 ? scroll_bar_horizontal_handle
3690 : scroll_bar_handle);
3362 3691
3363 if (bar->horizontal) 3692 if (bar->horizontal)
3364 { 3693 {
@@ -3594,14 +3923,17 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3594 case ZOOM_EVENT: 3923 case ZOOM_EVENT:
3595 { 3924 {
3596 struct haiku_zoom_event *b = buf; 3925 struct haiku_zoom_event *b = buf;
3597
3598 struct frame *f = haiku_window_to_frame (b->window); 3926 struct frame *f = haiku_window_to_frame (b->window);
3599 3927
3600 if (!f) 3928 if (!f)
3601 continue; 3929 continue;
3602 3930
3603 FRAME_OUTPUT_DATA (f)->zoomed_p = b->zoomed; 3931 if (b->fullscreen_mode == FULLSCREEN_MODE_MAXIMIZED)
3604 haiku_make_fullscreen_consistent (f); 3932 f->want_fullscreen = FULLSCREEN_NONE;
3933 else
3934 f->want_fullscreen = FULLSCREEN_MAXIMIZED;
3935
3936 FRAME_TERMINAL (f)->fullscreen_hook (f);
3605 break; 3937 break;
3606 } 3938 }
3607 case DRAG_AND_DROP_EVENT: 3939 case DRAG_AND_DROP_EVENT:
@@ -3625,6 +3957,15 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3625 BMessage_delete (b->message); 3957 BMessage_delete (b->message);
3626 break; 3958 break;
3627 } 3959 }
3960 case SCREEN_CHANGED_EVENT:
3961 {
3962 struct haiku_screen_changed_event *b = buf;
3963
3964 inev.kind = MONITORS_CHANGED_EVENT;
3965 XSETTERMINAL (inev.arg, x_display_list->terminal);
3966 inev.timestamp = b->when / 1000;
3967 break;
3968 }
3628 case APP_QUIT_REQUESTED_EVENT: 3969 case APP_QUIT_REQUESTED_EVENT:
3629 inev.kind = SAVE_SESSION_EVENT; 3970 inev.kind = SAVE_SESSION_EVENT;
3630 inev.arg = Qt; 3971 inev.arg = Qt;
@@ -3685,6 +4026,21 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3685 return message_count; 4026 return message_count;
3686} 4027}
3687 4028
4029static Lisp_Object
4030haiku_get_focus_frame (struct frame *f)
4031{
4032 Lisp_Object lisp_focus;
4033 struct frame *focus;
4034
4035 focus = FRAME_DISPLAY_INFO (f)->focused_frame;
4036
4037 if (!focus)
4038 return Qnil;
4039
4040 XSETFRAME (lisp_focus, focus);
4041 return lisp_focus;
4042}
4043
3688static void 4044static void
3689haiku_frame_rehighlight (struct frame *frame) 4045haiku_frame_rehighlight (struct frame *frame)
3690{ 4046{
@@ -3833,6 +4189,8 @@ haiku_toggle_invisible_pointer (struct frame *f, bool invisible_p)
3833static void 4189static void
3834haiku_fullscreen (struct frame *f) 4190haiku_fullscreen (struct frame *f)
3835{ 4191{
4192 enum haiku_fullscreen_mode mode;
4193
3836 /* When FRAME_OUTPUT_DATA (f)->configury_done is false, the frame is 4194 /* When FRAME_OUTPUT_DATA (f)->configury_done is false, the frame is
3837 being created, and its regular width and height have not yet been 4195 being created, and its regular width and height have not yet been
3838 set. This function will be called again by haiku_create_frame, 4196 set. This function will be called again by haiku_create_frame,
@@ -3841,18 +4199,22 @@ haiku_fullscreen (struct frame *f)
3841 return; 4199 return;
3842 4200
3843 if (f->want_fullscreen == FULLSCREEN_MAXIMIZED) 4201 if (f->want_fullscreen == FULLSCREEN_MAXIMIZED)
3844 BWindow_zoom (FRAME_HAIKU_WINDOW (f)); 4202 mode = FULLSCREEN_MODE_MAXIMIZED;
3845 else if (f->want_fullscreen == FULLSCREEN_BOTH) 4203 else if (f->want_fullscreen == FULLSCREEN_BOTH)
3846 EmacsWindow_make_fullscreen (FRAME_HAIKU_WINDOW (f), 1); 4204 mode = FULLSCREEN_MODE_BOTH;
4205 else if (f->want_fullscreen == FULLSCREEN_WIDTH)
4206 mode = FULLSCREEN_MODE_WIDTH;
4207 else if (f->want_fullscreen == FULLSCREEN_HEIGHT)
4208 mode = FULLSCREEN_MODE_HEIGHT;
3847 else 4209 else
3848 { 4210 mode = FULLSCREEN_MODE_NONE;
3849 EmacsWindow_make_fullscreen (FRAME_HAIKU_WINDOW (f), 0);
3850 EmacsWindow_unzoom (FRAME_HAIKU_WINDOW (f));
3851 }
3852 4211
3853 f->want_fullscreen = FULLSCREEN_NONE; 4212 f->want_fullscreen = FULLSCREEN_NONE;
4213 be_set_window_fullscreen_mode (FRAME_HAIKU_WINDOW (f), mode);
4214 FRAME_OUTPUT_DATA (f)->fullscreen_mode = mode;
3854 4215
3855 haiku_update_size_hints (f); 4216 haiku_update_size_hints (f);
4217 haiku_make_fullscreen_consistent (f);
3856} 4218}
3857 4219
3858static struct terminal * 4220static struct terminal *
@@ -3873,7 +4235,7 @@ haiku_create_terminal (struct haiku_display_info *dpyinfo)
3873 terminal->frame_visible_invisible_hook = haiku_set_frame_visible_invisible; 4235 terminal->frame_visible_invisible_hook = haiku_set_frame_visible_invisible;
3874 terminal->set_frame_offset_hook = haiku_set_offset; 4236 terminal->set_frame_offset_hook = haiku_set_offset;
3875 terminal->delete_terminal_hook = haiku_delete_terminal; 4237 terminal->delete_terminal_hook = haiku_delete_terminal;
3876 terminal->get_string_resource_hook = get_string_resource; 4238 terminal->get_string_resource_hook = haiku_get_string_resource;
3877 terminal->set_new_font_hook = haiku_new_font; 4239 terminal->set_new_font_hook = haiku_new_font;
3878 terminal->defined_color_hook = haiku_defined_color; 4240 terminal->defined_color_hook = haiku_defined_color;
3879 terminal->set_window_size_hook = haiku_set_window_size; 4241 terminal->set_window_size_hook = haiku_set_window_size;
@@ -3904,6 +4266,7 @@ haiku_create_terminal (struct haiku_display_info *dpyinfo)
3904 terminal->fullscreen_hook = haiku_fullscreen; 4266 terminal->fullscreen_hook = haiku_fullscreen;
3905 terminal->toolkit_position_hook = haiku_toolkit_position; 4267 terminal->toolkit_position_hook = haiku_toolkit_position;
3906 terminal->activate_menubar_hook = haiku_activate_menubar; 4268 terminal->activate_menubar_hook = haiku_activate_menubar;
4269 terminal->get_focus_frame = haiku_get_focus_frame;
3907 4270
3908 return terminal; 4271 return terminal;
3909} 4272}
@@ -3959,34 +4322,24 @@ haiku_term_init (void)
3959 4322
3960 gui_init_fringe (terminal->rif); 4323 gui_init_fringe (terminal->rif);
3961 4324
3962#define ASSIGN_CURSOR(cursor, be_cursor) (dpyinfo->cursor = be_cursor) 4325#define ASSIGN_CURSOR(cursor, cursor_id) \
3963 ASSIGN_CURSOR (text_cursor, BCursor_create_i_beam ()); 4326 (dpyinfo->cursor = be_create_cursor_from_id (cursor_id))
3964 ASSIGN_CURSOR (nontext_cursor, BCursor_create_default ()); 4327 ASSIGN_CURSOR (text_cursor, CURSOR_ID_I_BEAM);
3965 ASSIGN_CURSOR (modeline_cursor, BCursor_create_modeline ()); 4328 ASSIGN_CURSOR (nontext_cursor, CURSOR_ID_SYSTEM_DEFAULT);
3966 ASSIGN_CURSOR (hand_cursor, BCursor_create_grab ()); 4329 ASSIGN_CURSOR (modeline_cursor, CURSOR_ID_CONTEXT_MENU);
3967 ASSIGN_CURSOR (hourglass_cursor, BCursor_create_progress_cursor ()); 4330 ASSIGN_CURSOR (hand_cursor, CURSOR_ID_GRAB);
3968 ASSIGN_CURSOR (horizontal_drag_cursor, 4331 ASSIGN_CURSOR (hourglass_cursor, CURSOR_ID_PROGRESS);
3969 BCursor_from_id (CURSOR_ID_RESIZE_EAST_WEST)); 4332 ASSIGN_CURSOR (horizontal_drag_cursor, CURSOR_ID_RESIZE_EAST_WEST);
3970 ASSIGN_CURSOR (vertical_drag_cursor, 4333 ASSIGN_CURSOR (vertical_drag_cursor, CURSOR_ID_RESIZE_NORTH_SOUTH);
3971 BCursor_from_id (CURSOR_ID_RESIZE_NORTH_SOUTH)); 4334 ASSIGN_CURSOR (left_edge_cursor, CURSOR_ID_RESIZE_WEST);
3972 ASSIGN_CURSOR (left_edge_cursor, 4335 ASSIGN_CURSOR (top_left_corner_cursor, CURSOR_ID_RESIZE_NORTH_WEST);
3973 BCursor_from_id (CURSOR_ID_RESIZE_WEST)); 4336 ASSIGN_CURSOR (top_edge_cursor, CURSOR_ID_RESIZE_NORTH);
3974 ASSIGN_CURSOR (top_left_corner_cursor, 4337 ASSIGN_CURSOR (top_right_corner_cursor, CURSOR_ID_RESIZE_NORTH_EAST);
3975 BCursor_from_id (CURSOR_ID_RESIZE_NORTH_WEST)); 4338 ASSIGN_CURSOR (right_edge_cursor, CURSOR_ID_RESIZE_EAST);
3976 ASSIGN_CURSOR (top_edge_cursor, 4339 ASSIGN_CURSOR (bottom_right_corner_cursor, CURSOR_ID_RESIZE_SOUTH_EAST);
3977 BCursor_from_id (CURSOR_ID_RESIZE_NORTH)); 4340 ASSIGN_CURSOR (bottom_edge_cursor, CURSOR_ID_RESIZE_SOUTH);
3978 ASSIGN_CURSOR (top_right_corner_cursor, 4341 ASSIGN_CURSOR (bottom_left_corner_cursor, CURSOR_ID_RESIZE_SOUTH_WEST);
3979 BCursor_from_id (CURSOR_ID_RESIZE_NORTH_EAST)); 4342 ASSIGN_CURSOR (no_cursor, CURSOR_ID_NO_CURSOR);
3980 ASSIGN_CURSOR (right_edge_cursor,
3981 BCursor_from_id (CURSOR_ID_RESIZE_EAST));
3982 ASSIGN_CURSOR (bottom_right_corner_cursor,
3983 BCursor_from_id (CURSOR_ID_RESIZE_SOUTH_EAST));
3984 ASSIGN_CURSOR (bottom_edge_cursor,
3985 BCursor_from_id (CURSOR_ID_RESIZE_SOUTH));
3986 ASSIGN_CURSOR (bottom_left_corner_cursor,
3987 BCursor_from_id (CURSOR_ID_RESIZE_SOUTH_WEST));
3988 ASSIGN_CURSOR (no_cursor,
3989 BCursor_from_id (CURSOR_ID_NO_CURSOR));
3990#undef ASSIGN_CURSOR 4343#undef ASSIGN_CURSOR
3991 4344
3992 system_name = Fsystem_name (); 4345 system_name = Fsystem_name ();
@@ -4082,9 +4435,15 @@ mark_haiku_display (void)
4082void 4435void
4083haiku_scroll_bar_remove (struct scroll_bar *bar) 4436haiku_scroll_bar_remove (struct scroll_bar *bar)
4084{ 4437{
4438 void *view;
4439 struct frame *f;
4440
4441 f = WINDOW_XFRAME (XWINDOW (bar->window));
4442 view = FRAME_HAIKU_VIEW (f);
4443
4085 block_input (); 4444 block_input ();
4086 void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (XWINDOW (bar->window))); 4445 BView_forget_scroll_bar (view, bar->left, bar->top,
4087 BView_forget_scroll_bar (view, bar->left, bar->top, bar->width, bar->height); 4446 bar->width, bar->height);
4088 BScrollBar_delete (bar->scroll_bar); 4447 BScrollBar_delete (bar->scroll_bar);
4089 expose_frame (WINDOW_XFRAME (XWINDOW (bar->window)), 4448 expose_frame (WINDOW_XFRAME (XWINDOW (bar->window)),
4090 bar->left, bar->top, bar->width, bar->height); 4449 bar->left, bar->top, bar->width, bar->height);
@@ -4093,7 +4452,6 @@ haiku_scroll_bar_remove (struct scroll_bar *bar)
4093 wset_horizontal_scroll_bar (XWINDOW (bar->window), Qnil); 4452 wset_horizontal_scroll_bar (XWINDOW (bar->window), Qnil);
4094 else 4453 else
4095 wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil); 4454 wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil);
4096
4097 unblock_input (); 4455 unblock_input ();
4098}; 4456};
4099 4457
@@ -4101,6 +4459,22 @@ void
4101haiku_set_offset (struct frame *frame, int x, int y, 4459haiku_set_offset (struct frame *frame, int x, int y,
4102 int change_gravity) 4460 int change_gravity)
4103{ 4461{
4462 Lisp_Object lframe;
4463
4464 /* Don't allow moving a fullscreen frame: the semantics of that are
4465 unclear. */
4466
4467 XSETFRAME (lframe, frame);
4468 if (EQ (Fframe_parameter (lframe, Qfullscreen), Qfullboth)
4469 /* Only do this if the fullscreen status has actually been
4470 applied. */
4471 && frame->want_fullscreen == FULLSCREEN_NONE
4472 /* And if the configury during frame creation has been
4473 completed. Otherwise, there will be no valid "old position"
4474 to go back to. */
4475 && FRAME_OUTPUT_DATA (frame)->configury_done)
4476 return;
4477
4104 if (change_gravity > 0) 4478 if (change_gravity > 0)
4105 { 4479 {
4106 frame->top_pos = y; 4480 frame->top_pos = y;
@@ -4160,7 +4534,7 @@ haiku_merge_cursor_foreground (struct glyph_string *s,
4160 foreground = s->face->foreground; 4534 foreground = s->face->foreground;
4161 4535
4162 if (background == s->face->background 4536 if (background == s->face->background
4163 || foreground == s->face->foreground) 4537 && foreground == s->face->foreground)
4164 { 4538 {
4165 background = s->face->foreground; 4539 background = s->face->foreground;
4166 foreground = s->face->background; 4540 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
52 char *file; 52 char *file;
53 int refcount; 53 int refcount;
54 int height, width, depth; 54 int height, width, depth;
55
56 uint32_t stipple_foreground;
57 uint32_t stipple_background;
58 void *stipple_bits;
55}; 59};
56 60
57struct haiku_display_info 61struct haiku_display_info
@@ -156,13 +160,16 @@ struct haiku_output
156 int fontset; 160 int fontset;
157 int baseline_offset; 161 int baseline_offset;
158 162
159 bool_bf zoomed_p : 1; 163 /* Whether or not the hourglass cursor is currently being
164 displayed. */
160 bool_bf hourglass_p : 1; 165 bool_bf hourglass_p : 1;
166
167 /* Whether or not the menu bar is open. */
161 bool_bf menu_bar_open_p : 1; 168 bool_bf menu_bar_open_p : 1;
162 169
163 /* Whether or not there is data in a back buffer that hasn't been 170 /* Whether or not there is data in a back buffer that hasn't been
164 displayed yet. */ 171 displayed yet. */
165 bool dirty_p; 172 bool_bf dirty_p : 1;
166 173
167 struct font *font; 174 struct font *font;
168 175
@@ -192,6 +199,15 @@ struct haiku_output
192 They are changed only when a different background is involved. 199 They are changed only when a different background is involved.
193 -1 means no color has been computed. */ 200 -1 means no color has been computed. */
194 long relief_background; 201 long relief_background;
202
203 /* The absolute position of this frame. This differs from left_pos
204 and top_pos in that the decorator and parent frames are not taken
205 into account. */
206 int frame_x, frame_y;
207
208 /* The current fullscreen mode of this frame. This should be `enum
209 haiku_fullscreen_mode', but that isn't available here. */
210 int fullscreen_mode;
195}; 211};
196 212
197struct x_output 213struct x_output
@@ -203,7 +219,13 @@ extern struct haiku_display_info *x_display_list;
203extern struct font_driver const haikufont_driver; 219extern struct font_driver const haikufont_driver;
204 220
205extern Lisp_Object tip_frame; 221extern Lisp_Object tip_frame;
222extern Lisp_Object tip_dx;
223extern Lisp_Object tip_dy;
224
206extern struct frame *haiku_dnd_frame; 225extern struct frame *haiku_dnd_frame;
226extern bool haiku_dnd_follow_tooltip;
227
228extern frame_parm_handler haiku_frame_parm_handlers[];
207 229
208struct scroll_bar 230struct scroll_bar
209{ 231{
@@ -298,6 +320,7 @@ extern void haiku_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
298extern void haiku_set_internal_border_width (struct frame *, Lisp_Object, Lisp_Object); 320extern void haiku_set_internal_border_width (struct frame *, Lisp_Object, Lisp_Object);
299extern void haiku_change_tab_bar_height (struct frame *, int); 321extern void haiku_change_tab_bar_height (struct frame *, int);
300extern void haiku_change_tool_bar_height (struct frame *, int); 322extern void haiku_change_tool_bar_height (struct frame *, int);
323extern void haiku_free_custom_cursors (struct frame *);
301 324
302extern void haiku_query_color (uint32_t, Emacs_Color *); 325extern void haiku_query_color (uint32_t, Emacs_Color *);
303 326
@@ -323,6 +346,9 @@ extern int haiku_load_image (struct frame *, struct image *,
323extern void syms_of_haikuimage (void); 346extern void syms_of_haikuimage (void);
324#endif 347#endif
325 348
349extern void haiku_draw_background_rect (struct glyph_string *, struct face *,
350 int, int, int, int);
351
326#ifdef USE_BE_CAIRO 352#ifdef USE_BE_CAIRO
327extern cairo_t *haiku_begin_cr_clip (struct frame *, struct glyph_string *); 353extern cairo_t *haiku_begin_cr_clip (struct frame *, struct glyph_string *);
328 354
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,
542#endif /* HAVE_PGTK */ 542#endif /* HAVE_PGTK */
543 543
544#ifdef HAVE_HAIKU 544#ifdef HAVE_HAIKU
545 void *bitmap = BBitmap_new (width, height, 1); 545 void *bitmap, *stipple;
546 int bytes_per_line, x, y;
547
548 bitmap = BBitmap_new (width, height, false);
546 549
547 if (!bitmap) 550 if (!bitmap)
548 return -1; 551 return -1;
549 552
550 BBitmap_import_mono_bits (bitmap, bits, width, height); 553 bytes_per_line = (width + 7) / 8;
554 stipple = xmalloc (height * bytes_per_line);
555 memcpy (stipple, bits, height * bytes_per_line);
556
557 for (y = 0; y < height; y++)
558 {
559 for (x = 0; x < width; x++)
560 PUT_PIXEL (bitmap, x, y, ((bits[8] >> (x % 8)) & 1
561 ? f->foreground_pixel
562 : f->background_pixel));
563 bits += bytes_per_line;
564 }
551#endif 565#endif
552 566
553 id = image_allocate_bitmap_record (f); 567 id = image_allocate_bitmap_record (f);
@@ -567,6 +581,11 @@ image_create_bitmap_from_data (struct frame *f, char *bits,
567#ifdef HAVE_HAIKU 581#ifdef HAVE_HAIKU
568 dpyinfo->bitmaps[id - 1].img = bitmap; 582 dpyinfo->bitmaps[id - 1].img = bitmap;
569 dpyinfo->bitmaps[id - 1].depth = 1; 583 dpyinfo->bitmaps[id - 1].depth = 1;
584 dpyinfo->bitmaps[id - 1].stipple_bits = stipple;
585 dpyinfo->bitmaps[id - 1].stipple_foreground
586 = f->foreground_pixel & 0xffffffff;
587 dpyinfo->bitmaps[id - 1].stipple_background
588 = f->background_pixel & 0xffffffff;
570#endif 589#endif
571 590
572 dpyinfo->bitmaps[id - 1].file = NULL; 591 dpyinfo->bitmaps[id - 1].file = NULL;
@@ -592,24 +611,55 @@ image_create_bitmap_from_data (struct frame *f, char *bits,
592 return id; 611 return id;
593} 612}
594 613
614#if defined HAVE_HAIKU || defined HAVE_NS
615static char *slurp_file (int, ptrdiff_t *);
616static Lisp_Object image_find_image_fd (Lisp_Object, int *);
617static bool xbm_read_bitmap_data (struct frame *, char *, char *,
618 int *, int *, char **, bool);
619#endif
620
595/* Create bitmap from file FILE for frame F. */ 621/* Create bitmap from file FILE for frame F. */
596 622
597ptrdiff_t 623ptrdiff_t
598image_create_bitmap_from_file (struct frame *f, Lisp_Object file) 624image_create_bitmap_from_file (struct frame *f, Lisp_Object file)
599{ 625{
600#if defined (HAVE_NTGUI) || defined (HAVE_HAIKU) 626#if defined (HAVE_NTGUI)
601 return -1; /* W32_TODO : bitmap support */ 627 return -1; /* W32_TODO : bitmap support */
602#else 628#else
603 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f); 629 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
604#endif 630#endif
605 631
606#ifdef HAVE_NS 632#ifdef HAVE_NS
607 ptrdiff_t id; 633 ptrdiff_t id, size;
608 void *bitmap = ns_image_from_file (file); 634 int fd, width, height, rc;
635 char *contents, *data;
636 void *bitmap;
609 637
610 if (!bitmap) 638 if (!STRINGP (image_find_image_fd (file, &fd)))
639 return -1;
640
641 contents = slurp_file (fd, &size);
642
643 if (!contents)
644 return -1;
645
646 rc = xbm_read_bitmap_data (f, contents, contents + size,
647 &width, &height, &data, 0);
648
649 if (!rc)
650 {
651 xfree (contents);
611 return -1; 652 return -1;
653 }
612 654
655 bitmap = ns_image_from_XBM (data, width, height, 0, 0);
656
657 if (!bitmap)
658 {
659 xfree (contents);
660 xfree (data);
661 return -1;
662 }
613 663
614 id = image_allocate_bitmap_record (f); 664 id = image_allocate_bitmap_record (f);
615 dpyinfo->bitmaps[id - 1].img = bitmap; 665 dpyinfo->bitmaps[id - 1].img = bitmap;
@@ -618,6 +668,9 @@ image_create_bitmap_from_file (struct frame *f, Lisp_Object file)
618 dpyinfo->bitmaps[id - 1].depth = 1; 668 dpyinfo->bitmaps[id - 1].depth = 1;
619 dpyinfo->bitmaps[id - 1].height = ns_image_width (bitmap); 669 dpyinfo->bitmaps[id - 1].height = ns_image_width (bitmap);
620 dpyinfo->bitmaps[id - 1].width = ns_image_height (bitmap); 670 dpyinfo->bitmaps[id - 1].width = ns_image_height (bitmap);
671
672 xfree (contents);
673 xfree (data);
621 return id; 674 return id;
622#endif 675#endif
623 676
@@ -637,7 +690,6 @@ image_create_bitmap_from_file (struct frame *f, Lisp_Object file)
637 dpyinfo->bitmaps[id - 1].img = bitmap; 690 dpyinfo->bitmaps[id - 1].img = bitmap;
638 dpyinfo->bitmaps[id - 1].refcount = 1; 691 dpyinfo->bitmaps[id - 1].refcount = 1;
639 dpyinfo->bitmaps[id - 1].file = xlispstrdup (file); 692 dpyinfo->bitmaps[id - 1].file = xlispstrdup (file);
640 //dpyinfo->bitmaps[id - 1].depth = 1;
641 dpyinfo->bitmaps[id - 1].height = gdk_pixbuf_get_width (bitmap); 693 dpyinfo->bitmaps[id - 1].height = gdk_pixbuf_get_width (bitmap);
642 dpyinfo->bitmaps[id - 1].width = gdk_pixbuf_get_height (bitmap); 694 dpyinfo->bitmaps[id - 1].width = gdk_pixbuf_get_height (bitmap);
643 dpyinfo->bitmaps[id - 1].pattern 695 dpyinfo->bitmaps[id - 1].pattern
@@ -692,6 +744,89 @@ image_create_bitmap_from_file (struct frame *f, Lisp_Object file)
692 744
693 return id; 745 return id;
694#endif /* HAVE_X_WINDOWS */ 746#endif /* HAVE_X_WINDOWS */
747
748#ifdef HAVE_HAIKU
749 ptrdiff_t id, size;
750 int fd, width, height, rc, bytes_per_line, x, y;
751 char *contents, *data, *tmp;
752 void *bitmap;
753 Lisp_Object found;
754
755 /* Look for an existing bitmap with the same name. */
756 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
757 {
758 if (dpyinfo->bitmaps[id].refcount
759 && dpyinfo->bitmaps[id].file
760 && !strcmp (dpyinfo->bitmaps[id].file, SSDATA (file)))
761 {
762 ++dpyinfo->bitmaps[id].refcount;
763 return id + 1;
764 }
765 }
766
767 /* Search bitmap-file-path for the file, if appropriate. */
768 if (openp (Vx_bitmap_file_path, file, Qnil, &found,
769 make_fixnum (R_OK), false, false)
770 < 0)
771 return -1;
772
773 if (!STRINGP (image_find_image_fd (file, &fd))
774 && !STRINGP (image_find_image_fd (found, &fd)))
775 return -1;
776
777 contents = slurp_file (fd, &size);
778
779 if (!contents)
780 return -1;
781
782 rc = xbm_read_bitmap_data (f, contents, contents + size,
783 &width, &height, &data, 0);
784
785 if (!rc)
786 {
787 xfree (contents);
788 return -1;
789 }
790
791 bitmap = BBitmap_new (width, height, false);
792
793 if (!bitmap)
794 {
795 xfree (contents);
796 xfree (data);
797 return -1;
798 }
799
800 id = image_allocate_bitmap_record (f);
801
802 dpyinfo->bitmaps[id - 1].img = bitmap;
803 dpyinfo->bitmaps[id - 1].depth = 1;
804 dpyinfo->bitmaps[id - 1].file = xlispstrdup (file);
805 dpyinfo->bitmaps[id - 1].height = height;
806 dpyinfo->bitmaps[id - 1].width = width;
807 dpyinfo->bitmaps[id - 1].refcount = 1;
808 dpyinfo->bitmaps[id - 1].stipple_foreground
809 = f->foreground_pixel & 0xffffffff;
810 dpyinfo->bitmaps[id - 1].stipple_background
811 = f->background_pixel & 0xffffffff;
812 dpyinfo->bitmaps[id - 1].stipple_bits = data;
813
814 bytes_per_line = (width + 7) / 8;
815 tmp = data;
816
817 for (y = 0; y < height; y++)
818 {
819 for (x = 0; x < width; x++)
820 PUT_PIXEL (bitmap, x, y, ((tmp[x / 8] >> (x % 8)) & 1
821 ? f->foreground_pixel
822 : f->background_pixel));
823
824 tmp += bytes_per_line;
825 }
826
827 xfree (contents);
828 return id;
829#endif
695} 830}
696 831
697/* Free bitmap B. */ 832/* Free bitmap B. */
@@ -724,6 +859,9 @@ free_bitmap_record (Display_Info *dpyinfo, Bitmap_Record *bm)
724 859
725#ifdef HAVE_HAIKU 860#ifdef HAVE_HAIKU
726 BBitmap_free (bm->img); 861 BBitmap_free (bm->img);
862
863 if (bm->stipple_bits)
864 xfree (bm->stipple_bits);
727#endif 865#endif
728 866
729 if (bm->file) 867 if (bm->file)
@@ -6169,7 +6307,7 @@ image_edge_detection (struct frame *f, struct image *img,
6169} 6307}
6170 6308
6171 6309
6172#if defined HAVE_X_WINDOWS || defined USE_CAIRO 6310#if defined HAVE_X_WINDOWS || defined USE_CAIRO || defined HAVE_HAIKU
6173static void 6311static void
6174image_pixmap_draw_cross (struct frame *f, Emacs_Pixmap pixmap, 6312image_pixmap_draw_cross (struct frame *f, Emacs_Pixmap pixmap,
6175 int x, int y, unsigned int width, unsigned int height, 6313 int x, int y, unsigned int width, unsigned int height,
@@ -6203,9 +6341,11 @@ image_pixmap_draw_cross (struct frame *f, Emacs_Pixmap pixmap,
6203 XDrawLine (dpy, pixmap, gc, x, y, x + width - 1, y + height - 1); 6341 XDrawLine (dpy, pixmap, gc, x, y, x + width - 1, y + height - 1);
6204 XDrawLine (dpy, pixmap, gc, x, y + height - 1, x + width - 1, y); 6342 XDrawLine (dpy, pixmap, gc, x, y + height - 1, x + width - 1, y);
6205 XFreeGC (dpy, gc); 6343 XFreeGC (dpy, gc);
6206#endif /* HAVE_X_WINDOWS */ 6344#elif HAVE_HAIKU
6345 be_draw_cross_on_pixmap (pixmap, x, y, width, height, color);
6346#endif
6207} 6347}
6208#endif /* HAVE_X_WINDOWS || USE_CAIRO */ 6348#endif /* HAVE_X_WINDOWS || USE_CAIRO || HAVE_HAIKU */
6209 6349
6210/* Transform image IMG on frame F so that it looks disabled. */ 6350/* Transform image IMG on frame F so that it looks disabled. */
6211 6351
@@ -6247,25 +6387,23 @@ image_disable_image (struct frame *f, struct image *img)
6247 { 6387 {
6248#ifndef HAVE_NTGUI 6388#ifndef HAVE_NTGUI
6249#ifndef HAVE_NS /* TODO: NS support, however this not needed for toolbars */ 6389#ifndef HAVE_NS /* TODO: NS support, however this not needed for toolbars */
6250#ifndef HAVE_HAIKU
6251 6390
6252#ifndef USE_CAIRO 6391#if !defined USE_CAIRO && !defined HAVE_HAIKU
6253#define CrossForeground(f) BLACK_PIX_DEFAULT (f) 6392#define CrossForeground(f) BLACK_PIX_DEFAULT (f)
6254#define MaskForeground(f) WHITE_PIX_DEFAULT (f) 6393#define MaskForeground(f) WHITE_PIX_DEFAULT (f)
6255#else /* USE_CAIRO */ 6394#else /* USE_CAIRO || HAVE_HAIKU */
6256#define CrossForeground(f) 0 6395#define CrossForeground(f) 0
6257#define MaskForeground(f) PIX_MASK_DRAW 6396#define MaskForeground(f) PIX_MASK_DRAW
6258#endif /* USE_CAIRO */ 6397#endif /* USE_CAIRO || HAVE_HAIKU */
6259 6398
6260#ifndef USE_CAIRO 6399#if !defined USE_CAIRO && !defined HAVE_HAIKU
6261 image_sync_to_pixmaps (f, img); 6400 image_sync_to_pixmaps (f, img);
6262#endif /* !USE_CAIRO */ 6401#endif /* !USE_CAIRO && !HAVE_HAIKU */
6263 image_pixmap_draw_cross (f, img->pixmap, 0, 0, img->width, img->height, 6402 image_pixmap_draw_cross (f, img->pixmap, 0, 0, img->width, img->height,
6264 CrossForeground (f)); 6403 CrossForeground (f));
6265 if (img->mask) 6404 if (img->mask)
6266 image_pixmap_draw_cross (f, img->mask, 0, 0, img->width, img->height, 6405 image_pixmap_draw_cross (f, img->mask, 0, 0, img->width, img->height,
6267 MaskForeground (f)); 6406 MaskForeground (f));
6268#endif /* !HAVE_HAIKU */
6269#endif /* !HAVE_NS */ 6407#endif /* !HAVE_NS */
6270#else 6408#else
6271 HDC hdc, bmpdc; 6409 HDC hdc, bmpdc;
@@ -8970,7 +9108,7 @@ gif_load (struct frame *f, struct image *img)
8970 goto gif_error; 9108 goto gif_error;
8971 } 9109 }
8972 9110
8973 /* It's an animated image, so initalize the cache. */ 9111 /* It's an animated image, so initialize the cache. */
8974 if (cache && !cache->handle) 9112 if (cache && !cache->handle)
8975 { 9113 {
8976 cache->handle = gif; 9114 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,
1204 /* Negative width means use all available text columns. */ 1204 /* Negative width means use all available text columns. */
1205 if (width < 0) 1205 if (width < 0)
1206 { 1206 {
1207 width = window_body_width (win, 0); 1207 width = window_body_width (win, WINDOW_BODY_IN_CANONICAL_CHARS);
1208 /* We must make room for continuation marks if we don't have fringes. */ 1208 /* We must make room for continuation marks if we don't have fringes. */
1209#ifdef HAVE_WINDOW_SYSTEM 1209#ifdef HAVE_WINDOW_SYSTEM
1210 if (!FRAME_WINDOW_P (XFRAME (win->frame))) 1210 if (!FRAME_WINDOW_P (XFRAME (win->frame)))
@@ -1814,7 +1814,7 @@ visible section of the buffer, and pass LINE and COL as TOPOS. */)
1814 ? window_internal_height (w) 1814 ? window_internal_height (w)
1815 : XFIXNUM (XCDR (topos))), 1815 : XFIXNUM (XCDR (topos))),
1816 (NILP (topos) 1816 (NILP (topos)
1817 ? (window_body_width (w, 0) 1817 ? (window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS)
1818 - ( 1818 - (
1819#ifdef HAVE_WINDOW_SYSTEM 1819#ifdef HAVE_WINDOW_SYSTEM
1820 FRAME_WINDOW_P (XFRAME (w->frame)) ? 0 : 1820 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)
121{ 121{
122 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target)) 122 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
123 return; 123 return;
124 eassume (source && target);
125 124
126 COPY_INTERVAL_CACHE (source, target); 125 COPY_INTERVAL_CACHE (source, target);
127 set_interval_plist (target, Fcopy_sequence (source->plist)); 126 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,
251 void (*) (INTERVAL, void *), void *); 251 void (*) (INTERVAL, void *), void *);
252extern INTERVAL split_interval_right (INTERVAL, ptrdiff_t) 252extern INTERVAL split_interval_right (INTERVAL, ptrdiff_t)
253 ATTRIBUTE_RETURNS_NONNULL; 253 ATTRIBUTE_RETURNS_NONNULL;
254extern INTERVAL split_interval_left (INTERVAL, ptrdiff_t); 254extern INTERVAL split_interval_left (INTERVAL, ptrdiff_t) ATTRIBUTE_RETURNS_NONNULL;
255extern INTERVAL find_interval (INTERVAL, ptrdiff_t); 255extern INTERVAL find_interval (INTERVAL, ptrdiff_t);
256extern INTERVAL next_interval (INTERVAL); 256extern INTERVAL next_interval (INTERVAL);
257extern INTERVAL previous_interval (INTERVAL); 257extern 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,
364 for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i) 364 for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i)
365 { 365 {
366 Lisp_Object key = HASH_KEY (h, i); 366 Lisp_Object key = HASH_KEY (h, i);
367 if (!EQ (key, Qunbound)) 367 if (!BASE_EQ (key, Qunbound))
368 { 368 {
369 CHECK_STRING (key); 369 CHECK_STRING (key);
370 Lisp_Object ekey = json_encode (key); 370 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;
95 The maybe_quit function checks this. */ 95 The maybe_quit function checks this. */
96volatile bool pending_signals; 96volatile bool pending_signals;
97 97
98enum { KBD_BUFFER_SIZE = 4096 };
99
100KBOARD *initial_kboard; 98KBOARD *initial_kboard;
101KBOARD *current_kboard; 99KBOARD *current_kboard;
102static KBOARD *all_kboards; 100static KBOARD *all_kboards;
@@ -290,14 +288,14 @@ bool input_was_pending;
290 288
291/* Circular buffer for pre-read keyboard input. */ 289/* Circular buffer for pre-read keyboard input. */
292 290
293static union buffered_input_event kbd_buffer[KBD_BUFFER_SIZE]; 291union buffered_input_event kbd_buffer[KBD_BUFFER_SIZE];
294 292
295/* Pointer to next available character in kbd_buffer. 293/* Pointer to next available character in kbd_buffer.
296 If kbd_fetch_ptr == kbd_store_ptr, the buffer is empty. */ 294 If kbd_fetch_ptr == kbd_store_ptr, the buffer is empty. */
297static union buffered_input_event *kbd_fetch_ptr; 295union buffered_input_event *kbd_fetch_ptr;
298 296
299/* Pointer to next place to store character in kbd_buffer. */ 297/* Pointer to next place to store character in kbd_buffer. */
300static union buffered_input_event *kbd_store_ptr; 298union buffered_input_event *kbd_store_ptr;
301 299
302/* The above pair of variables forms a "queue empty" flag. When we 300/* The above pair of variables forms a "queue empty" flag. When we
303 enqueue a non-hook event, we increment kbd_store_ptr. When we 301 enqueue a non-hook event, we increment kbd_store_ptr. When we
@@ -391,14 +389,6 @@ next_kbd_event (union buffered_input_event *ptr)
391 return ptr == kbd_buffer + KBD_BUFFER_SIZE - 1 ? kbd_buffer : ptr + 1; 389 return ptr == kbd_buffer + KBD_BUFFER_SIZE - 1 ? kbd_buffer : ptr + 1;
392} 390}
393 391
394#ifdef HAVE_X11
395static union buffered_input_event *
396prev_kbd_event (union buffered_input_event *ptr)
397{
398 return ptr == kbd_buffer ? kbd_buffer + KBD_BUFFER_SIZE - 1 : ptr - 1;
399}
400#endif
401
402/* Like EVENT_START, but assume EVENT is an event. 392/* Like EVENT_START, but assume EVENT is an event.
403 This pacifies gcc -Wnull-dereference, which might otherwise 393 This pacifies gcc -Wnull-dereference, which might otherwise
404 complain about earlier checks that EVENT is indeed an event. */ 394 complain about earlier checks that EVENT is indeed an event. */
@@ -3530,6 +3520,11 @@ readable_events (int flags)
3530 return 1; 3520 return 1;
3531 } 3521 }
3532 3522
3523#ifdef HAVE_X_WINDOWS
3524 if (x_detect_pending_selection_requests ())
3525 return 1;
3526#endif
3527
3533 if (!(flags & READABLE_EVENTS_IGNORE_SQUEEZABLES) && some_mouse_moved ()) 3528 if (!(flags & READABLE_EVENTS_IGNORE_SQUEEZABLES) && some_mouse_moved ())
3534 return 1; 3529 return 1;
3535 if (single_kboard) 3530 if (single_kboard)
@@ -3701,25 +3696,6 @@ kbd_buffer_store_buffered_event (union buffered_input_event *event,
3701 Vquit_flag = Vthrow_on_input; 3696 Vquit_flag = Vthrow_on_input;
3702} 3697}
3703 3698
3704
3705#ifdef HAVE_X11
3706
3707/* Put a selection input event back in the head of the event queue. */
3708
3709void
3710kbd_buffer_unget_event (struct selection_input_event *event)
3711{
3712 /* Don't let the very last slot in the buffer become full, */
3713 union buffered_input_event *kp = prev_kbd_event (kbd_fetch_ptr);
3714 if (kp != kbd_store_ptr)
3715 {
3716 kp->sie = *event;
3717 kbd_fetch_ptr = kp;
3718 }
3719}
3720
3721#endif
3722
3723/* Limit help event positions to this range, to avoid overflow problems. */ 3699/* Limit help event positions to this range, to avoid overflow problems. */
3724#define INPUT_EVENT_POS_MAX \ 3700#define INPUT_EVENT_POS_MAX \
3725 ((ptrdiff_t) min (PTRDIFF_MAX, min (TYPE_MAXIMUM (Time) / 2, \ 3701 ((ptrdiff_t) min (PTRDIFF_MAX, min (TYPE_MAXIMUM (Time) / 2, \
@@ -3876,6 +3852,11 @@ kbd_buffer_get_event (KBOARD **kbp,
3876 struct timespec *end_time) 3852 struct timespec *end_time)
3877{ 3853{
3878 Lisp_Object obj, str; 3854 Lisp_Object obj, str;
3855#ifdef HAVE_X_WINDOWS
3856 bool had_pending_selection_requests;
3857
3858 had_pending_selection_requests = false;
3859#endif
3879 3860
3880#ifdef subprocesses 3861#ifdef subprocesses
3881 if (kbd_on_hold_p () && kbd_buffer_nr_stored () < KBD_BUFFER_SIZE / 4) 3862 if (kbd_on_hold_p () && kbd_buffer_nr_stored () < KBD_BUFFER_SIZE / 4)
@@ -3928,10 +3909,18 @@ kbd_buffer_get_event (KBOARD **kbp,
3928#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) 3909#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
3929 gobble_input (); 3910 gobble_input ();
3930#endif 3911#endif
3912
3931 if (kbd_fetch_ptr != kbd_store_ptr) 3913 if (kbd_fetch_ptr != kbd_store_ptr)
3932 break; 3914 break;
3933 if (some_mouse_moved ()) 3915 if (some_mouse_moved ())
3934 break; 3916 break;
3917#ifdef HAVE_X_WINDOWS
3918 if (x_detect_pending_selection_requests ())
3919 {
3920 had_pending_selection_requests = true;
3921 break;
3922 }
3923#endif
3935 if (end_time) 3924 if (end_time)
3936 { 3925 {
3937 struct timespec now = current_timespec (); 3926 struct timespec now = current_timespec ();
@@ -3968,6 +3957,16 @@ kbd_buffer_get_event (KBOARD **kbp,
3968 gobble_input (); 3957 gobble_input ();
3969 } 3958 }
3970 3959
3960#ifdef HAVE_X_WINDOWS
3961 /* Handle pending selection requests. This can happen if Emacs
3962 enters a recursive edit inside a nested event loop (probably
3963 because the debugger opened) or someone called
3964 `read-char'. */
3965
3966 if (had_pending_selection_requests)
3967 x_handle_pending_selection_requests ();
3968#endif
3969
3971 if (CONSP (Vunread_command_events)) 3970 if (CONSP (Vunread_command_events))
3972 { 3971 {
3973 Lisp_Object first; 3972 Lisp_Object first;
@@ -4022,6 +4021,11 @@ kbd_buffer_get_event (KBOARD **kbp,
4022 kbd_fetch_ptr = next_kbd_event (event); 4021 kbd_fetch_ptr = next_kbd_event (event);
4023 input_pending = readable_events (0); 4022 input_pending = readable_events (0);
4024 4023
4024 /* This means this event was already handled in
4025 `x_dnd_begin_drag_and_drop'. */
4026 if (event->ie.modifiers < x_dnd_unsupported_event_level)
4027 break;
4028
4025 f = XFRAME (event->ie.frame_or_window); 4029 f = XFRAME (event->ie.frame_or_window);
4026 4030
4027 if (!FRAME_LIVE_P (f)) 4031 if (!FRAME_LIVE_P (f))
@@ -4029,14 +4033,20 @@ kbd_buffer_get_event (KBOARD **kbp,
4029 4033
4030 if (!NILP (Vx_dnd_unsupported_drop_function)) 4034 if (!NILP (Vx_dnd_unsupported_drop_function))
4031 { 4035 {
4032 if (!NILP (call6 (Vx_dnd_unsupported_drop_function, 4036 if (!NILP (call7 (Vx_dnd_unsupported_drop_function,
4033 XCAR (XCDR (event->ie.arg)), event->ie.x, 4037 XCAR (XCDR (event->ie.arg)), event->ie.x,
4034 event->ie.y, XCAR (XCDR (XCDR (event->ie.arg))), 4038 event->ie.y, XCAR (XCDR (XCDR (event->ie.arg))),
4035 make_uint (event->ie.code), 4039 make_uint (event->ie.code),
4036 event->ie.frame_or_window))) 4040 event->ie.frame_or_window,
4041 make_int (event->ie.timestamp))))
4037 break; 4042 break;
4038 } 4043 }
4039 4044
4045 /* `x-dnd-unsupported-drop-function' could have deleted the
4046 event frame. */
4047 if (!FRAME_LIVE_P (f))
4048 break;
4049
4040 x_dnd_do_unsupported_drop (FRAME_DISPLAY_INFO (f), 4050 x_dnd_do_unsupported_drop (FRAME_DISPLAY_INFO (f),
4041 event->ie.frame_or_window, 4051 event->ie.frame_or_window,
4042 XCAR (event->ie.arg), 4052 XCAR (event->ie.arg),
@@ -4049,6 +4059,18 @@ kbd_buffer_get_event (KBOARD **kbp,
4049 } 4059 }
4050#endif 4060#endif
4051 4061
4062 case MONITORS_CHANGED_EVENT:
4063 {
4064 kbd_fetch_ptr = next_kbd_event (event);
4065 input_pending = readable_events (0);
4066
4067 CALLN (Frun_hook_with_args,
4068 Qdisplay_monitors_changed_functions,
4069 event->ie.arg);
4070
4071 break;
4072 }
4073
4052#ifdef HAVE_EXT_MENU_BAR 4074#ifdef HAVE_EXT_MENU_BAR
4053 case MENU_BAR_ACTIVATE_EVENT: 4075 case MENU_BAR_ACTIVATE_EVENT:
4054 { 4076 {
@@ -4324,6 +4346,10 @@ kbd_buffer_get_event (KBOARD **kbp,
4324 ? movement_frame->last_mouse_device 4346 ? movement_frame->last_mouse_device
4325 : virtual_core_pointer_name); 4347 : virtual_core_pointer_name);
4326 } 4348 }
4349#ifdef HAVE_X_WINDOWS
4350 else if (had_pending_selection_requests)
4351 obj = Qnil;
4352#endif
4327 else 4353 else
4328 /* We were promised by the above while loop that there was 4354 /* We were promised by the above while loop that there was
4329 something for us to read! */ 4355 something for us to read! */
@@ -7220,7 +7246,10 @@ lucid_event_type_list_p (Lisp_Object object)
7220 If READABLE_EVENTS_FILTER_EVENTS is set in FLAGS, ignore internal 7246 If READABLE_EVENTS_FILTER_EVENTS is set in FLAGS, ignore internal
7221 events (FOCUS_IN_EVENT). 7247 events (FOCUS_IN_EVENT).
7222 If READABLE_EVENTS_IGNORE_SQUEEZABLES is set in FLAGS, ignore mouse 7248 If READABLE_EVENTS_IGNORE_SQUEEZABLES is set in FLAGS, ignore mouse
7223 movements and toolkit scroll bar thumb drags. */ 7249 movements and toolkit scroll bar thumb drags.
7250
7251 On X, this also returns if the selection event chain is full, since
7252 that's also "keyboard input". */
7224 7253
7225static bool 7254static bool
7226get_input_pending (int flags) 7255get_input_pending (int flags)
@@ -12600,6 +12629,8 @@ See also `pre-command-hook'. */);
12600 DEFSYM (Qtouchscreen_end, "touchscreen-end"); 12629 DEFSYM (Qtouchscreen_end, "touchscreen-end");
12601 DEFSYM (Qtouchscreen_update, "touchscreen-update"); 12630 DEFSYM (Qtouchscreen_update, "touchscreen-update");
12602 DEFSYM (Qpinch, "pinch"); 12631 DEFSYM (Qpinch, "pinch");
12632 DEFSYM (Qdisplay_monitors_changed_functions,
12633 "display-monitors-changed-functions");
12603 12634
12604 DEFSYM (Qcoding, "coding"); 12635 DEFSYM (Qcoding, "coding");
12605 12636
@@ -12840,6 +12871,14 @@ Called with three arguments:
12840- the context (a string which normally goes at the start of the message), 12871- the context (a string which normally goes at the start of the message),
12841- the Lisp function within which the error was signaled. 12872- the Lisp function within which the error was signaled.
12842 12873
12874For instance, to make error messages stand out more in the echo area,
12875you could say something like:
12876
12877 (setq command-error-function
12878 (lambda (data _ _)
12879 (message "%s" (propertize (error-message-string data)
12880 \\='face \\='error))))
12881
12843Also see `set-message-function' (which controls how non-error messages 12882Also see `set-message-function' (which controls how non-error messages
12844are displayed). */); 12883are displayed). */);
12845 Vcommand_error_function = intern ("command-error-default-function"); 12884 Vcommand_error_function = intern ("command-error-default-function");
@@ -12854,11 +12893,12 @@ and tool-bar buttons. */);
12854 12893
12855 DEFVAR_LISP ("select-active-regions", 12894 DEFVAR_LISP ("select-active-regions",
12856 Vselect_active_regions, 12895 Vselect_active_regions,
12857 doc: /* If non-nil, an active region automatically sets the primary selection. 12896 doc: /* If non-nil, any active region automatically sets the primary selection.
12858If the value is `only', only temporarily active regions (usually made 12897This variable only has an effect when Transient Mark mode is enabled.
12859by mouse-dragging or shift-selection) set the window selection.
12860 12898
12861This takes effect only when Transient Mark mode is enabled. */); 12899If the value is `only', only temporarily active regions (usually made
12900by mouse-dragging or shift-selection) set the window system's primary
12901selection. */);
12862 Vselect_active_regions = Qt; 12902 Vselect_active_regions = Qt;
12863 12903
12864 DEFVAR_LISP ("saved-region-selection", 12904 DEFVAR_LISP ("saved-region-selection",
@@ -12943,6 +12983,15 @@ Otherwise, a wheel event will be sent every time the mouse wheel is
12943moved. */); 12983moved. */);
12944 mwheel_coalesce_scroll_events = true; 12984 mwheel_coalesce_scroll_events = true;
12945 12985
12986 DEFVAR_LISP ("display-monitors-changed-functions", Vdisplay_monitors_changed_functions,
12987 doc: /* Abnormal hook run when the monitor configuration changes.
12988This can happen if a monitor is rotated, moved, plugged in or removed
12989from a multi-monitor setup, if the primary monitor changes, or if the
12990resolution of a monitor changes. The hook should accept a single
12991argument, which is the terminal on which the monitor configuration
12992changed. */);
12993 Vdisplay_monitors_changed_functions = Qnil;
12994
12946 pdumper_do_now_and_after_load (syms_of_keyboard_for_pdumper); 12995 pdumper_do_now_and_after_load (syms_of_keyboard_for_pdumper);
12947} 12996}
12948 12997
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
358 MENU_ITEMS_ITEM_LENGTH 358 MENU_ITEMS_ITEM_LENGTH
359}; 359};
360 360
361enum
362 {
363 KBD_BUFFER_SIZE = 4096
364 };
365
361extern void unuse_menu_items (void); 366extern void unuse_menu_items (void);
362 367
363/* This is how to deal with multibyte text if HAVE_MULTILINGUAL_MENU 368/* This is how to deal with multibyte text if HAVE_MULTILINGUAL_MENU
@@ -419,6 +424,10 @@ extern void unuse_menu_items (void);
419 happens. */ 424 happens. */
420extern struct timespec *input_available_clear_time; 425extern struct timespec *input_available_clear_time;
421 426
427extern union buffered_input_event kbd_buffer[KBD_BUFFER_SIZE];
428extern union buffered_input_event *kbd_fetch_ptr;
429extern union buffered_input_event *kbd_store_ptr;
430
422extern bool ignore_mouse_drag_p; 431extern bool ignore_mouse_drag_p;
423 432
424extern Lisp_Object parse_modifiers (Lisp_Object); 433extern Lisp_Object parse_modifiers (Lisp_Object);
@@ -472,9 +481,6 @@ kbd_buffer_store_event_hold (struct input_event *event,
472 kbd_buffer_store_buffered_event ((union buffered_input_event *) event, 481 kbd_buffer_store_buffered_event ((union buffered_input_event *) event,
473 hold_quit); 482 hold_quit);
474} 483}
475#ifdef HAVE_X11
476extern void kbd_buffer_unget_event (struct selection_input_event *);
477#endif
478extern void poll_for_input_1 (void); 484extern void poll_for_input_1 (void);
479extern void show_help_echo (Lisp_Object, Lisp_Object, Lisp_Object, 485extern void show_help_echo (Lisp_Object, Lisp_Object, Lisp_Object,
480 Lisp_Object); 486 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,
395 if (noinherit || NILP (retval)) 395 if (noinherit || NILP (retval))
396 /* If NOINHERIT, stop here, the rest is inherited. */ 396 /* If NOINHERIT, stop here, the rest is inherited. */
397 break; 397 break;
398 else if (!EQ (retval, Qunbound)) 398 else if (!BASE_EQ (retval, Qunbound))
399 { 399 {
400 Lisp_Object parent_entry; 400 Lisp_Object parent_entry;
401 eassert (KEYMAPP (retval)); 401 eassert (KEYMAPP (retval));
@@ -454,7 +454,7 @@ access_keymap_1 (Lisp_Object map, Lisp_Object idx,
454 } 454 }
455 455
456 /* If we found a binding, clean it up and return it. */ 456 /* If we found a binding, clean it up and return it. */
457 if (!EQ (val, Qunbound)) 457 if (!BASE_EQ (val, Qunbound))
458 { 458 {
459 if (EQ (val, Qt)) 459 if (EQ (val, Qt))
460 /* A Qt binding is just like an explicit nil binding 460 /* A Qt binding is just like an explicit nil binding
@@ -466,12 +466,12 @@ access_keymap_1 (Lisp_Object map, Lisp_Object idx,
466 466
467 if (!KEYMAPP (val)) 467 if (!KEYMAPP (val))
468 { 468 {
469 if (NILP (retval) || EQ (retval, Qunbound)) 469 if (NILP (retval) || BASE_EQ (retval, Qunbound))
470 retval = val; 470 retval = val;
471 if (!NILP (val)) 471 if (!NILP (val))
472 break; /* Shadows everything that follows. */ 472 break; /* Shadows everything that follows. */
473 } 473 }
474 else if (NILP (retval) || EQ (retval, Qunbound)) 474 else if (NILP (retval) || BASE_EQ (retval, Qunbound))
475 retval = val; 475 retval = val;
476 else if (CONSP (retval_tail)) 476 else if (CONSP (retval_tail))
477 { 477 {
@@ -487,7 +487,8 @@ access_keymap_1 (Lisp_Object map, Lisp_Object idx,
487 maybe_quit (); 487 maybe_quit ();
488 } 488 }
489 489
490 return EQ (Qunbound, retval) ? get_keyelt (t_binding, autoload) : retval; 490 return BASE_EQ (Qunbound, retval)
491 ? get_keyelt (t_binding, autoload) : retval;
491 } 492 }
492} 493}
493 494
@@ -496,7 +497,7 @@ access_keymap (Lisp_Object map, Lisp_Object idx,
496 bool t_ok, bool noinherit, bool autoload) 497 bool t_ok, bool noinherit, bool autoload)
497{ 498{
498 Lisp_Object val = access_keymap_1 (map, idx, t_ok, noinherit, autoload); 499 Lisp_Object val = access_keymap_1 (map, idx, t_ok, noinherit, autoload);
499 return EQ (val, Qunbound) ? Qnil : val; 500 return BASE_EQ (val, Qunbound) ? Qnil : val;
500} 501}
501 502
502static void 503static void
@@ -1550,7 +1551,7 @@ current_minor_maps (Lisp_Object **modeptr, Lisp_Object **mapptr)
1550 for ( ; CONSP (alist); alist = XCDR (alist)) 1551 for ( ; CONSP (alist); alist = XCDR (alist))
1551 if ((assoc = XCAR (alist), CONSP (assoc)) 1552 if ((assoc = XCAR (alist), CONSP (assoc))
1552 && (var = XCAR (assoc), SYMBOLP (var)) 1553 && (var = XCAR (assoc), SYMBOLP (var))
1553 && (val = find_symbol_value (var), !EQ (val, Qunbound)) 1554 && (val = find_symbol_value (var), !BASE_EQ (val, Qunbound))
1554 && !NILP (val)) 1555 && !NILP (val))
1555 { 1556 {
1556 Lisp_Object temp; 1557 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;
621extern void char_table_set (Lisp_Object, int, Lisp_Object); 621extern void char_table_set (Lisp_Object, int, Lisp_Object);
622 622
623/* Defined in data.c. */ 623/* Defined in data.c. */
624extern bool symbols_with_pos_enabled;
625extern AVOID args_out_of_range_3 (Lisp_Object, Lisp_Object, Lisp_Object); 624extern AVOID args_out_of_range_3 (Lisp_Object, Lisp_Object, Lisp_Object);
626extern AVOID wrong_type_argument (Lisp_Object, Lisp_Object); 625extern AVOID wrong_type_argument (Lisp_Object, Lisp_Object);
627extern Lisp_Object default_value (Lisp_Object symbol); 626extern Lisp_Object default_value (Lisp_Object symbol);
@@ -2097,19 +2096,17 @@ XSUB_CHAR_TABLE (Lisp_Object a)
2097INLINE Lisp_Object 2096INLINE Lisp_Object
2098CHAR_TABLE_REF_ASCII (Lisp_Object ct, ptrdiff_t idx) 2097CHAR_TABLE_REF_ASCII (Lisp_Object ct, ptrdiff_t idx)
2099{ 2098{
2100 struct Lisp_Char_Table *tbl = NULL; 2099 for (struct Lisp_Char_Table *tbl = XCHAR_TABLE (ct); ;
2101 Lisp_Object val; 2100 tbl = XCHAR_TABLE (tbl->parent))
2102 do
2103 { 2101 {
2104 tbl = tbl ? XCHAR_TABLE (tbl->parent) : XCHAR_TABLE (ct); 2102 Lisp_Object val = (SUB_CHAR_TABLE_P (tbl->ascii)
2105 val = (! SUB_CHAR_TABLE_P (tbl->ascii) ? tbl->ascii 2103 ? XSUB_CHAR_TABLE (tbl->ascii)->contents[idx]
2106 : XSUB_CHAR_TABLE (tbl->ascii)->contents[idx]); 2104 : tbl->ascii);
2107 if (NILP (val)) 2105 if (NILP (val))
2108 val = tbl->defalt; 2106 val = tbl->defalt;
2107 if (!NILP (val) || NILP (tbl->parent))
2108 return val;
2109 } 2109 }
2110 while (NILP (val) && ! NILP (tbl->parent));
2111
2112 return val;
2113} 2110}
2114 2111
2115/* Almost equivalent to Faref (CT, IDX) with optimization for ASCII 2112/* Almost equivalent to Faref (CT, IDX) with optimization for ASCII
@@ -3639,6 +3636,10 @@ struct handler
3639 struct bc_frame *act_rec; 3636 struct bc_frame *act_rec;
3640 int poll_suppress_count; 3637 int poll_suppress_count;
3641 int interrupt_input_blocked; 3638 int interrupt_input_blocked;
3639
3640#ifdef HAVE_X_WINDOWS
3641 int x_error_handler_depth;
3642#endif
3642}; 3643};
3643 3644
3644extern Lisp_Object memory_signal_data; 3645extern Lisp_Object memory_signal_data;
@@ -4492,6 +4493,7 @@ extern void dir_warning (const char *, Lisp_Object);
4492extern void init_obarray_once (void); 4493extern void init_obarray_once (void);
4493extern void init_lread (void); 4494extern void init_lread (void);
4494extern void syms_of_lread (void); 4495extern void syms_of_lread (void);
4496extern void mark_lread (void);
4495 4497
4496INLINE Lisp_Object 4498INLINE Lisp_Object
4497intern (const char *str) 4499intern (const char *str)
@@ -5098,9 +5100,7 @@ extern void syms_of_w32cygwinx (void);
5098extern Lisp_Object Vface_alternative_font_family_alist; 5100extern Lisp_Object Vface_alternative_font_family_alist;
5099extern Lisp_Object Vface_alternative_font_registry_alist; 5101extern Lisp_Object Vface_alternative_font_registry_alist;
5100extern void syms_of_xfaces (void); 5102extern void syms_of_xfaces (void);
5101#ifdef HAVE_PDUMPER
5102extern void init_xfaces (void); 5103extern void init_xfaces (void);
5103#endif
5104 5104
5105#ifdef HAVE_X_WINDOWS 5105#ifdef HAVE_X_WINDOWS
5106/* Defined in xfns.c. */ 5106/* Defined in xfns.c. */
@@ -5503,7 +5503,7 @@ struct for_each_tail_internal
5503 intended for use only by the above macros. 5503 intended for use only by the above macros.
5504 5504
5505 Use Brent’s teleporting tortoise-hare algorithm. See: 5505 Use Brent’s teleporting tortoise-hare algorithm. See:
5506 Brent RP. BIT. 1980;20(2):176-84. doi:10.1007/BF01933190 5506 Brent RP. BIT. 1980;20(2):176-184. doi:10.1007/BF01933190
5507 https://maths-people.anu.edu.au/~brent/pd/rpb051i.pdf 5507 https://maths-people.anu.edu.au/~brent/pd/rpb051i.pdf
5508 5508
5509 This macro uses maybe_quit because of an excess of caution. The 5509 This macro uses maybe_quit because of an excess of caution. The
@@ -5520,7 +5520,7 @@ struct for_each_tail_internal
5520 || ((check_quit) ? maybe_quit () : (void) 0, 0 < --li.n) \ 5520 || ((check_quit) ? maybe_quit () : (void) 0, 0 < --li.n) \
5521 || (li.q = li.n = li.max <<= 1, li.n >>= USHRT_WIDTH, \ 5521 || (li.q = li.n = li.max <<= 1, li.n >>= USHRT_WIDTH, \
5522 li.tortoise = (tail), false)) \ 5522 li.tortoise = (tail), false)) \
5523 && EQ (tail, li.tortoise)) \ 5523 && BASE_EQ (tail, li.tortoise)) \
5524 ? (cycle) : (void) 0)) 5524 ? (cycle) : (void) 0))
5525 5525
5526/* Do a `for' loop over alist values. */ 5526/* 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
656static Lisp_Object read_internal_start (Lisp_Object, Lisp_Object, 656static Lisp_Object read_internal_start (Lisp_Object, Lisp_Object,
657 Lisp_Object, bool); 657 Lisp_Object, bool);
658static Lisp_Object read0 (Lisp_Object, bool); 658static Lisp_Object read0 (Lisp_Object, bool);
659static Lisp_Object read1 (Lisp_Object, int *, bool, bool);
660
661static Lisp_Object read_list (bool, Lisp_Object, bool);
662static Lisp_Object read_vector (Lisp_Object, bool, bool);
663 659
664static Lisp_Object substitute_object_recurse (struct subst *, Lisp_Object); 660static Lisp_Object substitute_object_recurse (struct subst *, Lisp_Object);
665static void substitute_in_interval (INTERVAL, void *); 661static void substitute_in_interval (INTERVAL, void *);
@@ -940,7 +936,7 @@ lisp_file_lexically_bound_p (Lisp_Object readcharfun)
940 ch = READCHAR; 936 ch = READCHAR;
941 if (ch == '\n') ch = READCHAR; 937 if (ch == '\n') ch = READCHAR;
942 /* It is OK to leave the position after a #! line, since 938 /* It is OK to leave the position after a #! line, since
943 that is what read1 does. */ 939 that is what read0 does. */
944 } 940 }
945 941
946 if (ch != ';') 942 if (ch != ';')
@@ -1248,10 +1244,9 @@ Return t if the file exists and loads successfully. */)
1248 CHECK_STRING (file); 1244 CHECK_STRING (file);
1249 1245
1250 /* If file name is magic, call the handler. */ 1246 /* If file name is magic, call the handler. */
1251 /* This shouldn't be necessary any more now that `openp' handles it right. 1247 handler = Ffind_file_name_handler (file, Qload);
1252 handler = Ffind_file_name_handler (file, Qload); 1248 if (!NILP (handler))
1253 if (!NILP (handler)) 1249 return call5 (handler, Qload, file, noerror, nomessage, nosuffix);
1254 return call5 (handler, Qload, file, noerror, nomessage, nosuffix); */
1255 1250
1256 /* The presence of this call is the result of a historical accident: 1251 /* The presence of this call is the result of a historical accident:
1257 it used to be in every file-operation and when it got removed 1252 it used to be in every file-operation and when it got removed
@@ -2221,7 +2216,7 @@ readevalloop (Lisp_Object readcharfun,
2221 lexical environment, otherwise, turn off lexical binding. */ 2216 lexical environment, otherwise, turn off lexical binding. */
2222 lex_bound = find_symbol_value (Qlexical_binding); 2217 lex_bound = find_symbol_value (Qlexical_binding);
2223 specbind (Qinternal_interpreter_environment, 2218 specbind (Qinternal_interpreter_environment,
2224 (NILP (lex_bound) || EQ (lex_bound, Qunbound) 2219 (NILP (lex_bound) || BASE_EQ (lex_bound, Qunbound)
2225 ? Qnil : list1 (Qt))); 2220 ? Qnil : list1 (Qt)));
2226 specbind (Qmacroexp__dynvars, Vmacroexp__dynvars); 2221 specbind (Qmacroexp__dynvars, Vmacroexp__dynvars);
2227 2222
@@ -2286,6 +2281,7 @@ readevalloop (Lisp_Object readcharfun,
2286 if (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r' 2281 if (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r'
2287 || c == NO_BREAK_SPACE) 2282 || c == NO_BREAK_SPACE)
2288 goto read_next; 2283 goto read_next;
2284 UNREAD (c);
2289 2285
2290 if (! HASH_TABLE_P (read_objects_map) 2286 if (! HASH_TABLE_P (read_objects_map)
2291 || XHASH_TABLE (read_objects_map)->count) 2287 || XHASH_TABLE (read_objects_map)->count)
@@ -2300,12 +2296,9 @@ readevalloop (Lisp_Object readcharfun,
2300 DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD, 2296 DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
2301 Qnil, false); 2297 Qnil, false);
2302 if (!NILP (Vpurify_flag) && c == '(') 2298 if (!NILP (Vpurify_flag) && c == '(')
2303 { 2299 val = read0 (readcharfun, false);
2304 val = read_list (0, readcharfun, false);
2305 }
2306 else 2300 else
2307 { 2301 {
2308 UNREAD (c);
2309 if (!NILP (readfun)) 2302 if (!NILP (readfun))
2310 { 2303 {
2311 val = call1 (readfun, readcharfun); 2304 val = call1 (readfun, readcharfun);
@@ -2349,7 +2342,7 @@ readevalloop (Lisp_Object readcharfun,
2349 { 2342 {
2350 Vvalues = Fcons (val, Vvalues); 2343 Vvalues = Fcons (val, Vvalues);
2351 if (EQ (Vstandard_output, Qt)) 2344 if (EQ (Vstandard_output, Qt))
2352 Fprin1 (val, Qnil); 2345 Fprin1 (val, Qnil, Qnil);
2353 else 2346 else
2354 Fprint (val, Qnil); 2347 Fprint (val, Qnil);
2355 } 2348 }
@@ -2582,24 +2575,6 @@ read_internal_start (Lisp_Object stream, Lisp_Object start, Lisp_Object end,
2582 return retval; 2575 return retval;
2583} 2576}
2584 2577
2585
2586/* Use this for recursive reads, in contexts where internal tokens
2587 are not allowed. */
2588
2589static Lisp_Object
2590read0 (Lisp_Object readcharfun, bool locate_syms)
2591{
2592 register Lisp_Object val;
2593 int c;
2594
2595 val = read1 (readcharfun, &c, 0, locate_syms);
2596 if (!c)
2597 return val;
2598
2599 invalid_syntax_lisp (Fmake_string (make_fixnum (1), make_fixnum (c), Qnil),
2600 readcharfun);
2601}
2602
2603/* Grow a read buffer BUF that contains OFFSET useful bytes of data, 2578/* Grow a read buffer BUF that contains OFFSET useful bytes of data,
2604 by at least MAX_MULTIBYTE_LENGTH bytes. Update *BUF_ADDR and 2579 by at least MAX_MULTIBYTE_LENGTH bytes. Update *BUF_ADDR and
2605 *BUF_SIZE accordingly; 0 <= OFFSET <= *BUF_SIZE. If *BUF_ADDR is 2580 *BUF_SIZE accordingly; 0 <= OFFSET <= *BUF_SIZE. If *BUF_ADDR is
@@ -2658,7 +2633,7 @@ enum { UNICODE_CHARACTER_NAME_LENGTH_BOUND = 200 };
2658 If the escape sequence forces unibyte, return eight-bit char. */ 2633 If the escape sequence forces unibyte, return eight-bit char. */
2659 2634
2660static int 2635static int
2661read_escape (Lisp_Object readcharfun, bool stringp) 2636read_escape (Lisp_Object readcharfun)
2662{ 2637{
2663 int c = READCHAR; 2638 int c = READCHAR;
2664 /* \u allows up to four hex digits, \U up to eight. Default to the 2639 /* \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)
2688 return '\t'; 2663 return '\t';
2689 case 'v': 2664 case 'v':
2690 return '\v'; 2665 return '\v';
2666
2691 case '\n': 2667 case '\n':
2692 return -1; 2668 /* ?\LF is an error; it's probably a user mistake. */
2693 case ' ': 2669 error ("Invalid escape character syntax");
2694 if (stringp)
2695 return -1;
2696 return ' ';
2697 2670
2698 case 'M': 2671 case 'M':
2699 c = READCHAR; 2672 c = READCHAR;
@@ -2701,7 +2674,7 @@ read_escape (Lisp_Object readcharfun, bool stringp)
2701 error ("Invalid escape character syntax"); 2674 error ("Invalid escape character syntax");
2702 c = READCHAR; 2675 c = READCHAR;
2703 if (c == '\\') 2676 if (c == '\\')
2704 c = read_escape (readcharfun, 0); 2677 c = read_escape (readcharfun);
2705 return c | meta_modifier; 2678 return c | meta_modifier;
2706 2679
2707 case 'S': 2680 case 'S':
@@ -2710,7 +2683,7 @@ read_escape (Lisp_Object readcharfun, bool stringp)
2710 error ("Invalid escape character syntax"); 2683 error ("Invalid escape character syntax");
2711 c = READCHAR; 2684 c = READCHAR;
2712 if (c == '\\') 2685 if (c == '\\')
2713 c = read_escape (readcharfun, 0); 2686 c = read_escape (readcharfun);
2714 return c | shift_modifier; 2687 return c | shift_modifier;
2715 2688
2716 case 'H': 2689 case 'H':
@@ -2719,7 +2692,7 @@ read_escape (Lisp_Object readcharfun, bool stringp)
2719 error ("Invalid escape character syntax"); 2692 error ("Invalid escape character syntax");
2720 c = READCHAR; 2693 c = READCHAR;
2721 if (c == '\\') 2694 if (c == '\\')
2722 c = read_escape (readcharfun, 0); 2695 c = read_escape (readcharfun);
2723 return c | hyper_modifier; 2696 return c | hyper_modifier;
2724 2697
2725 case 'A': 2698 case 'A':
@@ -2728,19 +2701,19 @@ read_escape (Lisp_Object readcharfun, bool stringp)
2728 error ("Invalid escape character syntax"); 2701 error ("Invalid escape character syntax");
2729 c = READCHAR; 2702 c = READCHAR;
2730 if (c == '\\') 2703 if (c == '\\')
2731 c = read_escape (readcharfun, 0); 2704 c = read_escape (readcharfun);
2732 return c | alt_modifier; 2705 return c | alt_modifier;
2733 2706
2734 case 's': 2707 case 's':
2735 c = READCHAR; 2708 c = READCHAR;
2736 if (stringp || c != '-') 2709 if (c != '-')
2737 { 2710 {
2738 UNREAD (c); 2711 UNREAD (c);
2739 return ' '; 2712 return ' ';
2740 } 2713 }
2741 c = READCHAR; 2714 c = READCHAR;
2742 if (c == '\\') 2715 if (c == '\\')
2743 c = read_escape (readcharfun, 0); 2716 c = read_escape (readcharfun);
2744 return c | super_modifier; 2717 return c | super_modifier;
2745 2718
2746 case 'C': 2719 case 'C':
@@ -2751,7 +2724,7 @@ read_escape (Lisp_Object readcharfun, bool stringp)
2751 case '^': 2724 case '^':
2752 c = READCHAR; 2725 c = READCHAR;
2753 if (c == '\\') 2726 if (c == '\\')
2754 c = read_escape (readcharfun, 0); 2727 c = read_escape (readcharfun);
2755 if ((c & ~CHAR_MODIFIER_MASK) == '?') 2728 if ((c & ~CHAR_MODIFIER_MASK) == '?')
2756 return 0177 | (c & CHAR_MODIFIER_MASK); 2729 return 0177 | (c & CHAR_MODIFIER_MASK);
2757 else if (! ASCII_CHAR_P ((c & ~CHAR_MODIFIER_MASK))) 2730 else if (! ASCII_CHAR_P ((c & ~CHAR_MODIFIER_MASK)))
@@ -2902,8 +2875,8 @@ read_escape (Lisp_Object readcharfun, bool stringp)
2902 invalid_syntax ("Empty character name", readcharfun); 2875 invalid_syntax ("Empty character name", readcharfun);
2903 name[length] = '\0'; 2876 name[length] = '\0';
2904 2877
2905 /* character_name_to_code can invoke read1, recursively. 2878 /* character_name_to_code can invoke read0, recursively.
2906 This is why read1's buffer is not static. */ 2879 This is why read0's buffer is not static. */
2907 return character_name_to_code (name, length, readcharfun); 2880 return character_name_to_code (name, length, readcharfun);
2908 } 2881 }
2909 2882
@@ -2932,20 +2905,17 @@ digit_to_number (int character, int base)
2932 return digit < base ? digit : -1; 2905 return digit < base ? digit : -1;
2933} 2906}
2934 2907
2935static char const invalid_radix_integer_format[] = "integer, radix %"pI"d"; 2908/* Size of the fixed-size buffer used during reading.
2936 2909 It should be at least big enough for `invalid_radix_integer' but
2937/* Small, as read1 is recursive (Bug#31995). But big enough to hold 2910 can usefully be much bigger than that. */
2938 the invalid_radix_integer string. */ 2911enum { stackbufsize = 1024 };
2939enum { stackbufsize = max (64,
2940 (sizeof invalid_radix_integer_format
2941 - sizeof "%"pI"d"
2942 + INT_STRLEN_BOUND (EMACS_INT) + 1)) };
2943 2912
2944static void 2913static void
2945invalid_radix_integer (EMACS_INT radix, char stackbuf[VLA_ELEMS (stackbufsize)], 2914invalid_radix_integer (EMACS_INT radix, char stackbuf[VLA_ELEMS (stackbufsize)],
2946 Lisp_Object readcharfun) 2915 Lisp_Object readcharfun)
2947{ 2916{
2948 sprintf (stackbuf, invalid_radix_integer_format, radix); 2917 int n = snprintf (stackbuf, stackbufsize, "integer, radix %"pI"d", radix);
2918 eassert (n < stackbufsize);
2949 invalid_syntax (stackbuf, readcharfun); 2919 invalid_syntax (stackbuf, readcharfun);
2950} 2920}
2951 2921
@@ -3011,780 +2981,1110 @@ read_integer (Lisp_Object readcharfun, int radix,
3011 *p = '\0'; 2981 *p = '\0';
3012 return unbind_to (count, string_to_number (read_buffer, radix, NULL)); 2982 return unbind_to (count, string_to_number (read_buffer, radix, NULL));
3013} 2983}
2984
3014 2985
3015/* If the next token is ')' or ']' or '.', we store that character 2986/* Read a character literal (preceded by `?'). */
3016 in *PCH and the return value is not interesting. Else, we store
3017 zero in *PCH and we read and return one lisp object.
3018
3019 FIRST_IN_LIST is true if this is the first element of a list.
3020 LOCATE_SYMS true means read symbol occurrences as symbols with
3021 position. */
3022
3023static Lisp_Object 2987static Lisp_Object
3024read1 (Lisp_Object readcharfun, int *pch, bool first_in_list, bool locate_syms) 2988read_char_literal (Lisp_Object readcharfun)
3025{ 2989{
3026 int c; 2990 int ch = READCHAR;
3027 bool uninterned_symbol = false; 2991 if (ch < 0)
3028 bool skip_shorthand = false; 2992 end_of_file_error ();
3029 bool multibyte;
3030 char stackbuf[stackbufsize];
3031 current_thread->stack_top = stackbuf;
3032 2993
3033 *pch = 0; 2994 /* Accept `single space' syntax like (list ? x) where the
2995 whitespace character is SPC or TAB.
2996 Other literal whitespace like NL, CR, and FF are not accepted,
2997 as there are well-established escape sequences for these. */
2998 if (ch == ' ' || ch == '\t')
2999 return make_fixnum (ch);
3034 3000
3035 retry: 3001 if ( ch == '(' || ch == ')' || ch == '[' || ch == ']'
3002 || ch == '"' || ch == ';')
3003 {
3004 CHECK_LIST (Vlread_unescaped_character_literals);
3005 Lisp_Object char_obj = make_fixed_natnum (ch);
3006 if (NILP (Fmemq (char_obj, Vlread_unescaped_character_literals)))
3007 Vlread_unescaped_character_literals =
3008 Fcons (char_obj, Vlread_unescaped_character_literals);
3009 }
3036 3010
3037 c = READCHAR_REPORT_MULTIBYTE (&multibyte); 3011 if (ch == '\\')
3038 if (c < 0) 3012 ch = read_escape (readcharfun);
3039 end_of_file_error ();
3040 3013
3041 switch (c) 3014 int modifiers = ch & CHAR_MODIFIER_MASK;
3042 { 3015 ch &= ~CHAR_MODIFIER_MASK;
3043 case '(': 3016 if (CHAR_BYTE8_P (ch))
3044 return read_list (0, readcharfun, locate_syms); 3017 ch = CHAR_TO_BYTE8 (ch);
3018 ch |= modifiers;
3045 3019
3046 case '[': 3020 int nch = READCHAR;
3047 return read_vector (readcharfun, 0, locate_syms); 3021 UNREAD (nch);
3022 if (nch <= 32
3023 || nch == '"' || nch == '\'' || nch == ';' || nch == '('
3024 || nch == ')' || nch == '[' || nch == ']' || nch == '#'
3025 || nch == '?' || nch == '`' || nch == ',' || nch == '.')
3026 return make_fixnum (ch);
3048 3027
3049 case ')': 3028 invalid_syntax ("?", readcharfun);
3050 case ']': 3029}
3051 {
3052 *pch = c;
3053 return Qnil;
3054 }
3055 3030
3056 case '#': 3031/* Read a string literal (preceded by '"'). */
3057 c = READCHAR; 3032static Lisp_Object
3058 if (c == 's') 3033read_string_literal (char stackbuf[VLA_ELEMS (stackbufsize)],
3034 Lisp_Object readcharfun)
3035{
3036 char *read_buffer = stackbuf;
3037 ptrdiff_t read_buffer_size = stackbufsize;
3038 specpdl_ref count = SPECPDL_INDEX ();
3039 char *heapbuf = NULL;
3040 char *p = read_buffer;
3041 char *end = read_buffer + read_buffer_size;
3042 /* True if we saw an escape sequence specifying
3043 a multibyte character. */
3044 bool force_multibyte = false;
3045 /* True if we saw an escape sequence specifying
3046 a single-byte character. */
3047 bool force_singlebyte = false;
3048 bool cancel = false;
3049 ptrdiff_t nchars = 0;
3050
3051 int ch;
3052 while ((ch = READCHAR) >= 0 && ch != '\"')
3053 {
3054 if (end - p < MAX_MULTIBYTE_LENGTH)
3059 { 3055 {
3060 c = READCHAR; 3056 ptrdiff_t offset = p - read_buffer;
3061 if (c == '(') 3057 read_buffer = grow_read_buffer (read_buffer, offset,
3058 &heapbuf, &read_buffer_size,
3059 count);
3060 p = read_buffer + offset;
3061 end = read_buffer + read_buffer_size;
3062 }
3063
3064 if (ch == '\\')
3065 {
3066 /* First apply string-specific escape rules: */
3067 ch = READCHAR;
3068 switch (ch)
3062 { 3069 {
3063 /* Accept extended format for hash tables (extensible to 3070 case 's':
3064 other types), e.g. 3071 /* `\s' is always a space in strings. */
3065 #s(hash-table size 2 test equal data (k1 v1 k2 v2)) */ 3072 ch = ' ';
3066 Lisp_Object tmp = read_list (0, readcharfun, false); 3073 break;
3067 Lisp_Object head = CAR_SAFE (tmp); 3074 case ' ':
3068 Lisp_Object data = Qnil; 3075 case '\n':
3069 Lisp_Object val = Qnil; 3076 /* `\SPC' and `\LF' generate no characters at all. */
3070 /* The size is 2 * number of allowed keywords to 3077 if (p == read_buffer)
3071 make-hash-table. */ 3078 cancel = true;
3072 Lisp_Object params[12]; 3079 continue;
3073 Lisp_Object ht; 3080 default:
3074 Lisp_Object key = Qnil; 3081 UNREAD (ch);
3075 int param_count = 0; 3082 ch = read_escape (readcharfun);
3076 3083 break;
3077 if (!EQ (head, Qhash_table)) 3084 }
3085
3086 int modifiers = ch & CHAR_MODIFIER_MASK;
3087 ch &= ~CHAR_MODIFIER_MASK;
3088
3089 if (CHAR_BYTE8_P (ch))
3090 force_singlebyte = true;
3091 else if (! ASCII_CHAR_P (ch))
3092 force_multibyte = true;
3093 else /* I.e. ASCII_CHAR_P (ch). */
3094 {
3095 /* Allow `\C-SPC' and `\^SPC'. This is done here because
3096 the literals ?\C-SPC and ?\^SPC (rather inconsistently)
3097 yield (' ' | CHAR_CTL); see bug#55738. */
3098 if (modifiers == CHAR_CTL && ch == ' ')
3099 {
3100 ch = 0;
3101 modifiers = 0;
3102 }
3103 if (modifiers & CHAR_SHIFT)
3078 { 3104 {
3079 ptrdiff_t size = XFIXNUM (Flength (tmp)); 3105 /* Shift modifier is valid only with [A-Za-z]. */
3080 Lisp_Object record = Fmake_record (CAR_SAFE (tmp), 3106 if (ch >= 'A' && ch <= 'Z')
3081 make_fixnum (size - 1), 3107 modifiers &= ~CHAR_SHIFT;
3082 Qnil); 3108 else if (ch >= 'a' && ch <= 'z')
3083 for (int i = 1; i < size; i++)
3084 { 3109 {
3085 tmp = Fcdr (tmp); 3110 ch -= ('a' - 'A');
3086 ASET (record, i, Fcar (tmp)); 3111 modifiers &= ~CHAR_SHIFT;
3087 } 3112 }
3088 return record;
3089 } 3113 }
3090 3114
3091 tmp = CDR_SAFE (tmp); 3115 if (modifiers & CHAR_META)
3116 {
3117 /* Move the meta bit to the right place for a
3118 string. */
3119 modifiers &= ~CHAR_META;
3120 ch = BYTE8_TO_CHAR (ch | 0x80);
3121 force_singlebyte = true;
3122 }
3123 }
3092 3124
3093 /* This is repetitive but fast and simple. */ 3125 /* Any modifiers remaining are invalid. */
3094 params[param_count] = QCsize; 3126 if (modifiers)
3095 params[param_count + 1] = Fplist_get (tmp, Qsize); 3127 invalid_syntax ("Invalid modifier in string", readcharfun);
3096 if (!NILP (params[param_count + 1])) 3128 p += CHAR_STRING (ch, (unsigned char *) p);
3097 param_count += 2; 3129 }
3130 else
3131 {
3132 p += CHAR_STRING (ch, (unsigned char *) p);
3133 if (CHAR_BYTE8_P (ch))
3134 force_singlebyte = true;
3135 else if (! ASCII_CHAR_P (ch))
3136 force_multibyte = true;
3137 }
3138 nchars++;
3139 }
3098 3140
3099 params[param_count] = QCtest; 3141 if (ch < 0)
3100 params[param_count + 1] = Fplist_get (tmp, Qtest); 3142 end_of_file_error ();
3101 if (!NILP (params[param_count + 1]))
3102 param_count += 2;
3103 3143
3104 params[param_count] = QCweakness; 3144 /* If purifying, and string starts with \ newline,
3105 params[param_count + 1] = Fplist_get (tmp, Qweakness); 3145 return zero instead. This is for doc strings
3106 if (!NILP (params[param_count + 1])) 3146 that we are really going to find in etc/DOC.nn.nn. */
3107 param_count += 2; 3147 if (!NILP (Vpurify_flag) && NILP (Vdoc_file_name) && cancel)
3148 {
3149 unbind_to (count, Qnil);
3150 return make_fixnum (0);
3151 }
3108 3152
3109 params[param_count] = QCrehash_size; 3153 if (!force_multibyte && force_singlebyte)
3110 params[param_count + 1] = Fplist_get (tmp, Qrehash_size); 3154 {
3111 if (!NILP (params[param_count + 1])) 3155 /* READ_BUFFER contains raw 8-bit bytes and no multibyte
3112 param_count += 2; 3156 forms. Convert it to unibyte. */
3157 nchars = str_as_unibyte ((unsigned char *) read_buffer,
3158 p - read_buffer);
3159 p = read_buffer + nchars;
3160 }
3113 3161
3114 params[param_count] = QCrehash_threshold; 3162 Lisp_Object obj = make_specified_string (read_buffer, nchars, p - read_buffer,
3115 params[param_count + 1] = Fplist_get (tmp, Qrehash_threshold); 3163 (force_multibyte
3116 if (!NILP (params[param_count + 1])) 3164 || (p - read_buffer != nchars)));
3117 param_count += 2; 3165 return unbind_to (count, obj);
3166}
3118 3167
3119 params[param_count] = QCpurecopy; 3168/* Make a hash table from the constructor plist. */
3120 params[param_count + 1] = Fplist_get (tmp, Qpurecopy); 3169static Lisp_Object
3121 if (!NILP (params[param_count + 1])) 3170hash_table_from_plist (Lisp_Object plist)
3122 param_count += 2; 3171{
3172 Lisp_Object params[12];
3173 Lisp_Object *par = params;
3174
3175 /* This is repetitive but fast and simple. */
3176#define ADDPARAM(name) \
3177 do { \
3178 Lisp_Object val = Fplist_get (plist, Q ## name); \
3179 if (!NILP (val)) \
3180 { \
3181 *par++ = QC ## name; \
3182 *par++ = val; \
3183 } \
3184 } while (0)
3185
3186 ADDPARAM (size);
3187 ADDPARAM (test);
3188 ADDPARAM (weakness);
3189 ADDPARAM (rehash_size);
3190 ADDPARAM (rehash_threshold);
3191 ADDPARAM (purecopy);
3192
3193 Lisp_Object data = Fplist_get (plist, Qdata);
3194
3195 /* Now use params to make a new hash table and fill it. */
3196 Lisp_Object ht = Fmake_hash_table (par - params, params);
3197
3198 Lisp_Object last = data;
3199 FOR_EACH_TAIL_SAFE (data)
3200 {
3201 Lisp_Object key = XCAR (data);
3202 data = XCDR (data);
3203 if (!CONSP (data))
3204 break;
3205 Lisp_Object val = XCAR (data);
3206 last = XCDR (data);
3207 Fputhash (key, val, ht);
3208 }
3209 if (!NILP (last))
3210 error ("Hash table data is not a list of even length");
3123 3211
3124 /* This is the hash table data. */ 3212 return ht;
3125 data = Fplist_get (tmp, Qdata); 3213}
3126 3214
3127 /* Now use params to make a new hash table and fill it. */ 3215static Lisp_Object
3128 ht = Fmake_hash_table (param_count, params); 3216record_from_list (Lisp_Object elems)
3217{
3218 ptrdiff_t size = list_length (elems);
3219 Lisp_Object obj = Fmake_record (XCAR (elems),
3220 make_fixnum (size - 1),
3221 Qnil);
3222 Lisp_Object tl = XCDR (elems);
3223 for (int i = 1; i < size; i++)
3224 {
3225 ASET (obj, i, XCAR (tl));
3226 tl = XCDR (tl);
3227 }
3228 return obj;
3229}
3129 3230
3130 Lisp_Object last = data; 3231/* Turn a reversed list into a vector. */
3131 FOR_EACH_TAIL_SAFE (data) 3232static Lisp_Object
3132 { 3233vector_from_rev_list (Lisp_Object elems)
3133 key = XCAR (data); 3234{
3134 data = XCDR (data); 3235 ptrdiff_t size = list_length (elems);
3135 if (!CONSP (data)) 3236 Lisp_Object obj = make_nil_vector (size);
3136 break; 3237 Lisp_Object *vec = XVECTOR (obj)->contents;
3137 val = XCAR (data); 3238 for (ptrdiff_t i = size - 1; i >= 0; i--)
3138 last = XCDR (data); 3239 {
3139 Fputhash (key, val, ht); 3240 vec[i] = XCAR (elems);
3140 } 3241 Lisp_Object next = XCDR (elems);
3141 if (!NILP (last)) 3242 free_cons (XCONS (elems));
3142 error ("Hash table data is not a list of even length"); 3243 elems = next;
3244 }
3245 return obj;
3246}
3143 3247
3144 return ht; 3248static Lisp_Object
3145 } 3249bytecode_from_rev_list (Lisp_Object elems, Lisp_Object readcharfun)
3146 UNREAD (c); 3250{
3147 invalid_syntax ("#", readcharfun); 3251 Lisp_Object obj = vector_from_rev_list (elems);
3148 } 3252 Lisp_Object *vec = XVECTOR (obj)->contents;
3149 if (c == '^') 3253 ptrdiff_t size = ASIZE (obj);
3150 { 3254
3151 c = READCHAR; 3255 if (!(size >= COMPILED_STACK_DEPTH + 1 && size <= COMPILED_INTERACTIVE + 1
3152 if (c == '[') 3256 && (FIXNUMP (vec[COMPILED_ARGLIST])
3153 { 3257 || CONSP (vec[COMPILED_ARGLIST])
3154 Lisp_Object tmp; 3258 || NILP (vec[COMPILED_ARGLIST]))
3155 tmp = read_vector (readcharfun, 0, false); 3259 && FIXNATP (vec[COMPILED_STACK_DEPTH])))
3156 if (ASIZE (tmp) < CHAR_TABLE_STANDARD_SLOTS) 3260 invalid_syntax ("Invalid byte-code object", readcharfun);
3157 error ("Invalid size char-table"); 3261
3158 XSETPVECTYPE (XVECTOR (tmp), PVEC_CHAR_TABLE); 3262 if (load_force_doc_strings
3159 return tmp; 3263 && NILP (vec[COMPILED_CONSTANTS])
3160 } 3264 && STRINGP (vec[COMPILED_BYTECODE]))
3161 else if (c == '^') 3265 {
3162 { 3266 /* Lazily-loaded bytecode is represented by the constant slot being nil
3163 c = READCHAR; 3267 and the bytecode slot a (lazily loaded) string containing the
3164 if (c == '[') 3268 print representation of (BYTECODE . CONSTANTS). Unpack the
3165 { 3269 pieces by coerceing the string to unibyte and reading the result. */
3166 /* Sub char-table can't be read as a regular 3270 Lisp_Object enc = vec[COMPILED_BYTECODE];
3167 vector because of a two C integer fields. */ 3271 Lisp_Object pair = Fread (Fcons (enc, readcharfun));
3168 Lisp_Object tbl, tmp = read_list (1, readcharfun, false); 3272 if (!CONSP (pair))
3169 ptrdiff_t size = list_length (tmp); 3273 invalid_syntax ("Invalid byte-code object", readcharfun);
3170 int i, depth, min_char; 3274
3171 struct Lisp_Cons *cell; 3275 vec[COMPILED_BYTECODE] = XCAR (pair);
3172 3276 vec[COMPILED_CONSTANTS] = XCDR (pair);
3173 if (size == 0) 3277 }
3174 error ("Zero-sized sub char-table"); 3278
3175 3279 if (!((STRINGP (vec[COMPILED_BYTECODE])
3176 if (! RANGED_FIXNUMP (1, XCAR (tmp), 3)) 3280 && VECTORP (vec[COMPILED_CONSTANTS]))
3177 error ("Invalid depth in sub char-table"); 3281 || CONSP (vec[COMPILED_BYTECODE])))
3178 depth = XFIXNUM (XCAR (tmp)); 3282 invalid_syntax ("Invalid byte-code object", readcharfun);
3179 if (chartab_size[depth] != size - 2) 3283
3180 error ("Invalid size in sub char-table"); 3284 if (STRINGP (vec[COMPILED_BYTECODE]))
3181 cell = XCONS (tmp), tmp = XCDR (tmp), size--; 3285 {
3182 free_cons (cell); 3286 if (STRING_MULTIBYTE (vec[COMPILED_BYTECODE]))
3183
3184 if (! RANGED_FIXNUMP (0, XCAR (tmp), MAX_CHAR))
3185 error ("Invalid minimum character in sub-char-table");
3186 min_char = XFIXNUM (XCAR (tmp));
3187 cell = XCONS (tmp), tmp = XCDR (tmp), size--;
3188 free_cons (cell);
3189
3190 tbl = make_uninit_sub_char_table (depth, min_char);
3191 for (i = 0; i < size; i++)
3192 {
3193 XSUB_CHAR_TABLE (tbl)->contents[i] = XCAR (tmp);
3194 cell = XCONS (tmp), tmp = XCDR (tmp);
3195 free_cons (cell);
3196 }
3197 return tbl;
3198 }
3199 invalid_syntax ("#^^", readcharfun);
3200 }
3201 invalid_syntax ("#^", readcharfun);
3202 }
3203 if (c == '&')
3204 { 3287 {
3205 Lisp_Object length; 3288 /* BYTESTR must have been produced by Emacs 20.2 or earlier
3206 length = read1 (readcharfun, pch, first_in_list, false); 3289 because it produced a raw 8-bit string for byte-code and
3207 c = READCHAR; 3290 now such a byte-code string is loaded as multibyte with
3208 if (c == '"') 3291 raw 8-bit characters converted to multibyte form.
3209 { 3292 Convert them back to the original unibyte form. */
3210 Lisp_Object tmp, val; 3293 vec[COMPILED_BYTECODE] = Fstring_as_unibyte (vec[COMPILED_BYTECODE]);
3211 EMACS_INT size_in_chars = bool_vector_bytes (XFIXNAT (length));
3212 unsigned char *data;
3213
3214 UNREAD (c);
3215 tmp = read1 (readcharfun, pch, first_in_list, false);
3216 if (STRING_MULTIBYTE (tmp)
3217 || (size_in_chars != SCHARS (tmp)
3218 /* We used to print 1 char too many
3219 when the number of bits was a multiple of 8.
3220 Accept such input in case it came from an old
3221 version. */
3222 && ! (XFIXNAT (length)
3223 == (SCHARS (tmp) - 1) * BOOL_VECTOR_BITS_PER_CHAR)))
3224 invalid_syntax ("#&...", readcharfun);
3225
3226 val = make_uninit_bool_vector (XFIXNAT (length));
3227 data = bool_vector_uchar_data (val);
3228 memcpy (data, SDATA (tmp), size_in_chars);
3229 /* Clear the extraneous bits in the last byte. */
3230 if (XFIXNUM (length) != size_in_chars * BOOL_VECTOR_BITS_PER_CHAR)
3231 data[size_in_chars - 1]
3232 &= (1 << (XFIXNUM (length) % BOOL_VECTOR_BITS_PER_CHAR)) - 1;
3233 return val;
3234 }
3235 invalid_syntax ("#&...", readcharfun);
3236 } 3294 }
3237 if (c == '[') 3295 // Bytecode must be immovable.
3238 { 3296 pin_string (vec[COMPILED_BYTECODE]);
3239 /* Accept compiled functions at read-time so that we don't have to 3297 }
3240 build them using function calls. */
3241 Lisp_Object tmp;
3242 struct Lisp_Vector *vec;
3243 tmp = read_vector (readcharfun, 1, false);
3244 vec = XVECTOR (tmp);
3245 if (! (COMPILED_STACK_DEPTH < ASIZE (tmp)
3246 && (FIXNUMP (AREF (tmp, COMPILED_ARGLIST))
3247 || CONSP (AREF (tmp, COMPILED_ARGLIST))
3248 || NILP (AREF (tmp, COMPILED_ARGLIST)))
3249 && ((STRINGP (AREF (tmp, COMPILED_BYTECODE))
3250 && VECTORP (AREF (tmp, COMPILED_CONSTANTS)))
3251 || CONSP (AREF (tmp, COMPILED_BYTECODE)))
3252 && FIXNATP (AREF (tmp, COMPILED_STACK_DEPTH))))
3253 invalid_syntax ("Invalid byte-code object", readcharfun);
3254
3255 if (STRINGP (AREF (tmp, COMPILED_BYTECODE)))
3256 {
3257 if (STRING_MULTIBYTE (AREF (tmp, COMPILED_BYTECODE)))
3258 {
3259 /* BYTESTR must have been produced by Emacs 20.2 or earlier
3260 because it produced a raw 8-bit string for byte-code and
3261 now such a byte-code string is loaded as multibyte with
3262 raw 8-bit characters converted to multibyte form.
3263 Convert them back to the original unibyte form. */
3264 ASET (tmp, COMPILED_BYTECODE,
3265 Fstring_as_unibyte (AREF (tmp, COMPILED_BYTECODE)));
3266 }
3267 // Bytecode must be immovable.
3268 pin_string (AREF (tmp, COMPILED_BYTECODE));
3269 }
3270 3298
3271 XSETPVECTYPE (vec, PVEC_COMPILED); 3299 XSETPVECTYPE (XVECTOR (obj), PVEC_COMPILED);
3272 return tmp; 3300 return obj;
3273 } 3301}
3274 if (c == '(')
3275 {
3276 Lisp_Object tmp;
3277 int ch;
3278
3279 /* Read the string itself. */
3280 tmp = read1 (readcharfun, &ch, 0, false);
3281 if (ch != 0 || !STRINGP (tmp))
3282 invalid_syntax ("#", readcharfun);
3283 /* Read the intervals and their properties. */
3284 while (1)
3285 {
3286 Lisp_Object beg, end, plist;
3287 3302
3288 beg = read1 (readcharfun, &ch, 0, false); 3303static Lisp_Object
3289 end = plist = Qnil; 3304char_table_from_rev_list (Lisp_Object elems, Lisp_Object readcharfun)
3290 if (ch == ')') 3305{
3291 break; 3306 Lisp_Object obj = vector_from_rev_list (elems);
3292 if (ch == 0) 3307 if (ASIZE (obj) < CHAR_TABLE_STANDARD_SLOTS)
3293 end = read1 (readcharfun, &ch, 0, false); 3308 invalid_syntax ("Invalid size char-table", readcharfun);
3294 if (ch == 0) 3309 XSETPVECTYPE (XVECTOR (obj), PVEC_CHAR_TABLE);
3295 plist = read1 (readcharfun, &ch, 0, false); 3310 return obj;
3296 if (ch)
3297 invalid_syntax ("Invalid string property list", readcharfun);
3298 Fset_text_properties (beg, end, plist, tmp);
3299 }
3300 3311
3301 return tmp; 3312}
3302 }
3303 3313
3304 /* #@NUMBER is used to skip NUMBER following bytes. 3314static Lisp_Object
3305 That's used in .elc files to skip over doc strings 3315sub_char_table_from_rev_list (Lisp_Object elems, Lisp_Object readcharfun)
3306 and function definitions. */ 3316{
3307 if (c == '@') 3317 /* A sub-char-table can't be read as a regular vector because of two
3318 C integer fields. */
3319 elems = Fnreverse (elems);
3320 ptrdiff_t size = list_length (elems);
3321 if (size < 2)
3322 error ("Invalid size of sub-char-table");
3323
3324 if (!RANGED_FIXNUMP (1, XCAR (elems), 3))
3325 error ("Invalid depth in sub-char-table");
3326 int depth = XFIXNUM (XCAR (elems));
3327
3328 if (chartab_size[depth] != size - 2)
3329 error ("Invalid size in sub-char-table");
3330 elems = XCDR (elems);
3331
3332 if (!RANGED_FIXNUMP (0, XCAR (elems), MAX_CHAR))
3333 error ("Invalid minimum character in sub-char-table");
3334 int min_char = XFIXNUM (XCAR (elems));
3335 elems = XCDR (elems);
3336
3337 Lisp_Object tbl = make_uninit_sub_char_table (depth, min_char);
3338 for (int i = 0; i < size - 2; i++)
3339 {
3340 XSUB_CHAR_TABLE (tbl)->contents[i] = XCAR (elems);
3341 elems = XCDR (elems);
3342 }
3343 return tbl;
3344}
3345
3346static Lisp_Object
3347string_props_from_rev_list (Lisp_Object elems, Lisp_Object readcharfun)
3348{
3349 elems = Fnreverse (elems);
3350 if (NILP (elems) || !STRINGP (XCAR (elems)))
3351 invalid_syntax ("#", readcharfun);
3352 Lisp_Object obj = XCAR (elems);
3353 for (Lisp_Object tl = XCDR (elems); !NILP (tl);)
3354 {
3355 Lisp_Object beg = XCAR (tl);
3356 tl = XCDR (tl);
3357 if (NILP (tl))
3358 invalid_syntax ("Invalid string property list", readcharfun);
3359 Lisp_Object end = XCAR (tl);
3360 tl = XCDR (tl);
3361 if (NILP (tl))
3362 invalid_syntax ("Invalid string property list", readcharfun);
3363 Lisp_Object plist = XCAR (tl);
3364 tl = XCDR (tl);
3365 Fset_text_properties (beg, end, plist, obj);
3366 }
3367 return obj;
3368}
3369
3370/* Read a bool vector (preceded by "#&"). */
3371static Lisp_Object
3372read_bool_vector (char stackbuf[VLA_ELEMS (stackbufsize)],
3373 Lisp_Object readcharfun)
3374{
3375 ptrdiff_t length = 0;
3376 for (;;)
3377 {
3378 int c = READCHAR;
3379 if (c < '0' || c > '9')
3308 { 3380 {
3309 enum { extra = 100 }; 3381 if (c != '"')
3310 ptrdiff_t i, nskip = 0, digits = 0; 3382 invalid_syntax ("#&", readcharfun);
3383 break;
3384 }
3385 if (INT_MULTIPLY_WRAPV (length, 10, &length)
3386 | INT_ADD_WRAPV (length, c - '0', &length))
3387 invalid_syntax ("#&", readcharfun);
3388 }
3311 3389
3312 /* Read a decimal integer. */ 3390 ptrdiff_t size_in_chars = bool_vector_bytes (length);
3313 while ((c = READCHAR) >= 0 3391 Lisp_Object str = read_string_literal (stackbuf, readcharfun);
3314 && c >= '0' && c <= '9') 3392 if (STRING_MULTIBYTE (str)
3315 { 3393 || !(size_in_chars == SCHARS (str)
3316 if ((STRING_BYTES_BOUND - extra) / 10 <= nskip) 3394 /* We used to print 1 char too many when the number of bits
3317 string_overflow (); 3395 was a multiple of 8. Accept such input in case it came
3318 digits++; 3396 from an old version. */
3319 nskip *= 10; 3397 || length == (SCHARS (str) - 1) * BOOL_VECTOR_BITS_PER_CHAR))
3320 nskip += c - '0'; 3398 invalid_syntax ("#&...", readcharfun);
3321 if (digits == 2 && nskip == 0) 3399
3322 { /* We've just seen #@00, which means "skip to end". */ 3400 Lisp_Object obj = make_uninit_bool_vector (length);
3323 skip_dyn_eof (readcharfun); 3401 unsigned char *data = bool_vector_uchar_data (obj);
3324 return Qnil; 3402 memcpy (data, SDATA (str), size_in_chars);
3325 } 3403 /* Clear the extraneous bits in the last byte. */
3326 } 3404 if (length != size_in_chars * BOOL_VECTOR_BITS_PER_CHAR)
3405 data[size_in_chars - 1] &= (1 << (length % BOOL_VECTOR_BITS_PER_CHAR)) - 1;
3406 return obj;
3407}
3408
3409/* Skip (and optionally remember) a lazily-loaded string
3410 preceded by "#@". */
3411static void
3412skip_lazy_string (Lisp_Object readcharfun)
3413{
3414 ptrdiff_t nskip = 0;
3415 ptrdiff_t digits = 0;
3416 for (;;)
3417 {
3418 int c = READCHAR;
3419 if (c < '0' || c > '9')
3420 {
3327 if (nskip > 0) 3421 if (nskip > 0)
3328 /* We can't use UNREAD here, because in the code below we side-step 3422 /* We can't use UNREAD here, because in the code below we side-step
3329 READCHAR. Instead, assume the first char after #@NNN occupies 3423 READCHAR. Instead, assume the first char after #@NNN occupies
3330 a single byte, which is the case normally since it's just 3424 a single byte, which is the case normally since it's just
3331 a space. */ 3425 a space. */
3332 nskip--; 3426 nskip--;
3333 else 3427 else
3334 UNREAD (c); 3428 UNREAD (c);
3335 3429 break;
3336 if (load_force_doc_strings
3337 && (FROM_FILE_P (readcharfun)))
3338 {
3339 /* If we are supposed to force doc strings into core right now,
3340 record the last string that we skipped,
3341 and record where in the file it comes from. */
3342
3343 /* But first exchange saved_doc_string
3344 with prev_saved_doc_string, so we save two strings. */
3345 {
3346 char *temp = saved_doc_string;
3347 ptrdiff_t temp_size = saved_doc_string_size;
3348 file_offset temp_pos = saved_doc_string_position;
3349 ptrdiff_t temp_len = saved_doc_string_length;
3350
3351 saved_doc_string = prev_saved_doc_string;
3352 saved_doc_string_size = prev_saved_doc_string_size;
3353 saved_doc_string_position = prev_saved_doc_string_position;
3354 saved_doc_string_length = prev_saved_doc_string_length;
3355
3356 prev_saved_doc_string = temp;
3357 prev_saved_doc_string_size = temp_size;
3358 prev_saved_doc_string_position = temp_pos;
3359 prev_saved_doc_string_length = temp_len;
3360 }
3361
3362 if (saved_doc_string_size == 0)
3363 {
3364 saved_doc_string = xmalloc (nskip + extra);
3365 saved_doc_string_size = nskip + extra;
3366 }
3367 if (nskip > saved_doc_string_size)
3368 {
3369 saved_doc_string = xrealloc (saved_doc_string, nskip + extra);
3370 saved_doc_string_size = nskip + extra;
3371 }
3372
3373 FILE *instream = infile->stream;
3374 saved_doc_string_position = (file_tell (instream)
3375 - infile->lookahead);
3376
3377 /* Copy that many bytes into saved_doc_string. */
3378 i = 0;
3379 for (int n = min (nskip, infile->lookahead); 0 < n; n--)
3380 saved_doc_string[i++]
3381 = c = infile->buf[--infile->lookahead];
3382 block_input ();
3383 for (; i < nskip && 0 <= c; i++)
3384 saved_doc_string[i] = c = getc (instream);
3385 unblock_input ();
3386
3387 saved_doc_string_length = i;
3388 }
3389 else
3390 /* Skip that many bytes. */
3391 skip_dyn_bytes (readcharfun, nskip);
3392
3393 goto retry;
3394 } 3430 }
3395 if (c == '!') 3431 if (INT_MULTIPLY_WRAPV (nskip, 10, &nskip)
3432 | INT_ADD_WRAPV (nskip, c - '0', &nskip))
3433 invalid_syntax ("#@", readcharfun);
3434 digits++;
3435 if (digits == 2 && nskip == 0)
3396 { 3436 {
3397 /* #! appears at the beginning of an executable file. 3437 /* #@00 means "skip to end" */
3398 Skip the first line. */ 3438 skip_dyn_eof (readcharfun);
3399 while (c != '\n' && c >= 0) 3439 return;
3400 c = READCHAR;
3401 goto retry;
3402 } 3440 }
3403 if (c == '$') 3441 }
3404 return Vload_file_name; 3442
3405 if (c == '\'') 3443 if (load_force_doc_strings && FROM_FILE_P (readcharfun))
3406 return list2 (Qfunction, read0 (readcharfun, locate_syms)); 3444 {
3407 /* #:foo is the uninterned symbol named foo. */ 3445 /* If we are supposed to force doc strings into core right now,
3408 if (c == ':') 3446 record the last string that we skipped,
3447 and record where in the file it comes from. */
3448
3449 /* But first exchange saved_doc_string
3450 with prev_saved_doc_string, so we save two strings. */
3451 {
3452 char *temp = saved_doc_string;
3453 ptrdiff_t temp_size = saved_doc_string_size;
3454 file_offset temp_pos = saved_doc_string_position;
3455 ptrdiff_t temp_len = saved_doc_string_length;
3456
3457 saved_doc_string = prev_saved_doc_string;
3458 saved_doc_string_size = prev_saved_doc_string_size;
3459 saved_doc_string_position = prev_saved_doc_string_position;
3460 saved_doc_string_length = prev_saved_doc_string_length;
3461
3462 prev_saved_doc_string = temp;
3463 prev_saved_doc_string_size = temp_size;
3464 prev_saved_doc_string_position = temp_pos;
3465 prev_saved_doc_string_length = temp_len;
3466 }
3467
3468 enum { extra = 100 };
3469 if (saved_doc_string_size == 0)
3409 { 3470 {
3410 uninterned_symbol = true; 3471 saved_doc_string = xmalloc (nskip + extra);
3411 read_hash_prefixed_symbol: 3472 saved_doc_string_size = nskip + extra;
3412 c = READCHAR;
3413 if (!(c > 040
3414 && c != NO_BREAK_SPACE
3415 && (c >= 0200
3416 || strchr ("\"';()[]#`,", c) == NULL)))
3417 {
3418 /* No symbol character follows, this is the empty
3419 symbol. */
3420 UNREAD (c);
3421 return Fmake_symbol (empty_unibyte_string);
3422 }
3423 goto read_symbol;
3424 } 3473 }
3425 /* #_foo is really the symbol foo, regardless of shorthands */ 3474 if (nskip > saved_doc_string_size)
3426 if (c == '_')
3427 { 3475 {
3428 skip_shorthand = true; 3476 saved_doc_string = xrealloc (saved_doc_string, nskip + extra);
3429 goto read_hash_prefixed_symbol; 3477 saved_doc_string_size = nskip + extra;
3430 } 3478 }
3431 /* ## is the empty symbol. */
3432 if (c == '#')
3433 return Fintern (empty_unibyte_string, Qnil);
3434 3479
3435 if (c >= '0' && c <= '9') 3480 FILE *instream = infile->stream;
3436 { 3481 saved_doc_string_position = (file_tell (instream) - infile->lookahead);
3437 EMACS_INT n = c - '0';
3438 bool overflow = false;
3439 3482
3440 /* Read a non-negative integer. */ 3483 /* Copy that many bytes into saved_doc_string. */
3441 while ('0' <= (c = READCHAR) && c <= '9') 3484 ptrdiff_t i = 0;
3442 { 3485 int c = 0;
3443 overflow |= INT_MULTIPLY_WRAPV (n, 10, &n); 3486 for (int n = min (nskip, infile->lookahead); n > 0; n--)
3444 overflow |= INT_ADD_WRAPV (n, c - '0', &n); 3487 saved_doc_string[i++] = c = infile->buf[--infile->lookahead];
3445 } 3488 block_input ();
3489 for (; i < nskip && c >= 0; i++)
3490 saved_doc_string[i] = c = getc (instream);
3491 unblock_input ();
3446 3492
3447 if (!overflow) 3493 saved_doc_string_length = i;
3448 { 3494 }
3449 if (c == 'r' || c == 'R') 3495 else
3450 { 3496 /* Skip that many bytes. */
3451 if (! (2 <= n && n <= 36)) 3497 skip_dyn_bytes (readcharfun, nskip);
3452 invalid_radix_integer (n, stackbuf, readcharfun); 3498}
3453 return read_integer (readcharfun, n, stackbuf);
3454 }
3455 3499
3456 if (n <= MOST_POSITIVE_FIXNUM && ! NILP (Vread_circle))
3457 {
3458 /* Reader forms that can reuse previously read objects. */
3459 3500
3460 /* #n=object returns object, but associates it with 3501/* Length of prefix only consisting of symbol constituent characters. */
3461 n for #n#. */ 3502static ptrdiff_t
3462 if (c == '=') 3503symbol_char_span (const char *s)
3463 { 3504{
3464 /* Make a placeholder for #n# to use temporarily. */ 3505 const char *p = s;
3465 /* Note: We used to use AUTO_CONS to allocate 3506 while ( *p == '^' || *p == '*' || *p == '+' || *p == '-' || *p == '/'
3466 placeholder, but that is a bad idea, since it 3507 || *p == '<' || *p == '=' || *p == '>' || *p == '_' || *p == '|')
3467 will place a stack-allocated cons cell into 3508 p++;
3468 the list in read_objects_map, which is a 3509 return p - s;
3469 staticpro'd global variable, and thus each of 3510}
3470 its elements is marked during each GC. A
3471 stack-allocated object will become garbled
3472 when its stack slot goes out of scope, and
3473 some other function reuses it for entirely
3474 different purposes, which will cause crashes
3475 in GC. */
3476 Lisp_Object placeholder = Fcons (Qnil, Qnil);
3477 struct Lisp_Hash_Table *h
3478 = XHASH_TABLE (read_objects_map);
3479 Lisp_Object number = make_fixnum (n), hash;
3480
3481 ptrdiff_t i = hash_lookup (h, number, &hash);
3482 if (i >= 0)
3483 /* Not normal, but input could be malformed. */
3484 set_hash_value_slot (h, i, placeholder);
3485 else
3486 hash_put (h, number, placeholder, hash);
3487
3488 /* Read the object itself. */
3489 Lisp_Object tem = read0 (readcharfun, locate_syms);
3490
3491 if (CONSP (tem))
3492 {
3493 if (BASE_EQ (tem, placeholder))
3494 /* Catch silly games like #1=#1# */
3495 invalid_syntax ("nonsensical self-reference",
3496 readcharfun);
3497 3511
3498 /* Optimisation: since the placeholder is already 3512static void
3499 a cons, repurpose it as the actual value. 3513skip_space_and_comments (Lisp_Object readcharfun)
3500 This allows us to skip the substition below, 3514{
3501 since the placeholder is already referenced 3515 int c;
3502 inside TEM at the appropriate places. */ 3516 do
3503 Fsetcar (placeholder, XCAR (tem)); 3517 {
3504 Fsetcdr (placeholder, XCDR (tem)); 3518 c = READCHAR;
3505 3519 if (c == ';')
3506 struct Lisp_Hash_Table *h2 3520 do
3507 = XHASH_TABLE (read_objects_completed); 3521 c = READCHAR;
3508 ptrdiff_t i = hash_lookup (h2, placeholder, &hash); 3522 while (c >= 0 && c != '\n');
3509 eassert (i < 0); 3523 if (c < 0)
3510 hash_put (h2, placeholder, Qnil, hash); 3524 end_of_file_error ();
3511 return placeholder; 3525 }
3512 } 3526 while (c <= 32 || c == NO_BREAK_SPACE);
3513 3527 UNREAD (c);
3514 /* If it can be recursive, remember it for 3528}
3515 future substitutions. */
3516 if (! SYMBOLP (tem)
3517 && ! NUMBERP (tem)
3518 && ! (STRINGP (tem) && !string_intervals (tem)))
3519 {
3520 struct Lisp_Hash_Table *h2
3521 = XHASH_TABLE (read_objects_completed);
3522 i = hash_lookup (h2, tem, &hash);
3523 eassert (i < 0);
3524 hash_put (h2, tem, Qnil, hash);
3525 }
3526
3527 /* Now put it everywhere the placeholder was... */
3528 Flread__substitute_object_in_subtree
3529 (tem, placeholder, read_objects_completed);
3530
3531 /* ...and #n# will use the real value from now on. */
3532 i = hash_lookup (h, number, &hash);
3533 eassert (i >= 0);
3534 set_hash_value_slot (h, i, tem);
3535
3536 return tem;
3537 }
3538 3529
3539 /* #n# returns a previously read object. */ 3530/* When an object is read, the type of the top read stack entry indicates
3540 if (c == '#') 3531 the syntactic context. */
3541 { 3532enum read_entry_type
3542 struct Lisp_Hash_Table *h 3533{
3543 = XHASH_TABLE (read_objects_map); 3534 /* preceding syntactic context */
3544 ptrdiff_t i = hash_lookup (h, make_fixnum (n), NULL); 3535 RE_list_start, /* "(" */
3545 if (i >= 0) 3536
3546 return HASH_VALUE (h, i); 3537 RE_list, /* "(" (+ OBJECT) */
3547 } 3538 RE_list_dot, /* "(" (+ OBJECT) "." */
3548 } 3539
3549 } 3540 RE_vector, /* "[" (* OBJECT) */
3550 /* Fall through to error message. */ 3541 RE_record, /* "#s(" (* OBJECT) */
3542 RE_char_table, /* "#^[" (* OBJECT) */
3543 RE_sub_char_table, /* "#^^[" (* OBJECT) */
3544 RE_byte_code, /* "#[" (* OBJECT) */
3545 RE_string_props, /* "#(" (* OBJECT) */
3546
3547 RE_special, /* "'" | "#'" | "`" | "," | ",@" */
3548
3549 RE_numbered, /* "#" (+ DIGIT) "=" */
3550};
3551
3552struct read_stack_entry
3553{
3554 enum read_entry_type type;
3555 union {
3556 /* RE_list, RE_list_dot */
3557 struct {
3558 Lisp_Object head; /* first cons of list */
3559 Lisp_Object tail; /* last cons of list */
3560 } list;
3561
3562 /* RE_vector, RE_record, RE_char_table, RE_sub_char_table,
3563 RE_byte_code, RE_string_props */
3564 struct {
3565 Lisp_Object elems; /* list of elements in reverse order */
3566 bool old_locate_syms; /* old value of locate_syms */
3567 } vector;
3568
3569 /* RE_special */
3570 struct {
3571 Lisp_Object symbol; /* symbol from special syntax */
3572 } special;
3573
3574 /* RE_numbered */
3575 struct {
3576 Lisp_Object number; /* number as a fixnum */
3577 Lisp_Object placeholder; /* placeholder object */
3578 } numbered;
3579 } u;
3580};
3581
3582struct read_stack
3583{
3584 struct read_stack_entry *stack; /* base of stack */
3585 ptrdiff_t size; /* allocated size in entries */
3586 ptrdiff_t sp; /* current number of entries */
3587};
3588
3589static struct read_stack rdstack = {NULL, 0, 0};
3590
3591void
3592mark_lread (void)
3593{
3594 /* Mark the read stack, which may contain data not otherwise traced */
3595 for (ptrdiff_t i = 0; i < rdstack.sp; i++)
3596 {
3597 struct read_stack_entry *e = &rdstack.stack[i];
3598 switch (e->type)
3599 {
3600 case RE_list_start:
3601 break;
3602 case RE_list:
3603 case RE_list_dot:
3604 mark_object (e->u.list.head);
3605 mark_object (e->u.list.tail);
3606 break;
3607 case RE_vector:
3608 case RE_record:
3609 case RE_char_table:
3610 case RE_sub_char_table:
3611 case RE_byte_code:
3612 case RE_string_props:
3613 mark_object (e->u.vector.elems);
3614 break;
3615 case RE_special:
3616 mark_object (e->u.special.symbol);
3617 break;
3618 case RE_numbered:
3619 mark_object (e->u.numbered.number);
3620 mark_object (e->u.numbered.placeholder);
3621 break;
3551 } 3622 }
3552 else if (c == 'x' || c == 'X') 3623 }
3553 return read_integer (readcharfun, 16, stackbuf); 3624}
3554 else if (c == 'o' || c == 'O')
3555 return read_integer (readcharfun, 8, stackbuf);
3556 else if (c == 'b' || c == 'B')
3557 return read_integer (readcharfun, 2, stackbuf);
3558
3559 char acm_buf[15]; /* FIXME!!! 2021-11-27. */
3560 sprintf (acm_buf, "#%c", c);
3561 invalid_syntax (acm_buf, readcharfun);
3562 UNREAD (c);
3563 invalid_syntax ("#", readcharfun);
3564 3625
3565 case ';': 3626static inline struct read_stack_entry *
3566 while ((c = READCHAR) >= 0 && c != '\n'); 3627read_stack_top (void)
3567 goto retry; 3628{
3629 eassume (rdstack.sp > 0);
3630 return &rdstack.stack[rdstack.sp - 1];
3631}
3568 3632
3569 case '\'': 3633static inline struct read_stack_entry *
3570 return list2 (Qquote, read0 (readcharfun, locate_syms)); 3634read_stack_pop (void)
3635{
3636 eassume (rdstack.sp > 0);
3637 return &rdstack.stack[--rdstack.sp];
3638}
3571 3639
3572 case '`': 3640static inline bool
3573 return list2 (Qbackquote, read0 (readcharfun, locate_syms)); 3641read_stack_empty_p (ptrdiff_t base_sp)
3642{
3643 return rdstack.sp <= base_sp;
3644}
3574 3645
3575 case ',': 3646NO_INLINE static void
3576 { 3647grow_read_stack (void)
3577 Lisp_Object comma_type = Qnil; 3648{
3578 Lisp_Object value; 3649 struct read_stack *rs = &rdstack;
3579 int ch = READCHAR; 3650 eassert (rs->sp == rs->size);
3651 rs->stack = xpalloc (rs->stack, &rs->size, 1, -1, sizeof *rs->stack);
3652 eassert (rs->sp < rs->size);
3653}
3580 3654
3581 if (ch == '@') 3655static inline void
3582 comma_type = Qcomma_at; 3656read_stack_push (struct read_stack_entry e)
3583 else 3657{
3584 { 3658 if (rdstack.sp >= rdstack.size)
3585 if (ch >= 0) UNREAD (ch); 3659 grow_read_stack ();
3586 comma_type = Qcomma; 3660 rdstack.stack[rdstack.sp++] = e;
3587 } 3661}
3588 3662
3589 value = read0 (readcharfun, locate_syms);
3590 return list2 (comma_type, value);
3591 }
3592 case '?':
3593 {
3594 int modifiers;
3595 int next_char;
3596 bool ok;
3597 3663
3598 c = READCHAR; 3664/* Read a Lisp object.
3599 if (c < 0) 3665 If LOCATE_SYMS is true, symbols are read with position. */
3600 end_of_file_error (); 3666static Lisp_Object
3601 3667read0 (Lisp_Object readcharfun, bool locate_syms)
3602 /* Accept `single space' syntax like (list ? x) where the 3668{
3603 whitespace character is SPC or TAB. 3669 char stackbuf[stackbufsize];
3604 Other literal whitespace like NL, CR, and FF are not accepted, 3670 char *read_buffer = stackbuf;
3605 as there are well-established escape sequences for these. */ 3671 ptrdiff_t read_buffer_size = sizeof stackbuf;
3606 if (c == ' ' || c == '\t') 3672 char *heapbuf = NULL;
3607 return make_fixnum (c); 3673 specpdl_ref count = SPECPDL_INDEX ();
3608 3674
3609 if (c == '(' || c == ')' || c == '[' || c == ']' 3675 ptrdiff_t base_sp = rdstack.sp;
3610 || c == '"' || c == ';') 3676
3677 bool uninterned_symbol;
3678 bool skip_shorthand;
3679
3680 /* Read an object into `obj'. */
3681 read_obj: ;
3682 Lisp_Object obj;
3683 bool multibyte;
3684 int c = READCHAR_REPORT_MULTIBYTE (&multibyte);
3685 if (c < 0)
3686 end_of_file_error ();
3687
3688 switch (c)
3689 {
3690 case '(':
3691 read_stack_push ((struct read_stack_entry) {.type = RE_list_start});
3692 goto read_obj;
3693
3694 case ')':
3695 if (read_stack_empty_p (base_sp))
3696 invalid_syntax (")", readcharfun);
3697 switch (read_stack_top ()->type)
3698 {
3699 case RE_list_start:
3700 read_stack_pop ();
3701 obj = Qnil;
3702 break;
3703 case RE_list:
3704 obj = read_stack_pop ()->u.list.head;
3705 break;
3706 case RE_record:
3611 { 3707 {
3612 CHECK_LIST (Vlread_unescaped_character_literals); 3708 locate_syms = read_stack_top ()->u.vector.old_locate_syms;
3613 Lisp_Object char_obj = make_fixed_natnum (c); 3709 Lisp_Object elems = Fnreverse (read_stack_pop ()->u.vector.elems);
3614 if (NILP (Fmemq (char_obj, Vlread_unescaped_character_literals))) 3710 if (NILP (elems))
3615 Vlread_unescaped_character_literals = 3711 invalid_syntax ("#s", readcharfun);
3616 Fcons (char_obj, Vlread_unescaped_character_literals); 3712
3713 if (BASE_EQ (XCAR (elems), Qhash_table))
3714 obj = hash_table_from_plist (XCDR (elems));
3715 else
3716 obj = record_from_list (elems);
3717 break;
3617 } 3718 }
3719 case RE_string_props:
3720 locate_syms = read_stack_top ()->u.vector.old_locate_syms;
3721 obj = string_props_from_rev_list (read_stack_pop () ->u.vector.elems,
3722 readcharfun);
3723 break;
3724 default:
3725 invalid_syntax (")", readcharfun);
3726 }
3727 break;
3618 3728
3619 if (c == '\\') 3729 case '[':
3620 c = read_escape (readcharfun, 0); 3730 read_stack_push ((struct read_stack_entry) {
3621 modifiers = c & CHAR_MODIFIER_MASK; 3731 .type = RE_vector,
3622 c &= ~CHAR_MODIFIER_MASK; 3732 .u.vector.elems = Qnil,
3623 if (CHAR_BYTE8_P (c)) 3733 .u.vector.old_locate_syms = locate_syms,
3624 c = CHAR_TO_BYTE8 (c); 3734 });
3625 c |= modifiers; 3735 /* FIXME: should vectors be read with locate_syms=false? */
3626 3736 goto read_obj;
3627 next_char = READCHAR;
3628 ok = (next_char <= 040
3629 || (next_char < 0200
3630 && strchr ("\"';()[]#?`,.", next_char) != NULL));
3631 UNREAD (next_char);
3632 if (ok)
3633 return make_fixnum (c);
3634
3635 invalid_syntax ("?", readcharfun);
3636 }
3637 3737
3638 case '"': 3738 case ']':
3739 if (read_stack_empty_p (base_sp))
3740 invalid_syntax ("]", readcharfun);
3741 switch (read_stack_top ()->type)
3742 {
3743 case RE_vector:
3744 locate_syms = read_stack_top ()->u.vector.old_locate_syms;
3745 obj = vector_from_rev_list (read_stack_pop ()->u.vector.elems);
3746 break;
3747 case RE_byte_code:
3748 locate_syms = read_stack_top ()->u.vector.old_locate_syms;
3749 obj = bytecode_from_rev_list (read_stack_pop ()->u.vector.elems,
3750 readcharfun);
3751 break;
3752 case RE_char_table:
3753 locate_syms = read_stack_top ()->u.vector.old_locate_syms;
3754 obj = char_table_from_rev_list (read_stack_pop ()->u.vector.elems,
3755 readcharfun);
3756 break;
3757 case RE_sub_char_table:
3758 locate_syms = read_stack_top ()->u.vector.old_locate_syms;
3759 obj = sub_char_table_from_rev_list (read_stack_pop ()->u.vector.elems,
3760 readcharfun);
3761 break;
3762 default:
3763 invalid_syntax ("]", readcharfun);
3764 break;
3765 }
3766 break;
3767
3768 case '#':
3639 { 3769 {
3640 specpdl_ref count = SPECPDL_INDEX (); 3770 int ch = READCHAR;
3641 char *read_buffer = stackbuf; 3771 switch (ch)
3642 ptrdiff_t read_buffer_size = sizeof stackbuf;
3643 char *heapbuf = NULL;
3644 char *p = read_buffer;
3645 char *end = read_buffer + read_buffer_size;
3646 int ch;
3647 /* True if we saw an escape sequence specifying
3648 a multibyte character. */
3649 bool force_multibyte = false;
3650 /* True if we saw an escape sequence specifying
3651 a single-byte character. */
3652 bool force_singlebyte = false;
3653 bool cancel = false;
3654 ptrdiff_t nchars = 0;
3655
3656 while ((ch = READCHAR) >= 0
3657 && ch != '\"')
3658 { 3772 {
3659 if (end - p < MAX_MULTIBYTE_LENGTH) 3773 case '\'':
3774 /* #'X -- special syntax for (function X) */
3775 read_stack_push ((struct read_stack_entry) {
3776 .type = RE_special,
3777 .u.special.symbol = Qfunction,
3778 });
3779 goto read_obj;
3780
3781 case '#':
3782 /* ## -- the empty symbol */
3783 obj = Fintern (empty_unibyte_string, Qnil);
3784 break;
3785
3786 case 's':
3787 /* #s(...) -- a record or hash-table */
3788 ch = READCHAR;
3789 if (ch != '(')
3660 { 3790 {
3661 ptrdiff_t offset = p - read_buffer; 3791 UNREAD (ch);
3662 read_buffer = grow_read_buffer (read_buffer, offset, 3792 invalid_syntax ("#s", readcharfun);
3663 &heapbuf, &read_buffer_size,
3664 count);
3665 p = read_buffer + offset;
3666 end = read_buffer + read_buffer_size;
3667 } 3793 }
3794 read_stack_push ((struct read_stack_entry) {
3795 .type = RE_record,
3796 .u.vector.elems = Qnil,
3797 .u.vector.old_locate_syms = locate_syms,
3798 });
3799 locate_syms = false;
3800 goto read_obj;
3801
3802 case '^':
3803 /* #^[...] -- char-table
3804 #^^[...] -- sub-char-table */
3805 ch = READCHAR;
3806 if (ch == '^')
3807 {
3808 ch = READCHAR;
3809 if (ch == '[')
3810 {
3811 read_stack_push ((struct read_stack_entry) {
3812 .type = RE_sub_char_table,
3813 .u.vector.elems = Qnil,
3814 .u.vector.old_locate_syms = locate_syms,
3815 });
3816 locate_syms = false;
3817 goto read_obj;
3818 }
3819 else
3820 {
3821 UNREAD (ch);
3822 invalid_syntax ("#^^", readcharfun);
3823 }
3824 }
3825 else if (ch == '[')
3826 {
3827 read_stack_push ((struct read_stack_entry) {
3828 .type = RE_char_table,
3829 .u.vector.elems = Qnil,
3830 .u.vector.old_locate_syms = locate_syms,
3831 });
3832 locate_syms = false;
3833 goto read_obj;
3834 }
3835 else
3836 {
3837 UNREAD (ch);
3838 invalid_syntax ("#^", readcharfun);
3839 }
3840
3841 case '(':
3842 /* #(...) -- string with properties */
3843 read_stack_push ((struct read_stack_entry) {
3844 .type = RE_string_props,
3845 .u.vector.elems = Qnil,
3846 .u.vector.old_locate_syms = locate_syms,
3847 });
3848 locate_syms = false;
3849 goto read_obj;
3850
3851 case '[':
3852 /* #[...] -- byte-code */
3853 read_stack_push ((struct read_stack_entry) {
3854 .type = RE_byte_code,
3855 .u.vector.elems = Qnil,
3856 .u.vector.old_locate_syms = locate_syms,
3857 });
3858 locate_syms = false;
3859 goto read_obj;
3860
3861 case '&':
3862 /* #&N"..." -- bool-vector */
3863 obj = read_bool_vector (stackbuf, readcharfun);
3864 break;
3865
3866 case '!':
3867 /* #! appears at the beginning of an executable file.
3868 Skip the rest of the line. */
3869 {
3870 int c;
3871 do
3872 c = READCHAR;
3873 while (c >= 0 && c != '\n');
3874 goto read_obj;
3875 }
3668 3876
3669 if (ch == '\\') 3877 case 'x':
3878 case 'X':
3879 obj = read_integer (readcharfun, 16, stackbuf);
3880 break;
3881
3882 case 'o':
3883 case 'O':
3884 obj = read_integer (readcharfun, 8, stackbuf);
3885 break;
3886
3887 case 'b':
3888 case 'B':
3889 obj = read_integer (readcharfun, 2, stackbuf);
3890 break;
3891
3892 case '@':
3893 /* #@NUMBER is used to skip NUMBER following bytes.
3894 That's used in .elc files to skip over doc strings
3895 and function definitions that can be loaded lazily. */
3896 skip_lazy_string (readcharfun);
3897 goto read_obj;
3898
3899 case '$':
3900 /* #$ -- reference to lazy-loaded string */
3901 obj = Vload_file_name;
3902 break;
3903
3904 case ':':
3905 /* #:X -- uninterned symbol */
3906 c = READCHAR;
3907 if (c <= 32 || c == NO_BREAK_SPACE
3908 || c == '"' || c == '\'' || c == ';' || c == '#'
3909 || c == '(' || c == ')' || c == '[' || c == ']'
3910 || c == '`' || c == ',')
3670 { 3911 {
3671 int modifiers; 3912 /* No symbol character follows: this is the empty symbol. */
3913 UNREAD (c);
3914 obj = Fmake_symbol (empty_unibyte_string);
3915 break;
3916 }
3917 uninterned_symbol = true;
3918 skip_shorthand = false;
3919 goto read_symbol;
3672 3920
3673 ch = read_escape (readcharfun, 1); 3921 case '_':
3922 /* #_X -- symbol without shorthand */
3923 c = READCHAR;
3924 if (c <= 32 || c == NO_BREAK_SPACE
3925 || c == '"' || c == '\'' || c == ';' || c == '#'
3926 || c == '(' || c == ')' || c == '[' || c == ']'
3927 || c == '`' || c == ',')
3928 {
3929 /* No symbol character follows: this is the empty symbol. */
3930 UNREAD (c);
3931 obj = Fintern (empty_unibyte_string, Qnil);
3932 break;
3933 }
3934 uninterned_symbol = false;
3935 skip_shorthand = true;
3936 goto read_symbol;
3674 3937
3675 /* CH is -1 if \ newline or \ space has just been seen. */ 3938 default:
3676 if (ch == -1) 3939 if (ch >= '0' && ch <= '9')
3940 {
3941 /* #N=OBJ or #N# -- first read the number N */
3942 EMACS_INT n = ch - '0';
3943 int c;
3944 for (;;)
3677 { 3945 {
3678 if (p == read_buffer) 3946 c = READCHAR;
3679 cancel = true; 3947 if (c < '0' || c > '9')
3680 continue; 3948 break;
3949 if (INT_MULTIPLY_WRAPV (n, 10, &n)
3950 || INT_ADD_WRAPV (n, c - '0', &n))
3951 invalid_syntax ("#", readcharfun);
3681 } 3952 }
3682 3953 if (c == 'r' || c == 'R')
3683 modifiers = ch & CHAR_MODIFIER_MASK;
3684 ch = ch & ~CHAR_MODIFIER_MASK;
3685
3686 if (CHAR_BYTE8_P (ch))
3687 force_singlebyte = true;
3688 else if (! ASCII_CHAR_P (ch))
3689 force_multibyte = true;
3690 else /* I.e. ASCII_CHAR_P (ch). */
3691 { 3954 {
3692 /* Allow `\C- ' and `\C-?'. */ 3955 /* #NrDIGITS -- radix-N number */
3693 if (modifiers == CHAR_CTL) 3956 if (n < 0 || n > 36)
3694 { 3957 invalid_radix_integer (n, stackbuf, readcharfun);
3695 if (ch == ' ') 3958 obj = read_integer (readcharfun, n, stackbuf);
3696 ch = 0, modifiers = 0; 3959 break;
3697 else if (ch == '?') 3960 }
3698 ch = 127, modifiers = 0; 3961 else if (n <= MOST_POSITIVE_FIXNUM && !NILP (Vread_circle))
3699 } 3962 {
3700 if (modifiers & CHAR_SHIFT) 3963 if (c == '=')
3701 { 3964 {
3702 /* Shift modifier is valid only with [A-Za-z]. */ 3965 /* #N=OBJ -- assign number N to OBJ */
3703 if (ch >= 'A' && ch <= 'Z') 3966 Lisp_Object placeholder = Fcons (Qnil, Qnil);
3704 modifiers &= ~CHAR_SHIFT; 3967
3705 else if (ch >= 'a' && ch <= 'z') 3968 struct Lisp_Hash_Table *h
3706 ch -= ('a' - 'A'), modifiers &= ~CHAR_SHIFT; 3969 = XHASH_TABLE (read_objects_map);
3970 Lisp_Object number = make_fixnum (n);
3971 Lisp_Object hash;
3972 ptrdiff_t i = hash_lookup (h, number, &hash);
3973 if (i >= 0)
3974 /* Not normal, but input could be malformed. */
3975 set_hash_value_slot (h, i, placeholder);
3976 else
3977 hash_put (h, number, placeholder, hash);
3978 read_stack_push ((struct read_stack_entry) {
3979 .type = RE_numbered,
3980 .u.numbered.number = number,
3981 .u.numbered.placeholder = placeholder,
3982 });
3983 goto read_obj;
3707 } 3984 }
3708 3985 else if (c == '#')
3709 if (modifiers & CHAR_META)
3710 { 3986 {
3711 /* Move the meta bit to the right place for a 3987 /* #N# -- reference to numbered object */
3712 string. */ 3988 struct Lisp_Hash_Table *h
3713 modifiers &= ~CHAR_META; 3989 = XHASH_TABLE (read_objects_map);
3714 ch = BYTE8_TO_CHAR (ch | 0x80); 3990 ptrdiff_t i = hash_lookup (h, make_fixnum (n), NULL);
3715 force_singlebyte = true; 3991 if (i < 0)
3992 invalid_syntax ("#", readcharfun);
3993 obj = HASH_VALUE (h, i);
3994 break;
3716 } 3995 }
3996 else
3997 invalid_syntax ("#", readcharfun);
3717 } 3998 }
3718 3999 else
3719 /* Any modifiers remaining are invalid. */ 4000 invalid_syntax ("#", readcharfun);
3720 if (modifiers)
3721 invalid_syntax ("Invalid modifier in string", readcharfun);
3722 p += CHAR_STRING (ch, (unsigned char *) p);
3723 } 4001 }
3724 else 4002 else
3725 { 4003 invalid_syntax ("#", readcharfun);
3726 p += CHAR_STRING (ch, (unsigned char *) p);
3727 if (CHAR_BYTE8_P (ch))
3728 force_singlebyte = true;
3729 else if (! ASCII_CHAR_P (ch))
3730 force_multibyte = true;
3731 }
3732 nchars++;
3733 } 4004 }
4005 break;
4006 }
3734 4007
3735 if (ch < 0) 4008 case '?':
3736 end_of_file_error (); 4009 obj = read_char_literal (readcharfun);
4010 break;
3737 4011
3738 /* If purifying, and string starts with \ newline, 4012 case '"':
3739 return zero instead. This is for doc strings 4013 obj = read_string_literal (stackbuf, readcharfun);
3740 that we are really going to find in etc/DOC.nn.nn. */ 4014 break;
3741 if (!NILP (Vpurify_flag) && NILP (Vdoc_file_name) && cancel) 4015
3742 return unbind_to (count, make_fixnum (0)); 4016 case '\'':
4017 read_stack_push ((struct read_stack_entry) {
4018 .type = RE_special,
4019 .u.special.symbol = Qquote,
4020 });
4021 goto read_obj;
3743 4022
3744 if (! force_multibyte && force_singlebyte) 4023 case '`':
4024 read_stack_push ((struct read_stack_entry) {
4025 .type = RE_special,
4026 .u.special.symbol = Qbackquote,
4027 });
4028 goto read_obj;
4029
4030 case ',':
4031 {
4032 int ch = READCHAR;
4033 Lisp_Object sym;
4034 if (ch == '@')
4035 sym = Qcomma_at;
4036 else
3745 { 4037 {
3746 /* READ_BUFFER contains raw 8-bit bytes and no multibyte 4038 if (ch >= 0)
3747 forms. Convert it to unibyte. */ 4039 UNREAD (ch);
3748 nchars = str_as_unibyte ((unsigned char *) read_buffer, 4040 sym = Qcomma;
3749 p - read_buffer);
3750 p = read_buffer + nchars;
3751 } 4041 }
4042 read_stack_push ((struct read_stack_entry) {
4043 .type = RE_special,
4044 .u.special.symbol = sym,
4045 });
4046 goto read_obj;
4047 }
3752 4048
3753 Lisp_Object result 4049 case ';':
3754 = make_specified_string (read_buffer, nchars, p - read_buffer, 4050 {
3755 (force_multibyte 4051 int c;
3756 || (p - read_buffer != nchars))); 4052 do
3757 return unbind_to (count, result); 4053 c = READCHAR;
4054 while (c >= 0 && c != '\n');
4055 goto read_obj;
3758 } 4056 }
3759 4057
3760 case '.': 4058 case '.':
3761 { 4059 {
3762 int next_char = READCHAR; 4060 int nch = READCHAR;
3763 UNREAD (next_char); 4061 UNREAD (nch);
3764 4062 if (nch <= 32 || nch == NO_BREAK_SPACE
3765 if (next_char <= 040 4063 || nch == '"' || nch == '\'' || nch == ';'
3766 || (next_char < 0200 4064 || nch == '(' || nch == '[' || nch == '#'
3767 && strchr ("\"';([#?`,", next_char) != NULL)) 4065 || nch == '?' || nch == '`' || nch == ',')
3768 { 4066 {
3769 *pch = c; 4067 if (!read_stack_empty_p (base_sp)
3770 return Qnil; 4068 && read_stack_top ()->type == RE_list)
4069 {
4070 read_stack_top ()->type = RE_list_dot;
4071 goto read_obj;
4072 }
4073 invalid_syntax (".", readcharfun);
3771 } 4074 }
3772 } 4075 }
3773 /* The atom-reading loop below will now loop at least once, 4076 /* may be a number or symbol starting with a dot */
3774 assuring that we will not try to UNREAD two characters in a
3775 row. */
3776 FALLTHROUGH; 4077 FALLTHROUGH;
4078
3777 default: 4079 default:
3778 if (c <= 040) goto retry; 4080 if (c <= 32 || c == NO_BREAK_SPACE)
3779 if (c == NO_BREAK_SPACE) 4081 goto read_obj;
3780 goto retry;
3781 4082
4083 uninterned_symbol = false;
4084 skip_shorthand = false;
4085 /* symbol or number */
3782 read_symbol: 4086 read_symbol:
3783 { 4087 {
3784 specpdl_ref count = SPECPDL_INDEX ();
3785 char *read_buffer = stackbuf;
3786 ptrdiff_t read_buffer_size = sizeof stackbuf;
3787 char *heapbuf = NULL;
3788 char *p = read_buffer; 4088 char *p = read_buffer;
3789 char *end = read_buffer + read_buffer_size; 4089 char *end = read_buffer + read_buffer_size;
3790 bool quoted = false; 4090 bool quoted = false;
@@ -3805,7 +4105,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list, bool locate_syms)
3805 if (c == '\\') 4105 if (c == '\\')
3806 { 4106 {
3807 c = READCHAR; 4107 c = READCHAR;
3808 if (c == -1) 4108 if (c < 0)
3809 end_of_file_error (); 4109 end_of_file_error ();
3810 quoted = true; 4110 quoted = true;
3811 } 4111 }
@@ -3816,94 +4116,205 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list, bool locate_syms)
3816 *p++ = c; 4116 *p++ = c;
3817 c = READCHAR; 4117 c = READCHAR;
3818 } 4118 }
3819 while (c > 040 4119 while (c > 32
3820 && c != NO_BREAK_SPACE 4120 && c != NO_BREAK_SPACE
3821 && (c >= 0200 4121 && (c >= 128
3822 || strchr ("\"';()[]#`,", c) == NULL)); 4122 || !( c == '"' || c == '\'' || c == ';' || c == '#'
4123 || c == '(' || c == ')' || c == '[' || c == ']'
4124 || c == '`' || c == ',')));
3823 4125
3824 *p = 0; 4126 *p = 0;
3825 ptrdiff_t nbytes = p - read_buffer; 4127 ptrdiff_t nbytes = p - read_buffer;
3826 UNREAD (c); 4128 UNREAD (c);
3827 4129
3828 if (!quoted && !uninterned_symbol && !skip_shorthand) 4130 /* Only attempt to parse the token as a number if it starts as one. */
4131 char c0 = read_buffer[0];
4132 if (((c0 >= '0' && c0 <= '9') || c0 == '.' || c0 == '-' || c0 == '+')
4133 && !quoted && !uninterned_symbol && !skip_shorthand)
3829 { 4134 {
3830 ptrdiff_t len; 4135 ptrdiff_t len;
3831 Lisp_Object result = string_to_number (read_buffer, 10, &len); 4136 Lisp_Object result = string_to_number (read_buffer, 10, &len);
3832 if (! NILP (result) && len == nbytes) 4137 if (!NILP (result) && len == nbytes)
3833 return unbind_to (count, result); 4138 {
4139 obj = result;
4140 break;
4141 }
3834 } 4142 }
3835 { 4143
3836 Lisp_Object result; 4144 /* symbol, possibly uninterned */
3837 ptrdiff_t nchars 4145 ptrdiff_t nchars
3838 = (multibyte 4146 = (multibyte
3839 ? multibyte_chars_in_text ((unsigned char *) read_buffer, 4147 ? multibyte_chars_in_text ((unsigned char *)read_buffer, nbytes)
3840 nbytes) 4148 : nbytes);
3841 : nbytes); 4149 Lisp_Object result;
3842 4150 if (uninterned_symbol)
3843 if (uninterned_symbol) 4151 {
3844 { 4152 Lisp_Object name
3845 Lisp_Object name 4153 = (!NILP (Vpurify_flag)
3846 = ((! NILP (Vpurify_flag) 4154 ? make_pure_string (read_buffer, nchars, nbytes, multibyte)
3847 ? make_pure_string : make_specified_string) 4155 : make_specified_string (read_buffer, nchars, nbytes,
3848 (read_buffer, nchars, nbytes, multibyte)); 4156 multibyte));
3849 result = Fmake_symbol (name); 4157 result = Fmake_symbol (name);
3850 } 4158 }
3851 else 4159 else
3852 { 4160 {
3853 /* Don't create the string object for the name unless 4161 /* Don't create the string object for the name unless
3854 we're going to retain it in a new symbol. 4162 we're going to retain it in a new symbol.
3855 4163
3856 Like intern_1 but supports multibyte names. */ 4164 Like intern_1 but supports multibyte names. */
3857 Lisp_Object obarray = check_obarray (Vobarray); 4165 Lisp_Object obarray = check_obarray (Vobarray);
3858 4166
3859 char* longhand = NULL; 4167 char *longhand = NULL;
3860 ptrdiff_t longhand_chars = 0; 4168 ptrdiff_t longhand_chars = 0;
3861 ptrdiff_t longhand_bytes = 0; 4169 ptrdiff_t longhand_bytes = 0;
3862 4170
3863 Lisp_Object tem; 4171 Lisp_Object found;
3864 if (skip_shorthand 4172 if (skip_shorthand
3865 /* The following ASCII characters are used in the 4173 /* We exempt characters used in the "core" Emacs Lisp
3866 only "core" Emacs Lisp symbols that are comprised 4174 symbols that are comprised entirely of characters
3867 entirely of characters that have the 'symbol 4175 that have the 'symbol constituent' syntax from
3868 constituent' syntax. We exempt them from 4176 transforming according to shorthands. */
3869 transforming according to shorthands. */ 4177 || symbol_char_span (read_buffer) >= nbytes)
3870 || strspn (read_buffer, "^*+-/<=>_|") >= nbytes) 4178 found = oblookup (obarray, read_buffer, nchars, nbytes);
3871 tem = oblookup (obarray, read_buffer, nchars, nbytes); 4179 else
3872 else 4180 found = oblookup_considering_shorthand (obarray, read_buffer,
3873 tem = oblookup_considering_shorthand (obarray, read_buffer,
3874 nchars, nbytes, &longhand, 4181 nchars, nbytes, &longhand,
3875 &longhand_chars, 4182 &longhand_chars,
3876 &longhand_bytes); 4183 &longhand_bytes);
3877 4184
3878 if (SYMBOLP (tem)) 4185 if (SYMBOLP (found))
3879 result = tem; 4186 result = found;
3880 else if (longhand) 4187 else if (longhand)
3881 { 4188 {
3882 Lisp_Object name 4189 Lisp_Object name = make_specified_string (longhand,
3883 = make_specified_string (longhand, longhand_chars, 4190 longhand_chars,
3884 longhand_bytes, multibyte); 4191 longhand_bytes,
3885 xfree (longhand); 4192 multibyte);
3886 result = intern_driver (name, obarray, tem); 4193 xfree (longhand);
3887 } 4194 result = intern_driver (name, obarray, found);
3888 else 4195 }
3889 { 4196 else
3890 Lisp_Object name 4197 {
3891 = make_specified_string (read_buffer, nchars, nbytes, 4198 Lisp_Object name = make_specified_string (read_buffer, nchars,
3892 multibyte); 4199 nbytes, multibyte);
3893 result = intern_driver (name, obarray, tem); 4200 result = intern_driver (name, obarray, found);
3894 } 4201 }
3895 } 4202 }
3896 if (locate_syms 4203 if (locate_syms && !NILP (result))
3897 && !NILP (result) 4204 result = build_symbol_with_pos (result,
3898 ) 4205 make_fixnum (start_position));
3899 result = build_symbol_with_pos (result,
3900 make_fixnum (start_position));
3901 4206
3902 return unbind_to (count, result); 4207 obj = result;
3903 } 4208 break;
3904 } 4209 }
3905 } 4210 }
4211
4212 /* We have read an object in `obj'. Use the stack to decide what to
4213 do with it. */
4214 while (rdstack.sp > base_sp)
4215 {
4216 struct read_stack_entry *e = read_stack_top ();
4217 switch (e->type)
4218 {
4219 case RE_list_start:
4220 e->type = RE_list;
4221 e->u.list.head = e->u.list.tail = Fcons (obj, Qnil);
4222 goto read_obj;
4223
4224 case RE_list:
4225 {
4226 Lisp_Object tl = Fcons (obj, Qnil);
4227 XSETCDR (e->u.list.tail, tl);
4228 e->u.list.tail = tl;
4229 goto read_obj;
4230 }
4231
4232 case RE_list_dot:
4233 {
4234 skip_space_and_comments (readcharfun);
4235 int ch = READCHAR;
4236 if (ch != ')')
4237 invalid_syntax ("expected )", readcharfun);
4238 XSETCDR (e->u.list.tail, obj);
4239 read_stack_pop ();
4240 obj = e->u.list.head;
4241 break;
4242 }
4243
4244 case RE_vector:
4245 case RE_record:
4246 case RE_char_table:
4247 case RE_sub_char_table:
4248 case RE_byte_code:
4249 case RE_string_props:
4250 e->u.vector.elems = Fcons (obj, e->u.vector.elems);
4251 goto read_obj;
4252
4253 case RE_special:
4254 read_stack_pop ();
4255 obj = list2 (e->u.special.symbol, obj);
4256 break;
4257
4258 case RE_numbered:
4259 {
4260 read_stack_pop ();
4261 Lisp_Object placeholder = e->u.numbered.placeholder;
4262 if (CONSP (obj))
4263 {
4264 if (BASE_EQ (obj, placeholder))
4265 /* Catch silly games like #1=#1# */
4266 invalid_syntax ("nonsensical self-reference", readcharfun);
4267
4268 /* Optimisation: since the placeholder is already
4269 a cons, repurpose it as the actual value.
4270 This allows us to skip the substitution below,
4271 since the placeholder is already referenced
4272 inside OBJ at the appropriate places. */
4273 Fsetcar (placeholder, XCAR (obj));
4274 Fsetcdr (placeholder, XCDR (obj));
4275
4276 struct Lisp_Hash_Table *h2
4277 = XHASH_TABLE (read_objects_completed);
4278 Lisp_Object hash;
4279 ptrdiff_t i = hash_lookup (h2, placeholder, &hash);
4280 eassert (i < 0);
4281 hash_put (h2, placeholder, Qnil, hash);
4282 obj = placeholder;
4283 }
4284 else
4285 {
4286 /* If it can be recursive, remember it for future
4287 substitutions. */
4288 if (!SYMBOLP (obj) && !NUMBERP (obj)
4289 && !(STRINGP (obj) && !string_intervals (obj)))
4290 {
4291 struct Lisp_Hash_Table *h2
4292 = XHASH_TABLE (read_objects_completed);
4293 Lisp_Object hash;
4294 ptrdiff_t i = hash_lookup (h2, obj, &hash);
4295 eassert (i < 0);
4296 hash_put (h2, obj, Qnil, hash);
4297 }
4298
4299 /* Now put it everywhere the placeholder was... */
4300 Flread__substitute_object_in_subtree (obj, placeholder,
4301 read_objects_completed);
4302
4303 /* ...and #n# will use the real value from now on. */
4304 struct Lisp_Hash_Table *h = XHASH_TABLE (read_objects_map);
4305 Lisp_Object hash;
4306 ptrdiff_t i = hash_lookup (h, e->u.numbered.number, &hash);
4307 eassert (i >= 0);
4308 set_hash_value_slot (h, i, obj);
4309 }
4310 break;
4311 }
4312 }
4313 }
4314
4315 return unbind_to (count, obj);
3906} 4316}
4317
3907 4318
3908DEFUN ("lread--substitute-object-in-subtree", 4319DEFUN ("lread--substitute-object-in-subtree",
3909 Flread__substitute_object_in_subtree, 4320 Flread__substitute_object_in_subtree,
@@ -4150,214 +4561,6 @@ string_to_number (char const *string, int base, ptrdiff_t *plen)
4150} 4561}
4151 4562
4152 4563
4153static Lisp_Object
4154read_vector (Lisp_Object readcharfun, bool bytecodeflag, bool locate_syms)
4155{
4156 Lisp_Object tem = read_list (1, readcharfun, locate_syms);
4157 ptrdiff_t size = list_length (tem);
4158 Lisp_Object vector = make_nil_vector (size);
4159
4160 /* Avoid accessing past the end of a vector if the vector is too
4161 small to be valid for bytecode. */
4162 bytecodeflag &= COMPILED_STACK_DEPTH < size;
4163
4164 Lisp_Object *ptr = XVECTOR (vector)->contents;
4165 for (ptrdiff_t i = 0; i < size; i++)
4166 {
4167 Lisp_Object item = Fcar (tem);
4168 /* If `load-force-doc-strings' is t when reading a lazily-loaded
4169 bytecode object, the docstring containing the bytecode and
4170 constants values must be treated as unibyte and passed to
4171 Fread, to get the actual bytecode string and constants vector. */
4172 if (bytecodeflag && load_force_doc_strings)
4173 {
4174 if (i == COMPILED_BYTECODE)
4175 {
4176 if (!STRINGP (item))
4177 error ("Invalid byte code");
4178
4179 /* Delay handling the bytecode slot until we know whether
4180 it is lazily-loaded (we can tell by whether the
4181 constants slot is nil). */
4182 ASET (vector, COMPILED_CONSTANTS, item);
4183 item = Qnil;
4184 }
4185 else if (i == COMPILED_CONSTANTS)
4186 {
4187 Lisp_Object bytestr = ptr[COMPILED_CONSTANTS];
4188
4189 if (NILP (item))
4190 {
4191 /* Coerce string to unibyte (like string-as-unibyte,
4192 but without generating extra garbage and
4193 guaranteeing no change in the contents). */
4194 STRING_SET_CHARS (bytestr, SBYTES (bytestr));
4195 STRING_SET_UNIBYTE (bytestr);
4196
4197 item = Fread (Fcons (bytestr, readcharfun));
4198 if (!CONSP (item))
4199 error ("Invalid byte code");
4200
4201 struct Lisp_Cons *otem = XCONS (item);
4202 bytestr = XCAR (item);
4203 item = XCDR (item);
4204 free_cons (otem);
4205 }
4206
4207 /* Now handle the bytecode slot. */
4208 ASET (vector, COMPILED_BYTECODE, bytestr);
4209 }
4210 else if (i == COMPILED_DOC_STRING
4211 && STRINGP (item)
4212 && ! STRING_MULTIBYTE (item))
4213 {
4214 if (EQ (readcharfun, Qget_emacs_mule_file_char))
4215 item = Fdecode_coding_string (item, Qemacs_mule, Qnil, Qnil);
4216 else
4217 item = Fstring_as_multibyte (item);
4218 }
4219 }
4220 ASET (vector, i, item);
4221 struct Lisp_Cons *otem = XCONS (tem);
4222 tem = Fcdr (tem);
4223 free_cons (otem);
4224 }
4225 return vector;
4226}
4227
4228/* FLAG means check for ']' to terminate rather than ')' and '.'.
4229 LOCATE_SYMS true means read symbol occurrencess as symbols with
4230 position. */
4231
4232static Lisp_Object
4233read_list (bool flag, Lisp_Object readcharfun, bool locate_syms)
4234{
4235 Lisp_Object val, tail;
4236 Lisp_Object elt, tem;
4237 /* 0 is the normal case.
4238 1 means this list is a doc reference; replace it with the number 0.
4239 2 means this list is a doc reference; replace it with the doc string. */
4240 int doc_reference = 0;
4241
4242 /* Initialize this to 1 if we are reading a list. */
4243 bool first_in_list = flag <= 0;
4244
4245 val = Qnil;
4246 tail = Qnil;
4247
4248 while (1)
4249 {
4250 int ch;
4251 elt = read1 (readcharfun, &ch, first_in_list, locate_syms);
4252
4253 first_in_list = 0;
4254
4255 /* While building, if the list starts with #$, treat it specially. */
4256 if (EQ (elt, Vload_file_name)
4257 && ! NILP (elt))
4258 {
4259 if (!NILP (Vpurify_flag))
4260 doc_reference = 0;
4261 else if (load_force_doc_strings)
4262 doc_reference = 2;
4263 }
4264 if (ch)
4265 {
4266 if (flag > 0)
4267 {
4268 if (ch == ']')
4269 return val;
4270 invalid_syntax (") or . in a vector", readcharfun);
4271 }
4272 if (ch == ')')
4273 return val;
4274 if (ch == '.')
4275 {
4276 if (!NILP (tail))
4277 XSETCDR (tail, read0 (readcharfun, locate_syms));
4278 else
4279 val = read0 (readcharfun, locate_syms);
4280 read1 (readcharfun, &ch, 0, locate_syms);
4281
4282 if (ch == ')')
4283 {
4284 if (doc_reference == 2 && FIXNUMP (XCDR (val)))
4285 {
4286 char *saved = NULL;
4287 file_offset saved_position;
4288 /* Get a doc string from the file we are loading.
4289 If it's in saved_doc_string, get it from there.
4290
4291 Here, we don't know if the string is a
4292 bytecode string or a doc string. As a
4293 bytecode string must be unibyte, we always
4294 return a unibyte string. If it is actually a
4295 doc string, caller must make it
4296 multibyte. */
4297
4298 /* Position is negative for user variables. */
4299 EMACS_INT pos = eabs (XFIXNUM (XCDR (val)));
4300 if (pos >= saved_doc_string_position
4301 && pos < (saved_doc_string_position
4302 + saved_doc_string_length))
4303 {
4304 saved = saved_doc_string;
4305 saved_position = saved_doc_string_position;
4306 }
4307 /* Look in prev_saved_doc_string the same way. */
4308 else if (pos >= prev_saved_doc_string_position
4309 && pos < (prev_saved_doc_string_position
4310 + prev_saved_doc_string_length))
4311 {
4312 saved = prev_saved_doc_string;
4313 saved_position = prev_saved_doc_string_position;
4314 }
4315 if (saved)
4316 {
4317 ptrdiff_t start = pos - saved_position;
4318 ptrdiff_t from, to;
4319
4320 /* Process quoting with ^A,
4321 and find the end of the string,
4322 which is marked with ^_ (037). */
4323 for (from = start, to = start;
4324 saved[from] != 037;)
4325 {
4326 int c = saved[from++];
4327 if (c == 1)
4328 {
4329 c = saved[from++];
4330 saved[to++] = (c == 1 ? c
4331 : c == '0' ? 0
4332 : c == '_' ? 037
4333 : c);
4334 }
4335 else
4336 saved[to++] = c;
4337 }
4338
4339 return make_unibyte_string (saved + start,
4340 to - start);
4341 }
4342 else
4343 return get_doc_string (val, 1, 0);
4344 }
4345
4346 return val;
4347 }
4348 invalid_syntax (". in wrong context", readcharfun);
4349 }
4350 invalid_syntax ("] in a list", readcharfun);
4351 }
4352 tem = list1 (elt);
4353 if (!NILP (tail))
4354 XSETCDR (tail, tem);
4355 else
4356 val = tem;
4357 tail = tem;
4358 }
4359}
4360
4361static Lisp_Object initial_obarray; 4564static Lisp_Object initial_obarray;
4362 4565
4363/* `oblookup' stores the bucket number here, for the sake of Funintern. */ 4566/* `oblookup' stores the bucket number here, for the sake of Funintern. */
@@ -4464,7 +4667,7 @@ define_symbol (Lisp_Object sym, char const *str)
4464 4667
4465 /* Qunbound is uninterned, so that it's not confused with any symbol 4668 /* Qunbound is uninterned, so that it's not confused with any symbol
4466 'unbound' created by a Lisp program. */ 4669 'unbound' created by a Lisp program. */
4467 if (! EQ (sym, Qunbound)) 4670 if (! BASE_EQ (sym, Qunbound))
4468 { 4671 {
4469 Lisp_Object bucket = oblookup (initial_obarray, str, len, len); 4672 Lisp_Object bucket = oblookup (initial_obarray, str, len, len);
4470 eassert (FIXNUMP (bucket)); 4673 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)
1118 Lisp_Object title; 1118 Lisp_Object title;
1119 const char *error_name = NULL; 1119 const char *error_name = NULL;
1120 Lisp_Object selection = Qnil; 1120 Lisp_Object selection = Qnil;
1121 struct frame *f = NULL; 1121 struct frame *f;
1122 Lisp_Object x, y, window; 1122 Lisp_Object x, y, window;
1123 int menuflags = 0; 1123 int menuflags = 0;
1124 specpdl_ref specpdl_count = SPECPDL_INDEX (); 1124 specpdl_ref specpdl_count = SPECPDL_INDEX ();
@@ -1269,9 +1269,9 @@ x_popup_menu_1 (Lisp_Object position, Lisp_Object menu)
1269 } 1269 }
1270 } 1270 }
1271 else 1271 else
1272 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME, 1272 /* ??? Not really clean; should be Qwindow_or_framep
1273 but I don't want to make one now. */ 1273 but I don't want to make one now. */
1274 CHECK_WINDOW (window); 1274 wrong_type_argument (Qwindowp, window);
1275 1275
1276 xpos += check_integer_range (x, 1276 xpos += check_integer_range (x,
1277 (xpos < INT_MIN - MOST_NEGATIVE_FIXNUM 1277 (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)
201 return; 201 return;
202 if (FRAME_LIVE_P (f) 202 if (FRAME_LIVE_P (f)
203 && !EQ (f->minibuffer_window, of->minibuffer_window) 203 && !EQ (f->minibuffer_window, of->minibuffer_window)
204 && WINDOW_LIVE_P (f->minibuffer_window) /* F not a tootip frame */ 204 && WINDOW_LIVE_P (f->minibuffer_window) /* F not a tooltip frame */
205 && WINDOW_LIVE_P (of->minibuffer_window)) 205 && WINDOW_LIVE_P (of->minibuffer_window))
206 { 206 {
207 zip_minibuffer_stacks (f->minibuffer_window, of->minibuffer_window); 207 zip_minibuffer_stacks (f->minibuffer_window, of->minibuffer_window);
208 if (for_deletion && XFRAME (MB_frame) != of) 208 if (for_deletion && XFRAME (MB_frame) != of)
209 MB_frame = selected_frame; 209 MB_frame = selected_frame;
210 if (!for_deletion
211 && MINI_WINDOW_P (XWINDOW (FRAME_SELECTED_WINDOW (of))))
212 {
213 Lisp_Object old_frame;
214 XSETFRAME (old_frame, of);
215 Fset_frame_selected_window (old_frame,
216 Fframe_first_window (old_frame), Qnil);
217 }
218 } 210 }
219} 211}
220 212
@@ -265,7 +257,7 @@ without invoking the usual minibuffer commands. */)
265 257
266static void read_minibuf_unwind (void); 258static void read_minibuf_unwind (void);
267static void minibuffer_unwind (void); 259static void minibuffer_unwind (void);
268static void run_exit_minibuf_hook (void); 260static void run_exit_minibuf_hook (Lisp_Object minibuf);
269 261
270 262
271/* Read a Lisp object from VAL and return it. If VAL is an empty 263/* 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,
749 separately from read_minibuf_unwind because we need to make sure that 741 separately from read_minibuf_unwind because we need to make sure that
750 read_minibuf_unwind is fully executed even if exit-minibuffer-hook 742 read_minibuf_unwind is fully executed even if exit-minibuffer-hook
751 signals an error. --Stef */ 743 signals an error. --Stef */
752 record_unwind_protect_void (run_exit_minibuf_hook); 744 record_unwind_protect (run_exit_minibuf_hook, minibuffer);
753 745
754 /* Now that we can restore all those variables, start changing them. */ 746 /* Now that we can restore all those variables, start changing them. */
755 747
@@ -768,7 +760,7 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt,
768 760
769 /* If variable is unbound, make it nil. */ 761 /* If variable is unbound, make it nil. */
770 histval = find_symbol_value (histvar); 762 histval = find_symbol_value (histvar);
771 if (EQ (histval, Qunbound)) 763 if (BASE_EQ (histval, Qunbound))
772 { 764 {
773 Fset (histvar, Qnil); 765 Fset (histvar, Qnil);
774 histval = Qnil; 766 histval = Qnil;
@@ -1076,9 +1068,14 @@ static EMACS_INT minibuf_c_loop_level (EMACS_INT depth)
1076} 1068}
1077 1069
1078static void 1070static void
1079run_exit_minibuf_hook (void) 1071run_exit_minibuf_hook (Lisp_Object minibuf)
1080{ 1072{
1073 specpdl_ref count = SPECPDL_INDEX ();
1074 record_unwind_current_buffer ();
1075 if (BUFFER_LIVE_P (XBUFFER (minibuf)))
1076 Fset_buffer (minibuf);
1081 safe_run_hooks (Qminibuffer_exit_hook); 1077 safe_run_hooks (Qminibuffer_exit_hook);
1078 unbind_to (count, Qnil);
1082} 1079}
1083 1080
1084/* This variable records the expired minibuffer's frame between the 1081/* This variable records the expired minibuffer's frame between the
@@ -1696,7 +1693,8 @@ or from one of the possible completions. */)
1696 else /* if (type == hash_table) */ 1693 else /* if (type == hash_table) */
1697 { 1694 {
1698 while (idx < HASH_TABLE_SIZE (XHASH_TABLE (collection)) 1695 while (idx < HASH_TABLE_SIZE (XHASH_TABLE (collection))
1699 && EQ (HASH_KEY (XHASH_TABLE (collection), idx), Qunbound)) 1696 && BASE_EQ (HASH_KEY (XHASH_TABLE (collection), idx),
1697 Qunbound))
1700 idx++; 1698 idx++;
1701 if (idx >= HASH_TABLE_SIZE (XHASH_TABLE (collection))) 1699 if (idx >= HASH_TABLE_SIZE (XHASH_TABLE (collection)))
1702 break; 1700 break;
@@ -1933,7 +1931,8 @@ with a space are ignored unless STRING itself starts with a space. */)
1933 else /* if (type == 3) */ 1931 else /* if (type == 3) */
1934 { 1932 {
1935 while (idx < HASH_TABLE_SIZE (XHASH_TABLE (collection)) 1933 while (idx < HASH_TABLE_SIZE (XHASH_TABLE (collection))
1936 && EQ (HASH_KEY (XHASH_TABLE (collection), idx), Qunbound)) 1934 && BASE_EQ (HASH_KEY (XHASH_TABLE (collection), idx),
1935 Qunbound))
1937 idx++; 1936 idx++;
1938 if (idx >= HASH_TABLE_SIZE (XHASH_TABLE (collection))) 1937 if (idx >= HASH_TABLE_SIZE (XHASH_TABLE (collection)))
1939 break; 1938 break;
@@ -2012,6 +2011,8 @@ REQUIRE-MATCH can take the following values:
2012 input, but she needs to confirm her choice if she called 2011 input, but she needs to confirm her choice if she called
2013 `minibuffer-complete' right before `minibuffer-complete-and-exit' 2012 `minibuffer-complete' right before `minibuffer-complete-and-exit'
2014 and the input is not an element of COLLECTION. 2013 and the input is not an element of COLLECTION.
2014- a function, which will be called with the input as the parameter.
2015 If it returns a non-nil value, the minibuffer is exited with that value.
2015- anything else behaves like t except that typing RET does not exit if it 2016- anything else behaves like t except that typing RET does not exit if it
2016 does non-null completion. 2017 does non-null completion.
2017 2018
@@ -2140,7 +2141,7 @@ the values STRING, PREDICATE and `lambda'. */)
2140 for (i = 0; i < HASH_TABLE_SIZE (h); ++i) 2141 for (i = 0; i < HASH_TABLE_SIZE (h); ++i)
2141 { 2142 {
2142 tem = HASH_KEY (h, i); 2143 tem = HASH_KEY (h, i);
2143 if (EQ (tem, Qunbound)) continue; 2144 if (BASE_EQ (tem, Qunbound)) continue;
2144 Lisp_Object strkey = (SYMBOLP (tem) ? Fsymbol_name (tem) : tem); 2145 Lisp_Object strkey = (SYMBOLP (tem) ? Fsymbol_name (tem) : tem);
2145 if (!STRINGP (strkey)) continue; 2146 if (!STRINGP (strkey)) continue;
2146 if (EQ (Fcompare_strings (string, Qnil, Qnil, 2147 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)
47#ifdef NS_IMPL_COCOA 47#ifdef NS_IMPL_COCOA
48#include <IOKit/graphics/IOGraphicsLib.h> 48#include <IOKit/graphics/IOGraphicsLib.h>
49#include "macfont.h" 49#include "macfont.h"
50
51#if MAC_OS_X_VERSION_MAX_ALLOWED >= 120000
52#include <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
53#if MAC_OS_X_VERSION_MIN_REQUIRED >= 120000
54#define IOMasterPort IOMainPort
55#endif
56#endif
50#endif 57#endif
51 58
52#ifdef HAVE_NS 59#ifdef HAVE_NS
53 60
54static EmacsTooltip *ns_tooltip = nil; 61static EmacsTooltip *ns_tooltip = nil;
55 62
63/* The frame of the currently visible tooltip, or nil if none. */
64static Lisp_Object tip_frame;
65
66/* The X and Y deltas of the last call to `x-show-tip'. */
67static Lisp_Object tip_dx, tip_dy;
68
69/* The window-system window corresponding to the frame of the
70 currently visible tooltip. */
71static NSWindow *tip_window;
72
73/* A timer that hides or deletes the currently visible tooltip when it
74 fires. */
75static Lisp_Object tip_timer;
76
77/* STRING argument of last `x-show-tip' call. */
78static Lisp_Object tip_last_string;
79
80/* Normalized FRAME argument of last `x-show-tip' call. */
81static Lisp_Object tip_last_frame;
82
83/* PARMS argument of last `x-show-tip' call. */
84static Lisp_Object tip_last_parms;
85
56/* Static variables to handle AppleScript execution. */ 86/* Static variables to handle AppleScript execution. */
57static Lisp_Object as_script, *as_result; 87static Lisp_Object as_script, *as_result;
58static int as_status; 88static int as_status;
@@ -769,11 +799,13 @@ ns_implicitly_set_icon_type (struct frame *f)
769 Lisp_Object chain, elt; 799 Lisp_Object chain, elt;
770 NSAutoreleasePool *pool; 800 NSAutoreleasePool *pool;
771 BOOL setMini = YES; 801 BOOL setMini = YES;
802 NSWorkspace *workspace;
772 803
773 NSTRACE ("ns_implicitly_set_icon_type"); 804 NSTRACE ("ns_implicitly_set_icon_type");
774 805
775 block_input (); 806 block_input ();
776 pool = [[NSAutoreleasePool alloc] init]; 807 pool = [[NSAutoreleasePool alloc] init];
808 workspace = [NSWorkspace sharedWorkspace];
777 if (f->output_data.ns->miniimage 809 if (f->output_data.ns->miniimage
778 && [[NSString stringWithLispString:f->name] 810 && [[NSString stringWithLispString:f->name]
779 isEqualToString: [(NSImage *)f->output_data.ns->miniimage name]]) 811 isEqualToString: [(NSImage *)f->output_data.ns->miniimage name]])
@@ -818,7 +850,21 @@ ns_implicitly_set_icon_type (struct frame *f)
818 850
819 if (image == nil) 851 if (image == nil)
820 { 852 {
821 image = [[[NSWorkspace sharedWorkspace] iconForFileType: @"text"] retain]; 853#ifndef NS_IMPL_GNUSTEP
854#if MAC_OS_X_VERSION_MAX_ALLOWED >= 120000
855#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000
856 if ([workspace respondsToSelector: @selector (iconForContentType:)])
857#endif
858 image = [[workspace iconForContentType:
859 [UTType typeWithIdentifier: @"text"]] retain];
860#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000
861 else
862#endif
863#endif
864#endif
865#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000
866 image = [[workspace iconForFileType: @"text"] retain];
867#endif
822 setMini = NO; 868 setMini = NO;
823 } 869 }
824 870
@@ -1021,7 +1067,7 @@ frame_parm_handler ns_frame_parm_handlers[] =
1021/* Handler for signals raised during x_create_frame. 1067/* Handler for signals raised during x_create_frame.
1022 FRAME is the frame which is partially constructed. */ 1068 FRAME is the frame which is partially constructed. */
1023 1069
1024static void 1070static Lisp_Object
1025unwind_create_frame (Lisp_Object frame) 1071unwind_create_frame (Lisp_Object frame)
1026{ 1072{
1027 struct frame *f = XFRAME (frame); 1073 struct frame *f = XFRAME (frame);
@@ -1030,7 +1076,7 @@ unwind_create_frame (Lisp_Object frame)
1030 display is disconnected after the frame has become official, but 1076 display is disconnected after the frame has become official, but
1031 before x_create_frame removes the unwind protect. */ 1077 before x_create_frame removes the unwind protect. */
1032 if (!FRAME_LIVE_P (f)) 1078 if (!FRAME_LIVE_P (f))
1033 return; 1079 return Qnil;
1034 1080
1035 /* If frame is ``official'', nothing to do. */ 1081 /* If frame is ``official'', nothing to do. */
1036 if (NILP (Fmemq (frame, Vframe_list))) 1082 if (NILP (Fmemq (frame, Vframe_list)))
@@ -1057,7 +1103,18 @@ unwind_create_frame (Lisp_Object frame)
1057 /* Check that reference counts are indeed correct. */ 1103 /* Check that reference counts are indeed correct. */
1058 eassert (dpyinfo->terminal->image_cache->refcount == image_cache_refcount); 1104 eassert (dpyinfo->terminal->image_cache->refcount == image_cache_refcount);
1059#endif 1105#endif
1106
1107 return Qt;
1060 } 1108 }
1109
1110 return Qnil;
1111}
1112
1113
1114static void
1115do_unwind_create_frame (Lisp_Object frame)
1116{
1117 unwind_create_frame (frame);
1061} 1118}
1062 1119
1063/* 1120/*
@@ -1191,7 +1248,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
1191 FRAME_DISPLAY_INFO (f) = dpyinfo; 1248 FRAME_DISPLAY_INFO (f) = dpyinfo;
1192 1249
1193 /* With FRAME_DISPLAY_INFO set up, this unwind-protect is safe. */ 1250 /* With FRAME_DISPLAY_INFO set up, this unwind-protect is safe. */
1194 record_unwind_protect (unwind_create_frame, frame); 1251 record_unwind_protect (do_unwind_create_frame, frame);
1195 1252
1196 f->output_data.ns->window_desc = desc_ctr++; 1253 f->output_data.ns->window_desc = desc_ctr++;
1197 if (TYPE_RANGED_FIXNUMP (Window, parent)) 1254 if (TYPE_RANGED_FIXNUMP (Window, parent))
@@ -1726,7 +1783,20 @@ Optional arg DIR_ONLY_P, if non-nil, means choose only directories. */)
1726 ns_fd_data.ret = NO; 1783 ns_fd_data.ret = NO;
1727#ifdef NS_IMPL_COCOA 1784#ifdef NS_IMPL_COCOA
1728 if (! NILP (mustmatch) || ! NILP (dir_only_p)) 1785 if (! NILP (mustmatch) || ! NILP (dir_only_p))
1729 [panel setAllowedFileTypes: nil]; 1786 {
1787#if MAC_OS_X_VERSION_MAX_ALLOWED >= 120000
1788#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000
1789 if ([panel respondsToSelector: @selector (setAllowedContentTypes:)])
1790#endif
1791 [panel setAllowedContentTypes: [NSArray array]];
1792#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000
1793 else
1794#endif
1795#endif
1796#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000
1797 [panel setAllowedFileTypes: nil];
1798#endif
1799 }
1730 if (dirS) [panel setDirectoryURL: [NSURL fileURLWithPath: dirS]]; 1800 if (dirS) [panel setDirectoryURL: [NSURL fileURLWithPath: dirS]];
1731 if (initS && NILP (Ffile_directory_p (init))) 1801 if (initS && NILP (Ffile_directory_p (init)))
1732 [panel setNameFieldStringValue: [initS lastPathComponent]]; 1802 [panel setNameFieldStringValue: [initS lastPathComponent]];
@@ -1792,7 +1862,7 @@ ns_get_defaults_value (const char *key)
1792DEFUN ("ns-get-resource", Fns_get_resource, Sns_get_resource, 2, 2, 0, 1862DEFUN ("ns-get-resource", Fns_get_resource, Sns_get_resource, 2, 2, 0,
1793 doc: /* Return the value of the property NAME of OWNER from the defaults database. 1863 doc: /* Return the value of the property NAME of OWNER from the defaults database.
1794If OWNER is nil, Emacs is assumed. */) 1864If OWNER is nil, Emacs is assumed. */)
1795 (Lisp_Object owner, Lisp_Object name) 1865 (Lisp_Object owner, Lisp_Object name)
1796{ 1866{
1797 const char *value; 1867 const char *value;
1798 1868
@@ -1813,7 +1883,7 @@ DEFUN ("ns-set-resource", Fns_set_resource, Sns_set_resource, 3, 3, 0,
1813 doc: /* Set property NAME of OWNER to VALUE, from the defaults database. 1883 doc: /* Set property NAME of OWNER to VALUE, from the defaults database.
1814If OWNER is nil, Emacs is assumed. 1884If OWNER is nil, Emacs is assumed.
1815If VALUE is nil, the default is removed. */) 1885If VALUE is nil, the default is removed. */)
1816 (Lisp_Object owner, Lisp_Object name, Lisp_Object value) 1886 (Lisp_Object owner, Lisp_Object name, Lisp_Object value)
1817{ 1887{
1818 check_window_system (NULL); 1888 check_window_system (NULL);
1819 if (NILP (owner)) 1889 if (NILP (owner))
@@ -1840,7 +1910,7 @@ DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
1840 Sx_server_max_request_size, 1910 Sx_server_max_request_size,
1841 0, 1, 0, 1911 0, 1, 0,
1842 doc: /* SKIP: real doc in xfns.c. */) 1912 doc: /* SKIP: real doc in xfns.c. */)
1843 (Lisp_Object terminal) 1913 (Lisp_Object terminal)
1844{ 1914{
1845 check_ns_display_info (terminal); 1915 check_ns_display_info (terminal);
1846 /* This function has no real equivalent under Nextstep. Return nil to 1916 /* This function has no real equivalent under Nextstep. Return nil to
@@ -2702,7 +2772,8 @@ Internal use only, use `display-monitor-attributes-list' instead. */)
2702 } 2772 }
2703 else 2773 else
2704 { 2774 {
2705 // Flip y coordinate as NS has y starting from the bottom. 2775 /* Flip y coordinate as NS screen coordinates originate from
2776 the bottom. */
2706 y = (short) (primary_display_height - fr.size.height - fr.origin.y); 2777 y = (short) (primary_display_height - fr.size.height - fr.origin.y);
2707 vy = (short) (primary_display_height - 2778 vy = (short) (primary_display_height -
2708 vfr.size.height - vfr.origin.y); 2779 vfr.size.height - vfr.origin.y);
@@ -2714,11 +2785,12 @@ Internal use only, use `display-monitor-attributes-list' instead. */)
2714 m->geom.height = (unsigned short) fr.size.height; 2785 m->geom.height = (unsigned short) fr.size.height;
2715 2786
2716 m->work.x = (short) vfr.origin.x; 2787 m->work.x = (short) vfr.origin.x;
2717 // y is flipped on NS, so vy - y are pixels missing at the bottom, 2788 /* y is flipped on NS, so vy - y are pixels missing at the
2718 // and fr.size.height - vfr.size.height are pixels missing in total. 2789 bottom, and fr.size.height - vfr.size.height are pixels
2719 // Pixels missing at top are 2790 missing in total.
2720 // fr.size.height - vfr.size.height - vy + y. 2791
2721 // work.y is then pixels missing at top + y. 2792 Pixels missing at top are fr.size.height - vfr.size.height -
2793 vy + y. work.y is then pixels missing at top + y. */
2722 m->work.y = (short) (fr.size.height - vfr.size.height) - vy + y + y; 2794 m->work.y = (short) (fr.size.height - vfr.size.height) - vy + y + y;
2723 m->work.width = (unsigned short) vfr.size.width; 2795 m->work.width = (unsigned short) vfr.size.width;
2724 m->work.height = (unsigned short) vfr.size.height; 2796 m->work.height = (unsigned short) vfr.size.height;
@@ -2733,13 +2805,14 @@ Internal use only, use `display-monitor-attributes-list' instead. */)
2733 } 2805 }
2734 2806
2735#else 2807#else
2736 // Assume 92 dpi as x-display-mm-height/x-display-mm-width does. 2808 /* Assume 92 dpi as x-display-mm-height and x-display-mm-width
2809 do. */
2737 m->mm_width = (int) (25.4 * fr.size.width / 92.0); 2810 m->mm_width = (int) (25.4 * fr.size.width / 92.0);
2738 m->mm_height = (int) (25.4 * fr.size.height / 92.0); 2811 m->mm_height = (int) (25.4 * fr.size.height / 92.0);
2739#endif 2812#endif
2740 } 2813 }
2741 2814
2742 // Primary monitor is always first for NS. 2815 /* Primary monitor is always ordered first for NS. */
2743 attributes_list = ns_make_monitor_attribute_list (monitors, n_monitors, 2816 attributes_list = ns_make_monitor_attribute_list (monitors, n_monitors,
2744 0, "NS"); 2817 0, "NS");
2745 2818
@@ -2769,16 +2842,10 @@ DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
2769 return make_fixnum (1 << min (dpyinfo->n_planes, 24)); 2842 return make_fixnum (1 << min (dpyinfo->n_planes, 24));
2770} 2843}
2771 2844
2772/* TODO: move to xdisp or similar */
2773static void 2845static void
2774compute_tip_xy (struct frame *f, 2846compute_tip_xy (struct frame *f, Lisp_Object parms, Lisp_Object dx,
2775 Lisp_Object parms, 2847 Lisp_Object dy, int width, int height, int *root_x,
2776 Lisp_Object dx, 2848 int *root_y)
2777 Lisp_Object dy,
2778 int width,
2779 int height,
2780 int *root_x,
2781 int *root_y)
2782{ 2849{
2783 Lisp_Object left, top, right, bottom; 2850 Lisp_Object left, top, right, bottom;
2784 NSPoint pt; 2851 NSPoint pt;
@@ -2847,6 +2914,299 @@ compute_tip_xy (struct frame *f,
2847 *root_y = screen.frame.origin.y + screen.frame.size.height - height; 2914 *root_y = screen.frame.origin.y + screen.frame.size.height - height;
2848} 2915}
2849 2916
2917static void
2918unwind_create_tip_frame (Lisp_Object frame)
2919{
2920 Lisp_Object deleted;
2921
2922 deleted = unwind_create_frame (frame);
2923 if (EQ (deleted, Qt))
2924 {
2925 tip_window = NULL;
2926 tip_frame = Qnil;
2927 }
2928}
2929
2930/* Create a frame for a tooltip on the display described by DPYINFO.
2931 PARMS is a list of frame parameters. TEXT is the string to
2932 display in the tip frame. Value is the frame.
2933
2934 Note that functions called here, esp. gui_default_parameter can
2935 signal errors, for instance when a specified color name is
2936 undefined. We have to make sure that we're in a consistent state
2937 when this happens. */
2938
2939static Lisp_Object
2940ns_create_tip_frame (struct ns_display_info *dpyinfo, Lisp_Object parms)
2941{
2942 struct frame *f;
2943 Lisp_Object frame;
2944 Lisp_Object name;
2945 specpdl_ref count = SPECPDL_INDEX ();
2946 bool face_change_before = face_change;
2947
2948 if (!dpyinfo->terminal->name)
2949 error ("Terminal is not live, can't create new frames on it");
2950
2951 parms = Fcopy_alist (parms);
2952
2953 /* Get the name of the frame to use for resource lookup. */
2954 name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name",
2955 RES_TYPE_STRING);
2956 if (!STRINGP (name)
2957 && !EQ (name, Qunbound)
2958 && !NILP (name))
2959 error ("Invalid frame name--not a string or nil");
2960
2961 frame = Qnil;
2962 f = make_frame (false);
2963 f->wants_modeline = false;
2964 XSETFRAME (frame, f);
2965 record_unwind_protect (unwind_create_tip_frame, frame);
2966
2967 f->terminal = dpyinfo->terminal;
2968
2969 f->output_method = output_ns;
2970 f->output_data.ns = xzalloc (sizeof *f->output_data.ns);
2971 f->tooltip = true;
2972
2973 FRAME_FONTSET (f) = -1;
2974 FRAME_DISPLAY_INFO (f) = dpyinfo;
2975
2976 block_input ();
2977#ifdef NS_IMPL_COCOA
2978 mac_register_font_driver (f);
2979#else
2980 register_font_driver (&nsfont_driver, f);
2981#endif
2982 unblock_input ();
2983
2984 image_cache_refcount =
2985 FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
2986
2987 gui_default_parameter (f, parms, Qfont_backend, Qnil,
2988 "fontBackend", "FontBackend", RES_TYPE_STRING);
2989
2990 {
2991#ifdef NS_IMPL_COCOA
2992 /* use for default font name */
2993 id font = [NSFont userFixedPitchFontOfSize: -1.0]; /* default */
2994 gui_default_parameter (f, parms, Qfontsize,
2995 make_fixnum (0 /* (int)[font pointSize] */),
2996 "fontSize", "FontSize", RES_TYPE_NUMBER);
2997 // Remove ' Regular', not handled by backends.
2998 char *fontname = xstrdup ([[font displayName] UTF8String]);
2999 int len = strlen (fontname);
3000 if (len > 8 && strcmp (fontname + len - 8, " Regular") == 0)
3001 fontname[len-8] = '\0';
3002 gui_default_parameter (f, parms, Qfont,
3003 build_string (fontname),
3004 "font", "Font", RES_TYPE_STRING);
3005 xfree (fontname);
3006#else
3007 gui_default_parameter (f, parms, Qfont,
3008 build_string ("fixed"),
3009 "font", "Font", RES_TYPE_STRING);
3010#endif
3011 }
3012
3013 gui_default_parameter (f, parms, Qborder_width, make_fixnum (0),
3014 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
3015
3016 /* This defaults to 1 in order to match xterm. We recognize either
3017 internalBorderWidth or internalBorder (which is what xterm calls
3018 it). */
3019 if (NILP (Fassq (Qinternal_border_width, parms)))
3020 {
3021 Lisp_Object value;
3022
3023 value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width,
3024 "internalBorder", "internalBorder",
3025 RES_TYPE_NUMBER);
3026 if (! EQ (value, Qunbound))
3027 parms = Fcons (Fcons (Qinternal_border_width, value),
3028 parms);
3029 }
3030
3031 gui_default_parameter (f, parms, Qinternal_border_width, make_fixnum (1),
3032 "internalBorderWidth", "internalBorderWidth",
3033 RES_TYPE_NUMBER);
3034 gui_default_parameter (f, parms, Qright_divider_width, make_fixnum (0),
3035 NULL, NULL, RES_TYPE_NUMBER);
3036 gui_default_parameter (f, parms, Qbottom_divider_width, make_fixnum (0),
3037 NULL, NULL, RES_TYPE_NUMBER);
3038
3039 /* Also do the stuff which must be set before the window exists. */
3040 gui_default_parameter (f, parms, Qforeground_color, build_string ("black"),
3041 "foreground", "Foreground", RES_TYPE_STRING);
3042 gui_default_parameter (f, parms, Qbackground_color, build_string ("white"),
3043 "background", "Background", RES_TYPE_STRING);
3044 gui_default_parameter (f, parms, Qmouse_color, build_string ("black"),
3045 "pointerColor", "Foreground", RES_TYPE_STRING);
3046 gui_default_parameter (f, parms, Qcursor_color, build_string ("black"),
3047 "cursorColor", "Foreground", RES_TYPE_STRING);
3048 gui_default_parameter (f, parms, Qborder_color, build_string ("black"),
3049 "borderColor", "BorderColor", RES_TYPE_STRING);
3050 gui_default_parameter (f, parms, Qno_special_glyphs, Qnil,
3051 NULL, NULL, RES_TYPE_BOOLEAN);
3052
3053 /* Init faces before gui_default_parameter is called for the
3054 scroll-bar-width parameter because otherwise we end up in
3055 init_iterator with a null face cache, which should not happen. */
3056 init_frame_faces (f);
3057
3058 f->output_data.ns->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
3059
3060 gui_default_parameter (f, parms, Qinhibit_double_buffering, Qnil,
3061 "inhibitDoubleBuffering", "InhibitDoubleBuffering",
3062 RES_TYPE_BOOLEAN);
3063
3064 gui_figure_window_size (f, parms, false, false);
3065
3066 block_input ();
3067 [[EmacsView alloc] initFrameFromEmacs: f];
3068 ns_icon (f, parms);
3069 unblock_input ();
3070
3071 gui_default_parameter (f, parms, Qauto_raise, Qnil,
3072 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
3073 gui_default_parameter (f, parms, Qauto_lower, Qnil,
3074 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
3075 gui_default_parameter (f, parms, Qcursor_type, Qbox,
3076 "cursorType", "CursorType", RES_TYPE_SYMBOL);
3077 gui_default_parameter (f, parms, Qalpha, Qnil,
3078 "alpha", "Alpha", RES_TYPE_NUMBER);
3079
3080 /* Add `tooltip' frame parameter's default value. */
3081 if (NILP (Fframe_parameter (frame, Qtooltip)))
3082 {
3083 AUTO_FRAME_ARG (arg, Qtooltip, Qt);
3084 Fmodify_frame_parameters (frame, arg);
3085 }
3086
3087 /* FIXME - can this be done in a similar way to normal frames?
3088 https://lists.gnu.org/r/emacs-devel/2007-10/msg00641.html */
3089
3090 /* Set the `display-type' frame parameter before setting up faces. */
3091 {
3092 Lisp_Object disptype = intern ("color");
3093
3094 if (NILP (Fframe_parameter (frame, Qdisplay_type)))
3095 {
3096 AUTO_FRAME_ARG (arg, Qdisplay_type, disptype);
3097 Fmodify_frame_parameters (frame, arg);
3098 }
3099 }
3100
3101 /* Set up faces after all frame parameters are known. This call
3102 also merges in face attributes specified for new frames.
3103
3104 Frame parameters may be changed if .Xdefaults contains
3105 specifications for the default font. For example, if there is an
3106 `Emacs.default.attributeBackground: pink', the `background-color'
3107 attribute of the frame gets set, which let's the internal border
3108 of the tooltip frame appear in pink. Prevent this. */
3109 {
3110 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
3111
3112 call2 (Qface_set_after_frame_default, frame, Qnil);
3113
3114 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
3115 {
3116 AUTO_FRAME_ARG (arg, Qbackground_color, bg);
3117 Fmodify_frame_parameters (frame, arg);
3118 }
3119 }
3120
3121 f->no_split = true;
3122
3123 /* Now that the frame will be official, it counts as a reference to
3124 its display and terminal. */
3125 f->terminal->reference_count++;
3126
3127 /* It is now ok to make the frame official even if we get an error
3128 below. And the frame needs to be on Vframe_list or making it
3129 visible won't work. */
3130 Vframe_list = Fcons (frame, Vframe_list);
3131 f->can_set_window_size = true;
3132 adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
3133 0, true, Qtip_frame);
3134
3135 /* Setting attributes of faces of the tooltip frame from resources
3136 and similar will set face_change, which leads to the clearing of
3137 all current matrices. Since this isn't necessary here, avoid it
3138 by resetting face_change to the value it had before we created
3139 the tip frame. */
3140 face_change = face_change_before;
3141
3142 /* Discard the unwind_protect. */
3143 return unbind_to (count, frame);
3144}
3145
3146static Lisp_Object
3147x_hide_tip (bool delete)
3148{
3149 if (!NILP (tip_timer))
3150 {
3151 call1 (intern ("cancel-timer"), tip_timer);
3152 tip_timer = Qnil;
3153 }
3154
3155 if (!(ns_tooltip == nil || ![ns_tooltip isActive]))
3156 {
3157 [ns_tooltip hide];
3158 tip_last_frame = Qnil;
3159 return Qt;
3160 }
3161
3162 if ((NILP (tip_last_frame) && NILP (tip_frame))
3163 || (!use_system_tooltips
3164 && !delete
3165 && !NILP (tip_frame)
3166 && FRAME_LIVE_P (XFRAME (tip_frame))
3167 && !FRAME_VISIBLE_P (XFRAME (tip_frame))))
3168 /* Either there's no tooltip to hide or it's an already invisible
3169 Emacs tooltip and we don't want to change its type. Return
3170 quickly. */
3171 return Qnil;
3172 else
3173 {
3174 specpdl_ref count;
3175 Lisp_Object was_open = Qnil;
3176
3177 count = SPECPDL_INDEX ();
3178 specbind (Qinhibit_redisplay, Qt);
3179 specbind (Qinhibit_quit, Qt);
3180
3181 /* Now look whether there's an Emacs tip around. */
3182 if (!NILP (tip_frame))
3183 {
3184 struct frame *f = XFRAME (tip_frame);
3185
3186 if (FRAME_LIVE_P (f))
3187 {
3188 if (delete || use_system_tooltips)
3189 {
3190 /* Delete the Emacs tooltip frame when DELETE is true
3191 or we change the tooltip type from an Emacs one to
3192 a GTK+ system one. */
3193 delete_frame (tip_frame, Qnil);
3194 tip_frame = Qnil;
3195 }
3196 else
3197 ns_make_frame_invisible (f);
3198
3199 was_open = Qt;
3200 }
3201 else
3202 tip_frame = Qnil;
3203 }
3204 else
3205 tip_frame = Qnil;
3206
3207 return unbind_to (count, was_open);
3208 }
3209}
2850 3210
2851DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, 3211DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
2852 doc: /* SKIP: real doc in xfns.c. */) 3212 doc: /* SKIP: real doc in xfns.c. */)
@@ -2854,11 +3214,18 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
2854{ 3214{
2855 int root_x, root_y; 3215 int root_x, root_y;
2856 specpdl_ref count = SPECPDL_INDEX (); 3216 specpdl_ref count = SPECPDL_INDEX ();
2857 struct frame *f; 3217 struct frame *f, *tip_f;
3218 struct window *w;
3219 struct buffer *old_buffer;
3220 struct text_pos pos;
3221 int width, height;
3222 int old_windows_or_buffers_changed = windows_or_buffers_changed;
3223 specpdl_ref count_1;
3224 Lisp_Object window, size, tip_buf;
2858 char *str; 3225 char *str;
2859 NSSize size; 3226 NSWindow *nswindow;
2860 NSColor *color; 3227
2861 Lisp_Object t; 3228 AUTO_STRING (tip, " *tip*");
2862 3229
2863 specbind (Qinhibit_redisplay, Qt); 3230 specbind (Qinhibit_redisplay, Qt);
2864 3231
@@ -2879,32 +3246,253 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
2879 else 3246 else
2880 CHECK_FIXNUM (dy); 3247 CHECK_FIXNUM (dy);
2881 3248
2882 block_input (); 3249 tip_dx = dx;
2883 if (ns_tooltip == nil) 3250 tip_dy = dy;
2884 ns_tooltip = [[EmacsTooltip alloc] init]; 3251
3252 if (use_system_tooltips)
3253 {
3254 NSSize size;
3255 NSColor *color;
3256 Lisp_Object t;
3257
3258 block_input ();
3259 if (ns_tooltip == nil)
3260 ns_tooltip = [[EmacsTooltip alloc] init];
3261 else
3262 Fx_hide_tip ();
3263
3264 t = gui_display_get_arg (NULL, parms, Qbackground_color, NULL, NULL,
3265 RES_TYPE_STRING);
3266 if (ns_lisp_to_color (t, &color) == 0)
3267 [ns_tooltip setBackgroundColor: color];
3268
3269 t = gui_display_get_arg (NULL, parms, Qforeground_color, NULL, NULL,
3270 RES_TYPE_STRING);
3271 if (ns_lisp_to_color (t, &color) == 0)
3272 [ns_tooltip setForegroundColor: color];
3273
3274 [ns_tooltip setText: str];
3275 size = [ns_tooltip frame].size;
3276
3277 /* Move the tooltip window where the mouse pointer is. Resize and
3278 show it. */
3279 compute_tip_xy (f, parms, dx, dy, (int) size.width, (int) size.height,
3280 &root_x, &root_y);
3281
3282 [ns_tooltip showAtX: root_x Y: root_y for: XFIXNUM (timeout)];
3283 unblock_input ();
3284 }
2885 else 3285 else
2886 Fx_hide_tip (); 3286 {
3287 if (!NILP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
3288 {
3289 if (FRAME_VISIBLE_P (XFRAME (tip_frame))
3290 && EQ (frame, tip_last_frame)
3291 && !NILP (Fequal_including_properties (tip_last_string, string))
3292 && !NILP (Fequal (tip_last_parms, parms)))
3293 {
3294 /* Only DX and DY have changed. */
3295 tip_f = XFRAME (tip_frame);
3296 if (!NILP (tip_timer))
3297 {
3298 call1 (intern ("cancel-timer"), tip_timer);
3299 tip_timer = Qnil;
3300 }
3301
3302 nswindow = [FRAME_NS_VIEW (tip_f) window];
3303
3304 block_input ();
3305 compute_tip_xy (tip_f, parms, dx, dy, FRAME_PIXEL_WIDTH (tip_f),
3306 FRAME_PIXEL_HEIGHT (tip_f), &root_x, &root_y);
3307 [nswindow setFrame: NSMakeRect (root_x, root_y,
3308 FRAME_PIXEL_WIDTH (tip_f),
3309 FRAME_PIXEL_HEIGHT (tip_f))
3310 display: YES];
3311 [nswindow setLevel: NSPopUpMenuWindowLevel];
3312 [nswindow orderFront: NSApp];
3313 [nswindow display];
3314
3315 SET_FRAME_VISIBLE (tip_f, 1);
3316 unblock_input ();
3317
3318 goto start_timer;
3319 }
3320 else if (tooltip_reuse_hidden_frame && EQ (frame, tip_last_frame))
3321 {
3322 bool delete = false;
3323 Lisp_Object tail, elt, parm, last;
3324
3325 /* Check if every parameter in PARMS has the same value in
3326 tip_last_parms. This may destruct tip_last_parms which,
3327 however, will be recreated below. */
3328 for (tail = parms; CONSP (tail); tail = XCDR (tail))
3329 {
3330 elt = XCAR (tail);
3331 parm = Fcar (elt);
3332 /* The left, top, right and bottom parameters are handled
3333 by compute_tip_xy so they can be ignored here. */
3334 if (!EQ (parm, Qleft) && !EQ (parm, Qtop)
3335 && !EQ (parm, Qright) && !EQ (parm, Qbottom))
3336 {
3337 last = Fassq (parm, tip_last_parms);
3338 if (NILP (Fequal (Fcdr (elt), Fcdr (last))))
3339 {
3340 /* We lost, delete the old tooltip. */
3341 delete = true;
3342 break;
3343 }
3344 else
3345 tip_last_parms =
3346 call2 (intern ("assq-delete-all"), parm, tip_last_parms);
3347 }
3348 else
3349 tip_last_parms =
3350 call2 (intern ("assq-delete-all"), parm, tip_last_parms);
3351 }
3352
3353 /* Now check if every parameter in what is left of
3354 tip_last_parms with a non-nil value has an association in
3355 PARMS. */
3356 for (tail = tip_last_parms; CONSP (tail); tail = XCDR (tail))
3357 {
3358 elt = XCAR (tail);
3359 parm = Fcar (elt);
3360 if (!EQ (parm, Qleft) && !EQ (parm, Qtop) && !EQ (parm, Qright)
3361 && !EQ (parm, Qbottom) && !NILP (Fcdr (elt)))
3362 {
3363 /* We lost, delete the old tooltip. */
3364 delete = true;
3365 break;
3366 }
3367 }
3368
3369 x_hide_tip (delete);
3370 }
3371 else
3372 x_hide_tip (true);
3373 }
3374 else
3375 x_hide_tip (true);
2887 3376
2888 t = gui_display_get_arg (NULL, parms, Qbackground_color, NULL, NULL, 3377 tip_last_frame = frame;
2889 RES_TYPE_STRING); 3378 tip_last_string = string;
2890 if (ns_lisp_to_color (t, &color) == 0) 3379 tip_last_parms = parms;
2891 [ns_tooltip setBackgroundColor: color];
2892 3380
2893 t = gui_display_get_arg (NULL, parms, Qforeground_color, NULL, NULL, 3381 if (NILP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame)))
2894 RES_TYPE_STRING); 3382 {
2895 if (ns_lisp_to_color (t, &color) == 0) 3383 /* Add default values to frame parameters. */
2896 [ns_tooltip setForegroundColor: color]; 3384 if (NILP (Fassq (Qname, parms)))
3385 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
3386 if (NILP (Fassq (Qinternal_border_width, parms)))
3387 parms = Fcons (Fcons (Qinternal_border_width, make_fixnum (3)), parms);
3388 if (NILP (Fassq (Qborder_width, parms)))
3389 parms = Fcons (Fcons (Qborder_width, make_fixnum (1)), parms);
3390 if (NILP (Fassq (Qborder_color, parms)))
3391 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
3392 if (NILP (Fassq (Qbackground_color, parms)))
3393 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
3394 parms);
3395
3396 /* Create a frame for the tooltip, and record it in the global
3397 variable tip_frame. */
3398 if (NILP (tip_frame = ns_create_tip_frame (FRAME_DISPLAY_INFO (f), parms)))
3399 /* Creating the tip frame failed. */
3400 return unbind_to (count, Qnil);
3401 }
2897 3402
2898 [ns_tooltip setText: str]; 3403 tip_f = XFRAME (tip_frame);
2899 size = [ns_tooltip frame].size; 3404 window = FRAME_ROOT_WINDOW (tip_f);
3405 tip_buf = Fget_buffer_create (tip, Qnil);
3406 /* We will mark the tip window a "pseudo-window" below, and such
3407 windows cannot have display margins. */
3408 bset_left_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
3409 bset_right_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
3410 set_window_buffer (window, tip_buf, false, false);
3411 w = XWINDOW (window);
3412 w->pseudo_window_p = true;
3413 /* Try to avoid that `other-window' select us (Bug#47207). */
3414 Fset_window_parameter (window, Qno_other_window, Qt);
3415
3416 /* Set up the frame's root window. Note: The following code does not
3417 try to size the window or its frame correctly. Its only purpose is
3418 to make the subsequent text size calculations work. The right
3419 sizes should get installed when the toolkit gets back to us. */
3420 w->left_col = 0;
3421 w->top_line = 0;
3422 w->pixel_left = 0;
3423 w->pixel_top = 0;
3424
3425 if (CONSP (Vx_max_tooltip_size)
3426 && RANGED_FIXNUMP (1, XCAR (Vx_max_tooltip_size), INT_MAX)
3427 && RANGED_FIXNUMP (1, XCDR (Vx_max_tooltip_size), INT_MAX))
3428 {
3429 w->total_cols = XFIXNAT (XCAR (Vx_max_tooltip_size));
3430 w->total_lines = XFIXNAT (XCDR (Vx_max_tooltip_size));
3431 }
3432 else
3433 {
3434 w->total_cols = 80;
3435 w->total_lines = 40;
3436 }
2900 3437
2901 /* Move the tooltip window where the mouse pointer is. Resize and 3438 w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (tip_f);
2902 show it. */ 3439 w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (tip_f);
2903 compute_tip_xy (f, parms, dx, dy, (int)size.width, (int)size.height, 3440 FRAME_TOTAL_COLS (tip_f) = w->total_cols;
2904 &root_x, &root_y); 3441 adjust_frame_glyphs (tip_f);
3442
3443 /* Insert STRING into root window's buffer and fit the frame to the
3444 buffer. */
3445 count_1 = SPECPDL_INDEX ();
3446 old_buffer = current_buffer;
3447 set_buffer_internal_1 (XBUFFER (w->contents));
3448 bset_truncate_lines (current_buffer, Qnil);
3449 specbind (Qinhibit_read_only, Qt);
3450 specbind (Qinhibit_modification_hooks, Qt);
3451 specbind (Qinhibit_point_motion_hooks, Qt);
3452 Ferase_buffer ();
3453 Finsert (1, &string);
3454 clear_glyph_matrix (w->desired_matrix);
3455 clear_glyph_matrix (w->current_matrix);
3456 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
3457 try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
3458 /* Calculate size of tooltip window. */
3459 size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil,
3460 make_fixnum (w->pixel_height), Qnil,
3461 Qnil);
3462 /* Add the frame's internal border to calculated size. */
3463 width = XFIXNUM (Fcar (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
3464 height = XFIXNUM (Fcdr (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
3465
3466 /* Calculate position of tooltip frame. */
3467 compute_tip_xy (tip_f, parms, dx, dy, width,
3468 height, &root_x, &root_y);
3469
3470 block_input ();
3471 nswindow = [FRAME_NS_VIEW (tip_f) window];
3472 [nswindow setFrame: NSMakeRect (root_x, root_y,
3473 width, height)
3474 display: YES];
3475 [nswindow setLevel: NSPopUpMenuWindowLevel];
3476 [nswindow orderFront: NSApp];
3477 [nswindow display];
3478
3479 SET_FRAME_VISIBLE (tip_f, YES);
3480 FRAME_PIXEL_WIDTH (tip_f) = width;
3481 FRAME_PIXEL_HEIGHT (tip_f) = height;
3482 unblock_input ();
2905 3483
2906 [ns_tooltip showAtX: root_x Y: root_y for: XFIXNUM (timeout)]; 3484 w->must_be_updated_p = true;
2907 unblock_input (); 3485 update_single_window (w);
3486 flush_frame (tip_f);
3487 set_buffer_internal_1 (old_buffer);
3488 unbind_to (count_1, Qnil);
3489 windows_or_buffers_changed = old_windows_or_buffers_changed;
3490
3491 start_timer:
3492 /* Let the tip disappear after timeout seconds. */
3493 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
3494 intern ("x-hide-tip"));
3495 }
2908 3496
2909 return unbind_to (count, Qnil); 3497 return unbind_to (count, Qnil);
2910} 3498}
@@ -2914,10 +3502,7 @@ DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
2914 doc: /* SKIP: real doc in xfns.c. */) 3502 doc: /* SKIP: real doc in xfns.c. */)
2915 (void) 3503 (void)
2916{ 3504{
2917 if (ns_tooltip == nil || ![ns_tooltip isActive]) 3505 return x_hide_tip (!tooltip_reuse_hidden_frame);
2918 return Qnil;
2919 [ns_tooltip hide];
2920 return Qt;
2921} 3506}
2922 3507
2923/* Return geometric attributes of FRAME. According to the value of 3508/* Return geometric attributes of FRAME. According to the value of
@@ -3215,6 +3800,48 @@ all_nonzero_ascii (unsigned char *str, ptrdiff_t n)
3215} 3800}
3216@end 3801@end
3217 3802
3803void
3804ns_move_tooltip_to_mouse_location (NSPoint screen_point)
3805{
3806 int root_x, root_y;
3807 NSSize size;
3808 NSWindow *window;
3809 struct frame *tip_f;
3810
3811 window = nil;
3812
3813 if (!FIXNUMP (tip_dx) || !FIXNUMP (tip_dy))
3814 return;
3815
3816 if (ns_tooltip)
3817 size = [ns_tooltip frame].size;
3818 else if (!FRAMEP (tip_frame)
3819 || !FRAME_LIVE_P (XFRAME (tip_frame))
3820 || !FRAME_VISIBLE_P (XFRAME (tip_frame)))
3821 return;
3822 else
3823 {
3824 tip_f = XFRAME (tip_frame);
3825 window = [FRAME_NS_VIEW (tip_f) window];
3826 size = [window frame].size;
3827 }
3828
3829 root_x = screen_point.x;
3830 root_y = screen_point.y;
3831
3832 /* We can directly use `compute_tip_xy' here, since it doesn't cons
3833 nearly as much as it does on X. */
3834 compute_tip_xy (NULL, Qnil, tip_dx, tip_dy, (int) size.width,
3835 (int) size.height, &root_x, &root_y);
3836
3837 if (ns_tooltip)
3838 [ns_tooltip moveTo: NSMakePoint (root_x, root_y)];
3839 else
3840 [window setFrame: NSMakeRect (root_x, root_y,
3841 size.width, size.height)
3842 display: YES];
3843}
3844
3218/* ========================================================================== 3845/* ==========================================================================
3219 3846
3220 Lisp interface declaration 3847 Lisp interface declaration
@@ -3260,6 +3887,10 @@ be used as the image of the icon representing the frame. */);
3260Default is t. */); 3887Default is t. */);
3261 ns_use_proxy_icon = true; 3888 ns_use_proxy_icon = true;
3262 3889
3890 DEFVAR_LISP ("x-max-tooltip-size", Vx_max_tooltip_size,
3891 doc: /* SKIP: real doc in xfns.c. */);
3892 Vx_max_tooltip_size = Fcons (make_fixnum (80), make_fixnum (40));
3893
3263 defsubr (&Sns_read_file_name); 3894 defsubr (&Sns_read_file_name);
3264 defsubr (&Sns_get_resource); 3895 defsubr (&Sns_get_resource);
3265 defsubr (&Sns_set_resource); 3896 defsubr (&Sns_set_resource);
@@ -3309,6 +3940,21 @@ Default is t. */);
3309 defsubr (&Sx_show_tip); 3940 defsubr (&Sx_show_tip);
3310 defsubr (&Sx_hide_tip); 3941 defsubr (&Sx_hide_tip);
3311 3942
3943 tip_timer = Qnil;
3944 staticpro (&tip_timer);
3945 tip_frame = Qnil;
3946 staticpro (&tip_frame);
3947 tip_last_frame = Qnil;
3948 staticpro (&tip_last_frame);
3949 tip_last_string = Qnil;
3950 staticpro (&tip_last_string);
3951 tip_last_parms = Qnil;
3952 staticpro (&tip_last_parms);
3953 tip_dx = Qnil;
3954 staticpro (&tip_dx);
3955 tip_dy = Qnil;
3956 staticpro (&tip_dy);
3957
3312#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 3958#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3313 defsubr (&Ssystem_move_file_to_trash); 3959 defsubr (&Ssystem_move_file_to_trash);
3314#endif 3960#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,
1177 face = s->face; 1177 face = s->face;
1178 1178
1179 r.origin.x = x; 1179 r.origin.x = x;
1180 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1181 r.origin.x += max (s->face->box_vertical_line_width, 0);
1182
1183 r.origin.y = y; 1180 r.origin.y = y;
1184 r.size.height = FONT_HEIGHT (font); 1181 r.size.height = FONT_HEIGHT (font);
1185 1182
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;
52/* Nonzero means a menu is currently active. */ 52/* Nonzero means a menu is currently active. */
53static int popup_activated_flag; 53static int popup_activated_flag;
54 54
55/* The last frame whose menubar was updated. (This is the frame whose
56 menu bar is currently being displayed.) */
57static struct frame *last_menubar_frame;
58
55/* NOTE: toolbar implementation is at end, 59/* NOTE: toolbar implementation is at end,
56 following complete menu implementation. */ 60 following complete menu implementation. */
57 61
@@ -71,6 +75,12 @@ void
71free_frame_menubar (struct frame *f) 75free_frame_menubar (struct frame *f)
72{ 76{
73 id menu = [NSApp mainMenu]; 77 id menu = [NSApp mainMenu];
78
79 if (f != last_menubar_frame)
80 return;
81
82 last_menubar_frame = NULL;
83
74 for (int i = [menu numberOfItems] - 1 ; i >= 0; i--) 84 for (int i = [menu numberOfItems] - 1 ; i >= 0; i--)
75 { 85 {
76 NSMenuItem *item = (NSMenuItem *)[menu itemAtIndex:i]; 86 NSMenuItem *item = (NSMenuItem *)[menu itemAtIndex:i];
@@ -135,9 +145,9 @@ ns_update_menubar (struct frame *f, bool deep_p)
135#endif 145#endif
136 return; 146 return;
137 } 147 }
138 XSETFRAME (Vmenu_updating_frame, f);
139/*fprintf (stderr, "ns_update_menubar: frame: %p\tdeep: %d\tsub: %p\n", f, deep_p, submenu); */
140 148
149 XSETFRAME (Vmenu_updating_frame, f);
150 last_menubar_frame = f;
141 block_input (); 151 block_input ();
142 152
143 /* Menu may have been created automatically; if so, discard it. */ 153 /* Menu may have been created automatically; if so, discard it. */
@@ -155,7 +165,7 @@ ns_update_menubar (struct frame *f, bool deep_p)
155 165
156#if NSMENUPROFILE 166#if NSMENUPROFILE
157 ftime (&tb); 167 ftime (&tb);
158 t = -(1000*tb.time+tb.millitm); 168 t = -(1000 * tb.time + tb.millitm);
159#endif 169#endif
160 170
161 if (deep_p) 171 if (deep_p)
@@ -413,7 +423,7 @@ ns_update_menubar (struct frame *f, bool deep_p)
413 423
414#if NSMENUPROFILE 424#if NSMENUPROFILE
415 ftime (&tb); 425 ftime (&tb);
416 t += 1000*tb.time+tb.millitm; 426 t += 1000 * tb.time + tb.millitm;
417 fprintf (stderr, "Menu update took %ld msec.\n", t); 427 fprintf (stderr, "Menu update took %ld msec.\n", t);
418#endif 428#endif
419 429
@@ -741,15 +751,15 @@ prettify_key (const char *key)
741 /* p = [view convertPoint:p fromView: nil]; */ 751 /* p = [view convertPoint:p fromView: nil]; */
742 p.y = NSHeight ([view frame]) - p.y; 752 p.y = NSHeight ([view frame]) - p.y;
743 e = [[view window] currentEvent]; 753 e = [[view window] currentEvent];
744 event = [NSEvent mouseEventWithType: NSEventTypeRightMouseDown 754 event = [NSEvent mouseEventWithType: NSEventTypeRightMouseDown
745 location: p 755 location: p
746 modifierFlags: 0 756 modifierFlags: 0
747 timestamp: [e timestamp] 757 timestamp: [e timestamp]
748 windowNumber: [[view window] windowNumber] 758 windowNumber: [[view window] windowNumber]
749 context: nil 759 context: nil
750 eventNumber: 0 /* [e eventNumber] */ 760 eventNumber: 0 /* [e eventNumber] */
751 clickCount: 1 761 clickCount: 1
752 pressure: 0]; 762 pressure: 0];
753 763
754 context_menu_value = -1; 764 context_menu_value = -1;
755 [NSMenu popUpContextMenu: self withEvent: event forView: view]; 765 [NSMenu popUpContextMenu: self withEvent: event forView: view];
@@ -765,13 +775,33 @@ prettify_key (const char *key)
765 NSInteger idx = [item tag]; 775 NSInteger idx = [item tag];
766 struct frame *f = SELECTED_FRAME (); 776 struct frame *f = SELECTED_FRAME ();
767 Lisp_Object vec = f->menu_bar_vector; 777 Lisp_Object vec = f->menu_bar_vector;
768 Lisp_Object help, frame; 778 Lisp_Object help, frame, *client_data;
769
770 if (idx >= ASIZE (vec))
771 return;
772 779
773 XSETFRAME (frame, f); 780 XSETFRAME (frame, f);
774 help = AREF (vec, idx + MENU_ITEMS_ITEM_HELP); 781
782 /* This menu isn't a menubar, so use the pointer to the popup menu
783 data. */
784 if (context_menu_value != 0)
785 {
786 client_data = (Lisp_Object *) idx;
787
788 if (client_data)
789 help = client_data[MENU_ITEMS_ITEM_HELP];
790 else
791 help = Qnil;
792 }
793 /* Just dismiss any help-echo that might already be in progress if
794 no menu item will be highlighted. */
795 else if (item == nil || idx <= 0)
796 help = Qnil;
797 else
798 {
799 if (idx >= ASIZE (vec))
800 return;
801
802 /* Otherwise, get the help data from the menu bar vector. */
803 help = AREF (vec, idx + MENU_ITEMS_ITEM_HELP);
804 }
775 805
776 popup_activated_flag++; 806 popup_activated_flag++;
777 if (STRINGP (help) || NILP (help)) 807 if (STRINGP (help) || NILP (help))
@@ -849,37 +879,35 @@ ns_menu_show (struct frame *f, int x, int y, int menuflags,
849 EmacsMenu *pmenu; 879 EmacsMenu *pmenu;
850 NSPoint p; 880 NSPoint p;
851 Lisp_Object tem; 881 Lisp_Object tem;
852 specpdl_ref specpdl_count = SPECPDL_INDEX (); 882 specpdl_ref specpdl_count;
853 widget_value *wv, *first_wv = 0; 883 widget_value *wv, *first_wv = 0;
884 widget_value *save_wv = 0, *prev_wv = 0;
885 widget_value **submenu_stack;
886 int submenu_depth = 0;
887 int first_pane = 1;
888 int i;
854 bool keymaps = (menuflags & MENU_KEYMAPS); 889 bool keymaps = (menuflags & MENU_KEYMAPS);
855 890
891 USE_SAFE_ALLOCA;
892
856 NSTRACE ("ns_menu_show"); 893 NSTRACE ("ns_menu_show");
857 894
858 block_input (); 895 block_input ();
859 896
860 p.x = x; p.y = y; 897 p.x = x; p.y = y;
861 898
862 /* Don't GC due to a mysterious bug. */
863 inhibit_garbage_collection ();
864
865 /* now parse stage 2 as in ns_update_menubar */ 899 /* now parse stage 2 as in ns_update_menubar */
866 wv = make_widget_value ("contextmenu", NULL, true, Qnil); 900 wv = make_widget_value ("contextmenu", NULL, true, Qnil);
867 wv->button_type = BUTTON_TYPE_NONE; 901 wv->button_type = BUTTON_TYPE_NONE;
868 first_wv = wv; 902 first_wv = wv;
869 903
870#if 0 904 submenu_stack
871 /* FIXME: a couple of one-line differences prevent reuse. */ 905 = SAFE_ALLOCA (menu_items_used * sizeof *submenu_stack);
872 wv = digest_single_submenu (0, menu_items_used, 0); 906
873#else 907 specpdl_count = SPECPDL_INDEX ();
874 { 908
875 widget_value *save_wv = 0, *prev_wv = 0; 909 /* Don't GC due to a mysterious bug. */
876 widget_value **submenu_stack 910 inhibit_garbage_collection ();
877 = alloca (menu_items_used * sizeof *submenu_stack);
878 /* Lisp_Object *subprefix_stack
879 = alloca (menu_items_used * sizeof *subprefix_stack); */
880 int submenu_depth = 0;
881 int first_pane = 1;
882 int i;
883 911
884 /* Loop over all panes and items, filling in the tree. */ 912 /* Loop over all panes and items, filling in the tree. */
885 i = 0; 913 i = 0;
@@ -1009,8 +1037,6 @@ ns_menu_show (struct frame *f, int x, int y, int menuflags,
1009 i += MENU_ITEMS_ITEM_LENGTH; 1037 i += MENU_ITEMS_ITEM_LENGTH;
1010 } 1038 }
1011 } 1039 }
1012 }
1013#endif
1014 1040
1015 if (!NILP (title)) 1041 if (!NILP (title))
1016 { 1042 {
@@ -1045,6 +1071,8 @@ ns_menu_show (struct frame *f, int x, int y, int menuflags,
1045 [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow]; 1071 [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
1046 unbind_to (specpdl_count, Qnil); 1072 unbind_to (specpdl_count, Qnil);
1047 unblock_input (); 1073 unblock_input ();
1074
1075 SAFE_FREE ();
1048 return tem; 1076 return tem;
1049} 1077}
1050 1078
@@ -1469,6 +1497,15 @@ update_frame_tool_bar (struct frame *f)
1469 [timer retain]; 1497 [timer retain];
1470} 1498}
1471 1499
1500- (void) moveTo: (NSPoint) screen_point
1501{
1502 [win setFrame: NSMakeRect (screen_point.x,
1503 screen_point.y,
1504 [self frame].size.width,
1505 [self frame].size.height)
1506 display: YES];
1507}
1508
1472- (void) hide 1509- (void) hide
1473{ 1510{
1474 [win close]; 1511 [win close];
@@ -1508,31 +1545,38 @@ pop_down_menu (void *arg)
1508 1545
1509 if (popup_activated_flag) 1546 if (popup_activated_flag)
1510 { 1547 {
1511 block_input ();
1512 popup_activated_flag = 0; 1548 popup_activated_flag = 0;
1513 [panel close]; 1549 [panel close];
1550 /* For some reason this is required on macOS, or the selected
1551 frame gets the keyboard focus but doesn't become
1552 highlighted. */
1553#ifdef NS_IMPL_COCOA
1514 [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow]; 1554 [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
1515 unblock_input (); 1555#endif
1556 discard_menu_items ();
1516 } 1557 }
1517} 1558}
1518 1559
1519
1520Lisp_Object 1560Lisp_Object
1521ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents) 1561ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1522{ 1562{
1523 id dialog; 1563 EmacsDialogPanel *dialog;
1524 Lisp_Object tem, title; 1564 Lisp_Object tem, title;
1525 NSPoint p; 1565 NSPoint p;
1526 BOOL isQ; 1566 BOOL is_question;
1567 const char *error_name;
1568 specpdl_ref specpdl_count;
1527 1569
1528 NSTRACE ("ns_popup_dialog"); 1570 NSTRACE ("ns_popup_dialog");
1571 specpdl_count = SPECPDL_INDEX ();
1529 1572
1530 isQ = NILP (header); 1573 is_question = NILP (header);
1531
1532 check_window_system (f); 1574 check_window_system (f);
1533 1575
1534 p.x = (int)f->left_pos + ((int)FRAME_COLUMN_WIDTH (f) * f->text_cols)/2; 1576 p.x = ((int) f->left_pos
1535 p.y = (int)f->top_pos + (FRAME_LINE_HEIGHT (f) * f->text_lines)/2; 1577 + ((int) FRAME_COLUMN_WIDTH (f) * f->text_cols) / 2);
1578 p.y = ((int) f->top_pos
1579 + (FRAME_LINE_HEIGHT (f) * f->text_lines) / 2);
1536 1580
1537 title = Fcar (contents); 1581 title = Fcar (contents);
1538 CHECK_STRING (title); 1582 CHECK_STRING (title);
@@ -1542,21 +1586,30 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1542 the dialog. */ 1586 the dialog. */
1543 contents = list2 (title, Fcons (build_string ("Ok"), Qt)); 1587 contents = list2 (title, Fcons (build_string ("Ok"), Qt));
1544 1588
1545 block_input (); 1589 record_unwind_protect_void (unuse_menu_items);
1546 dialog = [[EmacsDialogPanel alloc] initFromContents: contents 1590 list_of_panes (list1 (contents));
1547 isQuestion: isQ];
1548 1591
1549 { 1592 block_input ();
1550 specpdl_ref specpdl_count = SPECPDL_INDEX (); 1593 dialog = [[EmacsDialogPanel alloc] initWithTitle: SSDATA (title)
1551 1594 isQuestion: is_question];
1552 record_unwind_protect_ptr (pop_down_menu, dialog);
1553 popup_activated_flag = 1;
1554 tem = [dialog runDialogAt: p];
1555 unbind_to (specpdl_count, Qnil); /* calls pop_down_menu */
1556 }
1557 1595
1596 [dialog processMenuItems: menu_items
1597 used: menu_items_used
1598 withErrorOutput: &error_name];
1599 [dialog resizeBoundsPriorToDisplay];
1558 unblock_input (); 1600 unblock_input ();
1559 1601
1602 if (error_name)
1603 {
1604 discard_menu_items ();
1605 [dialog close];
1606 error ("%s", error_name);
1607 }
1608
1609 record_unwind_protect_ptr (pop_down_menu, dialog);
1610 popup_activated_flag = 1;
1611 tem = [dialog runDialogAt: p];
1612 unbind_to (specpdl_count, Qnil);
1560 return tem; 1613 return tem;
1561} 1614}
1562 1615
@@ -1597,7 +1650,6 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1597 NSImage *img; 1650 NSImage *img;
1598 1651
1599 dialog_return = Qundefined; 1652 dialog_return = Qundefined;
1600 button_values = NULL;
1601 area.origin.x = 3*SPACER; 1653 area.origin.x = 3*SPACER;
1602 area.origin.y = 2*SPACER; 1654 area.origin.y = 2*SPACER;
1603 area.size.width = ICONSIZE; 1655 area.size.width = ICONSIZE;
@@ -1681,58 +1733,65 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1681} 1733}
1682 1734
1683 1735
1684- (BOOL)windowShouldClose: (id)sender 1736- (BOOL)windowShouldClose: (id) sender
1685{ 1737{
1686 window_closed = YES; 1738 window_closed = YES;
1687 [NSApp stop:self]; 1739 [NSApp stop: self];
1688 return NO; 1740 return NO;
1689} 1741}
1690 1742
1691- (void)dealloc 1743- (void) dealloc
1692{ 1744{
1693 xfree (button_values);
1694 [super dealloc]; 1745 [super dealloc];
1695} 1746}
1696 1747
1697- (void)process_dialog: (Lisp_Object) list 1748- (void) processMenuItems: (Lisp_Object) menu_items
1749 used: (ptrdiff_t) menu_items_used
1750 withErrorOutput: (const char **) error_name
1698{ 1751{
1699 Lisp_Object item, lst = list; 1752 int i, nb_buttons = 0, row = 0;
1700 int row = 0; 1753 Lisp_Object item_name, enable;
1701 int buttons = 0, btnnr = 0;
1702 1754
1703 for (; CONSP (lst); lst = XCDR (lst)) 1755 i = MENU_ITEMS_PANE_LENGTH;
1756 *error_name = NULL;
1757
1758 /* Loop over all panes and items, filling in the tree. */
1759 while (i < menu_items_used)
1704 { 1760 {
1705 item = XCAR (list); 1761 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1706 if (CONSP (item)) 1762 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1707 ++buttons;
1708 }
1709 1763
1710 if (buttons > 0) 1764 if (NILP (item_name))
1711 button_values = xmalloc (buttons * sizeof *button_values); 1765 {
1766 *error_name = "Submenu in dialog items";
1767 return;
1768 }
1712 1769
1713 for (; CONSP (list); list = XCDR (list)) 1770 if (EQ (item_name, Qquote))
1714 { 1771 /* This is the boundary between elements on the left and those
1715 item = XCAR (list); 1772 on the right, but that boundary is currently not handled on
1716 if (STRINGP (item)) 1773 NS. */
1717 { 1774 continue;
1718 [self addString: SSDATA (item) row: row++]; 1775
1719 } 1776 if (nb_buttons > 9)
1720 else if (CONSP (item)) 1777 {
1721 { 1778 *error_name = "Too many dialog items";
1722 button_values[btnnr] = XCDR (item); 1779 return;
1723 [self addButton: SSDATA (XCAR (item)) value: btnnr row: row++]; 1780 }
1724 ++btnnr; 1781
1725 } 1782 [self addButton: SSDATA (item_name)
1726 else if (NILP (item)) 1783 value: (NSInteger) aref_addr (menu_items, i)
1727 { 1784 row: row++
1728 [self addSplit]; 1785 enable: !NILP (enable)];
1729 row = 0; 1786
1730 } 1787 i += MENU_ITEMS_ITEM_LENGTH;
1788 nb_buttons++;
1731 } 1789 }
1732} 1790}
1733 1791
1734 1792
1735- (void)addButton: (char *)str value: (int)tag row: (int)row 1793- (void) addButton: (char *) str value: (NSInteger) tag
1794 row: (int) row enable: (BOOL) enable
1736{ 1795{
1737 id cell; 1796 id cell;
1738 1797
@@ -1741,7 +1800,8 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1741 [matrix addRow]; 1800 [matrix addRow];
1742 rows++; 1801 rows++;
1743 } 1802 }
1744 cell = [matrix cellAtRow: row column: cols-1]; 1803
1804 cell = [matrix cellAtRow: row column: cols - 1];
1745 [cell setTarget: self]; 1805 [cell setTarget: self];
1746 [cell setAction: @selector (clicked: )]; 1806 [cell setAction: @selector (clicked: )];
1747 [cell setTitle: [NSString stringWithUTF8String: str]]; 1807 [cell setTitle: [NSString stringWithUTF8String: str]];
@@ -1751,7 +1811,7 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1751} 1811}
1752 1812
1753 1813
1754- (void)addString: (char *)str row: (int)row 1814- (void)addString: (char *) str row: (int) row
1755{ 1815{
1756 id cell; 1816 id cell;
1757 1817
@@ -1774,96 +1834,95 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1774} 1834}
1775 1835
1776 1836
1777- (void)clicked: sender 1837- (void) clicked: sender
1778{ 1838{
1779 NSArray *sellist = nil; 1839 NSArray *sellist = nil;
1780 EMACS_INT seltag; 1840 NSUInteger seltag;
1841 Lisp_Object *selarray;
1781 1842
1782 sellist = [sender selectedCells]; 1843 sellist = [sender selectedCells];
1844
1783 if ([sellist count] < 1) 1845 if ([sellist count] < 1)
1784 return; 1846 return;
1785 1847
1786 seltag = [[sellist objectAtIndex: 0] tag]; 1848 seltag = [[sellist objectAtIndex: 0] tag];
1787 dialog_return = button_values[seltag]; 1849 selarray = (void *) seltag;
1788 [NSApp stop:self]; 1850 dialog_return = selarray[MENU_ITEMS_ITEM_VALUE];
1851 [NSApp stop: self];
1789} 1852}
1790 1853
1791 1854
1792- (instancetype)initFromContents: (Lisp_Object)contents isQuestion: (BOOL)isQ 1855- (instancetype) initWithTitle: (char *) title_string
1856 isQuestion: (BOOL) is_question
1793{ 1857{
1794 Lisp_Object head;
1795 [super init]; 1858 [super init];
1796 1859
1797 if (CONSP (contents)) 1860 if (title_string)
1798 { 1861 [title setStringValue:
1799 head = Fcar (contents); 1862 [NSString stringWithUTF8String: title_string]];
1800 [self process_dialog: Fcdr (contents)];
1801 }
1802 else
1803 head = contents;
1804 1863
1805 if (STRINGP (head)) 1864 if (is_question)
1806 [title setStringValue: 1865 [command setStringValue: @"Question"];
1807 [NSString stringWithUTF8String: SSDATA (head)]];
1808 else if (isQ == YES)
1809 [title setStringValue: @"Question"];
1810 else 1866 else
1811 [title setStringValue: @"Information"]; 1867 [command setStringValue: @"Information"];
1812 1868
1813 { 1869 return self;
1814 int i; 1870}
1815 NSRect r, s, t;
1816 1871
1817 if (cols == 1 && rows > 1) /* Never told where to split. */ 1872- (void) resizeBoundsPriorToDisplay
1818 { 1873{
1819 [matrix addColumn]; 1874 int i;
1820 for (i = 0; i < rows/2; i++) 1875 NSRect r, s, t;
1821 { 1876 NSSize csize;
1822 [matrix putCell: [matrix cellAtRow: (rows+1)/2 column: 0]
1823 atRow: i column: 1];
1824 [matrix removeRow: (rows+1)/2];
1825 }
1826 }
1827 1877
1828 [matrix sizeToFit]; 1878 if (cols == 1 && rows > 1)
1829 { 1879 {
1830 NSSize csize = [matrix cellSize]; 1880 [matrix addColumn];
1831 if (csize.width < MINCELLWIDTH) 1881 for (i = 0; i < rows / 2; i++)
1832 { 1882 {
1833 csize.width = MINCELLWIDTH; 1883 [matrix putCell: [matrix cellAtRow: (rows + 1) /2
1834 [matrix setCellSize: csize]; 1884 column: 0]
1835 [matrix sizeToCells]; 1885 atRow: i column: 1];
1836 } 1886 [matrix removeRow: (rows + 1) / 2];
1887 }
1837 } 1888 }
1838 1889
1839 [title sizeToFit]; 1890 [matrix sizeToFit];
1840 [command sizeToFit];
1841 1891
1842 t = [matrix frame]; 1892 csize = [matrix cellSize];
1843 r = [title frame]; 1893 if (csize.width < MINCELLWIDTH)
1844 if (r.size.width+r.origin.x > t.size.width+t.origin.x) 1894 {
1845 { 1895 csize.width = MINCELLWIDTH;
1846 t.origin.x = r.origin.x; 1896 [matrix setCellSize: csize];
1847 t.size.width = r.size.width; 1897 [matrix sizeToCells];
1848 } 1898 }
1849 r = [command frame];
1850 if (r.size.width+r.origin.x > t.size.width+t.origin.x)
1851 {
1852 t.origin.x = r.origin.x;
1853 t.size.width = r.size.width;
1854 }
1855 1899
1856 r = [self frame]; 1900 [title sizeToFit];
1857 s = [(NSView *)[self contentView] frame]; 1901 [command sizeToFit];
1858 r.size.width += t.origin.x+t.size.width +2*SPACER-s.size.width;
1859 r.size.height += t.origin.y+t.size.height+SPACER-s.size.height;
1860 [self setFrame: r display: NO];
1861 }
1862 1902
1863 return self; 1903 t = [matrix frame];
1864} 1904 r = [title frame];
1905 if (r.size.width + r.origin.x > t.size.width + t.origin.x)
1906 {
1907 t.origin.x = r.origin.x;
1908 t.size.width = r.size.width;
1909 }
1865 1910
1911 r = [command frame];
1912 if (r.size.width + r.origin.x > t.size.width + t.origin.x)
1913 {
1914 t.origin.x = r.origin.x;
1915 t.size.width = r.size.width;
1916 }
1866 1917
1918 r = [self frame];
1919 s = [(NSView *) [self contentView] frame];
1920 r.size.width += (t.origin.x + t.size.width
1921 + 2 * SPACER - s.size.width);
1922 r.size.height += (t.origin.y + t.size.height
1923 + SPACER - s.size.height);
1924 [self setFrame: r display: NO];
1925}
1867 1926
1868- (void)timeout_handler: (NSTimer *)timedEntry 1927- (void)timeout_handler: (NSTimer *)timedEntry
1869{ 1928{
@@ -1881,11 +1940,11 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1881 /* We use stop because stopModal/abortModal out of the main loop 1940 /* We use stop because stopModal/abortModal out of the main loop
1882 does not seem to work in 10.6. But as we use stop we must send a 1941 does not seem to work in 10.6. But as we use stop we must send a
1883 real event so the stop is seen and acted upon. */ 1942 real event so the stop is seen and acted upon. */
1884 [NSApp stop:self]; 1943 [NSApp stop: self];
1885 [NSApp postEvent: nxev atStart: NO]; 1944 [NSApp postEvent: nxev atStart: NO];
1886} 1945}
1887 1946
1888- (Lisp_Object)runDialogAt: (NSPoint)p 1947- (Lisp_Object) runDialogAt: (NSPoint) p
1889{ 1948{
1890 Lisp_Object ret = Qundefined; 1949 Lisp_Object ret = Qundefined;
1891 1950
@@ -1905,13 +1964,17 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1905 [[NSRunLoop currentRunLoop] addTimer: tmo 1964 [[NSRunLoop currentRunLoop] addTimer: tmo
1906 forMode: NSModalPanelRunLoopMode]; 1965 forMode: NSModalPanelRunLoopMode];
1907 } 1966 }
1967
1908 timer_fired = NO; 1968 timer_fired = NO;
1909 dialog_return = Qundefined; 1969 dialog_return = Qundefined;
1910 [NSApp runModalForWindow: self]; 1970 [NSApp runModalForWindow: self];
1911 ret = dialog_return; 1971 ret = dialog_return;
1912 if (! timer_fired) 1972
1973 if (!timer_fired)
1913 { 1974 {
1914 if (tmo != nil) [tmo invalidate]; /* Cancels timer. */ 1975 if (tmo != nil)
1976 [tmo invalidate]; /* Cancels timer. */
1977
1915 break; 1978 break;
1916 } 1979 }
1917 } 1980 }
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.
17You should have received a copy of the GNU General Public License 17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ 18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19 19
20/* 20/* Originally by Carl Edman
21Originally by Carl Edman 21 Updated by Christian Limpach (chris@nice.ch)
22Updated by Christian Limpach (chris@nice.ch) 22 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
23OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com) 23 macOS/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
24macOS/Aqua port by Christophe de Dinechin (descubes@earthlink.net) 24 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu) */
25GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
26*/
27 25
28/* This should be the first include, as it may set up #defines affecting 26/* This should be the first include, as it may set up #defines affecting
29 interpretation of even the system includes. */ 27 interpretation of even the system includes. */
@@ -559,6 +557,225 @@ nxatoms_of_nsselect (void)
559 nil] retain]; 557 nil] retain];
560} 558}
561 559
560static void
561ns_decode_data_to_pasteboard (Lisp_Object type, Lisp_Object data,
562 NSPasteboard *pasteboard)
563{
564 NSArray *types, *new;
565 NSMutableArray *temp;
566 Lisp_Object tem;
567 specpdl_ref count;
568#if !NS_USE_NSPasteboardTypeFileURL
569 NSURL *url;
570#endif
571
572 types = [pasteboard types];
573 count = SPECPDL_INDEX ();
574
575 CHECK_SYMBOL (type);
576
577 if (EQ (type, Qstring))
578 {
579 CHECK_STRING (data);
580
581 new = [types arrayByAddingObject: NSPasteboardTypeString];
582
583 [pasteboard declareTypes: new
584 owner: nil];
585 [pasteboard setString: [NSString stringWithLispString: data]
586 forType: NSPasteboardTypeString];
587 }
588 else if (EQ (type, Qfile))
589 {
590#if NS_USE_NSPasteboardTypeFileURL
591 if (CONSP (data))
592 new = [types arrayByAddingObject: NSPasteboardTypeURL];
593 else
594 new = [types arrayByAddingObject: NSPasteboardTypeFileURL];
595#else
596 new = [types arrayByAddingObject: NSFilenamesPboardType];
597#endif
598
599 [pasteboard declareTypes: new
600 owner: nil];
601
602 if (STRINGP (data))
603 {
604#if NS_USE_NSPasteboardTypeFileURL
605 [pasteboard setString: [NSString stringWithLispString: data]
606 forType: NSPasteboardTypeFileURL];
607#else
608 url = [NSURL URLWithString: [NSString stringWithLispString: data]];
609
610 if (!url)
611 signal_error ("Invalid file URL", data);
612
613 [pasteboard setString: [url path]
614 forType: NSFilenamesPboardType];
615#endif
616 }
617 else
618 {
619 CHECK_LIST (data);
620 temp = [[NSMutableArray alloc] init];
621 record_unwind_protect_ptr (ns_release_object, temp);
622
623 for (tem = data; CONSP (tem); tem = XCDR (tem))
624 {
625 CHECK_STRING (XCAR (tem));
626
627 [temp addObject: [NSString stringWithLispString: XCAR (tem)]];
628 }
629 CHECK_LIST_END (tem, data);
630#if NS_USE_NSPasteboardTypeFileURL
631 [pasteboard setPropertyList: temp
632 /* We have to use this deprecated pasteboard
633 type, since Apple doesn't let us use
634 dragImage:at: to drag multiple file URLs. */
635 forType: @"NSFilenamesPboardType"];
636#else
637 [pasteboard setPropertyList: temp
638 forType: NSFilenamesPboardType];
639#endif
640 unbind_to (count, Qnil);
641 }
642 }
643 else
644 signal_error ("Unknown pasteboard type", type);
645}
646
647static void
648ns_lisp_to_pasteboard (Lisp_Object object,
649 NSPasteboard *pasteboard)
650{
651 Lisp_Object tem, type, data;
652
653 [pasteboard declareTypes: [NSArray array]
654 owner: nil];
655
656 CHECK_LIST (object);
657 for (tem = object; CONSP (tem); tem = XCDR (tem))
658 {
659 maybe_quit ();
660
661 type = Fcar (Fcar (tem));
662 data = Fcdr (Fcar (tem));
663
664 ns_decode_data_to_pasteboard (type, data, pasteboard);
665 }
666 CHECK_LIST_END (tem, object);
667}
668
669static NSDragOperation
670ns_dnd_action_to_operation (Lisp_Object action)
671{
672 if (EQ (action, QXdndActionCopy))
673 return NSDragOperationCopy;
674
675 if (EQ (action, QXdndActionMove))
676 return NSDragOperationMove;
677
678 if (EQ (action, QXdndActionLink))
679 return NSDragOperationLink;
680
681 signal_error ("Unsupported drag-and-drop action", action);
682}
683
684static Lisp_Object
685ns_dnd_action_from_operation (NSDragOperation operation)
686{
687 switch (operation)
688 {
689 case NSDragOperationCopy:
690 return QXdndActionCopy;
691
692 case NSDragOperationMove:
693 return QXdndActionMove;
694
695 case NSDragOperationLink:
696 return QXdndActionLink;
697
698 case NSDragOperationNone:
699 return Qnil;
700
701 default:
702 return QXdndActionPrivate;
703 }
704}
705
706DEFUN ("ns-begin-drag", Fns_begin_drag, Sns_begin_drag, 3, 6, 0,
707 doc: /* Begin a drag-and-drop operation on FRAME.
708
709FRAME must be a window system frame. PBOARD is an alist of (TYPE
710. DATA), where TYPE is one of the following data types that determine
711the meaning of DATA:
712
713 - `string' means DATA should be a string describing text that will
714 be dragged to another program.
715
716 - `file' means DATA should be a file URL that will be dragged to
717 another program. DATA may also be a list of file names; that
718 means each file in the list will be dragged to another program.
719
720ACTION is the action that will be taken by the drop target towards the
721data inside PBOARD.
722
723Return the action that the drop target actually chose to perform, or
724nil if no action was performed (either because there was no drop
725target, or the drop was rejected). If RETURN-FRAME is the symbol
726`now', also return any frame that mouse moves into during the
727drag-and-drop operation, whilst simultaneously cancelling it. Any
728other non-nil value means to do the same, but to wait for the mouse to
729leave FRAME first.
730
731If ALLOW-SAME-FRAME is nil, dropping on FRAME will result in the drop
732being ignored.
733
734FOLLOW-TOOLTIP means the same thing it does in `x-begin-drag'. */)
735 (Lisp_Object frame, Lisp_Object pboard, Lisp_Object action,
736 Lisp_Object return_frame, Lisp_Object allow_same_frame,
737 Lisp_Object follow_tooltip)
738{
739 struct frame *f, *return_to;
740 NSPasteboard *pasteboard;
741 EmacsWindow *window;
742 NSDragOperation operation;
743 enum ns_return_frame_mode mode;
744 Lisp_Object val;
745
746 if (EQ (return_frame, Qnow))
747 mode = RETURN_FRAME_NOW;
748 else if (!NILP (return_frame))
749 mode = RETURN_FRAME_EVENTUALLY;
750 else
751 mode = RETURN_FRAME_NEVER;
752
753 if (NILP (pboard))
754 signal_error ("Empty pasteboard", pboard);
755
756 f = decode_window_system_frame (frame);
757 pasteboard = [NSPasteboard pasteboardWithName: NSPasteboardNameDrag];
758 window = (EmacsWindow *) [FRAME_NS_VIEW (f) window];
759
760 operation = ns_dnd_action_to_operation (action);
761 ns_lisp_to_pasteboard (pboard, pasteboard);
762
763 operation = [window beginDrag: operation
764 forPasteboard: pasteboard
765 withMode: mode
766 returnFrameTo: &return_to
767 prohibitSame: (BOOL) NILP (allow_same_frame)
768 followTooltip: (BOOL) !NILP (follow_tooltip)];
769
770 if (return_to)
771 {
772 XSETFRAME (val, return_to);
773 return val;
774 }
775
776 return ns_dnd_action_from_operation (operation);
777}
778
562void 779void
563syms_of_nsselect (void) 780syms_of_nsselect (void)
564{ 781{
@@ -568,12 +785,18 @@ syms_of_nsselect (void)
568 DEFSYM (QFILE_NAME, "FILE_NAME"); 785 DEFSYM (QFILE_NAME, "FILE_NAME");
569 786
570 DEFSYM (QTARGETS, "TARGETS"); 787 DEFSYM (QTARGETS, "TARGETS");
788 DEFSYM (QXdndActionCopy, "XdndActionCopy");
789 DEFSYM (QXdndActionMove, "XdndActionMove");
790 DEFSYM (QXdndActionLink, "XdndActionLink");
791 DEFSYM (QXdndActionPrivate, "XdndActionPrivate");
792 DEFSYM (Qnow, "now");
571 793
572 defsubr (&Sns_disown_selection_internal); 794 defsubr (&Sns_disown_selection_internal);
573 defsubr (&Sns_get_selection); 795 defsubr (&Sns_get_selection);
574 defsubr (&Sns_own_selection_internal); 796 defsubr (&Sns_own_selection_internal);
575 defsubr (&Sns_selection_exists_p); 797 defsubr (&Sns_selection_exists_p);
576 defsubr (&Sns_selection_owner_p); 798 defsubr (&Sns_selection_owner_p);
799 defsubr (&Sns_begin_drag);
577 800
578 Vselection_alist = Qnil; 801 Vselection_alist = Qnil;
579 staticpro (&Vselection_alist); 802 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;
408@end 408@end
409#endif 409#endif
410 410
411enum ns_return_frame_mode
412 {
413 RETURN_FRAME_NEVER,
414 RETURN_FRAME_EVENTUALLY,
415 RETURN_FRAME_NOW,
416 };
417
411/* EmacsWindow */ 418/* EmacsWindow */
412@interface EmacsWindow : NSWindow 419@interface EmacsWindow : NSWindow
413{ 420{
414 NSPoint grabOffset; 421 NSPoint grabOffset;
422 NSEvent *last_drag_event;
423 NSDragOperation drag_op;
424 NSDragOperation selected_op;
425
426 struct frame *dnd_return_frame;
427 enum ns_return_frame_mode dnd_mode;
428 BOOL dnd_allow_same_frame;
429 BOOL dnd_move_tooltip_with_frame;
415} 430}
416 431
417#ifdef NS_IMPL_GNUSTEP 432#ifdef NS_IMPL_GNUSTEP
418- (NSInteger) orderedIndex; 433- (NSInteger) orderedIndex;
419#endif 434#endif
420 435
421- (instancetype)initWithEmacsFrame:(struct frame *)f; 436- (instancetype) initWithEmacsFrame: (struct frame *) f;
422- (instancetype)initWithEmacsFrame:(struct frame *)f fullscreen:(BOOL)fullscreen screen:(NSScreen *)screen; 437- (instancetype) initWithEmacsFrame: (struct frame *) f
423- (void)createToolbar:(struct frame *)f; 438 fullscreen: (BOOL) fullscreen
424- (void)setParentChildRelationships; 439 screen: (NSScreen *) screen;
425- (NSInteger)borderWidth; 440- (void) createToolbar: (struct frame *) f;
426- (BOOL)restackWindow:(NSWindow *)win above:(BOOL)above; 441- (void) setParentChildRelationships;
427- (void)setAppearance; 442- (NSInteger) borderWidth;
443- (BOOL) restackWindow: (NSWindow *) win above: (BOOL) above;
444- (void) setAppearance;
445- (void) setLastDragEvent: (NSEvent *) event;
446- (NSDragOperation) beginDrag: (NSDragOperation) op
447 forPasteboard: (NSPasteboard *) pasteboard
448 withMode: (enum ns_return_frame_mode) mode
449 returnFrameTo: (struct frame **) frame_return
450 prohibitSame: (BOOL) prohibit_same_frame
451 followTooltip: (BOOL) follow_tooltip;
452- (BOOL) mustNotDropOn: (NSView *) receiver;
428@end 453@end
429 454
430 455
@@ -574,22 +599,32 @@ typedef id instancetype;
574 ========================================================================== */ 599 ========================================================================== */
575 600
576@interface EmacsDialogPanel : NSPanel 601@interface EmacsDialogPanel : NSPanel
577 { 602{
578 NSTextField *command; 603 NSTextField *command;
579 NSTextField *title; 604 NSTextField *title;
580 NSMatrix *matrix; 605 NSMatrix *matrix;
581 int rows, cols; 606 int rows, cols;
582 BOOL timer_fired, window_closed; 607 BOOL timer_fired, window_closed;
583 Lisp_Object dialog_return; 608 Lisp_Object dialog_return;
584 Lisp_Object *button_values; 609}
585 } 610
586- (instancetype)initFromContents: (Lisp_Object)menu isQuestion: (BOOL)isQ; 611- (instancetype) initWithTitle: (char *) title_str
587- (void)process_dialog: (Lisp_Object)list; 612 isQuestion: (BOOL) is_question;
588- (void)addButton: (char *)str value: (int)tag row: (int)row; 613- (void) processMenuItems: (Lisp_Object) menu_items
589- (void)addString: (char *)str row: (int)row; 614 used: (ptrdiff_t) menu_items_used
590- (void)addSplit; 615 withErrorOutput: (const char **) error_name;
591- (Lisp_Object)runDialogAt: (NSPoint)p; 616
592- (void)timeout_handler: (NSTimer *)timedEntry; 617- (void) addButton: (char *) str
618 value: (NSInteger) tag
619 row: (int) row
620 enable: (BOOL) enable;
621- (void) addString: (char *) str
622 row: (int) row;
623- (void) addSplit;
624- (void) resizeBoundsPriorToDisplay;
625
626- (Lisp_Object) runDialogAt: (NSPoint) p;
627- (void) timeout_handler: (NSTimer *) timedEntry;
593@end 628@end
594 629
595#ifdef NS_IMPL_COCOA 630#ifdef NS_IMPL_COCOA
@@ -597,19 +632,21 @@ typedef id instancetype;
597#else 632#else
598@interface EmacsTooltip : NSObject 633@interface EmacsTooltip : NSObject
599#endif 634#endif
600 { 635{
601 NSWindow *win; 636 NSWindow *win;
602 NSTextField *textField; 637 NSTextField *textField;
603 NSTimer *timer; 638 NSTimer *timer;
604 } 639}
640
605- (instancetype) init; 641- (instancetype) init;
606- (void) setText: (char *)text; 642- (void) setText: (char *) text;
607- (void) setBackgroundColor: (NSColor *)col; 643- (void) setBackgroundColor: (NSColor *) col;
608- (void) setForegroundColor: (NSColor *)col; 644- (void) setForegroundColor: (NSColor *) col;
609- (void) showAtX: (int)x Y: (int)y for: (int)seconds; 645- (void) showAtX: (int) x Y: (int) y for: (int) seconds;
610- (void) hide; 646- (void) hide;
611- (BOOL) isActive; 647- (BOOL) isActive;
612- (NSRect) frame; 648- (NSRect) frame;
649- (void) moveTo: (NSPoint) screen_point;
613@end 650@end
614 651
615 652
@@ -1107,6 +1144,9 @@ extern const char *ns_get_pending_menu_title (void);
1107#endif 1144#endif
1108 1145
1109/* Implemented in nsfns, published in nsterm. */ 1146/* Implemented in nsfns, published in nsterm. */
1147#ifdef __OBJC__
1148extern void ns_move_tooltip_to_mouse_location (NSPoint);
1149#endif
1110extern void ns_implicitly_set_name (struct frame *f, Lisp_Object arg, 1150extern void ns_implicitly_set_name (struct frame *f, Lisp_Object arg,
1111 Lisp_Object oldval); 1151 Lisp_Object oldval);
1112extern void ns_set_scroll_bar_default_width (struct frame *f); 1152extern void ns_set_scroll_bar_default_width (struct frame *f);
@@ -1176,6 +1216,7 @@ extern size_t ns_image_size_in_bytes (void *img);
1176/* This in nsterm.m */ 1216/* This in nsterm.m */
1177extern float ns_antialias_threshold; 1217extern float ns_antialias_threshold;
1178extern void ns_make_frame_visible (struct frame *f); 1218extern void ns_make_frame_visible (struct frame *f);
1219extern void ns_make_frame_invisible (struct frame *f);
1179extern void ns_iconify_frame (struct frame *f); 1220extern void ns_iconify_frame (struct frame *f);
1180extern void ns_set_undecorated (struct frame *f, Lisp_Object new_value, 1221extern void ns_set_undecorated (struct frame *f, Lisp_Object new_value,
1181 Lisp_Object old_value); 1222 Lisp_Object old_value);
@@ -1312,6 +1353,7 @@ enum NSWindowTabbingMode
1312#if !defined (NS_IMPL_COCOA) || !defined (MAC_OS_X_VERSION_10_13) 1353#if !defined (NS_IMPL_COCOA) || !defined (MAC_OS_X_VERSION_10_13)
1313/* Deprecated in macOS 10.13. */ 1354/* Deprecated in macOS 10.13. */
1314#define NSPasteboardNameGeneral NSGeneralPboard 1355#define NSPasteboardNameGeneral NSGeneralPboard
1356#define NSPasteboardNameDrag NSDragPboard
1315#endif 1357#endif
1316 1358
1317#if !defined (NS_IMPL_COCOA) || !defined (MAC_OS_X_VERSION_10_14) 1359#if !defined (NS_IMPL_COCOA) || !defined (MAC_OS_X_VERSION_10_14)
@@ -1329,5 +1371,6 @@ enum NSWindowTabbingMode
1329#define NSControlStateValueOn NSOnState 1371#define NSControlStateValueOn NSOnState
1330#define NSControlStateValueOff NSOffState 1372#define NSControlStateValueOff NSOffState
1331#define NSBezelStyleRounded NSRoundedBezelStyle 1373#define NSBezelStyleRounded NSRoundedBezelStyle
1374#define NSButtonTypeMomentaryPushIn NSMomentaryPushInButton
1332#endif 1375#endif
1333#endif /* HAVE_NS */ 1376#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;
79static EmacsMenu *mainMenu; 79static EmacsMenu *mainMenu;
80#endif 80#endif
81 81
82/* The last known monitor attributes list. */
83static Lisp_Object last_known_monitors;
84
82/* ========================================================================== 85/* ==========================================================================
83 86
84 NSTRACE, Trace support. 87 NSTRACE, Trace support.
@@ -89,8 +92,8 @@ static EmacsMenu *mainMenu;
89 92
90/* The following use "volatile" since they can be accessed from 93/* The following use "volatile" since they can be accessed from
91 parallel threads. */ 94 parallel threads. */
92volatile int nstrace_num = 0; 95volatile int nstrace_num;
93volatile int nstrace_depth = 0; 96volatile int nstrace_depth;
94 97
95/* When 0, no trace is emitted. This is used by NSTRACE_WHEN and 98/* When 0, no trace is emitted. This is used by NSTRACE_WHEN and
96 NSTRACE_UNLESS to silence functions called. 99 NSTRACE_UNLESS to silence functions called.
@@ -101,33 +104,41 @@ volatile int nstrace_depth = 0;
101volatile int nstrace_enabled_global = 1; 104volatile int nstrace_enabled_global = 1;
102 105
103/* Called when nstrace_enabled goes out of scope. */ 106/* Called when nstrace_enabled goes out of scope. */
104void nstrace_leave(int * pointer_to_nstrace_enabled) 107void
108nstrace_leave (int *pointer_to_nstrace_enabled)
105{ 109{
106 if (*pointer_to_nstrace_enabled) 110 if (*pointer_to_nstrace_enabled)
107 { 111 --nstrace_depth;
108 --nstrace_depth;
109 }
110} 112}
111 113
112 114
113/* Called when nstrace_saved_enabled_global goes out of scope. */ 115/* Called when nstrace_saved_enabled_global goes out of scope. */
114void nstrace_restore_global_trace_state(int * pointer_to_saved_enabled_global) 116void
117nstrace_restore_global_trace_state (int *pointer_to_saved_enabled_global)
115{ 118{
116 nstrace_enabled_global = *pointer_to_saved_enabled_global; 119 nstrace_enabled_global = *pointer_to_saved_enabled_global;
117} 120}
118 121
119 122
120char const * nstrace_fullscreen_type_name (int fs_type) 123const char *
124nstrace_fullscreen_type_name (int fs_type)
121{ 125{
122 switch (fs_type) 126 switch (fs_type)
123 { 127 {
124 case -1: return "-1"; 128 case -1:
125 case FULLSCREEN_NONE: return "FULLSCREEN_NONE"; 129 return "-1";
126 case FULLSCREEN_WIDTH: return "FULLSCREEN_WIDTH"; 130 case FULLSCREEN_NONE:
127 case FULLSCREEN_HEIGHT: return "FULLSCREEN_HEIGHT"; 131 return "FULLSCREEN_NONE";
128 case FULLSCREEN_BOTH: return "FULLSCREEN_BOTH"; 132 case FULLSCREEN_WIDTH:
129 case FULLSCREEN_MAXIMIZED: return "FULLSCREEN_MAXIMIZED"; 133 return "FULLSCREEN_WIDTH";
130 default: return "FULLSCREEN_?????"; 134 case FULLSCREEN_HEIGHT:
135 return "FULLSCREEN_HEIGHT";
136 case FULLSCREEN_BOTH:
137 return "FULLSCREEN_BOTH";
138 case FULLSCREEN_MAXIMIZED:
139 return "FULLSCREEN_MAXIMIZED";
140 default:
141 return "FULLSCREEN_?????";
131 } 142 }
132} 143}
133#endif 144#endif
@@ -429,28 +440,28 @@ ev_modifiers_helper (unsigned int flags, unsigned int left_mask,
429 440
430/* This is a piece of code which is common to all the event handling 441/* This is a piece of code which is common to all the event handling
431 methods. Maybe it should even be a function. */ 442 methods. Maybe it should even be a function. */
432#define EV_TRAILER(e) \ 443#define EV_TRAILER(e) \
433 { \ 444 { \
434 XSETFRAME (emacs_event->frame_or_window, emacsframe); \ 445 XSETFRAME (emacs_event->frame_or_window, emacsframe); \
435 EV_TRAILER2 (e); \ 446 EV_TRAILER2 (e); \
436 } 447 }
437 448
438#define EV_TRAILER2(e) \ 449#define EV_TRAILER2(e) \
439 { \ 450 { \
440 if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \ 451 if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
441 if (q_event_ptr) \ 452 if (q_event_ptr) \
442 { \ 453 { \
443 Lisp_Object tem = Vinhibit_quit; \ 454 Lisp_Object tem = Vinhibit_quit; \
444 Vinhibit_quit = Qt; \ 455 Vinhibit_quit = Qt; \
445 n_emacs_events_pending++; \ 456 n_emacs_events_pending++; \
446 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \ 457 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
447 Vinhibit_quit = tem; \ 458 Vinhibit_quit = tem; \
448 } \ 459 } \
449 else \ 460 else \
450 hold_event (emacs_event); \ 461 hold_event (emacs_event); \
451 EVENT_INIT (*emacs_event); \ 462 EVENT_INIT (*emacs_event); \
452 ns_send_appdefined (-1); \ 463 ns_send_appdefined (-1); \
453 } 464 }
454 465
455 466
456/* TODO: Get rid of need for these forward declarations. */ 467/* TODO: Get rid of need for these forward declarations. */
@@ -1517,7 +1528,7 @@ ns_make_frame_visible (struct frame *f)
1517} 1528}
1518 1529
1519 1530
1520static void 1531void
1521ns_make_frame_invisible (struct frame *f) 1532ns_make_frame_invisible (struct frame *f)
1522/* -------------------------------------------------------------------------- 1533/* --------------------------------------------------------------------------
1523 Hide the window (X11 semantics) 1534 Hide the window (X11 semantics)
@@ -1708,10 +1719,8 @@ ns_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1708 1719
1709 1720
1710static void 1721static void
1711ns_set_window_size (struct frame *f, 1722ns_set_window_size (struct frame *f, bool change_gravity,
1712 bool change_gravity, 1723 int width, int height)
1713 int width,
1714 int height)
1715/* -------------------------------------------------------------------------- 1724/* --------------------------------------------------------------------------
1716 Adjust window pixel size based on native sizes WIDTH and HEIGHT. 1725 Adjust window pixel size based on native sizes WIDTH and HEIGHT.
1717 Impl is a bit more complex than other terms, need to do some 1726 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,
2288 struct frame *f = NULL; 2297 struct frame *f = NULL;
2289 struct ns_display_info *dpyinfo; 2298 struct ns_display_info *dpyinfo;
2290 bool return_no_frame_flag = false; 2299 bool return_no_frame_flag = false;
2300#ifdef NS_IMPL_COCOA
2301 NSPoint screen_position;
2302 NSInteger window_number;
2303 NSWindow *w;
2304#endif
2291 2305
2292 NSTRACE ("ns_mouse_position"); 2306 NSTRACE ("ns_mouse_position");
2293 2307
@@ -2314,18 +2328,29 @@ ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2314 This doesn't work on GNUstep, although in recent versions there 2328 This doesn't work on GNUstep, although in recent versions there
2315 is compatibility code that makes it a noop. */ 2329 is compatibility code that makes it a noop. */
2316 2330
2317 NSPoint screen_position = [NSEvent mouseLocation]; 2331 screen_position = [NSEvent mouseLocation];
2318 NSInteger window_number = 0; 2332 window_number = 0;
2333
2319 do 2334 do
2320 { 2335 {
2321 NSWindow *w; 2336 window_number = [NSWindow windowNumberAtPoint: screen_position
2337 belowWindowWithWindowNumber: window_number];
2338 w = [NSApp windowWithWindowNumber: window_number];
2322 2339
2323 window_number = [NSWindow windowNumberAtPoint:screen_position 2340 if ((EQ (track_mouse, Qdrag_source)
2324 belowWindowWithWindowNumber:window_number]; 2341 || EQ (track_mouse, Qdropping))
2325 w = [NSApp windowWithWindowNumber:window_number]; 2342 && w && [[w delegate] isKindOfClass: [EmacsTooltip class]])
2343 continue;
2326 2344
2327 if (w && [[w delegate] isKindOfClass:[EmacsView class]]) 2345 if (w && [[w delegate] isKindOfClass: [EmacsView class]])
2328 f = ((EmacsView *)[w delegate])->emacsframe; 2346 f = ((EmacsView *) [w delegate])->emacsframe;
2347 else if (EQ (track_mouse, Qdrag_source))
2348 break;
2349
2350 if (f && (EQ (track_mouse, Qdrag_source)
2351 || EQ (track_mouse, Qdropping))
2352 && FRAME_TOOLTIP_P (f))
2353 continue;
2329 } 2354 }
2330 while (window_number > 0 && !f); 2355 while (window_number > 0 && !f);
2331#endif 2356#endif
@@ -2340,6 +2365,9 @@ ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2340 if (!FRAME_NS_P (f)) 2365 if (!FRAME_NS_P (f))
2341 f = NULL; 2366 f = NULL;
2342 2367
2368 if (f && FRAME_TOOLTIP_P (f))
2369 f = dpyinfo->last_mouse_frame;
2370
2343 /* While dropping, use the last mouse frame only if there is no 2371 /* While dropping, use the last mouse frame only if there is no
2344 currently focused frame. */ 2372 currently focused frame. */
2345 if (!f && (EQ (track_mouse, Qdropping) 2373 if (!f && (EQ (track_mouse, Qdropping)
@@ -3079,7 +3107,9 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
3079 break; 3107 break;
3080 case HOLLOW_BOX_CURSOR: 3108 case HOLLOW_BOX_CURSOR:
3081 draw_phys_cursor_glyph (w, glyph_row, DRAW_NORMAL_TEXT); 3109 draw_phys_cursor_glyph (w, glyph_row, DRAW_NORMAL_TEXT);
3082 [NSBezierPath strokeRect: r]; 3110
3111 /* This works like it does in PostScript, not X Windows. */
3112 [NSBezierPath strokeRect: NSInsetRect (r, 0.5, 0.5)];
3083 break; 3113 break;
3084 case HBAR_CURSOR: 3114 case HBAR_CURSOR:
3085 NSRectFill (r); 3115 NSRectFill (r);
@@ -3448,36 +3478,35 @@ ns_draw_box (NSRect r, CGFloat hthickness, CGFloat vthickness,
3448 3478
3449static void 3479static void
3450ns_draw_relief (NSRect outer, int hthickness, int vthickness, char raised_p, 3480ns_draw_relief (NSRect outer, int hthickness, int vthickness, char raised_p,
3451 char top_p, char bottom_p, char left_p, char right_p, 3481 char top_p, char bottom_p, char left_p, char right_p,
3452 struct glyph_string *s) 3482 struct glyph_string *s)
3453/* -------------------------------------------------------------------------- 3483/* --------------------------------------------------------------------------
3454 Draw a relief rect inside r, optionally leaving some sides open. 3484 Draw a relief rect inside r, optionally leaving some sides open.
3455 Note we can't just use an NSDrawBezel command, because of the possibility 3485 Note we can't just use an NSDrawBezel command, because of the possibility
3456 of some sides not being drawn, and because the rect will be filled. 3486 of some sides not being drawn, and because the rect will be filled.
3457 -------------------------------------------------------------------------- */ 3487 -------------------------------------------------------------------------- */
3458{ 3488{
3459 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil; 3489 static NSColor *baseCol, *lightCol, *darkCol;
3460 NSColor *newBaseCol = nil; 3490 NSColor *newBaseCol;
3461 NSRect inner; 3491 NSRect inner;
3492 NSBezierPath *p;
3493
3494 baseCol = nil;
3495 lightCol = nil;
3496 newBaseCol = nil;
3497 p = nil;
3462 3498
3463 NSTRACE ("ns_draw_relief"); 3499 NSTRACE ("ns_draw_relief");
3464 3500
3465 /* set up colors */ 3501 /* set up colors */
3466 3502
3467 if (s->face->use_box_color_for_shadows_p) 3503 if (s->face->use_box_color_for_shadows_p)
3468 { 3504 newBaseCol = [NSColor colorWithUnsignedLong: s->face->box_color];
3469 newBaseCol = [NSColor colorWithUnsignedLong:s->face->box_color];
3470 }
3471/* else if (s->first_glyph->type == IMAGE_GLYPH
3472 && s->img->pixmap
3473 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3474 {
3475 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
3476 } */
3477 else 3505 else
3478 { 3506 newBaseCol = [NSColor colorWithUnsignedLong: s->face->background];
3479 newBaseCol = [NSColor colorWithUnsignedLong:s->face->background]; 3507
3480 } 3508 if (s->hl == DRAW_CURSOR)
3509 newBaseCol = FRAME_CURSOR_COLOR (s->f);
3481 3510
3482 if (newBaseCol == nil) 3511 if (newBaseCol == nil)
3483 newBaseCol = [NSColor grayColor]; 3512 newBaseCol = [NSColor grayColor];
@@ -3487,35 +3516,49 @@ ns_draw_relief (NSRect outer, int hthickness, int vthickness, char raised_p,
3487 [baseCol release]; 3516 [baseCol release];
3488 baseCol = [newBaseCol retain]; 3517 baseCol = [newBaseCol retain];
3489 [lightCol release]; 3518 [lightCol release];
3490 lightCol = [[baseCol highlightWithLevel: 0.2] retain]; 3519 lightCol = [[baseCol highlightWithLevel: 0.4] retain];
3491 [darkCol release]; 3520 [darkCol release];
3492 darkCol = [[baseCol shadowWithLevel: 0.3] retain]; 3521 darkCol = [[baseCol shadowWithLevel: 0.4] retain];
3493 } 3522 }
3494 3523
3495 /* Calculate the inner rectangle. */ 3524 /* Calculate the inner rectangle. */
3496 inner = NSMakeRect (NSMinX (outer) + (left_p ? hthickness : 0), 3525 inner = outer;
3497 NSMinY (outer) + (top_p ? vthickness : 0), 3526
3498 NSWidth (outer) - (left_p ? hthickness : 0) 3527 if (left_p)
3499 - (right_p ? hthickness : 0), 3528 {
3500 NSHeight (outer) - (top_p ? vthickness : 0) 3529 inner.origin.x += vthickness;
3501 - (bottom_p ? vthickness : 0)); 3530 inner.size.width -= vthickness;
3531 }
3532
3533 if (right_p)
3534 inner.size.width -= vthickness;
3535
3536 if (top_p)
3537 {
3538 inner.origin.y += hthickness;
3539 inner.size.height -= hthickness;
3540 }
3541
3542 if (bottom_p)
3543 inner.size.height -= hthickness;
3502 3544
3503 [(raised_p ? lightCol : darkCol) set]; 3545 [(raised_p ? lightCol : darkCol) set];
3504 3546
3505 if (top_p || left_p) 3547 if (top_p || left_p)
3506 { 3548 {
3507 NSBezierPath *p = [NSBezierPath bezierPath]; 3549 p = [NSBezierPath bezierPath];
3508 [p moveToPoint:NSMakePoint (NSMinX (outer), NSMinY (outer))]; 3550
3551 [p moveToPoint: NSMakePoint (NSMinX (outer), NSMinY (outer))];
3509 if (top_p) 3552 if (top_p)
3510 { 3553 {
3511 [p lineToPoint:NSMakePoint (NSMaxX (outer), NSMinY (outer))]; 3554 [p lineToPoint: NSMakePoint (NSMaxX (outer), NSMinY (outer))];
3512 [p lineToPoint:NSMakePoint (NSMaxX (inner), NSMinY (inner))]; 3555 [p lineToPoint: NSMakePoint (NSMaxX (inner), NSMinY (inner))];
3513 } 3556 }
3514 [p lineToPoint:NSMakePoint (NSMinX (inner), NSMinY (inner))]; 3557 [p lineToPoint: NSMakePoint (NSMinX (inner), NSMinY (inner))];
3515 if (left_p) 3558 if (left_p)
3516 { 3559 {
3517 [p lineToPoint:NSMakePoint (NSMinX (inner), NSMaxY (inner))]; 3560 [p lineToPoint: NSMakePoint (NSMinX (inner), NSMaxY (inner))];
3518 [p lineToPoint:NSMakePoint (NSMinX (outer), NSMaxY (outer))]; 3561 [p lineToPoint: NSMakePoint (NSMinX (outer), NSMaxY (outer))];
3519 } 3562 }
3520 [p closePath]; 3563 [p closePath];
3521 [p fill]; 3564 [p fill];
@@ -3523,24 +3566,93 @@ ns_draw_relief (NSRect outer, int hthickness, int vthickness, char raised_p,
3523 3566
3524 [(raised_p ? darkCol : lightCol) set]; 3567 [(raised_p ? darkCol : lightCol) set];
3525 3568
3526 if (bottom_p || right_p) 3569 if (bottom_p || right_p)
3527 { 3570 {
3528 NSBezierPath *p = [NSBezierPath bezierPath]; 3571 p = [NSBezierPath bezierPath];
3529 [p moveToPoint:NSMakePoint (NSMaxX (outer), NSMaxY (outer))]; 3572
3573 [p moveToPoint: NSMakePoint (NSMaxX (outer), NSMaxY (outer))];
3530 if (right_p) 3574 if (right_p)
3531 { 3575 {
3532 [p lineToPoint:NSMakePoint (NSMaxX (outer), NSMinY (outer))]; 3576 [p lineToPoint: NSMakePoint (NSMaxX (outer), NSMinY (outer))];
3533 [p lineToPoint:NSMakePoint (NSMaxX (inner), NSMinY (inner))]; 3577 [p lineToPoint: NSMakePoint (NSMaxX (inner), NSMinY (inner))];
3534 } 3578 }
3535 [p lineToPoint:NSMakePoint (NSMaxX (inner), NSMaxY (inner))]; 3579 [p lineToPoint:NSMakePoint (NSMaxX (inner), NSMaxY (inner))];
3536 if (bottom_p) 3580 if (bottom_p)
3537 { 3581 {
3538 [p lineToPoint:NSMakePoint (NSMinX (inner), NSMaxY (inner))]; 3582 [p lineToPoint: NSMakePoint (NSMinX (inner), NSMaxY (inner))];
3539 [p lineToPoint:NSMakePoint (NSMinX (outer), NSMaxY (outer))]; 3583 [p lineToPoint: NSMakePoint (NSMinX (outer), NSMaxY (outer))];
3540 } 3584 }
3541 [p closePath]; 3585 [p closePath];
3542 [p fill]; 3586 [p fill];
3543 } 3587 }
3588
3589 /* If one of h/vthickness are more than 1, draw the outermost line
3590 on the respective sides in the black relief color. */
3591
3592 if (p)
3593 [p removeAllPoints];
3594 else
3595 p = [NSBezierPath bezierPath];
3596
3597 if (hthickness > 1 && top_p)
3598 {
3599 [p moveToPoint: NSMakePoint (NSMinX (outer),
3600 NSMinY (outer) + 0.5)];
3601 [p lineToPoint: NSMakePoint (NSMaxX (outer),
3602 NSMinY (outer) + 0.5)];
3603 }
3604
3605 if (hthickness > 1 && bottom_p)
3606 {
3607 [p moveToPoint: NSMakePoint (NSMinX (outer),
3608 NSMaxY (outer) - 0.5)];
3609 [p lineToPoint: NSMakePoint (NSMaxX (outer),
3610 NSMaxY (outer) - 0.5)];
3611 }
3612
3613 if (vthickness > 1 && left_p)
3614 {
3615 [p moveToPoint: NSMakePoint (NSMinX (outer) + 0.5,
3616 NSMinY (outer) + 0.5)];
3617 [p lineToPoint: NSMakePoint (NSMinX (outer) + 0.5,
3618 NSMaxY (outer) - 0.5)];
3619 }
3620
3621 if (vthickness > 1 && left_p)
3622 {
3623 [p moveToPoint: NSMakePoint (NSMinX (outer) + 0.5,
3624 NSMinY (outer) + 0.5)];
3625 [p lineToPoint: NSMakePoint (NSMinX (outer) + 0.5,
3626 NSMaxY (outer) - 0.5)];
3627 }
3628
3629 [darkCol set];
3630 [p stroke];
3631
3632 if (vthickness > 1 && hthickness > 1)
3633 {
3634 [FRAME_BACKGROUND_COLOR (s->f) set];
3635
3636 if (left_p && top_p)
3637 [NSBezierPath fillRect: NSMakeRect (NSMinX (outer),
3638 NSMinY (outer),
3639 1, 1)];
3640
3641 if (right_p && top_p)
3642 [NSBezierPath fillRect: NSMakeRect (NSMaxX (outer) - 1,
3643 NSMinY (outer),
3644 1, 1)];
3645
3646 if (right_p && bottom_p)
3647 [NSBezierPath fillRect: NSMakeRect (NSMaxX (outer) - 1,
3648 NSMaxY (outer) - 1,
3649 1, 1)];
3650
3651 if (left_p && bottom_p)
3652 [NSBezierPath fillRect: NSMakeRect (NSMinX (outer),
3653 NSMaxY (outer) - 1,
3654 1, 1)];
3655 }
3544} 3656}
3545 3657
3546 3658
@@ -3622,6 +3734,7 @@ ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3622 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/) 3734 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3623 { 3735 {
3624 int box_line_width = max (s->face->box_horizontal_line_width, 0); 3736 int box_line_width = max (s->face->box_horizontal_line_width, 0);
3737
3625 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width 3738 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3626 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font 3739 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3627 dimensions, since the actual glyphs might be much 3740 dimensions, since the actual glyphs might be much
@@ -3648,7 +3761,7 @@ ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3648 3761
3649 NSRect r = NSMakeRect (s->x, s->y + box_line_width, 3762 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3650 s->background_width, 3763 s->background_width,
3651 s->height-2*box_line_width); 3764 s->height - 2 * box_line_width);
3652 NSRectFill (r); 3765 NSRectFill (r);
3653 3766
3654 s->background_filled_p = 1; 3767 s->background_filled_p = 1;
@@ -3656,6 +3769,92 @@ ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3656 } 3769 }
3657} 3770}
3658 3771
3772static void
3773ns_draw_image_relief (struct glyph_string *s)
3774{
3775 int x1, y1, thick;
3776 bool raised_p, top_p, bot_p, left_p, right_p;
3777 int extra_x, extra_y;
3778 int x = s->x;
3779 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3780
3781 /* If first glyph of S has a left box line, start drawing it to the
3782 right of that line. */
3783 if (s->face->box != FACE_NO_BOX
3784 && s->first_glyph->left_box_line_p
3785 && s->slice.x == 0)
3786 x += max (s->face->box_vertical_line_width, 0);
3787
3788 /* If there is a margin around the image, adjust x- and y-position
3789 by that margin. */
3790 if (s->slice.x == 0)
3791 x += s->img->hmargin;
3792 if (s->slice.y == 0)
3793 y += s->img->vmargin;
3794
3795 if (s->hl == DRAW_IMAGE_SUNKEN
3796 || s->hl == DRAW_IMAGE_RAISED)
3797 {
3798 if (s->face->id == TAB_BAR_FACE_ID)
3799 thick = (tab_bar_button_relief < 0
3800 ? DEFAULT_TAB_BAR_BUTTON_RELIEF
3801 : min (tab_bar_button_relief, 1000000));
3802 else
3803 thick = (tool_bar_button_relief < 0
3804 ? DEFAULT_TOOL_BAR_BUTTON_RELIEF
3805 : min (tool_bar_button_relief, 1000000));
3806 raised_p = s->hl == DRAW_IMAGE_RAISED;
3807 }
3808 else
3809 {
3810 thick = eabs (s->img->relief);
3811 raised_p = s->img->relief > 0;
3812 }
3813
3814 x1 = x + s->slice.width - 1;
3815 y1 = y + s->slice.height - 1;
3816
3817 extra_x = extra_y = 0;
3818 if (s->face->id == TAB_BAR_FACE_ID)
3819 {
3820 if (CONSP (Vtab_bar_button_margin)
3821 && FIXNUMP (XCAR (Vtab_bar_button_margin))
3822 && FIXNUMP (XCDR (Vtab_bar_button_margin)))
3823 {
3824 extra_x = XFIXNUM (XCAR (Vtab_bar_button_margin)) - thick;
3825 extra_y = XFIXNUM (XCDR (Vtab_bar_button_margin)) - thick;
3826 }
3827 else if (FIXNUMP (Vtab_bar_button_margin))
3828 extra_x = extra_y = XFIXNUM (Vtab_bar_button_margin) - thick;
3829 }
3830
3831 if (s->face->id == TOOL_BAR_FACE_ID)
3832 {
3833 if (CONSP (Vtool_bar_button_margin)
3834 && FIXNUMP (XCAR (Vtool_bar_button_margin))
3835 && FIXNUMP (XCDR (Vtool_bar_button_margin)))
3836 {
3837 extra_x = XFIXNUM (XCAR (Vtool_bar_button_margin));
3838 extra_y = XFIXNUM (XCDR (Vtool_bar_button_margin));
3839 }
3840 else if (FIXNUMP (Vtool_bar_button_margin))
3841 extra_x = extra_y = XFIXNUM (Vtool_bar_button_margin);
3842 }
3843
3844 top_p = bot_p = left_p = right_p = false;
3845
3846 if (s->slice.x == 0)
3847 x -= thick + extra_x, left_p = true;
3848 if (s->slice.y == 0)
3849 y -= thick + extra_y, top_p = true;
3850 if (s->slice.x + s->slice.width == s->img->width)
3851 x1 += thick + extra_x, right_p = true;
3852 if (s->slice.y + s->slice.height == s->img->height)
3853 y1 += thick + extra_y, bot_p = true;
3854
3855 ns_draw_relief (NSMakeRect (x, y, x1 - x + 1, y1 - y + 1), thick,
3856 thick, raised_p, top_p, bot_p, left_p, right_p, s);
3857}
3659 3858
3660static void 3859static void
3661ns_dumpglyphs_image (struct glyph_string *s, NSRect r) 3860ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
@@ -3667,8 +3866,6 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3667 int box_line_vwidth = max (s->face->box_horizontal_line_width, 0); 3866 int box_line_vwidth = max (s->face->box_horizontal_line_width, 0);
3668 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice); 3867 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3669 int bg_x, bg_y, bg_height; 3868 int bg_x, bg_y, bg_height;
3670 int th;
3671 char raised_p;
3672 NSRect br; 3869 NSRect br;
3673 struct face *face = s->face; 3870 struct face *face = s->face;
3674 NSColor *tdCol; 3871 NSColor *tdCol;
@@ -3762,51 +3959,29 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3762 if (s->hl == DRAW_CURSOR) 3959 if (s->hl == DRAW_CURSOR)
3763 { 3960 {
3764 [FRAME_CURSOR_COLOR (s->f) set]; 3961 [FRAME_CURSOR_COLOR (s->f) set];
3765 tdCol = [NSColor colorWithUnsignedLong:NS_FACE_BACKGROUND (face)]; 3962 tdCol = [NSColor colorWithUnsignedLong: NS_FACE_BACKGROUND (face)];
3766 } 3963 }
3767 else 3964 else
3768 { 3965 tdCol = [NSColor colorWithUnsignedLong: NS_FACE_FOREGROUND (face)];
3769 tdCol = [NSColor colorWithUnsignedLong:NS_FACE_FOREGROUND (face)];
3770 }
3771 3966
3772 /* Draw underline, overline, strike-through. */ 3967 /* Draw underline, overline, strike-through. */
3773 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x); 3968 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3774 3969
3775 /* Draw relief, if requested */ 3970 /* If we must draw a relief around the image, do it. */
3776 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN) 3971 if (s->img->relief
3777 { 3972 || s->hl == DRAW_IMAGE_RAISED
3778 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED) 3973 || s->hl == DRAW_IMAGE_SUNKEN)
3779 { 3974 ns_draw_image_relief (s);
3780 th = (tool_bar_button_relief < 0
3781 ? DEFAULT_TOOL_BAR_BUTTON_RELIEF
3782 : min (tool_bar_button_relief, 1000000));
3783 raised_p = (s->hl == DRAW_IMAGE_RAISED);
3784 }
3785 else
3786 {
3787 th = abs (s->img->relief);
3788 raised_p = (s->img->relief > 0);
3789 }
3790
3791 r.origin.x = x - th;
3792 r.origin.y = y - th;
3793 r.size.width = s->slice.width + 2*th-1;
3794 r.size.height = s->slice.height + 2*th-1;
3795 ns_draw_relief (r, th, th, raised_p,
3796 s->slice.y == 0,
3797 s->slice.y + s->slice.height == s->img->height,
3798 s->slice.x == 0,
3799 s->slice.x + s->slice.width == s->img->width, s);
3800 }
3801 3975
3802 /* If there is no mask, the background won't be seen, 3976 /* If there is no mask, the background won't be seen, so draw a
3803 so draw a rectangle on the image for the cursor. 3977 rectangle on the image for the cursor. Do this for all images,
3804 Do this for all images, getting transparency right is not reliable. */ 3978 getting transparency right is not reliable. */
3805 if (s->hl == DRAW_CURSOR) 3979 if (s->hl == DRAW_CURSOR)
3806 { 3980 {
3807 int thickness = abs (s->img->relief); 3981 int thickness = abs (s->img->relief);
3808 if (thickness == 0) thickness = 1; 3982 if (thickness == 0) thickness = 1;
3809 ns_draw_box (br, thickness, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1); 3983 ns_draw_box (br, thickness, thickness,
3984 FRAME_CURSOR_COLOR (s->f), 1, 1);
3810 } 3985 }
3811} 3986}
3812 3987
@@ -4035,6 +4210,10 @@ ns_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
4035 YES, YES); 4210 YES, YES);
4036 x += glyph->pixel_width; 4211 x += glyph->pixel_width;
4037 } 4212 }
4213
4214 /* GCC 12 complains even though nothing ever uses s->char2b after
4215 this function returns. */
4216 s->char2b = NULL;
4038} 4217}
4039 4218
4040static void 4219static void
@@ -4363,11 +4542,14 @@ check_native_fs ()
4363 4542
4364 4543
4365static int 4544static int
4366ns_read_socket (struct terminal *terminal, struct input_event *hold_quit) 4545ns_read_socket_1 (struct terminal *terminal, struct input_event *hold_quit,
4546 BOOL no_release)
4367/* -------------------------------------------------------------------------- 4547/* --------------------------------------------------------------------------
4368 External (hook): Post an event to ourself and keep reading events until 4548 External (hook): Post an event to ourself and keep reading events until
4369 we read it back again. In effect process all events which were waiting. 4549 we read it back again. In effect process all events which were waiting.
4370 From 21+ we have to manage the event buffer ourselves. 4550 From 21+ we have to manage the event buffer ourselves.
4551
4552 NO_RELEASE means not to touch the global autorelease pool.
4371 -------------------------------------------------------------------------- */ 4553 -------------------------------------------------------------------------- */
4372{ 4554{
4373 struct input_event ev; 4555 struct input_event ev;
@@ -4398,11 +4580,14 @@ ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4398 ns_init_events (&ev); 4580 ns_init_events (&ev);
4399 q_event_ptr = hold_quit; 4581 q_event_ptr = hold_quit;
4400 4582
4401 /* We manage autorelease pools by allocate/reallocate each time around 4583 if (!no_release)
4402 the loop; strict nesting is occasionally violated but seems not to 4584 {
4403 matter... earlier methods using full nesting caused major memory leaks. */ 4585 /* We manage autorelease pools by allocate/reallocate each time around
4404 [outerpool release]; 4586 the loop; strict nesting is occasionally violated but seems not to
4405 outerpool = [[NSAutoreleasePool alloc] init]; 4587 matter... earlier methods using full nesting caused major memory leaks. */
4588 [outerpool release];
4589 outerpool = [[NSAutoreleasePool alloc] init];
4590 }
4406 4591
4407 /* If have pending open-file requests, attend to the next one of those. */ 4592 /* If have pending open-file requests, attend to the next one of those. */
4408 if (ns_pending_files && [ns_pending_files count] != 0 4593 if (ns_pending_files && [ns_pending_files count] != 0
@@ -4441,6 +4626,12 @@ ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4441 return nevents; 4626 return nevents;
4442} 4627}
4443 4628
4629static int
4630ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4631{
4632 return ns_read_socket_1 (terminal, hold_quit, NO);
4633}
4634
4444 4635
4445static int 4636static int
4446ns_select_1 (int nfds, fd_set *readfds, fd_set *writefds, 4637ns_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,
5022} 5213}
5023#endif 5214#endif
5024 5215
5025/* This and next define (many of the) public functions in this file. */ 5216static void
5026/* gui_* are generic versions in xdisp.c that we, and other terms, get away 5217ns_flush_display (struct frame *f)
5027 with using despite presence in the "system dependent" redisplay 5218{
5028 interface. In addition, many of the ns_ methods have code that is 5219 struct input_event ie;
5029 shared with all terms, indicating need for further refactoring. */ 5220
5221 EVENT_INIT (ie);
5222 ns_read_socket_1 (FRAME_TERMINAL (f), &ie, YES);
5223}
5224
5225/* This and next define (many of the) public functions in this
5226 file. */
5227/* gui_* are generic versions in xdisp.c that we, and other terms, get
5228 away with using despite presence in the "system dependent"
5229 redisplay interface. In addition, many of the ns_ methods have
5230 code that is shared with all terms, indicating need for further
5231 refactoring. */
5030extern frame_parm_handler ns_frame_parm_handlers[]; 5232extern frame_parm_handler ns_frame_parm_handlers[];
5031static struct redisplay_interface ns_redisplay_interface = 5233static struct redisplay_interface ns_redisplay_interface =
5032{ 5234{
@@ -5043,7 +5245,7 @@ static struct redisplay_interface ns_redisplay_interface =
5043#else 5245#else
5044 ns_update_window_end, 5246 ns_update_window_end,
5045#endif 5247#endif
5046 0, /* flush_display */ 5248 ns_flush_display,
5047 gui_clear_window_mouse_face, 5249 gui_clear_window_mouse_face,
5048 gui_get_glyph_overhangs, 5250 gui_get_glyph_overhangs,
5049 gui_fix_overlapping_area, 5251 gui_fix_overlapping_area,
@@ -5064,6 +5266,39 @@ static struct redisplay_interface ns_redisplay_interface =
5064 ns_default_font_parameter 5266 ns_default_font_parameter
5065}; 5267};
5066 5268
5269#ifdef NS_IMPL_COCOA
5270static void
5271ns_displays_reconfigured (CGDirectDisplayID display,
5272 CGDisplayChangeSummaryFlags flags,
5273 void *user_info)
5274{
5275 struct input_event ie;
5276 union buffered_input_event *ev;
5277 Lisp_Object new_monitors;
5278
5279 EVENT_INIT (ie);
5280
5281 new_monitors = Fns_display_monitor_attributes_list (Qnil);
5282
5283 if (!NILP (Fequal (new_monitors, last_known_monitors)))
5284 return;
5285
5286 last_known_monitors = new_monitors;
5287
5288 ev = (kbd_store_ptr == kbd_buffer
5289 ? kbd_buffer + KBD_BUFFER_SIZE - 1
5290 : kbd_store_ptr - 1);
5291
5292 if (kbd_store_ptr != kbd_fetch_ptr
5293 && ev->ie.kind == MONITORS_CHANGED_EVENT)
5294 return;
5295
5296 ie.kind = MONITORS_CHANGED_EVENT;
5297 XSETTERMINAL (ie.arg, x_display_list->terminal);
5298
5299 kbd_buffer_store_event (&ie);
5300}
5301#endif
5067 5302
5068static void 5303static void
5069ns_delete_display (struct ns_display_info *dpyinfo) 5304ns_delete_display (struct ns_display_info *dpyinfo)
@@ -5419,6 +5654,16 @@ ns_term_init (Lisp_Object display_name)
5419 catch_child_signal (); 5654 catch_child_signal ();
5420#endif 5655#endif
5421 5656
5657#ifdef NS_IMPL_COCOA
5658 /* Begin listening for display reconfiguration, so we can run the
5659 appropriate hooks. FIXME: is this called when the resolution of
5660 a monitor changes? */
5661
5662 CGDisplayRegisterReconfigurationCallback (ns_displays_reconfigured,
5663 NULL);
5664#endif
5665 last_known_monitors = Fns_display_monitor_attributes_list (Qnil);
5666
5422 NSTRACE_MSG ("ns_term_init done"); 5667 NSTRACE_MSG ("ns_term_init done");
5423 5668
5424 unblock_input (); 5669 unblock_input ();
@@ -5459,6 +5704,10 @@ ns_term_shutdown (int sig)
5459 5704
5460- (id)init 5705- (id)init
5461{ 5706{
5707#ifdef NS_IMPL_GNUSTEP
5708 NSNotificationCenter *notification_center;
5709#endif
5710
5462 NSTRACE ("[EmacsApp init]"); 5711 NSTRACE ("[EmacsApp init]");
5463 5712
5464 if ((self = [super init])) 5713 if ((self = [super init]))
@@ -5471,6 +5720,14 @@ ns_term_shutdown (int sig)
5471#endif 5720#endif
5472 } 5721 }
5473 5722
5723#ifdef NS_IMPL_GNUSTEP
5724 notification_center = [NSNotificationCenter defaultCenter];
5725 [notification_center addObserver: self
5726 selector: @selector(updateMonitors:)
5727 name: NSApplicationDidChangeScreenParametersNotification
5728 object: nil];
5729#endif
5730
5474 return self; 5731 return self;
5475} 5732}
5476 5733
@@ -5483,11 +5740,11 @@ ns_term_shutdown (int sig)
5483#define NSAppKitVersionNumber10_9 1265 5740#define NSAppKitVersionNumber10_9 1265
5484#endif 5741#endif
5485 5742
5486 if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9) 5743 if ((int) NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5487 { 5744 {
5488 [super run]; 5745 [super run];
5489 return; 5746 return;
5490 } 5747 }
5491 5748
5492 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 5749 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5493 5750
@@ -5671,6 +5928,36 @@ ns_term_shutdown (int sig)
5671 return YES; 5928 return YES;
5672} 5929}
5673 5930
5931#ifdef NS_IMPL_GNUSTEP
5932- (void) updateMonitors: (NSNotification *) notification
5933{
5934 struct input_event ie;
5935 union buffered_input_event *ev;
5936 Lisp_Object new_monitors;
5937
5938 EVENT_INIT (ie);
5939
5940 new_monitors = Fns_display_monitor_attributes_list (Qnil);
5941
5942 if (!NILP (Fequal (new_monitors, last_known_monitors)))
5943 return;
5944
5945 last_known_monitors = new_monitors;
5946
5947 ev = (kbd_store_ptr == kbd_buffer
5948 ? kbd_buffer + KBD_BUFFER_SIZE - 1
5949 : kbd_store_ptr - 1);
5950
5951 if (kbd_store_ptr != kbd_fetch_ptr
5952 && ev->ie.kind == MONITORS_CHANGED_EVENT)
5953 return;
5954
5955 ie.kind = MONITORS_CHANGED_EVENT;
5956 XSETTERMINAL (ie.arg, x_display_list->terminal);
5957
5958 kbd_buffer_store_event (&ie);
5959}
5960#endif
5674 5961
5675/* ************************************************************************** 5962/* **************************************************************************
5676 5963
@@ -6814,17 +7101,24 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
6814{ 7101{
6815 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe); 7102 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6816 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil]; 7103 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
7104 EmacsWindow *window;
6817 7105
6818 NSTRACE ("[EmacsView mouseDown:]"); 7106 NSTRACE ("[EmacsView mouseDown:]");
6819 7107
6820 if (!emacs_event) 7108 if (!emacs_event)
6821 return; 7109 return;
6822 7110
7111 if (FRAME_TOOLTIP_P (emacsframe))
7112 return;
7113
6823 dpyinfo->last_mouse_frame = emacsframe; 7114 dpyinfo->last_mouse_frame = emacsframe;
6824 /* Appears to be needed to prevent spurious movement events generated on 7115 /* Appears to be needed to prevent spurious movement events generated on
6825 button clicks. */ 7116 button clicks. */
6826 emacsframe->mouse_moved = 0; 7117 emacsframe->mouse_moved = 0;
6827 7118
7119 window = (EmacsWindow *) [self window];
7120 [window setLastDragEvent: theEvent];
7121
6828 if ([theEvent type] == NSEventTypeScrollWheel) 7122 if ([theEvent type] == NSEventTypeScrollWheel)
6829 { 7123 {
6830#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 7124#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)
7017 tab_bar_p = EQ (window, emacsframe->tab_bar_window); 7311 tab_bar_p = EQ (window, emacsframe->tab_bar_window);
7018 7312
7019 if (tab_bar_p) 7313 if (tab_bar_p)
7020 tab_bar_arg = handle_tab_bar_click (emacsframe, x, y, EV_UDMODIFIERS (theEvent) & down_modifier, 7314 tab_bar_arg = handle_tab_bar_click (emacsframe, x, y,
7315 EV_UDMODIFIERS (theEvent) & down_modifier,
7021 EV_MODIFIERS (theEvent) | EV_UDMODIFIERS (theEvent)); 7316 EV_MODIFIERS (theEvent) | EV_UDMODIFIERS (theEvent));
7022 } 7317 }
7023 7318
@@ -7092,6 +7387,9 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
7092 NSPoint pt; 7387 NSPoint pt;
7093 BOOL dragging; 7388 BOOL dragging;
7094 7389
7390 if (FRAME_TOOLTIP_P (emacsframe))
7391 return;
7392
7095 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]"); 7393 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
7096 7394
7097 dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e); 7395 dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
@@ -8330,13 +8628,30 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
8330 8628
8331-(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender 8629-(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
8332{ 8630{
8631 id source;
8632
8333 NSTRACE ("[EmacsView draggingEntered:]"); 8633 NSTRACE ("[EmacsView draggingEntered:]");
8634
8635 source = [sender draggingSource];
8636
8637 if (source && [source respondsToSelector: @selector(mustNotDropOn:)]
8638 && [source mustNotDropOn: self])
8639 return NSDragOperationNone;
8640
8334 return NSDragOperationGeneric; 8641 return NSDragOperationGeneric;
8335} 8642}
8336 8643
8337 8644
8338-(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender 8645-(BOOL) prepareForDragOperation: (id <NSDraggingInfo>) sender
8339{ 8646{
8647 id source;
8648
8649 source = [sender draggingSource];
8650
8651 if (source && [source respondsToSelector: @selector(mustNotDropOn:)]
8652 && [source mustNotDropOn: self])
8653 return NO;
8654
8340 return YES; 8655 return YES;
8341} 8656}
8342 8657
@@ -8347,12 +8662,24 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
8347 8662
8348- (NSDragOperation) draggingUpdated: (id <NSDraggingInfo>) sender 8663- (NSDragOperation) draggingUpdated: (id <NSDraggingInfo>) sender
8349{ 8664{
8665#ifdef NS_IMPL_GNUSTEP
8350 struct input_event ie; 8666 struct input_event ie;
8667#else
8668 Lisp_Object frame;
8669#endif
8351 NSPoint position; 8670 NSPoint position;
8352 int x, y; 8671 int x, y;
8672 NSAutoreleasePool *ap;
8673 specpdl_ref count;
8353 8674
8675 ap = [[NSAutoreleasePool alloc] init];
8676 count = SPECPDL_INDEX ();
8677 record_unwind_protect_ptr (ns_release_autorelease_pool, ap);
8678
8679#ifdef NS_IMPL_GNUSTEP
8354 EVENT_INIT (ie); 8680 EVENT_INIT (ie);
8355 ie.kind = DRAG_N_DROP_EVENT; 8681 ie.kind = DRAG_N_DROP_EVENT;
8682#endif
8356 8683
8357 /* Get rid of mouse face. */ 8684 /* Get rid of mouse face. */
8358 [self mouseExited: [[self window] currentEvent]]; 8685 [self mouseExited: [[self window] currentEvent]];
@@ -8362,6 +8689,7 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
8362 x = lrint (position.x); 8689 x = lrint (position.x);
8363 y = lrint (position.y); 8690 y = lrint (position.y);
8364 8691
8692#ifdef NS_IMPL_GNUSTEP
8365 XSETINT (ie.x, x); 8693 XSETINT (ie.x, x);
8366 XSETINT (ie.y, y); 8694 XSETINT (ie.y, y);
8367 XSETFRAME (ie.frame_or_window, emacsframe); 8695 XSETFRAME (ie.frame_or_window, emacsframe);
@@ -8369,28 +8697,44 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
8369 ie.modifiers = 0; 8697 ie.modifiers = 0;
8370 8698
8371 kbd_buffer_store_event (&ie); 8699 kbd_buffer_store_event (&ie);
8700#else
8701 /* Input events won't be processed until the drop happens on macOS,
8702 so call this function instead. */
8703 XSETFRAME (frame, emacsframe);
8704
8705 safe_call (4, Vns_drag_motion_function, frame,
8706 make_fixnum (x), make_fixnum (y));
8707
8708 redisplay ();
8709#endif
8710
8711 unbind_to (count, Qnil);
8372 return NSDragOperationGeneric; 8712 return NSDragOperationGeneric;
8373} 8713}
8374 8714
8375-(BOOL)performDragOperation: (id <NSDraggingInfo>) sender 8715- (BOOL) performDragOperation: (id <NSDraggingInfo>) sender
8376{ 8716{
8377 id pb; 8717 id pb, source;
8378 int x, y; 8718 int x, y;
8379 NSString *type; 8719 NSString *type;
8380 NSEvent *theEvent = [[self window] currentEvent];
8381 NSPoint position; 8720 NSPoint position;
8382 NSDragOperation op = [sender draggingSourceOperationMask]; 8721 NSDragOperation op = [sender draggingSourceOperationMask];
8383 Lisp_Object operations = Qnil; 8722 Lisp_Object operations = Qnil;
8384 Lisp_Object strings = Qnil; 8723 Lisp_Object strings = Qnil;
8385 Lisp_Object type_sym; 8724 Lisp_Object type_sym;
8725 struct input_event ie;
8386 8726
8387 NSTRACE ("[EmacsView performDragOperation:]"); 8727 NSTRACE (@"[EmacsView performDragOperation:]");
8388 8728
8389 if (!emacs_event) 8729 source = [sender draggingSource];
8730
8731 if (source && [source respondsToSelector: @selector(mustNotDropOn:)]
8732 && [source mustNotDropOn: self])
8390 return NO; 8733 return NO;
8391 8734
8392 position = [self convertPoint: [sender draggingLocation] fromView: nil]; 8735 position = [self convertPoint: [sender draggingLocation] fromView: nil];
8393 x = lrint (position.x); y = lrint (position.y); 8736 x = lrint (position.x);
8737 y = lrint (position.y);
8394 8738
8395 pb = [sender draggingPasteboard]; 8739 pb = [sender draggingPasteboard];
8396 type = [pb availableTypeFromArray: ns_drag_types]; 8740 type = [pb availableTypeFromArray: ns_drag_types];
@@ -8406,11 +8750,9 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
8406 if (op & NSDragOperationGeneric || NILP (operations)) 8750 if (op & NSDragOperationGeneric || NILP (operations))
8407 operations = Fcons (Qns_drag_operation_generic, operations); 8751 operations = Fcons (Qns_drag_operation_generic, operations);
8408 8752
8409 if (type == 0) 8753 if (!type)
8410 { 8754 return NO;
8411 return NO; 8755#if NS_USE_NSPasteboardTypeFileURL
8412 }
8413#if NS_USE_NSPasteboardTypeFileURL != 0
8414 else if ([type isEqualToString: NSPasteboardTypeFileURL]) 8756 else if ([type isEqualToString: NSPasteboardTypeFileURL])
8415 { 8757 {
8416 type_sym = Qfile; 8758 type_sym = Qfile;
@@ -8425,18 +8767,29 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
8425#else // !NS_USE_NSPasteboardTypeFileURL 8767#else // !NS_USE_NSPasteboardTypeFileURL
8426 else if ([type isEqualToString: NSFilenamesPboardType]) 8768 else if ([type isEqualToString: NSFilenamesPboardType])
8427 { 8769 {
8428 NSArray *files; 8770 id files;
8429 NSEnumerator *fenum; 8771 NSEnumerator *fenum;
8430 NSString *file; 8772 NSString *file;
8431 8773
8432 if (!(files = [pb propertyListForType: type])) 8774 files = [pb propertyListForType: type];
8775
8776 if (!files)
8433 return NO; 8777 return NO;
8434 8778
8435 type_sym = Qfile; 8779 type_sym = Qfile;
8436 8780
8437 fenum = [files objectEnumerator]; 8781 /* On GNUstep, files might be a string. */
8438 while ( (file = [fenum nextObject]) ) 8782
8439 strings = Fcons ([file lispString], strings); 8783 if ([files respondsToSelector: @selector (objectEnumerator:)])
8784 {
8785 fenum = [files objectEnumerator];
8786
8787 while ((file = [fenum nextObject]))
8788 strings = Fcons ([file lispString], strings);
8789 }
8790 else
8791 /* Then `files' is an NSString. */
8792 strings = list1 ([files lispString]);
8440 } 8793 }
8441#endif // !NS_USE_NSPasteboardTypeFileURL 8794#endif // !NS_USE_NSPasteboardTypeFileURL
8442 else if ([type isEqualToString: NSPasteboardTypeURL]) 8795 else if ([type isEqualToString: NSPasteboardTypeURL])
@@ -8453,29 +8806,26 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
8453 { 8806 {
8454 NSString *data; 8807 NSString *data;
8455 8808
8456 if (! (data = [pb stringForType: type])) 8809 data = [pb stringForType: type];
8810
8811 if (!data)
8457 return NO; 8812 return NO;
8458 8813
8459 type_sym = Qnil; 8814 type_sym = Qnil;
8460
8461 strings = list1 ([data lispString]); 8815 strings = list1 ([data lispString]);
8462 } 8816 }
8463 else 8817 else
8464 { 8818 return NO;
8465 fputs ("Invalid data type in dragging pasteboard\n", stderr);
8466 return NO;
8467 }
8468
8469 emacs_event->kind = DRAG_N_DROP_EVENT;
8470 XSETINT (emacs_event->x, x);
8471 XSETINT (emacs_event->y, y);
8472 emacs_event->modifiers = 0;
8473 8819
8474 emacs_event->arg = Fcons (type_sym, 8820 EVENT_INIT (ie);
8475 Fcons (operations, 8821 ie.kind = DRAG_N_DROP_EVENT;
8476 strings)); 8822 ie.arg = Fcons (type_sym, Fcons (operations,
8477 EV_TRAILER (theEvent); 8823 strings));
8824 XSETINT (ie.x, x);
8825 XSETINT (ie.y, y);
8826 XSETFRAME (ie.frame_or_window, emacsframe);
8478 8827
8828 kbd_buffer_store_event (&ie);
8479 return YES; 8829 return YES;
8480} 8830}
8481 8831
@@ -8582,17 +8932,18 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
8582@implementation EmacsWindow 8932@implementation EmacsWindow
8583 8933
8584 8934
8585- (instancetype) initWithEmacsFrame:(struct frame *)f 8935- (instancetype) initWithEmacsFrame: (struct frame *) f
8586{ 8936{
8587 return [self initWithEmacsFrame:f fullscreen:NO screen:nil]; 8937 return [self initWithEmacsFrame:f fullscreen:NO screen:nil];
8588} 8938}
8589 8939
8590 8940
8591- (instancetype) initWithEmacsFrame:(struct frame *)f 8941- (instancetype) initWithEmacsFrame: (struct frame *) f
8592 fullscreen:(BOOL)fullscreen 8942 fullscreen: (BOOL) fullscreen
8593 screen:(NSScreen *)screen 8943 screen: (NSScreen *) screen
8594{ 8944{
8595 NSWindowStyleMask styleMask; 8945 NSWindowStyleMask styleMask;
8946 int width, height;
8596 8947
8597 NSTRACE ("[EmacsWindow initWithEmacsFrame:fullscreen:screen:]"); 8948 NSTRACE ("[EmacsWindow initWithEmacsFrame:fullscreen:screen:]");
8598 8949
@@ -8605,20 +8956,24 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
8605 styleMask |= NSWindowStyleMaskResizable; 8956 styleMask |= NSWindowStyleMaskResizable;
8606#endif 8957#endif
8607 } 8958 }
8959 else if (f->tooltip)
8960 styleMask = 0;
8608 else 8961 else
8609 styleMask = NSWindowStyleMaskTitled 8962 styleMask = (NSWindowStyleMaskTitled
8610 | NSWindowStyleMaskResizable 8963 | NSWindowStyleMaskResizable
8611 | NSWindowStyleMaskMiniaturizable 8964 | NSWindowStyleMaskMiniaturizable
8612 | NSWindowStyleMaskClosable; 8965 | NSWindowStyleMaskClosable);
8613 8966
8614 self = [super initWithContentRect: 8967 last_drag_event = nil;
8615 NSMakeRect (0, 0, 8968
8616 FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols), 8969 width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols);
8617 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines)) 8970 height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines);
8618 styleMask:styleMask 8971
8619 backing:NSBackingStoreBuffered 8972 self = [super initWithContentRect: NSMakeRect (0, 0, width, height)
8620 defer:YES 8973 styleMask: styleMask
8621 screen:screen]; 8974 backing: NSBackingStoreBuffered
8975 defer: YES
8976 screen: screen];
8622 if (self) 8977 if (self)
8623 { 8978 {
8624 NSString *name; 8979 NSString *name;
@@ -8726,6 +9081,11 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
8726 9081
8727 /* We need to release the toolbar ourselves. */ 9082 /* We need to release the toolbar ourselves. */
8728 [[self toolbar] release]; 9083 [[self toolbar] release];
9084
9085 /* Also the last button press event . */
9086 if (last_drag_event)
9087 [last_drag_event release];
9088
8729 [super dealloc]; 9089 [super dealloc];
8730} 9090}
8731 9091
@@ -9250,6 +9610,153 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9250 return YES; 9610 return YES;
9251} 9611}
9252 9612
9613- (void) setLastDragEvent: (NSEvent *) event
9614{
9615 if (last_drag_event)
9616 [last_drag_event release];
9617 last_drag_event = [event copy];
9618}
9619
9620- (NSDragOperation) draggingSourceOperationMaskForLocal: (BOOL) is_local
9621{
9622 return drag_op;
9623}
9624
9625- (void) draggedImage: (NSImage *) image
9626 endedAt: (NSPoint) screen_point
9627 operation: (NSDragOperation) operation
9628{
9629 selected_op = operation;
9630}
9631
9632- (void) draggedImage: (NSImage *) dragged_image
9633 movedTo: (NSPoint) screen_point
9634{
9635 NSPoint mouse_loc;
9636#ifdef NS_IMPL_COCOA
9637 NSInteger window_number;
9638 NSWindow *w;
9639#endif
9640
9641 mouse_loc = [NSEvent mouseLocation];
9642
9643#ifdef NS_IMPL_COCOA
9644 if (dnd_mode != RETURN_FRAME_NEVER)
9645 {
9646 window_number = [NSWindow windowNumberAtPoint: mouse_loc
9647 belowWindowWithWindowNumber: 0];
9648 w = [NSApp windowWithWindowNumber: window_number];
9649
9650 if (!w || w != self)
9651 dnd_mode = RETURN_FRAME_NOW;
9652
9653 if (dnd_mode != RETURN_FRAME_NOW
9654 || ![[w delegate] isKindOfClass: [EmacsView class]]
9655 || ((EmacsView *) [w delegate])->emacsframe->tooltip)
9656 goto out;
9657
9658 dnd_return_frame = ((EmacsView *) [w delegate])->emacsframe;
9659
9660 /* FIXME: there must be a better way to leave the event loop. */
9661 [NSException raise: @""
9662 format: @"Must return DND frame"];
9663 }
9664
9665 out:
9666#endif
9667
9668 if (dnd_move_tooltip_with_frame)
9669 ns_move_tooltip_to_mouse_location (mouse_loc);
9670}
9671
9672- (BOOL) mustNotDropOn: (NSView *) receiver
9673{
9674 return ([receiver window] == self
9675 ? !dnd_allow_same_frame : NO);
9676}
9677
9678- (NSDragOperation) beginDrag: (NSDragOperation) op
9679 forPasteboard: (NSPasteboard *) pasteboard
9680 withMode: (enum ns_return_frame_mode) mode
9681 returnFrameTo: (struct frame **) frame_return
9682 prohibitSame: (BOOL) prohibit_same_frame
9683 followTooltip: (BOOL) follow_tooltip
9684{
9685 NSImage *image;
9686#ifdef NS_IMPL_COCOA
9687 NSInteger window_number;
9688 NSWindow *w;
9689#endif
9690 drag_op = op;
9691 selected_op = NSDragOperationNone;
9692 image = [[NSImage alloc] initWithSize: NSMakeSize (1.0, 1.0)];
9693 dnd_mode = mode;
9694 dnd_return_frame = NULL;
9695 dnd_allow_same_frame = !prohibit_same_frame;
9696 dnd_move_tooltip_with_frame = follow_tooltip;
9697
9698 /* Now draw transparency onto the image. */
9699 [image lockFocus];
9700 [[NSColor colorWithUnsignedLong: 0] set];
9701 NSRectFillUsingOperation (NSMakeRect (0, 0, 1, 1),
9702 NSCompositingOperationCopy);
9703 [image unlockFocus];
9704
9705 block_input ();
9706#ifdef NS_IMPL_COCOA
9707 if (mode == RETURN_FRAME_NOW)
9708 {
9709 window_number = [NSWindow windowNumberAtPoint: [NSEvent mouseLocation]
9710 belowWindowWithWindowNumber: 0];
9711 w = [NSApp windowWithWindowNumber: window_number];
9712
9713 if (w && [[w delegate] isKindOfClass: [EmacsView class]]
9714 && !((EmacsView *) [w delegate])->emacsframe->tooltip)
9715 {
9716 *frame_return = ((EmacsView *) [w delegate])->emacsframe;
9717 [image release];
9718 unblock_input ();
9719
9720 return NSDragOperationNone;
9721 }
9722 }
9723
9724 @try
9725 {
9726#endif
9727 if (last_drag_event)
9728 [self dragImage: image
9729 at: NSMakePoint (0, 0)
9730 offset: NSMakeSize (0, 0)
9731 event: last_drag_event
9732 pasteboard: pasteboard
9733 source: self
9734 slideBack: NO];
9735#ifdef NS_IMPL_COCOA
9736 }
9737 @catch (NSException *e)
9738 {
9739 /* Ignore. This is probably the wrong way to leave the
9740 drag-and-drop run loop. */
9741 }
9742#endif
9743 unblock_input ();
9744
9745 /* The drop happened, so delete the tooltip. */
9746 if (follow_tooltip)
9747 Fx_hide_tip ();
9748
9749 /* Assume all buttons have been released since the drag-and-drop
9750 operation is now over. */
9751 if (!dnd_return_frame)
9752 x_display_list->grabbed = 0;
9753
9754 [image release];
9755
9756 *frame_return = dnd_return_frame;
9757 return selected_op;
9758}
9759
9253@end /* EmacsWindow */ 9760@end /* EmacsWindow */
9254 9761
9255 9762
@@ -10182,6 +10689,7 @@ syms_of_nsterm (void)
10182 DEFSYM (Qns_drag_operation_copy, "ns-drag-operation-copy"); 10689 DEFSYM (Qns_drag_operation_copy, "ns-drag-operation-copy");
10183 DEFSYM (Qns_drag_operation_link, "ns-drag-operation-link"); 10690 DEFSYM (Qns_drag_operation_link, "ns-drag-operation-link");
10184 DEFSYM (Qns_drag_operation_generic, "ns-drag-operation-generic"); 10691 DEFSYM (Qns_drag_operation_generic, "ns-drag-operation-generic");
10692 DEFSYM (Qns_handle_drag_motion, "ns-handle-drag-motion");
10185 10693
10186 Fput (Qalt, Qmodifier_value, make_fixnum (alt_modifier)); 10694 Fput (Qalt, Qmodifier_value, make_fixnum (alt_modifier));
10187 Fput (Qhyper, Qmodifier_value, make_fixnum (hyper_modifier)); 10695 Fput (Qhyper, Qmodifier_value, make_fixnum (hyper_modifier));
@@ -10189,117 +10697,117 @@ syms_of_nsterm (void)
10189 Fput (Qsuper, Qmodifier_value, make_fixnum (super_modifier)); 10697 Fput (Qsuper, Qmodifier_value, make_fixnum (super_modifier));
10190 Fput (Qcontrol, Qmodifier_value, make_fixnum (ctrl_modifier)); 10698 Fput (Qcontrol, Qmodifier_value, make_fixnum (ctrl_modifier));
10191 10699
10192 DEFVAR_LISP ("ns-input-file", ns_input_file, 10700 DEFVAR_LISP ("ns-input-font", ns_input_font,
10193 "The file specified in the last NS event."); 10701 doc: /* The font specified in the last NS event. */);
10194 ns_input_file =Qnil; 10702 ns_input_font = Qnil;
10195 10703
10196 DEFVAR_LISP ("ns-working-text", ns_working_text, 10704 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
10197 "String for visualizing working composition sequence."); 10705 doc: /* The fontsize specified in the last NS event. */);
10198 ns_working_text =Qnil; 10706 ns_input_fontsize = Qnil;
10199 10707
10200 DEFVAR_LISP ("ns-input-font", ns_input_font, 10708 DEFVAR_LISP ("ns-input-line", ns_input_line,
10201 "The font specified in the last NS event."); 10709 doc: /* The line specified in the last NS event. */);
10202 ns_input_font =Qnil; 10710 ns_input_line = Qnil;
10203 10711
10204 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize, 10712 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
10205 "The fontsize specified in the last NS event."); 10713 doc: /* The service name specified in the last NS event. */);
10206 ns_input_fontsize =Qnil; 10714 ns_input_spi_name = Qnil;
10207 10715
10208 DEFVAR_LISP ("ns-input-line", ns_input_line, 10716 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
10209 "The line specified in the last NS event."); 10717 doc: /* The service argument specified in the last NS event. */);
10210 ns_input_line =Qnil; 10718 ns_input_spi_arg = Qnil;
10211 10719
10212 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name, 10720 DEFVAR_LISP ("ns-input-file", ns_input_file,
10213 "The service name specified in the last NS event."); 10721 doc: /* The file specified in the last NS event. */);
10214 ns_input_spi_name =Qnil; 10722 ns_input_file = Qnil;
10215 10723
10216 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg, 10724 DEFVAR_LISP ("ns-working-text", ns_working_text,
10217 "The service argument specified in the last NS event."); 10725 doc: /* String for visualizing working composition sequence. */);
10218 ns_input_spi_arg =Qnil; 10726 ns_working_text = Qnil;
10219 10727
10220 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier, 10728 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
10221 "This variable describes the behavior of the alternate or option key.\n\ 10729 doc: /* This variable describes the behavior of the alternate or option key.
10222Either SYMBOL, describing the behavior for any event,\n\ 10730Either SYMBOL, describing the behavior for any event,
10223or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\ 10731or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior
10224separately for ordinary keys, function keys, and mouse events.\n\ 10732separately for ordinary keys, function keys, and mouse events.
10225\n\ 10733
10226Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\ 10734Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.
10227If `none', the key is ignored by Emacs and retains its standard meaning."); 10735If `none', the key is ignored by Emacs and retains its standard meaning. */);
10228 ns_alternate_modifier = Qmeta; 10736 ns_alternate_modifier = Qmeta;
10229 10737
10230 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier, 10738 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
10231 "This variable describes the behavior of the right alternate or option key.\n\ 10739 doc: /* This variable describes the behavior of the right alternate or option key.
10232Either SYMBOL, describing the behavior for any event,\n\ 10740Either SYMBOL, describing the behavior for any event,
10233or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\ 10741or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior
10234separately for ordinary keys, function keys, and mouse events.\n\ 10742separately for ordinary keys, function keys, and mouse events.
10235It can also be `left' to use the value of `ns-alternate-modifier' instead.\n\ 10743It can also be `left' to use the value of `ns-alternate-modifier' instead.
10236\n\ 10744
10237Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\ 10745Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.
10238If `none', the key is ignored by Emacs and retains its standard meaning."); 10746If `none', the key is ignored by Emacs and retains its standard meaning. */);
10239 ns_right_alternate_modifier = Qleft; 10747 ns_right_alternate_modifier = Qleft;
10240 10748
10241 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier, 10749 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
10242 "This variable describes the behavior of the command key.\n\ 10750 doc: /* This variable describes the behavior of the command key.
10243Either SYMBOL, describing the behavior for any event,\n\ 10751Either SYMBOL, describing the behavior for any event,
10244or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\ 10752or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior
10245separately for ordinary keys, function keys, and mouse events.\n\ 10753separately for ordinary keys, function keys, and mouse events.
10246\n\ 10754
10247Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\ 10755Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.
10248If `none', the key is ignored by Emacs and retains its standard meaning."); 10756If `none', the key is ignored by Emacs and retains its standard meaning. */);
10249 ns_command_modifier = Qsuper; 10757 ns_command_modifier = Qsuper;
10250 10758
10251 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier, 10759 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
10252 "This variable describes the behavior of the right command key.\n\ 10760 doc: /* This variable describes the behavior of the right command key.
10253Either SYMBOL, describing the behavior for any event,\n\ 10761Either SYMBOL, describing the behavior for any event,
10254or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\ 10762or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior
10255separately for ordinary keys, function keys, and mouse events.\n\ 10763separately for ordinary keys, function keys, and mouse events.
10256It can also be `left' to use the value of `ns-command-modifier' instead.\n\ 10764It can also be `left' to use the value of `ns-command-modifier' instead.
10257\n\ 10765
10258Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\ 10766Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.
10259If `none', the key is ignored by Emacs and retains its standard meaning."); 10767If `none', the key is ignored by Emacs and retains its standard meaning. */);
10260 ns_right_command_modifier = Qleft; 10768 ns_right_command_modifier = Qleft;
10261 10769
10262 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier, 10770 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
10263 "This variable describes the behavior of the control key.\n\ 10771 doc: /* This variable describes the behavior of the control key.
10264Either SYMBOL, describing the behavior for any event,\n\ 10772Either SYMBOL, describing the behavior for any event,
10265or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\ 10773or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior
10266separately for ordinary keys, function keys, and mouse events.\n\ 10774separately for ordinary keys, function keys, and mouse events.
10267\n\ 10775
10268Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\ 10776Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.
10269If `none', the key is ignored by Emacs and retains its standard meaning."); 10777If `none', the key is ignored by Emacs and retains its standard meaning. */);
10270 ns_control_modifier = Qcontrol; 10778 ns_control_modifier = Qcontrol;
10271 10779
10272 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier, 10780 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
10273 "This variable describes the behavior of the right control key.\n\ 10781 doc: /* This variable describes the behavior of the right control key.
10274Either SYMBOL, describing the behavior for any event,\n\ 10782Either SYMBOL, describing the behavior for any event,
10275or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\ 10783or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior
10276separately for ordinary keys, function keys, and mouse events.\n\ 10784separately for ordinary keys, function keys, and mouse events.
10277It can also be `left' to use the value of `ns-control-modifier' instead.\n\ 10785It can also be `left' to use the value of `ns-control-modifier' instead.
10278\n\ 10786
10279Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\ 10787Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.
10280If `none', the key is ignored by Emacs and retains its standard meaning."); 10788If `none', the key is ignored by Emacs and retains its standard meaning. */);
10281 ns_right_control_modifier = Qleft; 10789 ns_right_control_modifier = Qleft;
10282 10790
10283 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier, 10791 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
10284 "This variable describes the behavior of the function (fn) key.\n\ 10792 doc: /* This variable describes the behavior of the function (fn) key.
10285Either SYMBOL, describing the behavior for any event,\n\ 10793Either SYMBOL, describing the behavior for any event,
10286or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\ 10794or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior
10287separately for ordinary keys, function keys, and mouse events.\n\ 10795separately for ordinary keys, function keys, and mouse events.
10288\n\ 10796
10289Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\ 10797Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.
10290If `none', the key is ignored by Emacs and retains its standard meaning."); 10798If `none', the key is ignored by Emacs and retains its standard meaning. */);
10291 ns_function_modifier = Qnone; 10799 ns_function_modifier = Qnone;
10292 10800
10293 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text, 10801 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
10294 "Non-nil (the default) means to render text antialiased."); 10802 doc: /* Non-nil (the default) means to render text antialiased. */);
10295 ns_antialias_text = Qt; 10803 ns_antialias_text = Qt;
10296 10804
10297 DEFVAR_LISP ("ns-use-thin-smoothing", ns_use_thin_smoothing, 10805 DEFVAR_LISP ("ns-use-thin-smoothing", ns_use_thin_smoothing,
10298 "Non-nil turns on a font smoothing method that produces thinner strokes."); 10806 doc: /* Non-nil turns on a font smoothing method that produces thinner strokes. */);
10299 ns_use_thin_smoothing = Qnil; 10807 ns_use_thin_smoothing = Qnil;
10300 10808
10301 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit, 10809 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
10302 "Whether to confirm application quit using dialog."); 10810 doc: /* Whether to confirm application quit using dialog. */);
10303 ns_confirm_quit = Qnil; 10811 ns_confirm_quit = Qnil;
10304 10812
10305 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar, 10813 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. */);
10369 mice with smooth scrolling capability. */); 10877 mice with smooth scrolling capability. */);
10370 Vns_scroll_event_delta_factor = make_float (1.0); 10878 Vns_scroll_event_delta_factor = make_float (1.0);
10371 10879
10880 DEFVAR_LISP ("ns-drag-motion-function", Vns_drag_motion_function,
10881 doc: /* Function called when another program drags items over Emacs.
10882
10883It is called with three arguments FRAME, X, and Y, whenever the user
10884moves the mouse over an Emacs frame as part of a drag-and-drop
10885operation. FRAME is the frame the mouse is on top of, and X and Y are
10886the frame-relative positions of the mouse in the X and Y axises
10887respectively. */);
10888 Vns_drag_motion_function = Qns_handle_drag_motion;
10889
10372 /* Tell Emacs about this window system. */ 10890 /* Tell Emacs about this window system. */
10373 Fprovide (Qns, Qnil); 10891 Fprovide (Qns, Qnil);
10374 10892
@@ -10389,4 +10907,6 @@ This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */);
10389 syms_of_nsfont (); 10907 syms_of_nsfont ();
10390#endif 10908#endif
10391 10909
10910 last_known_monitors = Qnil;
10911 staticpro (&last_known_monitors);
10392} 10912}
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/>. */
69 [configuration.preferences setValue:@YES 69 [configuration.preferences setValue:@YES
70 forKey:@"developerExtrasEnabled"]; 70 forKey:@"developerExtrasEnabled"];
71 71
72#if 0 /* Plugins are not supported by Mac OS X anymore. */
72 Lisp_Object enablePlugins = 73 Lisp_Object enablePlugins =
73 Fintern (build_string ("xwidget-webkit-enable-plugins"), Qnil); 74 Fintern (build_string ("xwidget-webkit-enable-plugins"), Qnil);
75
74 if (!EQ (Fsymbol_value (enablePlugins), Qnil)) 76 if (!EQ (Fsymbol_value (enablePlugins), Qnil))
75 configuration.preferences.plugInsEnabled = YES; 77 configuration.preferences.plugInsEnabled = YES;
78#endif
76 79
77 self = [super initWithFrame:frame configuration:configuration]; 80 self = [super initWithFrame:frame configuration:configuration];
78 if (self) 81 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,
1069 } 1069 }
1070 } 1070 }
1071 1071
1072 if (!EQ (weights, orig_weights)) 1072 if (!BASE_EQ (weights, orig_weights))
1073 Fputhash (object, weights, dump_queue->link_weights); 1073 Fputhash (object, weights, dump_queue->link_weights);
1074} 1074}
1075 1075
@@ -1383,7 +1383,7 @@ print_paths_to_root_1 (struct dump_context *ctx,
1383 { 1383 {
1384 Lisp_Object referrer = XCAR (referrers); 1384 Lisp_Object referrer = XCAR (referrers);
1385 referrers = XCDR (referrers); 1385 referrers = XCDR (referrers);
1386 Lisp_Object repr = Fprin1_to_string (referrer, Qnil); 1386 Lisp_Object repr = Fprin1_to_string (referrer, Qnil, Qnil);
1387 for (int i = 0; i < level; ++i) 1387 for (int i = 0; i < level; ++i)
1388 putc (' ', stderr); 1388 putc (' ', stderr);
1389 fwrite (SDATA (repr), 1, SBYTES (repr), stderr); 1389 fwrite (SDATA (repr), 1, SBYTES (repr), stderr);
@@ -3758,7 +3758,7 @@ decode_emacs_reloc (struct dump_context *ctx, Lisp_Object lreloc)
3758 reloc.u.dump_offset = dump_recall_object (ctx, target_value); 3758 reloc.u.dump_offset = dump_recall_object (ctx, target_value);
3759 if (reloc.u.dump_offset <= 0) 3759 if (reloc.u.dump_offset <= 0)
3760 { 3760 {
3761 Lisp_Object repr = Fprin1_to_string (target_value, Qnil); 3761 Lisp_Object repr = Fprin1_to_string (target_value, Qnil, Qnil);
3762 error ("relocation target was not dumped: %s", SDATA (repr)); 3762 error ("relocation target was not dumped: %s", SDATA (repr));
3763 } 3763 }
3764 dump_check_dump_off (ctx, reloc.u.dump_offset); 3764 dump_check_dump_off (ctx, reloc.u.dump_offset);
@@ -5543,7 +5543,10 @@ pdumper_load (const char *dump_filename, char *argv0)
5543 5543
5544 struct dump_header header_buf = { 0 }; 5544 struct dump_header header_buf = { 0 };
5545 struct dump_header *header = &header_buf; 5545 struct dump_header *header = &header_buf;
5546 struct dump_memory_map sections[NUMBER_DUMP_SECTIONS] = { 0 }; 5546 struct dump_memory_map sections[NUMBER_DUMP_SECTIONS];
5547
5548 /* Use memset instead of "= { 0 }" to work around GCC bug 105961. */
5549 memset (sections, 0, sizeof sections);
5547 5550
5548 const struct timespec start_time = current_timespec (); 5551 const struct timespec start_time = current_timespec ();
5549 char *dump_filename_copy; 5552 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)
566static void 566static void
567pgtk_set_child_frame_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval) 567pgtk_set_child_frame_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
568{ 568{
569 int border = check_int_nonnegative (arg); 569 int border;
570
571 if (NILP (arg))
572 border = -1;
573 else if (RANGED_FIXNUMP (0, arg, INT_MAX))
574 border = XFIXNAT (arg);
575 else
576 signal_error ("Invalid child frame border width", arg);
570 577
571 if (border != FRAME_CHILD_FRAME_BORDER_WIDTH (f)) 578 if (border != FRAME_CHILD_FRAME_BORDER_WIDTH (f))
572 { 579 {
573 f->child_frame_border_width = border; 580 f->child_frame_border_width = border;
574 581
575 if (FRAME_X_WINDOW (f)) 582 if (FRAME_GTK_WIDGET (f))
576 { 583 {
577 adjust_frame_size (f, -1, -1, 3, false, Qchild_frame_border_width); 584 adjust_frame_size (f, -1, -1, 3,
585 false, Qchild_frame_border_width);
578 pgtk_clear_under_internal_border (f); 586 pgtk_clear_under_internal_border (f);
579 } 587 }
580 } 588 }
@@ -848,7 +856,7 @@ pgtk_set_scroll_bar_background (struct frame *f, Lisp_Object new_value,
848 error ("Unknown color."); 856 error ("Unknown color.");
849 857
850 /* On pgtk, this frame parameter should be ignored, and honor 858 /* On pgtk, this frame parameter should be ignored, and honor
851 gtk theme. (It honors the GTK theme if not explictly set, so 859 gtk theme. (It honors the GTK theme if not explicitly set, so
852 I see no harm in letting users tinker a bit more.) */ 860 I see no harm in letting users tinker a bit more.) */
853 char css[64]; 861 char css[64];
854 sprintf (css, "scrollbar trough { background-color: #%06x; }", 862 sprintf (css, "scrollbar trough { background-color: #%06x; }",
@@ -1060,7 +1068,7 @@ pgtk_default_font_parameter (struct frame *f, Lisp_Object parms)
1060 gui_display_get_arg (dpyinfo, parms, Qfont, NULL, NULL, 1068 gui_display_get_arg (dpyinfo, parms, Qfont, NULL, NULL,
1061 RES_TYPE_STRING); 1069 RES_TYPE_STRING);
1062 Lisp_Object font = Qnil; 1070 Lisp_Object font = Qnil;
1063 if (EQ (font_param, Qunbound)) 1071 if (BASE_EQ (font_param, Qunbound))
1064 font_param = Qnil; 1072 font_param = Qnil;
1065 1073
1066 if (NILP (font_param)) 1074 if (NILP (font_param))
@@ -1213,10 +1221,10 @@ This function is an internal primitive--use `make-frame' instead. */ )
1213 1221
1214 display = 1222 display =
1215 gui_display_get_arg (dpyinfo, parms, Qterminal, 0, 0, RES_TYPE_NUMBER); 1223 gui_display_get_arg (dpyinfo, parms, Qterminal, 0, 0, RES_TYPE_NUMBER);
1216 if (EQ (display, Qunbound)) 1224 if (BASE_EQ (display, Qunbound))
1217 display = 1225 display =
1218 gui_display_get_arg (dpyinfo, parms, Qdisplay, 0, 0, RES_TYPE_STRING); 1226 gui_display_get_arg (dpyinfo, parms, Qdisplay, 0, 0, RES_TYPE_STRING);
1219 if (EQ (display, Qunbound)) 1227 if (BASE_EQ (display, Qunbound))
1220 display = Qnil; 1228 display = Qnil;
1221 dpyinfo = check_pgtk_display_info (display); 1229 dpyinfo = check_pgtk_display_info (display);
1222 kb = dpyinfo->terminal->kboard; 1230 kb = dpyinfo->terminal->kboard;
@@ -1227,7 +1235,7 @@ This function is an internal primitive--use `make-frame' instead. */ )
1227 name = 1235 name =
1228 gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name", 1236 gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name",
1229 RES_TYPE_STRING); 1237 RES_TYPE_STRING);
1230 if (!STRINGP (name) && !EQ (name, Qunbound) && !NILP (name)) 1238 if (!STRINGP (name) && !BASE_EQ (name, Qunbound) && !NILP (name))
1231 error ("Invalid frame name--not a string or nil"); 1239 error ("Invalid frame name--not a string or nil");
1232 1240
1233 if (STRINGP (name)) 1241 if (STRINGP (name))
@@ -1237,7 +1245,7 @@ This function is an internal primitive--use `make-frame' instead. */ )
1237 parent = 1245 parent =
1238 gui_display_get_arg (dpyinfo, parms, Qparent_id, NULL, NULL, 1246 gui_display_get_arg (dpyinfo, parms, Qparent_id, NULL, NULL,
1239 RES_TYPE_NUMBER); 1247 RES_TYPE_NUMBER);
1240 if (EQ (parent, Qunbound)) 1248 if (BASE_EQ (parent, Qunbound))
1241 parent = Qnil; 1249 parent = Qnil;
1242 if (!NILP (parent)) 1250 if (!NILP (parent))
1243 CHECK_NUMBER (parent); 1251 CHECK_NUMBER (parent);
@@ -1263,7 +1271,7 @@ This function is an internal primitive--use `make-frame' instead. */ )
1263 RES_TYPE_SYMBOL); 1271 RES_TYPE_SYMBOL);
1264 /* Accept parent-frame iff parent-id was not specified. */ 1272 /* Accept parent-frame iff parent-id was not specified. */
1265 if (!NILP (parent) 1273 if (!NILP (parent)
1266 || EQ (parent_frame, Qunbound) 1274 || BASE_EQ (parent_frame, Qunbound)
1267 || NILP (parent_frame) 1275 || NILP (parent_frame)
1268 || !FRAMEP (parent_frame) 1276 || !FRAMEP (parent_frame)
1269 || !FRAME_LIVE_P (XFRAME (parent_frame)) 1277 || !FRAME_LIVE_P (XFRAME (parent_frame))
@@ -1277,7 +1285,7 @@ This function is an internal primitive--use `make-frame' instead. */ )
1277 (tem = 1285 (tem =
1278 (gui_display_get_arg 1286 (gui_display_get_arg
1279 (dpyinfo, parms, Qundecorated, NULL, NULL, RES_TYPE_BOOLEAN))) 1287 (dpyinfo, parms, Qundecorated, NULL, NULL, RES_TYPE_BOOLEAN)))
1280 && !(EQ (tem, Qunbound))) 1288 && !(BASE_EQ (tem, Qunbound)))
1281 undecorated = true; 1289 undecorated = true;
1282 1290
1283 FRAME_UNDECORATED (f) = undecorated; 1291 FRAME_UNDECORATED (f) = undecorated;
@@ -1287,7 +1295,7 @@ This function is an internal primitive--use `make-frame' instead. */ )
1287 (tem = 1295 (tem =
1288 (gui_display_get_arg 1296 (gui_display_get_arg
1289 (dpyinfo, parms, Qoverride_redirect, NULL, NULL, RES_TYPE_BOOLEAN))) 1297 (dpyinfo, parms, Qoverride_redirect, NULL, NULL, RES_TYPE_BOOLEAN)))
1290 && !(EQ (tem, Qunbound))) 1298 && !(BASE_EQ (tem, Qunbound)))
1291 override_redirect = true; 1299 override_redirect = true;
1292 1300
1293 FRAME_OVERRIDE_REDIRECT (f) = override_redirect; 1301 FRAME_OVERRIDE_REDIRECT (f) = override_redirect;
@@ -1363,7 +1371,7 @@ This function is an internal primitive--use `make-frame' instead. */ )
1363 1371
1364 /* Set the name; the functions to which we pass f expect the name to 1372 /* Set the name; the functions to which we pass f expect the name to
1365 be set. */ 1373 be set. */
1366 if (EQ (name, Qunbound) || NILP (name)) 1374 if (BASE_EQ (name, Qunbound) || NILP (name))
1367 { 1375 {
1368 fset_name (f, build_string (dpyinfo->x_id_name)); 1376 fset_name (f, build_string (dpyinfo->x_id_name));
1369 f->explicit_name = false; 1377 f->explicit_name = false;
@@ -1406,7 +1414,7 @@ This function is an internal primitive--use `make-frame' instead. */ )
1406 value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width, 1414 value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width,
1407 "internalBorder", "internalBorder", 1415 "internalBorder", "internalBorder",
1408 RES_TYPE_NUMBER); 1416 RES_TYPE_NUMBER);
1409 if (!EQ (value, Qunbound)) 1417 if (!BASE_EQ (value, Qunbound))
1410 parms = Fcons (Fcons (Qinternal_border_width, value), parms); 1418 parms = Fcons (Fcons (Qinternal_border_width, value), parms);
1411 } 1419 }
1412 1420
@@ -1423,14 +1431,13 @@ This function is an internal primitive--use `make-frame' instead. */ )
1423 value = gui_display_get_arg (dpyinfo, parms, Qchild_frame_border_width, 1431 value = gui_display_get_arg (dpyinfo, parms, Qchild_frame_border_width,
1424 "childFrameBorder", "childFrameBorder", 1432 "childFrameBorder", "childFrameBorder",
1425 RES_TYPE_NUMBER); 1433 RES_TYPE_NUMBER);
1426 if (! EQ (value, Qunbound)) 1434 if (! BASE_EQ (value, Qunbound))
1427 parms = Fcons (Fcons (Qchild_frame_border_width, value), 1435 parms = Fcons (Fcons (Qchild_frame_border_width, value),
1428 parms); 1436 parms);
1429 1437
1430 } 1438 }
1431 1439
1432 gui_default_parameter (f, parms, Qchild_frame_border_width, 1440 gui_default_parameter (f, parms, Qchild_frame_border_width, Qnil,
1433 make_fixnum (0),
1434 "childFrameBorderWidth", "childFrameBorderWidth", 1441 "childFrameBorderWidth", "childFrameBorderWidth",
1435 RES_TYPE_NUMBER); 1442 RES_TYPE_NUMBER);
1436 gui_default_parameter (f, parms, Qright_divider_width, make_fixnum (0), 1443 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. */ )
1688 } 1695 }
1689 else 1696 else
1690 { 1697 {
1691 if (EQ (visibility, Qunbound)) 1698 if (BASE_EQ (visibility, Qunbound))
1692 visibility = Qt; 1699 visibility = Qt;
1693 1700
1694 if (!NILP (visibility)) 1701 if (!NILP (visibility))
@@ -1702,7 +1709,7 @@ This function is an internal primitive--use `make-frame' instead. */ )
1702 from `x-create-frame-with-faces' (see above comment). */ 1709 from `x-create-frame-with-faces' (see above comment). */
1703 f->was_invisible 1710 f->was_invisible
1704 = (f->was_invisible 1711 = (f->was_invisible
1705 && (!EQ (height, Qunbound) || !EQ (width, Qunbound))); 1712 && (!BASE_EQ (height, Qunbound) || !BASE_EQ (width, Qunbound)));
1706 1713
1707 store_frame_param (f, Qvisibility, visibility); 1714 store_frame_param (f, Qvisibility, visibility);
1708 } 1715 }
@@ -2670,7 +2677,7 @@ x_create_tip_frame (struct pgtk_display_info *dpyinfo, Lisp_Object parms, struct
2670 name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name", 2677 name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name",
2671 RES_TYPE_STRING); 2678 RES_TYPE_STRING);
2672 if (!STRINGP (name) 2679 if (!STRINGP (name)
2673 && !EQ (name, Qunbound) 2680 && !BASE_EQ (name, Qunbound)
2674 && !NILP (name)) 2681 && !NILP (name))
2675 error ("Invalid frame name--not a string or nil"); 2682 error ("Invalid frame name--not a string or nil");
2676 2683
@@ -2721,7 +2728,7 @@ x_create_tip_frame (struct pgtk_display_info *dpyinfo, Lisp_Object parms, struct
2721 2728
2722 /* Set the name; the functions to which we pass f expect the name to 2729 /* Set the name; the functions to which we pass f expect the name to
2723 be set. */ 2730 be set. */
2724 if (EQ (name, Qunbound) || NILP (name)) 2731 if (BASE_EQ (name, Qunbound) || NILP (name))
2725 { 2732 {
2726 fset_name (f, build_string (dpyinfo->x_id_name)); 2733 fset_name (f, build_string (dpyinfo->x_id_name));
2727 f->explicit_name = false; 2734 f->explicit_name = false;
@@ -2762,7 +2769,7 @@ x_create_tip_frame (struct pgtk_display_info *dpyinfo, Lisp_Object parms, struct
2762 value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width, 2769 value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width,
2763 "internalBorder", "internalBorder", 2770 "internalBorder", "internalBorder",
2764 RES_TYPE_NUMBER); 2771 RES_TYPE_NUMBER);
2765 if (! EQ (value, Qunbound)) 2772 if (! BASE_EQ (value, Qunbound))
2766 parms = Fcons (Fcons (Qinternal_border_width, value), 2773 parms = Fcons (Fcons (Qinternal_border_width, value),
2767 parms); 2774 parms);
2768 } 2775 }
@@ -2853,7 +2860,7 @@ x_create_tip_frame (struct pgtk_display_info *dpyinfo, Lisp_Object parms, struct
2853 Frame parameters may be changed if .Xdefaults contains 2860 Frame parameters may be changed if .Xdefaults contains
2854 specifications for the default font. For example, if there is an 2861 specifications for the default font. For example, if there is an
2855 `Emacs.default.attributeBackground: pink', the `background-color' 2862 `Emacs.default.attributeBackground: pink', the `background-color'
2856 attribute of the frame get's set, which let's the internal border 2863 attribute of the frame gets set, which lets the internal border
2857 of the tooltip frame appear in pink. Prevent this. */ 2864 of the tooltip frame appear in pink. Prevent this. */
2858 { 2865 {
2859 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color); 2866 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,
610 610
611 *error_name = NULL; 611 *error_name = NULL;
612 612
613 if (!FRAME_GTK_OUTER_WIDGET (f)) {
614 *error_name = "Can't popup from child frames.";
615 return Qnil;
616 }
617
618 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH) 613 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
619 { 614 {
620 *error_name = "Empty menu"; 615 *error_name = "Empty menu";
@@ -919,11 +914,6 @@ pgtk_dialog_show (struct frame *f, Lisp_Object title,
919 914
920 *error_name = NULL; 915 *error_name = NULL;
921 916
922 if (!FRAME_GTK_OUTER_WIDGET (f)) {
923 *error_name = "Can't popup from child frames.";
924 return Qnil;
925 }
926
927 if (menu_items_n_panes > 1) 917 if (menu_items_n_panes > 1)
928 { 918 {
929 *error_name = "Multiple panes in dialog box"; 919 *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. */)
323 gtk_target_list_unref (list); 323 gtk_target_list_unref (list);
324 } 324 }
325 325
326 if (!EQ (Vpgtk_sent_selection_hooks, Qunbound)) 326 if (!BASE_EQ (Vpgtk_sent_selection_hooks, Qunbound))
327 { 327 {
328 /* FIXME: Use run-hook-with-args! */ 328 /* FIXME: Use run-hook-with-args! */
329 for (rest = Vpgtk_sent_selection_hooks; CONSP (rest); 329 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)
1333 if (s->stippled_p) 1333 if (s->stippled_p)
1334 { 1334 {
1335 /* Fill background with a stipple pattern. */ 1335 /* Fill background with a stipple pattern. */
1336 1336 fill_background (s, s->x, s->y + box_line_width,
1337 fill_background (s,
1338 s->x, s->y + box_line_width,
1339 s->background_width, 1337 s->background_width,
1340 s->height - 2 * box_line_width); 1338 s->height - 2 * box_line_width);
1341 s->background_filled_p = true; 1339 s->background_filled_p = true;
@@ -1589,6 +1587,10 @@ pgtk_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
1589 false); 1587 false);
1590 x += glyph->pixel_width; 1588 x += glyph->pixel_width;
1591 } 1589 }
1590
1591 /* Pacify GCC 12 even though s->char2b is not used after this
1592 function returns. */
1593 s->char2b = NULL;
1592} 1594}
1593 1595
1594/* Brightness beyond which a color won't have its highlight brightness 1596/* Brightness beyond which a color won't have its highlight brightness
@@ -2501,9 +2503,7 @@ pgtk_draw_glyph_string (struct glyph_string *s)
2501 if (s->face->underline_defaulted_p) 2503 if (s->face->underline_defaulted_p)
2502 pgtk_draw_underwave (s, s->xgcv.foreground); 2504 pgtk_draw_underwave (s, s->xgcv.foreground);
2503 else 2505 else
2504 { 2506 pgtk_draw_underwave (s, s->face->underline_color);
2505 pgtk_draw_underwave (s, s->face->underline_color);
2506 }
2507 } 2507 }
2508 else if (s->face->underline == FACE_UNDER_LINE) 2508 else if (s->face->underline == FACE_UNDER_LINE)
2509 { 2509 {
@@ -2555,7 +2555,7 @@ pgtk_draw_glyph_string (struct glyph_string *s)
2555 } 2555 }
2556 2556
2557 /* Ignore minimum_offset if the amount of pixels was 2557 /* Ignore minimum_offset if the amount of pixels was
2558 explictly specified. */ 2558 explicitly specified. */
2559 if (!s->face->underline_pixels_above_descent_line) 2559 if (!s->face->underline_pixels_above_descent_line)
2560 position = max (position, underline_minimum_offset); 2560 position = max (position, underline_minimum_offset);
2561 } 2561 }
@@ -2670,6 +2670,11 @@ pgtk_draw_glyph_string (struct glyph_string *s)
2670 } 2670 }
2671 } 2671 }
2672 2672
2673 /* TODO: figure out in which cases the stipple is actually drawn on
2674 PGTK. */
2675 if (!s->row->stipple_p)
2676 s->row->stipple_p = s->face->stipple;
2677
2673 /* Reset clipping. */ 2678 /* Reset clipping. */
2674 pgtk_end_cr_clip (s->f); 2679 pgtk_end_cr_clip (s->f);
2675 s->num_clips = 0; 2680 s->num_clips = 0;
@@ -3346,15 +3351,10 @@ pgtk_mouse_position (struct frame **fp, int insist, Lisp_Object * bar_window,
3346 if (gui_mouse_grabbed (dpyinfo) 3351 if (gui_mouse_grabbed (dpyinfo)
3347 && (!EQ (track_mouse, Qdropping) 3352 && (!EQ (track_mouse, Qdropping)
3348 && !EQ (track_mouse, Qdrag_source))) 3353 && !EQ (track_mouse, Qdrag_source)))
3349 { 3354 f1 = dpyinfo->last_mouse_frame;
3350 /* 1.1. use last_mouse_frame as frame where the pointer is
3351 on. */
3352 f1 = dpyinfo->last_mouse_frame;
3353 }
3354 else 3355 else
3355 { 3356 {
3356 f1 = *fp; 3357 f1 = *fp;
3357 /* 1.2. get frame where the pointer is on. */
3358 win = gtk_widget_get_window (FRAME_GTK_WIDGET (*fp)); 3358 win = gtk_widget_get_window (FRAME_GTK_WIDGET (*fp));
3359 seat = gdk_display_get_default_seat (dpyinfo->gdpy); 3359 seat = gdk_display_get_default_seat (dpyinfo->gdpy);
3360 device = gdk_seat_get_pointer (seat); 3360 device = gdk_seat_get_pointer (seat);
@@ -3380,19 +3380,17 @@ pgtk_mouse_position (struct frame **fp, int insist, Lisp_Object * bar_window,
3380 return; 3380 return;
3381 } 3381 }
3382 3382
3383 /* 2. get the display and the device. */
3384 win = gtk_widget_get_window (FRAME_GTK_WIDGET (f1)); 3383 win = gtk_widget_get_window (FRAME_GTK_WIDGET (f1));
3385 GdkDisplay *gdpy = gdk_window_get_display (win); 3384 seat = gdk_display_get_default_seat (dpyinfo->gdpy);
3386 seat = gdk_display_get_default_seat (gdpy);
3387 device = gdk_seat_get_pointer (seat); 3385 device = gdk_seat_get_pointer (seat);
3388 3386
3389 /* 3. get x, y relative to edit window of the frame. */ 3387 win = gdk_window_get_device_position (win, device,
3390 win = gdk_window_get_device_position (win, device, &win_x, &win_y, &mask); 3388 &win_x, &win_y, &mask);
3391 3389
3392 if (f1 != NULL) 3390 if (f1 != NULL)
3393 { 3391 {
3394 dpyinfo = FRAME_DISPLAY_INFO (f1); 3392 remember_mouse_glyph (f1, win_x, win_y,
3395 remember_mouse_glyph (f1, win_x, win_y, &dpyinfo->last_mouse_glyph); 3393 &dpyinfo->last_mouse_glyph);
3396 dpyinfo->last_mouse_glyph_frame = f1; 3394 dpyinfo->last_mouse_glyph_frame = f1;
3397 3395
3398 *bar_window = Qnil; 3396 *bar_window = Qnil;
@@ -3505,9 +3503,7 @@ pgtk_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
3505 mono-displays, the fill style may have been changed to 3503 mono-displays, the fill style may have been changed to
3506 FillSolid in pgtk_draw_glyph_string_background. */ 3504 FillSolid in pgtk_draw_glyph_string_background. */
3507 if (face->stipple) 3505 if (face->stipple)
3508 { 3506 fill_background_by_face (f, face, p->bx, p->by, p->nx, p->ny);
3509 fill_background_by_face (f, face, p->bx, p->by, p->nx, p->ny);
3510 }
3511 else 3507 else
3512 { 3508 {
3513 pgtk_set_cr_source_with_color (f, face->background, true); 3509 pgtk_set_cr_source_with_color (f, face->background, true);
@@ -6164,6 +6160,20 @@ drag_data_received (GtkWidget *widget, GdkDragContext *context,
6164 gtk_drag_finish (context, TRUE, FALSE, time); 6160 gtk_drag_finish (context, TRUE, FALSE, time);
6165} 6161}
6166 6162
6163static void
6164pgtk_monitors_changed_cb (GdkScreen *screen, gpointer user_data)
6165{
6166 struct terminal *terminal;
6167 union buffered_input_event inev;
6168
6169 EVENT_INIT (inev.ie);
6170 terminal = user_data;
6171 inev.ie.kind = MONITORS_CHANGED_EVENT;
6172 XSETTERMINAL (inev.ie.arg, terminal);
6173
6174 evq_enqueue (&inev);
6175}
6176
6167void 6177void
6168pgtk_set_event_handler (struct frame *f) 6178pgtk_set_event_handler (struct frame *f)
6169{ 6179{
@@ -6282,26 +6292,6 @@ same_x_server (const char *name1, const char *name2)
6282 && (*name2 == '.' || *name2 == '\0')); 6292 && (*name2 == '.' || *name2 == '\0'));
6283} 6293}
6284 6294
6285#define GNOME_INTERFACE_SCHEMA "org.gnome.desktop.interface"
6286
6287static gdouble pgtk_text_scaling_factor (void)
6288{
6289 GSettingsSchemaSource *schema_source = g_settings_schema_source_get_default ();
6290 if (schema_source != NULL)
6291 {
6292 GSettingsSchema *schema = g_settings_schema_source_lookup (schema_source,
6293 GNOME_INTERFACE_SCHEMA, true);
6294 if (schema != NULL)
6295 {
6296 g_settings_schema_unref (schema);
6297 GSettings *set = g_settings_new (GNOME_INTERFACE_SCHEMA);
6298 return g_settings_get_double (set, "text-scaling-factor");
6299 }
6300 }
6301 return 1;
6302}
6303
6304
6305/* Open a connection to X display DISPLAY_NAME, and return 6295/* Open a connection to X display DISPLAY_NAME, and return
6306 the structure that describes the open display. 6296 the structure that describes the open display.
6307 If we cannot contact the display, return null. */ 6297 If we cannot contact the display, return null. */
@@ -6318,6 +6308,8 @@ pgtk_term_init (Lisp_Object display_name, char *resource_name)
6318 char *dpy_name; 6308 char *dpy_name;
6319 static void *handle = NULL; 6309 static void *handle = NULL;
6320 Lisp_Object lisp_dpy_name = Qnil; 6310 Lisp_Object lisp_dpy_name = Qnil;
6311 GdkScreen *gscr;
6312 gdouble dpi;
6321 6313
6322 block_input (); 6314 block_input ();
6323 6315
@@ -6468,21 +6460,22 @@ pgtk_term_init (Lisp_Object display_name, char *resource_name)
6468 6460
6469 reset_mouse_highlight (&dpyinfo->mouse_highlight); 6461 reset_mouse_highlight (&dpyinfo->mouse_highlight);
6470 6462
6471 { 6463 gscr = gdk_display_get_default_screen (dpyinfo->gdpy);
6472 GdkScreen *gscr = gdk_display_get_default_screen (dpyinfo->gdpy); 6464 dpi = gdk_screen_get_resolution (gscr);
6473 6465
6474 gdouble dpi = gdk_screen_get_resolution (gscr); 6466 if (dpi < 0)
6475 if (dpi < 0) 6467 dpi = 96.0;
6476 dpi = 96.0;
6477 6468
6478 dpi *= pgtk_text_scaling_factor (); 6469 dpyinfo->resx = dpi;
6479 dpyinfo->resx = dpi; 6470 dpyinfo->resy = dpi;
6480 dpyinfo->resy = dpi; 6471
6481 } 6472 g_signal_connect (G_OBJECT (gscr), "monitors-changed",
6473 G_CALLBACK (pgtk_monitors_changed_cb),
6474 terminal);
6482 6475
6483 /* smooth scroll setting */ 6476 /* Set up scrolling increments. */
6484 dpyinfo->scroll.x_per_char = 2; 6477 dpyinfo->scroll.x_per_char = 1;
6485 dpyinfo->scroll.y_per_line = 2; 6478 dpyinfo->scroll.y_per_line = 1;
6486 6479
6487 dpyinfo->connection = -1; 6480 dpyinfo->connection = -1;
6488 6481
@@ -6608,9 +6601,9 @@ pgtk_xlfd_to_fontname (const char *xlfd)
6608} 6601}
6609 6602
6610bool 6603bool
6611pgtk_defined_color (struct frame *f, 6604pgtk_defined_color (struct frame *f, const char *name,
6612 const char *name, 6605 Emacs_Color *color_def, bool alloc,
6613 Emacs_Color * color_def, bool alloc, bool makeIndex) 6606 bool makeIndex)
6614/* -------------------------------------------------------------------------- 6607/* --------------------------------------------------------------------------
6615 Return true if named color found, and set color_def rgb accordingly. 6608 Return true if named color found, and set color_def rgb accordingly.
6616 If makeIndex and alloc are nonzero put the color in the color_table, 6609 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
96 editing large files, we establish a minimum height by always 96 editing large files, we establish a minimum height by always
97 drawing handle bottoms VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below 97 drawing handle bottoms VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
98 where they would be normally; the bottom and top are in a 98 where they would be normally; the bottom and top are in a
99 different co-ordinate system. */ 99 different coordinate system. */
100 int start, end; 100 int start, end;
101 101
102 /* If the scroll bar handle is currently being dragged by the user, 102 /* 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. */)
624 return val; 624 return val;
625} 625}
626 626
627DEFUN ("prin1", Fprin1, Sprin1, 1, 2, 0, 627static Lisp_Object Vprint_variable_mapping;
628
629static void
630print_bind_all_defaults (void)
631{
632 for (Lisp_Object vars = Vprint_variable_mapping; !NILP (vars);
633 vars = XCDR (vars))
634 {
635 Lisp_Object elem = XCDR (XCAR (vars));
636 specbind (XCAR (elem), XCAR (XCDR (elem)));
637 }
638}
639
640static void
641print_create_variable_mapping (void)
642{
643 Lisp_Object total[] = {
644 list3 (intern ("length"), intern ("print-length"), Qnil),
645 list3 (intern ("level"), intern ("print-level"), Qnil),
646 list3 (intern ("circle"), intern ("print-circle"), Qnil),
647 list3 (intern ("quoted"), intern ("print-quoted"), Qt),
648 list3 (intern ("escape-newlines"), intern ("print-escape-newlines"), Qnil),
649 list3 (intern ("escape-control-characters"),
650 intern ("print-escape-control-characters"), Qnil),
651 list3 (intern ("escape-nonascii"), intern ("print-escape-nonascii"), Qnil),
652 list3 (intern ("escape-multibyte"),
653 intern ("print-escape-multibyte"), Qnil),
654 list3 (intern ("charset-text-property"),
655 intern ("print-charset-text-property"), Qnil),
656 list3 (intern ("unreadeable-function"),
657 intern ("print-unreadable-function"), Qnil),
658 list3 (intern ("gensym"), intern ("print-gensym"), Qnil),
659 list3 (intern ("continuous-numbering"),
660 intern ("print-continuous-numbering"), Qnil),
661 list3 (intern ("number-table"), intern ("print-number-table"), Qnil),
662 list3 (intern ("float-format"), intern ("float-output-format"), Qnil),
663 list3 (intern ("integers-as-characters"),
664 intern ("print-integers-as-characters"), Qnil),
665 };
666
667 Vprint_variable_mapping = CALLMANY (Flist, total);
668}
669
670static void
671print_bind_overrides (Lisp_Object overrides)
672{
673 if (NILP (Vprint_variable_mapping))
674 print_create_variable_mapping ();
675
676 if (EQ (overrides, Qt))
677 print_bind_all_defaults ();
678 else if (!CONSP (overrides))
679 xsignal (Qwrong_type_argument, Qconsp);
680 else
681 {
682 while (!NILP (overrides))
683 {
684 Lisp_Object setting = XCAR (overrides);
685 if (EQ (setting, Qt))
686 print_bind_all_defaults ();
687 else if (!CONSP (setting))
688 xsignal (Qwrong_type_argument, Qconsp);
689 else
690 {
691 Lisp_Object key = XCAR (setting),
692 value = XCDR (setting);
693 Lisp_Object map = Fassq (key, Vprint_variable_mapping);
694 if (NILP (map))
695 xsignal2 (Qwrong_type_argument, Qsymbolp, map);
696 specbind (XCAR (XCDR (map)), value);
697 }
698
699 if (!NILP (XCDR (overrides)) && !CONSP (XCDR (overrides)))
700 xsignal (Qwrong_type_argument, Qconsp);
701 overrides = XCDR (overrides);
702 }
703 }
704}
705
706DEFUN ("prin1", Fprin1, Sprin1, 1, 3, 0,
628 doc: /* Output the printed representation of OBJECT, any Lisp object. 707 doc: /* Output the printed representation of OBJECT, any Lisp object.
629Quoting characters are printed when needed to make output that `read' 708Quoting characters are printed when needed to make output that `read'
630can handle, whenever this is possible. For complex objects, the behavior 709can handle, whenever this is possible. For complex objects, the behavior
@@ -646,21 +725,43 @@ of these:
646 - t, in which case the output is displayed in the echo area. 725 - t, in which case the output is displayed in the echo area.
647 726
648If PRINTCHARFUN is omitted, the value of `standard-output' (which see) 727If PRINTCHARFUN is omitted, the value of `standard-output' (which see)
649is used instead. */) 728is used instead.
650 (Lisp_Object object, Lisp_Object printcharfun) 729
730Optional argument OVERRIDES should be a list of settings for print-related
731variables. An element in this list can be the symbol t, which means "reset
732all the values to their defaults". Otherwise, an element should be a pair,
733where the `car' or the pair is the setting symbol, and the `cdr' is the
734value of of the setting to use for this `prin1' call.
735
736For instance:
737
738 (prin1 object nil \\='((length . 100) (circle . t))).
739
740See the manual entry `(elisp)Output Overrides' for a list of possible
741values.
742
743As a special case, OVERRIDES can also simply be the symbol t, which
744means "use default values for all the print-related settings". */)
745 (Lisp_Object object, Lisp_Object printcharfun, Lisp_Object overrides)
651{ 746{
747 specpdl_ref count = SPECPDL_INDEX ();
748
652 if (NILP (printcharfun)) 749 if (NILP (printcharfun))
653 printcharfun = Vstandard_output; 750 printcharfun = Vstandard_output;
751 if (!NILP (overrides))
752 print_bind_overrides (overrides);
753
654 PRINTPREPARE; 754 PRINTPREPARE;
655 print (object, printcharfun, 1); 755 print (object, printcharfun, 1);
656 PRINTFINISH; 756 PRINTFINISH;
657 return object; 757
758 return unbind_to (count, object);
658} 759}
659 760
660/* A buffer which is used to hold output being built by prin1-to-string. */ 761/* A buffer which is used to hold output being built by prin1-to-string. */
661Lisp_Object Vprin1_to_string_buffer; 762Lisp_Object Vprin1_to_string_buffer;
662 763
663DEFUN ("prin1-to-string", Fprin1_to_string, Sprin1_to_string, 1, 2, 0, 764DEFUN ("prin1-to-string", Fprin1_to_string, Sprin1_to_string, 1, 3, 0,
664 doc: /* Return a string containing the printed representation of OBJECT. 765 doc: /* Return a string containing the printed representation of OBJECT.
665OBJECT can be any Lisp object. This function outputs quoting characters 766OBJECT can be any Lisp object. This function outputs quoting characters
666when necessary to make output that `read' can handle, whenever possible, 767when 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.
670OBJECT is any of the Lisp data types: a number, a string, a symbol, 771OBJECT is any of the Lisp data types: a number, a string, a symbol,
671a list, a buffer, a window, a frame, etc. 772a list, a buffer, a window, a frame, etc.
672 773
774See `prin1' for the meaning of OVERRIDES.
775
673A printed representation of an object is text which describes that object. */) 776A printed representation of an object is text which describes that object. */)
674 (Lisp_Object object, Lisp_Object noescape) 777 (Lisp_Object object, Lisp_Object noescape, Lisp_Object overrides)
675{ 778{
676 specpdl_ref count = SPECPDL_INDEX (); 779 specpdl_ref count = SPECPDL_INDEX ();
677 780
678 specbind (Qinhibit_modification_hooks, Qt); 781 specbind (Qinhibit_modification_hooks, Qt);
679 782
783 if (!NILP (overrides))
784 print_bind_overrides (overrides);
785
680 /* Save and restore this: we are altering a buffer 786 /* Save and restore this: we are altering a buffer
681 but we don't want to deactivate the mark just for that. 787 but we don't want to deactivate the mark just for that.
682 No need for specbind, since errors deactivate the mark. */ 788 No need for specbind, since errors deactivate the mark. */
@@ -732,7 +838,13 @@ is used instead. */)
732 if (NILP (printcharfun)) 838 if (NILP (printcharfun))
733 printcharfun = Vstandard_output; 839 printcharfun = Vstandard_output;
734 PRINTPREPARE; 840 PRINTPREPARE;
735 print (object, printcharfun, 0); 841 if (STRINGP (object)
842 && !string_intervals (object)
843 && NILP (Vprint_continuous_numbering))
844 /* fast path for plain strings */
845 print_string (object, printcharfun);
846 else
847 print (object, printcharfun, 0);
736 PRINTFINISH; 848 PRINTFINISH;
737 return object; 849 return object;
738} 850}
@@ -851,7 +963,7 @@ append to existing target file. */)
851void 963void
852debug_print (Lisp_Object arg) 964debug_print (Lisp_Object arg)
853{ 965{
854 Fprin1 (arg, Qexternal_debugging_output); 966 Fprin1 (arg, Qexternal_debugging_output, Qnil);
855 fputs ("\r\n", stderr); 967 fputs ("\r\n", stderr);
856} 968}
857 969
@@ -999,7 +1111,7 @@ print_error_message (Lisp_Object data, Lisp_Object stream, const char *context,
999 || EQ (errname, Qend_of_file) || EQ (errname, Quser_error)) 1111 || EQ (errname, Qend_of_file) || EQ (errname, Quser_error))
1000 Fprinc (obj, stream); 1112 Fprinc (obj, stream);
1001 else 1113 else
1002 Fprin1 (obj, stream); 1114 Fprin1 (obj, stream, Qnil);
1003 } 1115 }
1004 } 1116 }
1005} 1117}
@@ -1147,7 +1259,6 @@ print (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
1147 { 1259 {
1148 /* Construct Vprint_number_table. 1260 /* Construct Vprint_number_table.
1149 This increments print_number_index for the objects added. */ 1261 This increments print_number_index for the objects added. */
1150 print_depth = 0;
1151 print_preprocess (obj); 1262 print_preprocess (obj);
1152 1263
1153 if (HASH_TABLE_P (Vprint_number_table)) 1264 if (HASH_TABLE_P (Vprint_number_table))
@@ -1159,7 +1270,7 @@ print (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
1159 for (i = 0; i < HASH_TABLE_SIZE (h); ++i) 1270 for (i = 0; i < HASH_TABLE_SIZE (h); ++i)
1160 { 1271 {
1161 Lisp_Object key = HASH_KEY (h, i); 1272 Lisp_Object key = HASH_KEY (h, i);
1162 if (!EQ (key, Qunbound) 1273 if (!BASE_EQ (key, Qunbound)
1163 && EQ (HASH_VALUE (h, i), Qt)) 1274 && EQ (HASH_VALUE (h, i), Qt))
1164 Fremhash (key, Vprint_number_table); 1275 Fremhash (key, Vprint_number_table);
1165 } 1276 }
@@ -1171,10 +1282,7 @@ print (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
1171} 1282}
1172 1283
1173#define PRINT_CIRCLE_CANDIDATE_P(obj) \ 1284#define PRINT_CIRCLE_CANDIDATE_P(obj) \
1174 ((STRINGP (obj) \ 1285 (STRINGP (obj) \
1175 && (string_intervals (obj) \
1176 || print_depth > 1 \
1177 || !NILP (Vprint_continuous_numbering))) \
1178 || CONSP (obj) \ 1286 || CONSP (obj) \
1179 || (VECTORLIKEP (obj) \ 1287 || (VECTORLIKEP (obj) \
1180 && (VECTORP (obj) || COMPILEDP (obj) \ 1288 && (VECTORP (obj) || COMPILEDP (obj) \
@@ -1185,6 +1293,78 @@ print (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
1185 && SYMBOLP (obj) \ 1293 && SYMBOLP (obj) \
1186 && !SYMBOL_INTERNED_P (obj))) 1294 && !SYMBOL_INTERNED_P (obj)))
1187 1295
1296/* The print preprocess stack, used to traverse data structures. */
1297
1298struct print_pp_entry {
1299 ptrdiff_t n; /* number of values, or 0 if a single value */
1300 union {
1301 Lisp_Object value; /* when n = 0 */
1302 Lisp_Object *values; /* when n > 0 */
1303 } u;
1304};
1305
1306struct print_pp_stack {
1307 struct print_pp_entry *stack; /* base of stack */
1308 ptrdiff_t size; /* allocated size in entries */
1309 ptrdiff_t sp; /* current number of entries */
1310};
1311
1312static struct print_pp_stack ppstack = {NULL, 0, 0};
1313
1314NO_INLINE static void
1315grow_pp_stack (void)
1316{
1317 struct print_pp_stack *ps = &ppstack;
1318 eassert (ps->sp == ps->size);
1319 ps->stack = xpalloc (ps->stack, &ps->size, 1, -1, sizeof *ps->stack);
1320 eassert (ps->sp < ps->size);
1321}
1322
1323static inline void
1324pp_stack_push_value (Lisp_Object value)
1325{
1326 if (ppstack.sp >= ppstack.size)
1327 grow_pp_stack ();
1328 ppstack.stack[ppstack.sp++] = (struct print_pp_entry){.n = 0,
1329 .u.value = value};
1330}
1331
1332static inline void
1333pp_stack_push_values (Lisp_Object *values, ptrdiff_t n)
1334{
1335 eassume (n >= 0);
1336 if (n == 0)
1337 return;
1338 if (ppstack.sp >= ppstack.size)
1339 grow_pp_stack ();
1340 ppstack.stack[ppstack.sp++] = (struct print_pp_entry){.n = n,
1341 .u.values = values};
1342}
1343
1344static inline bool
1345pp_stack_empty_p (void)
1346{
1347 return ppstack.sp <= 0;
1348}
1349
1350static inline Lisp_Object
1351pp_stack_pop (void)
1352{
1353 eassume (!pp_stack_empty_p ());
1354 struct print_pp_entry *e = &ppstack.stack[ppstack.sp - 1];
1355 if (e->n == 0) /* single value */
1356 {
1357 --ppstack.sp;
1358 return e->u.value;
1359 }
1360 /* Array of values: pop them left to right, which seems to be slightly
1361 faster than right to left. */
1362 e->n--;
1363 if (e->n == 0)
1364 --ppstack.sp; /* last value consumed */
1365 return (++e->u.values)[-1];
1366}
1367
1188/* Construct Vprint_number_table for the print-circle feature 1368/* Construct Vprint_number_table for the print-circle feature
1189 according to the structure of OBJ. OBJ itself and all its elements 1369 according to the structure of OBJ. OBJ itself and all its elements
1190 will be added to Vprint_number_table recursively if it is a list, 1370 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)
1196static void 1376static void
1197print_preprocess (Lisp_Object obj) 1377print_preprocess (Lisp_Object obj)
1198{ 1378{
1199 int i;
1200 ptrdiff_t size;
1201 int loop_count = 0;
1202 Lisp_Object halftail;
1203
1204 eassert (!NILP (Vprint_circle)); 1379 eassert (!NILP (Vprint_circle));
1380 ptrdiff_t base_sp = ppstack.sp;
1205 1381
1206 print_depth++; 1382 for (;;)
1207 halftail = obj;
1208
1209 loop:
1210 if (PRINT_CIRCLE_CANDIDATE_P (obj))
1211 { 1383 {
1212 if (!HASH_TABLE_P (Vprint_number_table)) 1384 if (PRINT_CIRCLE_CANDIDATE_P (obj))
1213 Vprint_number_table = CALLN (Fmake_hash_table, QCtest, Qeq); 1385 {
1214 1386 if (!HASH_TABLE_P (Vprint_number_table))
1215 Lisp_Object num = Fgethash (obj, Vprint_number_table, Qnil); 1387 Vprint_number_table = CALLN (Fmake_hash_table, QCtest, Qeq);
1216 if (!NILP (num) 1388
1217 /* If Vprint_continuous_numbering is non-nil and OBJ is a gensym, 1389 Lisp_Object num = Fgethash (obj, Vprint_number_table, Qnil);
1218 always print the gensym with a number. This is a special for 1390 if (!NILP (num)
1219 the lisp function byte-compile-output-docform. */ 1391 /* If Vprint_continuous_numbering is non-nil and OBJ is a gensym,
1220 || (!NILP (Vprint_continuous_numbering) 1392 always print the gensym with a number. This is a special for
1221 && SYMBOLP (obj) 1393 the lisp function byte-compile-output-docform. */
1222 && !SYMBOL_INTERNED_P (obj))) 1394 || (!NILP (Vprint_continuous_numbering)
1223 { /* OBJ appears more than once. Let's remember that. */ 1395 && SYMBOLP (obj)
1224 if (!FIXNUMP (num)) 1396 && !SYMBOL_INTERNED_P (obj)))
1225 { 1397 { /* OBJ appears more than once. Let's remember that. */
1226 print_number_index++; 1398 if (!FIXNUMP (num))
1227 /* Negative number indicates it hasn't been printed yet. */ 1399 {
1228 Fputhash (obj, make_fixnum (- print_number_index), 1400 print_number_index++;
1229 Vprint_number_table); 1401 /* Negative number indicates it hasn't been printed yet. */
1402 Fputhash (obj, make_fixnum (- print_number_index),
1403 Vprint_number_table);
1404 }
1230 } 1405 }
1231 print_depth--; 1406 else
1232 return; 1407 {
1233 } 1408 /* OBJ is not yet recorded. Let's add to the table. */
1234 else 1409 Fputhash (obj, Qt, Vprint_number_table);
1235 /* OBJ is not yet recorded. Let's add to the table. */
1236 Fputhash (obj, Qt, Vprint_number_table);
1237 1410
1238 switch (XTYPE (obj)) 1411 switch (XTYPE (obj))
1239 { 1412 {
1240 case Lisp_String: 1413 case Lisp_String:
1241 /* A string may have text properties, which can be circular. */ 1414 /* A string may have text properties,
1242 traverse_intervals_noorder (string_intervals (obj), 1415 which can be circular. */
1243 print_preprocess_string, NULL); 1416 traverse_intervals_noorder (string_intervals (obj),
1244 break; 1417 print_preprocess_string, NULL);
1418 break;
1245 1419
1246 case Lisp_Cons: 1420 case Lisp_Cons:
1247 /* Use HALFTAIL and LOOP_COUNT to detect circular lists, 1421 if (!NILP (XCDR (obj)))
1248 just as in print_object. */ 1422 pp_stack_push_value (XCDR (obj));
1249 if (loop_count && EQ (obj, halftail)) 1423 obj = XCAR (obj);
1250 break; 1424 continue;
1251 print_preprocess (XCAR (obj));
1252 obj = XCDR (obj);
1253 loop_count++;
1254 if (!(loop_count & 1))
1255 halftail = XCDR (halftail);
1256 goto loop;
1257
1258 case Lisp_Vectorlike:
1259 size = ASIZE (obj);
1260 if (size & PSEUDOVECTOR_FLAG)
1261 size &= PSEUDOVECTOR_SIZE_MASK;
1262 for (i = (SUB_CHAR_TABLE_P (obj)
1263 ? SUB_CHAR_TABLE_OFFSET : 0); i < size; i++)
1264 print_preprocess (AREF (obj, i));
1265 if (HASH_TABLE_P (obj))
1266 { /* For hash tables, the key_and_value slot is past
1267 `size' because it needs to be marked specially in case
1268 the table is weak. */
1269 struct Lisp_Hash_Table *h = XHASH_TABLE (obj);
1270 print_preprocess (h->key_and_value);
1271 }
1272 break;
1273 1425
1274 default: 1426 case Lisp_Vectorlike:
1275 break; 1427 {
1428 struct Lisp_Vector *vec = XVECTOR (obj);
1429 ptrdiff_t size = ASIZE (obj);
1430 if (size & PSEUDOVECTOR_FLAG)
1431 size &= PSEUDOVECTOR_SIZE_MASK;
1432 ptrdiff_t start = (SUB_CHAR_TABLE_P (obj)
1433 ? SUB_CHAR_TABLE_OFFSET : 0);
1434 pp_stack_push_values (vec->contents + start, size - start);
1435 if (HASH_TABLE_P (obj))
1436 {
1437 struct Lisp_Hash_Table *h = XHASH_TABLE (obj);
1438 obj = h->key_and_value;
1439 continue;
1440 }
1441 break;
1442 }
1443
1444 default:
1445 break;
1446 }
1447 }
1276 } 1448 }
1449
1450 if (ppstack.sp <= base_sp)
1451 break;
1452 obj = pp_stack_pop ();
1277 } 1453 }
1278 print_depth--;
1279} 1454}
1280 1455
1281DEFUN ("print--preprocess", Fprint_preprocess, Sprint_preprocess, 1, 1, 0, 1456DEFUN ("print--preprocess", Fprint_preprocess, Sprint_preprocess, 1, 1, 0,
@@ -1467,162 +1642,6 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag,
1467 } 1642 }
1468 return true; 1643 return true;
1469 1644
1470 case PVEC_HASH_TABLE:
1471 {
1472 struct Lisp_Hash_Table *h = XHASH_TABLE (obj);
1473 /* Implement a readable output, e.g.:
1474 #s(hash-table size 2 test equal data (k1 v1 k2 v2)) */
1475 /* Always print the size. */
1476 int len = sprintf (buf, "#s(hash-table size %"pD"d",
1477 HASH_TABLE_SIZE (h));
1478 strout (buf, len, len, printcharfun);
1479
1480 if (!NILP (h->test.name))
1481 {
1482 print_c_string (" test ", printcharfun);
1483 print_object (h->test.name, printcharfun, escapeflag);
1484 }
1485
1486 if (!NILP (h->weak))
1487 {
1488 print_c_string (" weakness ", printcharfun);
1489 print_object (h->weak, printcharfun, escapeflag);
1490 }
1491
1492 print_c_string (" rehash-size ", printcharfun);
1493 print_object (Fhash_table_rehash_size (obj),
1494 printcharfun, escapeflag);
1495
1496 print_c_string (" rehash-threshold ", printcharfun);
1497 print_object (Fhash_table_rehash_threshold (obj),
1498 printcharfun, escapeflag);
1499
1500 if (h->purecopy)
1501 {
1502 print_c_string (" purecopy ", printcharfun);
1503 print_object (h->purecopy ? Qt : Qnil, printcharfun, escapeflag);
1504 }
1505
1506 print_c_string (" data ", printcharfun);
1507
1508 /* Print the data here as a plist. */
1509 ptrdiff_t real_size = HASH_TABLE_SIZE (h);
1510 ptrdiff_t size = h->count;
1511
1512 /* Don't print more elements than the specified maximum. */
1513 if (FIXNATP (Vprint_length) && XFIXNAT (Vprint_length) < size)
1514 size = XFIXNAT (Vprint_length);
1515
1516 printchar ('(', printcharfun);
1517 ptrdiff_t j = 0;
1518 for (ptrdiff_t i = 0; i < real_size; i++)
1519 {
1520 Lisp_Object key = HASH_KEY (h, i);
1521 if (!EQ (key, Qunbound))
1522 {
1523 if (j++) printchar (' ', printcharfun);
1524 print_object (key, printcharfun, escapeflag);
1525 printchar (' ', printcharfun);
1526 print_object (HASH_VALUE (h, i), printcharfun, escapeflag);
1527 if (j == size)
1528 break;
1529 }
1530 }
1531
1532 if (j < h->count)
1533 {
1534 if (j)
1535 printchar (' ', printcharfun);
1536 print_c_string ("...", printcharfun);
1537 }
1538
1539 print_c_string ("))", printcharfun);
1540 }
1541 return true;
1542
1543 case PVEC_RECORD:
1544 {
1545 ptrdiff_t size = PVSIZE (obj);
1546
1547 /* Don't print more elements than the specified maximum. */
1548 ptrdiff_t n
1549 = (FIXNATP (Vprint_length) && XFIXNAT (Vprint_length) < size
1550 ? XFIXNAT (Vprint_length) : size);
1551
1552 print_c_string ("#s(", printcharfun);
1553 for (ptrdiff_t i = 0; i < n; i ++)
1554 {
1555 if (i) printchar (' ', printcharfun);
1556 print_object (AREF (obj, i), printcharfun, escapeflag);
1557 }
1558 if (n < size)
1559 print_c_string (" ...", printcharfun);
1560 printchar (')', printcharfun);
1561 }
1562 return true;
1563
1564 case PVEC_SUB_CHAR_TABLE:
1565 case PVEC_COMPILED:
1566 case PVEC_CHAR_TABLE:
1567 case PVEC_NORMAL_VECTOR:
1568 {
1569 ptrdiff_t size = ASIZE (obj);
1570 if (COMPILEDP (obj))
1571 {
1572 printchar ('#', printcharfun);
1573 size &= PSEUDOVECTOR_SIZE_MASK;
1574 }
1575 if (CHAR_TABLE_P (obj) || SUB_CHAR_TABLE_P (obj))
1576 {
1577 /* Print a char-table as if it were a vector,
1578 lumping the parent and default slots in with the
1579 character slots. But add #^ as a prefix. */
1580
1581 /* Make each lowest sub_char_table start a new line.
1582 Otherwise we'll make a line extremely long, which
1583 results in slow redisplay. */
1584 if (SUB_CHAR_TABLE_P (obj)
1585 && XSUB_CHAR_TABLE (obj)->depth == 3)
1586 printchar ('\n', printcharfun);
1587 print_c_string ("#^", printcharfun);
1588 if (SUB_CHAR_TABLE_P (obj))
1589 printchar ('^', printcharfun);
1590 size &= PSEUDOVECTOR_SIZE_MASK;
1591 }
1592 if (size & PSEUDOVECTOR_FLAG)
1593 return false;
1594
1595 printchar ('[', printcharfun);
1596
1597 int idx = SUB_CHAR_TABLE_P (obj) ? SUB_CHAR_TABLE_OFFSET : 0;
1598 Lisp_Object tem;
1599 ptrdiff_t real_size = size;
1600
1601 /* For a sub char-table, print heading non-Lisp data first. */
1602 if (SUB_CHAR_TABLE_P (obj))
1603 {
1604 int i = sprintf (buf, "%d %d", XSUB_CHAR_TABLE (obj)->depth,
1605 XSUB_CHAR_TABLE (obj)->min_char);
1606 strout (buf, i, i, printcharfun);
1607 }
1608
1609 /* Don't print more elements than the specified maximum. */
1610 if (FIXNATP (Vprint_length)
1611 && XFIXNAT (Vprint_length) < size)
1612 size = XFIXNAT (Vprint_length);
1613
1614 for (int i = idx; i < size; i++)
1615 {
1616 if (i) printchar (' ', printcharfun);
1617 tem = AREF (obj, i);
1618 print_object (tem, printcharfun, escapeflag);
1619 }
1620 if (size < real_size)
1621 print_c_string (" ...", printcharfun);
1622 printchar (']', printcharfun);
1623 }
1624 return true;
1625
1626 default: 1645 default:
1627 break; 1646 break;
1628 } 1647 }
@@ -2028,32 +2047,132 @@ named_escape (int i)
2028 return 0; 2047 return 0;
2029} 2048}
2030 2049
2050enum print_entry_type
2051 {
2052 PE_list, /* print rest of list */
2053 PE_rbrac, /* print ")" */
2054 PE_vector, /* print rest of vector */
2055 PE_hash, /* print rest of hash data */
2056 };
2057
2058struct print_stack_entry
2059{
2060 enum print_entry_type type;
2061
2062 union
2063 {
2064 struct
2065 {
2066 Lisp_Object last; /* cons whose car was just printed */
2067 intmax_t maxlen; /* max number of elements left to print */
2068 /* State for Brent cycle detection. See
2069 Brent RP. BIT. 1980;20(2):176-184. doi:10.1007/BF01933190
2070 https://maths-people.anu.edu.au/~brent/pd/rpb051i.pdf */
2071 Lisp_Object tortoise; /* slow pointer */
2072 ptrdiff_t n; /* tortoise step countdown */
2073 ptrdiff_t m; /* tortoise step period */
2074 intmax_t tortoise_idx; /* index of tortoise */
2075 } list;
2076
2077 struct
2078 {
2079 Lisp_Object obj; /* object to print after " . " */
2080 } dotted_cdr;
2081
2082 struct
2083 {
2084 Lisp_Object obj; /* vector object */
2085 ptrdiff_t size; /* length of vector */
2086 ptrdiff_t idx; /* index of next element */
2087 const char *end; /* string to print at end */
2088 bool truncated; /* whether to print "..." before end */
2089 } vector;
2090
2091 struct
2092 {
2093 Lisp_Object obj; /* hash-table object */
2094 ptrdiff_t nobjs; /* number of keys and values to print */
2095 ptrdiff_t idx; /* index of key-value pair */
2096 ptrdiff_t printed; /* number of keys and values printed */
2097 bool truncated; /* whether to print "..." before end */
2098 } hash;
2099 } u;
2100};
2101
2102struct print_stack
2103{
2104 struct print_stack_entry *stack; /* base of stack */
2105 ptrdiff_t size; /* allocated size in entries */
2106 ptrdiff_t sp; /* current number of entries */
2107};
2108
2109static struct print_stack prstack = {NULL, 0, 0};
2110
2111NO_INLINE static void
2112grow_print_stack (void)
2113{
2114 struct print_stack *ps = &prstack;
2115 eassert (ps->sp == ps->size);
2116 ps->stack = xpalloc (ps->stack, &ps->size, 1, -1, sizeof *ps->stack);
2117 eassert (ps->sp < ps->size);
2118}
2119
2120static inline void
2121print_stack_push (struct print_stack_entry e)
2122{
2123 if (prstack.sp >= prstack.size)
2124 grow_print_stack ();
2125 prstack.stack[prstack.sp++] = e;
2126}
2127
2128static void
2129print_stack_push_vector (const char *lbrac, const char *rbrac,
2130 Lisp_Object obj, ptrdiff_t start, ptrdiff_t size,
2131 Lisp_Object printcharfun)
2132{
2133 print_c_string (lbrac, printcharfun);
2134
2135 ptrdiff_t print_size = ((FIXNATP (Vprint_length)
2136 && XFIXNAT (Vprint_length) < size)
2137 ? XFIXNAT (Vprint_length) : size);
2138 print_stack_push ((struct print_stack_entry){
2139 .type = PE_vector,
2140 .u.vector.obj = obj,
2141 .u.vector.size = print_size,
2142 .u.vector.idx = start,
2143 .u.vector.end = rbrac,
2144 .u.vector.truncated = (print_size < size),
2145 });
2146}
2147
2031static void 2148static void
2032print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag) 2149print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
2033{ 2150{
2151 ptrdiff_t base_depth = print_depth;
2152 ptrdiff_t base_sp = prstack.sp;
2034 char buf[max (sizeof "from..to..in " + 2 * INT_STRLEN_BOUND (EMACS_INT), 2153 char buf[max (sizeof "from..to..in " + 2 * INT_STRLEN_BOUND (EMACS_INT),
2035 max (sizeof " . #" + INT_STRLEN_BOUND (intmax_t), 2154 max (sizeof " . #" + INT_STRLEN_BOUND (intmax_t),
2036 max ((sizeof " with data 0x" 2155 max ((sizeof " with data 0x"
2037 + (sizeof (uintmax_t) * CHAR_BIT + 4 - 1) / 4), 2156 + (sizeof (uintmax_t) * CHAR_BIT + 4 - 1) / 4),
2038 40)))]; 2157 40)))];
2039 current_thread->stack_top = buf; 2158 current_thread->stack_top = buf;
2159
2160 print_obj:
2040 maybe_quit (); 2161 maybe_quit ();
2041 2162
2042 /* Detect circularities and truncate them. */ 2163 /* Detect circularities and truncate them. */
2043 if (NILP (Vprint_circle)) 2164 if (NILP (Vprint_circle))
2044 { 2165 {
2045 /* Simple but incomplete way. */ 2166 /* Simple but incomplete way. */
2046 int i;
2047
2048 if (print_depth >= PRINT_CIRCLE) 2167 if (print_depth >= PRINT_CIRCLE)
2049 error ("Apparently circular structure being printed"); 2168 error ("Apparently circular structure being printed");
2050 2169
2051 for (i = 0; i < print_depth; i++) 2170 for (int i = 0; i < print_depth; i++)
2052 if (BASE_EQ (obj, being_printed[i])) 2171 if (BASE_EQ (obj, being_printed[i]))
2053 { 2172 {
2054 int len = sprintf (buf, "#%d", i); 2173 int len = sprintf (buf, "#%d", i);
2055 strout (buf, len, len, printcharfun); 2174 strout (buf, len, len, printcharfun);
2056 return; 2175 goto next_obj;
2057 } 2176 }
2058 being_printed[print_depth] = obj; 2177 being_printed[print_depth] = obj;
2059 } 2178 }
@@ -2077,7 +2196,7 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
2077 /* Just print #n# if OBJ has already been printed. */ 2196 /* Just print #n# if OBJ has already been printed. */
2078 int len = sprintf (buf, "#%"pI"d#", n); 2197 int len = sprintf (buf, "#%"pI"d#", n);
2079 strout (buf, len, len, printcharfun); 2198 strout (buf, len, len, printcharfun);
2080 return; 2199 goto next_obj;
2081 } 2200 }
2082 } 2201 }
2083 } 2202 }
@@ -2151,7 +2270,8 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
2151 for (i = 0, i_byte = 0; i_byte < size_byte;) 2270 for (i = 0, i_byte = 0; i_byte < size_byte;)
2152 { 2271 {
2153 /* Here, we must convert each multi-byte form to the 2272 /* Here, we must convert each multi-byte form to the
2154 corresponding character code before handing it to printchar. */ 2273 corresponding character code before handing it to
2274 printchar. */
2155 int c = fetch_string_char_advance (obj, &i, &i_byte); 2275 int c = fetch_string_char_advance (obj, &i, &i_byte);
2156 2276
2157 maybe_quit (); 2277 maybe_quit ();
@@ -2171,7 +2291,8 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
2171 else if (multibyte 2291 else if (multibyte
2172 && ! ASCII_CHAR_P (c) && print_escape_multibyte) 2292 && ! ASCII_CHAR_P (c) && print_escape_multibyte)
2173 { 2293 {
2174 /* When requested, print multibyte chars using hex escapes. */ 2294 /* When requested, print multibyte chars using
2295 hex escapes. */
2175 char outbuf[sizeof "\\x" + INT_STRLEN_BOUND (c)]; 2296 char outbuf[sizeof "\\x" + INT_STRLEN_BOUND (c)];
2176 int len = sprintf (outbuf, "\\x%04x", c + 0u); 2297 int len = sprintf (outbuf, "\\x%04x", c + 0u);
2177 strout (outbuf, len, len, printcharfun); 2298 strout (outbuf, len, len, printcharfun);
@@ -2282,14 +2403,22 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
2282 && EQ (XCAR (obj), Qquote)) 2403 && EQ (XCAR (obj), Qquote))
2283 { 2404 {
2284 printchar ('\'', printcharfun); 2405 printchar ('\'', printcharfun);
2285 print_object (XCAR (XCDR (obj)), printcharfun, escapeflag); 2406 obj = XCAR (XCDR (obj));
2407 --print_depth; /* tail recursion */
2408 goto print_obj;
2286 } 2409 }
2287 else if (print_quoted && CONSP (XCDR (obj)) && NILP (XCDR (XCDR (obj))) 2410 else if (print_quoted && CONSP (XCDR (obj)) && NILP (XCDR (XCDR (obj)))
2288 && EQ (XCAR (obj), Qfunction)) 2411 && EQ (XCAR (obj), Qfunction))
2289 { 2412 {
2290 print_c_string ("#'", printcharfun); 2413 print_c_string ("#'", printcharfun);
2291 print_object (XCAR (XCDR (obj)), printcharfun, escapeflag); 2414 obj = XCAR (XCDR (obj));
2415 --print_depth; /* tail recursion */
2416 goto print_obj;
2292 } 2417 }
2418 /* FIXME: Do we really need the new_backquote_output gating of
2419 special syntax for comma and comma-at? There is basically no
2420 benefit from it at all, and it would be nice to get rid of
2421 the recursion here without additional complexity. */
2293 else if (print_quoted && CONSP (XCDR (obj)) && NILP (XCDR (XCDR (obj))) 2422 else if (print_quoted && CONSP (XCDR (obj)) && NILP (XCDR (XCDR (obj)))
2294 && EQ (XCAR (obj), Qbackquote)) 2423 && EQ (XCAR (obj), Qbackquote))
2295 { 2424 {
@@ -2299,9 +2428,9 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
2299 new_backquote_output--; 2428 new_backquote_output--;
2300 } 2429 }
2301 else if (print_quoted && CONSP (XCDR (obj)) && NILP (XCDR (XCDR (obj))) 2430 else if (print_quoted && CONSP (XCDR (obj)) && NILP (XCDR (XCDR (obj)))
2302 && new_backquote_output
2303 && (EQ (XCAR (obj), Qcomma) 2431 && (EQ (XCAR (obj), Qcomma)
2304 || EQ (XCAR (obj), Qcomma_at))) 2432 || EQ (XCAR (obj), Qcomma_at))
2433 && new_backquote_output)
2305 { 2434 {
2306 print_object (XCAR (obj), printcharfun, false); 2435 print_object (XCAR (obj), printcharfun, false);
2307 new_backquote_output--; 2436 new_backquote_output--;
@@ -2311,70 +2440,135 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
2311 else 2440 else
2312 { 2441 {
2313 printchar ('(', printcharfun); 2442 printchar ('(', printcharfun);
2314
2315 /* Negative values of print-length are invalid in CL. 2443 /* Negative values of print-length are invalid in CL.
2316 Treat them like nil, as CMUCL does. */ 2444 Treat them like nil, as CMUCL does. */
2317 intmax_t print_length = (FIXNATP (Vprint_length) 2445 intmax_t print_length = (FIXNATP (Vprint_length)
2318 ? XFIXNAT (Vprint_length) 2446 ? XFIXNAT (Vprint_length)
2319 : INTMAX_MAX); 2447 : INTMAX_MAX);
2320 Lisp_Object objtail = Qnil; 2448 if (print_length == 0)
2321 intmax_t i = 0; 2449 print_c_string ("...)", printcharfun);
2322 FOR_EACH_TAIL_SAFE (obj) 2450 else
2323 { 2451 {
2324 if (i != 0) 2452 print_stack_push ((struct print_stack_entry){
2325 { 2453 .type = PE_list,
2326 printchar (' ', printcharfun); 2454 .u.list.last = obj,
2327 2455 .u.list.maxlen = print_length,
2328 if (!NILP (Vprint_circle)) 2456 .u.list.tortoise = obj,
2329 { 2457 .u.list.n = 2,
2330 /* With the print-circle feature. */ 2458 .u.list.m = 2,
2331 Lisp_Object num = Fgethash (obj, Vprint_number_table, 2459 .u.list.tortoise_idx = 0,
2332 Qnil); 2460 });
2333 if (FIXNUMP (num)) 2461 /* print the car */
2334 { 2462 obj = XCAR (obj);
2335 print_c_string (". ", printcharfun); 2463 goto print_obj;
2336 print_object (obj, printcharfun, escapeflag);
2337 goto end_of_list;
2338 }
2339 }
2340 }
2341
2342 if (print_length <= i)
2343 {
2344 print_c_string ("...", printcharfun);
2345 goto end_of_list;
2346 }
2347
2348 i++;
2349 print_object (XCAR (obj), printcharfun, escapeflag);
2350 objtail = XCDR (obj);
2351 } 2464 }
2465 }
2466 break;
2352 2467
2353 /* OBJTAIL non-nil here means it's the end of a dotted list 2468 case Lisp_Vectorlike:
2354 or FOR_EACH_TAIL_SAFE detected a circular list. */ 2469 /* First do all the vectorlike types that have a readable syntax. */
2355 if (!NILP (objtail)) 2470 switch (PSEUDOVECTOR_TYPE (XVECTOR (obj)))
2356 { 2471 {
2357 print_c_string (" . ", printcharfun); 2472 case PVEC_NORMAL_VECTOR:
2473 {
2474 print_stack_push_vector ("[", "]", obj, 0, ASIZE (obj),
2475 printcharfun);
2476 goto next_obj;
2477 }
2478 case PVEC_RECORD:
2479 {
2480 print_stack_push_vector ("#s(", ")", obj, 0, PVSIZE (obj),
2481 printcharfun);
2482 goto next_obj;
2483 }
2484 case PVEC_COMPILED:
2485 {
2486 print_stack_push_vector ("#[", "]", obj, 0, PVSIZE (obj),
2487 printcharfun);
2488 goto next_obj;
2489 }
2490 case PVEC_CHAR_TABLE:
2491 {
2492 print_stack_push_vector ("#^[", "]", obj, 0, PVSIZE (obj),
2493 printcharfun);
2494 goto next_obj;
2495 }
2496 case PVEC_SUB_CHAR_TABLE:
2497 {
2498 /* Make each lowest sub_char_table start a new line.
2499 Otherwise we'll make a line extremely long, which
2500 results in slow redisplay. */
2501 if (XSUB_CHAR_TABLE (obj)->depth == 3)
2502 printchar ('\n', printcharfun);
2503 print_c_string ("#^^[", printcharfun);
2504 int n = sprintf (buf, "%d %d",
2505 XSUB_CHAR_TABLE (obj)->depth,
2506 XSUB_CHAR_TABLE (obj)->min_char);
2507 strout (buf, n, n, printcharfun);
2508 print_stack_push_vector ("", "]", obj,
2509 SUB_CHAR_TABLE_OFFSET, PVSIZE (obj),
2510 printcharfun);
2511 goto next_obj;
2512 }
2513 case PVEC_HASH_TABLE:
2514 {
2515 struct Lisp_Hash_Table *h = XHASH_TABLE (obj);
2516 /* Implement a readable output, e.g.:
2517 #s(hash-table size 2 test equal data (k1 v1 k2 v2)) */
2518 /* Always print the size. */
2519 int len = sprintf (buf, "#s(hash-table size %"pD"d",
2520 HASH_TABLE_SIZE (h));
2521 strout (buf, len, len, printcharfun);
2358 2522
2359 if (CONSP (objtail) && NILP (Vprint_circle)) 2523 if (!NILP (h->test.name))
2360 { 2524 {
2361 int len = sprintf (buf, "#%"PRIdMAX, i >> 1); 2525 print_c_string (" test ", printcharfun);
2362 strout (buf, len, len, printcharfun); 2526 print_object (h->test.name, printcharfun, escapeflag);
2363 goto end_of_list; 2527 }
2364 }
2365 2528
2366 print_object (objtail, printcharfun, escapeflag); 2529 if (!NILP (h->weak))
2367 } 2530 {
2531 print_c_string (" weakness ", printcharfun);
2532 print_object (h->weak, printcharfun, escapeflag);
2533 }
2368 2534
2369 end_of_list: 2535 print_c_string (" rehash-size ", printcharfun);
2370 printchar (')', printcharfun); 2536 print_object (Fhash_table_rehash_size (obj),
2537 printcharfun, escapeflag);
2538
2539 print_c_string (" rehash-threshold ", printcharfun);
2540 print_object (Fhash_table_rehash_threshold (obj),
2541 printcharfun, escapeflag);
2542
2543 if (h->purecopy)
2544 print_c_string (" purecopy t", printcharfun);
2545
2546 print_c_string (" data (", printcharfun);
2547
2548 ptrdiff_t size = h->count;
2549 /* Don't print more elements than the specified maximum. */
2550 if (FIXNATP (Vprint_length) && XFIXNAT (Vprint_length) < size)
2551 size = XFIXNAT (Vprint_length);
2552
2553 print_stack_push ((struct print_stack_entry){
2554 .type = PE_hash,
2555 .u.hash.obj = obj,
2556 .u.hash.nobjs = size * 2,
2557 .u.hash.idx = 0,
2558 .u.hash.printed = 0,
2559 .u.hash.truncated = (size < h->count),
2560 });
2561 goto next_obj;
2562 }
2563
2564 default:
2565 break;
2371 } 2566 }
2372 break;
2373 2567
2374 case Lisp_Vectorlike:
2375 if (print_vectorlike (obj, printcharfun, escapeflag, buf)) 2568 if (print_vectorlike (obj, printcharfun, escapeflag, buf))
2376 break; 2569 break;
2377 FALLTHROUGH; 2570 FALLTHROUGH;
2571
2378 default: 2572 default:
2379 { 2573 {
2380 int len; 2574 int len;
@@ -2389,10 +2583,157 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
2389 print_c_string ((" Save your buffers immediately" 2583 print_c_string ((" Save your buffers immediately"
2390 " and please report this bug>"), 2584 " and please report this bug>"),
2391 printcharfun); 2585 printcharfun);
2586 break;
2392 } 2587 }
2393 } 2588 }
2394
2395 print_depth--; 2589 print_depth--;
2590
2591 next_obj:
2592 if (prstack.sp > base_sp)
2593 {
2594 /* Handle a continuation on the print stack. */
2595 struct print_stack_entry *e = &prstack.stack[prstack.sp - 1];
2596 switch (e->type)
2597 {
2598 case PE_list:
2599 {
2600 /* after "(" ELEM (* " " ELEM) */
2601 Lisp_Object next = XCDR (e->u.list.last);
2602 if (NILP (next))
2603 {
2604 /* end of list: print ")" */
2605 printchar (')', printcharfun);
2606 --prstack.sp;
2607 --print_depth;
2608 goto next_obj;
2609 }
2610 else if (CONSP (next))
2611 {
2612 if (!NILP (Vprint_circle))
2613 {
2614 /* With the print-circle feature. */
2615 Lisp_Object num = Fgethash (next, Vprint_number_table,
2616 Qnil);
2617 if (FIXNUMP (num))
2618 {
2619 print_c_string (" . ", printcharfun);
2620 obj = next;
2621 e->type = PE_rbrac;
2622 goto print_obj;
2623 }
2624 }
2625
2626 /* list continues: print " " ELEM ... */
2627
2628 printchar (' ', printcharfun);
2629
2630 --e->u.list.maxlen;
2631 if (e->u.list.maxlen <= 0)
2632 {
2633 print_c_string ("...)", printcharfun);
2634 --prstack.sp;
2635 --print_depth;
2636 goto next_obj;
2637 }
2638
2639 e->u.list.last = next;
2640 e->u.list.n--;
2641 if (e->u.list.n == 0)
2642 {
2643 /* Double tortoise update period and teleport it. */
2644 e->u.list.tortoise_idx += e->u.list.m;
2645 e->u.list.m <<= 1;
2646 e->u.list.n = e->u.list.m;
2647 e->u.list.tortoise = next;
2648 }
2649 else if (BASE_EQ (next, e->u.list.tortoise))
2650 {
2651 /* FIXME: This #N tail index is somewhat ambiguous;
2652 see bug#55395. */
2653 int len = sprintf (buf, ". #%" PRIdMAX ")",
2654 e->u.list.tortoise_idx);
2655 strout (buf, len, len, printcharfun);
2656 --prstack.sp;
2657 --print_depth;
2658 goto next_obj;
2659 }
2660 obj = XCAR (next);
2661 }
2662 else
2663 {
2664 /* non-nil ending: print " . " ELEM ")" */
2665 print_c_string (" . ", printcharfun);
2666 obj = next;
2667 e->type = PE_rbrac;
2668 }
2669 break;
2670 }
2671
2672 case PE_rbrac:
2673 printchar (')', printcharfun);
2674 --prstack.sp;
2675 --print_depth;
2676 goto next_obj;
2677
2678 case PE_vector:
2679 if (e->u.vector.idx >= e->u.vector.size)
2680 {
2681 if (e->u.vector.truncated)
2682 {
2683 if (e->u.vector.idx > 0)
2684 printchar (' ', printcharfun);
2685 print_c_string ("...", printcharfun);
2686 }
2687 print_c_string (e->u.vector.end, printcharfun);
2688 --prstack.sp;
2689 --print_depth;
2690 goto next_obj;
2691 }
2692 if (e->u.vector.idx > 0)
2693 printchar (' ', printcharfun);
2694 obj = AREF (e->u.vector.obj, e->u.vector.idx);
2695 e->u.vector.idx++;
2696 break;
2697
2698 case PE_hash:
2699 if (e->u.hash.printed >= e->u.hash.nobjs)
2700 {
2701 if (e->u.hash.truncated)
2702 {
2703 if (e->u.hash.printed)
2704 printchar (' ', printcharfun);
2705 print_c_string ("...", printcharfun);
2706 }
2707 print_c_string ("))", printcharfun);
2708 --prstack.sp;
2709 --print_depth;
2710 goto next_obj;
2711 }
2712
2713 if (e->u.hash.printed)
2714 printchar (' ', printcharfun);
2715
2716 struct Lisp_Hash_Table *h = XHASH_TABLE (e->u.hash.obj);
2717 if ((e->u.hash.printed & 1) == 0)
2718 {
2719 Lisp_Object key;
2720 ptrdiff_t idx = e->u.hash.idx;
2721 while (BASE_EQ ((key = HASH_KEY (h, idx)), Qunbound))
2722 idx++;
2723 e->u.hash.idx = idx;
2724 obj = key;
2725 }
2726 else
2727 {
2728 obj = HASH_VALUE (h, e->u.hash.idx);
2729 e->u.hash.idx++;
2730 }
2731 e->u.hash.printed++;
2732 break;
2733 }
2734 goto print_obj;
2735 }
2736 eassert (print_depth == base_depth);
2396} 2737}
2397 2738
2398 2739
@@ -2602,4 +2943,7 @@ be printed. */);
2602 DEFSYM (Qprint_unreadable_function, "print-unreadable-function"); 2943 DEFSYM (Qprint_unreadable_function, "print-unreadable-function");
2603 2944
2604 defsubr (&Sflush_standard_output); 2945 defsubr (&Sflush_standard_output);
2946
2947 /* Initialized in print_create_variable_mapping. */
2948 staticpro (&Vprint_variable_mapping);
2605} 2949}
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)
1071 1071
1072} 1072}
1073 1073
1074DEFUN ("delete-process", Fdelete_process, Sdelete_process, 1, 1, 0, 1074DEFUN ("delete-process", Fdelete_process, Sdelete_process, 0, 1,
1075 "(list 'message)",
1075 doc: /* Delete PROCESS: kill it and forget about it immediately. 1076 doc: /* Delete PROCESS: kill it and forget about it immediately.
1076PROCESS may be a process, a buffer, the name of a process or buffer, or 1077PROCESS may be a process, a buffer, the name of a process or buffer, or
1077nil, indicating the current buffer's process. */) 1078nil, indicating the current buffer's process.
1079
1080Interactively, it will kill the current buffer's process. */)
1078 (register Lisp_Object process) 1081 (register Lisp_Object process)
1079{ 1082{
1080 register struct Lisp_Process *p; 1083 register struct Lisp_Process *p;
1084 bool mess = false;
1085
1086 /* We use this to see whether we were called interactively. */
1087 if (EQ (process, Qmessage))
1088 {
1089 mess = true;
1090 process = Qnil;
1091 }
1081 1092
1082 process = get_process (process); 1093 process = get_process (process);
1083 p = XPROCESS (process); 1094 p = XPROCESS (process);
@@ -1131,6 +1142,8 @@ nil, indicating the current buffer's process. */)
1131 } 1142 }
1132 } 1143 }
1133 remove_process (process); 1144 remove_process (process);
1145 if (mess)
1146 message ("Deleted process");
1134 return Qnil; 1147 return Qnil;
1135} 1148}
1136 1149
@@ -2132,6 +2145,10 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
2132 inchannel = p->open_fd[READ_FROM_SUBPROCESS]; 2145 inchannel = p->open_fd[READ_FROM_SUBPROCESS];
2133 forkout = p->open_fd[SUBPROCESS_STDOUT]; 2146 forkout = p->open_fd[SUBPROCESS_STDOUT];
2134 2147
2148#if defined(GNU_LINUX) && defined(F_SETPIPE_SZ)
2149 fcntl (inchannel, F_SETPIPE_SZ, read_process_output_max);
2150#endif
2151
2135 if (!NILP (p->stderrproc)) 2152 if (!NILP (p->stderrproc))
2136 { 2153 {
2137 struct Lisp_Process *pp = XPROCESS (p->stderrproc); 2154 struct Lisp_Process *pp = XPROCESS (p->stderrproc);
@@ -4766,7 +4783,7 @@ corresponding connection was closed. */)
4766 SDATA (proc->name), 4783 SDATA (proc->name),
4767 STRINGP (proc_thread_name) 4784 STRINGP (proc_thread_name)
4768 ? SDATA (proc_thread_name) 4785 ? SDATA (proc_thread_name)
4769 : SDATA (Fprin1_to_string (proc->thread, Qt))); 4786 : SDATA (Fprin1_to_string (proc->thread, Qt, Qnil)));
4770 } 4787 }
4771 } 4788 }
4772 else 4789 else
@@ -8618,7 +8635,10 @@ returns non-nil. */);
8618 DEFVAR_INT ("read-process-output-max", read_process_output_max, 8635 DEFVAR_INT ("read-process-output-max", read_process_output_max,
8619 doc: /* Maximum number of bytes to read from subprocess in a single chunk. 8636 doc: /* Maximum number of bytes to read from subprocess in a single chunk.
8620Enlarge the value only if the subprocess generates very large (megabytes) 8637Enlarge the value only if the subprocess generates very large (megabytes)
8621amounts of data in one go. */); 8638amounts of data in one go.
8639
8640On GNU/Linux systems, the value should not exceed
8641/proc/sys/fs/pipe-max-size. See pipe(7) manpage for details. */);
8622 read_process_output_max = 4096; 8642 read_process_output_max = 4096;
8623 8643
8624 DEFVAR_INT ("process-error-pause-time", process_error_pause_time, 8644 DEFVAR_INT ("process-error-pause-time", process_error_pause_time,
@@ -8637,6 +8657,7 @@ sentinel or a process filter function has an error. */);
8637 8657
8638 DEFSYM (Qnull, "null"); 8658 DEFSYM (Qnull, "null");
8639 DEFSYM (Qpipe_process_p, "pipe-process-p"); 8659 DEFSYM (Qpipe_process_p, "pipe-process-p");
8660 DEFSYM (Qmessage, "message");
8640 8661
8641 defsubr (&Sprocessp); 8662 defsubr (&Sprocessp);
8642 defsubr (&Sget_process); 8663 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)
132 XSET_HASH_TABLE (tmp, log); /* FIXME: Use make_lisp_ptr. */ 132 XSET_HASH_TABLE (tmp, log); /* FIXME: Use make_lisp_ptr. */
133 Fremhash (key, tmp); 133 Fremhash (key, tmp);
134 } 134 }
135 eassert (EQ (Qunbound, HASH_KEY (log, i))); 135 eassert (BASE_EQ (Qunbound, HASH_KEY (log, i)));
136 eassert (log->next_free == i); 136 eassert (log->next_free == i);
137 137
138 eassert (VECTORP (key)); 138 eassert (VECTORP (key));
@@ -158,7 +158,7 @@ record_backtrace (log_t *log, EMACS_INT count)
158 158
159 /* Get a "working memory" vector. */ 159 /* Get a "working memory" vector. */
160 Lisp_Object backtrace = HASH_VALUE (log, index); 160 Lisp_Object backtrace = HASH_VALUE (log, index);
161 eassert (EQ (Qunbound, HASH_KEY (log, index))); 161 eassert (BASE_EQ (Qunbound, HASH_KEY (log, index)));
162 get_backtrace (backtrace); 162 get_backtrace (backtrace);
163 163
164 { /* We basically do a `gethash+puthash' here, except that we have to be 164 { /* 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,
1244 return REG_ESIZE; \ 1244 return REG_ESIZE; \
1245 ptrdiff_t b_off = b - old_buffer; \ 1245 ptrdiff_t b_off = b - old_buffer; \
1246 ptrdiff_t begalt_off = begalt - old_buffer; \ 1246 ptrdiff_t begalt_off = begalt - old_buffer; \
1247 bool fixup_alt_jump_set = !!fixup_alt_jump; \ 1247 ptrdiff_t fixup_alt_jump_off = \
1248 bool laststart_set = !!laststart; \ 1248 fixup_alt_jump ? fixup_alt_jump - old_buffer : -1; \
1249 bool pending_exact_set = !!pending_exact; \ 1249 ptrdiff_t laststart_off = laststart ? laststart - old_buffer : -1; \
1250 ptrdiff_t fixup_alt_jump_off, laststart_off, pending_exact_off; \ 1250 ptrdiff_t pending_exact_off = \
1251 if (fixup_alt_jump_set) fixup_alt_jump_off = fixup_alt_jump - old_buffer; \ 1251 pending_exact ? pending_exact - old_buffer : -1; \
1252 if (laststart_set) laststart_off = laststart - old_buffer; \
1253 if (pending_exact_set) pending_exact_off = pending_exact - old_buffer; \
1254 bufp->buffer = xpalloc (bufp->buffer, &bufp->allocated, \ 1252 bufp->buffer = xpalloc (bufp->buffer, &bufp->allocated, \
1255 requested_extension, MAX_BUF_SIZE, 1); \ 1253 requested_extension, MAX_BUF_SIZE, 1); \
1256 unsigned char *new_buffer = bufp->buffer; \ 1254 unsigned char *new_buffer = bufp->buffer; \
1257 b = new_buffer + b_off; \ 1255 b = new_buffer + b_off; \
1258 begalt = new_buffer + begalt_off; \ 1256 begalt = new_buffer + begalt_off; \
1259 if (fixup_alt_jump_set) fixup_alt_jump = new_buffer + fixup_alt_jump_off; \ 1257 if (0 <= fixup_alt_jump_off) \
1260 if (laststart_set) laststart = new_buffer + laststart_off; \ 1258 fixup_alt_jump = new_buffer + fixup_alt_jump_off; \
1261 if (pending_exact_set) pending_exact = new_buffer + pending_exact_off; \ 1259 if (0 <= laststart_off) \
1260 laststart = new_buffer + laststart_off; \
1261 if (0 <= pending_exact_off) \
1262 pending_exact = new_buffer + pending_exact_off; \
1262 } while (false) 1263 } while (false)
1263 1264
1264 1265
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)
783} 783}
784 784
785 785
786/* Compute the "power" of the first of two adjacent runs begining at 786/* Compute the "power" of the first of two adjacent runs beginning at
787 index S1, with the first having length N1 and the second (starting 787 index S1, with the first having length N1 and the second (starting
788 at index S1+N1) having length N2. The run has total length N. */ 788 at index S1+N1) having length N2. The run has total length N. */
789 789
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/>. */
28#include <attribute.h> 28#include <attribute.h>
29#include <unlocked-io.h> 29#include <unlocked-io.h>
30 30
31extern FILE *emacs_fopen (char const *, char const *) ATTRIBUTE_MALLOC; 31extern FILE *emacs_fopen (char const *, char const *)
32 ATTRIBUTE_MALLOC ATTRIBUTE_DEALLOC (fclose, 1);
32extern void errputc (int); 33extern void errputc (int);
33extern void errwrite (void const *, ptrdiff_t); 34extern void errwrite (void const *, ptrdiff_t);
34extern void close_output_streams (void); 35extern 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. */)
2287 delete_keyboard_wait_descriptor (fileno (f)); 2287 delete_keyboard_wait_descriptor (fileno (f));
2288 2288
2289#ifndef MSDOS 2289#ifndef MSDOS
2290 fclose (f);
2291 if (f != t->display_info.tty->output) 2290 if (f != t->display_info.tty->output)
2292 fclose (t->display_info.tty->output); 2291 fclose (t->display_info.tty->output);
2292 fclose (f);
2293#endif 2293#endif
2294 2294
2295 t->display_info.tty->input = 0; 2295 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;
31 31
32INLINE_HEADER_BEGIN 32INLINE_HEADER_BEGIN
33 33
34enum scroll_bar_part { 34enum scroll_bar_part
35{
35 scroll_bar_nowhere, 36 scroll_bar_nowhere,
36 scroll_bar_above_handle, 37 scroll_bar_above_handle,
37 scroll_bar_handle, 38 scroll_bar_handle,
@@ -223,6 +224,11 @@ enum event_kind
223 gives the timestamp where the drop 224 gives the timestamp where the drop
224 happened. 225 happened.
225 226
227 .modifiers gives a number that
228 determines if an event was already
229 handled by
230 `x_dnd_begin_drag_and_drop'.
231
226 .x and .y give the coordinates of 232 .x and .y give the coordinates of
227 the drop originating from the root 233 the drop originating from the root
228 window. */ 234 window. */
@@ -296,8 +302,9 @@ enum event_kind
296#endif 302#endif
297 303
298#ifdef HAVE_XWIDGETS 304#ifdef HAVE_XWIDGETS
299 /* events generated by xwidgets*/ 305 /* An event generated by an xwidget to tell us something. */
300 , XWIDGET_EVENT 306 , XWIDGET_EVENT
307
301 /* Event generated when WebKit asks us to display another widget. */ 308 /* Event generated when WebKit asks us to display another widget. */
302 , XWIDGET_DISPLAY_EVENT 309 , XWIDGET_DISPLAY_EVENT
303#endif 310#endif
@@ -344,6 +351,11 @@ enum event_kind
344 positive delta represents a change clockwise, and a negative 351 positive delta represents a change clockwise, and a negative
345 delta represents a change counter-clockwise. */ 352 delta represents a change counter-clockwise. */
346 , PINCH_EVENT 353 , PINCH_EVENT
354
355 /* In a MONITORS_CHANGED_EVENT, .arg gives the terminal on which the
356 monitor configuration changed. .timestamp gives the time on
357 which the monitors changed. */
358 , MONITORS_CHANGED_EVENT
347}; 359};
348 360
349/* Bit width of an enum event_kind tag at the start of structs and unions. */ 361/* 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)
290 keyboard_coding = 290 keyboard_coding =
291 find_symbol_value (intern ("default-keyboard-coding-system")); 291 find_symbol_value (intern ("default-keyboard-coding-system"));
292 if (NILP (keyboard_coding) 292 if (NILP (keyboard_coding)
293 || EQ (keyboard_coding, Qunbound) 293 || BASE_EQ (keyboard_coding, Qunbound)
294 || NILP (Fcoding_system_p (keyboard_coding))) 294 || NILP (Fcoding_system_p (keyboard_coding)))
295 keyboard_coding = Qno_conversion; 295 keyboard_coding = Qno_conversion;
296 terminal_coding = 296 terminal_coding =
297 find_symbol_value (intern ("default-terminal-coding-system")); 297 find_symbol_value (intern ("default-terminal-coding-system"));
298 if (NILP (terminal_coding) 298 if (NILP (terminal_coding)
299 || EQ (terminal_coding, Qunbound) 299 || BASE_EQ (terminal_coding, Qunbound)
300 || NILP (Fcoding_system_p (terminal_coding))) 300 || NILP (Fcoding_system_p (terminal_coding)))
301 terminal_coding = Qundecided; 301 terminal_coding = Qundecided;
302 302
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)
341 for (sym = properties; 341 for (sym = properties;
342 PLIST_ELT_P (sym, value); 342 PLIST_ELT_P (sym, value);
343 sym = XCDR (value)) 343 sym = XCDR (value))
344 if (EQ (property_value (interval->plist, XCAR (sym)), Qunbound)) 344 if (BASE_EQ (property_value (interval->plist, XCAR (sym)), Qunbound))
345 { 345 {
346 record_property_change (interval->position, LENGTH (interval), 346 record_property_change (interval->position, LENGTH (interval),
347 XCAR (sym), Qnil, 347 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/>. */
20#ifndef EMACS_TPARAM_H 20#ifndef EMACS_TPARAM_H
21#define EMACS_TPARAM_H 21#define EMACS_TPARAM_H
22 22
23#include <stdlib.h>
24
23#include <attribute.h> 25#include <attribute.h>
24 26
25/* Don't try to include termcap.h. On some systems, configure finds a 27/* Don't try to include termcap.h. On some systems, configure finds a
@@ -32,7 +34,8 @@ int tgetnum (const char *);
32char *tgetstr (const char *, char **); 34char *tgetstr (const char *, char **);
33char *tgoto (const char *, int, int); 35char *tgoto (const char *, int, int);
34 36
35char *tparam (const char *, char *, int, int, int, int, int) ATTRIBUTE_MALLOC; 37char *tparam (const char *, char *, int, int, int, int, int)
38 ATTRIBUTE_MALLOC ATTRIBUTE_DEALLOC_FREE;
36 39
37extern char PC; 40extern char PC;
38extern char *BC; 41extern 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)
10297 openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0, 0); 10297 openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0, 0);
10298 if (fd < 0) 10298 if (fd < 0)
10299 { 10299 {
10300 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil); 10300 Lisp_Object load_path_print = Fprin1_to_string (Vload_path,
10301 Qnil, Qnil);
10301 char *init_file_name = SSDATA (init_file); 10302 char *init_file_name = SSDATA (init_file);
10302 char *load_path = SSDATA (load_path_print); 10303 char *load_path = SSDATA (load_path_print);
10303 char *buffer = alloca (1024 10304 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;
247 247
248static int w32_unicode_gui; 248static int w32_unicode_gui;
249 249
250static bool w32_selection_dialog_open;
251
250/* From w32menu.c */ 252/* From w32menu.c */
251int menubar_in_use = 0; 253int menubar_in_use = 0;
252 254
@@ -4184,6 +4186,16 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
4184 update_rect.left, update_rect.top, 4186 update_rect.left, update_rect.top,
4185 update_rect.right, update_rect.bottom)); 4187 update_rect.right, update_rect.bottom));
4186#endif 4188#endif
4189 /* Under double-buffering, update the frame from the back
4190 buffer, to prevent a "ghost" of the selection dialog to
4191 be left on display while the user selects in the dialog. */
4192 if (w32_selection_dialog_open
4193 && !w32_disable_double_buffering
4194 && FRAME_OUTPUT_DATA (f)->paint_dc)
4195 BitBlt (FRAME_OUTPUT_DATA (f)->paint_buffer_handle,
4196 0, 0, FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f),
4197 FRAME_OUTPUT_DATA (f)->paint_dc, 0, 0, SRCCOPY);
4198
4187 EndPaint (hwnd, &paintStruct); 4199 EndPaint (hwnd, &paintStruct);
4188 leave_crit (); 4200 leave_crit ();
4189 4201
@@ -5536,11 +5548,11 @@ my_create_window (struct frame * f)
5536 RES_TYPE_NUMBER); 5548 RES_TYPE_NUMBER);
5537 top = gui_display_get_arg (dpyinfo, Qnil, Qtop, "top", "Top", 5549 top = gui_display_get_arg (dpyinfo, Qnil, Qtop, "top", "Top",
5538 RES_TYPE_NUMBER); 5550 RES_TYPE_NUMBER);
5539 if (EQ (left, Qunbound)) 5551 if (BASE_EQ (left, Qunbound))
5540 coords[0] = CW_USEDEFAULT; 5552 coords[0] = CW_USEDEFAULT;
5541 else 5553 else
5542 coords[0] = XFIXNUM (left); 5554 coords[0] = XFIXNUM (left);
5543 if (EQ (top, Qunbound)) 5555 if (BASE_EQ (top, Qunbound))
5544 coords[1] = CW_USEDEFAULT; 5556 coords[1] = CW_USEDEFAULT;
5545 else 5557 else
5546 coords[1] = XFIXNUM (top); 5558 coords[1] = XFIXNUM (top);
@@ -5656,12 +5668,12 @@ w32_icon (struct frame *f, Lisp_Object parms)
5656 RES_TYPE_NUMBER); 5668 RES_TYPE_NUMBER);
5657 icon_y = gui_display_get_arg (dpyinfo, parms, Qicon_top, 0, 0, 5669 icon_y = gui_display_get_arg (dpyinfo, parms, Qicon_top, 0, 0,
5658 RES_TYPE_NUMBER); 5670 RES_TYPE_NUMBER);
5659 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound)) 5671 if (!BASE_EQ (icon_x, Qunbound) && !BASE_EQ (icon_y, Qunbound))
5660 { 5672 {
5661 CHECK_FIXNUM (icon_x); 5673 CHECK_FIXNUM (icon_x);
5662 CHECK_FIXNUM (icon_y); 5674 CHECK_FIXNUM (icon_y);
5663 } 5675 }
5664 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound)) 5676 else if (!BASE_EQ (icon_x, Qunbound) || !BASE_EQ (icon_y, Qunbound))
5665 error ("Both left and top icon corners of icon must be specified"); 5677 error ("Both left and top icon corners of icon must be specified");
5666 5678
5667 block_input (); 5679 block_input ();
@@ -5756,7 +5768,7 @@ w32_default_font_parameter (struct frame *f, Lisp_Object parms)
5756 parms, Qfont, NULL, NULL, 5768 parms, Qfont, NULL, NULL,
5757 RES_TYPE_STRING); 5769 RES_TYPE_STRING);
5758 Lisp_Object font; 5770 Lisp_Object font;
5759 if (EQ (font_param, Qunbound)) 5771 if (BASE_EQ (font_param, Qunbound))
5760 font_param = Qnil; 5772 font_param = Qnil;
5761 font = !NILP (font_param) ? font_param 5773 font = !NILP (font_param) ? font_param
5762 : gui_display_get_arg (dpyinfo, parms, Qfont, "font", "Font", 5774 : gui_display_get_arg (dpyinfo, parms, Qfont, "font", "Font",
@@ -5821,10 +5833,10 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5821 5833
5822 display = gui_display_get_arg (dpyinfo, parameters, Qterminal, 0, 0, 5834 display = gui_display_get_arg (dpyinfo, parameters, Qterminal, 0, 0,
5823 RES_TYPE_NUMBER); 5835 RES_TYPE_NUMBER);
5824 if (EQ (display, Qunbound)) 5836 if (BASE_EQ (display, Qunbound))
5825 display = gui_display_get_arg (dpyinfo, parameters, Qdisplay, 0, 0, 5837 display = gui_display_get_arg (dpyinfo, parameters, Qdisplay, 0, 0,
5826 RES_TYPE_STRING); 5838 RES_TYPE_STRING);
5827 if (EQ (display, Qunbound)) 5839 if (BASE_EQ (display, Qunbound))
5828 display = Qnil; 5840 display = Qnil;
5829 dpyinfo = check_x_display_info (display); 5841 dpyinfo = check_x_display_info (display);
5830 kb = dpyinfo->terminal->kboard; 5842 kb = dpyinfo->terminal->kboard;
@@ -5835,7 +5847,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5835 name = gui_display_get_arg (dpyinfo, parameters, Qname, "name", "Name", 5847 name = gui_display_get_arg (dpyinfo, parameters, Qname, "name", "Name",
5836 RES_TYPE_STRING); 5848 RES_TYPE_STRING);
5837 if (!STRINGP (name) 5849 if (!STRINGP (name)
5838 && ! EQ (name, Qunbound) 5850 && ! BASE_EQ (name, Qunbound)
5839 && ! NILP (name)) 5851 && ! NILP (name))
5840 error ("Invalid frame name--not a string or nil"); 5852 error ("Invalid frame name--not a string or nil");
5841 5853
@@ -5845,7 +5857,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5845 /* See if parent window is specified. */ 5857 /* See if parent window is specified. */
5846 parent = gui_display_get_arg (dpyinfo, parameters, Qparent_id, NULL, NULL, 5858 parent = gui_display_get_arg (dpyinfo, parameters, Qparent_id, NULL, NULL,
5847 RES_TYPE_NUMBER); 5859 RES_TYPE_NUMBER);
5848 if (EQ (parent, Qunbound)) 5860 if (BASE_EQ (parent, Qunbound))
5849 parent = Qnil; 5861 parent = Qnil;
5850 else if (!NILP (parent)) 5862 else if (!NILP (parent))
5851 CHECK_FIXNUM (parent); 5863 CHECK_FIXNUM (parent);
@@ -5888,14 +5900,14 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5888 5900
5889 tem = gui_display_get_arg (dpyinfo, parameters, Qundecorated, NULL, NULL, 5901 tem = gui_display_get_arg (dpyinfo, parameters, Qundecorated, NULL, NULL,
5890 RES_TYPE_BOOLEAN); 5902 RES_TYPE_BOOLEAN);
5891 FRAME_UNDECORATED (f) = !NILP (tem) && !EQ (tem, Qunbound); 5903 FRAME_UNDECORATED (f) = !NILP (tem) && !BASE_EQ (tem, Qunbound);
5892 store_frame_param (f, Qundecorated, FRAME_UNDECORATED (f) ? Qt : Qnil); 5904 store_frame_param (f, Qundecorated, FRAME_UNDECORATED (f) ? Qt : Qnil);
5893 5905
5894 tem = gui_display_get_arg (dpyinfo, parameters, Qskip_taskbar, NULL, NULL, 5906 tem = gui_display_get_arg (dpyinfo, parameters, Qskip_taskbar, NULL, NULL,
5895 RES_TYPE_BOOLEAN); 5907 RES_TYPE_BOOLEAN);
5896 FRAME_SKIP_TASKBAR (f) = !NILP (tem) && !EQ (tem, Qunbound); 5908 FRAME_SKIP_TASKBAR (f) = !NILP (tem) && !BASE_EQ (tem, Qunbound);
5897 store_frame_param (f, Qskip_taskbar, 5909 store_frame_param (f, Qskip_taskbar,
5898 (NILP (tem) || EQ (tem, Qunbound)) ? Qnil : Qt); 5910 (NILP (tem) || BASE_EQ (tem, Qunbound)) ? Qnil : Qt);
5899 5911
5900 /* By default, make scrollbars the system standard width and height. */ 5912 /* By default, make scrollbars the system standard width and height. */
5901 FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL); 5913 FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
@@ -5951,7 +5963,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5951 5963
5952 /* Set the name; the functions to which we pass f expect the name to 5964 /* Set the name; the functions to which we pass f expect the name to
5953 be set. */ 5965 be set. */
5954 if (EQ (name, Qunbound) || NILP (name)) 5966 if (BASE_EQ (name, Qunbound) || NILP (name))
5955 { 5967 {
5956 fset_name (f, build_string (dpyinfo->w32_id_name)); 5968 fset_name (f, build_string (dpyinfo->w32_id_name));
5957 f->explicit_name = false; 5969 f->explicit_name = false;
@@ -5991,7 +6003,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5991 value = gui_display_get_arg (dpyinfo, parameters, Qinternal_border_width, 6003 value = gui_display_get_arg (dpyinfo, parameters, Qinternal_border_width,
5992 "internalBorder", "internalBorder", 6004 "internalBorder", "internalBorder",
5993 RES_TYPE_NUMBER); 6005 RES_TYPE_NUMBER);
5994 if (! EQ (value, Qunbound)) 6006 if (! BASE_EQ (value, Qunbound))
5995 parameters = Fcons (Fcons (Qinternal_border_width, value), 6007 parameters = Fcons (Fcons (Qinternal_border_width, value),
5996 parameters); 6008 parameters);
5997 } 6009 }
@@ -6008,7 +6020,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
6008 value = gui_display_get_arg (dpyinfo, parameters, Qchild_frame_border_width, 6020 value = gui_display_get_arg (dpyinfo, parameters, Qchild_frame_border_width,
6009 "childFrameBorder", "childFrameBorder", 6021 "childFrameBorder", "childFrameBorder",
6010 RES_TYPE_NUMBER); 6022 RES_TYPE_NUMBER);
6011 if (!EQ (value, Qunbound)) 6023 if (!BASE_EQ (value, Qunbound))
6012 parameters = Fcons (Fcons (Qchild_frame_border_width, value), 6024 parameters = Fcons (Fcons (Qchild_frame_border_width, value),
6013 parameters); 6025 parameters);
6014 } 6026 }
@@ -6207,7 +6219,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
6207 w32_iconify_frame (f); 6219 w32_iconify_frame (f);
6208 else 6220 else
6209 { 6221 {
6210 if (EQ (visibility, Qunbound)) 6222 if (BASE_EQ (visibility, Qunbound))
6211 visibility = Qt; 6223 visibility = Qt;
6212 6224
6213 if (!NILP (visibility)) 6225 if (!NILP (visibility))
@@ -6999,7 +7011,7 @@ w32_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms)
6999 name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name", 7011 name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name",
7000 RES_TYPE_STRING); 7012 RES_TYPE_STRING);
7001 if (!STRINGP (name) 7013 if (!STRINGP (name)
7002 && !EQ (name, Qunbound) 7014 && !BASE_EQ (name, Qunbound)
7003 && !NILP (name)) 7015 && !NILP (name))
7004 error ("Invalid frame name--not a string or nil"); 7016 error ("Invalid frame name--not a string or nil");
7005 Vx_resource_name = name; 7017 Vx_resource_name = name;
@@ -7033,7 +7045,7 @@ w32_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms)
7033 7045
7034 /* Set the name; the functions to which we pass f expect the name to 7046 /* Set the name; the functions to which we pass f expect the name to
7035 be set. */ 7047 be set. */
7036 if (EQ (name, Qunbound) || NILP (name)) 7048 if (BASE_EQ (name, Qunbound) || NILP (name))
7037 { 7049 {
7038 fset_name (f, build_string (dpyinfo->w32_id_name)); 7050 fset_name (f, build_string (dpyinfo->w32_id_name));
7039 f->explicit_name = false; 7051 f->explicit_name = false;
@@ -7072,7 +7084,7 @@ w32_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms)
7072 value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width, 7084 value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width,
7073 "internalBorder", "internalBorder", 7085 "internalBorder", "internalBorder",
7074 RES_TYPE_NUMBER); 7086 RES_TYPE_NUMBER);
7075 if (! EQ (value, Qunbound)) 7087 if (! BASE_EQ (value, Qunbound))
7076 parms = Fcons (Fcons (Qinternal_border_width, value), 7088 parms = Fcons (Fcons (Qinternal_border_width, value),
7077 parms); 7089 parms);
7078 } 7090 }
@@ -7755,6 +7767,15 @@ w32_dialog_in_progress (Lisp_Object in_progress)
7755{ 7767{
7756 Lisp_Object frames, frame; 7768 Lisp_Object frames, frame;
7757 7769
7770 /* Indicate to w32_wnd_proc that the selection dialog is about to be
7771 open (or was closed, if IN_PROGRESS is nil). */
7772 if (!w32_disable_double_buffering)
7773 {
7774 enter_crit ();
7775 w32_selection_dialog_open = !NILP (in_progress);
7776 leave_crit ();
7777 }
7778
7758 /* Don't let frames in `above' z-group obscure dialog windows. */ 7779 /* Don't let frames in `above' z-group obscure dialog windows. */
7759 FOR_EACH_FRAME (frames, frame) 7780 FOR_EACH_FRAME (frames, frame)
7760 { 7781 {
@@ -10769,21 +10790,6 @@ bass-down, bass-boost, bass-up, treble-down, treble-up */);
10769 doc: /* SKIP: real doc in xfns.c. */); 10790 doc: /* SKIP: real doc in xfns.c. */);
10770 Vx_pixel_size_width_font_regexp = Qnil; 10791 Vx_pixel_size_width_font_regexp = Qnil;
10771 10792
10772 DEFVAR_LISP ("w32-bdf-filename-alist",
10773 Vw32_bdf_filename_alist,
10774 doc: /* List of bdf fonts and their corresponding filenames. */);
10775 Vw32_bdf_filename_alist = Qnil;
10776
10777 DEFVAR_BOOL ("w32-strict-fontnames",
10778 w32_strict_fontnames,
10779 doc: /* Non-nil means only use fonts that are exact matches for those requested.
10780Default is nil, which allows old fontnames that are not XLFD compliant,
10781and allows third-party CJK display to work by specifying false charset
10782fields to trick Emacs into translating to Big5, SJIS etc.
10783Setting this to t will prevent wrong fonts being selected when
10784fontsets are automatically created. */);
10785 w32_strict_fontnames = 0;
10786
10787 DEFVAR_BOOL ("w32-strict-painting", 10793 DEFVAR_BOOL ("w32-strict-painting",
10788 w32_strict_painting, 10794 w32_strict_painting,
10789 doc: /* Non-nil means use strict rules for repainting frames. 10795 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,
1540 || physical_font->ntmFontSig.fsUsb[1] 1540 || physical_font->ntmFontSig.fsUsb[1]
1541 || physical_font->ntmFontSig.fsUsb[0] & 0x3fffffff; 1541 || physical_font->ntmFontSig.fsUsb[0] & 0x3fffffff;
1542 1542
1543 /* Kludgey fix for Arial Unicode MS font that claims support for
1544 scripts it doesn't actually cover. */
1545 if (strncmp (logical_font->elfLogFont.lfFaceName,
1546 "Arial Unicode MS", 16) == 0)
1547 {
1548 /* Reset bits 4 (Phonetic), 12 (Vai), 14 (Nko), 27 (Balinese). */
1549 physical_font->ntmFontSig.fsUsb[0] &= 0xf7ffafef;
1550 /* Reset bits 53 (Phags-pa) and 58 (Phoenician). */
1551 physical_font->ntmFontSig.fsUsb[1] &= 0xfbdfffff;
1552 /* Set bit 70 (Tibetan). */
1553 physical_font->ntmFontSig.fsUsb[2] |= 0x00000040;
1554 }
1555
1543 /* Skip non matching fonts. */ 1556 /* Skip non matching fonts. */
1544 1557
1545 /* For uniscribe backend, consider only truetype or opentype fonts 1558 /* For uniscribe backend, consider only truetype or opentype fonts
@@ -2834,18 +2847,18 @@ syms_of_w32font (void)
2834 DEFSYM (Qhanunoo, "hanunoo"); 2847 DEFSYM (Qhanunoo, "hanunoo");
2835 DEFSYM (Qkharoshthi, "kharoshthi"); 2848 DEFSYM (Qkharoshthi, "kharoshthi");
2836 DEFSYM (Qlimbu, "limbu"); 2849 DEFSYM (Qlimbu, "limbu");
2837 DEFSYM (Qlinear_b, "linear_b"); 2850 DEFSYM (Qlinear_b, "linear-b");
2838 DEFSYM (Qaegean_number, "aegean-number"); 2851 DEFSYM (Qaegean_number, "aegean-number");
2839 DEFSYM (Qold_italic, "old_italic"); 2852 DEFSYM (Qold_italic, "old-italic");
2840 DEFSYM (Qold_persian, "old_persian"); 2853 DEFSYM (Qold_persian, "old-persian");
2841 DEFSYM (Qosmanya, "osmanya"); 2854 DEFSYM (Qosmanya, "osmanya");
2842 DEFSYM (Qphags_pa, "phags-pa"); 2855 DEFSYM (Qphags_pa, "phags-pa");
2843 DEFSYM (Qphoenician, "phoenician"); 2856 DEFSYM (Qphoenician, "phoenician");
2844 DEFSYM (Qshavian, "shavian"); 2857 DEFSYM (Qshavian, "shavian");
2845 DEFSYM (Qsyloti_nagri, "syloti_nagri"); 2858 DEFSYM (Qsyloti_nagri, "syloti-nagri");
2846 DEFSYM (Qtagalog, "tagalog"); 2859 DEFSYM (Qtagalog, "tagalog");
2847 DEFSYM (Qtagbanwa, "tagbanwa"); 2860 DEFSYM (Qtagbanwa, "tagbanwa");
2848 DEFSYM (Qtai_le, "tai_le"); 2861 DEFSYM (Qtai_le, "tai-le");
2849 DEFSYM (Qtifinagh, "tifinagh"); 2862 DEFSYM (Qtifinagh, "tifinagh");
2850 DEFSYM (Qugaritic, "ugaritic"); 2863 DEFSYM (Qugaritic, "ugaritic");
2851 DEFSYM (Qlycian, "lycian"); 2864 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,
556 HMENU menu; 556 HMENU menu;
557 POINT pos; 557 POINT pos;
558 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; 558 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
559 widget_value **submenu_stack 559 widget_value **submenu_stack;
560 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *)); 560 Lisp_Object *subprefix_stack;
561 Lisp_Object *subprefix_stack
562 = (Lisp_Object *) alloca (menu_items_used * word_size);
563 int submenu_depth = 0; 561 int submenu_depth = 0;
564 bool first_pane; 562 bool first_pane;
565 563
@@ -574,6 +572,11 @@ w32_menu_show (struct frame *f, int x, int y, int menuflags,
574 return Qnil; 572 return Qnil;
575 } 573 }
576 574
575 USE_SAFE_ALLOCA;
576
577 submenu_stack = SAFE_ALLOCA (menu_items_used * sizeof (widget_value *));
578 subprefix_stack = SAFE_ALLOCA (menu_items_used * word_size);
579
577 block_input (); 580 block_input ();
578 581
579 /* Create a tree of widget_value objects 582 /* Create a tree of widget_value objects
@@ -816,6 +819,7 @@ w32_menu_show (struct frame *f, int x, int y, int menuflags,
816 entry = Fcons (subprefix_stack[j], entry); 819 entry = Fcons (subprefix_stack[j], entry);
817 } 820 }
818 unblock_input (); 821 unblock_input ();
822 SAFE_FREE ();
819 return entry; 823 return entry;
820 } 824 }
821 i += MENU_ITEMS_ITEM_LENGTH; 825 i += MENU_ITEMS_ITEM_LENGTH;
@@ -830,6 +834,7 @@ w32_menu_show (struct frame *f, int x, int y, int menuflags,
830 } 834 }
831 835
832 unblock_input (); 836 unblock_input ();
837 SAFE_FREE ();
833 return Qnil; 838 return Qnil;
834} 839}
835 840
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.
519FILTER is a list of conditions for reporting an event. It can include 519FILTER is a list of conditions for reporting an event. It can include
520the following symbols: 520the following symbols:
521 521
522 'file-name' -- report file creation, deletion, or renaming 522 `file-name' -- report file creation, deletion, or renaming
523 'directory-name' -- report directory creation, deletion, or renaming 523 `directory-name' -- report directory creation, deletion, or renaming
524 'attributes' -- report changes in attributes 524 `attributes' -- report changes in attributes
525 'size' -- report changes in file-size 525 `size' -- report changes in file-size
526 'last-write-time' -- report changes in last-write time 526 `last-write-time' -- report changes in last-write time
527 'last-access-time' -- report changes in last-access time 527 `last-access-time' -- report changes in last-access time
528 'creation-time' -- report changes in creation time 528 `creation-time' -- report changes in creation time
529 'security-desc' -- report changes in security descriptor 529 `security-desc' -- report changes in security descriptor
530 530
531If FILE is a directory, and FILTER includes 'subtree', then all the 531If FILE is a directory, and FILTER includes `subtree', then all the
532subdirectories will also be watched and changes in them reported. 532subdirectories will also be watched and changes in them reported.
533 533
534When any event happens that satisfies the conditions specified by 534When 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.
541ACTION is the description of the event. It could be any one of the 541ACTION is the description of the event. It could be any one of the
542following: 542following:
543 543
544 'added' -- FILE was added 544 `added' -- FILE was added
545 'removed' -- FILE was deleted 545 `removed' -- FILE was deleted
546 'modified' -- FILE's contents or its attributes were modified 546 `modified' -- FILE's contents or its attributes were modified
547 'renamed-from' -- a file was renamed whose old name was FILE 547 `renamed-from' -- a file was renamed whose old name was FILE
548 'renamed-to' -- a file was renamed and its new name is FILE 548 `renamed-to' -- a file was renamed and its new name is FILE
549 549
550FILE is the name of the file whose event is being reported. 550FILE is the name of the file whose event is being reported.
551 551
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/>. */
63#include "w32term.h" 63#include "w32term.h"
64#include "coding.h" 64#include "coding.h"
65 65
66void w32_raise (int);
67
66#define RVA_TO_PTR(var,section,filedata) \ 68#define RVA_TO_PTR(var,section,filedata) \
67 ((void *)((section)->PointerToRawData \ 69 ((void *)((section)->PointerToRawData \
68 + ((DWORD_PTR)(var) - (section)->VirtualAddress) \ 70 + ((DWORD_PTR)(var) - (section)->VirtualAddress) \
@@ -311,6 +313,21 @@ sigismember (const sigset_t *set, int signo)
311 return (*set & (1U << signo)) != 0; 313 return (*set & (1U << signo)) != 0;
312} 314}
313 315
316/* A fuller emulation of 'raise', which supports signals that MS
317 runtime doesn't know about. */
318void
319w32_raise (int signo)
320{
321 if (!(signo == SIGCHLD || signo == SIGALRM || signo == SIGPROF))
322 raise (signo);
323
324 /* Call the handler directly for the signals that we handle
325 ourselves. */
326 signal_handler handler = sig_handlers[signo];
327 if (!(handler == SIG_DFL || handler == SIG_IGN || handler == SIG_ERR))
328 handler (signo);
329}
330
314pid_t 331pid_t
315getpgrp (void) 332getpgrp (void)
316{ 333{
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)
2682 val = (WINDOW_BUFFER_LOCAL_VALUE 2682 val = (WINDOW_BUFFER_LOCAL_VALUE
2683 (Qx_underline_at_descent_line, s->w)); 2683 (Qx_underline_at_descent_line, s->w));
2684 underline_at_descent_line 2684 underline_at_descent_line
2685 = (!(NILP (val) || EQ (val, Qunbound)) 2685 = (!(NILP (val) || BASE_EQ (val, Qunbound))
2686 || s->face->underline_at_descent_line_p); 2686 || s->face->underline_at_descent_line_p);
2687 2687
2688 val = (WINDOW_BUFFER_LOCAL_VALUE 2688 val = (WINDOW_BUFFER_LOCAL_VALUE
2689 (Qx_use_underline_position_properties, s->w)); 2689 (Qx_use_underline_position_properties, s->w));
2690 use_underline_position_properties 2690 use_underline_position_properties
2691 = !(NILP (val) || EQ (val, Qunbound)); 2691 = !(NILP (val) || BASE_EQ (val, Qunbound));
2692 2692
2693 /* Get the underline thickness. Default is 1 pixel. */ 2693 /* Get the underline thickness. Default is 1 pixel. */
2694 if (font && font->underline_thickness > 0) 2694 if (font && font->underline_thickness > 0)
@@ -2720,7 +2720,7 @@ w32_draw_glyph_string (struct glyph_string *s)
2720 2720
2721 if (!(s->face->underline_at_descent_line_p 2721 if (!(s->face->underline_at_descent_line_p
2722 /* Ignore minimum_offset if the amount of pixels 2722 /* Ignore minimum_offset if the amount of pixels
2723 was explictly specified. */ 2723 was explicitly specified. */
2724 && s->face->underline_pixels_above_descent_line)) 2724 && s->face->underline_pixels_above_descent_line))
2725 position = max (position, minimum_offset); 2725 position = max (position, minimum_offset);
2726 } 2726 }
@@ -5912,6 +5912,29 @@ w32_read_socket (struct terminal *terminal,
5912 (short) HIWORD (msg.msg.lParam))); 5912 (short) HIWORD (msg.msg.lParam)));
5913 } 5913 }
5914 5914
5915 /* According to the MS documentation, this message is sent
5916 to each window whenever a monitor is added, removed, or
5917 has its resolution change. Detect duplicate events when
5918 there are multiple frames by ensuring only one event is
5919 put in the keyboard buffer at any given time. */
5920 {
5921 union buffered_input_event *ev;
5922
5923 ev = (kbd_store_ptr == kbd_buffer
5924 ? kbd_buffer + KBD_BUFFER_SIZE - 1
5925 : kbd_store_ptr - 1);
5926
5927 if (kbd_store_ptr != kbd_fetch_ptr
5928 && ev->ie.kind == MONITORS_CHANGED_EVENT
5929 && XTERMINAL (ev->ie.arg) == dpyinfo->terminal)
5930 /* Don't store a MONITORS_CHANGED_EVENT if there is
5931 already an undelivered event on the queue. */
5932 break;
5933
5934 inev.kind = MONITORS_CHANGED_EVENT;
5935 XSETTERMINAL (inev.arg, dpyinfo->terminal);
5936 }
5937
5915 check_visibility = 1; 5938 check_visibility = 1;
5916 break; 5939 break;
5917 5940
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. */)
1014 return make_fixnum (decode_valid_window (window)->top_line); 1014 return make_fixnum (decode_valid_window (window)->top_line);
1015} 1015}
1016 1016
1017static enum window_body_unit
1018window_body_unit_from_symbol (Lisp_Object unit)
1019{
1020 return
1021 EQ (unit, Qremap)
1022 ? WINDOW_BODY_IN_REMAPPED_CHARS
1023 : (NILP (unit)
1024 ? WINDOW_BODY_IN_CANONICAL_CHARS
1025 : WINDOW_BODY_IN_PIXELS);
1026}
1027
1017/* Return the number of lines/pixels of W's body. Don't count any mode 1028/* Return the number of lines/pixels of W's body. Don't count any mode
1018 or header line or horizontal divider of W. Rounds down to nearest 1029 or header line or horizontal divider of W. Rounds down to nearest
1019 integer when not working pixelwise. */ 1030 integer when not working pixelwise. */
1020static int 1031static int
1021window_body_height (struct window *w, bool pixelwise) 1032window_body_height (struct window *w, enum window_body_unit pixelwise)
1022{ 1033{
1023 int height = (w->pixel_height 1034 int height = (w->pixel_height
1024 - WINDOW_TAB_LINE_HEIGHT (w) 1035 - WINDOW_TAB_LINE_HEIGHT (w)
@@ -1029,11 +1040,27 @@ window_body_height (struct window *w, bool pixelwise)
1029 - WINDOW_MODE_LINE_HEIGHT (w) 1040 - WINDOW_MODE_LINE_HEIGHT (w)
1030 - WINDOW_BOTTOM_DIVIDER_WIDTH (w)); 1041 - WINDOW_BOTTOM_DIVIDER_WIDTH (w));
1031 1042
1043 int denom = 1;
1044 if (pixelwise == WINDOW_BODY_IN_REMAPPED_CHARS)
1045 {
1046 if (!NILP (Vface_remapping_alist))
1047 {
1048 struct frame *f = XFRAME (WINDOW_FRAME (w));
1049 int face_id = lookup_named_face (NULL, f, Qdefault, true);
1050 struct face *face = FACE_FROM_ID_OR_NULL (f, face_id);
1051 if (face && face->font && face->font->height)
1052 denom = face->font->height;
1053 }
1054 /* For performance, use canonical chars if no face remapping. */
1055 else
1056 pixelwise = WINDOW_BODY_IN_CANONICAL_CHARS;
1057 }
1058
1059 if (pixelwise == WINDOW_BODY_IN_CANONICAL_CHARS)
1060 denom = FRAME_LINE_HEIGHT (WINDOW_XFRAME (w));
1061
1032 /* Don't return a negative value. */ 1062 /* Don't return a negative value. */
1033 return max (pixelwise 1063 return max (height / denom, 0);
1034 ? height
1035 : height / FRAME_LINE_HEIGHT (WINDOW_XFRAME (w)),
1036 0);
1037} 1064}
1038 1065
1039/* Return the number of columns/pixels of W's body. Don't count columns 1066/* 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)
1042 fringes either. Round down to nearest integer when not working 1069 fringes either. Round down to nearest integer when not working
1043 pixelwise. */ 1070 pixelwise. */
1044int 1071int
1045window_body_width (struct window *w, bool pixelwise) 1072window_body_width (struct window *w, enum window_body_unit pixelwise)
1046{ 1073{
1047 struct frame *f = XFRAME (WINDOW_FRAME (w)); 1074 struct frame *f = XFRAME (WINDOW_FRAME (w));
1048 1075
@@ -1059,50 +1086,76 @@ window_body_width (struct window *w, bool pixelwise)
1059 ? WINDOW_FRINGES_WIDTH (w) 1086 ? WINDOW_FRINGES_WIDTH (w)
1060 : 0)); 1087 : 0));
1061 1088
1089 int denom = 1;
1090 if (pixelwise == WINDOW_BODY_IN_REMAPPED_CHARS)
1091 {
1092 if (!NILP (Vface_remapping_alist))
1093 {
1094 int face_id = lookup_named_face (NULL, f, Qdefault, true);
1095 struct face *face = FACE_FROM_ID_OR_NULL (f, face_id);
1096 if (face && face->font)
1097 {
1098 if (face->font->average_width)
1099 denom = face->font->average_width;
1100 else if (face->font->space_width)
1101 denom = face->font->space_width;
1102 }
1103 }
1104 /* For performance, use canonical chars if no face remapping. */
1105 else
1106 pixelwise = WINDOW_BODY_IN_CANONICAL_CHARS;
1107 }
1108
1109 if (pixelwise == WINDOW_BODY_IN_CANONICAL_CHARS)
1110 denom = FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w));
1111
1062 /* Don't return a negative value. */ 1112 /* Don't return a negative value. */
1063 return max (pixelwise 1113 return max (width / denom, 0);
1064 ? width
1065 : width / FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w)),
1066 0);
1067} 1114}
1068 1115
1069DEFUN ("window-body-width", Fwindow_body_width, Swindow_body_width, 0, 2, 0, 1116DEFUN ("window-body-width", Fwindow_body_width, Swindow_body_width, 0, 2, 0,
1070 doc: /* Return the width of WINDOW's text area. 1117 doc: /* Return the width of WINDOW's text area.
1071WINDOW must be a live window and defaults to the selected one. Optional 1118WINDOW must be a live window and defaults to the selected one. The
1072argument PIXELWISE non-nil means return the width in pixels. The return 1119return value does not include any vertical dividers, fringes or
1073value does not include any vertical dividers, fringes or marginal areas, 1120marginal areas, or scroll bars.
1074or scroll bars.
1075 1121
1076If PIXELWISE is nil, return the largest integer smaller than WINDOW's 1122The optional argument PIXELWISE defines the units to use for the
1077pixel width divided by the character width of WINDOW's frame. This 1123width. If nil, return the largest integer smaller than WINDOW's pixel
1078means that if a column at the right of the text area is only partially 1124width in units of the character width of WINDOW's frame. If PIXELWISE
1079visible, that column is not counted. 1125is `remap' and the default face is remapped (see
1126`face-remapping-alist'), use the remapped face to determine the
1127character width. For any other non-nil value, return the width in
1128pixels.
1080 1129
1081Note that the returned value includes the column reserved for the 1130Note that the returned value includes the column reserved for the
1082continuation glyph. 1131continuation glyph.
1083 1132
1084Also see `window-max-characters-per-line'. */) 1133Also see `window-max-chars-per-line'. */)
1085 (Lisp_Object window, Lisp_Object pixelwise) 1134 (Lisp_Object window, Lisp_Object pixelwise)
1086{ 1135{
1087 return make_fixnum (window_body_width (decode_live_window (window), 1136 return (make_fixnum
1088 !NILP (pixelwise))); 1137 (window_body_width (decode_live_window (window),
1138 window_body_unit_from_symbol (pixelwise))));
1089} 1139}
1090 1140
1091DEFUN ("window-body-height", Fwindow_body_height, Swindow_body_height, 0, 2, 0, 1141DEFUN ("window-body-height", Fwindow_body_height, Swindow_body_height, 0, 2, 0,
1092 doc: /* Return the height of WINDOW's text area. 1142 doc: /* Return the height of WINDOW's text area.
1093WINDOW must be a live window and defaults to the selected one. Optional 1143WINDOW must be a live window and defaults to the selected one. The
1094argument PIXELWISE non-nil means return the height of WINDOW's text area 1144return value does not include the mode line or header line or any
1095in pixels. The return value does not include the mode line or header 1145horizontal divider.
1096line or any horizontal divider. 1146
1097 1147The optional argument PIXELWISE defines the units to use for the
1098If PIXELWISE is nil, return the largest integer smaller than WINDOW's 1148height. If nil, return the largest integer smaller than WINDOW's
1099pixel height divided by the character height of WINDOW's frame. This 1149pixel height in units of the character height of WINDOW's frame. If
1100means that if a line at the bottom of the text area is only partially 1150PIXELWISE is `remap' and the default face is remapped (see
1101visible, that line is not counted. */) 1151`face-remapping-alist'), use the remapped face to determine the
1152character height. For any other non-nil value, return the height in
1153pixels. */)
1102 (Lisp_Object window, Lisp_Object pixelwise) 1154 (Lisp_Object window, Lisp_Object pixelwise)
1103{ 1155{
1104 return make_fixnum (window_body_height (decode_live_window (window), 1156 return (make_fixnum
1105 !NILP (pixelwise))); 1157 (window_body_height (decode_live_window (window),
1158 window_body_unit_from_symbol (pixelwise))));
1106} 1159}
1107 1160
1108DEFUN ("window-old-body-pixel-width", 1161DEFUN ("window-old-body-pixel-width",
@@ -2124,7 +2177,8 @@ though when run from an idle timer with a delay of zero seconds. */)
2124 struct glyph_row *row, *end_row; 2177 struct glyph_row *row, *end_row;
2125 int max_y = NILP (body) ? WINDOW_PIXEL_HEIGHT (w) : window_text_bottom_y (w); 2178 int max_y = NILP (body) ? WINDOW_PIXEL_HEIGHT (w) : window_text_bottom_y (w);
2126 Lisp_Object rows = Qnil; 2179 Lisp_Object rows = Qnil;
2127 int window_width = NILP (body) ? w->pixel_width : window_body_width (w, true); 2180 int window_width = NILP (body)
2181 ? w->pixel_width : window_body_width (w, WINDOW_BODY_IN_PIXELS);
2128 int tab_line_height = WINDOW_TAB_LINE_HEIGHT (w); 2182 int tab_line_height = WINDOW_TAB_LINE_HEIGHT (w);
2129 int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w); 2183 int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2130 int subtract = NILP (body) ? 0 : (tab_line_height + header_line_height); 2184 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)
3657 wset_old_buffer (w, w->contents); 3711 wset_old_buffer (w, w->contents);
3658 w->old_pixel_width = w->pixel_width; 3712 w->old_pixel_width = w->pixel_width;
3659 w->old_pixel_height = w->pixel_height; 3713 w->old_pixel_height = w->pixel_height;
3660 w->old_body_pixel_width = window_body_width (w, true); 3714 w->old_body_pixel_width
3661 w->old_body_pixel_height = window_body_height (w, true); 3715 = window_body_width (w, WINDOW_BODY_IN_PIXELS);
3716 w->old_body_pixel_height
3717 = window_body_height (w, WINDOW_BODY_IN_PIXELS);
3662 } 3718 }
3663 3719
3664 w = NILP (w->next) ? 0 : XWINDOW (w->next); 3720 w = NILP (w->next) ? 0 : XWINDOW (w->next);
@@ -3903,8 +3959,10 @@ run_window_change_functions (void)
3903 && (window_buffer_change 3959 && (window_buffer_change
3904 || w->pixel_width != w->old_pixel_width 3960 || w->pixel_width != w->old_pixel_width
3905 || w->pixel_height != w->old_pixel_height 3961 || w->pixel_height != w->old_pixel_height
3906 || window_body_width (w, true) != w->old_body_pixel_width 3962 || (window_body_width (w, WINDOW_BODY_IN_PIXELS)
3907 || window_body_height (w, true) != w->old_body_pixel_height)); 3963 != w->old_body_pixel_width)
3964 || (window_body_height (w, WINDOW_BODY_IN_PIXELS)
3965 != w->old_body_pixel_height)));
3908 3966
3909 /* The following two are needed when running the default 3967 /* The following two are needed when running the default
3910 values for this frame below. */ 3968 values for this frame below. */
@@ -4768,7 +4826,8 @@ resize_frame_windows (struct frame *f, int size, bool horflag)
4768 Lisp_Object mini = f->minibuffer_window; 4826 Lisp_Object mini = f->minibuffer_window;
4769 struct window *m = WINDOWP (mini) ? XWINDOW (mini) : NULL; 4827 struct window *m = WINDOWP (mini) ? XWINDOW (mini) : NULL;
4770 int mini_height = ((FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f)) 4828 int mini_height = ((FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f))
4771 ? unit + m->pixel_height - window_body_height (m, true) 4829 ? (unit + m->pixel_height
4830 - window_body_height (m, WINDOW_BODY_IN_PIXELS))
4772 : 0); 4831 : 0);
4773 4832
4774 new_pixel_size = max (horflag ? size : size - mini_height, unit); 4833 new_pixel_size = max (horflag ? size : size - mini_height, unit);
@@ -5255,7 +5314,7 @@ void
5255grow_mini_window (struct window *w, int delta) 5314grow_mini_window (struct window *w, int delta)
5256{ 5315{
5257 struct frame *f = XFRAME (w->frame); 5316 struct frame *f = XFRAME (w->frame);
5258 int old_height = window_body_height (w, true); 5317 int old_height = window_body_height (w, WINDOW_BODY_IN_PIXELS);
5259 int min_height = FRAME_LINE_HEIGHT (f); 5318 int min_height = FRAME_LINE_HEIGHT (f);
5260 5319
5261 eassert (MINI_WINDOW_P (w)); 5320 eassert (MINI_WINDOW_P (w));
@@ -5289,7 +5348,8 @@ void
5289shrink_mini_window (struct window *w) 5348shrink_mini_window (struct window *w)
5290{ 5349{
5291 struct frame *f = XFRAME (w->frame); 5350 struct frame *f = XFRAME (w->frame);
5292 int delta = window_body_height (w, true) - FRAME_LINE_HEIGHT (f); 5351 int delta = (window_body_height (w, WINDOW_BODY_IN_PIXELS)
5352 - FRAME_LINE_HEIGHT (f));
5293 5353
5294 eassert (MINI_WINDOW_P (w)); 5354 eassert (MINI_WINDOW_P (w));
5295 5355
@@ -5636,7 +5696,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
5636 if (w->vscroll < 0 && rtop > 0) 5696 if (w->vscroll < 0 && rtop > 0)
5637 { 5697 {
5638 px = max (0, -w->vscroll - min (rtop, -dy)); 5698 px = max (0, -w->vscroll - min (rtop, -dy));
5639 Fset_window_vscroll (window, make_fixnum (px), Qt); 5699 Fset_window_vscroll (window, make_fixnum (px), Qt,
5700 Qnil);
5640 return; 5701 return;
5641 } 5702 }
5642 } 5703 }
@@ -5646,7 +5707,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
5646 if (rbot > 0 && (w->vscroll < 0 || vpos == 0)) 5707 if (rbot > 0 && (w->vscroll < 0 || vpos == 0))
5647 { 5708 {
5648 px = max (0, -w->vscroll + min (rbot, dy)); 5709 px = max (0, -w->vscroll + min (rbot, dy));
5649 Fset_window_vscroll (window, make_fixnum (px), Qt); 5710 Fset_window_vscroll (window, make_fixnum (px), Qt,
5711 Qnil);
5650 return; 5712 return;
5651 } 5713 }
5652 5714
@@ -5655,7 +5717,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
5655 { 5717 {
5656 ptrdiff_t spos; 5718 ptrdiff_t spos;
5657 5719
5658 Fset_window_vscroll (window, make_fixnum (0), Qt); 5720 Fset_window_vscroll (window, make_fixnum (0), Qt,
5721 Qnil);
5659 /* If there are other text lines above the current row, 5722 /* If there are other text lines above the current row,
5660 move window start to current row. Else to next row. */ 5723 move window start to current row. Else to next row. */
5661 if (rbot > 0) 5724 if (rbot > 0)
@@ -5674,7 +5737,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
5674 } 5737 }
5675 } 5738 }
5676 /* Cancel previous vscroll. */ 5739 /* Cancel previous vscroll. */
5677 Fset_window_vscroll (window, make_fixnum (0), Qt); 5740 Fset_window_vscroll (window, make_fixnum (0), Qt, Qnil);
5678 } 5741 }
5679 5742
5680 itdata = bidi_shelve_cache (); 5743 itdata = bidi_shelve_cache ();
@@ -6353,9 +6416,10 @@ by this function. This happens in an interactive call. */)
6353 (register Lisp_Object arg, Lisp_Object set_minimum) 6416 (register Lisp_Object arg, Lisp_Object set_minimum)
6354{ 6417{
6355 struct window *w = XWINDOW (selected_window); 6418 struct window *w = XWINDOW (selected_window);
6356 EMACS_INT requested_arg = (NILP (arg) 6419 EMACS_INT requested_arg =
6357 ? window_body_width (w, 0) - 2 6420 (NILP (arg)
6358 : XFIXNUM (Fprefix_numeric_value (arg))); 6421 ? window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS) - 2
6422 : XFIXNUM (Fprefix_numeric_value (arg)));
6359 Lisp_Object result = set_window_hscroll (w, w->hscroll + requested_arg); 6423 Lisp_Object result = set_window_hscroll (w, w->hscroll + requested_arg);
6360 6424
6361 if (!NILP (set_minimum)) 6425 if (!NILP (set_minimum))
@@ -6378,9 +6442,10 @@ by this function. This happens in an interactive call. */)
6378 (register Lisp_Object arg, Lisp_Object set_minimum) 6442 (register Lisp_Object arg, Lisp_Object set_minimum)
6379{ 6443{
6380 struct window *w = XWINDOW (selected_window); 6444 struct window *w = XWINDOW (selected_window);
6381 EMACS_INT requested_arg = (NILP (arg) 6445 EMACS_INT requested_arg =
6382 ? window_body_width (w, 0) - 2 6446 (NILP (arg)
6383 : XFIXNUM (Fprefix_numeric_value (arg))); 6447 ? window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS) - 2
6448 : XFIXNUM (Fprefix_numeric_value (arg)));
6384 Lisp_Object result = set_window_hscroll (w, w->hscroll - requested_arg); 6449 Lisp_Object result = set_window_hscroll (w, w->hscroll - requested_arg);
6385 6450
6386 if (!NILP (set_minimum)) 6451 if (!NILP (set_minimum))
@@ -7944,7 +8009,7 @@ optional second arg PIXELS-P means value is measured in pixels. */)
7944 8009
7945 8010
7946DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll, 8011DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
7947 2, 3, 0, 8012 2, 4, 0,
7948 doc: /* Set amount by which WINDOW should be scrolled vertically to VSCROLL. 8013 doc: /* Set amount by which WINDOW should be scrolled vertically to VSCROLL.
7949This takes effect when displaying tall lines or images. 8014This takes effect when displaying tall lines or images.
7950 8015
@@ -7954,8 +8019,12 @@ optional third arg PIXELS-P non-nil means that VSCROLL is in pixels.
7954If PIXELS-P is nil, VSCROLL may have to be rounded so that it 8019If PIXELS-P is nil, VSCROLL may have to be rounded so that it
7955corresponds to an integral number of pixels. The return value is the 8020corresponds to an integral number of pixels. The return value is the
7956result of this rounding. 8021result of this rounding.
7957If PIXELS-P is non-nil, the return value is VSCROLL. */) 8022If PIXELS-P is non-nil, the return value is VSCROLL.
7958 (Lisp_Object window, Lisp_Object vscroll, Lisp_Object pixels_p) 8023
8024PRESERVE-VSCROLL-P makes setting the start of WINDOW preserve the
8025vscroll if its start is "frozen" due to a resized mini-window. */)
8026 (Lisp_Object window, Lisp_Object vscroll, Lisp_Object pixels_p,
8027 Lisp_Object preserve_vscroll_p)
7959{ 8028{
7960 struct window *w = decode_live_window (window); 8029 struct window *w = decode_live_window (window);
7961 struct frame *f = XFRAME (w->frame); 8030 struct frame *f = XFRAME (w->frame);
@@ -7980,7 +8049,12 @@ If PIXELS-P is non-nil, the return value is VSCROLL. */)
7980 8049
7981 /* Prevent redisplay shortcuts. */ 8050 /* Prevent redisplay shortcuts. */
7982 XBUFFER (w->contents)->prevent_redisplay_optimizations_p = true; 8051 XBUFFER (w->contents)->prevent_redisplay_optimizations_p = true;
8052
8053 /* Mark W for redisplay. (bug#55299) */
8054 wset_redisplay (w);
7983 } 8055 }
8056
8057 w->preserve_vscroll_p = !NILP (preserve_vscroll_p);
7984 } 8058 }
7985 8059
7986 return Fwindow_vscroll (window, pixels_p); 8060 return Fwindow_vscroll (window, pixels_p);
@@ -8109,11 +8183,11 @@ compare_window_configurations (Lisp_Object configuration1,
8109 return true; 8183 return true;
8110} 8184}
8111 8185
8112DEFUN ("compare-window-configurations", Fcompare_window_configurations, 8186DEFUN ("window-configuration-equal-p", Fwindow_configuration_equal_p,
8113 Scompare_window_configurations, 2, 2, 0, 8187 Swindow_configuration_equal_p, 2, 2, 0,
8114 doc: /* Compare two window configurations as regards the structure of windows. 8188 doc: /* Say whether two window configurations have the same window layout.
8115This function ignores details such as the values of point 8189This function ignores details such as the values of point and
8116and scrolling positions. */) 8190scrolling positions. */)
8117 (Lisp_Object x, Lisp_Object y) 8191 (Lisp_Object x, Lisp_Object y)
8118{ 8192{
8119 if (compare_window_configurations (x, y)) 8193 if (compare_window_configurations (x, y))
@@ -8601,7 +8675,7 @@ displayed after a scrolling operation to be somewhat inaccurate. */);
8601 defsubr (&Swindow_scroll_bars); 8675 defsubr (&Swindow_scroll_bars);
8602 defsubr (&Swindow_vscroll); 8676 defsubr (&Swindow_vscroll);
8603 defsubr (&Sset_window_vscroll); 8677 defsubr (&Sset_window_vscroll);
8604 defsubr (&Scompare_window_configurations); 8678 defsubr (&Swindow_configuration_equal_p);
8605 defsubr (&Swindow_bump_use_time); 8679 defsubr (&Swindow_bump_use_time);
8606 defsubr (&Swindow_list); 8680 defsubr (&Swindow_list);
8607 defsubr (&Swindow_list_1); 8681 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
445 window. */ 445 window. */
446 bool_bf suspend_auto_hscroll : 1; 446 bool_bf suspend_auto_hscroll : 1;
447 447
448 /* True if vscroll should be preserved while forcing the start due
449 to a frozen window. */
450 bool_bf preserve_vscroll_p : 1;
451
448 /* Amount by which lines of this window are scrolled in 452 /* Amount by which lines of this window are scrolled in
449 y-direction (smooth scrolling). */ 453 y-direction (smooth scrolling). */
450 int vscroll; 454 int vscroll;
@@ -1182,7 +1186,13 @@ extern bool window_wants_mode_line (struct window *);
1182extern bool window_wants_header_line (struct window *); 1186extern bool window_wants_header_line (struct window *);
1183extern bool window_wants_tab_line (struct window *); 1187extern bool window_wants_tab_line (struct window *);
1184extern int window_internal_height (struct window *); 1188extern int window_internal_height (struct window *);
1185extern int window_body_width (struct window *w, bool); 1189enum window_body_unit
1190 {
1191 WINDOW_BODY_IN_CANONICAL_CHARS,
1192 WINDOW_BODY_IN_PIXELS,
1193 WINDOW_BODY_IN_REMAPPED_CHARS
1194 };
1195extern int window_body_width (struct window *w, enum window_body_unit);
1186enum margin_unit { MARGIN_IN_LINES, MARGIN_IN_PIXELS }; 1196enum margin_unit { MARGIN_IN_LINES, MARGIN_IN_PIXELS };
1187extern int window_scroll_margin (struct window *, enum margin_unit); 1197extern int window_scroll_margin (struct window *, enum margin_unit);
1188extern void temp_output_buffer_show (Lisp_Object); 1198extern 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,
5894 location = tem; 5894 location = tem;
5895 } 5895 }
5896 5896
5897 if (EQ (location, Qunbound)) 5897 if (BASE_EQ (location, Qunbound))
5898 { 5898 {
5899 location = Qnil; 5899 location = Qnil;
5900 value = spec; 5900 value = spec;
@@ -11234,7 +11234,7 @@ argument if the size of the buffer is large or unknown.
11234 11234
11235Optional argument MODE-LINES nil or omitted means do not include the 11235Optional argument MODE-LINES nil or omitted means do not include the
11236height of the mode-, tab- or header-line of WINDOW in the return value. 11236height of the mode-, tab- or header-line of WINDOW in the return value.
11237If it is the symbol `mode-line', 'tab-line' or `header-line', include 11237If it is the symbol `mode-line', `tab-line' or `header-line', include
11238only the height of that line, if present, in the return value. If t, 11238only the height of that line, if present, in the return value. If t,
11239include the height of any of these, if present, in the return value. 11239include the height of any of these, if present, in the return value.
11240 11240
@@ -13148,7 +13148,7 @@ store_mode_line_noprop (const char *string, int field_width, int precision)
13148 Vicon_title_format if FRAME is iconified, otherwise it is 13148 Vicon_title_format if FRAME is iconified, otherwise it is
13149 frame_title_format. */ 13149 frame_title_format. */
13150 13150
13151static void 13151void
13152gui_consider_frame_title (Lisp_Object frame) 13152gui_consider_frame_title (Lisp_Object frame)
13153{ 13153{
13154 struct frame *f = XFRAME (frame); 13154 struct frame *f = XFRAME (frame);
@@ -13200,8 +13200,9 @@ gui_consider_frame_title (Lisp_Object frame)
13200 mode_line_noprop_buf; then display the title. */ 13200 mode_line_noprop_buf; then display the title. */
13201 record_unwind_protect (unwind_format_mode_line, 13201 record_unwind_protect (unwind_format_mode_line,
13202 format_mode_line_unwind_data 13202 format_mode_line_unwind_data
13203 (NULL, current_buffer, Qnil, false)); 13203 (f, current_buffer, selected_window, false));
13204 13204
13205 Fselect_window (f->selected_window, Qt);
13205 set_buffer_internal_1 13206 set_buffer_internal_1
13206 (XBUFFER (XWINDOW (f->selected_window)->contents)); 13207 (XBUFFER (XWINDOW (f->selected_window)->contents));
13207 fmt = FRAME_ICONIFIED_P (f) ? Vicon_title_format : Vframe_title_format; 13208 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)
17006 17007
17007 w->window_end_valid = true; 17008 w->window_end_valid = true;
17008 w->update_mode_line = false; 17009 w->update_mode_line = false;
17010 w->preserve_vscroll_p = false;
17009 } 17011 }
17010 17012
17011 w->redisplay = !accurate_p; 17013 w->redisplay = !accurate_p;
@@ -17850,7 +17852,7 @@ cursor_row_fully_visible_p (struct window *w, bool force_p,
17850 buffer_local_value (Qmake_cursor_line_fully_visible, w->contents); 17852 buffer_local_value (Qmake_cursor_line_fully_visible, w->contents);
17851 17853
17852 /* If no local binding, use the global value. */ 17854 /* If no local binding, use the global value. */
17853 if (EQ (mclfv_p, Qunbound)) 17855 if (BASE_EQ (mclfv_p, Qunbound))
17854 mclfv_p = Vmake_cursor_line_fully_visible; 17856 mclfv_p = Vmake_cursor_line_fully_visible;
17855 /* Follow mode sets the variable to a Lisp function in buffers that 17857 /* Follow mode sets the variable to a Lisp function in buffers that
17856 are under Follow mode. */ 17858 are under Follow mode. */
@@ -19168,7 +19170,14 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
19168 int new_vpos = -1; 19170 int new_vpos = -1;
19169 19171
19170 w->force_start = false; 19172 w->force_start = false;
19171 w->vscroll = 0; 19173
19174 /* The vscroll should be preserved in this case, since
19175 `pixel-scroll-precision-mode' must continue working normally
19176 when a mini-window is resized. (bug#55312) */
19177 if (!w->preserve_vscroll_p || !window_frozen_p (w))
19178 w->vscroll = 0;
19179
19180 w->preserve_vscroll_p = false;
19172 w->window_end_valid = false; 19181 w->window_end_valid = false;
19173 19182
19174 /* Forget any recorded base line for line number display. */ 19183 /* Forget any recorded base line for line number display. */
@@ -22463,6 +22472,13 @@ compute_line_metrics (struct it *it)
22463} 22472}
22464 22473
22465 22474
22475static void
22476clear_position (struct it *it)
22477{
22478 it->position.charpos = 0;
22479 it->position.bytepos = 0;
22480}
22481
22466/* Append one space to the glyph row of iterator IT if doing a 22482/* Append one space to the glyph row of iterator IT if doing a
22467 window-based redisplay. The space has the same face as 22483 window-based redisplay. The space has the same face as
22468 IT->face_id. Value is true if a space was added. 22484 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)
22498 struct face *face; 22514 struct face *face;
22499 22515
22500 it->what = IT_CHARACTER; 22516 it->what = IT_CHARACTER;
22501 memset (&it->position, 0, sizeof it->position); 22517 clear_position (it);
22502 it->object = Qnil; 22518 it->object = Qnil;
22503 it->len = 1; 22519 it->len = 1;
22504 22520
@@ -22827,7 +22843,7 @@ extend_face_to_end_of_line (struct it *it)
22827 const int stretch_width = 22843 const int stretch_width =
22828 indicator_column - it->current_x - char_width; 22844 indicator_column - it->current_x - char_width;
22829 22845
22830 memset (&it->position, 0, sizeof it->position); 22846 clear_position (it);
22831 22847
22832 /* Only generate a stretch glyph if there is distance 22848 /* Only generate a stretch glyph if there is distance
22833 between current_x and the indicator position. */ 22849 between current_x and the indicator position. */
@@ -22861,7 +22877,7 @@ extend_face_to_end_of_line (struct it *it)
22861 22877
22862 if (stretch_width > 0) 22878 if (stretch_width > 0)
22863 { 22879 {
22864 memset (&it->position, 0, sizeof it->position); 22880 clear_position (it);
22865 append_stretch_glyph (it, Qnil, stretch_width, 22881 append_stretch_glyph (it, Qnil, stretch_width,
22866 it->ascent + it->descent, 22882 it->ascent + it->descent,
22867 stretch_ascent); 22883 stretch_ascent);
@@ -22911,7 +22927,7 @@ extend_face_to_end_of_line (struct it *it)
22911 (((it->ascent + it->descent) 22927 (((it->ascent + it->descent)
22912 * FONT_BASE (font)) / FONT_HEIGHT (font)); 22928 * FONT_BASE (font)) / FONT_HEIGHT (font));
22913 saved_pos = it->position; 22929 saved_pos = it->position;
22914 memset (&it->position, 0, sizeof it->position); 22930 clear_position (it);
22915 saved_avoid_cursor = it->avoid_cursor_p; 22931 saved_avoid_cursor = it->avoid_cursor_p;
22916 it->avoid_cursor_p = true; 22932 it->avoid_cursor_p = true;
22917 saved_face_id = it->face_id; 22933 saved_face_id = it->face_id;
@@ -22949,7 +22965,7 @@ extend_face_to_end_of_line (struct it *it)
22949 enum display_element_type saved_what = it->what; 22965 enum display_element_type saved_what = it->what;
22950 22966
22951 it->what = IT_CHARACTER; 22967 it->what = IT_CHARACTER;
22952 memset (&it->position, 0, sizeof it->position); 22968 clear_position (it);
22953 it->object = Qnil; 22969 it->object = Qnil;
22954 it->c = it->char_to_display = ' '; 22970 it->c = it->char_to_display = ' ';
22955 it->len = 1; 22971 it->len = 1;
@@ -28357,7 +28373,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
28357 } 28373 }
28358 28374
28359 prop = buffer_local_value (prop, it->w->contents); 28375 prop = buffer_local_value (prop, it->w->contents);
28360 if (EQ (prop, Qunbound)) 28376 if (BASE_EQ (prop, Qunbound))
28361 prop = Qnil; 28377 prop = Qnil;
28362 } 28378 }
28363 28379
@@ -28420,13 +28436,13 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
28420 } 28436 }
28421 28437
28422 car = buffer_local_value (car, it->w->contents); 28438 car = buffer_local_value (car, it->w->contents);
28423 if (EQ (car, Qunbound)) 28439 if (BASE_EQ (car, Qunbound))
28424 car = Qnil; 28440 car = Qnil;
28425 } 28441 }
28426 28442
28427 /* '(NUM)': absolute number of pixels. */ 28443 /* '(NUM)': absolute number of pixels. */
28428 if (NUMBERP (car)) 28444 if (NUMBERP (car))
28429{ 28445 {
28430 double fact; 28446 double fact;
28431 int offset = 28447 int offset =
28432 width_p && align_to && *align_to < 0 ? it->lnum_pixel_width : 0; 28448 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,
32015 32031
32016void 32032void
32017gui_clear_end_of_line (struct window *w, struct glyph_row *updated_row, 32033gui_clear_end_of_line (struct window *w, struct glyph_row *updated_row,
32018 enum glyph_row_area updated_area, int to_x) 32034 enum glyph_row_area updated_area, int to_x)
32019{ 32035{
32020 struct frame *f; 32036 struct frame *f;
32021 int max_x, min_y, max_y; 32037 int max_x, min_y, max_y;
32022 int from_x, from_y, to_y; 32038 int from_x, from_y, to_y;
32039 struct face *face;
32023 32040
32024 eassert (updated_row); 32041 eassert (updated_row);
32025 f = XFRAME (w->frame); 32042 f = XFRAME (w->frame);
32043 face = FACE_FROM_ID_OR_NULL (f, DEFAULT_FACE_ID);
32026 32044
32027 if (updated_row->full_width_p) 32045 if (updated_row->full_width_p)
32028 max_x = (WINDOW_PIXEL_WIDTH (w) 32046 max_x = (WINDOW_PIXEL_WIDTH (w)
@@ -32074,6 +32092,9 @@ gui_clear_end_of_line (struct window *w, struct glyph_row *updated_row,
32074 block_input (); 32092 block_input ();
32075 FRAME_RIF (f)->clear_frame_area (f, from_x, from_y, 32093 FRAME_RIF (f)->clear_frame_area (f, from_x, from_y,
32076 to_x - from_x, to_y - from_y); 32094 to_x - from_x, to_y - from_y);
32095
32096 if (face && !updated_row->stipple_p)
32097 updated_row->stipple_p = face->stipple;
32077 unblock_input (); 32098 unblock_input ();
32078 } 32099 }
32079} 32100}
@@ -32638,7 +32659,7 @@ display_and_set_cursor (struct window *w, bool on,
32638{ 32659{
32639 struct frame *f = XFRAME (w->frame); 32660 struct frame *f = XFRAME (w->frame);
32640 int new_cursor_type; 32661 int new_cursor_type;
32641 int new_cursor_width; 32662 int new_cursor_width UNINIT;
32642 bool active_cursor; 32663 bool active_cursor;
32643 struct glyph_row *glyph_row; 32664 struct glyph_row *glyph_row;
32644 struct glyph *glyph; 32665 struct glyph *glyph;
@@ -36229,7 +36250,7 @@ they return to their normal size when the minibuffer is closed, or the
36229echo area becomes empty. 36250echo area becomes empty.
36230 36251
36231This variable does not affect resizing of the minibuffer window of 36252This variable does not affect resizing of the minibuffer window of
36232minibuffer-only frames. These are handled by 'resize-mini-frames' 36253minibuffer-only frames. These are handled by `resize-mini-frames'
36233only. */); 36254only. */);
36234 /* Contrary to the doc string, we initialize this to nil, so that 36255 /* Contrary to the doc string, we initialize this to nil, so that
36235 loading loadup.el won't try to resize windows before loading 36256 loading loadup.el won't try to resize windows before loading
@@ -36453,7 +36474,7 @@ see biditest.el in the test suite. */);
36453 doc: /* Non-nil means inhibit the Bidirectional Parentheses Algorithm. 36474 doc: /* Non-nil means inhibit the Bidirectional Parentheses Algorithm.
36454Disabling the BPA makes redisplay faster, but might produce incorrect 36475Disabling the BPA makes redisplay faster, but might produce incorrect
36455display reordering of bidirectional text with embedded parentheses and 36476display reordering of bidirectional text with embedded parentheses and
36456other bracket characters whose 'paired-bracket' Unicode property is 36477other bracket characters whose `paired-bracket' Unicode property is
36457non-nil, see `get-char-code-property'. */); 36478non-nil, see `get-char-code-property'. */);
36458 bidi_inhibit_bpa = false; 36479 bidi_inhibit_bpa = false;
36459 36480
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,
6871 Initialization 6871 Initialization
6872 ***********************************************************************/ 6872 ***********************************************************************/
6873 6873
6874#ifdef HAVE_PDUMPER
6875/* All the faces defined during loadup are recorded in 6874/* All the faces defined during loadup are recorded in
6876 face-new-frame-defaults. We need to set next_lface_id to the next 6875 face-new-frame-defaults. We need to set next_lface_id to the next
6877 face ID number, so that any new faces defined in this session will 6876 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,
6881void 6880void
6882init_xfaces (void) 6881init_xfaces (void)
6883{ 6882{
6884 int nfaces = XFIXNAT (Fhash_table_count (Vface_new_frame_defaults)); 6883#ifdef HAVE_PDUMPER
6885 if (nfaces > 0) 6884 int nfaces;
6886 {
6887 /* Allocate the lface_id_to_name[] array. */
6888 lface_id_to_name_size = next_lface_id = nfaces;
6889 lface_id_to_name = xnmalloc (next_lface_id, sizeof *lface_id_to_name);
6890 6885
6891 /* Store the faces. */ 6886 if (dumped_with_pdumper_p ())
6892 struct Lisp_Hash_Table* table = XHASH_TABLE (Vface_new_frame_defaults); 6887 {
6893 for (ptrdiff_t idx = 0; idx < nfaces; ++idx) 6888 nfaces = XFIXNAT (Fhash_table_count (Vface_new_frame_defaults));
6889 if (nfaces > 0)
6894 { 6890 {
6895 Lisp_Object lface = HASH_KEY (table, idx); 6891 /* Allocate the lface_id_to_name[] array. */
6896 Lisp_Object face_id = CAR (HASH_VALUE (table, idx)); 6892 lface_id_to_name_size = next_lface_id = nfaces;
6897 if (FIXNATP (face_id)) { 6893 lface_id_to_name = xnmalloc (next_lface_id, sizeof *lface_id_to_name);
6898 int id = XFIXNAT (face_id); 6894
6899 eassert (id >= 0); 6895 /* Store the faces. */
6900 lface_id_to_name[id] = lface; 6896 struct Lisp_Hash_Table* table = XHASH_TABLE (Vface_new_frame_defaults);
6901 } 6897 for (ptrdiff_t idx = 0; idx < nfaces; ++idx)
6898 {
6899 Lisp_Object lface = HASH_KEY (table, idx);
6900 Lisp_Object face_id = CAR (HASH_VALUE (table, idx));
6901 if (FIXNATP (face_id))
6902 {
6903 int id = XFIXNAT (face_id);
6904 eassert (id >= 0);
6905 lface_id_to_name[id] = lface;
6906 }
6907 }
6902 } 6908 }
6903 } 6909 }
6910#endif
6911
6904 face_attr_sym[0] = Qface; 6912 face_attr_sym[0] = Qface;
6905 face_attr_sym[LFACE_FOUNDRY_INDEX] = QCfoundry; 6913 face_attr_sym[LFACE_FOUNDRY_INDEX] = QCfoundry;
6906 face_attr_sym[LFACE_SWIDTH_INDEX] = QCwidth; 6914 face_attr_sym[LFACE_SWIDTH_INDEX] = QCwidth;
@@ -6921,7 +6929,6 @@ init_xfaces (void)
6921 face_attr_sym[LFACE_DISTANT_FOREGROUND_INDEX] = QCdistant_foreground; 6929 face_attr_sym[LFACE_DISTANT_FOREGROUND_INDEX] = QCdistant_foreground;
6922 face_attr_sym[LFACE_EXTEND_INDEX] = QCextend; 6930 face_attr_sym[LFACE_EXTEND_INDEX] = QCextend;
6923} 6931}
6924#endif
6925 6932
6926void 6933void
6927syms_of_xfaces (void) 6934syms_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
973 if (p) 973 if (p)
974 { 974 {
975 window = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f)); 975 window = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f));
976 gdk_x11_window_set_frame_sync_enabled (window, false); 976 gdk_x11_window_set_frame_sync_enabled (window, FALSE);
977 } 977 }
978#endif 978#endif
979 unblock_input (); 979 unblock_input ();
@@ -1261,25 +1261,27 @@ struct mouse_cursor_types {
1261}; 1261};
1262 1262
1263/* This array must stay in sync with enum mouse_cursor above! */ 1263/* This array must stay in sync with enum mouse_cursor above! */
1264static const struct mouse_cursor_types mouse_cursor_types[] = { 1264static const struct mouse_cursor_types mouse_cursor_types[] =
1265 { "text", &Vx_pointer_shape, XC_xterm }, 1265 {
1266 { "nontext", &Vx_nontext_pointer_shape, XC_left_ptr }, 1266 { "text", &Vx_pointer_shape, XC_xterm },
1267 { "hourglass", &Vx_hourglass_pointer_shape, XC_watch }, 1267 { "nontext", &Vx_nontext_pointer_shape, XC_left_ptr },
1268 { "modeline", &Vx_mode_pointer_shape, XC_xterm }, 1268 { "hourglass", &Vx_hourglass_pointer_shape, XC_watch },
1269 { NULL, &Vx_sensitive_text_pointer_shape, XC_hand2 }, 1269 { "modeline", &Vx_mode_pointer_shape, XC_xterm },
1270 { NULL, &Vx_window_horizontal_drag_shape, XC_sb_h_double_arrow }, 1270 { NULL, &Vx_sensitive_text_pointer_shape, XC_hand2 },
1271 { NULL, &Vx_window_vertical_drag_shape, XC_sb_v_double_arrow }, 1271 { NULL, &Vx_window_horizontal_drag_shape, XC_sb_h_double_arrow },
1272 { NULL, &Vx_window_left_edge_shape, XC_left_side }, 1272 { NULL, &Vx_window_vertical_drag_shape, XC_sb_v_double_arrow },
1273 { NULL, &Vx_window_top_left_corner_shape, XC_top_left_corner }, 1273 { NULL, &Vx_window_left_edge_shape, XC_left_side },
1274 { NULL, &Vx_window_top_edge_shape, XC_top_side }, 1274 { NULL, &Vx_window_top_left_corner_shape, XC_top_left_corner },
1275 { NULL, &Vx_window_top_right_corner_shape, XC_top_right_corner }, 1275 { NULL, &Vx_window_top_edge_shape, XC_top_side },
1276 { NULL, &Vx_window_right_edge_shape, XC_right_side }, 1276 { NULL, &Vx_window_top_right_corner_shape, XC_top_right_corner },
1277 { NULL, &Vx_window_bottom_right_corner_shape, XC_bottom_right_corner }, 1277 { NULL, &Vx_window_right_edge_shape, XC_right_side },
1278 { NULL, &Vx_window_bottom_edge_shape, XC_bottom_side }, 1278 { NULL, &Vx_window_bottom_right_corner_shape, XC_bottom_right_corner },
1279 { NULL, &Vx_window_bottom_left_corner_shape, XC_bottom_left_corner }, 1279 { NULL, &Vx_window_bottom_edge_shape, XC_bottom_side },
1280}; 1280 { NULL, &Vx_window_bottom_left_corner_shape, XC_bottom_left_corner },
1281 };
1281 1282
1282struct mouse_cursor_data { 1283struct mouse_cursor_data
1284{
1283 /* Last index for which XCreateFontCursor has been called, and thus 1285 /* Last index for which XCreateFontCursor has been called, and thus
1284 the last index for which x_request_serial[] is valid. */ 1286 the last index for which x_request_serial[] is valid. */
1285 int last_cursor_create_request; 1287 int last_cursor_create_request;
@@ -1360,8 +1362,10 @@ x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
1360 { 1362 {
1361 cursor_data.x_request_serial[i] = XNextRequest (dpy); 1363 cursor_data.x_request_serial[i] = XNextRequest (dpy);
1362 cursor_data.last_cursor_create_request = i; 1364 cursor_data.last_cursor_create_request = i;
1363 cursor_data.cursor[i] = XCreateFontCursor (dpy, 1365
1364 cursor_data.cursor_num[i]); 1366 cursor_data.cursor[i]
1367 = x_create_font_cursor (FRAME_DISPLAY_INFO (f),
1368 cursor_data.cursor_num[i]);
1365 } 1369 }
1366 1370
1367 /* Now sync up and process all received errors from cursor 1371 /* Now sync up and process all received errors from cursor
@@ -2372,6 +2376,63 @@ x_set_scroll_bar_default_height (struct frame *f)
2372#endif 2376#endif
2373} 2377}
2374 2378
2379static void
2380x_set_alpha (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
2381{
2382 double alpha = 1.0;
2383 double newval[2];
2384 int i;
2385 Lisp_Object item;
2386 bool alpha_identical_p;
2387
2388 alpha_identical_p = true;
2389
2390 for (i = 0; i < 2; i++)
2391 {
2392 newval[i] = 1.0;
2393 if (CONSP (arg))
2394 {
2395 item = CAR (arg);
2396 arg = CDR (arg);
2397
2398 alpha_identical_p = false;
2399 }
2400 else
2401 item = arg;
2402
2403 if (NILP (item))
2404 alpha = - 1.0;
2405 else if (FLOATP (item))
2406 {
2407 alpha = XFLOAT_DATA (item);
2408 if (! (0 <= alpha && alpha <= 1.0))
2409 args_out_of_range (make_float (0.0), make_float (1.0));
2410 }
2411 else if (FIXNUMP (item))
2412 {
2413 EMACS_INT ialpha = XFIXNUM (item);
2414 if (! (0 <= ialpha && ialpha <= 100))
2415 args_out_of_range (make_fixnum (0), make_fixnum (100));
2416 alpha = ialpha / 100.0;
2417 }
2418 else
2419 wrong_type_argument (Qnumberp, item);
2420 newval[i] = alpha;
2421 }
2422
2423 for (i = 0; i < 2; i++)
2424 f->alpha[i] = newval[i];
2425
2426 FRAME_X_OUTPUT (f)->alpha_identical_p = alpha_identical_p;
2427
2428 if (FRAME_TERMINAL (f)->set_frame_alpha_hook)
2429 {
2430 block_input ();
2431 FRAME_TERMINAL (f)->set_frame_alpha_hook (f);
2432 unblock_input ();
2433 }
2434}
2435
2375 2436
2376/* Record in frame F the specified or default value according to ALIST 2437/* Record in frame F the specified or default value according to ALIST
2377 of the parameter named PROP (a Lisp symbol). If no value is 2438 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,
2389 2450
2390 tem = gui_display_get_arg (dpyinfo, alist, prop, xprop, xclass, 2451 tem = gui_display_get_arg (dpyinfo, alist, prop, xprop, xclass,
2391 RES_TYPE_STRING); 2452 RES_TYPE_STRING);
2392 if (EQ (tem, Qunbound)) 2453 if (BASE_EQ (tem, Qunbound))
2393 { 2454 {
2394#ifdef USE_TOOLKIT_SCROLL_BARS 2455#ifdef USE_TOOLKIT_SCROLL_BARS
2395 2456
@@ -4163,12 +4224,12 @@ x_icon_verify (struct frame *f, Lisp_Object parms)
4163 icons in an icon window. */ 4224 icons in an icon window. */
4164 icon_x = gui_frame_get_and_record_arg (f, parms, Qicon_left, 0, 0, RES_TYPE_NUMBER); 4225 icon_x = gui_frame_get_and_record_arg (f, parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
4165 icon_y = gui_frame_get_and_record_arg (f, parms, Qicon_top, 0, 0, RES_TYPE_NUMBER); 4226 icon_y = gui_frame_get_and_record_arg (f, parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
4166 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound)) 4227 if (!BASE_EQ (icon_x, Qunbound) && !BASE_EQ (icon_y, Qunbound))
4167 { 4228 {
4168 CHECK_FIXNUM (icon_x); 4229 CHECK_FIXNUM (icon_x);
4169 CHECK_FIXNUM (icon_y); 4230 CHECK_FIXNUM (icon_y);
4170 } 4231 }
4171 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound)) 4232 else if (!BASE_EQ (icon_x, Qunbound) || !BASE_EQ (icon_y, Qunbound))
4172 error ("Both left and top icon corners of icon must be specified"); 4233 error ("Both left and top icon corners of icon must be specified");
4173} 4234}
4174 4235
@@ -4187,8 +4248,8 @@ x_icon (struct frame *f, Lisp_Object parms)
4187 = gui_frame_get_and_record_arg (f, parms, Qicon_top, 0, 0, RES_TYPE_NUMBER); 4248 = gui_frame_get_and_record_arg (f, parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
4188 int icon_xval, icon_yval; 4249 int icon_xval, icon_yval;
4189 4250
4190 bool xgiven = !EQ (icon_x, Qunbound); 4251 bool xgiven = !BASE_EQ (icon_x, Qunbound);
4191 bool ygiven = !EQ (icon_y, Qunbound); 4252 bool ygiven = !BASE_EQ (icon_y, Qunbound);
4192 if (xgiven != ygiven) 4253 if (xgiven != ygiven)
4193 error ("Both left and top icon corners of icon must be specified"); 4254 error ("Both left and top icon corners of icon must be specified");
4194 if (xgiven) 4255 if (xgiven)
@@ -4373,7 +4434,7 @@ x_default_font_parameter (struct frame *f, Lisp_Object parms)
4373 Lisp_Object font_param = gui_display_get_arg (dpyinfo, parms, Qfont, NULL, NULL, 4434 Lisp_Object font_param = gui_display_get_arg (dpyinfo, parms, Qfont, NULL, NULL,
4374 RES_TYPE_STRING); 4435 RES_TYPE_STRING);
4375 Lisp_Object font = Qnil; 4436 Lisp_Object font = Qnil;
4376 if (EQ (font_param, Qunbound)) 4437 if (BASE_EQ (font_param, Qunbound))
4377 font_param = Qnil; 4438 font_param = Qnil;
4378 4439
4379 if (NILP (font_param)) 4440 if (NILP (font_param))
@@ -4490,6 +4551,9 @@ This function is an internal primitive--use `make-frame' instead. */)
4490 struct x_display_info *dpyinfo = NULL; 4551 struct x_display_info *dpyinfo = NULL;
4491 Lisp_Object parent, parent_frame; 4552 Lisp_Object parent, parent_frame;
4492 struct kboard *kb; 4553 struct kboard *kb;
4554#ifdef HAVE_GTK3
4555 GdkWindow *gwin;
4556#endif
4493 4557
4494 parms = Fcopy_alist (parms); 4558 parms = Fcopy_alist (parms);
4495 4559
@@ -4499,10 +4563,10 @@ This function is an internal primitive--use `make-frame' instead. */)
4499 4563
4500 display = gui_display_get_arg (dpyinfo, parms, Qterminal, 0, 0, 4564 display = gui_display_get_arg (dpyinfo, parms, Qterminal, 0, 0,
4501 RES_TYPE_NUMBER); 4565 RES_TYPE_NUMBER);
4502 if (EQ (display, Qunbound)) 4566 if (BASE_EQ (display, Qunbound))
4503 display = gui_display_get_arg (dpyinfo, parms, Qdisplay, 0, 0, 4567 display = gui_display_get_arg (dpyinfo, parms, Qdisplay, 0, 0,
4504 RES_TYPE_STRING); 4568 RES_TYPE_STRING);
4505 if (EQ (display, Qunbound)) 4569 if (BASE_EQ (display, Qunbound))
4506 display = Qnil; 4570 display = Qnil;
4507 dpyinfo = check_x_display_info (display); 4571 dpyinfo = check_x_display_info (display);
4508 kb = dpyinfo->terminal->kboard; 4572 kb = dpyinfo->terminal->kboard;
@@ -4513,7 +4577,7 @@ This function is an internal primitive--use `make-frame' instead. */)
4513 name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name", 4577 name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name",
4514 RES_TYPE_STRING); 4578 RES_TYPE_STRING);
4515 if (!STRINGP (name) 4579 if (!STRINGP (name)
4516 && ! EQ (name, Qunbound) 4580 && ! BASE_EQ (name, Qunbound)
4517 && ! NILP (name)) 4581 && ! NILP (name))
4518 error ("Invalid frame name--not a string or nil"); 4582 error ("Invalid frame name--not a string or nil");
4519 4583
@@ -4523,7 +4587,7 @@ This function is an internal primitive--use `make-frame' instead. */)
4523 /* See if parent window is specified. */ 4587 /* See if parent window is specified. */
4524 parent = gui_display_get_arg (dpyinfo, parms, Qparent_id, NULL, NULL, 4588 parent = gui_display_get_arg (dpyinfo, parms, Qparent_id, NULL, NULL,
4525 RES_TYPE_NUMBER); 4589 RES_TYPE_NUMBER);
4526 if (EQ (parent, Qunbound)) 4590 if (BASE_EQ (parent, Qunbound))
4527 parent = Qnil; 4591 parent = Qnil;
4528 if (! NILP (parent)) 4592 if (! NILP (parent))
4529 CHECK_FIXNUM (parent); 4593 CHECK_FIXNUM (parent);
@@ -4552,7 +4616,7 @@ This function is an internal primitive--use `make-frame' instead. */)
4552 RES_TYPE_SYMBOL); 4616 RES_TYPE_SYMBOL);
4553 /* Accept parent-frame iff parent-id was not specified. */ 4617 /* Accept parent-frame iff parent-id was not specified. */
4554 if (!NILP (parent) 4618 if (!NILP (parent)
4555 || EQ (parent_frame, Qunbound) 4619 || BASE_EQ (parent_frame, Qunbound)
4556 || NILP (parent_frame) 4620 || NILP (parent_frame)
4557 || !FRAMEP (parent_frame) 4621 || !FRAMEP (parent_frame)
4558 || !FRAME_LIVE_P (XFRAME (parent_frame)) 4622 || !FRAME_LIVE_P (XFRAME (parent_frame))
@@ -4568,7 +4632,7 @@ This function is an internal primitive--use `make-frame' instead. */)
4568 NULL, 4632 NULL,
4569 NULL, 4633 NULL,
4570 RES_TYPE_BOOLEAN))) 4634 RES_TYPE_BOOLEAN)))
4571 && !(EQ (tem, Qunbound))) 4635 && !(BASE_EQ (tem, Qunbound)))
4572 undecorated = true; 4636 undecorated = true;
4573 4637
4574 FRAME_UNDECORATED (f) = undecorated; 4638 FRAME_UNDECORATED (f) = undecorated;
@@ -4580,7 +4644,7 @@ This function is an internal primitive--use `make-frame' instead. */)
4580 NULL, 4644 NULL,
4581 NULL, 4645 NULL,
4582 RES_TYPE_BOOLEAN))) 4646 RES_TYPE_BOOLEAN)))
4583 && !(EQ (tem, Qunbound))) 4647 && !(BASE_EQ (tem, Qunbound)))
4584 override_redirect = true; 4648 override_redirect = true;
4585 4649
4586 FRAME_OVERRIDE_REDIRECT (f) = override_redirect; 4650 FRAME_OVERRIDE_REDIRECT (f) = override_redirect;
@@ -4661,7 +4725,7 @@ This function is an internal primitive--use `make-frame' instead. */)
4661 4725
4662 /* Set the name; the functions to which we pass f expect the name to 4726 /* Set the name; the functions to which we pass f expect the name to
4663 be set. */ 4727 be set. */
4664 if (EQ (name, Qunbound) || NILP (name)) 4728 if (BASE_EQ (name, Qunbound) || NILP (name))
4665 { 4729 {
4666 fset_name (f, build_string (dpyinfo->x_id_name)); 4730 fset_name (f, build_string (dpyinfo->x_id_name));
4667 f->explicit_name = false; 4731 f->explicit_name = false;
@@ -4724,7 +4788,7 @@ This function is an internal primitive--use `make-frame' instead. */)
4724 value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width, 4788 value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width,
4725 "internalBorder", "internalBorder", 4789 "internalBorder", "internalBorder",
4726 RES_TYPE_NUMBER); 4790 RES_TYPE_NUMBER);
4727 if (! EQ (value, Qunbound)) 4791 if (! BASE_EQ (value, Qunbound))
4728 parms = Fcons (Fcons (Qinternal_border_width, value), 4792 parms = Fcons (Fcons (Qinternal_border_width, value),
4729 parms); 4793 parms);
4730 } 4794 }
@@ -4746,7 +4810,7 @@ This function is an internal primitive--use `make-frame' instead. */)
4746 value = gui_display_get_arg (dpyinfo, parms, Qchild_frame_border_width, 4810 value = gui_display_get_arg (dpyinfo, parms, Qchild_frame_border_width,
4747 "childFrameBorder", "childFrameBorder", 4811 "childFrameBorder", "childFrameBorder",
4748 RES_TYPE_NUMBER); 4812 RES_TYPE_NUMBER);
4749 if (! EQ (value, Qunbound)) 4813 if (! BASE_EQ (value, Qunbound))
4750 parms = Fcons (Fcons (Qchild_frame_border_width, value), 4814 parms = Fcons (Fcons (Qchild_frame_border_width, value),
4751 parms); 4815 parms);
4752 } 4816 }
@@ -4917,6 +4981,10 @@ This function is an internal primitive--use `make-frame' instead. */)
4917 gtk_container_set_resize_mode 4981 gtk_container_set_resize_mode
4918 (GTK_CONTAINER (FRAME_GTK_OUTER_WIDGET (f)), GTK_RESIZE_IMMEDIATE); 4982 (GTK_CONTAINER (FRAME_GTK_OUTER_WIDGET (f)), GTK_RESIZE_IMMEDIATE);
4919#endif 4983#endif
4984#ifdef HAVE_GTK3
4985 gwin = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f));
4986 gdk_x11_window_set_frame_sync_enabled (gwin, FALSE);
4987#endif
4920 unblock_input (); 4988 unblock_input ();
4921 } 4989 }
4922 4990
@@ -4984,7 +5052,7 @@ This function is an internal primitive--use `make-frame' instead. */)
4984 } 5052 }
4985 else 5053 else
4986 { 5054 {
4987 if (EQ (visibility, Qunbound)) 5055 if (BASE_EQ (visibility, Qunbound))
4988 visibility = Qt; 5056 visibility = Qt;
4989 5057
4990 if (!NILP (visibility)) 5058 if (!NILP (visibility))
@@ -4998,7 +5066,7 @@ This function is an internal primitive--use `make-frame' instead. */)
4998 from `x-create-frame-with-faces' (see above comment). */ 5066 from `x-create-frame-with-faces' (see above comment). */
4999 f->was_invisible 5067 f->was_invisible
5000 = (f->was_invisible 5068 = (f->was_invisible
5001 && (!EQ (height, Qunbound) || !EQ (width, Qunbound))); 5069 && (!BASE_EQ (height, Qunbound) || !BASE_EQ (width, Qunbound)));
5002 5070
5003 store_frame_param (f, Qvisibility, visibility); 5071 store_frame_param (f, Qvisibility, visibility);
5004 } 5072 }
@@ -5366,6 +5434,9 @@ for each physical monitor, use `display-monitor-attributes-list'. */)
5366{ 5434{
5367 struct x_display_info *dpyinfo = check_x_display_info (terminal); 5435 struct x_display_info *dpyinfo = check_x_display_info (terminal);
5368 5436
5437 if (dpyinfo->screen_mm_height)
5438 return make_fixnum (dpyinfo->screen_mm_height);
5439
5369 return make_fixnum (HeightMMOfScreen (dpyinfo->screen)); 5440 return make_fixnum (HeightMMOfScreen (dpyinfo->screen));
5370} 5441}
5371 5442
@@ -5383,6 +5454,9 @@ for each physical monitor, use `display-monitor-attributes-list'. */)
5383{ 5454{
5384 struct x_display_info *dpyinfo = check_x_display_info (terminal); 5455 struct x_display_info *dpyinfo = check_x_display_info (terminal);
5385 5456
5457 if (dpyinfo->screen_mm_width)
5458 return make_fixnum (dpyinfo->screen_mm_width);
5459
5386 return make_fixnum (WidthMMOfScreen (dpyinfo->screen)); 5460 return make_fixnum (WidthMMOfScreen (dpyinfo->screen));
5387} 5461}
5388 5462
@@ -6526,17 +6600,61 @@ menu bar or tool bar of FRAME. */)
6526 * WINDOW to FRAMES and return FRAMES. 6600 * WINDOW to FRAMES and return FRAMES.
6527 */ 6601 */
6528static Lisp_Object 6602static Lisp_Object
6529x_frame_list_z_order (Display* dpy, Window window) 6603x_frame_list_z_order (struct x_display_info *dpyinfo, Window window)
6530{ 6604{
6605 Display *dpy;
6531 Window root, parent, *children; 6606 Window root, parent, *children;
6532 unsigned int nchildren; 6607 unsigned int nchildren;
6533 int i; 6608 unsigned long i;
6534 Lisp_Object frames = Qnil; 6609 Lisp_Object frames, val;
6610 Atom type;
6611 Window *toplevels;
6612 int format, rc;
6613 unsigned long nitems, bytes_after;
6614 unsigned char *data;
6615 struct frame *f;
6616
6617 dpy = dpyinfo->display;
6618 data = NULL;
6619 frames = Qnil;
6620
6621 if (window == dpyinfo->root_window
6622 && x_wm_supports_1 (dpyinfo,
6623 dpyinfo->Xatom_net_client_list_stacking))
6624 {
6625 rc = XGetWindowProperty (dpyinfo->display, dpyinfo->root_window,
6626 dpyinfo->Xatom_net_client_list_stacking,
6627 0, LONG_MAX, False, XA_WINDOW, &type,
6628 &format, &nitems, &bytes_after, &data);
6629
6630 if (rc != Success)
6631 return Qnil;
6632
6633 if (format != 32 || type != XA_WINDOW)
6634 {
6635 XFree (data);
6636 return Qnil;
6637 }
6638
6639 toplevels = (Window *) data;
6640
6641 for (i = 0; i < nitems; ++i)
6642 {
6643 f = x_top_window_to_frame (dpyinfo, toplevels[i]);
6644
6645 if (f)
6646 {
6647 XSETFRAME (val, f);
6648 frames = Fcons (val, frames);
6649 }
6650 }
6651
6652 XFree (data);
6653 return frames;
6654 }
6535 6655
6536 block_input ();
6537 if (XQueryTree (dpy, window, &root, &parent, &children, &nchildren)) 6656 if (XQueryTree (dpy, window, &root, &parent, &children, &nchildren))
6538 { 6657 {
6539 unblock_input ();
6540 for (i = 0; i < nchildren; i++) 6658 for (i = 0; i < nchildren; i++)
6541 { 6659 {
6542 Lisp_Object frame, tail; 6660 Lisp_Object frame, tail;
@@ -6554,10 +6672,9 @@ x_frame_list_z_order (Display* dpy, Window window)
6554 } 6672 }
6555 } 6673 }
6556 6674
6557 if (children) XFree ((char *)children); 6675 if (children)
6676 XFree (children);
6558 } 6677 }
6559 else
6560 unblock_input ();
6561 6678
6562 return frames; 6679 return frames;
6563} 6680}
@@ -6578,7 +6695,6 @@ Frames are listed from topmost (first) to bottommost (last). */)
6578 (Lisp_Object terminal) 6695 (Lisp_Object terminal)
6579{ 6696{
6580 struct x_display_info *dpyinfo = check_x_display_info (terminal); 6697 struct x_display_info *dpyinfo = check_x_display_info (terminal);
6581 Display *dpy = dpyinfo->display;
6582 Window window; 6698 Window window;
6583 6699
6584 if (FRAMEP (terminal) && FRAME_LIVE_P (XFRAME (terminal))) 6700 if (FRAMEP (terminal) && FRAME_LIVE_P (XFRAME (terminal)))
@@ -6586,7 +6702,7 @@ Frames are listed from topmost (first) to bottommost (last). */)
6586 else 6702 else
6587 window = dpyinfo->root_window; 6703 window = dpyinfo->root_window;
6588 6704
6589 return x_frame_list_z_order (dpy, window); 6705 return x_frame_list_z_order (dpyinfo, window);
6590} 6706}
6591 6707
6592/** 6708/**
@@ -6715,7 +6831,7 @@ The coordinates X and Y are interpreted in pixels relative to a position
6715 return Qnil; 6831 return Qnil;
6716} 6832}
6717 6833
6718DEFUN ("x-begin-drag", Fx_begin_drag, Sx_begin_drag, 1, 5, 0, 6834DEFUN ("x-begin-drag", Fx_begin_drag, Sx_begin_drag, 1, 6, 0,
6719 doc: /* Begin dragging contents on FRAME, with targets TARGETS. 6835 doc: /* Begin dragging contents on FRAME, with targets TARGETS.
6720TARGETS is a list of strings, which defines the X selection targets 6836TARGETS is a list of strings, which defines the X selection targets
6721that will be available to the drop target. Block until the mouse 6837that 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
6724starts when the mouse is pressed on FRAME, and the contents of the 6840starts when the mouse is pressed on FRAME, and the contents of the
6725selection `XdndSelection' will be sent to the X window underneath the 6841selection `XdndSelection' will be sent to the X window underneath the
6726mouse pointer (the drop target) when the mouse button is released. 6842mouse pointer (the drop target) when the mouse button is released.
6727ACTION is a symbol which tells the target what the source will do, and 6843
6728can be one of the following: 6844ACTION is a symbol which tells the target what it should do, and can
6845be one of the following:
6729 6846
6730 - `XdndActionCopy', which means to copy the contents from the drag 6847 - `XdndActionCopy', which means to copy the contents from the drag
6731 source (FRAME) to the drop target. 6848 source (FRAME) to the drop target.
@@ -6737,6 +6854,10 @@ can be one of the following:
6737`XdndActionPrivate' is also a valid return value, and means that the 6854`XdndActionPrivate' is also a valid return value, and means that the
6738drop target chose to perform an unspecified or unknown action. 6855drop target chose to perform an unspecified or unknown action.
6739 6856
6857The source is also expected to cooperate with the target to perform
6858the action chosen by the target. For example, callers should delete
6859the buffer text that was dragged if `XdndActionMove' is returned.
6860
6740There are also some other valid values of ACTION that depend on 6861There are also some other valid values of ACTION that depend on
6741details of both the drop target's implementation details and that of 6862details of both the drop target's implementation details and that of
6742Emacs. For that reason, they are not mentioned here. Consult 6863Emacs. For that reason, they are not mentioned here. Consult
@@ -6759,20 +6880,29 @@ instead.
6759 6880
6760If ALLOW-CURRENT-FRAME is not specified or nil, then the drop target 6881If ALLOW-CURRENT-FRAME is not specified or nil, then the drop target
6761is allowed to be FRAME. Otherwise, no action will be taken if the 6882is allowed to be FRAME. Otherwise, no action will be taken if the
6762mouse buttons are released on top of FRAME. */) 6883mouse buttons are released on top of FRAME.
6884
6885If FOLLOW-TOOLTIP is non-nil, any tooltip currently being displayed
6886will be moved to follow the mouse pointer while the drag is in
6887progress. Note that this does not work with system tooltips (tooltips
6888created when `use-system-tooltips' is non-nil).
6889
6890This function will sometimes return immediately if no mouse buttons
6891are currently held down. It should only be called when it is known
6892that mouse buttons are being held down, such as immediately after a
6893`down-mouse-1' (or similar) event. */)
6763 (Lisp_Object targets, Lisp_Object action, Lisp_Object frame, 6894 (Lisp_Object targets, Lisp_Object action, Lisp_Object frame,
6764 Lisp_Object return_frame, Lisp_Object allow_current_frame) 6895 Lisp_Object return_frame, Lisp_Object allow_current_frame,
6896 Lisp_Object follow_tooltip)
6765{ 6897{
6766 struct frame *f = decode_window_system_frame (frame); 6898 struct frame *f = decode_window_system_frame (frame);
6767 int ntargets = 0, nnames = 0; 6899 int ntargets = 0, nnames = 0;
6768 ptrdiff_t len;
6769 char *target_names[2048]; 6900 char *target_names[2048];
6770 Atom *target_atoms; 6901 Atom *target_atoms;
6771 Lisp_Object lval, original, tem, t1, t2; 6902 Lisp_Object lval, original, tem, t1, t2;
6772 Atom xaction; 6903 Atom xaction;
6773 Atom action_list[2048]; 6904 Atom action_list[2048];
6774 char *name_list[2048]; 6905 char *name_list[2048];
6775 char *scratch;
6776 6906
6777 USE_SAFE_ALLOCA; 6907 USE_SAFE_ALLOCA;
6778 6908
@@ -6786,10 +6916,8 @@ mouse buttons are released on top of FRAME. */)
6786 6916
6787 if (ntargets < 2048) 6917 if (ntargets < 2048)
6788 { 6918 {
6789 scratch = SSDATA (XCAR (targets)); 6919 SAFE_ALLOCA_STRING (target_names[ntargets],
6790 len = strlen (scratch); 6920 XCAR (targets));
6791 target_names[ntargets] = SAFE_ALLOCA (len + 1);
6792 strncpy (target_names[ntargets], scratch, len + 1);
6793 ntargets++; 6921 ntargets++;
6794 } 6922 }
6795 else 6923 else
@@ -6839,10 +6967,8 @@ mouse buttons are released on top of FRAME. */)
6839 else 6967 else
6840 signal_error ("Invalid drag-and-drop action", tem); 6968 signal_error ("Invalid drag-and-drop action", tem);
6841 6969
6842 scratch = SSDATA (ENCODE_UTF_8 (t2)); 6970 SAFE_ALLOCA_STRING (name_list[nnames],
6843 len = strlen (scratch); 6971 ENCODE_SYSTEM (t2));
6844 name_list[nnames] = SAFE_ALLOCA (len + 1);
6845 strncpy (name_list[nnames], scratch, len + 1);
6846 6972
6847 nnames++; 6973 nnames++;
6848 } 6974 }
@@ -6854,18 +6980,22 @@ mouse buttons are released on top of FRAME. */)
6854 else 6980 else
6855 signal_error ("Invalid drag-and-drop action", action); 6981 signal_error ("Invalid drag-and-drop action", action);
6856 6982
6857 target_atoms = xmalloc (ntargets * sizeof *target_atoms); 6983 target_atoms = SAFE_ALLOCA (ntargets * sizeof *target_atoms);
6858 6984
6859 block_input (); 6985 /* Catch errors since interning lots of targets can potentially
6986 generate a BadAlloc error. */
6987 x_catch_errors (FRAME_X_DISPLAY (f));
6860 XInternAtoms (FRAME_X_DISPLAY (f), target_names, 6988 XInternAtoms (FRAME_X_DISPLAY (f), target_names,
6861 ntargets, False, target_atoms); 6989 ntargets, False, target_atoms);
6862 unblock_input (); 6990 x_check_errors (FRAME_X_DISPLAY (f),
6991 "Failed to intern target atoms: %s");
6992 x_uncatch_errors_after_check ();
6863 6993
6864 x_set_dnd_targets (target_atoms, ntargets);
6865 lval = x_dnd_begin_drag_and_drop (f, FRAME_DISPLAY_INFO (f)->last_user_time, 6994 lval = x_dnd_begin_drag_and_drop (f, FRAME_DISPLAY_INFO (f)->last_user_time,
6866 xaction, return_frame, action_list, 6995 xaction, return_frame, action_list,
6867 (const char **) &name_list, nnames, 6996 (const char **) &name_list, nnames,
6868 !NILP (allow_current_frame)); 6997 !NILP (allow_current_frame), target_atoms,
6998 ntargets, original, !NILP (follow_tooltip));
6869 6999
6870 SAFE_FREE (); 7000 SAFE_FREE ();
6871 return lval; 7001 return lval;
@@ -7184,19 +7314,28 @@ converted to an atom and the value of the atom is used. If an element
7184is a cons, it is converted to a 32 bit number where the car is the 16 7314is a cons, it is converted to a 32 bit number where the car is the 16
7185top bits and the cdr is the lower 16 bits. 7315top bits and the cdr is the lower 16 bits.
7186 7316
7187FRAME nil or omitted means use the selected frame. 7317FRAME nil or omitted means use the selected frame. If TYPE is given
7188If TYPE is given and non-nil, it is the name of the type of VALUE. 7318and non-nil, it is the name of the type of VALUE. If TYPE is not
7189 If TYPE is not given or nil, the type is STRING. 7319given or nil, the type is STRING.
7190FORMAT gives the size in bits of each element if VALUE is a list. 7320
7191 It must be one of 8, 16 or 32. 7321FORMAT gives the size in bits of each element if VALUE is a list. It
7192 If VALUE is a string or FORMAT is nil or not given, FORMAT defaults to 8. 7322must be one of 8, 16 or 32.
7193If OUTER-P is non-nil, the property is changed for the outer X window of 7323
7194 FRAME. Default is to change on the edit X window. 7324If VALUE is a string or FORMAT is nil or not given, FORMAT defaults to
7195If WINDOW-ID is non-nil, change the property of that window instead 73258. If OUTER-P is non-nil, the property is changed for the outer X
7196 of FRAME's X window; the number 0 denotes the root window. This argument 7326window of FRAME. Default is to change on the edit X window.
7197 is separate from FRAME because window IDs are not unique across X 7327
7198 displays or screens on the same display, so FRAME provides context 7328If WINDOW-ID is non-nil, change the property of that window instead of
7199 for the window ID. */) 7329FRAME's X window; the number 0 denotes the root window. This argument
7330is separate from FRAME because window IDs are not unique across X
7331displays or screens on the same display, so FRAME provides context for
7332the window ID.
7333
7334If VALUE is a string and FORMAT is 32, then the format of VALUE is
7335system-specific. VALUE must contain unsigned integer data in native
7336endian-ness in multiples of the size of the C type 'long': the low 32
7337bits of each such number are used as the value of each element of the
7338property. */)
7200 (Lisp_Object prop, Lisp_Object value, Lisp_Object frame, 7339 (Lisp_Object prop, Lisp_Object value, Lisp_Object frame,
7201 Lisp_Object type, Lisp_Object format, Lisp_Object outer_p, 7340 Lisp_Object type, Lisp_Object format, Lisp_Object outer_p,
7202 Lisp_Object window_id) 7341 Lisp_Object window_id)
@@ -7209,6 +7348,8 @@ If WINDOW-ID is non-nil, change the property of that window instead
7209 int nelements; 7348 int nelements;
7210 Window target_window; 7349 Window target_window;
7211#ifdef USE_XCB 7350#ifdef USE_XCB
7351 bool intern_prop;
7352 bool intern_target;
7212 xcb_intern_atom_cookie_t prop_atom_cookie; 7353 xcb_intern_atom_cookie_t prop_atom_cookie;
7213 xcb_intern_atom_cookie_t target_type_cookie; 7354 xcb_intern_atom_cookie_t target_type_cookie;
7214 xcb_intern_atom_reply_t *reply; 7355 xcb_intern_atom_reply_t *reply;
@@ -7279,41 +7420,62 @@ If WINDOW-ID is non-nil, change the property of that window instead
7279 7420
7280 block_input (); 7421 block_input ();
7281#ifndef USE_XCB 7422#ifndef USE_XCB
7282 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SSDATA (prop), False); 7423 prop_atom = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
7424 SSDATA (prop), false);
7283 if (! NILP (type)) 7425 if (! NILP (type))
7284 { 7426 {
7285 CHECK_STRING (type); 7427 CHECK_STRING (type);
7286 target_type = XInternAtom (FRAME_X_DISPLAY (f), SSDATA (type), False); 7428 target_type = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
7429 SSDATA (type), false);
7287 } 7430 }
7288#else 7431#else
7289 rc = true; 7432 rc = true;
7290 prop_atom_cookie 7433 intern_target = true;
7291 = xcb_intern_atom (FRAME_DISPLAY_INFO (f)->xcb_connection, 7434 intern_prop = true;
7292 0, SBYTES (prop), SSDATA (prop)); 7435
7436 prop_atom = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
7437 SSDATA (prop), true);
7438
7439 if (prop_atom != None)
7440 intern_prop = false;
7441 else
7442 prop_atom_cookie
7443 = xcb_intern_atom (FRAME_DISPLAY_INFO (f)->xcb_connection,
7444 0, SBYTES (prop), SSDATA (prop));
7293 7445
7294 if (!NILP (type)) 7446 if (!NILP (type))
7295 { 7447 {
7296 CHECK_STRING (type); 7448 CHECK_STRING (type);
7297 target_type_cookie
7298 = xcb_intern_atom (FRAME_DISPLAY_INFO (f)->xcb_connection,
7299 0, SBYTES (type), SSDATA (type));
7300 }
7301 7449
7302 reply = xcb_intern_atom_reply (FRAME_DISPLAY_INFO (f)->xcb_connection, 7450 target_type = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
7303 prop_atom_cookie, &generic_error); 7451 SSDATA (type), true);
7304 7452
7305 if (reply) 7453 if (target_type)
7306 { 7454 intern_target = false;
7307 prop_atom = (Atom) reply->atom; 7455 else
7308 free (reply); 7456 target_type_cookie
7457 = xcb_intern_atom (FRAME_DISPLAY_INFO (f)->xcb_connection,
7458 0, SBYTES (type), SSDATA (type));
7309 } 7459 }
7310 else 7460
7461 if (intern_prop)
7311 { 7462 {
7312 free (generic_error); 7463 reply = xcb_intern_atom_reply (FRAME_DISPLAY_INFO (f)->xcb_connection,
7313 rc = false; 7464 prop_atom_cookie, &generic_error);
7465
7466 if (reply)
7467 {
7468 prop_atom = (Atom) reply->atom;
7469 free (reply);
7470 }
7471 else
7472 {
7473 free (generic_error);
7474 rc = false;
7475 }
7314 } 7476 }
7315 7477
7316 if (!NILP (type)) 7478 if (!NILP (type) && intern_target)
7317 { 7479 {
7318 reply = xcb_intern_atom_reply (FRAME_DISPLAY_INFO (f)->xcb_connection, 7480 reply = xcb_intern_atom_reply (FRAME_DISPLAY_INFO (f)->xcb_connection,
7319 target_type_cookie, &generic_error); 7481 target_type_cookie, &generic_error);
@@ -7334,16 +7496,17 @@ If WINDOW-ID is non-nil, change the property of that window instead
7334 error ("Failed to intern type or property atom"); 7496 error ("Failed to intern type or property atom");
7335#endif 7497#endif
7336 7498
7499 x_catch_errors (FRAME_X_DISPLAY (f));
7337 XChangeProperty (FRAME_X_DISPLAY (f), target_window, 7500 XChangeProperty (FRAME_X_DISPLAY (f), target_window,
7338 prop_atom, target_type, element_format, PropModeReplace, 7501 prop_atom, target_type, element_format, PropModeReplace,
7339 data, nelements); 7502 data, nelements);
7340 7503
7341 if (CONSP (value)) xfree (data); 7504 if (CONSP (value)) xfree (data);
7505 x_check_errors (FRAME_X_DISPLAY (f),
7506 "Couldn't change window property: %s");
7507 x_uncatch_errors_after_check ();
7342 7508
7343 /* Make sure the property is set when we return. */
7344 XFlush (FRAME_X_DISPLAY (f));
7345 unblock_input (); 7509 unblock_input ();
7346
7347 return value; 7510 return value;
7348} 7511}
7349 7512
@@ -7375,13 +7538,16 @@ Value is PROP. */)
7375 } 7538 }
7376 7539
7377 block_input (); 7540 block_input ();
7378 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SSDATA (prop), False); 7541 prop_atom = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
7542 SSDATA (prop), false);
7543
7544 x_catch_errors (FRAME_X_DISPLAY (f));
7379 XDeleteProperty (FRAME_X_DISPLAY (f), target_window, prop_atom); 7545 XDeleteProperty (FRAME_X_DISPLAY (f), target_window, prop_atom);
7546 x_check_errors (FRAME_X_DISPLAY (f),
7547 "Couldn't delete window property: %s");
7548 x_uncatch_errors_after_check ();
7380 7549
7381 /* Make sure the property is removed when we return. */
7382 XFlush (FRAME_X_DISPLAY (f));
7383 unblock_input (); 7550 unblock_input ();
7384
7385 return prop; 7551 return prop;
7386} 7552}
7387 7553
@@ -7501,15 +7667,19 @@ if PROP has no value of TYPE (always a string in the MS Windows case). */)
7501 } 7667 }
7502 7668
7503 block_input (); 7669 block_input ();
7670 x_catch_errors (FRAME_X_DISPLAY (f));
7671
7504 if (STRINGP (type)) 7672 if (STRINGP (type))
7505 { 7673 {
7506 if (strcmp ("AnyPropertyType", SSDATA (type)) == 0) 7674 if (strcmp ("AnyPropertyType", SSDATA (type)) == 0)
7507 target_type = AnyPropertyType; 7675 target_type = AnyPropertyType;
7508 else 7676 else
7509 target_type = XInternAtom (FRAME_X_DISPLAY (f), SSDATA (type), False); 7677 target_type = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
7678 SSDATA (type), false);
7510 } 7679 }
7511 7680
7512 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SSDATA (prop), False); 7681 prop_atom = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
7682 SSDATA (prop), false);
7513 prop_value = x_window_property_intern (f, 7683 prop_value = x_window_property_intern (f,
7514 target_window, 7684 target_window,
7515 prop_atom, 7685 prop_atom,
@@ -7531,6 +7701,9 @@ if PROP has no value of TYPE (always a string in the MS Windows case). */)
7531 &found); 7701 &found);
7532 } 7702 }
7533 7703
7704 x_check_errors (FRAME_X_DISPLAY (f),
7705 "Can't retrieve window property: %s");
7706 x_uncatch_errors_after_check ();
7534 7707
7535 unblock_input (); 7708 unblock_input ();
7536 return prop_value; 7709 return prop_value;
@@ -7576,7 +7749,9 @@ Otherwise, the return value is a vector with the following fields:
7576 7749
7577 block_input (); 7750 block_input ();
7578 7751
7579 prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SSDATA (prop), False); 7752 x_catch_errors (FRAME_X_DISPLAY (f));
7753 prop_atom = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
7754 SSDATA (prop), false);
7580 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), target_window, 7755 rc = XGetWindowProperty (FRAME_X_DISPLAY (f), target_window,
7581 prop_atom, 0, 0, False, AnyPropertyType, 7756 prop_atom, 0, 0, False, AnyPropertyType,
7582 &actual_type, &actual_format, &actual_size, 7757 &actual_type, &actual_format, &actual_size,
@@ -7606,6 +7781,10 @@ Otherwise, the return value is a vector with the following fields:
7606 make_fixnum (bytes_remaining / (actual_format >> 3))); 7781 make_fixnum (bytes_remaining / (actual_format >> 3)));
7607 } 7782 }
7608 7783
7784 x_check_errors (FRAME_X_DISPLAY (f),
7785 "Can't retrieve window property: %s");
7786 x_uncatch_errors_after_check ();
7787
7609 unblock_input (); 7788 unblock_input ();
7610 return prop_attr; 7789 return prop_attr;
7611} 7790}
@@ -7618,12 +7797,15 @@ static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object,
7618 Lisp_Object, int, int, int *, int *); 7797 Lisp_Object, int, int, int *, int *);
7619 7798
7620/* The frame of the currently visible tooltip, or nil if none. */ 7799/* The frame of the currently visible tooltip, or nil if none. */
7621static Lisp_Object tip_frame; 7800Lisp_Object tip_frame;
7622 7801
7623/* The window-system window corresponding to the frame of the 7802/* The window-system window corresponding to the frame of the
7624 currently visible tooltip. */ 7803 currently visible tooltip. */
7625Window tip_window; 7804Window tip_window;
7626 7805
7806/* The X and Y deltas of the last call to `x-show-tip'. */
7807Lisp_Object tip_dx, tip_dy;
7808
7627/* A timer that hides or deletes the currently visible tooltip when it 7809/* A timer that hides or deletes the currently visible tooltip when it
7628 fires. */ 7810 fires. */
7629static Lisp_Object tip_timer; 7811static Lisp_Object tip_timer;
@@ -7679,7 +7861,7 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms)
7679 name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name", 7861 name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name",
7680 RES_TYPE_STRING); 7862 RES_TYPE_STRING);
7681 if (!STRINGP (name) 7863 if (!STRINGP (name)
7682 && !EQ (name, Qunbound) 7864 && !BASE_EQ (name, Qunbound)
7683 && !NILP (name)) 7865 && !NILP (name))
7684 error ("Invalid frame name--not a string or nil"); 7866 error ("Invalid frame name--not a string or nil");
7685 7867
@@ -7746,7 +7928,7 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms)
7746 7928
7747 /* Set the name; the functions to which we pass f expect the name to 7929 /* Set the name; the functions to which we pass f expect the name to
7748 be set. */ 7930 be set. */
7749 if (EQ (name, Qunbound) || NILP (name)) 7931 if (BASE_EQ (name, Qunbound) || NILP (name))
7750 { 7932 {
7751 fset_name (f, build_string (dpyinfo->x_id_name)); 7933 fset_name (f, build_string (dpyinfo->x_id_name));
7752 f->explicit_name = false; 7934 f->explicit_name = false;
@@ -7802,7 +7984,7 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms)
7802 value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width, 7984 value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width,
7803 "internalBorder", "internalBorder", 7985 "internalBorder", "internalBorder",
7804 RES_TYPE_NUMBER); 7986 RES_TYPE_NUMBER);
7805 if (! EQ (value, Qunbound)) 7987 if (! BASE_EQ (value, Qunbound))
7806 parms = Fcons (Fcons (Qinternal_border_width, value), 7988 parms = Fcons (Fcons (Qinternal_border_width, value),
7807 parms); 7989 parms);
7808 } 7990 }
@@ -8029,9 +8211,9 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms)
8029 the display in *ROOT_X, and *ROOT_Y. */ 8211 the display in *ROOT_X, and *ROOT_Y. */
8030 8212
8031static void 8213static void
8032compute_tip_xy (struct frame *f, 8214compute_tip_xy (struct frame *f, Lisp_Object parms, Lisp_Object dx,
8033 Lisp_Object parms, Lisp_Object dx, Lisp_Object dy, 8215 Lisp_Object dy, int width, int height, int *root_x,
8034 int width, int height, int *root_x, int *root_y) 8216 int *root_y)
8035{ 8217{
8036 Lisp_Object left, top, right, bottom; 8218 Lisp_Object left, top, right, bottom;
8037 int win_x, win_y; 8219 int win_x, win_y;
@@ -8057,7 +8239,7 @@ compute_tip_xy (struct frame *f,
8057 &root, &child, root_x, root_y, &win_x, &win_y, &pmask); 8239 &root, &child, root_x, root_y, &win_x, &win_y, &pmask);
8058 unblock_input (); 8240 unblock_input ();
8059 8241
8060 XSETFRAME(frame, f); 8242 XSETFRAME (frame, f);
8061 attributes = Fx_display_monitor_attributes_list (frame); 8243 attributes = Fx_display_monitor_attributes_list (frame);
8062 8244
8063 /* Try to determine the monitor where the mouse pointer is and 8245 /* Try to determine the monitor where the mouse pointer is and
@@ -8072,11 +8254,13 @@ compute_tip_xy (struct frame *f,
8072 min_y = XFIXNUM (Fnth (make_fixnum (2), geometry)); 8254 min_y = XFIXNUM (Fnth (make_fixnum (2), geometry));
8073 max_x = min_x + XFIXNUM (Fnth (make_fixnum (3), geometry)); 8255 max_x = min_x + XFIXNUM (Fnth (make_fixnum (3), geometry));
8074 max_y = min_y + XFIXNUM (Fnth (make_fixnum (4), geometry)); 8256 max_y = min_y + XFIXNUM (Fnth (make_fixnum (4), geometry));
8257
8075 if (min_x <= *root_x && *root_x < max_x 8258 if (min_x <= *root_x && *root_x < max_x
8076 && min_y <= *root_y && *root_y < max_y) 8259 && min_y <= *root_y && *root_y < max_y)
8077 { 8260 {
8078 break; 8261 break;
8079 } 8262 }
8263
8080 max_y = -1; 8264 max_y = -1;
8081 } 8265 }
8082 8266
@@ -8086,7 +8270,7 @@ compute_tip_xy (struct frame *f,
8086 8270
8087 /* It was not possible to determine the monitor's geometry, so we 8271 /* It was not possible to determine the monitor's geometry, so we
8088 assign some sane defaults here: */ 8272 assign some sane defaults here: */
8089 if ( max_y < 0 ) 8273 if (max_y < 0)
8090 { 8274 {
8091 min_x = 0; 8275 min_x = 0;
8092 min_y = 0; 8276 min_y = 0;
@@ -8335,6 +8519,9 @@ Text larger than the specified size is clipped. */)
8335 else 8519 else
8336 CHECK_FIXNUM (dy); 8520 CHECK_FIXNUM (dy);
8337 8521
8522 tip_dx = dx;
8523 tip_dy = dy;
8524
8338#ifdef USE_GTK 8525#ifdef USE_GTK
8339 if (use_system_tooltips) 8526 if (use_system_tooltips)
8340 { 8527 {
@@ -8360,7 +8547,7 @@ Text larger than the specified size is clipped. */)
8360 if (!NILP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame))) 8547 if (!NILP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
8361 { 8548 {
8362 if (FRAME_VISIBLE_P (XFRAME (tip_frame)) 8549 if (FRAME_VISIBLE_P (XFRAME (tip_frame))
8363 && EQ (frame, tip_last_frame) 8550 && BASE_EQ (frame, tip_last_frame)
8364 && !NILP (Fequal_including_properties (tip_last_string, string)) 8551 && !NILP (Fequal_including_properties (tip_last_string, string))
8365 && !NILP (Fequal (tip_last_parms, parms))) 8552 && !NILP (Fequal (tip_last_parms, parms)))
8366 { 8553 {
@@ -8381,7 +8568,7 @@ Text larger than the specified size is clipped. */)
8381 8568
8382 goto start_timer; 8569 goto start_timer;
8383 } 8570 }
8384 else if (tooltip_reuse_hidden_frame && EQ (frame, tip_last_frame)) 8571 else if (tooltip_reuse_hidden_frame && BASE_EQ (frame, tip_last_frame))
8385 { 8572 {
8386 bool delete = false; 8573 bool delete = false;
8387 Lisp_Object tail, elt, parm, last; 8574 Lisp_Object tail, elt, parm, last;
@@ -8714,6 +8901,9 @@ DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0,
8714 /* Prevent redisplay. */ 8901 /* Prevent redisplay. */
8715 specbind (Qinhibit_redisplay, Qt); 8902 specbind (Qinhibit_redisplay, Qt);
8716 8903
8904 /* Defer selection requests. */
8905 DEFER_SELECTIONS;
8906
8717 block_input (); 8907 block_input ();
8718 8908
8719 /* Create the dialog with PROMPT as title, using DIR as initial 8909 /* Create the dialog with PROMPT as title, using DIR as initial
@@ -9368,7 +9558,7 @@ frame_parm_handler x_frame_parm_handlers[] =
9368 x_set_wait_for_wm, 9558 x_set_wait_for_wm,
9369 gui_set_fullscreen, 9559 gui_set_fullscreen,
9370 gui_set_font_backend, 9560 gui_set_font_backend,
9371 gui_set_alpha, 9561 x_set_alpha,
9372 x_set_sticky, 9562 x_set_sticky,
9373 x_set_tool_bar_position, 9563 x_set_tool_bar_position,
9374#ifdef HAVE_XDBE 9564#ifdef HAVE_XDBE
@@ -9638,11 +9828,11 @@ default and usually works with most desktops. Some desktop environments
9638however, may refuse to resize a child frame when Emacs is built with 9828however, may refuse to resize a child frame when Emacs is built with
9639GTK3. For those environments, the two settings below are provided. 9829GTK3. For those environments, the two settings below are provided.
9640 9830
9641If this equals the symbol 'hide', Emacs temporarily hides the child 9831If this equals the symbol `hide', Emacs temporarily hides the child
9642frame during resizing. This approach seems to work reliably, may 9832frame during resizing. This approach seems to work reliably, may
9643however induce some flicker when the frame is made visible again. 9833however induce some flicker when the frame is made visible again.
9644 9834
9645If this equals the symbol 'resize-mode', Emacs uses GTK's resize mode to 9835If this equals the symbol `resize-mode', Emacs uses GTK's resize mode to
9646always trigger an immediate resize of the child frame. This method is 9836always trigger an immediate resize of the child frame. This method is
9647deprecated by GTK and may not work in future versions of that toolkit. 9837deprecated by GTK and may not work in future versions of that toolkit.
9648It also may freeze Emacs when used with other desktop environments. It 9838It also may freeze Emacs when used with other desktop environments. It
@@ -9757,6 +9947,10 @@ eliminated in future versions of Emacs. */);
9757 staticpro (&tip_last_string); 9947 staticpro (&tip_last_string);
9758 tip_last_parms = Qnil; 9948 tip_last_parms = Qnil;
9759 staticpro (&tip_last_parms); 9949 staticpro (&tip_last_parms);
9950 tip_dx = Qnil;
9951 staticpro (&tip_dx);
9952 tip_dy = Qnil;
9953 staticpro (&tip_dy);
9760 9954
9761 defsubr (&Sx_uses_old_gtk_dialog); 9955 defsubr (&Sx_uses_old_gtk_dialog);
9762#if defined (USE_MOTIF) || defined (USE_GTK) 9956#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,
295{ 295{
296 Lisp_Object list = Qnil; 296 Lisp_Object list = Qnil;
297 Lisp_Object chars = Qnil; 297 Lisp_Object chars = Qnil;
298 struct charset *encoding, *repertory = NULL; 298 struct charset *encoding = NULL, *repertory = NULL;
299 int i, limit, num_fonts; 299 int i, limit, num_fonts;
300 char **names; 300 char **names;
301 /* Large enough to decode the longest XLFD (255 bytes). */ 301 /* 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)
797This is needed with some fonts to correct vertical overlap of glyphs. */); 797This is needed with some fonts to correct vertical overlap of glyphs. */);
798 xft_font_ascent_descent_override = 0; 798 xft_font_ascent_descent_override = 0;
799 799
800 DEFVAR_LISP ("xft-color-font-whitelist", Vxft_color_font_whitelist,
801 doc: /* List of "color" font families that don't actually have color glyphs.
802Some fonts (such as Source Code Pro) are reported as color fonts, but
803do not actually have glyphs with colors that can cause Xft crashes.
804
805The font families in this list will not be ignored when
806`xft-ignore-color-fonts' is non-nil. */);
807 Vxft_color_font_whitelist = list1 (build_pure_c_string ("Source Code Pro"));
808
800 pdumper_do_now_and_after_load (syms_of_xftfont_for_pdumper); 809 pdumper_do_now_and_after_load (syms_of_xftfont_for_pdumper);
801} 810}
802 811
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/>. */
33static ptrdiff_t threads_holding_glib_lock; 33static ptrdiff_t threads_holding_glib_lock;
34static GMainContext *glib_main_context; 34static GMainContext *glib_main_context;
35 35
36/* The depth of xg_select suppression. */
37static int xg_select_suppress_count;
38
36void 39void
37release_select_lock (void) 40release_select_lock (void)
38{ 41{
@@ -69,6 +72,23 @@ acquire_select_lock (GMainContext *context)
69#endif 72#endif
70} 73}
71 74
75/* Call this to not use xg_select when using it would be a bad idea,
76 i.e. during drag-and-drop. */
77void
78suppress_xg_select (void)
79{
80 ++xg_select_suppress_count;
81}
82
83void
84release_xg_select (void)
85{
86 if (!xg_select_suppress_count)
87 emacs_abort ();
88
89 --xg_select_suppress_count;
90}
91
72/* `xg_select' is a `pselect' replacement. Why do we need a separate function? 92/* `xg_select' is a `pselect' replacement. Why do we need a separate function?
73 1. Timeouts. Glib and Gtk rely on timer events. If we did pselect 93 1. Timeouts. Glib and Gtk rely on timer events. If we did pselect
74 with a greater timeout then the one scheduled by Glib, we would 94 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,
100 bool already_has_events; 120 bool already_has_events;
101#endif 121#endif
102 122
123 if (xg_select_suppress_count)
124 return pselect (fds_lim, rfds, wfds, efds, timeout, sigmask);
125
103 context = g_main_context_default (); 126 context = g_main_context_default ();
104 acquire_select_lock (context); 127 acquire_select_lock (context);
105 128
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/>. */
25 25
26struct timespec; 26struct timespec;
27 27
28extern int xg_select (int max_fds, 28extern int xg_select (int, fd_set *, fd_set *, fd_set *,
29 fd_set *rfds, fd_set *wfds, fd_set *efds, 29 struct timespec *, sigset_t *);
30 struct timespec *timeout, sigset_t *sigmask); 30extern void suppress_xg_select (void);
31extern void release_xg_select (void);
31 32
32extern void release_select_lock (void); 33extern void release_select_lock (void);
33 34
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)
198 struct x_display_info *dpyinfo; 198 struct x_display_info *dpyinfo;
199 int n = 0; 199 int n = 0;
200 200
201 /* ISTM that if timer_check is okay, this should be too, since
202 both can run random Lisp. */
203 x_handle_pending_selection_requests ();
204
201 FD_ZERO (&read_fds); 205 FD_ZERO (&read_fds);
202 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) 206 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
203 { 207 {
@@ -1579,6 +1583,8 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1579 } 1583 }
1580#endif 1584#endif
1581 1585
1586 DEFER_SELECTIONS;
1587
1582 /* Display the menu. */ 1588 /* Display the menu. */
1583 gtk_widget_show_all (menu); 1589 gtk_widget_show_all (menu);
1584 1590
@@ -1868,6 +1874,8 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1868 { 1874 {
1869 specpdl_ref specpdl_count = SPECPDL_INDEX (); 1875 specpdl_ref specpdl_count = SPECPDL_INDEX ();
1870 1876
1877 DEFER_SELECTIONS;
1878
1871 record_unwind_protect_int (pop_down_menu, (int) menu_id); 1879 record_unwind_protect_int (pop_down_menu, (int) menu_id);
1872#ifdef HAVE_XINPUT2 1880#ifdef HAVE_XINPUT2
1873 record_unwind_protect_ptr (leave_toolkit_menu, f); 1881 record_unwind_protect_ptr (leave_toolkit_menu, f);
@@ -1894,13 +1902,19 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
1894{ 1902{
1895 int i; 1903 int i;
1896 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; 1904 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1897 widget_value **submenu_stack 1905 widget_value **submenu_stack;
1898 = alloca (menu_items_used * sizeof *submenu_stack); 1906 Lisp_Object *subprefix_stack;
1899 Lisp_Object *subprefix_stack
1900 = alloca (menu_items_used * sizeof *subprefix_stack);
1901 int submenu_depth = 0; 1907 int submenu_depth = 0;
1908 specpdl_ref specpdl_count;
1902 1909
1903 specpdl_ref specpdl_count = SPECPDL_INDEX (); 1910 USE_SAFE_ALLOCA;
1911
1912 submenu_stack = SAFE_ALLOCA (menu_items_used
1913 * sizeof *submenu_stack);
1914 subprefix_stack = SAFE_ALLOCA (menu_items_used
1915 * sizeof *subprefix_stack);
1916
1917 specpdl_count = SPECPDL_INDEX ();
1904 1918
1905 eassert (FRAME_X_P (f)); 1919 eassert (FRAME_X_P (f));
1906 1920
@@ -1909,6 +1923,7 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
1909 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH) 1923 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1910 { 1924 {
1911 *error_name = "Empty menu"; 1925 *error_name = "Empty menu";
1926 SAFE_FREE ();
1912 return Qnil; 1927 return Qnil;
1913 } 1928 }
1914 1929
@@ -2141,6 +2156,8 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
2141 entry = Fcons (subprefix_stack[j], entry); 2156 entry = Fcons (subprefix_stack[j], entry);
2142 } 2157 }
2143 unblock_input (); 2158 unblock_input ();
2159
2160 SAFE_FREE ();
2144 return entry; 2161 return entry;
2145 } 2162 }
2146 i += MENU_ITEMS_ITEM_LENGTH; 2163 i += MENU_ITEMS_ITEM_LENGTH;
@@ -2155,6 +2172,8 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
2155 } 2172 }
2156 2173
2157 unblock_input (); 2174 unblock_input ();
2175
2176 SAFE_FREE ();
2158 return Qnil; 2177 return Qnil;
2159} 2178}
2160 2179
@@ -2188,6 +2207,8 @@ create_and_show_dialog (struct frame *f, widget_value *first_wv)
2188 if (menu) 2207 if (menu)
2189 { 2208 {
2190 specpdl_ref specpdl_count = SPECPDL_INDEX (); 2209 specpdl_ref specpdl_count = SPECPDL_INDEX ();
2210
2211 DEFER_SELECTIONS;
2191 record_unwind_protect_ptr (pop_down_menu, menu); 2212 record_unwind_protect_ptr (pop_down_menu, menu);
2192 2213
2193 /* Display the menu. */ 2214 /* Display the menu. */
@@ -2244,6 +2265,8 @@ create_and_show_dialog (struct frame *f, widget_value *first_wv)
2244 { 2265 {
2245 specpdl_ref count = SPECPDL_INDEX (); 2266 specpdl_ref count = SPECPDL_INDEX ();
2246 2267
2268 DEFER_SELECTIONS;
2269
2247 /* xdialog_show_unwind is responsible for popping the dialog box down. */ 2270 /* xdialog_show_unwind is responsible for popping the dialog box down. */
2248 2271
2249 record_unwind_protect_int (pop_down_menu, (int) dialog_id); 2272 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,
2704 y = max (y, 1); 2727 y = max (y, 1);
2705 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y, 2728 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2706 &ulx, &uly, &width, &height); 2729 &ulx, &uly, &width, &height);
2707 if (ulx+width > dispwidth) 2730 if (ulx + width > dispwidth)
2708 { 2731 {
2709 x -= (ulx + width) - dispwidth; 2732 x -= (ulx + width) - dispwidth;
2710 ulx = dispwidth - width; 2733 ulx = dispwidth - width;
2711 } 2734 }
2712 if (uly+height > dispheight) 2735 if (uly + height > dispheight)
2713 { 2736 {
2714 y -= (uly + height) - dispheight; 2737 y -= (uly + height) - dispheight;
2715 uly = dispheight - height; 2738 uly = dispheight - height;
2716 } 2739 }
2717#ifndef HAVE_X_WINDOWS 2740#ifndef HAVE_X_WINDOWS
2718 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1) 2741 if (FRAME_HAS_MINIBUF_P (f) && uly + height > dispheight - 1)
2719 { 2742 {
2720 /* Move the menu away of the echo area, to avoid overwriting the 2743 /* Move the menu away of the echo area, to avoid overwriting the
2721 menu with help echo messages or vice versa. */ 2744 menu with help echo messages or vice versa. */
@@ -2739,8 +2762,8 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
2739 /* If position was not given by a mouse click, adjust so upper left 2762 /* If position was not given by a mouse click, adjust so upper left
2740 corner of the menu as a whole ends up at given coordinates. This 2763 corner of the menu as a whole ends up at given coordinates. This
2741 is what x-popup-menu says in its documentation. */ 2764 is what x-popup-menu says in its documentation. */
2742 x += width/2; 2765 x += width / 2;
2743 y += 1.5*height/(maxlines+2); 2766 y += 1.5 * height/ (maxlines + 2);
2744 } 2767 }
2745 2768
2746 XMenuSetAEQ (menu, true); 2769 XMenuSetAEQ (menu, true);
@@ -2748,6 +2771,8 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
2748 pane = selidx = 0; 2771 pane = selidx = 0;
2749 2772
2750#ifndef MSDOS 2773#ifndef MSDOS
2774 DEFER_SELECTIONS;
2775
2751 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f)); 2776 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2752#ifdef HAVE_XINPUT2 2777#ifdef HAVE_XINPUT2
2753 XMenuActivateSetTranslateFunction (x_menu_translate_generic_event); 2778 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,
486 if (XrmQGetResource (rdb, namelist, classlist, &type, &value) == True 486 if (XrmQGetResource (rdb, namelist, classlist, &type, &value) == True
487 && (type == expected_type)) 487 && (type == expected_type))
488 { 488 {
489 if (type == x_rm_string) 489 *ret_value = value;
490 ret_value->addr = (char *) value.addr;
491 else
492 memcpy (ret_value->addr, value.addr, ret_value->size);
493
494 return value.size; 490 return value.size;
495 } 491 }
496 492
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)
112 : MAX_SELECTION_QUANTUM); 112 : MAX_SELECTION_QUANTUM);
113} 113}
114 114
115#define LOCAL_SELECTION(selection_symbol,dpyinfo) \ 115#define LOCAL_SELECTION(selection_symbol, dpyinfo) \
116 assq_no_quit (selection_symbol, dpyinfo->terminal->Vselection_alist) 116 assq_no_quit (selection_symbol, dpyinfo->terminal->Vselection_alist)
117 117
118 118
119/* Define a queue to save up SELECTION_REQUEST_EVENT events for later
120 handling. */
121
122struct selection_event_queue
123 {
124 struct selection_input_event event;
125 struct selection_event_queue *next;
126 };
127
128static struct selection_event_queue *selection_queue;
129
130/* Nonzero means queue up SELECTION_REQUEST_EVENT events. */
131
132static int x_queue_selection_requests;
133
134/* True if the input events are duplicates. */
135
136static bool
137selection_input_event_equal (struct selection_input_event *a,
138 struct selection_input_event *b)
139{
140 return (a->kind == b->kind && a->dpyinfo == b->dpyinfo
141 && a->requestor == b->requestor && a->selection == b->selection
142 && a->target == b->target && a->property == b->property
143 && a->time == b->time);
144}
145
146/* Queue up an SELECTION_REQUEST_EVENT *EVENT, to be processed later. */
147
148static void
149x_queue_event (struct selection_input_event *event)
150{
151 struct selection_event_queue *queue_tmp;
152
153 /* Don't queue repeated requests.
154 This only happens for large requests which uses the incremental protocol. */
155 for (queue_tmp = selection_queue; queue_tmp; queue_tmp = queue_tmp->next)
156 {
157 if (selection_input_event_equal (event, &queue_tmp->event))
158 {
159 TRACE1 ("DECLINE DUP SELECTION EVENT %p", queue_tmp);
160 x_decline_selection_request (event);
161 return;
162 }
163 }
164
165 queue_tmp = xmalloc (sizeof *queue_tmp);
166 TRACE1 ("QUEUE SELECTION EVENT %p", queue_tmp);
167 queue_tmp->event = *event;
168 queue_tmp->next = selection_queue;
169 selection_queue = queue_tmp;
170}
171
172/* Start queuing SELECTION_REQUEST_EVENT events. */
173
174static void
175x_start_queuing_selection_requests (void)
176{
177 if (x_queue_selection_requests)
178 emacs_abort ();
179
180 x_queue_selection_requests++;
181 TRACE1 ("x_start_queuing_selection_requests %d", x_queue_selection_requests);
182}
183
184/* Stop queuing SELECTION_REQUEST_EVENT events. */
185
186static void
187x_stop_queuing_selection_requests (void)
188{
189 TRACE1 ("x_stop_queuing_selection_requests %d", x_queue_selection_requests);
190 --x_queue_selection_requests;
191
192 /* Take all the queued events and put them back
193 so that they get processed afresh. */
194
195 while (selection_queue != NULL)
196 {
197 struct selection_event_queue *queue_tmp = selection_queue;
198 TRACE1 ("RESTORE SELECTION EVENT %p", queue_tmp);
199 kbd_buffer_unget_event (&queue_tmp->event);
200 selection_queue = queue_tmp->next;
201 xfree (queue_tmp);
202 }
203}
204
205 119
206/* This converts a Lisp symbol to a server Atom, avoiding a server 120/* This converts a Lisp symbol to a server Atom, avoiding a server
207 roundtrip whenever possible. */ 121 roundtrip whenever possible. */
@@ -256,7 +170,7 @@ symbol_to_x_atom (struct x_display_info *dpyinfo, Lisp_Object sym)
256 170
257 TRACE1 (" XInternAtom %s", SSDATA (SYMBOL_NAME (sym))); 171 TRACE1 (" XInternAtom %s", SSDATA (SYMBOL_NAME (sym)));
258 block_input (); 172 block_input ();
259 val = XInternAtom (dpyinfo->display, SSDATA (SYMBOL_NAME (sym)), False); 173 val = x_intern_cached_atom (dpyinfo, SSDATA (SYMBOL_NAME (sym)), false);
260 unblock_input (); 174 unblock_input ();
261 return val; 175 return val;
262} 176}
@@ -265,7 +179,7 @@ symbol_to_x_atom (struct x_display_info *dpyinfo, Lisp_Object sym)
265/* This converts a server Atom to a Lisp symbol, avoiding server roundtrips 179/* This converts a server Atom to a Lisp symbol, avoiding server roundtrips
266 and calls to intern whenever possible. */ 180 and calls to intern whenever possible. */
267 181
268static Lisp_Object 182Lisp_Object
269x_atom_to_symbol (struct x_display_info *dpyinfo, Atom atom) 183x_atom_to_symbol (struct x_display_info *dpyinfo, Atom atom)
270{ 184{
271 char *str; 185 char *str;
@@ -319,18 +233,17 @@ x_atom_to_symbol (struct x_display_info *dpyinfo, Atom atom)
319 if (atom == dpyinfo->Xatom_XmTRANSFER_FAILURE) 233 if (atom == dpyinfo->Xatom_XmTRANSFER_FAILURE)
320 return QXmTRANSFER_FAILURE; 234 return QXmTRANSFER_FAILURE;
321 235
322 block_input ();
323 x_catch_errors (dpyinfo->display); 236 x_catch_errors (dpyinfo->display);
324 str = XGetAtomName (dpyinfo->display, atom); 237 str = x_get_atom_name (dpyinfo, atom, NULL);
325 x_uncatch_errors (); 238 x_uncatch_errors ();
326 unblock_input (); 239
240 TRACE0 ("XGetAtomName --> NULL");
241 if (!str)
242 return Qnil;
327 TRACE1 ("XGetAtomName --> %s", str); 243 TRACE1 ("XGetAtomName --> %s", str);
328 if (! str) return Qnil; 244
329 val = intern (str); 245 val = intern (str);
330 block_input (); 246 xfree (str);
331 /* This was allocated by Xlib, so use XFree. */
332 XFree (str);
333 unblock_input ();
334 return val; 247 return val;
335} 248}
336 249
@@ -399,7 +312,7 @@ static Lisp_Object
399x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type, 312x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
400 bool local_request, struct x_display_info *dpyinfo) 313 bool local_request, struct x_display_info *dpyinfo)
401{ 314{
402 Lisp_Object local_value; 315 Lisp_Object local_value, tem;
403 Lisp_Object handler_fn, value, check; 316 Lisp_Object handler_fn, value, check;
404 317
405 local_value = LOCAL_SELECTION (selection_symbol, dpyinfo); 318 local_value = LOCAL_SELECTION (selection_symbol, dpyinfo);
@@ -426,10 +339,24 @@ x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
426 if (CONSP (handler_fn)) 339 if (CONSP (handler_fn))
427 handler_fn = XCDR (handler_fn); 340 handler_fn = XCDR (handler_fn);
428 341
342 tem = XCAR (XCDR (local_value));
343
344 if (STRINGP (tem))
345 {
346 local_value = Fget_text_property (make_fixnum (0),
347 target_type, tem);
348
349 if (!NILP (local_value))
350 tem = local_value;
351 }
352
429 if (!NILP (handler_fn)) 353 if (!NILP (handler_fn))
430 value = call3 (handler_fn, 354 value = call3 (handler_fn, selection_symbol,
431 selection_symbol, (local_request ? Qnil : target_type), 355 ((local_request
432 XCAR (XCDR (local_value))); 356 && NILP (Vx_treat_local_requests_remotely))
357 ? Qnil
358 : target_type),
359 tem);
433 else 360 else
434 value = Qnil; 361 value = Qnil;
435 value = unbind_to (count, value); 362 value = unbind_to (count, value);
@@ -492,14 +419,6 @@ x_decline_selection_request (struct selection_input_event *event)
492 unblock_input (); 419 unblock_input ();
493} 420}
494 421
495/* This is the selection request currently being processed.
496 It is set to zero when the request is fully processed. */
497static struct selection_input_event *x_selection_current_request;
498
499/* Display info in x_selection_request. */
500
501static struct x_display_info *selection_request_dpyinfo;
502
503/* Raw selection data, for sending to a requestor window. */ 422/* Raw selection data, for sending to a requestor window. */
504 423
505struct selection_data 424struct selection_data
@@ -517,12 +436,59 @@ struct selection_data
517 struct selection_data *next; 436 struct selection_data *next;
518}; 437};
519 438
520/* Linked list of the above (in support of MULTIPLE targets). */ 439struct x_selection_request
440{
441 /* The last element in this stack. */
442 struct x_selection_request *last;
443
444 /* Its display info. */
445 struct x_display_info *dpyinfo;
446
447 /* Its selection input event. */
448 struct selection_input_event *request;
449
450 /* Linked list of the above (in support of MULTIPLE targets). */
451 struct selection_data *converted_selections;
452
453 /* "Data" to send a requestor for a failed MULTIPLE subtarget. */
454 Atom conversion_fail_tag;
455
456 /* Whether or not conversion was successful. */
457 bool converted;
458};
459
460/* Stack of selections currently being processed.
461 NULL if all requests have been fully processed. */
521 462
522static struct selection_data *converted_selections; 463struct x_selection_request *selection_request_stack;
523 464
524/* "Data" to send a requestor for a failed MULTIPLE subtarget. */ 465static void
525static Atom conversion_fail_tag; 466x_push_current_selection_request (struct selection_input_event *se,
467 struct x_display_info *dpyinfo)
468{
469 struct x_selection_request *frame;
470
471 frame = xmalloc (sizeof *frame);
472 frame->converted = false;
473 frame->last = selection_request_stack;
474 frame->request = se;
475 frame->dpyinfo = dpyinfo;
476 frame->converted_selections = NULL;
477 frame->conversion_fail_tag = None;
478
479 selection_request_stack = frame;
480}
481
482static void
483x_pop_current_selection_request (void)
484{
485 struct x_selection_request *tem;
486
487 tem = selection_request_stack;
488 selection_request_stack = selection_request_stack->last;
489
490 xfree (tem);
491}
526 492
527/* Used as an unwind-protect clause so that, if a selection-converter signals 493/* Used as an unwind-protect clause so that, if a selection-converter signals
528 an error, we tell the requestor that we were unable to do what they wanted 494 an error, we tell the requestor that we were unable to do what they wanted
@@ -532,19 +498,21 @@ static void
532x_selection_request_lisp_error (void) 498x_selection_request_lisp_error (void)
533{ 499{
534 struct selection_data *cs, *next; 500 struct selection_data *cs, *next;
501 struct x_selection_request *frame;
502
503 frame = selection_request_stack;
535 504
536 for (cs = converted_selections; cs; cs = next) 505 for (cs = frame->converted_selections; cs; cs = next)
537 { 506 {
538 next = cs->next; 507 next = cs->next;
539 if (! cs->nofree && cs->data) 508 if (! cs->nofree && cs->data)
540 xfree (cs->data); 509 xfree (cs->data);
541 xfree (cs); 510 xfree (cs);
542 } 511 }
543 converted_selections = NULL; 512 frame->converted_selections = NULL;
544 513
545 if (x_selection_current_request != 0 514 if (!frame->converted && frame->dpyinfo->display)
546 && selection_request_dpyinfo->display) 515 x_decline_selection_request (frame->request);
547 x_decline_selection_request (x_selection_current_request);
548} 516}
549 517
550static void 518static void
@@ -610,6 +578,9 @@ x_reply_selection_request (struct selection_input_event *event,
610 int max_bytes = selection_quantum (display); 578 int max_bytes = selection_quantum (display);
611 specpdl_ref count = SPECPDL_INDEX (); 579 specpdl_ref count = SPECPDL_INDEX ();
612 struct selection_data *cs; 580 struct selection_data *cs;
581 struct x_selection_request *frame;
582
583 frame = selection_request_stack;
613 584
614 reply->type = SelectionNotify; 585 reply->type = SelectionNotify;
615 reply->display = display; 586 reply->display = display;
@@ -633,7 +604,7 @@ x_reply_selection_request (struct selection_input_event *event,
633 (section 2.7.2 of ICCCM). Note that we store the data for a 604 (section 2.7.2 of ICCCM). Note that we store the data for a
634 MULTIPLE request in the opposite order; the ICCM says only that 605 MULTIPLE request in the opposite order; the ICCM says only that
635 the conversion itself must be done in the same order. */ 606 the conversion itself must be done in the same order. */
636 for (cs = converted_selections; cs; cs = cs->next) 607 for (cs = frame->converted_selections; cs; cs = cs->next)
637 { 608 {
638 if (cs->property == None) 609 if (cs->property == None)
639 continue; 610 continue;
@@ -688,7 +659,7 @@ x_reply_selection_request (struct selection_input_event *event,
688 be improved; there's a chance of deadlock if more than one 659 be improved; there's a chance of deadlock if more than one
689 subtarget in a MULTIPLE selection requires an INCR transfer, and 660 subtarget in a MULTIPLE selection requires an INCR transfer, and
690 the requestor and Emacs loop waiting on different transfers. */ 661 the requestor and Emacs loop waiting on different transfers. */
691 for (cs = converted_selections; cs; cs = cs->next) 662 for (cs = frame->converted_selections; cs; cs = cs->next)
692 if (cs->wait_object) 663 if (cs->wait_object)
693 { 664 {
694 int format_bytes = cs->format / 8; 665 int format_bytes = cs->format / 8;
@@ -793,7 +764,6 @@ static void
793x_handle_selection_request (struct selection_input_event *event) 764x_handle_selection_request (struct selection_input_event *event)
794{ 765{
795 Time local_selection_time; 766 Time local_selection_time;
796
797 struct x_display_info *dpyinfo = SELECTION_EVENT_DPYINFO (event); 767 struct x_display_info *dpyinfo = SELECTION_EVENT_DPYINFO (event);
798 Atom selection = SELECTION_EVENT_SELECTION (event); 768 Atom selection = SELECTION_EVENT_SELECTION (event);
799 Lisp_Object selection_symbol = x_atom_to_symbol (dpyinfo, selection); 769 Lisp_Object selection_symbol = x_atom_to_symbol (dpyinfo, selection);
@@ -803,8 +773,12 @@ x_handle_selection_request (struct selection_input_event *event)
803 Lisp_Object local_selection_data; 773 Lisp_Object local_selection_data;
804 bool success = false; 774 bool success = false;
805 specpdl_ref count = SPECPDL_INDEX (); 775 specpdl_ref count = SPECPDL_INDEX ();
776 bool pushed;
777
778 pushed = false;
806 779
807 if (!dpyinfo) goto DONE; 780 if (!dpyinfo)
781 goto DONE;
808 782
809 /* This is how the XDND protocol recommends dropping text onto a 783 /* This is how the XDND protocol recommends dropping text onto a
810 target that doesn't support XDND. */ 784 target that doesn't support XDND. */
@@ -824,14 +798,12 @@ x_handle_selection_request (struct selection_input_event *event)
824 && local_selection_time > SELECTION_EVENT_TIME (event)) 798 && local_selection_time > SELECTION_EVENT_TIME (event))
825 goto DONE; 799 goto DONE;
826 800
827 x_selection_current_request = event; 801 block_input ();
828 selection_request_dpyinfo = dpyinfo; 802 pushed = true;
803 x_push_current_selection_request (event, dpyinfo);
804 record_unwind_protect_void (x_pop_current_selection_request);
829 record_unwind_protect_void (x_selection_request_lisp_error); 805 record_unwind_protect_void (x_selection_request_lisp_error);
830 806 unblock_input ();
831 /* We might be able to handle nested x_handle_selection_requests,
832 but this is difficult to test, and seems unimportant. */
833 x_start_queuing_selection_requests ();
834 record_unwind_protect_void (x_stop_queuing_selection_requests);
835 807
836 TRACE2 ("x_handle_selection_request: selection=%s, target=%s", 808 TRACE2 ("x_handle_selection_request: selection=%s, target=%s",
837 SDATA (SYMBOL_NAME (selection_symbol)), 809 SDATA (SYMBOL_NAME (selection_symbol)),
@@ -888,15 +860,17 @@ x_handle_selection_request (struct selection_input_event *event)
888 860
889 DONE: 861 DONE:
890 862
863 if (pushed)
864 selection_request_stack->converted = true;
865
891 if (success) 866 if (success)
892 x_reply_selection_request (event, dpyinfo); 867 x_reply_selection_request (event, dpyinfo);
893 else 868 else
894 x_decline_selection_request (event); 869 x_decline_selection_request (event);
895 x_selection_current_request = 0;
896 870
897 /* Run the `x-sent-selection-functions' abnormal hook. */ 871 /* Run the `x-sent-selection-functions' abnormal hook. */
898 if (!NILP (Vx_sent_selection_functions) 872 if (!NILP (Vx_sent_selection_functions)
899 && !EQ (Vx_sent_selection_functions, Qunbound)) 873 && !BASE_EQ (Vx_sent_selection_functions, Qunbound))
900 CALLN (Frun_hook_with_args, Qx_sent_selection_functions, 874 CALLN (Frun_hook_with_args, Qx_sent_selection_functions,
901 selection_symbol, target_symbol, success ? Qt : Qnil); 875 selection_symbol, target_symbol, success ? Qt : Qnil);
902 876
@@ -917,11 +891,14 @@ x_convert_selection (Lisp_Object selection_symbol,
917{ 891{
918 Lisp_Object lisp_selection; 892 Lisp_Object lisp_selection;
919 struct selection_data *cs; 893 struct selection_data *cs;
894 struct x_selection_request *frame;
920 895
921 lisp_selection 896 lisp_selection
922 = x_get_local_selection (selection_symbol, target_symbol, 897 = x_get_local_selection (selection_symbol, target_symbol,
923 false, dpyinfo); 898 false, dpyinfo);
924 899
900 frame = selection_request_stack;
901
925 /* A nil return value means we can't perform the conversion. */ 902 /* A nil return value means we can't perform the conversion. */
926 if (NILP (lisp_selection) 903 if (NILP (lisp_selection)
927 || (CONSP (lisp_selection) && NILP (XCDR (lisp_selection)))) 904 || (CONSP (lisp_selection) && NILP (XCDR (lisp_selection))))
@@ -929,15 +906,16 @@ x_convert_selection (Lisp_Object selection_symbol,
929 if (for_multiple) 906 if (for_multiple)
930 { 907 {
931 cs = xmalloc (sizeof *cs); 908 cs = xmalloc (sizeof *cs);
932 cs->data = (unsigned char *) &conversion_fail_tag; 909 cs->data = ((unsigned char *)
910 &selection_request_stack->conversion_fail_tag);
933 cs->size = 1; 911 cs->size = 1;
934 cs->format = 32; 912 cs->format = 32;
935 cs->type = XA_ATOM; 913 cs->type = XA_ATOM;
936 cs->nofree = true; 914 cs->nofree = true;
937 cs->property = property; 915 cs->property = property;
938 cs->wait_object = NULL; 916 cs->wait_object = NULL;
939 cs->next = converted_selections; 917 cs->next = frame->converted_selections;
940 converted_selections = cs; 918 frame->converted_selections = cs;
941 } 919 }
942 920
943 return false; 921 return false;
@@ -949,8 +927,8 @@ x_convert_selection (Lisp_Object selection_symbol,
949 cs->nofree = true; 927 cs->nofree = true;
950 cs->property = property; 928 cs->property = property;
951 cs->wait_object = NULL; 929 cs->wait_object = NULL;
952 cs->next = converted_selections; 930 cs->next = frame->converted_selections;
953 converted_selections = cs; 931 frame->converted_selections = cs;
954 lisp_data_to_selection_data (dpyinfo, lisp_selection, cs); 932 lisp_data_to_selection_data (dpyinfo, lisp_selection, cs);
955 return true; 933 return true;
956} 934}
@@ -1008,6 +986,12 @@ x_handle_selection_clear (struct selection_input_event *event)
1008 /* Run the `x-lost-selection-functions' abnormal hook. */ 986 /* Run the `x-lost-selection-functions' abnormal hook. */
1009 CALLN (Frun_hook_with_args, Qx_lost_selection_functions, selection_symbol); 987 CALLN (Frun_hook_with_args, Qx_lost_selection_functions, selection_symbol);
1010 988
989 /* If Emacs lost ownership of XdndSelection during drag-and-drop,
990 there is no point in continuing the drag-and-drop session. */
991 if (x_dnd_in_progress
992 && EQ (selection_symbol, QXdndSelection))
993 error ("Lost ownership of XdndSelection");
994
1011 redisplay_preserve_echo_area (20); 995 redisplay_preserve_echo_area (20);
1012} 996}
1013 997
@@ -1017,8 +1001,6 @@ x_handle_selection_event (struct selection_input_event *event)
1017 TRACE0 ("x_handle_selection_event"); 1001 TRACE0 ("x_handle_selection_event");
1018 if (event->kind != SELECTION_REQUEST_EVENT) 1002 if (event->kind != SELECTION_REQUEST_EVENT)
1019 x_handle_selection_clear (event); 1003 x_handle_selection_clear (event);
1020 else if (x_queue_selection_requests)
1021 x_queue_event (event);
1022 else 1004 else
1023 x_handle_selection_request (event); 1005 x_handle_selection_request (event);
1024} 1006}
@@ -1148,8 +1130,13 @@ wait_for_property_change (struct prop_location *location)
1148 intmax_t secs = timeout / 1000; 1130 intmax_t secs = timeout / 1000;
1149 int nsecs = (timeout % 1000) * 1000000; 1131 int nsecs = (timeout % 1000) * 1000000;
1150 TRACE2 (" Waiting %"PRIdMAX" secs, %d nsecs", secs, nsecs); 1132 TRACE2 (" Waiting %"PRIdMAX" secs, %d nsecs", secs, nsecs);
1151 wait_reading_process_output (secs, nsecs, 0, false, 1133
1152 property_change_reply, NULL, 0); 1134 if (!input_blocked_p ())
1135 wait_reading_process_output (secs, nsecs, 0, false,
1136 property_change_reply, NULL, 0);
1137 else
1138 x_wait_for_cell_change (property_change_reply,
1139 make_timespec (secs, nsecs));
1153 1140
1154 if (NILP (XCAR (property_change_reply))) 1141 if (NILP (XCAR (property_change_reply)))
1155 { 1142 {
@@ -1256,9 +1243,22 @@ x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
1256 intmax_t secs = timeout / 1000; 1243 intmax_t secs = timeout / 1000;
1257 int nsecs = (timeout % 1000) * 1000000; 1244 int nsecs = (timeout % 1000) * 1000000;
1258 TRACE1 (" Start waiting %"PRIdMAX" secs for SelectionNotify", secs); 1245 TRACE1 (" Start waiting %"PRIdMAX" secs for SelectionNotify", secs);
1259 wait_reading_process_output (secs, nsecs, 0, false, 1246 /* This function can be called with input blocked inside Xt or GTK
1260 reading_selection_reply, NULL, 0); 1247 timeouts run inside popup menus, so use a function that works
1261 TRACE1 (" Got event = %d", !NILP (XCAR (reading_selection_reply))); 1248 when input is blocked. Prefer wait_reading_process_output
1249 otherwise, or the toolkit might not get some events.
1250 (bug#22214) */
1251 if (!input_blocked_p ())
1252 wait_reading_process_output (secs, nsecs, 0, false,
1253 reading_selection_reply, NULL, 0);
1254 else
1255 x_wait_for_cell_change (reading_selection_reply,
1256 make_timespec (secs, nsecs));
1257 TRACE1 (" Got event = %s", (!NILP (XCAR (reading_selection_reply))
1258 ? (SYMBOLP (XCAR (reading_selection_reply))
1259 ? SSDATA (SYMBOL_NAME (XCAR (reading_selection_reply)))
1260 : "YES")
1261 : "NO"));
1262 1262
1263 if (NILP (XCAR (reading_selection_reply))) 1263 if (NILP (XCAR (reading_selection_reply)))
1264 error ("Timed out waiting for reply from selection owner"); 1264 error ("Timed out waiting for reply from selection owner");
@@ -1953,7 +1953,7 @@ x_handle_selection_notify (const XSelectionEvent *event)
1953 if (event->selection != reading_which_selection) 1953 if (event->selection != reading_which_selection)
1954 return; 1954 return;
1955 1955
1956 TRACE0 ("Received SelectionNotify"); 1956 TRACE1 ("Received SelectionNotify: %d", (int) event->property);
1957 XSETCAR (reading_selection_reply, 1957 XSETCAR (reading_selection_reply,
1958 (event->property != 0 ? Qt : Qlambda)); 1958 (event->property != 0 ? Qt : Qlambda));
1959} 1959}
@@ -2454,28 +2454,29 @@ If the value is 0 or the atom is not known, return the empty string. */)
2454 (Lisp_Object value, Lisp_Object frame) 2454 (Lisp_Object value, Lisp_Object frame)
2455{ 2455{
2456 struct frame *f = decode_window_system_frame (frame); 2456 struct frame *f = decode_window_system_frame (frame);
2457 char *name = 0;
2458 char empty[] = "";
2459 Lisp_Object ret = Qnil;
2460 Display *dpy = FRAME_X_DISPLAY (f); 2457 Display *dpy = FRAME_X_DISPLAY (f);
2458 struct x_display_info *dpyinfo;
2461 Atom atom; 2459 Atom atom;
2462 bool had_errors_p; 2460 bool had_errors_p, need_sync;
2461 char *name;
2462 Lisp_Object ret;
2463 2463
2464 dpyinfo = FRAME_DISPLAY_INFO (f);
2464 CONS_TO_INTEGER (value, Atom, atom); 2465 CONS_TO_INTEGER (value, Atom, atom);
2465 2466
2466 block_input ();
2467 x_catch_errors (dpy); 2467 x_catch_errors (dpy);
2468 name = atom ? XGetAtomName (dpy, atom) : empty; 2468 name = x_get_atom_name (dpyinfo, atom, &need_sync);
2469 had_errors_p = x_had_errors_p (dpy); 2469 had_errors_p = need_sync && x_had_errors_p (dpy);
2470 x_uncatch_errors_after_check (); 2470 x_uncatch_errors_after_check ();
2471 2471
2472 if (!had_errors_p) 2472 ret = empty_unibyte_string;
2473 ret = build_string (name);
2474 2473
2475 if (atom && name) XFree (name); 2474 if (name)
2476 if (NILP (ret)) ret = empty_unibyte_string; 2475 {
2477 2476 if (!had_errors_p)
2478 unblock_input (); 2477 ret = build_string (name);
2478 xfree (name);
2479 }
2479 2480
2480 return ret; 2481 return ret;
2481} 2482}
@@ -2492,13 +2493,13 @@ FRAME is on. If FRAME is nil, the selected frame is used. */)
2492 ptrdiff_t i; 2493 ptrdiff_t i;
2493 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); 2494 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2494 2495
2495
2496 if (SYMBOLP (atom)) 2496 if (SYMBOLP (atom))
2497 x_atom = symbol_to_x_atom (dpyinfo, atom); 2497 x_atom = symbol_to_x_atom (dpyinfo, atom);
2498 else if (STRINGP (atom)) 2498 else if (STRINGP (atom))
2499 { 2499 {
2500 block_input (); 2500 block_input ();
2501 x_atom = XInternAtom (FRAME_X_DISPLAY (f), SSDATA (atom), False); 2501 x_atom = x_intern_cached_atom (dpyinfo, SSDATA (atom),
2502 false);
2502 unblock_input (); 2503 unblock_input ();
2503 } 2504 }
2504 else 2505 else
@@ -2521,7 +2522,8 @@ FRAME is on. If FRAME is nil, the selected frame is used. */)
2521 2522
2522bool 2523bool
2523x_handle_dnd_message (struct frame *f, const XClientMessageEvent *event, 2524x_handle_dnd_message (struct frame *f, const XClientMessageEvent *event,
2524 struct x_display_info *dpyinfo, struct input_event *bufp) 2525 struct x_display_info *dpyinfo, struct input_event *bufp,
2526 bool root_window_coords, int root_x, int root_y)
2525{ 2527{
2526 Lisp_Object vec; 2528 Lisp_Object vec;
2527 Lisp_Object frame; 2529 Lisp_Object frame;
@@ -2531,6 +2533,7 @@ x_handle_dnd_message (struct frame *f, const XClientMessageEvent *event,
2531 unsigned char *data = (unsigned char *) event->data.b; 2533 unsigned char *data = (unsigned char *) event->data.b;
2532 int idata[5]; 2534 int idata[5];
2533 ptrdiff_t i; 2535 ptrdiff_t i;
2536 Window child_return;
2534 2537
2535 for (i = 0; i < dpyinfo->x_dnd_atoms_length; ++i) 2538 for (i = 0; i < dpyinfo->x_dnd_atoms_length; ++i)
2536 if (dpyinfo->x_dnd_atoms[i] == event->message_type) break; 2539 if (dpyinfo->x_dnd_atoms[i] == event->message_type) break;
@@ -2562,7 +2565,15 @@ x_handle_dnd_message (struct frame *f, const XClientMessageEvent *event,
2562 event->format, 2565 event->format,
2563 size)); 2566 size));
2564 2567
2565 x_relative_mouse_position (f, &x, &y); 2568 if (!root_window_coords)
2569 x_relative_mouse_position (f, &x, &y);
2570 else
2571 XTranslateCoordinates (dpyinfo->display,
2572 dpyinfo->root_window,
2573 FRAME_X_WINDOW (f),
2574 root_x, root_y,
2575 &x, &y, &child_return);
2576
2566 bufp->kind = DRAG_N_DROP_EVENT; 2577 bufp->kind = DRAG_N_DROP_EVENT;
2567 bufp->frame_or_window = frame; 2578 bufp->frame_or_window = frame;
2568 bufp->timestamp = CurrentTime; 2579 bufp->timestamp = CurrentTime;
@@ -2799,6 +2810,14 @@ A value of 0 means wait as long as necessary. This is initialized from the
2799\"*selectionTimeout\" resource. */); 2810\"*selectionTimeout\" resource. */);
2800 x_selection_timeout = 0; 2811 x_selection_timeout = 0;
2801 2812
2813 DEFVAR_LISP ("x-treat-local-requests-remotely", Vx_treat_local_requests_remotely,
2814 doc: /* Whether to treat local selection requests as remote ones.
2815
2816If non-nil, selection converters for string types (`STRING',
2817`UTF8_STRING', `COMPOUND_TEXT', etc) will encode the strings, even
2818when Emacs itself is converting the selection. */);
2819 Vx_treat_local_requests_remotely = Qnil;
2820
2802 /* QPRIMARY is defined in keyboard.c. */ 2821 /* QPRIMARY is defined in keyboard.c. */
2803 DEFSYM (QSECONDARY, "SECONDARY"); 2822 DEFSYM (QSECONDARY, "SECONDARY");
2804 DEFSYM (QSTRING, "STRING"); 2823 DEFSYM (QSTRING, "STRING");
@@ -2838,6 +2857,4 @@ syms_of_xselect_for_pdumper (void)
2838 property_change_wait_list = 0; 2857 property_change_wait_list = 0;
2839 prop_location_identifier = 0; 2858 prop_location_identifier = 0;
2840 property_change_reply = Fcons (Qnil, Qnil); 2859 property_change_reply = Fcons (Qnil, Qnil);
2841 converted_selections = NULL;
2842 conversion_fail_tag = None;
2843} 2860}
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
206 unsigned seen; 206 unsigned seen;
207}; 207};
208 208
209#ifdef HAVE_PGTK
210/* The cairo font_options as obtained using gsettings. */
211static cairo_font_options_t *font_options;
212#endif
213
209#ifdef HAVE_GSETTINGS 214#ifdef HAVE_GSETTINGS
210#define GSETTINGS_SCHEMA "org.gnome.desktop.interface" 215#define GSETTINGS_SCHEMA "org.gnome.desktop.interface"
211#define GSETTINGS_TOOL_BAR_STYLE "toolbar-style" 216#define GSETTINGS_TOOL_BAR_STYLE "toolbar-style"
@@ -215,11 +220,162 @@ struct xsettings
215#define GSETTINGS_FONT_NAME "font-name" 220#define GSETTINGS_FONT_NAME "font-name"
216#endif 221#endif
217 222
223#ifdef HAVE_PGTK
224#define GSETTINGS_FONT_ANTIALIASING "font-antialiasing"
225#define GSETTINGS_FONT_RGBA_ORDER "font-rgba-order"
226#define GSETTINGS_FONT_HINTING "font-hinting"
227#endif
218 228
219/* The single GSettings instance, or NULL if not connected to GSettings. */ 229/* The single GSettings instance, or NULL if not connected to GSettings. */
220 230
221static GSettings *gsettings_client; 231static GSettings *gsettings_client;
222 232
233#if defined HAVE_PGTK && defined HAVE_GSETTINGS
234
235static bool
236xg_settings_key_valid_p (GSettings *settings, const char *key)
237{
238#ifdef GLIB_VERSION_2_32
239 GSettingsSchema *schema;
240 bool rc;
241
242 g_object_get (G_OBJECT (settings),
243 "settings-schema", &schema,
244 NULL);
245
246 if (!schema)
247 return false;
248
249 rc = g_settings_schema_has_key (schema, key);
250 g_settings_schema_unref (schema);
251
252 return rc;
253#else
254 return false;
255#endif
256}
257
258#endif
259
260#ifdef HAVE_PGTK
261/* Store an event for re-rendering of the fonts. */
262static void
263store_font_options_changed (void)
264{
265 if (dpyinfo_valid (first_dpyinfo))
266 store_config_changed_event (Qfont_render,
267 XCAR (first_dpyinfo->name_list_element));
268}
269
270/* Apply changes in the hinting system setting. */
271static void
272apply_gsettings_font_hinting (GSettings *settings)
273{
274 GVariant *val;
275 const char *hinting;
276
277 if (!xg_settings_key_valid_p (settings, GSETTINGS_FONT_HINTING))
278 return;
279
280 val = g_settings_get_value (settings, GSETTINGS_FONT_HINTING);
281
282 if (val)
283 {
284 g_variant_ref_sink (val);
285
286 if (g_variant_is_of_type (val, G_VARIANT_TYPE_STRING))
287 {
288 hinting = g_variant_get_string (val, NULL);
289
290 if (!strcmp (hinting, "full"))
291 cairo_font_options_set_hint_style (font_options,
292 CAIRO_HINT_STYLE_FULL);
293 else if (!strcmp (hinting, "medium"))
294 cairo_font_options_set_hint_style (font_options,
295 CAIRO_HINT_STYLE_MEDIUM);
296 else if (!strcmp (hinting, "slight"))
297 cairo_font_options_set_hint_style (font_options,
298 CAIRO_HINT_STYLE_SLIGHT);
299 else if (!strcmp (hinting, "none"))
300 cairo_font_options_set_hint_style (font_options,
301 CAIRO_HINT_STYLE_NONE);
302 }
303 g_variant_unref (val);
304 }
305}
306
307/* Apply changes in the antialiasing system setting. */
308static void
309apply_gsettings_font_antialias (GSettings *settings)
310{
311 GVariant *val;
312 const char *antialias;
313
314 if (!xg_settings_key_valid_p (settings, GSETTINGS_FONT_ANTIALIASING))
315 return;
316
317 val = g_settings_get_value (settings, GSETTINGS_FONT_ANTIALIASING);
318
319 if (val)
320 {
321 g_variant_ref_sink (val);
322 if (g_variant_is_of_type (val, G_VARIANT_TYPE_STRING))
323 {
324 antialias = g_variant_get_string (val, NULL);
325
326 if (!strcmp (antialias, "none"))
327 cairo_font_options_set_antialias (font_options,
328 CAIRO_ANTIALIAS_NONE);
329 else if (!strcmp (antialias, "grayscale"))
330 cairo_font_options_set_antialias (font_options,
331 CAIRO_ANTIALIAS_GRAY);
332 else if (!strcmp (antialias, "rgba"))
333 cairo_font_options_set_antialias (font_options,
334 CAIRO_ANTIALIAS_SUBPIXEL);
335 }
336 g_variant_unref (val);
337 }
338}
339
340/* Apply the settings for the rgb element ordering. */
341static void
342apply_gsettings_font_rgba_order (GSettings *settings)
343{
344 GVariant *val;
345 const char *rgba_order;
346
347 if (!xg_settings_key_valid_p (settings, GSETTINGS_FONT_RGBA_ORDER))
348 return;
349
350 val = g_settings_get_value (settings,
351 GSETTINGS_FONT_RGBA_ORDER);
352
353 if (val)
354 {
355 g_variant_ref_sink (val);
356
357 if (g_variant_is_of_type (val, G_VARIANT_TYPE_STRING))
358 {
359 rgba_order = g_variant_get_string (val, NULL);
360
361 if (!strcmp (rgba_order, "rgb"))
362 cairo_font_options_set_subpixel_order (font_options,
363 CAIRO_SUBPIXEL_ORDER_RGB);
364 else if (!strcmp (rgba_order, "bgr"))
365 cairo_font_options_set_subpixel_order (font_options,
366 CAIRO_SUBPIXEL_ORDER_BGR);
367 else if (!strcmp (rgba_order, "vrgb"))
368 cairo_font_options_set_subpixel_order (font_options,
369 CAIRO_SUBPIXEL_ORDER_VRGB);
370 else if (!strcmp (rgba_order, "vbgr"))
371 cairo_font_options_set_subpixel_order (font_options,
372 CAIRO_SUBPIXEL_ORDER_VBGR);
373 }
374 g_variant_unref (val);
375 }
376}
377#endif /* HAVE_PGTK */
378
223/* Callback called when something changed in GSettings. */ 379/* Callback called when something changed in GSettings. */
224 380
225static void 381static void
@@ -273,6 +429,23 @@ something_changed_gsettingsCB (GSettings *settings,
273 } 429 }
274 } 430 }
275#endif /* USE_CAIRO || HAVE_XFT */ 431#endif /* USE_CAIRO || HAVE_XFT */
432#ifdef HAVE_PGTK
433 else if (!strcmp (key, GSETTINGS_FONT_ANTIALIASING))
434 {
435 apply_gsettings_font_antialias (settings);
436 store_font_options_changed ();
437 }
438 else if (!strcmp (key, GSETTINGS_FONT_HINTING))
439 {
440 apply_gsettings_font_hinting (settings);
441 store_font_options_changed ();
442 }
443 else if (!strcmp (key, GSETTINGS_FONT_RGBA_ORDER))
444 {
445 apply_gsettings_font_rgba_order (settings);
446 store_font_options_changed ();
447 }
448#endif /* HAVE_PGTK */
276} 449}
277 450
278#endif /* HAVE_GSETTINGS */ 451#endif /* HAVE_GSETTINGS */
@@ -900,6 +1073,16 @@ init_gsettings (void)
900 dupstring (&current_font, g_variant_get_string (val, NULL)); 1073 dupstring (&current_font, g_variant_get_string (val, NULL));
901 g_variant_unref (val); 1074 g_variant_unref (val);
902 } 1075 }
1076
1077 /* Only use the gsettings font entries for the Cairo backend
1078 running on PGTK. */
1079#ifdef HAVE_PGTK
1080 font_options = cairo_font_options_create ();
1081 apply_gsettings_font_antialias (gsettings_client);
1082 apply_gsettings_font_hinting (gsettings_client);
1083 apply_gsettings_font_rgba_order (gsettings_client);
1084#endif /* HAVE_PGTK */
1085
903#endif /* USE_CAIRO || HAVE_XFT */ 1086#endif /* USE_CAIRO || HAVE_XFT */
904 1087
905#endif /* HAVE_GSETTINGS */ 1088#endif /* HAVE_GSETTINGS */
@@ -1021,6 +1204,21 @@ xsettings_get_system_normal_font (void)
1021} 1204}
1022#endif 1205#endif
1023 1206
1207#ifdef HAVE_PGTK
1208/* Return the cairo font options, updated from the gsettings font
1209 config entries. The caller should call cairo_font_options_destroy
1210 on the result. */
1211cairo_font_options_t *
1212xsettings_get_font_options (void)
1213{
1214 if (font_options != NULL)
1215 return cairo_font_options_copy (font_options);
1216 else
1217 /* GSettings is not configured. */
1218 return cairo_font_options_create ();
1219}
1220#endif
1221
1024DEFUN ("font-get-system-normal-font", Ffont_get_system_normal_font, 1222DEFUN ("font-get-system-normal-font", Ffont_get_system_normal_font,
1025 Sfont_get_system_normal_font, 1223 Sfont_get_system_normal_font,
1026 0, 0, 0, 1224 0, 0, 0,
@@ -1073,6 +1271,10 @@ syms_of_xsettings (void)
1073 gconf_client = NULL; 1271 gconf_client = NULL;
1074 PDUMPER_IGNORE (gconf_client); 1272 PDUMPER_IGNORE (gconf_client);
1075#endif 1273#endif
1274#ifdef HAVE_PGTK
1275 font_options = NULL;
1276 PDUMPER_IGNORE (font_options);
1277#endif
1076 1278
1077 DEFSYM (Qmonospace_font_name, "monospace-font-name"); 1279 DEFSYM (Qmonospace_font_name, "monospace-font-name");
1078 DEFSYM (Qfont_name, "font-name"); 1280 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/>. */
23#ifndef HAVE_PGTK 23#ifndef HAVE_PGTK
24#include "dispextern.h" 24#include "dispextern.h"
25#include <X11/Xlib.h> 25#include <X11/Xlib.h>
26#else
27#include <cairo.h>
26#endif 28#endif
27 29
28struct x_display_info; 30struct x_display_info;
@@ -41,5 +43,8 @@ extern const char *xsettings_get_system_font (void);
41extern const char *xsettings_get_system_normal_font (void); 43extern const char *xsettings_get_system_normal_font (void);
42#endif 44#endif
43 45
46#ifdef HAVE_PGTK
47extern cairo_font_options_t *xsettings_get_font_options (void);
48#endif
44 49
45#endif /* XSETTINGS_H */ 50#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/>. */
78 INPUT FOCUS 78 INPUT FOCUS
79 79
80 Under X, the window where keyboard input is sent is not always 80 Under X, the window where keyboard input is sent is not always
81 explictly defined. When there is a focus window, it receives what 81 explicitly defined. When there is a focus window, it receives what
82 is referred to as "explicit focus", but when there is none, it 82 is referred to as "explicit focus", but when there is none, it
83 receives "implicit focus" whenever the pointer enters it, and loses 83 receives "implicit focus" whenever the pointer enters it, and loses
84 that focus when the pointer leaves. When the toplevel window of a 84 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/>. */
550#include <config.h> 550#include <config.h>
551#include <stdlib.h> 551#include <stdlib.h>
552#include <math.h> 552#include <math.h>
553#include <signal.h>
553 554
554#include "lisp.h" 555#include "lisp.h"
555#include "blockinput.h" 556#include "blockinput.h"
@@ -699,6 +700,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
699#endif 700#endif
700#endif 701#endif
701 702
703#ifdef USE_GTK
704#include <xgselect.h>
705#endif
706
702#include "bitmaps/gray.xbm" 707#include "bitmaps/gray.xbm"
703 708
704#ifdef HAVE_XKB 709#ifdef HAVE_XKB
@@ -784,6 +789,227 @@ static int current_finish;
784static struct input_event *current_hold_quit; 789static struct input_event *current_hold_quit;
785#endif 790#endif
786 791
792/* Queue selection requests in `pending_selection_requests' if more
793 than 0. */
794static int x_use_pending_selection_requests;
795
796static void x_push_selection_request (struct selection_input_event *);
797
798/* Defer selection requests. Between this and
799 x_release_selection_requests, any selection requests can be
800 processed by calling `x_handle_pending_selection_requests'.
801
802 Also run through and queue all the selection events already in the
803 keyboard buffer. */
804void
805x_defer_selection_requests (void)
806{
807 union buffered_input_event *event;
808 bool between;
809
810 between = false;
811
812 block_input ();
813 if (!x_use_pending_selection_requests)
814 {
815 event = kbd_fetch_ptr;
816
817 while (event != kbd_store_ptr)
818 {
819 if (event->ie.kind == SELECTION_REQUEST_EVENT
820 || event->ie.kind == SELECTION_CLEAR_EVENT)
821 {
822 x_push_selection_request (&event->sie);
823
824 /* Mark this selection event as invalid. */
825 SELECTION_EVENT_DPYINFO (&event->sie) = NULL;
826
827 /* Move the kbd_fetch_ptr along if doing so would not
828 result in any other events being skipped. This
829 avoids exhausting the keyboard buffer with some
830 over-enthusiastic clipboard managers. */
831 if (!between)
832 kbd_fetch_ptr = (event == kbd_buffer + KBD_BUFFER_SIZE - 1
833 ? kbd_buffer : event + 1);
834 }
835 else
836 between = true;
837
838 event = (event == kbd_buffer + KBD_BUFFER_SIZE - 1
839 ? kbd_buffer : event + 1);
840 }
841 }
842
843 x_use_pending_selection_requests++;
844 unblock_input ();
845}
846
847static void
848x_release_selection_requests (void)
849{
850 x_use_pending_selection_requests--;
851}
852
853void
854x_release_selection_requests_and_flush (void)
855{
856 x_release_selection_requests ();
857
858 if (!x_use_pending_selection_requests)
859 x_handle_pending_selection_requests ();
860}
861
862struct x_selection_request_event
863{
864 /* The selection request event. */
865 struct selection_input_event se;
866
867 /* The next unprocessed selection request event. */
868 struct x_selection_request_event *next;
869};
870
871/* Chain of unprocessed selection request events. Used to handle
872 selection requests inside long-lasting modal event loops, such as
873 the drag-and-drop loop. */
874
875struct x_selection_request_event *pending_selection_requests;
876
877/* Compare two request serials A and B with OP, handling
878 wraparound. */
879#define X_COMPARE_SERIALS(a, op ,b) \
880 (((long) (a) - (long) (b)) op 0)
881
882struct x_atom_ref
883{
884 /* Atom name. */
885 const char *name;
886
887 /* Offset of atom in the display info structure. */
888 int offset;
889};
890
891/* List of all atoms that should be interned when connecting to a
892 display. */
893static const struct x_atom_ref x_atom_refs[] =
894 {
895#define ATOM_REFS_INIT(string, member) \
896 { string, offsetof (struct x_display_info, member) },
897 ATOM_REFS_INIT ("WM_PROTOCOLS", Xatom_wm_protocols)
898 ATOM_REFS_INIT ("WM_TAKE_FOCUS", Xatom_wm_take_focus)
899 ATOM_REFS_INIT ("WM_SAVE_YOURSELF", Xatom_wm_save_yourself)
900 ATOM_REFS_INIT ("WM_DELETE_WINDOW", Xatom_wm_delete_window)
901 ATOM_REFS_INIT ("WM_CHANGE_STATE", Xatom_wm_change_state)
902 ATOM_REFS_INIT ("WM_STATE", Xatom_wm_state)
903 ATOM_REFS_INIT ("WM_CONFIGURE_DENIED", Xatom_wm_configure_denied)
904 ATOM_REFS_INIT ("WM_MOVED", Xatom_wm_window_moved)
905 ATOM_REFS_INIT ("WM_CLIENT_LEADER", Xatom_wm_client_leader)
906 ATOM_REFS_INIT ("WM_TRANSIENT_FOR", Xatom_wm_transient_for)
907 ATOM_REFS_INIT ("Editres", Xatom_editres)
908 ATOM_REFS_INIT ("CLIPBOARD", Xatom_CLIPBOARD)
909 ATOM_REFS_INIT ("TIMESTAMP", Xatom_TIMESTAMP)
910 ATOM_REFS_INIT ("TEXT", Xatom_TEXT)
911 ATOM_REFS_INIT ("COMPOUND_TEXT", Xatom_COMPOUND_TEXT)
912 ATOM_REFS_INIT ("UTF8_STRING", Xatom_UTF8_STRING)
913 ATOM_REFS_INIT ("DELETE", Xatom_DELETE)
914 ATOM_REFS_INIT ("MULTIPLE", Xatom_MULTIPLE)
915 ATOM_REFS_INIT ("INCR", Xatom_INCR)
916 ATOM_REFS_INIT ("_EMACS_TMP_", Xatom_EMACS_TMP)
917 ATOM_REFS_INIT ("EMACS_SERVER_TIME_PROP", Xatom_EMACS_SERVER_TIME_PROP)
918 ATOM_REFS_INIT ("TARGETS", Xatom_TARGETS)
919 ATOM_REFS_INIT ("NULL", Xatom_NULL)
920 ATOM_REFS_INIT ("ATOM", Xatom_ATOM)
921 ATOM_REFS_INIT ("ATOM_PAIR", Xatom_ATOM_PAIR)
922 ATOM_REFS_INIT ("CLIPBOARD_MANAGER", Xatom_CLIPBOARD_MANAGER)
923 ATOM_REFS_INIT ("_XEMBED_INFO", Xatom_XEMBED_INFO)
924 ATOM_REFS_INIT ("_MOTIF_WM_HINTS", Xatom_MOTIF_WM_HINTS)
925 /* For properties of font. */
926 ATOM_REFS_INIT ("PIXEL_SIZE", Xatom_PIXEL_SIZE)
927 ATOM_REFS_INIT ("AVERAGE_WIDTH", Xatom_AVERAGE_WIDTH)
928 ATOM_REFS_INIT ("_MULE_BASELINE_OFFSET", Xatom_MULE_BASELINE_OFFSET)
929 ATOM_REFS_INIT ("_MULE_RELATIVE_COMPOSE", Xatom_MULE_RELATIVE_COMPOSE)
930 ATOM_REFS_INIT ("_MULE_DEFAULT_ASCENT", Xatom_MULE_DEFAULT_ASCENT)
931 /* Ghostscript support. */
932 ATOM_REFS_INIT ("DONE", Xatom_DONE)
933 ATOM_REFS_INIT ("PAGE", Xatom_PAGE)
934 ATOM_REFS_INIT ("SCROLLBAR", Xatom_Scrollbar)
935 ATOM_REFS_INIT ("HORIZONTAL_SCROLLBAR", Xatom_Horizontal_Scrollbar)
936 ATOM_REFS_INIT ("_XEMBED", Xatom_XEMBED)
937 /* EWMH */
938 ATOM_REFS_INIT ("_NET_WM_STATE", Xatom_net_wm_state)
939 ATOM_REFS_INIT ("_NET_WM_STATE_FULLSCREEN", Xatom_net_wm_state_fullscreen)
940 ATOM_REFS_INIT ("_NET_WM_STATE_MAXIMIZED_HORZ",
941 Xatom_net_wm_state_maximized_horz)
942 ATOM_REFS_INIT ("_NET_WM_STATE_MAXIMIZED_VERT",
943 Xatom_net_wm_state_maximized_vert)
944 ATOM_REFS_INIT ("_NET_WM_STATE_STICKY", Xatom_net_wm_state_sticky)
945 ATOM_REFS_INIT ("_NET_WM_STATE_SHADED", Xatom_net_wm_state_shaded)
946 ATOM_REFS_INIT ("_NET_WM_STATE_HIDDEN", Xatom_net_wm_state_hidden)
947 ATOM_REFS_INIT ("_NET_WM_WINDOW_TYPE", Xatom_net_window_type)
948 ATOM_REFS_INIT ("_NET_WM_WINDOW_TYPE_TOOLTIP",
949 Xatom_net_window_type_tooltip)
950 ATOM_REFS_INIT ("_NET_WM_ICON_NAME", Xatom_net_wm_icon_name)
951 ATOM_REFS_INIT ("_NET_WM_NAME", Xatom_net_wm_name)
952 ATOM_REFS_INIT ("_NET_SUPPORTED", Xatom_net_supported)
953 ATOM_REFS_INIT ("_NET_SUPPORTING_WM_CHECK", Xatom_net_supporting_wm_check)
954 ATOM_REFS_INIT ("_NET_WM_WINDOW_OPACITY", Xatom_net_wm_window_opacity)
955 ATOM_REFS_INIT ("_NET_ACTIVE_WINDOW", Xatom_net_active_window)
956 ATOM_REFS_INIT ("_NET_FRAME_EXTENTS", Xatom_net_frame_extents)
957 ATOM_REFS_INIT ("_NET_CURRENT_DESKTOP", Xatom_net_current_desktop)
958 ATOM_REFS_INIT ("_NET_WORKAREA", Xatom_net_workarea)
959 ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST", Xatom_net_wm_sync_request)
960 ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST_COUNTER", Xatom_net_wm_sync_request_counter)
961 ATOM_REFS_INIT ("_NET_WM_FRAME_DRAWN", Xatom_net_wm_frame_drawn)
962 ATOM_REFS_INIT ("_NET_WM_USER_TIME", Xatom_net_wm_user_time)
963 ATOM_REFS_INIT ("_NET_WM_USER_TIME_WINDOW", Xatom_net_wm_user_time_window)
964 ATOM_REFS_INIT ("_NET_CLIENT_LIST_STACKING", Xatom_net_client_list_stacking)
965 /* Session management */
966 ATOM_REFS_INIT ("SM_CLIENT_ID", Xatom_SM_CLIENT_ID)
967 ATOM_REFS_INIT ("_XSETTINGS_SETTINGS", Xatom_xsettings_prop)
968 ATOM_REFS_INIT ("MANAGER", Xatom_xsettings_mgr)
969 ATOM_REFS_INIT ("_NET_WM_STATE_SKIP_TASKBAR", Xatom_net_wm_state_skip_taskbar)
970 ATOM_REFS_INIT ("_NET_WM_STATE_ABOVE", Xatom_net_wm_state_above)
971 ATOM_REFS_INIT ("_NET_WM_STATE_BELOW", Xatom_net_wm_state_below)
972 ATOM_REFS_INIT ("_NET_WM_OPAQUE_REGION", Xatom_net_wm_opaque_region)
973 ATOM_REFS_INIT ("_NET_WM_PING", Xatom_net_wm_ping)
974 ATOM_REFS_INIT ("_NET_WM_PID", Xatom_net_wm_pid)
975#ifdef HAVE_XKB
976 ATOM_REFS_INIT ("Meta", Xatom_Meta)
977 ATOM_REFS_INIT ("Super", Xatom_Super)
978 ATOM_REFS_INIT ("Hyper", Xatom_Hyper)
979 ATOM_REFS_INIT ("ShiftLock", Xatom_ShiftLock)
980 ATOM_REFS_INIT ("Alt", Xatom_Alt)
981#endif
982 /* DND source. */
983 ATOM_REFS_INIT ("XdndAware", Xatom_XdndAware)
984 ATOM_REFS_INIT ("XdndSelection", Xatom_XdndSelection)
985 ATOM_REFS_INIT ("XdndTypeList", Xatom_XdndTypeList)
986 ATOM_REFS_INIT ("XdndActionCopy", Xatom_XdndActionCopy)
987 ATOM_REFS_INIT ("XdndActionMove", Xatom_XdndActionMove)
988 ATOM_REFS_INIT ("XdndActionLink", Xatom_XdndActionLink)
989 ATOM_REFS_INIT ("XdndActionAsk", Xatom_XdndActionAsk)
990 ATOM_REFS_INIT ("XdndActionPrivate", Xatom_XdndActionPrivate)
991 ATOM_REFS_INIT ("XdndActionList", Xatom_XdndActionList)
992 ATOM_REFS_INIT ("XdndActionDescription", Xatom_XdndActionDescription)
993 ATOM_REFS_INIT ("XdndProxy", Xatom_XdndProxy)
994 ATOM_REFS_INIT ("XdndEnter", Xatom_XdndEnter)
995 ATOM_REFS_INIT ("XdndPosition", Xatom_XdndPosition)
996 ATOM_REFS_INIT ("XdndStatus", Xatom_XdndStatus)
997 ATOM_REFS_INIT ("XdndLeave", Xatom_XdndLeave)
998 ATOM_REFS_INIT ("XdndDrop", Xatom_XdndDrop)
999 ATOM_REFS_INIT ("XdndFinished", Xatom_XdndFinished)
1000 /* Motif drop protocol support. */
1001 ATOM_REFS_INIT ("_MOTIF_DRAG_WINDOW", Xatom_MOTIF_DRAG_WINDOW)
1002 ATOM_REFS_INIT ("_MOTIF_DRAG_TARGETS", Xatom_MOTIF_DRAG_TARGETS)
1003 ATOM_REFS_INIT ("_MOTIF_DRAG_AND_DROP_MESSAGE",
1004 Xatom_MOTIF_DRAG_AND_DROP_MESSAGE)
1005 ATOM_REFS_INIT ("_MOTIF_DRAG_INITIATOR_INFO",
1006 Xatom_MOTIF_DRAG_INITIATOR_INFO)
1007 ATOM_REFS_INIT ("_MOTIF_DRAG_RECEIVER_INFO",
1008 Xatom_MOTIF_DRAG_RECEIVER_INFO)
1009 ATOM_REFS_INIT ("XmTRANSFER_SUCCESS", Xatom_XmTRANSFER_SUCCESS)
1010 ATOM_REFS_INIT ("XmTRANSFER_FAILURE", Xatom_XmTRANSFER_FAILURE)
1011 };
1012
787enum 1013enum
788{ 1014{
789 X_EVENT_NORMAL, 1015 X_EVENT_NORMAL,
@@ -863,19 +1089,39 @@ static void x_scroll_bar_end_update (struct x_display_info *, struct scroll_bar
863static int x_filter_event (struct x_display_info *, XEvent *); 1089static int x_filter_event (struct x_display_info *, XEvent *);
864#endif 1090#endif
865 1091
1092static struct frame *x_tooltip_window_to_frame (struct x_display_info *,
1093 Window, bool *);
1094static Window x_get_window_below (Display *, Window, int, int, int *, int *);
1095
866/* Global state maintained during a drag-and-drop operation. */ 1096/* Global state maintained during a drag-and-drop operation. */
867 1097
868/* Flag that indicates if a drag-and-drop operation is in progress. */ 1098/* Flag that indicates if a drag-and-drop operation is in progress. */
869bool x_dnd_in_progress; 1099bool x_dnd_in_progress;
870 1100
1101/* Number that indicates the last "generation" of
1102 UNSUPPORTED_DROP_EVENTs handled. */
1103unsigned x_dnd_unsupported_event_level;
1104
871/* The frame where the drag-and-drop operation originated. */ 1105/* The frame where the drag-and-drop operation originated. */
872struct frame *x_dnd_frame; 1106struct frame *x_dnd_frame;
873 1107
1108/* That frame, but set when x_dnd_waiting_for_finish is true. Used to
1109 prevent the frame from being deleted inside selection handlers and
1110 other callbacks. */
1111struct frame *x_dnd_finish_frame;
1112
874/* Flag that indicates if a drag-and-drop operation is no longer in 1113/* Flag that indicates if a drag-and-drop operation is no longer in
875 progress, but the nested event loop should continue to run, because 1114 progress, but the nested event loop should continue to run, because
876 handle_one_xevent is waiting for the drop target to return some 1115 handle_one_xevent is waiting for the drop target to return some
877 important information. */ 1116 important information. */
878static bool x_dnd_waiting_for_finish; 1117bool x_dnd_waiting_for_finish;
1118
1119/* Whether or not to move the tooltip along with the mouse pointer
1120 during drag-and-drop. */
1121static bool x_dnd_update_tooltip;
1122
1123/* Monitor attribute list used for updating the tooltip position. */
1124static Lisp_Object x_dnd_monitors;
879 1125
880/* The display the drop target that is supposed to send information is 1126/* The display the drop target that is supposed to send information is
881 on. */ 1127 on. */
@@ -916,6 +1162,10 @@ static int x_dnd_waiting_for_finish_proto;
916 where the drag-and-drop operation originated. */ 1162 where the drag-and-drop operation originated. */
917static bool x_dnd_allow_current_frame; 1163static bool x_dnd_allow_current_frame;
918 1164
1165/* Whether or not the `XdndTypeList' property has already been set on
1166 the drag frame. */
1167static bool x_dnd_init_type_lists;
1168
919/* Whether or not to return a frame from `x_dnd_begin_drag_and_drop'. 1169/* Whether or not to return a frame from `x_dnd_begin_drag_and_drop'.
920 1170
921 0 means to do nothing. 1 means to wait for the mouse to first exit 1171 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;
943 did not support XDND. */ 1193 did not support XDND. */
944static int x_dnd_last_protocol_version; 1194static int x_dnd_last_protocol_version;
945 1195
1196/* Whether or not the last seen window is actually one of our
1197 frames. */
1198static bool x_dnd_last_window_is_frame;
1199
946/* The Motif drag and drop protocol style of `x_dnd_last_seen_window'. 1200/* The Motif drag and drop protocol style of `x_dnd_last_seen_window'.
947 XM_DRAG_STYLE_NONE means the window does not support the Motif drag 1201 XM_DRAG_STYLE_NONE means the window does not support the Motif drag
948 or drop protocol. XM_DRAG_STYLE_DROP_ONLY means the window does 1202 or drop protocol. XM_DRAG_STYLE_DROP_ONLY means the window does
@@ -974,13 +1228,25 @@ static XRectangle x_dnd_mouse_rect;
974 protocol, this is set to the atom XdndActionPrivate. */ 1228 protocol, this is set to the atom XdndActionPrivate. */
975static Atom x_dnd_action; 1229static Atom x_dnd_action;
976 1230
1231/* The symbol to return from `x-begin-drag' if non-nil. Takes
1232 precedence over `x_dnd_action`. */
1233static Lisp_Object x_dnd_action_symbol;
1234
977/* The action we want the drop target to perform. The drop target may 1235/* The action we want the drop target to perform. The drop target may
978 elect to perform some different action, which is guaranteed to be 1236 elect to perform some different action, which is guaranteed to be
979 in `x_dnd_action' upon completion of a drop. */ 1237 in `x_dnd_action' upon completion of a drop. */
980static Atom x_dnd_wanted_action; 1238static Atom x_dnd_wanted_action;
981 1239
1240/* The set of optional actions available to a Motif drop target
1241 computed at the start of the drag-and-drop operation. */
1242static uint8_t x_dnd_motif_operations;
1243
1244/* The preferred optional action out of that set. Only takes effect
1245 if `x_dnd_action' is XdndAsk. */
1246static uint8_t x_dnd_first_motif_operation;
1247
982/* Array of selection targets available to the drop target. */ 1248/* Array of selection targets available to the drop target. */
983static Atom *x_dnd_targets = NULL; 1249static Atom *x_dnd_targets;
984 1250
985/* The number of elements in that array. */ 1251/* The number of elements in that array. */
986static int x_dnd_n_targets; 1252static int x_dnd_n_targets;
@@ -1009,42 +1275,86 @@ static unsigned int x_dnd_keyboard_state;
1009 1275
1010/* jmp_buf that gets us out of the IO error handler if an error occurs 1276/* jmp_buf that gets us out of the IO error handler if an error occurs
1011 terminating DND as part of the display disconnect handler. */ 1277 terminating DND as part of the display disconnect handler. */
1012static jmp_buf x_dnd_disconnect_handler; 1278static sigjmp_buf x_dnd_disconnect_handler;
1279
1280/* Whether or not the current invocation of handle_one_xevent
1281 happened inside the drag_and_drop event loop. */
1282static bool x_dnd_inside_handle_one_xevent;
1283
1284/* The recursive edit depth when the drag-and-drop operation was
1285 started. */
1286static int x_dnd_recursion_depth;
1013 1287
1288/* Structure describing a single window that can be the target of
1289 drag-and-drop operations. */
1014struct x_client_list_window 1290struct x_client_list_window
1015{ 1291{
1292 /* The window itself. */
1016 Window window; 1293 Window window;
1294
1295 /* The display that window is on. */
1017 Display *dpy; 1296 Display *dpy;
1297
1298 /* Its X and Y coordinates from the root window. */
1018 int x, y; 1299 int x, y;
1300
1301 /* The width and height of the window. */
1019 int width, height; 1302 int width, height;
1303
1304 /* Whether or not the window is mapped. */
1020 bool mapped_p; 1305 bool mapped_p;
1306
1307 /* A bitmask describing events Emacs was listening for from the
1308 window before some extra events were added in
1309 `x_dnd_compute_toplevels'. */
1021 long previous_event_mask; 1310 long previous_event_mask;
1311
1312 /* The window manager state of the window. */
1022 unsigned long wm_state; 1313 unsigned long wm_state;
1023 1314
1315 /* The next window in this list. */
1024 struct x_client_list_window *next; 1316 struct x_client_list_window *next;
1317
1318 /* The Motif protocol style of this window, if any. */
1025 uint8_t xm_protocol_style; 1319 uint8_t xm_protocol_style;
1026 1320
1321 /* The extents of the frame window in each direction. */
1027 int frame_extents_left; 1322 int frame_extents_left;
1028 int frame_extents_right; 1323 int frame_extents_right;
1029 int frame_extents_top; 1324 int frame_extents_top;
1030 int frame_extents_bottom; 1325 int frame_extents_bottom;
1031 1326
1032#ifdef HAVE_XSHAPE 1327#ifdef HAVE_XSHAPE
1328 /* The border width of this window. */
1033 int border_width; 1329 int border_width;
1034 1330
1331 /* The rectangles making up the input shape. */
1035 XRectangle *input_rects; 1332 XRectangle *input_rects;
1333
1334 /* The number of rectangles composing the input shape. */
1036 int n_input_rects; 1335 int n_input_rects;
1037 1336
1337 /* The rectangles making up the bounding shape. */
1038 XRectangle *bounding_rects; 1338 XRectangle *bounding_rects;
1339
1340 /* The number of rectangles composing the bounding shape. */
1039 int n_bounding_rects; 1341 int n_bounding_rects;
1040#endif 1342#endif
1041}; 1343};
1042 1344
1043static struct x_client_list_window *x_dnd_toplevels = NULL; 1345/* List of all toplevels in stacking order, from top to bottom. */
1346static struct x_client_list_window *x_dnd_toplevels;
1347
1348/* Whether or not the window manager supports the required features
1349 for `x_dnd_toplevels' to work. */
1044static bool x_dnd_use_toplevels; 1350static bool x_dnd_use_toplevels;
1045 1351
1046/* Motif drag-and-drop protocol support. */ 1352/* Motif drag-and-drop protocol support. */
1047 1353
1354/* Pointer to a variable which stores whether or not an X error
1355 occured while trying to create the Motif drag window. */
1356static volatile bool *xm_drag_window_error;
1357
1048typedef enum xm_byte_order 1358typedef enum xm_byte_order
1049 { 1359 {
1050 XM_BYTE_ORDER_LSB_FIRST = 'l', 1360 XM_BYTE_ORDER_LSB_FIRST = 'l',
@@ -1078,8 +1388,8 @@ typedef enum xm_byte_order
1078 } 1388 }
1079 1389
1080#else 1390#else
1081#define SWAPCARD32(l) bswap_32 (l) 1391#define SWAPCARD32(l) ((l) = bswap_32 (l))
1082#define SWAPCARD16(l) bswap_16 (l) 1392#define SWAPCARD16(l) ((l) = bswap_16 (l))
1083#endif 1393#endif
1084 1394
1085typedef struct xm_targets_table_header 1395typedef struct xm_targets_table_header
@@ -1181,34 +1491,50 @@ typedef struct xm_top_level_leave_message
1181/* #define XM_DRAG_SIDE_EFFECT_OPERATIONS(effect) (((effect) & 0xf00) >> 8) */ 1491/* #define XM_DRAG_SIDE_EFFECT_OPERATIONS(effect) (((effect) & 0xf00) >> 8) */
1182#define XM_DRAG_SIDE_EFFECT_DROP_ACTION(effect) (((effect) & 0xf000) >> 12) 1492#define XM_DRAG_SIDE_EFFECT_DROP_ACTION(effect) (((effect) & 0xf000) >> 12)
1183 1493
1184#define XM_DRAG_NOOP 0 1494enum xm_drag_operation
1185#define XM_DRAG_MOVE (1L << 0) 1495 {
1186#define XM_DRAG_COPY (1L << 1) 1496 XM_DRAG_NOOP = 0,
1187#define XM_DRAG_LINK (1L << 2) 1497 XM_DRAG_MOVE = (1L << 0),
1498 XM_DRAG_COPY = (1L << 1),
1499 XM_DRAG_LINK = (1L << 2),
1500 };
1188 1501
1189#define XM_DROP_ACTION_DROP 0 1502enum xm_drag_action
1190#define XM_DROP_ACTION_DROP_HELP 1 1503 {
1191#define XM_DROP_ACTION_DROP_CANCEL 2 1504 XM_DROP_ACTION_DROP = 0,
1505 XM_DROP_ACTION_DROP_HELP = 1,
1506 XM_DROP_ACTION_DROP_CANCEL = 2,
1507 };
1192 1508
1193#define XM_DRAG_REASON(originator, code) ((code) | ((originator) << 7)) 1509#define XM_DRAG_REASON(originator, code) ((code) | ((originator) << 7))
1194#define XM_DRAG_REASON_ORIGINATOR(reason) (((reason) & 0x80) ? 1 : 0) 1510#define XM_DRAG_REASON_ORIGINATOR(reason) (((reason) & 0x80) ? 1 : 0)
1195#define XM_DRAG_REASON_CODE(reason) ((reason) & 0x7f) 1511#define XM_DRAG_REASON_CODE(reason) ((reason) & 0x7f)
1196 1512
1197#define XM_DRAG_REASON_DROP_START 5 1513enum xm_drag_reason
1198#define XM_DRAG_REASON_TOP_LEVEL_ENTER 0 1514 {
1199#define XM_DRAG_REASON_TOP_LEVEL_LEAVE 1 1515 XM_DRAG_REASON_DROP_START = 5,
1200#define XM_DRAG_REASON_DRAG_MOTION 2 1516 XM_DRAG_REASON_TOP_LEVEL_ENTER = 0,
1201#define XM_DRAG_ORIGINATOR_INITIATOR 0 1517 XM_DRAG_REASON_TOP_LEVEL_LEAVE = 1,
1202#define XM_DRAG_ORIGINATOR_RECEIVER 1 1518 XM_DRAG_REASON_DRAG_MOTION = 2,
1203 1519 };
1204#define XM_DRAG_STYLE_NONE 0
1205 1520
1206#define XM_DRAG_STYLE_DROP_ONLY 1 1521enum xm_drag_originator
1207#define XM_DRAG_STYLE_DROP_ONLY_REC 3 1522 {
1523 XM_DRAG_ORIGINATOR_INITIATOR = 0,
1524 XM_DRAG_ORIGINATOR_RECEIVER = 1,
1525 };
1208 1526
1209#define XM_DRAG_STYLE_DYNAMIC 5 1527enum xm_drag_style
1210#define XM_DRAG_STYLE_DYNAMIC_REC 2 1528 {
1211#define XM_DRAG_STYLE_DYNAMIC_REC1 4 1529 /* The values ending with _REC should be treated as equivalent to
1530 the ones without in messages from the receiver. */
1531 XM_DRAG_STYLE_NONE = 0,
1532 XM_DRAG_STYLE_DROP_ONLY = 1,
1533 XM_DRAG_STYLE_DROP_ONLY_REC = 3,
1534 XM_DRAG_STYLE_DYNAMIC = 5,
1535 XM_DRAG_STYLE_DYNAMIC_REC = 2,
1536 XM_DRAG_STYLE_DYNAMIC_REC1 = 4,
1537 };
1212 1538
1213#define XM_DRAG_STYLE_IS_DROP_ONLY(n) ((n) == XM_DRAG_STYLE_DROP_ONLY \ 1539#define XM_DRAG_STYLE_IS_DROP_ONLY(n) ((n) == XM_DRAG_STYLE_DROP_ONLY \
1214 || (n) == XM_DRAG_STYLE_DROP_ONLY_REC) 1540 || (n) == XM_DRAG_STYLE_DROP_ONLY_REC)
@@ -1216,9 +1542,16 @@ typedef struct xm_top_level_leave_message
1216 || (n) == XM_DRAG_STYLE_DYNAMIC_REC \ 1542 || (n) == XM_DRAG_STYLE_DYNAMIC_REC \
1217 || (n) == XM_DRAG_STYLE_DYNAMIC_REC1) 1543 || (n) == XM_DRAG_STYLE_DYNAMIC_REC1)
1218 1544
1219#define XM_DROP_SITE_VALID 3 1545enum xm_drop_site_status
1220/* #define XM_DROP_SITE_INVALID 2 */ 1546 {
1221#define XM_DROP_SITE_NONE 1 1547 XM_DROP_SITE_VALID = 3,
1548 XM_DROP_SITE_INVALID = 2,
1549 XM_DROP_SITE_NONE = 1,
1550 };
1551
1552/* The version of the Motif drag-and-drop protocols that Emacs
1553 supports. */
1554#define XM_DRAG_PROTOCOL_VERSION 0
1222 1555
1223static uint8_t 1556static uint8_t
1224xm_side_effect_from_action (struct x_display_info *dpyinfo, Atom action) 1557xm_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)
1229 return XM_DRAG_MOVE; 1562 return XM_DRAG_MOVE;
1230 else if (action == dpyinfo->Xatom_XdndActionLink) 1563 else if (action == dpyinfo->Xatom_XdndActionLink)
1231 return XM_DRAG_LINK; 1564 return XM_DRAG_LINK;
1565 else if (action == dpyinfo->Xatom_XdndActionAsk)
1566 return x_dnd_first_motif_operation;
1232 1567
1233 return XM_DRAG_NOOP; 1568 return XM_DRAG_NOOP;
1234} 1569}
1235 1570
1571static uint8_t
1572xm_operations_from_actions (struct x_display_info *dpyinfo,
1573 Atom *ask_actions, int n_ask_actions)
1574{
1575 int i;
1576 uint8_t flags;
1577
1578 flags = 0;
1579
1580 for (i = 0; i < n_ask_actions; ++i)
1581 {
1582 if (ask_actions[i] == dpyinfo->Xatom_XdndActionCopy)
1583 flags |= XM_DRAG_COPY;
1584 else if (ask_actions[i] == dpyinfo->Xatom_XdndActionMove)
1585 flags |= XM_DRAG_MOVE;
1586 else if (ask_actions[i] == dpyinfo->Xatom_XdndActionLink)
1587 flags |= XM_DRAG_LINK;
1588 }
1589
1590 return flags;
1591}
1592
1236static int 1593static int
1237xm_read_targets_table_header (uint8_t *bytes, ptrdiff_t length, 1594xm_read_targets_table_header (uint8_t *bytes, ptrdiff_t length,
1238 xm_targets_table_header *header_return, 1595 xm_targets_table_header *header_return,
@@ -1396,6 +1753,9 @@ xm_write_drag_initiator_info (Display *dpy, Window wdesc,
1396static int 1753static int
1397xm_drag_window_error_handler (Display *display, XErrorEvent *event) 1754xm_drag_window_error_handler (Display *display, XErrorEvent *event)
1398{ 1755{
1756 if (xm_drag_window_error)
1757 *xm_drag_window_error = true;
1758
1399 return 0; 1759 return 0;
1400} 1760}
1401 1761
@@ -1404,7 +1764,7 @@ xm_drag_window_io_error_handler (Display *dpy)
1404{ 1764{
1405 /* DPY isn't created through GDK, so it doesn't matter if we don't 1765 /* DPY isn't created through GDK, so it doesn't matter if we don't
1406 crash here. */ 1766 crash here. */
1407 longjmp (x_dnd_disconnect_handler, 1); 1767 siglongjmp (x_dnd_disconnect_handler, 1);
1408} 1768}
1409 1769
1410static Window 1770static Window
@@ -1418,6 +1778,9 @@ xm_get_drag_window (struct x_display_info *dpyinfo)
1418 XSetWindowAttributes attrs; 1778 XSetWindowAttributes attrs;
1419 Display *temp_display; 1779 Display *temp_display;
1420 void *old_handler, *old_io_handler; 1780 void *old_handler, *old_io_handler;
1781 /* These are volatile because GCC mistakenly warns about them being
1782 clobbered by longjmp. */
1783 volatile bool error, created;
1421 1784
1422 drag_window = None; 1785 drag_window = None;
1423 rc = XGetWindowProperty (dpyinfo->display, dpyinfo->root_window, 1786 rc = XGetWindowProperty (dpyinfo->display, dpyinfo->root_window,
@@ -1473,6 +1836,9 @@ xm_get_drag_window (struct x_display_info *dpyinfo)
1473 return None; 1836 return None;
1474 } 1837 }
1475 1838
1839 error = false;
1840 xm_drag_window_error = &error;
1841
1476 XGrabServer (temp_display); 1842 XGrabServer (temp_display);
1477 XSetCloseDownMode (temp_display, RetainPermanent); 1843 XSetCloseDownMode (temp_display, RetainPermanent);
1478 1844
@@ -1483,6 +1849,9 @@ xm_get_drag_window (struct x_display_info *dpyinfo)
1483 _MOTIF_DRAG_WINDOW = XInternAtom (temp_display, 1849 _MOTIF_DRAG_WINDOW = XInternAtom (temp_display,
1484 "_MOTIF_DRAG_WINDOW", False); 1850 "_MOTIF_DRAG_WINDOW", False);
1485 1851
1852 if (error)
1853 goto give_up;
1854
1486 /* Some other program might've created a drag window between now 1855 /* Some other program might've created a drag window between now
1487 and when we first looked. Use that if it exists. */ 1856 and when we first looked. Use that if it exists. */
1488 1857
@@ -1500,8 +1869,12 @@ xm_get_drag_window (struct x_display_info *dpyinfo)
1500 if (tmp_data) 1869 if (tmp_data)
1501 XFree (tmp_data); 1870 XFree (tmp_data);
1502 1871
1872 error = false;
1873
1503 if (drag_window == None) 1874 if (drag_window == None)
1504 { 1875 {
1876 created = true;
1877
1505 attrs.override_redirect = True; 1878 attrs.override_redirect = True;
1506 drag_window = XCreateWindow (temp_display, DefaultRootWindow (temp_display), 1879 drag_window = XCreateWindow (temp_display, DefaultRootWindow (temp_display),
1507 -1, -1, 1, 1, 0, CopyFromParent, InputOnly, 1880 -1, -1, 1, 1, 0, CopyFromParent, InputOnly,
@@ -1510,8 +1883,41 @@ xm_get_drag_window (struct x_display_info *dpyinfo)
1510 _MOTIF_DRAG_WINDOW, XA_WINDOW, 32, PropModeReplace, 1883 _MOTIF_DRAG_WINDOW, XA_WINDOW, 32, PropModeReplace,
1511 (unsigned char *) &drag_window, 1); 1884 (unsigned char *) &drag_window, 1);
1512 } 1885 }
1886 else
1887 created = false;
1888
1889 /* Handle all errors now. */
1890 XSync (temp_display, False);
1513 1891
1892 give_up:
1893
1894 /* Some part of the drag window creation process failed, so
1895 punt. */
1896 if (error)
1897 {
1898 /* If the drag window was actually created, delete it now.
1899 Probably, a BadAlloc happened during the XChangeProperty
1900 request. */
1901 if (created)
1902 {
1903 if (drag_window != None)
1904 XDestroyWindow (temp_display, drag_window);
1905
1906 XDeleteProperty (temp_display, DefaultRootWindow (temp_display),
1907 _MOTIF_DRAG_WINDOW);
1908 }
1909
1910 drag_window = None;
1911 }
1912
1913 xm_drag_window_error = NULL;
1914
1915 /* FIXME: why does XCloseDisplay hang if SIGIO arrives and there
1916 are multiple displays? */
1917 unrequest_sigio ();
1514 XCloseDisplay (temp_display); 1918 XCloseDisplay (temp_display);
1919 request_sigio ();
1920
1515 XSetErrorHandler (old_handler); 1921 XSetErrorHandler (old_handler);
1516 XSetIOErrorHandler (old_io_handler); 1922 XSetIOErrorHandler (old_io_handler);
1517 1923
@@ -1633,7 +2039,7 @@ xm_setup_dnd_targets (struct x_display_info *dpyinfo,
1633 if (!rc) 2039 if (!rc)
1634 { 2040 {
1635 header.byte_order = XM_BYTE_ORDER_CUR_FIRST; 2041 header.byte_order = XM_BYTE_ORDER_CUR_FIRST;
1636 header.protocol = 0; 2042 header.protocol = XM_DRAG_PROTOCOL_VERSION;
1637 header.target_list_count = 1; 2043 header.target_list_count = 1;
1638 header.total_data_size = 8 + 2 + ntargets * 4; 2044 header.total_data_size = 8 + 2 + ntargets * 4;
1639 2045
@@ -1678,7 +2084,7 @@ xm_setup_dnd_targets (struct x_display_info *dpyinfo,
1678 xfree (recs); 2084 xfree (recs);
1679 2085
1680 header.byte_order = XM_BYTE_ORDER_CUR_FIRST; 2086 header.byte_order = XM_BYTE_ORDER_CUR_FIRST;
1681 header.protocol = 0; 2087 header.protocol = XM_DRAG_PROTOCOL_VERSION;
1682 header.target_list_count = 1; 2088 header.target_list_count = 1;
1683 header.total_data_size = 8 + 2 + ntargets * 4; 2089 header.total_data_size = 8 + 2 + ntargets * 4;
1684 2090
@@ -1715,10 +2121,17 @@ xm_setup_dnd_targets (struct x_display_info *dpyinfo,
1715 data format. To avoid confusing Motif when that happens, set 2121 data format. To avoid confusing Motif when that happens, set
1716 it back to 0. There will probably be no more updates to the 2122 it back to 0. There will probably be no more updates to the
1717 protocol either. */ 2123 protocol either. */
1718 header.protocol = 0; 2124 header.protocol = XM_DRAG_PROTOCOL_VERSION;
2125
2126 x_catch_errors (dpyinfo->display);
1719 xm_write_targets_table (dpyinfo->display, drag_window, 2127 xm_write_targets_table (dpyinfo->display, drag_window,
1720 dpyinfo->Xatom_MOTIF_DRAG_TARGETS, 2128 dpyinfo->Xatom_MOTIF_DRAG_TARGETS,
1721 &header, recs); 2129 &header, recs);
2130 /* Presumably we got a BadAlloc upon writing the targets
2131 table. */
2132 if (x_had_errors_p (dpyinfo->display))
2133 idx = -1;
2134 x_uncatch_errors_after_check ();
1722 } 2135 }
1723 2136
1724 XUngrabServer (dpyinfo->display); 2137 XUngrabServer (dpyinfo->display);
@@ -1745,7 +2158,7 @@ xm_setup_drag_info (struct x_display_info *dpyinfo,
1745 if (idx != -1) 2158 if (idx != -1)
1746 { 2159 {
1747 drag_initiator_info.byteorder = XM_BYTE_ORDER_CUR_FIRST; 2160 drag_initiator_info.byteorder = XM_BYTE_ORDER_CUR_FIRST;
1748 drag_initiator_info.protocol = 0; 2161 drag_initiator_info.protocol = XM_DRAG_PROTOCOL_VERSION;
1749 drag_initiator_info.table_index = idx; 2162 drag_initiator_info.table_index = idx;
1750 drag_initiator_info.selection = dpyinfo->Xatom_XdndSelection; 2163 drag_initiator_info.selection = dpyinfo->Xatom_XdndSelection;
1751 2164
@@ -1862,7 +2275,7 @@ xm_send_top_level_leave_message (struct x_display_info *dpyinfo, Window source,
1862 mmsg.byteorder = XM_BYTE_ORDER_CUR_FIRST; 2275 mmsg.byteorder = XM_BYTE_ORDER_CUR_FIRST;
1863 mmsg.side_effects = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo, 2276 mmsg.side_effects = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
1864 x_dnd_wanted_action), 2277 x_dnd_wanted_action),
1865 XM_DROP_SITE_NONE, XM_DRAG_NOOP, 2278 XM_DROP_SITE_NONE, x_dnd_motif_operations,
1866 XM_DROP_ACTION_DROP_CANCEL); 2279 XM_DROP_ACTION_DROP_CANCEL);
1867 mmsg.timestamp = dmsg->timestamp; 2280 mmsg.timestamp = dmsg->timestamp;
1868 mmsg.x = 65535; 2281 mmsg.x = 65535;
@@ -1927,6 +2340,44 @@ xm_read_drop_start_reply (const XEvent *msg, xm_drop_start_reply *reply)
1927} 2340}
1928 2341
1929static int 2342static int
2343xm_read_drop_start_message (const XEvent *msg,
2344 xm_drop_start_message *dmsg)
2345{
2346 const uint8_t *data;
2347
2348 data = (const uint8_t *) &msg->xclient.data.b[0];
2349
2350 if ((XM_DRAG_REASON_ORIGINATOR (data[0])
2351 != XM_DRAG_ORIGINATOR_INITIATOR)
2352 || (XM_DRAG_REASON_CODE (data[0])
2353 != XM_DRAG_REASON_DROP_START))
2354 return 1;
2355
2356 dmsg->reason = *(data++);
2357 dmsg->byte_order = *(data++);
2358 dmsg->side_effects = *(uint16_t *) data;
2359 dmsg->timestamp = *(uint32_t *) (data + 2);
2360 dmsg->x = *(uint16_t *) (data + 6);
2361 dmsg->y = *(uint16_t *) (data + 8);
2362 dmsg->index_atom = *(uint32_t *) (data + 10);
2363 dmsg->source_window = *(uint32_t *) (data + 14);
2364
2365 if (dmsg->byte_order != XM_BYTE_ORDER_CUR_FIRST)
2366 {
2367 SWAPCARD16 (dmsg->side_effects);
2368 SWAPCARD32 (dmsg->timestamp);
2369 SWAPCARD16 (dmsg->x);
2370 SWAPCARD16 (dmsg->y);
2371 SWAPCARD32 (dmsg->index_atom);
2372 SWAPCARD32 (dmsg->source_window);
2373 }
2374
2375 dmsg->byte_order = XM_BYTE_ORDER_CUR_FIRST;
2376
2377 return 0;
2378}
2379
2380static int
1930xm_read_drag_receiver_info (struct x_display_info *dpyinfo, 2381xm_read_drag_receiver_info (struct x_display_info *dpyinfo,
1931 Window wdesc, xm_drag_receiver_info *rec) 2382 Window wdesc, xm_drag_receiver_info *rec)
1932{ 2383{
@@ -1955,6 +2406,9 @@ xm_read_drag_receiver_info (struct x_display_info *dpyinfo,
1955 { 2406 {
1956 data = (uint8_t *) tmp_data; 2407 data = (uint8_t *) tmp_data;
1957 2408
2409 if (data[1] > XM_DRAG_PROTOCOL_VERSION)
2410 return 1;
2411
1958 rec->byteorder = data[0]; 2412 rec->byteorder = data[0];
1959 rec->protocol = data[1]; 2413 rec->protocol = data[1];
1960 rec->protocol_style = data[2]; 2414 rec->protocol_style = data[2];
@@ -1979,6 +2433,40 @@ xm_read_drag_receiver_info (struct x_display_info *dpyinfo,
1979 return !rc; 2433 return !rc;
1980} 2434}
1981 2435
2436static int
2437xm_read_drag_motion_message (const XEvent *msg,
2438 xm_drag_motion_message *dmsg)
2439{
2440 const uint8_t *data;
2441
2442 data = (const uint8_t *) &msg->xclient.data.b[0];
2443
2444 if ((XM_DRAG_REASON_CODE (data[0])
2445 != XM_DRAG_REASON_DRAG_MOTION)
2446 || (XM_DRAG_REASON_ORIGINATOR (data[0])
2447 != XM_DRAG_ORIGINATOR_INITIATOR))
2448 return 1;
2449
2450 dmsg->reason = *(data++);
2451 dmsg->byteorder = *(data++);
2452 dmsg->side_effects = *(uint16_t *) data;
2453 dmsg->timestamp = *(uint32_t *) (data + 2);
2454 dmsg->x = *(uint16_t *) (data + 6);
2455 dmsg->y = *(uint16_t *) (data + 8);
2456
2457 if (dmsg->byteorder != XM_BYTE_ORDER_CUR_FIRST)
2458 {
2459 SWAPCARD16 (dmsg->side_effects);
2460 SWAPCARD32 (dmsg->timestamp);
2461 SWAPCARD16 (dmsg->x);
2462 SWAPCARD16 (dmsg->y);
2463 }
2464
2465 dmsg->byteorder = XM_BYTE_ORDER_CUR_FIRST;
2466
2467 return 0;
2468}
2469
1982static void 2470static void
1983x_dnd_send_xm_leave_for_drop (struct x_display_info *dpyinfo, 2471x_dnd_send_xm_leave_for_drop (struct x_display_info *dpyinfo,
1984 struct frame *f, Window wdesc, 2472 struct frame *f, Window wdesc,
@@ -1999,23 +2487,57 @@ x_dnd_send_xm_leave_for_drop (struct x_display_info *dpyinfo,
1999} 2487}
2000 2488
2001static void 2489static void
2002x_dnd_free_toplevels (void) 2490x_dnd_free_toplevels (bool display_alive)
2003{ 2491{
2004 struct x_client_list_window *last; 2492 struct x_client_list_window *last;
2005 struct x_client_list_window *tem = x_dnd_toplevels; 2493 struct x_client_list_window *tem = x_dnd_toplevels;
2494 ptrdiff_t n_windows, i, buffer_size;
2495 Window *destroy_windows;
2496 unsigned long *prev_masks;
2497 specpdl_ref count;
2498 Display *dpy;
2499
2500 if (!x_dnd_toplevels)
2501 /* Probably called inside an IO error handler. */
2502 return;
2503
2504 /* Pacify GCC. */
2505 prev_masks = NULL;
2506 destroy_windows = NULL;
2006 2507
2508 if (display_alive)
2509 {
2510 buffer_size = 1024;
2511 destroy_windows = xmalloc (sizeof *destroy_windows
2512 * buffer_size);
2513 prev_masks = xmalloc (sizeof *prev_masks *
2514 buffer_size);
2515 n_windows = 0;
2516 }
2517
2518 block_input ();
2007 while (tem) 2519 while (tem)
2008 { 2520 {
2009 last = tem; 2521 last = tem;
2010 tem = tem->next; 2522 tem = tem->next;
2011 2523
2012 x_catch_errors (last->dpy); 2524 if (display_alive)
2013 XSelectInput (last->dpy, last->window, 2525 {
2014 last->previous_event_mask); 2526 if (++n_windows >= buffer_size)
2015#ifdef HAVE_XSHAPE 2527 {
2016 XShapeSelectInput (last->dpy, last->window, None); 2528 buffer_size += 1024;
2017#endif 2529 destroy_windows
2018 x_uncatch_errors (); 2530 = xrealloc (destroy_windows, (sizeof *destroy_windows
2531 * buffer_size));
2532 prev_masks
2533 = xrealloc (prev_masks, (sizeof *prev_masks
2534 * buffer_size));
2535 }
2536
2537 dpy = last->dpy;
2538 prev_masks[n_windows - 1] = last->previous_event_mask;
2539 destroy_windows[n_windows - 1] = last->window;
2540 }
2019 2541
2020#ifdef HAVE_XSHAPE 2542#ifdef HAVE_XSHAPE
2021 if (last->n_input_rects != -1) 2543 if (last->n_input_rects != -1)
@@ -2028,6 +2550,34 @@ x_dnd_free_toplevels (void)
2028 } 2550 }
2029 2551
2030 x_dnd_toplevels = NULL; 2552 x_dnd_toplevels = NULL;
2553
2554 if (!display_alive)
2555 {
2556 unblock_input ();
2557 return;
2558 }
2559
2560 count = SPECPDL_INDEX ();
2561 record_unwind_protect_ptr (xfree, destroy_windows);
2562 record_unwind_protect_ptr (xfree, prev_masks);
2563
2564 if (display_alive)
2565 {
2566 x_catch_errors (dpy);
2567
2568 for (i = 0; i < n_windows; ++i)
2569 {
2570 XSelectInput (dpy, destroy_windows[i], prev_masks[i]);
2571#ifdef HAVE_XSHAPE
2572 XShapeSelectInput (dpy, destroy_windows[i], None);
2573#endif
2574 }
2575
2576 x_uncatch_errors ();
2577 }
2578
2579 unbind_to (count, Qnil);
2580 unblock_input ();
2031} 2581}
2032 2582
2033static int 2583static int
@@ -2102,27 +2652,29 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
2102 toplevels = (Window *) data; 2652 toplevels = (Window *) data;
2103 2653
2104#ifdef USE_XCB 2654#ifdef USE_XCB
2655 USE_SAFE_ALLOCA;
2656
2105 window_attribute_cookies 2657 window_attribute_cookies
2106 = alloca (sizeof *window_attribute_cookies * nitems); 2658 = SAFE_ALLOCA (sizeof *window_attribute_cookies * nitems);
2107 translate_coordinate_cookies 2659 translate_coordinate_cookies
2108 = alloca (sizeof *translate_coordinate_cookies * nitems); 2660 = SAFE_ALLOCA (sizeof *translate_coordinate_cookies * nitems);
2109 get_property_cookies 2661 get_property_cookies
2110 = alloca (sizeof *get_property_cookies * nitems); 2662 = SAFE_ALLOCA (sizeof *get_property_cookies * nitems);
2111 xm_property_cookies 2663 xm_property_cookies
2112 = alloca (sizeof *xm_property_cookies * nitems); 2664 = SAFE_ALLOCA (sizeof *xm_property_cookies * nitems);
2113 extent_property_cookies 2665 extent_property_cookies
2114 = alloca (sizeof *extent_property_cookies * nitems); 2666 = SAFE_ALLOCA (sizeof *extent_property_cookies * nitems);
2115 get_geometry_cookies 2667 get_geometry_cookies
2116 = alloca (sizeof *get_geometry_cookies * nitems); 2668 = SAFE_ALLOCA (sizeof *get_geometry_cookies * nitems);
2117 2669
2118#ifdef HAVE_XCB_SHAPE 2670#ifdef HAVE_XCB_SHAPE
2119 bounding_rect_cookies 2671 bounding_rect_cookies
2120 = alloca (sizeof *bounding_rect_cookies * nitems); 2672 = SAFE_ALLOCA (sizeof *bounding_rect_cookies * nitems);
2121#endif 2673#endif
2122 2674
2123#ifdef HAVE_XCB_SHAPE_INPUT_RECTS 2675#ifdef HAVE_XCB_SHAPE_INPUT_RECTS
2124 input_rect_cookies 2676 input_rect_cookies
2125 = alloca (sizeof *input_rect_cookies * nitems); 2677 = SAFE_ALLOCA (sizeof *input_rect_cookies * nitems);
2126#endif 2678#endif
2127 2679
2128 for (i = 0; i < nitems; ++i) 2680 for (i = 0; i < nitems; ++i)
@@ -2353,7 +2905,9 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
2353 && xcb_get_property_value_length (xm_property_reply) >= 4) 2905 && xcb_get_property_value_length (xm_property_reply) >= 4)
2354 { 2906 {
2355 xmdata = xcb_get_property_value (xm_property_reply); 2907 xmdata = xcb_get_property_value (xm_property_reply);
2356 tem->xm_protocol_style = xmdata[2]; 2908
2909 if (xmdata[1] <= XM_DRAG_PROTOCOL_VERSION)
2910 tem->xm_protocol_style = xmdata[2];
2357 } 2911 }
2358#endif 2912#endif
2359 2913
@@ -2509,7 +3063,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
2509 } 3063 }
2510 3064
2511 /* And the common case where there is no input rect and the 3065 /* And the common case where there is no input rect and the
2512 bouding rect equals the window dimensions. */ 3066 bounding rect equals the window dimensions. */
2513 3067
2514 if (tem->n_input_rects == -1 3068 if (tem->n_input_rects == -1
2515 && tem->n_bounding_rects == 1 3069 && tem->n_bounding_rects == 1
@@ -2602,6 +3156,13 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
2602#endif 3156#endif
2603 } 3157 }
2604 3158
3159#ifdef USE_XCB
3160 SAFE_FREE ();
3161#endif
3162
3163 if (data)
3164 XFree (data);
3165
2605 return 0; 3166 return 0;
2606} 3167}
2607 3168
@@ -2611,7 +3172,7 @@ x_dnd_io_error_handler (Display *display)
2611#ifdef USE_GTK 3172#ifdef USE_GTK
2612 emacs_abort (); 3173 emacs_abort ();
2613#else 3174#else
2614 longjmp (x_dnd_disconnect_handler, 1); 3175 siglongjmp (x_dnd_disconnect_handler, 1);
2615#endif 3176#endif
2616} 3177}
2617 3178
@@ -2978,7 +3539,6 @@ x_dnd_do_unsupported_drop (struct x_display_info *dpyinfo,
2978 int dest_x, dest_y; 3539 int dest_x, dest_y;
2979 Window child_return, child; 3540 Window child_return, child;
2980 3541
2981 event.xbutton.type = ButtonPress;
2982 event.xbutton.serial = 0; 3542 event.xbutton.serial = 0;
2983 event.xbutton.send_event = True; 3543 event.xbutton.send_event = True;
2984 event.xbutton.display = dpyinfo->display; 3544 event.xbutton.display = dpyinfo->display;
@@ -2992,39 +3552,37 @@ x_dnd_do_unsupported_drop (struct x_display_info *dpyinfo,
2992 dest_x = root_x; 3552 dest_x = root_x;
2993 dest_y = root_y; 3553 dest_y = root_y;
2994 3554
2995 while (XTranslateCoordinates (dpyinfo->display, child, 3555 while (XTranslateCoordinates (dpyinfo->display, dpyinfo->root_window,
2996 child, root_x, root_y, &dest_x, 3556 child, root_x, root_y, &dest_x, &dest_y,
2997 &dest_y, &child_return) 3557 &child_return)
2998 && child_return != None 3558 && child_return != None)
2999 && XTranslateCoordinates (dpyinfo->display, child, 3559 child = child_return;
3000 child_return, root_x, root_y,
3001 &dest_x, &dest_y, &child))
3002 {
3003 child = child_return;
3004 root_x = dest_x;
3005 root_y = dest_y;
3006 }
3007 3560
3008 if (CONSP (value)) 3561 if (CONSP (value))
3009 x_own_selection (QPRIMARY, Fnth (make_fixnum (1), value), 3562 x_own_selection (QPRIMARY, Fnth (make_fixnum (1), value),
3010 frame); 3563 frame);
3011 else 3564 else
3012 x_own_selection (QPRIMARY, Qnil, frame); 3565 error ("Lost ownership of XdndSelection");
3013 3566
3014 event.xbutton.window = child; 3567 event.xbutton.window = child;
3568 event.xbutton.subwindow = None;
3015 event.xbutton.x = dest_x; 3569 event.xbutton.x = dest_x;
3016 event.xbutton.y = dest_y; 3570 event.xbutton.y = dest_y;
3017 event.xbutton.state = 0; 3571 event.xbutton.state = 0;
3018 event.xbutton.button = 2; 3572 event.xbutton.button = 2;
3019 event.xbutton.same_screen = True; 3573 event.xbutton.same_screen = True;
3020 event.xbutton.time = before + 1;
3021 event.xbutton.time = before + 2;
3022 3574
3023 x_set_pending_dnd_time (before); 3575 x_set_pending_dnd_time (before);
3024 3576
3577 event.xbutton.type = ButtonPress;
3578 event.xbutton.time = before + 1;
3579
3025 XSendEvent (dpyinfo->display, child, 3580 XSendEvent (dpyinfo->display, child,
3026 True, ButtonPressMask, &event); 3581 True, ButtonPressMask, &event);
3582
3027 event.xbutton.type = ButtonRelease; 3583 event.xbutton.type = ButtonRelease;
3584 event.xbutton.time = before + 2;
3585
3028 XSendEvent (dpyinfo->display, child, 3586 XSendEvent (dpyinfo->display, child,
3029 True, ButtonReleaseMask, &event); 3587 True, ButtonReleaseMask, &event);
3030 3588
@@ -3057,19 +3615,20 @@ x_dnd_send_unsupported_drop (struct x_display_info *dpyinfo, Window target_windo
3057 XFree (atom_names[i - 1]); 3615 XFree (atom_names[i - 1]);
3058 } 3616 }
3059 3617
3060 name = XGetAtomName (dpyinfo->display, 3618 name = x_get_atom_name (dpyinfo, x_dnd_wanted_action,
3061 x_dnd_wanted_action); 3619 NULL);
3062 3620
3063 if (name) 3621 if (name)
3064 { 3622 {
3065 arg = intern (name); 3623 arg = intern (name);
3066 XFree (name); 3624 xfree (name);
3067 } 3625 }
3068 else 3626 else
3069 arg = Qnil; 3627 arg = Qnil;
3070 3628
3071 ie.kind = UNSUPPORTED_DROP_EVENT; 3629 ie.kind = UNSUPPORTED_DROP_EVENT;
3072 ie.code = (unsigned) target_window; 3630 ie.code = (unsigned) target_window;
3631 ie.modifiers = x_dnd_unsupported_event_level;
3073 ie.arg = list3 (assq_no_quit (QXdndSelection, 3632 ie.arg = list3 (assq_no_quit (QXdndSelection,
3074 dpyinfo->terminal->Vselection_alist), 3633 dpyinfo->terminal->Vselection_alist),
3075 targets, arg); 3634 targets, arg);
@@ -3085,16 +3644,20 @@ x_dnd_send_unsupported_drop (struct x_display_info *dpyinfo, Window target_windo
3085static Window 3644static Window
3086x_dnd_get_target_window (struct x_display_info *dpyinfo, 3645x_dnd_get_target_window (struct x_display_info *dpyinfo,
3087 int root_x, int root_y, int *proto_out, 3646 int root_x, int root_y, int *proto_out,
3088 int *motif_out, Window *toplevel_out) 3647 int *motif_out, Window *toplevel_out,
3648 bool *was_frame)
3089{ 3649{
3090 Window child_return, child, dummy, proxy; 3650 Window child_return, child, proxy;
3091 int dest_x_return, dest_y_return, rc, proto, motif; 3651 int dest_x_return, dest_y_return, rc, proto, motif;
3652 int parent_x, parent_y;
3092 bool extents_p; 3653 bool extents_p;
3093#if defined HAVE_XCOMPOSITE && (XCOMPOSITE_MAJOR > 0 || XCOMPOSITE_MINOR > 2) 3654#if defined HAVE_XCOMPOSITE && (XCOMPOSITE_MAJOR > 0 || XCOMPOSITE_MINOR > 2)
3094 Window overlay_window; 3655 Window overlay_window;
3095 XWindowAttributes attrs; 3656 XWindowAttributes attrs;
3096#endif 3657#endif
3097 int wmstate; 3658 int wmstate;
3659 struct frame *tooltip, *f;
3660 bool unrelated;
3098 3661
3099 child_return = dpyinfo->root_window; 3662 child_return = dpyinfo->root_window;
3100 dest_x_return = root_x; 3663 dest_x_return = root_x;
@@ -3103,6 +3666,7 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo,
3103 proto = -1; 3666 proto = -1;
3104 *motif_out = XM_DRAG_STYLE_NONE; 3667 *motif_out = XM_DRAG_STYLE_NONE;
3105 *toplevel_out = None; 3668 *toplevel_out = None;
3669 *was_frame = false;
3106 3670
3107 if (x_dnd_use_toplevels) 3671 if (x_dnd_use_toplevels)
3108 { 3672 {
@@ -3115,10 +3679,21 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo,
3115 && FRAME_X_WINDOW (x_dnd_frame) == child) 3679 && FRAME_X_WINDOW (x_dnd_frame) == child)
3116 *motif_out = XM_DRAG_STYLE_NONE; 3680 *motif_out = XM_DRAG_STYLE_NONE;
3117 3681
3682 f = x_top_window_to_frame (dpyinfo, child);
3683
3118 *toplevel_out = child; 3684 *toplevel_out = child;
3119 3685
3120 if (child != None) 3686 if (child != None)
3121 { 3687 {
3688 if (f)
3689 {
3690 *was_frame = true;
3691 *proto_out = -1;
3692 *motif_out = XM_DRAG_STYLE_NONE;
3693
3694 return child;
3695 }
3696
3122#ifndef USE_XCB 3697#ifndef USE_XCB
3123 proxy = x_dnd_get_window_proxy (dpyinfo, child); 3698 proxy = x_dnd_get_window_proxy (dpyinfo, child);
3124#else 3699#else
@@ -3161,10 +3736,13 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo,
3161 dpyinfo->Xatom_NET_WM_CM_Sn) != None) 3736 dpyinfo->Xatom_NET_WM_CM_Sn) != None)
3162 { 3737 {
3163 x_catch_errors (dpyinfo->display); 3738 x_catch_errors (dpyinfo->display);
3739 XGrabServer (dpyinfo->display);
3164 overlay_window = XCompositeGetOverlayWindow (dpyinfo->display, 3740 overlay_window = XCompositeGetOverlayWindow (dpyinfo->display,
3165 dpyinfo->root_window); 3741 dpyinfo->root_window);
3166 XCompositeReleaseOverlayWindow (dpyinfo->display, 3742 XCompositeReleaseOverlayWindow (dpyinfo->display,
3167 dpyinfo->root_window); 3743 dpyinfo->root_window);
3744 XUngrabServer (dpyinfo->display);
3745
3168 if (!x_had_errors_p (dpyinfo->display)) 3746 if (!x_had_errors_p (dpyinfo->display))
3169 { 3747 {
3170 XGetWindowAttributes (dpyinfo->display, overlay_window, &attrs); 3748 XGetWindowAttributes (dpyinfo->display, overlay_window, &attrs);
@@ -3222,13 +3800,13 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo,
3222 while (child_return != None) 3800 while (child_return != None)
3223 { 3801 {
3224 child = child_return; 3802 child = child_return;
3803 parent_x = dest_x_return;
3804 parent_y = dest_y_return;
3225 3805
3226 x_catch_errors (dpyinfo->display); 3806 x_catch_errors (dpyinfo->display);
3227 rc = XTranslateCoordinates (dpyinfo->display, 3807 rc = XTranslateCoordinates (dpyinfo->display, dpyinfo->root_window,
3228 child_return, child_return, 3808 child_return, root_x, root_y, &dest_x_return,
3229 dest_x_return, dest_y_return, 3809 &dest_y_return, &child_return);
3230 &dest_x_return, &dest_y_return,
3231 &child_return);
3232 3810
3233 if (x_had_errors_p (dpyinfo->display) || !rc) 3811 if (x_had_errors_p (dpyinfo->display) || !rc)
3234 { 3812 {
@@ -3238,6 +3816,35 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo,
3238 3816
3239 if (child_return) 3817 if (child_return)
3240 { 3818 {
3819 /* If child_return is a tooltip frame, look beneath it. We
3820 never want to drop anything onto a tooltip frame. */
3821
3822 tooltip = x_tooltip_window_to_frame (dpyinfo, child_return,
3823 &unrelated);
3824
3825 if (tooltip || unrelated)
3826 child_return = x_get_window_below (dpyinfo->display, child_return,
3827 parent_x, parent_y, &dest_x_return,
3828 &dest_y_return);
3829
3830 if (!child_return)
3831 {
3832 x_uncatch_errors ();
3833 break;
3834 }
3835
3836 f = x_top_window_to_frame (dpyinfo, child_return);
3837
3838 if (f)
3839 {
3840 *proto_out = -1;
3841 *motif_out = XM_DRAG_STYLE_NONE;
3842 *toplevel_out = child_return;
3843 *was_frame = true;
3844
3845 return child_return;
3846 }
3847
3241 if (x_dnd_get_wm_state_and_proto (dpyinfo, child_return, 3848 if (x_dnd_get_wm_state_and_proto (dpyinfo, child_return,
3242 &wmstate, &proto, &motif, 3849 &wmstate, &proto, &motif,
3243 &proxy) 3850 &proxy)
@@ -3266,23 +3873,9 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo,
3266 return proxy; 3873 return proxy;
3267 } 3874 }
3268 } 3875 }
3269
3270 rc = XTranslateCoordinates (dpyinfo->display,
3271 child, child_return,
3272 dest_x_return, dest_y_return,
3273 &dest_x_return, &dest_y_return,
3274 &dummy);
3275
3276 if (x_had_errors_p (dpyinfo->display) || !rc)
3277 {
3278 x_uncatch_errors_after_check ();
3279 *proto_out = -1;
3280 *toplevel_out = dpyinfo->root_window;
3281 return None;
3282 }
3283 } 3876 }
3284 3877
3285 x_uncatch_errors_after_check (); 3878 x_uncatch_errors ();
3286 } 3879 }
3287 3880
3288#if defined HAVE_XCOMPOSITE && (XCOMPOSITE_MAJOR > 0 || XCOMPOSITE_MINOR > 2) 3881#if defined HAVE_XCOMPOSITE && (XCOMPOSITE_MAJOR > 0 || XCOMPOSITE_MINOR > 2)
@@ -3319,10 +3912,13 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo,
3319 dpyinfo->Xatom_NET_WM_CM_Sn) != None) 3912 dpyinfo->Xatom_NET_WM_CM_Sn) != None)
3320 { 3913 {
3321 x_catch_errors (dpyinfo->display); 3914 x_catch_errors (dpyinfo->display);
3915 XGrabServer (dpyinfo->display);
3322 overlay_window = XCompositeGetOverlayWindow (dpyinfo->display, 3916 overlay_window = XCompositeGetOverlayWindow (dpyinfo->display,
3323 dpyinfo->root_window); 3917 dpyinfo->root_window);
3324 XCompositeReleaseOverlayWindow (dpyinfo->display, 3918 XCompositeReleaseOverlayWindow (dpyinfo->display,
3325 dpyinfo->root_window); 3919 dpyinfo->root_window);
3920 XUngrabServer (dpyinfo->display);
3921
3326 if (!x_had_errors_p (dpyinfo->display)) 3922 if (!x_had_errors_p (dpyinfo->display))
3327 { 3923 {
3328 XGetWindowAttributes (dpyinfo->display, overlay_window, &attrs); 3924 XGetWindowAttributes (dpyinfo->display, overlay_window, &attrs);
@@ -3456,9 +4052,6 @@ x_dnd_send_enter (struct frame *f, Window target, int supported)
3456 int i; 4052 int i;
3457 XEvent msg; 4053 XEvent msg;
3458 4054
3459 if (x_top_window_to_frame (dpyinfo, target))
3460 return;
3461
3462 msg.xclient.type = ClientMessage; 4055 msg.xclient.type = ClientMessage;
3463 msg.xclient.message_type = dpyinfo->Xatom_XdndEnter; 4056 msg.xclient.message_type = dpyinfo->Xatom_XdndEnter;
3464 msg.xclient.format = 32; 4057 msg.xclient.format = 32;
@@ -3474,12 +4067,16 @@ x_dnd_send_enter (struct frame *f, Window target, int supported)
3474 for (i = 0; i < min (3, x_dnd_n_targets); ++i) 4067 for (i = 0; i < min (3, x_dnd_n_targets); ++i)
3475 msg.xclient.data.l[i + 2] = x_dnd_targets[i]; 4068 msg.xclient.data.l[i + 2] = x_dnd_targets[i];
3476 4069
3477 if (x_dnd_n_targets > 3) 4070 if (x_dnd_n_targets > 3 && !x_dnd_init_type_lists)
3478 XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 4071 XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3479 dpyinfo->Xatom_XdndTypeList, XA_ATOM, 32, 4072 dpyinfo->Xatom_XdndTypeList, XA_ATOM, 32,
3480 PropModeReplace, (unsigned char *) x_dnd_targets, 4073 PropModeReplace, (unsigned char *) x_dnd_targets,
3481 x_dnd_n_targets); 4074 x_dnd_n_targets);
3482 4075
4076 /* Now record that the type list has already been set (if required),
4077 so we don't have to set it again. */
4078 x_dnd_init_type_lists = true;
4079
3483 x_catch_errors (dpyinfo->display); 4080 x_catch_errors (dpyinfo->display);
3484 XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); 4081 XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg);
3485 x_uncatch_errors (); 4082 x_uncatch_errors ();
@@ -3493,23 +4090,6 @@ x_dnd_send_position (struct frame *f, Window target, int supported,
3493{ 4090{
3494 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); 4091 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
3495 XEvent msg; 4092 XEvent msg;
3496 struct frame *target_frame;
3497 int dest_x, dest_y;
3498 Window child_return;
3499
3500 target_frame = x_top_window_to_frame (dpyinfo, target);
3501
3502 if (target_frame && XTranslateCoordinates (dpyinfo->display,
3503 dpyinfo->root_window,
3504 FRAME_X_WINDOW (target_frame),
3505 root_x, root_y, &dest_x,
3506 &dest_y, &child_return))
3507 {
3508 x_dnd_movement_frame = target_frame;
3509 x_dnd_movement_x = dest_x;
3510 x_dnd_movement_y = dest_y;
3511 return;
3512 }
3513 4093
3514 if (target == x_dnd_mouse_rect_target 4094 if (target == x_dnd_mouse_rect_target
3515 && x_dnd_mouse_rect.width 4095 && x_dnd_mouse_rect.width
@@ -3533,7 +4113,7 @@ x_dnd_send_position (struct frame *f, Window target, int supported,
3533 4113
3534 if (supported >= 5) 4114 if (supported >= 5)
3535 { 4115 {
3536 if (button >= 4 && button <= 8) 4116 if (button >= 4 && button <= 7)
3537 { 4117 {
3538 msg.xclient.data.l[1] |= (1 << 9); 4118 msg.xclient.data.l[1] |= (1 << 9);
3539 msg.xclient.data.l[1] |= (button - 4) << 7; 4119 msg.xclient.data.l[1] |= (button - 4) << 7;
@@ -3567,9 +4147,6 @@ x_dnd_send_leave (struct frame *f, Window target)
3567 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); 4147 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
3568 XEvent msg; 4148 XEvent msg;
3569 4149
3570 if (x_top_window_to_frame (dpyinfo, target))
3571 return;
3572
3573 msg.xclient.type = ClientMessage; 4150 msg.xclient.type = ClientMessage;
3574 msg.xclient.message_type = dpyinfo->Xatom_XdndLeave; 4151 msg.xclient.message_type = dpyinfo->Xatom_XdndLeave;
3575 msg.xclient.format = 32; 4152 msg.xclient.format = 32;
@@ -3589,74 +4166,17 @@ static bool
3589x_dnd_send_drop (struct frame *f, Window target, Time timestamp, 4166x_dnd_send_drop (struct frame *f, Window target, Time timestamp,
3590 int supported) 4167 int supported)
3591{ 4168{
3592 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); 4169 struct x_display_info *dpyinfo;
3593 XEvent msg; 4170 XEvent msg;
3594 struct input_event ie;
3595 struct frame *self_frame;
3596 int root_x, root_y, win_x, win_y, i;
3597 unsigned int mask;
3598 Window root, child;
3599 Lisp_Object lval;
3600 char **atom_names;
3601 char *name;
3602
3603 self_frame = x_top_window_to_frame (dpyinfo, target);
3604 4171
3605 if (self_frame) 4172 if (x_dnd_action == None)
3606 {
3607 if (!x_dnd_allow_current_frame
3608 && self_frame == x_dnd_frame)
3609 return false;
3610
3611 /* Send a special drag-and-drop event when dropping on top of an
3612 Emacs frame to avoid all the overhead involved with sending
3613 client events. */
3614 EVENT_INIT (ie);
3615
3616 if (XQueryPointer (dpyinfo->display, FRAME_X_WINDOW (self_frame),
3617 &root, &child, &root_x, &root_y, &win_x, &win_y,
3618 &mask))
3619 {
3620 ie.kind = DRAG_N_DROP_EVENT;
3621 XSETFRAME (ie.frame_or_window, self_frame);
3622
3623 lval = Qnil;
3624 atom_names = alloca (x_dnd_n_targets * sizeof *atom_names);
3625 name = XGetAtomName (dpyinfo->display, x_dnd_wanted_action);
3626
3627 if (!XGetAtomNames (dpyinfo->display, x_dnd_targets,
3628 x_dnd_n_targets, atom_names))
3629 {
3630 XFree (name);
3631 return false;
3632 }
3633
3634 for (i = x_dnd_n_targets; i != 0; --i)
3635 {
3636 lval = Fcons (intern (atom_names[i - 1]), lval);
3637 XFree (atom_names[i - 1]);
3638 }
3639
3640 lval = Fcons (intern (name), lval);
3641 lval = Fcons (QXdndSelection, lval);
3642 ie.arg = lval;
3643 ie.timestamp = CurrentTime;
3644
3645 XSETINT (ie.x, win_x);
3646 XSETINT (ie.y, win_y);
3647
3648 XFree (name);
3649 kbd_buffer_store_event (&ie);
3650
3651 return false;
3652 }
3653 }
3654 else if (x_dnd_action == None)
3655 { 4173 {
3656 x_dnd_send_leave (f, target); 4174 x_dnd_send_leave (f, target);
3657 return false; 4175 return false;
3658 } 4176 }
3659 4177
4178 dpyinfo = FRAME_DISPLAY_INFO (f);
4179
3660 msg.xclient.type = ClientMessage; 4180 msg.xclient.type = ClientMessage;
3661 msg.xclient.message_type = dpyinfo->Xatom_XdndDrop; 4181 msg.xclient.message_type = dpyinfo->Xatom_XdndDrop;
3662 msg.xclient.format = 32; 4182 msg.xclient.format = 32;
@@ -3676,14 +4196,48 @@ x_dnd_send_drop (struct frame *f, Window target, Time timestamp,
3676 return true; 4196 return true;
3677} 4197}
3678 4198
3679void 4199static void
3680x_set_dnd_targets (Atom *targets, int ntargets) 4200x_set_dnd_targets (Atom *targets, int ntargets)
3681{ 4201{
3682 if (x_dnd_targets) 4202 if (x_dnd_targets)
3683 xfree (x_dnd_targets); 4203 xfree (x_dnd_targets);
3684 4204
3685 x_dnd_targets = targets; 4205 block_input ();
4206 x_dnd_targets = xmalloc (sizeof *targets * ntargets);
3686 x_dnd_n_targets = ntargets; 4207 x_dnd_n_targets = ntargets;
4208
4209 memcpy (x_dnd_targets, targets,
4210 sizeof *targets * ntargets);
4211 unblock_input ();
4212}
4213
4214static void
4215x_free_dnd_targets (void)
4216{
4217 if (!x_dnd_targets)
4218 return;
4219
4220 xfree (x_dnd_targets);
4221 x_dnd_targets = NULL;
4222 x_dnd_n_targets = 0;
4223}
4224
4225static void
4226x_clear_dnd_monitors (void)
4227{
4228 x_dnd_monitors = Qnil;
4229}
4230
4231static void
4232x_free_dnd_toplevels (void)
4233{
4234 if (!x_dnd_use_toplevels || !x_dnd_toplevels)
4235 return;
4236
4237 /* If the display is deleted, x_dnd_toplevels will already be
4238 NULL, so we can always assume the display is alive here. */
4239
4240 x_dnd_free_toplevels (true);
3687} 4241}
3688 4242
3689static void 4243static void
@@ -3716,9 +4270,7 @@ x_dnd_cleanup_drag_and_drop (void *frame)
3716 dmsg.side_effects 4270 dmsg.side_effects
3717 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (FRAME_DISPLAY_INFO (f), 4271 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
3718 x_dnd_wanted_action), 4272 x_dnd_wanted_action),
3719 XM_DROP_SITE_VALID, 4273 XM_DROP_SITE_VALID, x_dnd_motif_operations,
3720 xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
3721 x_dnd_wanted_action),
3722 XM_DROP_ACTION_DROP_CANCEL); 4274 XM_DROP_ACTION_DROP_CANCEL);
3723 dmsg.x = 0; 4275 dmsg.x = 0;
3724 dmsg.y = 0; 4276 dmsg.y = 0;
@@ -3739,12 +4291,8 @@ x_dnd_cleanup_drag_and_drop (void *frame)
3739 x_dnd_in_progress = false; 4291 x_dnd_in_progress = false;
3740 } 4292 }
3741 4293
3742 x_set_dnd_targets (NULL, 0);
3743 x_dnd_waiting_for_finish = false; 4294 x_dnd_waiting_for_finish = false;
3744 4295
3745 if (x_dnd_use_toplevels)
3746 x_dnd_free_toplevels ();
3747
3748 FRAME_DISPLAY_INFO (f)->grabbed = 0; 4296 FRAME_DISPLAY_INFO (f)->grabbed = 0;
3749#ifdef USE_GTK 4297#ifdef USE_GTK
3750 current_hold_quit = NULL; 4298 current_hold_quit = NULL;
@@ -3768,11 +4316,123 @@ x_dnd_cleanup_drag_and_drop (void *frame)
3768 if (x_dnd_motif_setup_p) 4316 if (x_dnd_motif_setup_p)
3769 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 4317 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3770 FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection); 4318 FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection);
4319
4320 /* Remove any type list set as well. */
4321 if (x_dnd_init_type_lists && x_dnd_n_targets > 3)
4322 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4323 FRAME_DISPLAY_INFO (f)->Xatom_XdndTypeList);
4324
3771 unblock_input (); 4325 unblock_input ();
3772 4326
3773 x_dnd_frame = NULL; 4327 x_dnd_frame = NULL;
3774} 4328}
3775 4329
4330static void
4331x_dnd_note_self_position (struct x_display_info *dpyinfo, Window target,
4332 unsigned short root_x, unsigned short root_y)
4333{
4334 struct frame *f;
4335 int dest_x, dest_y;
4336 Window child_return;
4337
4338 f = x_top_window_to_frame (dpyinfo, target);
4339
4340 if (f && XTranslateCoordinates (dpyinfo->display,
4341 dpyinfo->root_window,
4342 FRAME_X_WINDOW (f),
4343 root_x, root_y, &dest_x,
4344 &dest_y, &child_return))
4345 {
4346 x_dnd_movement_frame = f;
4347 x_dnd_movement_x = dest_x;
4348 x_dnd_movement_y = dest_y;
4349
4350 return;
4351 }
4352}
4353
4354static void
4355x_dnd_note_self_drop (struct x_display_info *dpyinfo, Window target,
4356 unsigned short root_x, unsigned short root_y,
4357 Time timestamp)
4358{
4359 struct input_event ie;
4360 struct frame *f;
4361 Lisp_Object lval;
4362 char **atom_names;
4363 char *name;
4364 int win_x, win_y, i;
4365 Window dummy;
4366
4367 if (!x_dnd_allow_current_frame
4368 && (FRAME_OUTER_WINDOW (x_dnd_frame)
4369 == target))
4370 return;
4371
4372 f = x_top_window_to_frame (dpyinfo, target);
4373
4374 if (!f)
4375 return;
4376
4377 if (NILP (Vx_dnd_native_test_function))
4378 return;
4379
4380 if (!XTranslateCoordinates (dpyinfo->display, dpyinfo->root_window,
4381 FRAME_X_WINDOW (f), root_x, root_y,
4382 &win_x, &win_y, &dummy))
4383 return;
4384
4385 /* Emacs can't respond to DND events inside the nested event loop,
4386 so when dragging items to itself, call the test function
4387 manually. */
4388
4389 XSETFRAME (lval, f);
4390 x_dnd_action = None;
4391 x_dnd_action_symbol
4392 = safe_call2 (Vx_dnd_native_test_function,
4393 Fposn_at_x_y (make_fixnum (win_x),
4394 make_fixnum (win_y),
4395 lval, Qnil),
4396 x_atom_to_symbol (dpyinfo,
4397 x_dnd_wanted_action));
4398
4399 if (!SYMBOLP (x_dnd_action_symbol))
4400 return;
4401
4402 EVENT_INIT (ie);
4403
4404 ie.kind = DRAG_N_DROP_EVENT;
4405 XSETFRAME (ie.frame_or_window, f);
4406
4407 lval = Qnil;
4408 atom_names = alloca (x_dnd_n_targets * sizeof *atom_names);
4409 name = x_get_atom_name (dpyinfo, x_dnd_wanted_action, NULL);
4410
4411 if (!XGetAtomNames (dpyinfo->display, x_dnd_targets,
4412 x_dnd_n_targets, atom_names))
4413 {
4414 xfree (name);
4415 return;
4416 }
4417
4418 for (i = x_dnd_n_targets; i != 0; --i)
4419 {
4420 lval = Fcons (intern (atom_names[i - 1]), lval);
4421 XFree (atom_names[i - 1]);
4422 }
4423
4424 lval = Fcons (intern (name), lval);
4425 lval = Fcons (QXdndSelection, lval);
4426 ie.arg = lval;
4427 ie.timestamp = timestamp;
4428
4429 XSETINT (ie.x, win_x);
4430 XSETINT (ie.y, win_y);
4431
4432 xfree (name);
4433 kbd_buffer_store_event (&ie);
4434}
4435
3776/* Flush display of frame F. */ 4436/* Flush display of frame F. */
3777 4437
3778static void 4438static void
@@ -3967,11 +4627,16 @@ x_update_opaque_region (struct frame *f, XEvent *configure)
3967 (unsigned char *) &opaque_region, 4); 4627 (unsigned char *) &opaque_region, 4);
3968 else 4628 else
3969 { 4629 {
3970 object_class = G_OBJECT_GET_CLASS (FRAME_GTK_OUTER_WIDGET (f)); 4630 /* This causes child frames to not update correctly for an
3971 class = GTK_WIDGET_CLASS (object_class); 4631 unknown reason. (bug#55779) */
4632 if (!FRAME_PARENT_FRAME (f))
4633 {
4634 object_class = G_OBJECT_GET_CLASS (FRAME_GTK_OUTER_WIDGET (f));
4635 class = GTK_WIDGET_CLASS (object_class);
3972 4636
3973 if (class->style_updated) 4637 if (class->style_updated)
3974 class->style_updated (FRAME_GTK_OUTER_WIDGET (f)); 4638 class->style_updated (FRAME_GTK_OUTER_WIDGET (f));
4639 }
3975 } 4640 }
3976#endif 4641#endif
3977 unblock_input (); 4642 unblock_input ();
@@ -4062,27 +4727,48 @@ x_free_xi_devices (struct x_display_info *dpyinfo)
4062 unblock_input (); 4727 unblock_input ();
4063} 4728}
4064 4729
4730#ifdef HAVE_XINPUT2_1
4731struct xi_known_valuator
4732{
4733 /* The current value of this valuator. */
4734 double current_value;
4735
4736 /* The number of the valuator. */
4737 int number;
4738
4739 /* The next valuator whose value we already know. */
4740 struct xi_known_valuator *next;
4741};
4742#endif
4743
4065static void 4744static void
4066xi_populate_device_from_info (struct xi_device_t *xi_device, 4745xi_populate_device_from_info (struct xi_device_t *xi_device,
4067 XIDeviceInfo *device) 4746 XIDeviceInfo *device)
4068{ 4747{
4069#ifdef HAVE_XINPUT2_1 4748#ifdef HAVE_XINPUT2_1
4070 struct xi_scroll_valuator_t *valuator; 4749 struct xi_scroll_valuator_t *valuator;
4750 struct xi_known_valuator *values, *tem;
4071 int actual_valuator_count; 4751 int actual_valuator_count;
4072 XIScrollClassInfo *info; 4752 XIScrollClassInfo *info;
4753 XIValuatorClassInfo *val_info;
4073#endif 4754#endif
4755 int c;
4074#ifdef HAVE_XINPUT2_2 4756#ifdef HAVE_XINPUT2_2
4075 XITouchClassInfo *touch_info; 4757 XITouchClassInfo *touch_info;
4076#endif 4758#endif
4077 int c; 4759
4760#ifdef HAVE_XINPUT2_1
4761 USE_SAFE_ALLOCA;
4762#endif
4078 4763
4079 xi_device->device_id = device->deviceid; 4764 xi_device->device_id = device->deviceid;
4080 xi_device->grab = 0; 4765 xi_device->grab = 0;
4081 4766
4082#ifdef HAVE_XINPUT2_1 4767#ifdef HAVE_XINPUT2_1
4083 actual_valuator_count = 0; 4768 actual_valuator_count = 0;
4084 xi_device->valuators = 4769 xi_device->valuators = xmalloc (sizeof *xi_device->valuators
4085 xmalloc (sizeof *xi_device->valuators * device->num_classes); 4770 * device->num_classes);
4771 values = NULL;
4086#endif 4772#endif
4087#ifdef HAVE_XINPUT2_2 4773#ifdef HAVE_XINPUT2_2
4088 xi_device->touchpoints = NULL; 4774 xi_device->touchpoints = NULL;
@@ -4114,7 +4800,21 @@ xi_populate_device_from_info (struct xi_device_t *xi_device,
4114 4800
4115 break; 4801 break;
4116 } 4802 }
4803
4804 case XIValuatorClass:
4805 {
4806 val_info = (XIValuatorClassInfo *) device->classes[c];
4807 tem = SAFE_ALLOCA (sizeof *tem);
4808
4809 tem->next = values;
4810 tem->number = val_info->number;
4811 tem->current_value = val_info->value;
4812
4813 values = tem;
4814 break;
4815 }
4117#endif 4816#endif
4817
4118#ifdef HAVE_XINPUT2_2 4818#ifdef HAVE_XINPUT2_2
4119 case XITouchClass: 4819 case XITouchClass:
4120 { 4820 {
@@ -4129,6 +4829,25 @@ xi_populate_device_from_info (struct xi_device_t *xi_device,
4129 4829
4130#ifdef HAVE_XINPUT2_1 4830#ifdef HAVE_XINPUT2_1
4131 xi_device->scroll_valuator_count = actual_valuator_count; 4831 xi_device->scroll_valuator_count = actual_valuator_count;
4832
4833 /* Now look through all the valuators whose values are already known
4834 and populate our client-side records with their current
4835 values. */
4836
4837 for (tem = values; values; values = values->next)
4838 {
4839 for (c = 0; c < xi_device->scroll_valuator_count; ++c)
4840 {
4841 if (xi_device->valuators[c].number == tem->number)
4842 {
4843 xi_device->valuators[c].invalid_p = false;
4844 xi_device->valuators[c].current_value = tem->current_value;
4845 xi_device->valuators[c].pending_enter_reset = true;
4846 }
4847 }
4848 }
4849
4850 SAFE_FREE ();
4132#endif 4851#endif
4133} 4852}
4134 4853
@@ -4242,6 +4961,7 @@ x_get_scroll_valuator_delta (struct x_display_info *dpyinfo,
4242 } 4961 }
4243 } 4962 }
4244 4963
4964 *valuator_return = NULL;
4245 return DBL_MAX; 4965 return DBL_MAX;
4246} 4966}
4247 4967
@@ -5305,6 +6025,20 @@ x_set_frame_alpha (struct frame *f)
5305 unsigned long opac; 6025 unsigned long opac;
5306 Window parent; 6026 Window parent;
5307 6027
6028#ifndef USE_XCB
6029 unsigned char *data = NULL;
6030 Atom actual;
6031 int rc, format;
6032 unsigned long n, left;
6033 unsigned long value;
6034#else
6035 xcb_get_property_cookie_t opacity_cookie;
6036 xcb_get_property_reply_t *opacity_reply;
6037 xcb_generic_error_t *error;
6038 bool rc;
6039 uint32_t value;
6040#endif
6041
5308 if (dpyinfo->highlight_frame == f) 6042 if (dpyinfo->highlight_frame == f)
5309 alpha = f->alpha[0]; 6043 alpha = f->alpha[0];
5310 else 6044 else
@@ -5343,19 +6077,22 @@ x_set_frame_alpha (struct frame *f)
5343 6077
5344 /* return unless necessary */ 6078 /* return unless necessary */
5345 { 6079 {
5346 unsigned char *data = NULL; 6080#ifndef USE_XCB
5347 Atom actual;
5348 int rc, format;
5349 unsigned long n, left;
5350
5351 rc = XGetWindowProperty (dpy, win, dpyinfo->Xatom_net_wm_window_opacity, 6081 rc = XGetWindowProperty (dpy, win, dpyinfo->Xatom_net_wm_window_opacity,
5352 0, 1, False, XA_CARDINAL, 6082 0, 1, False, XA_CARDINAL,
5353 &actual, &format, &n, &left, 6083 &actual, &format, &n, &left,
5354 &data); 6084 &data);
5355 6085
5356 if (rc == Success && actual != None && data) 6086 if (rc == Success && actual != None
6087 && n && format == XA_CARDINAL && data)
5357 { 6088 {
5358 unsigned long value = *(unsigned long *) data; 6089 value = *(unsigned long *) data;
6090
6091 /* Xlib sign-extends values greater than 0x7fffffff on 64-bit
6092 machines. Get the low bits by ourself. */
6093
6094 value &= 0xffffffff;
6095
5359 if (value == opac) 6096 if (value == opac)
5360 { 6097 {
5361 x_uncatch_errors (); 6098 x_uncatch_errors ();
@@ -5366,6 +6103,37 @@ x_set_frame_alpha (struct frame *f)
5366 6103
5367 if (data) 6104 if (data)
5368 XFree (data); 6105 XFree (data);
6106#else
6107 /* Avoid the confusing Xlib sign-extension mess by using XCB
6108 instead. */
6109 opacity_cookie
6110 = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) win,
6111 (xcb_atom_t) dpyinfo->Xatom_net_wm_window_opacity,
6112 XCB_ATOM_CARDINAL, 0, 1);
6113 opacity_reply
6114 = xcb_get_property_reply (dpyinfo->xcb_connection,
6115 opacity_cookie, &error);
6116
6117 rc = opacity_reply;
6118
6119 if (!opacity_reply)
6120 free (error);
6121 else
6122 {
6123 rc = (opacity_reply->format == 32
6124 && opacity_reply->type == XCB_ATOM_CARDINAL
6125 && (xcb_get_property_value_length (opacity_reply) >= 4));
6126
6127 if (rc)
6128 value = *(uint32_t *) xcb_get_property_value (opacity_reply);
6129 }
6130
6131 if (opacity_reply)
6132 free (opacity_reply);
6133
6134 if (rc && value == opac)
6135 return;
6136#endif
5369 } 6137 }
5370 6138
5371 XChangeProperty (dpy, win, dpyinfo->Xatom_net_wm_window_opacity, 6139 XChangeProperty (dpy, win, dpyinfo->Xatom_net_wm_window_opacity,
@@ -5504,6 +6272,15 @@ show_back_buffer (struct frame *f)
5504static void 6272static void
5505x_flip_and_flush (struct frame *f) 6273x_flip_and_flush (struct frame *f)
5506{ 6274{
6275 /* Flipping buffers requires a working connection to the X server,
6276 which isn't always present if `inhibit-redisplay' is t, since
6277 this can be called from the IO error handler. */
6278 if (!NILP (Vinhibit_redisplay)
6279 /* This has to work for tooltip frames, however, and redisplay
6280 cannot happen when they are being flushed anyway. (bug#55519) */
6281 && !FRAME_TOOLTIP_P (f))
6282 return;
6283
5507 block_input (); 6284 block_input ();
5508#ifdef HAVE_XDBE 6285#ifdef HAVE_XDBE
5509 if (FRAME_X_NEED_BUFFER_FLIP (f)) 6286 if (FRAME_X_NEED_BUFFER_FLIP (f))
@@ -5745,7 +6522,8 @@ x_after_update_window_line (struct window *w, struct glyph_row *desired_row)
5745} 6522}
5746 6523
5747static void 6524static void
5748x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fringe_bitmap_params *p) 6525x_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
6526 struct draw_fringe_bitmap_params *p)
5749{ 6527{
5750 struct frame *f = XFRAME (WINDOW_FRAME (w)); 6528 struct frame *f = XFRAME (WINDOW_FRAME (w));
5751 Display *display = FRAME_X_DISPLAY (f); 6529 Display *display = FRAME_X_DISPLAY (f);
@@ -5762,15 +6540,21 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fring
5762 mono-displays, the fill style may have been changed to 6540 mono-displays, the fill style may have been changed to
5763 FillSolid in x_draw_glyph_string_background. */ 6541 FillSolid in x_draw_glyph_string_background. */
5764 if (face->stipple) 6542 if (face->stipple)
5765 XSetFillStyle (display, face->gc, FillOpaqueStippled); 6543 {
5766 else 6544 XSetFillStyle (display, face->gc, FillOpaqueStippled);
5767 XSetBackground (display, face->gc, face->background); 6545 x_fill_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny,
5768 6546 true);
5769 x_clear_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny, 6547 XSetFillStyle (display, face->gc, FillSolid);
5770 true);
5771 6548
5772 if (!face->stipple) 6549 row->stipple_p = true;
5773 XSetForeground (display, face->gc, face->foreground); 6550 }
6551 else
6552 {
6553 XSetBackground (display, face->gc, face->background);
6554 x_clear_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny,
6555 true);
6556 XSetForeground (display, face->gc, face->foreground);
6557 }
5774 } 6558 }
5775 6559
5776#ifdef USE_CAIRO 6560#ifdef USE_CAIRO
@@ -6231,6 +7015,31 @@ x_clear_glyph_string_rect (struct glyph_string *s, int x, int y, int w, int h)
6231 x_clear_rectangle (s->f, s->gc, x, y, w, h, s->hl != DRAW_CURSOR); 7015 x_clear_rectangle (s->f, s->gc, x, y, w, h, s->hl != DRAW_CURSOR);
6232} 7016}
6233 7017
7018#ifndef USE_CAIRO
7019
7020static void
7021x_clear_point (struct frame *f, GC gc, int x, int y,
7022 bool respect_alpha_background)
7023{
7024 XGCValues xgcv;
7025 Display *dpy;
7026
7027 dpy = FRAME_X_DISPLAY (f);
7028
7029 if (f->alpha_background != 1.0
7030 && respect_alpha_background)
7031 {
7032 x_clear_rectangle (f, gc, x, y, 1, 1, true);
7033 return;
7034 }
7035
7036 XGetGCValues (dpy, gc, GCBackground | GCForeground, &xgcv);
7037 XSetForeground (dpy, gc, xgcv.background);
7038 XDrawPoint (dpy, FRAME_X_DRAWABLE (f), gc, x, y);
7039 XSetForeground (dpy, gc, xgcv.foreground);
7040}
7041
7042#endif
6234 7043
6235/* Draw the background of glyph_string S. If S->background_filled_p 7044/* Draw the background of glyph_string S. If S->background_filled_p
6236 is non-zero don't draw it. FORCE_P non-zero means draw the 7045 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)
6561 glyph->ascent + glyph->descent - 1); 7370 glyph->ascent + glyph->descent - 1);
6562 x += glyph->pixel_width; 7371 x += glyph->pixel_width;
6563 } 7372 }
7373
7374 /* Defend against hypothetical bad code elsewhere that uses
7375 s->char2b after this function returns. */
7376 s->char2b = NULL;
6564} 7377}
6565 7378
6566#ifdef USE_X_TOOLKIT 7379#ifdef USE_X_TOOLKIT
@@ -6923,21 +7736,21 @@ x_hash_string_ignore_case (const char *string)
6923/* On frame F, translate the color name to RGB values. Use cached 7736/* On frame F, translate the color name to RGB values. Use cached
6924 information, if possible. 7737 information, if possible.
6925 7738
6926 Note that there is currently no way to clean old entries out of the 7739 If too many entries are placed in the cache, the least recently
6927 cache. However, it is limited to names in the server's database, 7740 used entries are removed. */
6928 and names we've actually looked up; list-colors-display is probably
6929 the most color-intensive case we're likely to hit. */
6930 7741
6931Status 7742Status
6932x_parse_color (struct frame *f, const char *color_name, 7743x_parse_color (struct frame *f, const char *color_name,
6933 XColor *color) 7744 XColor *color)
6934{ 7745{
6935 unsigned short r, g, b; 7746 unsigned short r, g, b;
6936 Display *dpy = FRAME_X_DISPLAY (f); 7747 Display *dpy;
6937 Colormap cmap = FRAME_X_COLORMAP (f); 7748 Colormap cmap;
6938 struct x_display_info *dpyinfo; 7749 struct x_display_info *dpyinfo;
6939 struct color_name_cache_entry *cache_entry; 7750 struct color_name_cache_entry *cache_entry, *last;
7751 struct color_name_cache_entry *next, *color_entry;
6940 unsigned int hash, idx; 7752 unsigned int hash, idx;
7753 int rc, i;
6941 7754
6942 /* Don't pass #RGB strings directly to XParseColor, because that 7755 /* Don't pass #RGB strings directly to XParseColor, because that
6943 follows the X convention of zero-extending each channel 7756 follows the X convention of zero-extending each channel
@@ -6949,37 +7762,94 @@ x_parse_color (struct frame *f, const char *color_name,
6949 color->red = r; 7762 color->red = r;
6950 color->green = g; 7763 color->green = g;
6951 color->blue = b; 7764 color->blue = b;
7765
6952 return 1; 7766 return 1;
6953 } 7767 }
6954 7768
7769 /* Some X servers send BadValue on empty color names. */
7770 if (!strlen (color_name))
7771 return 0;
7772
7773 cmap = FRAME_X_COLORMAP (f);
7774 dpy = FRAME_X_DISPLAY (f);
6955 dpyinfo = FRAME_DISPLAY_INFO (f); 7775 dpyinfo = FRAME_DISPLAY_INFO (f);
7776
6956 hash = x_hash_string_ignore_case (color_name); 7777 hash = x_hash_string_ignore_case (color_name);
6957 idx = hash % dpyinfo->color_names_size; 7778 idx = hash % dpyinfo->color_names_size;
6958 7779
6959 for (cache_entry = FRAME_DISPLAY_INFO (f)->color_names[idx]; 7780 last = NULL;
7781
7782 for (cache_entry = dpyinfo->color_names[idx];
6960 cache_entry; cache_entry = cache_entry->next) 7783 cache_entry; cache_entry = cache_entry->next)
6961 { 7784 {
6962 if (!xstrcasecmp (cache_entry->name, color_name)) 7785 if (!xstrcasecmp (cache_entry->name, color_name))
6963 { 7786 {
6964 *color = cache_entry->rgb; 7787 /* Move recently used entries to the start of the color
6965 return 1; 7788 cache. */
7789
7790 if (last)
7791 {
7792 last->next = cache_entry->next;
7793 cache_entry->next = dpyinfo->color_names[idx];
7794
7795 dpyinfo->color_names[idx] = cache_entry;
7796 }
7797
7798 if (cache_entry->valid)
7799 *color = cache_entry->rgb;
7800
7801 return cache_entry->valid;
6966 } 7802 }
6967 }
6968 7803
6969 /* Some X servers send BadValue on empty color names. */ 7804 last = cache_entry;
6970 if (!strlen (color_name)) 7805 }
6971 return 0;
6972 7806
6973 if (XParseColor (dpy, cmap, color_name, color) == 0) 7807 block_input ();
6974 /* No caching of negative results, currently. */ 7808 rc = XParseColor (dpy, cmap, color_name, color);
6975 return 0; 7809 unblock_input ();
6976 7810
6977 cache_entry = xzalloc (sizeof *cache_entry); 7811 cache_entry = xzalloc (sizeof *cache_entry);
6978 cache_entry->rgb = *color; 7812 dpyinfo->color_names_length[idx] += 1;
7813
7814 if (rc)
7815 cache_entry->rgb = *color;
7816
7817 cache_entry->valid = rc;
6979 cache_entry->name = xstrdup (color_name); 7818 cache_entry->name = xstrdup (color_name);
6980 cache_entry->next = FRAME_DISPLAY_INFO (f)->color_names[idx]; 7819 cache_entry->next = dpyinfo->color_names[idx];
6981 FRAME_DISPLAY_INFO (f)->color_names[idx] = cache_entry; 7820
6982 return 1; 7821 dpyinfo->color_names[idx] = cache_entry;
7822
7823 /* Don't let the color cache become too big. */
7824 if (dpyinfo->color_names_length[idx] > (x_color_cache_bucket_size > 0
7825 ? x_color_cache_bucket_size : 128))
7826 {
7827 i = 0;
7828
7829 for (last = dpyinfo->color_names[idx]; last; last = last->next)
7830 {
7831 if (++i == (x_color_cache_bucket_size > 0
7832 ? x_color_cache_bucket_size : 128))
7833 {
7834 next = last->next;
7835 last->next = NULL;
7836
7837 for (color_entry = next; color_entry; color_entry = last)
7838 {
7839 last = color_entry->next;
7840
7841 xfree (color_entry->name);
7842 xfree (color_entry);
7843
7844 dpyinfo->color_names_length[idx] -= 1;
7845 }
7846
7847 return rc;
7848 }
7849 }
7850 }
7851
7852 return rc;
6983} 7853}
6984 7854
6985 7855
@@ -7358,20 +8228,62 @@ x_setup_relief_colors (struct glyph_string *s)
7358 } 8228 }
7359} 8229}
7360 8230
8231#ifndef USE_CAIRO
8232static void
8233x_fill_triangle (struct frame *f, GC gc, XPoint point1,
8234 XPoint point2, XPoint point3)
8235{
8236 XPoint abc[3];
8237
8238 abc[0] = point1;
8239 abc[1] = point2;
8240 abc[2] = point3;
8241
8242 XFillPolygon (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
8243 gc, abc, 3, Convex, CoordModeOrigin);
8244}
8245
8246static XPoint
8247x_make_point (int x, int y)
8248{
8249 XPoint pt;
8250
8251 pt.x = x;
8252 pt.y = y;
8253
8254 return pt;
8255}
8256
8257static bool
8258x_inside_rect_p (XRectangle *rects, int nrects, int x, int y)
8259{
8260 int i;
8261
8262 for (i = 0; i < nrects; ++i)
8263 {
8264 if (x >= rects[i].x && y >= rects[i].y
8265 && x < rects[i].x + rects[i].width
8266 && y < rects[i].y + rects[i].height)
8267 return true;
8268 }
8269
8270 return false;
8271}
8272#endif
7361 8273
7362/* Draw a relief on frame F inside the rectangle given by LEFT_X, 8274/* Draw a relief on frame F inside the rectangle given by LEFT_X,
7363 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief 8275 TOP_Y, RIGHT_X, and BOTTOM_Y. VWIDTH and HWIDTH are respectively
7364 to draw, it must be >= 0. RAISED_P means draw a raised 8276 the thickness of the vertical relief (left and right) and
7365 relief. LEFT_P means draw a relief on the left side of 8277 horizontal relief (top and bottom) to draw, it must be >= 0.
7366 the rectangle. RIGHT_P means draw a relief on the right 8278 RAISED_P means draw a raised relief. LEFT_P means draw a relief on
7367 side of the rectangle. CLIP_RECT is the clipping rectangle to use 8279 the left side of the rectangle. RIGHT_P means draw a relief on the
7368 when drawing. */ 8280 right side of the rectangle. CLIP_RECT is the clipping rectangle
8281 to use when drawing. */
7369 8282
7370static void 8283static void
7371x_draw_relief_rect (struct frame *f, 8284x_draw_relief_rect (struct frame *f, int left_x, int top_y, int right_x,
7372 int left_x, int top_y, int right_x, int bottom_y, 8285 int bottom_y, int hwidth, int vwidth, bool raised_p,
7373 int hwidth, int vwidth, bool raised_p, bool top_p, bool bot_p, 8286 bool top_p, bool bot_p, bool left_p, bool right_p,
7374 bool left_p, bool right_p,
7375 XRectangle *clip_rect) 8287 XRectangle *clip_rect)
7376{ 8288{
7377#ifdef USE_CAIRO 8289#ifdef USE_CAIRO
@@ -7447,90 +8359,118 @@ x_draw_relief_rect (struct frame *f,
7447 x_reset_clip_rectangles (f, top_left_gc); 8359 x_reset_clip_rectangles (f, top_left_gc);
7448 x_reset_clip_rectangles (f, bottom_right_gc); 8360 x_reset_clip_rectangles (f, bottom_right_gc);
7449#else 8361#else
7450 Display *dpy = FRAME_X_DISPLAY (f); 8362 GC gc, white_gc, black_gc, normal_gc;
7451 Drawable drawable = FRAME_X_DRAWABLE (f); 8363 Drawable drawable;
7452 int i; 8364 Display *dpy;
7453 GC gc;
7454
7455 if (raised_p)
7456 gc = f->output_data.x->white_relief.gc;
7457 else
7458 gc = f->output_data.x->black_relief.gc;
7459 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
7460 8365
7461 /* This code is more complicated than it has to be, because of two 8366 /* This code is more complicated than it has to be, because of two
7462 minor hacks to make the boxes look nicer: (i) if width > 1, draw 8367 minor hacks to make the boxes look nicer: (i) if width > 1, draw
7463 the outermost line using the black relief. (ii) Omit the four 8368 the outermost line using the black relief. (ii) Omit the four
7464 corner pixels. */ 8369 corner pixels. */
7465 8370
7466 /* Top. */ 8371 white_gc = f->output_data.x->white_relief.gc;
7467 if (top_p) 8372 black_gc = f->output_data.x->black_relief.gc;
7468 { 8373 normal_gc = f->output_data.x->normal_gc;
7469 if (hwidth == 1)
7470 XDrawLine (dpy, drawable, gc,
7471 left_x + left_p, top_y,
7472 right_x + !right_p, top_y);
7473 8374
7474 for (i = 1; i < hwidth; ++i) 8375 drawable = FRAME_X_DRAWABLE (f);
7475 XDrawLine (dpy, drawable, gc, 8376 dpy = FRAME_X_DISPLAY (f);
7476 left_x + i * left_p, top_y + i,
7477 right_x + 1 - i * right_p, top_y + i);
7478 }
7479 8377
7480 /* Left. */ 8378 x_set_clip_rectangles (f, white_gc, clip_rect, 1);
7481 if (left_p) 8379 x_set_clip_rectangles (f, black_gc, clip_rect, 1);
7482 {
7483 if (vwidth == 1)
7484 XDrawLine (dpy, drawable, gc, left_x, top_y + 1, left_x, bottom_y);
7485 8380
7486 for (i = 1; i < vwidth; ++i)
7487 XDrawLine (dpy, drawable, gc,
7488 left_x + i, top_y + (i + 1) * top_p,
7489 left_x + i, bottom_y + 1 - (i + 1) * bot_p);
7490 }
7491
7492 XSetClipMask (dpy, gc, None);
7493 if (raised_p) 8381 if (raised_p)
7494 gc = f->output_data.x->black_relief.gc; 8382 gc = white_gc;
7495 else 8383 else
7496 gc = f->output_data.x->white_relief.gc; 8384 gc = black_gc;
7497 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
7498 8385
7499 /* Outermost top line. */ 8386 /* Draw lines. */
7500 if (top_p && hwidth > 1)
7501 XDrawLine (dpy, drawable, gc,
7502 left_x + left_p, top_y,
7503 right_x + !right_p, top_y);
7504 8387
7505 /* Outermost left line. */ 8388 if (top_p)
7506 if (left_p && vwidth > 1) 8389 x_fill_rectangle (f, gc, left_x, top_y,
7507 XDrawLine (dpy, drawable, gc, left_x, top_y + 1, left_x, bottom_y); 8390 right_x - left_x + 1, hwidth,
8391 false);
8392
8393 if (left_p)
8394 x_fill_rectangle (f, gc, left_x, top_y, vwidth,
8395 bottom_y - top_y + 1, false);
8396
8397 if (raised_p)
8398 gc = black_gc;
8399 else
8400 gc = white_gc;
7508 8401
7509 /* Bottom. */
7510 if (bot_p) 8402 if (bot_p)
8403 x_fill_rectangle (f, gc, left_x, bottom_y - hwidth + 1,
8404 right_x - left_x + 1, hwidth, false);
8405
8406 if (right_p)
8407 x_fill_rectangle (f, gc, right_x - vwidth + 1, top_y,
8408 vwidth, bottom_y - top_y + 1, false);
8409
8410 /* Draw corners. */
8411
8412 if (bot_p && left_p)
8413 x_fill_triangle (f, raised_p ? white_gc : black_gc,
8414 x_make_point (left_x, bottom_y - hwidth),
8415 x_make_point (left_x + vwidth, bottom_y - hwidth),
8416 x_make_point (left_x, bottom_y));
8417
8418 if (top_p && right_p)
8419 x_fill_triangle (f, raised_p ? white_gc : black_gc,
8420 x_make_point (right_x - vwidth, top_y),
8421 x_make_point (right_x, top_y),
8422 x_make_point (right_x - vwidth, top_y + hwidth));
8423
8424 /* Draw outer line. */
8425
8426 if (top_p && left_p && bot_p && right_p
8427 && hwidth > 1 && vwidth > 1)
8428 x_draw_rectangle (f, black_gc, left_x, top_y,
8429 right_x - left_x, bottom_y - top_y);
8430 else
7511 { 8431 {
7512 if (hwidth >= 1) 8432 if (top_p && hwidth > 1)
7513 XDrawLine (dpy, drawable, gc, 8433 XDrawLine (dpy, drawable, black_gc, left_x, top_y,
7514 left_x + left_p, bottom_y, 8434 right_x + 1, top_y);
7515 right_x + !right_p, bottom_y);
7516 8435
7517 for (i = 1; i < hwidth; ++i) 8436 if (bot_p && hwidth > 1)
7518 XDrawLine (dpy, drawable, gc, 8437 XDrawLine (dpy, drawable, black_gc, left_x, bottom_y,
7519 left_x + i * left_p, bottom_y - i, 8438 right_x + 1, bottom_y);
7520 right_x + 1 - i * right_p, bottom_y - i); 8439
8440 if (left_p && vwidth > 1)
8441 XDrawLine (dpy, drawable, black_gc, left_x, top_y,
8442 left_x, bottom_y + 1);
8443
8444 if (right_p && vwidth > 1)
8445 XDrawLine (dpy, drawable, black_gc, right_x, top_y,
8446 right_x, bottom_y + 1);
7521 } 8447 }
7522 8448
7523 /* Right. */ 8449 /* Erase corners. */
7524 if (right_p) 8450
8451 if (hwidth > 1 && vwidth > 1)
7525 { 8452 {
7526 for (i = 0; i < vwidth; ++i) 8453 if (left_p && top_p && x_inside_rect_p (clip_rect, 1,
7527 XDrawLine (dpy, drawable, gc, 8454 left_x, top_y))
7528 right_x - i, top_y + (i + 1) * top_p, 8455 /* This should respect `alpha-background' since it's being
7529 right_x - i, bottom_y + 1 - (i + 1) * bot_p); 8456 cleared with the background color of the frame. */
7530 } 8457 x_clear_point (f, normal_gc, left_x, top_y, true);
7531 8458
7532 x_reset_clip_rectangles (f, gc); 8459 if (left_p && bot_p && x_inside_rect_p (clip_rect, 1,
8460 left_x, bottom_y))
8461 x_clear_point (f, normal_gc, left_x, bottom_y, true);
8462
8463 if (right_p && top_p && x_inside_rect_p (clip_rect, 1,
8464 right_x, top_y))
8465 x_clear_point (f, normal_gc, right_x, top_y, true);
7533 8466
8467 if (right_p && bot_p && x_inside_rect_p (clip_rect, 1,
8468 right_x, bottom_y))
8469 x_clear_point (f, normal_gc, right_x, bottom_y, true);
8470 }
8471
8472 x_reset_clip_rectangles (f, white_gc);
8473 x_reset_clip_rectangles (f, black_gc);
7534#endif 8474#endif
7535} 8475}
7536 8476
@@ -8039,6 +8979,9 @@ x_draw_image_glyph_string (struct glyph_string *s)
8039 || s->img->pixmap == 0 8979 || s->img->pixmap == 0
8040 || s->width != s->background_width) 8980 || s->width != s->background_width)
8041 { 8981 {
8982 if (s->stippled_p)
8983 s->row->stipple_p = true;
8984
8042#ifndef USE_CAIRO 8985#ifndef USE_CAIRO
8043 if (s->img->mask) 8986 if (s->img->mask)
8044 { 8987 {
@@ -8219,6 +9162,8 @@ x_draw_stretch_glyph_string (struct glyph_string *s)
8219 XSetFillStyle (display, gc, FillOpaqueStippled); 9162 XSetFillStyle (display, gc, FillOpaqueStippled);
8220 x_fill_rectangle (s->f, gc, x, y, w, h, true); 9163 x_fill_rectangle (s->f, gc, x, y, w, h, true);
8221 XSetFillStyle (display, gc, FillSolid); 9164 XSetFillStyle (display, gc, FillSolid);
9165
9166 s->row->stipple_p = true;
8222 } 9167 }
8223 else 9168 else
8224 { 9169 {
@@ -8245,8 +9190,13 @@ x_draw_stretch_glyph_string (struct glyph_string *s)
8245 background_width -= text_left_x - x; 9190 background_width -= text_left_x - x;
8246 x = text_left_x; 9191 x = text_left_x;
8247 } 9192 }
9193
9194 if (!s->row->stipple_p)
9195 s->row->stipple_p = s->stippled_p;
9196
8248 if (background_width > 0) 9197 if (background_width > 0)
8249 x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height); 9198 x_draw_glyph_string_bg_rect (s, x, s->y,
9199 background_width, s->height);
8250 } 9200 }
8251 9201
8252 s->background_filled_p = true; 9202 s->background_filled_p = true;
@@ -8522,13 +9472,13 @@ x_draw_glyph_string (struct glyph_string *s)
8522 val = (WINDOW_BUFFER_LOCAL_VALUE 9472 val = (WINDOW_BUFFER_LOCAL_VALUE
8523 (Qx_underline_at_descent_line, s->w)); 9473 (Qx_underline_at_descent_line, s->w));
8524 underline_at_descent_line 9474 underline_at_descent_line
8525 = (!(NILP (val) || EQ (val, Qunbound)) 9475 = (!(NILP (val) || BASE_EQ (val, Qunbound))
8526 || s->face->underline_at_descent_line_p); 9476 || s->face->underline_at_descent_line_p);
8527 9477
8528 val = (WINDOW_BUFFER_LOCAL_VALUE 9478 val = (WINDOW_BUFFER_LOCAL_VALUE
8529 (Qx_use_underline_position_properties, s->w)); 9479 (Qx_use_underline_position_properties, s->w));
8530 use_underline_position_properties 9480 use_underline_position_properties
8531 = !(NILP (val) || EQ (val, Qunbound)); 9481 = !(NILP (val) || BASE_EQ (val, Qunbound));
8532 9482
8533 /* Get the underline thickness. Default is 1 pixel. */ 9483 /* Get the underline thickness. Default is 1 pixel. */
8534 if (font && font->underline_thickness > 0) 9484 if (font && font->underline_thickness > 0)
@@ -8560,7 +9510,7 @@ x_draw_glyph_string (struct glyph_string *s)
8560 } 9510 }
8561 9511
8562 /* Ignore minimum_offset if the amount of pixels was 9512 /* Ignore minimum_offset if the amount of pixels was
8563 explictly specified. */ 9513 explicitly specified. */
8564 if (!s->face->underline_pixels_above_descent_line) 9514 if (!s->face->underline_pixels_above_descent_line)
8565 position = max (position, minimum_offset); 9515 position = max (position, minimum_offset);
8566 } 9516 }
@@ -8695,6 +9645,14 @@ x_draw_glyph_string (struct glyph_string *s)
8695 /* Reset clipping. */ 9645 /* Reset clipping. */
8696 x_reset_clip_rectangles (s->f, s->gc); 9646 x_reset_clip_rectangles (s->f, s->gc);
8697 s->num_clips = 0; 9647 s->num_clips = 0;
9648
9649 /* Set the stippled flag that tells redisplay whether or not a
9650 stipple was actually draw. */
9651
9652 if (s->first_glyph->type != STRETCH_GLYPH
9653 && s->first_glyph->type != IMAGE_GLYPH
9654 && !s->row->stipple_p)
9655 s->row->stipple_p = s->stippled_p;
8698} 9656}
8699 9657
8700/* Shift display to make room for inserted glyphs. */ 9658/* Shift display to make room for inserted glyphs. */
@@ -8724,13 +9682,15 @@ x_delete_glyphs (struct frame *f, int n)
8724/* Like XClearArea, but check that WIDTH and HEIGHT are reasonable. 9682/* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
8725 If they are <= 0, this is probably an error. */ 9683 If they are <= 0, this is probably an error. */
8726 9684
8727MAYBE_UNUSED static void 9685#if defined USE_GTK || !defined USE_CAIRO
9686static void
8728x_clear_area1 (Display *dpy, Window window, 9687x_clear_area1 (Display *dpy, Window window,
8729 int x, int y, int width, int height, int exposures) 9688 int x, int y, int width, int height, int exposures)
8730{ 9689{
8731 eassert (width > 0 && height > 0); 9690 eassert (width > 0 && height > 0);
8732 XClearArea (dpy, window, x, y, width, height, exposures); 9691 XClearArea (dpy, window, x, y, width, height, exposures);
8733} 9692}
9693#endif
8734 9694
8735void 9695void
8736x_clear_area (struct frame *f, int x, int y, int width, int height) 9696x_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)
9439 if (dpyinfo->invisible_cursor == None) 10399 if (dpyinfo->invisible_cursor == None)
9440 dpyinfo->invisible_cursor = make_invisible_cursor (dpyinfo); 10400 dpyinfo->invisible_cursor = make_invisible_cursor (dpyinfo);
9441 10401
10402#ifndef HAVE_XFIXES
9442 if (dpyinfo->invisible_cursor == None) 10403 if (dpyinfo->invisible_cursor == None)
9443 invisible = false; 10404 invisible = false;
10405#else
10406 /* But if Xfixes is available, try using it instead. */
10407 if (dpyinfo->invisible_cursor == None)
10408 {
10409 if (x_probe_xfixes_extension (dpyinfo))
10410 {
10411 dpyinfo->fixes_pointer_blanking = true;
10412 xfixes_toggle_visible_pointer (f, invisible);
10413
10414 return;
10415 }
10416 else
10417 invisible = false;
10418 }
10419#endif
9444 10420
9445 if (invisible) 10421 if (invisible)
9446 XDefineCursor (dpyinfo->display, FRAME_X_WINDOW (f), 10422 XDefineCursor (dpyinfo->display, FRAME_X_WINDOW (f),
@@ -9588,6 +10564,67 @@ x_window_to_frame (struct x_display_info *dpyinfo, int wdesc)
9588 return 0; 10564 return 0;
9589} 10565}
9590 10566
10567/* Like x_any_window_to_frame but only try to find tooltip frames.
10568
10569 If wdesc is a toolkit tooltip without an associated frame, set
10570 UNRELATED_TOOLTIP_P to true. Otherwise, set it to false. */
10571static struct frame *
10572x_tooltip_window_to_frame (struct x_display_info *dpyinfo,
10573 Window wdesc, bool *unrelated_tooltip_p)
10574{
10575 Lisp_Object tail, frame;
10576 struct frame *f;
10577#ifdef USE_GTK
10578 GtkWidget *widget;
10579 GdkWindow *tooltip_window;
10580#endif
10581
10582 *unrelated_tooltip_p = false;
10583
10584 FOR_EACH_FRAME (tail, frame)
10585 {
10586 f = XFRAME (frame);
10587
10588 if (FRAME_X_P (f) && FRAME_TOOLTIP_P (f)
10589 && FRAME_DISPLAY_INFO (f) == dpyinfo
10590 && FRAME_X_WINDOW (f) == wdesc)
10591 return f;
10592
10593#ifdef USE_GTK
10594 if (!FRAME_X_P (f))
10595 continue;
10596
10597 if (FRAME_X_OUTPUT (f)->ttip_window)
10598 widget = GTK_WIDGET (FRAME_X_OUTPUT (f)->ttip_window);
10599 else
10600 widget = NULL;
10601
10602 if (widget)
10603 tooltip_window = gtk_widget_get_window (widget);
10604 else
10605 tooltip_window = NULL;
10606
10607#ifdef HAVE_GTK3
10608 if (tooltip_window
10609 && (gdk_x11_window_get_xid (tooltip_window) == wdesc))
10610 {
10611 *unrelated_tooltip_p = true;
10612 break;
10613 }
10614#else
10615 if (tooltip_window
10616 && (GDK_WINDOW_XID (tooltip_window) == wdesc))
10617 {
10618 *unrelated_tooltip_p = true;
10619 break;
10620 }
10621#endif
10622#endif
10623 }
10624
10625 return NULL;
10626}
10627
9591#if defined (USE_X_TOOLKIT) || defined (USE_GTK) 10628#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
9592 10629
9593/* Like x_window_to_frame but also compares the window with the widget's 10630/* Like x_window_to_frame but also compares the window with the widget's
@@ -9742,8 +10779,11 @@ static void
9742x_next_event_from_any_display (XEvent *event) 10779x_next_event_from_any_display (XEvent *event)
9743{ 10780{
9744 struct x_display_info *dpyinfo; 10781 struct x_display_info *dpyinfo;
9745 fd_set fds; 10782 fd_set fds, rfds;
9746 int fd, maxfd; 10783 int fd, maxfd, rc;
10784
10785 rc = -1;
10786 FD_ZERO (&rfds);
9747 10787
9748 while (true) 10788 while (true)
9749 { 10789 {
@@ -9753,47 +10793,113 @@ x_next_event_from_any_display (XEvent *event)
9753 for (dpyinfo = x_display_list; dpyinfo; 10793 for (dpyinfo = x_display_list; dpyinfo;
9754 dpyinfo = dpyinfo->next) 10794 dpyinfo = dpyinfo->next)
9755 { 10795 {
9756 if (XPending (dpyinfo->display)) 10796 fd = ConnectionNumber (dpyinfo->display);
10797
10798 if ((rc < 0 || FD_ISSET (fd, &rfds))
10799 && XPending (dpyinfo->display))
9757 { 10800 {
9758 XNextEvent (dpyinfo->display, event); 10801 XNextEvent (dpyinfo->display, event);
9759 return; 10802 return;
9760 } 10803 }
9761 10804
9762 fd = XConnectionNumber (dpyinfo->display);
9763
9764 if (fd > maxfd) 10805 if (fd > maxfd)
9765 maxfd = fd; 10806 maxfd = fd;
9766 10807
9767 eassert (fd < FD_SETSIZE); 10808 eassert (fd < FD_SETSIZE);
9768 FD_SET (XConnectionNumber (dpyinfo->display), &fds); 10809 FD_SET (fd, &fds);
9769 } 10810 }
9770 10811
9771 eassert (maxfd >= 0); 10812 eassert (maxfd >= 0);
9772 10813
9773 /* We don't have to check the return of pselect, because if an 10814 /* Continue to read input even if pselect fails, because if an
9774 error occurs XPending will call the IO error handler, which 10815 error occurs XPending will call the IO error handler, which
9775 then brings us out of this loop. */ 10816 then brings us out of this loop. */
9776 pselect (maxfd, &fds, NULL, NULL, NULL, NULL); 10817 rc = pselect (maxfd + 1, &fds, NULL, NULL, NULL, NULL);
10818
10819 if (rc >= 0)
10820 rfds = fds;
9777 } 10821 }
9778} 10822}
9779 10823
9780#endif /* USE_X_TOOLKIT || USE_GTK */ 10824#endif /* USE_X_TOOLKIT || USE_GTK */
9781 10825
9782static void 10826static void
9783x_clear_dnd_targets (void) 10827x_handle_pending_selection_requests_1 (struct x_selection_request_event *tem)
9784{ 10828{
9785 if (x_dnd_unwind_flag) 10829 specpdl_ref count;
9786 x_set_dnd_targets (NULL, 0); 10830 struct selection_input_event se;
10831
10832 count = SPECPDL_INDEX ();
10833 se = tem->se;
10834
10835 record_unwind_protect_ptr (xfree, tem);
10836 x_handle_selection_event (&se);
10837 unbind_to (count, Qnil);
10838}
10839
10840/* Handle all pending selection request events from modal event
10841 loops. */
10842void
10843x_handle_pending_selection_requests (void)
10844{
10845 struct x_selection_request_event *tem;
10846
10847 while (pending_selection_requests)
10848 {
10849 tem = pending_selection_requests;
10850 pending_selection_requests = tem->next;
10851
10852 x_handle_pending_selection_requests_1 (tem);
10853 }
10854}
10855
10856static void
10857x_push_selection_request (struct selection_input_event *se)
10858{
10859 struct x_selection_request_event *tem;
10860
10861 tem = xmalloc (sizeof *tem);
10862 tem->next = pending_selection_requests;
10863 tem->se = *se;
10864 pending_selection_requests = tem;
10865}
10866
10867bool
10868x_detect_pending_selection_requests (void)
10869{
10870 return pending_selection_requests;
10871}
10872
10873static void
10874x_clear_dnd_action (void)
10875{
10876 x_dnd_action_symbol = Qnil;
9787} 10877}
9788 10878
9789/* This function is defined far away from the rest of the XDND code so 10879/* This function is defined far away from the rest of the XDND code so
9790 it can utilize `x_any_window_to_frame'. */ 10880 it can utilize `x_any_window_to_frame'. */
9791 10881
10882/* Implementors beware! On most other platforms (where drag-and-drop
10883 data is not provided via selections, but some kind of serialization
10884 mechanism), it is usually much easier to implement a suitable
10885 primitive instead of copying the C code here, and then to build
10886 `x-begin-drag' on top of that, by making it a wrapper function in
10887 Lisp that converts the list of targets and value of `XdndSelection'
10888 to serialized data. Also be sure to update the data types used in
10889 dnd.el.
10890
10891 For examples of how to do this, see `haiku-drag-message' and
10892 `x-begin-drag' in haikuselect.c and lisp/term/haiku-win.el, and
10893 `ns-begin-drag' and `x-begin-drag' in nsselect.m and
10894 lisp/term/ns-win.el. */
10895
9792Lisp_Object 10896Lisp_Object
9793x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, 10897x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
9794 Lisp_Object return_frame, Atom *ask_action_list, 10898 Lisp_Object return_frame, Atom *ask_action_list,
9795 const char **ask_action_names, size_t n_ask_actions, 10899 const char **ask_action_names, size_t n_ask_actions,
9796 bool allow_current_frame) 10900 bool allow_current_frame, Atom *target_atoms,
10901 int ntargets, Lisp_Object selection_target_list,
10902 bool follow_tooltip)
9797{ 10903{
9798#ifndef USE_GTK 10904#ifndef USE_GTK
9799 XEvent next_event; 10905 XEvent next_event;
@@ -9801,60 +10907,119 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
9801#endif 10907#endif
9802 XWindowAttributes root_window_attrs; 10908 XWindowAttributes root_window_attrs;
9803 struct input_event hold_quit; 10909 struct input_event hold_quit;
9804 struct frame *any;
9805 char *atom_name, *ask_actions; 10910 char *atom_name, *ask_actions;
9806 Lisp_Object action, ltimestamp; 10911 Lisp_Object action, ltimestamp;
9807 specpdl_ref ref; 10912 specpdl_ref ref, count, base;
9808 ptrdiff_t i, end, fill; 10913 ptrdiff_t i, end, fill;
9809 XTextProperty prop; 10914 XTextProperty prop;
9810 xm_drop_start_message dmsg; 10915 xm_drop_start_message dmsg;
9811 Lisp_Object frame_object, x, y, frame, local_value; 10916 Lisp_Object frame_object, x, y, frame, local_value;
9812 bool signals_were_pending; 10917 bool signals_were_pending, need_sync;
9813#ifdef HAVE_XKB 10918#ifdef HAVE_XKB
9814 XkbStateRec keyboard_state; 10919 XkbStateRec keyboard_state;
9815#endif 10920#endif
9816#ifndef USE_GTK 10921#ifndef USE_GTK
9817 struct x_display_info *event_display; 10922 struct x_display_info *event_display;
9818#endif 10923#endif
10924 union buffered_input_event *events, *event;
10925 int n_events;
10926 struct frame *event_frame;
9819 10927
9820 if (!FRAME_VISIBLE_P (f)) 10928 base = SPECPDL_INDEX ();
10929
10930 /* Bind this here to avoid juggling bindings and SAFE_FREE in
10931 Fx_begin_drag. */
10932 specbind (Qx_dnd_targets_list, selection_target_list);
10933
10934 /* Before starting drag-and-drop, walk through the keyboard buffer
10935 to see if there are any UNSUPPORTED_DROP_EVENTs, and run them now
10936 if they exist, to prevent race conditions from happening due to
10937 multiple unsupported drops running at once. */
10938
10939 block_input ();
10940 events = alloca (sizeof *events * KBD_BUFFER_SIZE);
10941 n_events = 0;
10942 event = kbd_fetch_ptr;
10943
10944 while (event != kbd_store_ptr)
9821 { 10945 {
9822 x_set_dnd_targets (NULL, 0); 10946 if (event->ie.kind == UNSUPPORTED_DROP_EVENT
9823 error ("Frame is invisible"); 10947 && event->ie.modifiers < x_dnd_unsupported_event_level)
10948 events[n_events++] = *event;
10949
10950 event = (event == kbd_buffer + KBD_BUFFER_SIZE - 1
10951 ? kbd_buffer : event + 1);
9824 } 10952 }
9825 10953
10954 x_dnd_unsupported_event_level += 1;
10955 unblock_input ();
10956
10957 for (i = 0; i < n_events; ++i)
10958 {
10959 maybe_quit ();
10960
10961 event = &events[i];
10962 event_frame = XFRAME (event->ie.frame_or_window);
10963
10964 if (!FRAME_LIVE_P (event_frame))
10965 continue;
10966
10967 if (!NILP (Vx_dnd_unsupported_drop_function))
10968 {
10969 if (!NILP (call7 (Vx_dnd_unsupported_drop_function,
10970 XCAR (XCDR (event->ie.arg)), event->ie.x,
10971 event->ie.y, XCAR (XCDR (XCDR (event->ie.arg))),
10972 make_uint (event->ie.code),
10973 event->ie.frame_or_window,
10974 make_int (event->ie.timestamp))))
10975 continue;
10976 }
10977
10978 /* `x-dnd-unsupported-drop-function' could have deleted the
10979 event frame. */
10980 if (!FRAME_LIVE_P (event_frame))
10981 continue;
10982
10983 x_dnd_do_unsupported_drop (FRAME_DISPLAY_INFO (event_frame),
10984 event->ie.frame_or_window,
10985 XCAR (event->ie.arg),
10986 XCAR (XCDR (event->ie.arg)),
10987 (Window) event->ie.code,
10988 XFIXNUM (event->ie.x),
10989 XFIXNUM (event->ie.y),
10990 event->ie.timestamp);
10991 break;
10992 }
10993
10994 if (!FRAME_VISIBLE_P (f))
10995 error ("Frame must be visible");
10996
9826 XSETFRAME (frame, f); 10997 XSETFRAME (frame, f);
9827 local_value = assq_no_quit (QXdndSelection, 10998 local_value = assq_no_quit (QXdndSelection,
9828 FRAME_TERMINAL (f)->Vselection_alist); 10999 FRAME_TERMINAL (f)->Vselection_alist);
9829 11000
9830 if (x_dnd_in_progress || x_dnd_waiting_for_finish) 11001 if (x_dnd_in_progress || x_dnd_waiting_for_finish)
9831 { 11002 error ("A drag-and-drop session is already in progress");
9832 x_set_dnd_targets (NULL, 0);
9833 error ("A drag-and-drop session is already in progress");
9834 }
9835 11003
9836 if (CONSP (local_value)) 11004 DEFER_SELECTIONS;
9837 {
9838 ref = SPECPDL_INDEX ();
9839 11005
9840 record_unwind_protect_void (x_clear_dnd_targets); 11006 /* If local_value is nil, then we lost ownership of XdndSelection.
9841 x_dnd_unwind_flag = true; 11007 Signal a more informative error than args-out-of-range. */
9842 x_own_selection (QXdndSelection, 11008 if (NILP (local_value))
9843 Fnth (make_fixnum (1), local_value), frame); 11009 error ("Lost ownership of XdndSelection");
9844 x_dnd_unwind_flag = false; 11010
9845 unbind_to (ref, Qnil); 11011 if (CONSP (local_value))
9846 } 11012 x_own_selection (QXdndSelection,
11013 Fnth (make_fixnum (1), local_value), frame);
9847 else 11014 else
9848 { 11015 error ("No local value for XdndSelection");
9849 x_set_dnd_targets (NULL, 0);
9850 error ("No local value for XdndSelection");
9851 }
9852 11016
9853 if (popup_activated ()) 11017 if (popup_activated ())
9854 { 11018 error ("Trying to drag-and-drop from within a menu-entry");
9855 x_set_dnd_targets (NULL, 0); 11019
9856 error ("Trying to drag-and-drop from within a menu-entry"); 11020 x_set_dnd_targets (target_atoms, ntargets);
9857 } 11021 record_unwind_protect_void (x_free_dnd_targets);
11022 record_unwind_protect_void (x_clear_dnd_action);
9858 11023
9859 ltimestamp = x_timestamp_for_selection (FRAME_DISPLAY_INFO (f), 11024 ltimestamp = x_timestamp_for_selection (FRAME_DISPLAY_INFO (f),
9860 QXdndSelection); 11025 QXdndSelection);
@@ -9864,10 +11029,24 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
9864 else 11029 else
9865 x_dnd_selection_timestamp = XFIXNUM (ltimestamp); 11030 x_dnd_selection_timestamp = XFIXNUM (ltimestamp);
9866 11031
11032 x_dnd_motif_operations
11033 = xm_side_effect_from_action (FRAME_DISPLAY_INFO (f), xaction);
11034
11035 x_dnd_first_motif_operation = XM_DRAG_NOOP;
11036
9867 if (n_ask_actions) 11037 if (n_ask_actions)
9868 { 11038 {
11039 x_dnd_motif_operations
11040 = xm_operations_from_actions (FRAME_DISPLAY_INFO (f),
11041 ask_action_list,
11042 n_ask_actions);
11043 x_dnd_first_motif_operation
11044 = xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
11045 ask_action_list[0]);
11046
9869 ask_actions = NULL; 11047 ask_actions = NULL;
9870 end = 0; 11048 end = 0;
11049 count = SPECPDL_INDEX ();
9871 11050
9872 for (i = 0; i < n_ask_actions; ++i) 11051 for (i = 0; i < n_ask_actions; ++i)
9873 { 11052 {
@@ -9889,16 +11068,25 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
9889 prop.format = 8; 11068 prop.format = 8;
9890 prop.nitems = end; 11069 prop.nitems = end;
9891 11070
11071 record_unwind_protect_ptr (xfree, ask_actions);
11072
11073 /* This can potentially store a lot of data in window
11074 properties, so check for allocation errors. */
9892 block_input (); 11075 block_input ();
11076 x_catch_errors (FRAME_X_DISPLAY (f));
9893 XSetTextProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 11077 XSetTextProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9894 &prop, FRAME_DISPLAY_INFO (f)->Xatom_XdndActionDescription); 11078 &prop, FRAME_DISPLAY_INFO (f)->Xatom_XdndActionDescription);
9895 xfree (ask_actions);
9896 11079
9897 XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 11080 XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9898 FRAME_DISPLAY_INFO (f)->Xatom_XdndActionList, XA_ATOM, 32, 11081 FRAME_DISPLAY_INFO (f)->Xatom_XdndActionList, XA_ATOM, 32,
9899 PropModeReplace, (unsigned char *) ask_action_list, 11082 PropModeReplace, (unsigned char *) ask_action_list,
9900 n_ask_actions); 11083 n_ask_actions);
11084 x_check_errors (FRAME_X_DISPLAY (f),
11085 "Can't set action descriptions: %s");
11086 x_uncatch_errors_after_check ();
9901 unblock_input (); 11087 unblock_input ();
11088
11089 unbind_to (count, Qnil);
9902 } 11090 }
9903 else 11091 else
9904 { 11092 {
@@ -9914,14 +11102,45 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
9914 unblock_input (); 11102 unblock_input ();
9915 } 11103 }
9916 11104
11105 if (follow_tooltip)
11106 {
11107#if defined HAVE_XRANDR || defined USE_GTK
11108 x_dnd_monitors
11109 = FRAME_DISPLAY_INFO (f)->last_monitor_attributes_list;
11110
11111 if (NILP (x_dnd_monitors))
11112#endif
11113 x_dnd_monitors
11114 = Fx_display_monitor_attributes_list (frame);
11115
11116 record_unwind_protect_void (x_clear_dnd_monitors);
11117 }
11118
11119 x_dnd_update_tooltip = follow_tooltip;
11120
11121 /* This shouldn't happen. */
11122 if (x_dnd_toplevels)
11123 x_dnd_free_toplevels (true);
11124
11125#ifdef USE_GTK
11126 /* Prevent GTK+ timeouts from being run, since they can call
11127 handle_one_xevent behind our back. */
11128 suppress_xg_select ();
11129 record_unwind_protect_void (release_xg_select);
11130#endif
11131
11132 /* Initialize most of the state for the drag-and-drop operation. */
9917 x_dnd_in_progress = true; 11133 x_dnd_in_progress = true;
11134 x_dnd_recursion_depth = command_loop_level + minibuf_level;
9918 x_dnd_frame = f; 11135 x_dnd_frame = f;
9919 x_dnd_last_seen_window = None; 11136 x_dnd_last_seen_window = None;
9920 x_dnd_last_seen_toplevel = None; 11137 x_dnd_last_seen_toplevel = None;
9921 x_dnd_last_protocol_version = -1; 11138 x_dnd_last_protocol_version = -1;
11139 x_dnd_last_window_is_frame = false;
9922 x_dnd_last_motif_style = XM_DRAG_STYLE_NONE; 11140 x_dnd_last_motif_style = XM_DRAG_STYLE_NONE;
9923 x_dnd_mouse_rect_target = None; 11141 x_dnd_mouse_rect_target = None;
9924 x_dnd_action = None; 11142 x_dnd_action = None;
11143 x_dnd_action_symbol = Qnil;
9925 x_dnd_wanted_action = xaction; 11144 x_dnd_wanted_action = xaction;
9926 x_dnd_return_frame = 0; 11145 x_dnd_return_frame = 0;
9927 x_dnd_waiting_for_finish = false; 11146 x_dnd_waiting_for_finish = false;
@@ -9934,6 +11153,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
9934 x_dnd_toplevels = NULL; 11153 x_dnd_toplevels = NULL;
9935 x_dnd_allow_current_frame = allow_current_frame; 11154 x_dnd_allow_current_frame = allow_current_frame;
9936 x_dnd_movement_frame = NULL; 11155 x_dnd_movement_frame = NULL;
11156 x_dnd_init_type_lists = false;
9937#ifdef HAVE_XKB 11157#ifdef HAVE_XKB
9938 x_dnd_keyboard_state = 0; 11158 x_dnd_keyboard_state = 0;
9939 11159
@@ -9953,9 +11173,11 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
9953 { 11173 {
9954 if (x_dnd_compute_toplevels (FRAME_DISPLAY_INFO (f))) 11174 if (x_dnd_compute_toplevels (FRAME_DISPLAY_INFO (f)))
9955 { 11175 {
9956 x_dnd_free_toplevels (); 11176 x_dnd_free_toplevels (true);
9957 x_dnd_use_toplevels = false; 11177 x_dnd_use_toplevels = false;
9958 } 11178 }
11179 else
11180 record_unwind_protect_void (x_free_dnd_toplevels);
9959 } 11181 }
9960 11182
9961 if (!NILP (return_frame)) 11183 if (!NILP (return_frame))
@@ -9983,14 +11205,17 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
9983 11205
9984 while (x_dnd_in_progress || x_dnd_waiting_for_finish) 11206 while (x_dnd_in_progress || x_dnd_waiting_for_finish)
9985 { 11207 {
9986 hold_quit.kind = NO_EVENT; 11208 EVENT_INIT (hold_quit);
11209
9987#ifdef USE_GTK 11210#ifdef USE_GTK
9988 current_finish = X_EVENT_NORMAL; 11211 current_finish = X_EVENT_NORMAL;
9989 current_hold_quit = &hold_quit; 11212 current_hold_quit = &hold_quit;
9990 current_count = 0; 11213 current_count = 0;
11214 xg_pending_quit_event.kind = NO_EVENT;
9991#endif 11215#endif
9992 11216
9993 block_input (); 11217 block_input ();
11218 x_dnd_inside_handle_one_xevent = true;
9994#ifdef USE_GTK 11219#ifdef USE_GTK
9995 gtk_main_iteration (); 11220 gtk_main_iteration ();
9996#elif defined USE_X_TOOLKIT 11221#elif defined USE_X_TOOLKIT
@@ -10027,7 +11252,12 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
10027 &next_event, &finish, &hold_quit); 11252 &next_event, &finish, &hold_quit);
10028#endif 11253#endif
10029 } 11254 }
11255#else
11256 /* Clear these before the read_socket_hook can be called. */
11257 current_count = -1;
11258 current_hold_quit = NULL;
10030#endif 11259#endif
11260 x_dnd_inside_handle_one_xevent = false;
10031 11261
10032 /* The unblock_input below might try to read input, but 11262 /* The unblock_input below might try to read input, but
10033 XTread_socket does nothing inside a drag-and-drop event 11263 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,
10042 if (event_display == FRAME_DISPLAY_INFO (f)) 11272 if (event_display == FRAME_DISPLAY_INFO (f))
10043 { 11273 {
10044#endif 11274#endif
10045 if (x_dnd_movement_frame) 11275 if (x_dnd_movement_frame
11276 /* FIXME: how come this can end up with movement frames
11277 from other displays on GTK builds? */
11278 && (FRAME_X_DISPLAY (x_dnd_movement_frame)
11279 == FRAME_X_DISPLAY (f))
11280 /* If both those variables are false, then F is no
11281 longer protected from deletion by Lisp code. This
11282 can only happen during the final iteration of the DND
11283 event loop. */
11284 && (x_dnd_in_progress || x_dnd_waiting_for_finish))
10046 { 11285 {
10047 XSETFRAME (frame_object, x_dnd_movement_frame); 11286 XSETFRAME (frame_object, x_dnd_movement_frame);
10048 XSETINT (x, x_dnd_movement_x); 11287 XSETINT (x, x_dnd_movement_x);
@@ -10050,6 +11289,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
10050 x_dnd_movement_frame = NULL; 11289 x_dnd_movement_frame = NULL;
10051 11290
10052 if (!NILP (Vx_dnd_movement_function) 11291 if (!NILP (Vx_dnd_movement_function)
11292 && FRAME_LIVE_P (XFRAME (frame_object))
10053 && !FRAME_TOOLTIP_P (XFRAME (frame_object)) 11293 && !FRAME_TOOLTIP_P (XFRAME (frame_object))
10054 && x_dnd_movement_x >= 0 11294 && x_dnd_movement_x >= 0
10055 && x_dnd_movement_y >= 0 11295 && x_dnd_movement_y >= 0
@@ -10071,19 +11311,6 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
10071 11311
10072 if (hold_quit.kind != NO_EVENT) 11312 if (hold_quit.kind != NO_EVENT)
10073 { 11313 {
10074 if (hold_quit.kind == SELECTION_REQUEST_EVENT)
10075 {
10076 x_dnd_old_window_attrs = root_window_attrs;
10077 x_dnd_unwind_flag = true;
10078
10079 ref = SPECPDL_INDEX ();
10080 record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f);
10081 x_handle_selection_event ((struct selection_input_event *) &hold_quit);
10082 x_dnd_unwind_flag = false;
10083 unbind_to (ref, Qnil);
10084 continue;
10085 }
10086
10087 if (x_dnd_in_progress) 11314 if (x_dnd_in_progress)
10088 { 11315 {
10089 if (x_dnd_last_seen_window != None 11316 if (x_dnd_last_seen_window != None
@@ -10101,9 +11328,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
10101 dmsg.side_effects 11328 dmsg.side_effects
10102 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (FRAME_DISPLAY_INFO (f), 11329 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
10103 x_dnd_wanted_action), 11330 x_dnd_wanted_action),
10104 XM_DROP_SITE_VALID, 11331 XM_DROP_SITE_VALID, x_dnd_motif_operations,
10105 xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
10106 x_dnd_wanted_action),
10107 XM_DROP_ACTION_DROP_CANCEL); 11332 XM_DROP_ACTION_DROP_CANCEL);
10108 dmsg.x = 0; 11333 dmsg.x = 0;
10109 dmsg.y = 0; 11334 dmsg.y = 0;
@@ -10124,19 +11349,107 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
10124 x_dnd_frame = NULL; 11349 x_dnd_frame = NULL;
10125 } 11350 }
10126 11351
10127 x_set_dnd_targets (NULL, 0);
10128 x_dnd_waiting_for_finish = false; 11352 x_dnd_waiting_for_finish = false;
11353 x_dnd_return_frame_object = NULL;
11354 x_dnd_movement_frame = NULL;
11355
11356 /* Don't clear dpyinfo->grabbed if we're quitting. */
11357
11358#ifdef USE_GTK
11359 current_hold_quit = NULL;
11360#endif
11361 /* Restore the old event mask. */
11362 XSelectInput (FRAME_X_DISPLAY (f),
11363 FRAME_DISPLAY_INFO (f)->root_window,
11364 root_window_attrs.your_event_mask);
11365#ifdef HAVE_XKB
11366 if (FRAME_DISPLAY_INFO (f)->supports_xkb)
11367 XkbSelectEvents (FRAME_X_DISPLAY (f), XkbUseCoreKbd,
11368 XkbStateNotifyMask, 0);
11369#endif
11370 /* Delete the Motif drag initiator info if it was set up. */
11371 if (x_dnd_motif_setup_p)
11372 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11373 FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection);
11374
11375
11376 /* Remove any type list set as well. */
11377 if (x_dnd_init_type_lists && x_dnd_n_targets > 3)
11378 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11379 FRAME_DISPLAY_INFO (f)->Xatom_XdndTypeList);
11380
11381 /* Call kbd_buffer_store event, which calls
11382 handle_interrupt and sets `last-event-frame' along
11383 with various other things. */
11384 kbd_buffer_store_event (&hold_quit);
11385 /* Now quit anyway. */
11386 quit ();
11387 }
11388
11389 if (pending_selection_requests
11390 && (x_dnd_in_progress || x_dnd_waiting_for_finish))
11391 {
11392 x_dnd_old_window_attrs = root_window_attrs;
11393 x_dnd_unwind_flag = true;
11394
11395 ref = SPECPDL_INDEX ();
11396 record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f);
11397 x_handle_pending_selection_requests ();
11398 x_dnd_unwind_flag = false;
11399 unbind_to (ref, Qnil);
11400 }
10129 11401
10130 if (x_dnd_use_toplevels) 11402#ifdef USE_GTK
10131 x_dnd_free_toplevels (); 11403 if (xg_pending_quit_event.kind != NO_EVENT)
11404 {
11405 xg_pending_quit_event.kind = NO_EVENT;
10132 11406
11407 if (x_dnd_in_progress)
11408 {
11409 if (x_dnd_last_seen_window != None
11410 && x_dnd_last_protocol_version != -1)
11411 x_dnd_send_leave (f, x_dnd_last_seen_window);
11412 else if (x_dnd_last_seen_window != None
11413 && !XM_DRAG_STYLE_IS_DROP_ONLY (x_dnd_last_motif_style)
11414 && x_dnd_last_motif_style != XM_DRAG_STYLE_NONE
11415 && x_dnd_motif_setup_p)
11416 {
11417 dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
11418 XM_DRAG_REASON_DROP_START);
11419 dmsg.byte_order = XM_BYTE_ORDER_CUR_FIRST;
11420 dmsg.timestamp = xg_pending_quit_event.timestamp;
11421 dmsg.side_effects
11422 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
11423 x_dnd_wanted_action),
11424 XM_DROP_SITE_VALID, x_dnd_motif_operations,
11425 XM_DROP_ACTION_DROP_CANCEL);
11426 dmsg.x = 0;
11427 dmsg.y = 0;
11428 dmsg.index_atom = FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection;
11429 dmsg.source_window = FRAME_X_WINDOW (f);
11430
11431 x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
11432 x_dnd_last_seen_window,
11433 xg_pending_quit_event.timestamp);
11434 xm_send_drop_message (FRAME_DISPLAY_INFO (f), FRAME_X_WINDOW (f),
11435 x_dnd_last_seen_window, &dmsg);
11436 }
11437
11438 x_dnd_end_window = x_dnd_last_seen_window;
11439 x_dnd_last_seen_window = None;
11440 x_dnd_last_seen_toplevel = None;
11441 x_dnd_in_progress = false;
11442 x_dnd_frame = NULL;
11443 }
11444
11445 x_dnd_waiting_for_finish = false;
10133 x_dnd_return_frame_object = NULL; 11446 x_dnd_return_frame_object = NULL;
10134 x_dnd_movement_frame = NULL; 11447 x_dnd_movement_frame = NULL;
10135 11448
10136 FRAME_DISPLAY_INFO (f)->grabbed = 0; 11449 FRAME_DISPLAY_INFO (f)->grabbed = 0;
10137#ifdef USE_GTK
10138 current_hold_quit = NULL; 11450 current_hold_quit = NULL;
10139#endif 11451
11452 block_input ();
10140 /* Restore the old event mask. */ 11453 /* Restore the old event mask. */
10141 XSelectInput (FRAME_X_DISPLAY (f), 11454 XSelectInput (FRAME_X_DISPLAY (f),
10142 FRAME_DISPLAY_INFO (f)->root_window, 11455 FRAME_DISPLAY_INFO (f)->root_window,
@@ -10150,9 +11463,17 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
10150 if (x_dnd_motif_setup_p) 11463 if (x_dnd_motif_setup_p)
10151 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 11464 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10152 FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection); 11465 FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection);
11466
11467
11468 /* Remove any type list set as well. */
11469 if (x_dnd_init_type_lists && x_dnd_n_targets > 3)
11470 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11471 FRAME_DISPLAY_INFO (f)->Xatom_XdndTypeList);
11472 unblock_input ();
11473
10153 quit (); 11474 quit ();
10154 } 11475 }
10155#ifndef USE_GTK 11476#else
10156 } 11477 }
10157 else 11478 else
10158 { 11479 {
@@ -10165,7 +11486,6 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
10165#endif 11486#endif
10166 } 11487 }
10167 11488
10168 x_set_dnd_targets (NULL, 0);
10169 x_dnd_waiting_for_finish = false; 11489 x_dnd_waiting_for_finish = false;
10170 11490
10171#ifdef USE_GTK 11491#ifdef USE_GTK
@@ -10187,6 +11507,11 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
10187 if (x_dnd_motif_setup_p) 11507 if (x_dnd_motif_setup_p)
10188 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 11508 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10189 FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection); 11509 FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection);
11510
11511 /* Remove any type list set as well. */
11512 if (x_dnd_init_type_lists && x_dnd_n_targets > 3)
11513 XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11514 FRAME_DISPLAY_INFO (f)->Xatom_XdndTypeList);
10190 unblock_input (); 11515 unblock_input ();
10191 11516
10192 if (x_dnd_return_frame == 3 11517 if (x_dnd_return_frame == 3
@@ -10202,45 +11527,43 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
10202 11527
10203 XSETFRAME (action, x_dnd_return_frame_object); 11528 XSETFRAME (action, x_dnd_return_frame_object);
10204 x_dnd_return_frame_object = NULL; 11529 x_dnd_return_frame_object = NULL;
10205 return action; 11530
11531 return unbind_to (base, action);
10206 } 11532 }
10207 11533
10208 x_dnd_return_frame_object = NULL; 11534 x_dnd_return_frame_object = NULL;
10209
10210 if (x_dnd_use_toplevels)
10211 x_dnd_free_toplevels ();
10212 FRAME_DISPLAY_INFO (f)->grabbed = 0; 11535 FRAME_DISPLAY_INFO (f)->grabbed = 0;
10213 11536
10214 /* Emacs can't respond to DND events inside the nested event 11537 if (!NILP (x_dnd_action_symbol))
10215 loop, so when dragging items to itself, always return 11538 return unbind_to (base, x_dnd_action_symbol);
10216 XdndActionPrivate. */
10217 if (x_dnd_end_window != None
10218 && (any = x_any_window_to_frame (FRAME_DISPLAY_INFO (f),
10219 x_dnd_end_window))
10220 && (allow_current_frame || any != f))
10221 return QXdndActionPrivate;
10222 11539
10223 if (x_dnd_action != None) 11540 if (x_dnd_action != None)
10224 { 11541 {
10225 block_input (); 11542 block_input ();
10226 x_catch_errors (FRAME_X_DISPLAY (f)); 11543 x_catch_errors (FRAME_X_DISPLAY (f));
10227 atom_name = XGetAtomName (FRAME_X_DISPLAY (f), 11544 atom_name = x_get_atom_name (FRAME_DISPLAY_INFO (f),
10228 x_dnd_action); 11545 x_dnd_action, &need_sync);
10229 x_uncatch_errors (); 11546
11547 if (need_sync)
11548 x_uncatch_errors ();
11549 else
11550 /* No protocol request actually happened, so avoid the extra
11551 sync by calling x_uncatch_errors_after_check instead. */
11552 x_uncatch_errors_after_check ();
10230 11553
10231 if (atom_name) 11554 if (atom_name)
10232 { 11555 {
10233 action = intern (atom_name); 11556 action = intern (atom_name);
10234 XFree (atom_name); 11557 xfree (atom_name);
10235 } 11558 }
10236 else 11559 else
10237 action = Qnil; 11560 action = Qnil;
10238 unblock_input (); 11561 unblock_input ();
10239 11562
10240 return action; 11563 return unbind_to (base, action);
10241 } 11564 }
10242 11565
10243 return Qnil; 11566 return unbind_to (base, Qnil);
10244} 11567}
10245 11568
10246/* The focus may have changed. Figure out if it is a real focus change, 11569/* 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,
10780 return false; 12103 return false;
10781} 12104}
10782 12105
12106/* Get a sibling below WINDOW on DPY at PARENT_X and PARENT_Y. */
12107static Window
12108x_get_window_below (Display *dpy, Window window,
12109 int parent_x, int parent_y,
12110 int *inner_x, int *inner_y)
12111{
12112 int rc, i, cx, cy;
12113 XWindowAttributes attrs;
12114 unsigned int nchildren;
12115 Window root, parent, *children, value;
12116 bool window_seen;
12117
12118 /* TODO: rewrite to have less dependencies. */
12119
12120 children = NULL;
12121 window_seen = false;
12122 value = None;
12123
12124 rc = XQueryTree (dpy, window, &root, &parent,
12125 &children, &nchildren);
12126
12127 if (rc)
12128 {
12129 if (children)
12130 XFree (children);
12131
12132 rc = XQueryTree (dpy, parent, &root,
12133 &parent, &children, &nchildren);
12134 }
12135
12136 if (rc)
12137 {
12138 for (i = nchildren - 1; i >= 0; --i)
12139 {
12140 if (children[i] == window)
12141 {
12142 window_seen = true;
12143 continue;
12144 }
12145
12146 if (!window_seen)
12147 continue;
12148
12149 rc = XGetWindowAttributes (dpy, children[i], &attrs);
12150
12151 if (rc && attrs.map_state != IsViewable)
12152 continue;
12153
12154 if (rc && parent_x >= attrs.x
12155 && parent_y >= attrs.y
12156 && parent_x < attrs.x + attrs.width
12157 && parent_y < attrs.y + attrs.height)
12158 {
12159 value = children[i];
12160 cx = parent_x - attrs.x;
12161 cy = parent_y - attrs.y;
12162
12163 break;
12164 }
12165 }
12166 }
12167
12168 if (children)
12169 XFree (children);
12170
12171 if (value)
12172 {
12173 *inner_x = cx;
12174 *inner_y = cy;
12175 }
12176
12177 return value;
12178}
12179
10783/* Return the current position of the mouse. 12180/* Return the current position of the mouse.
10784 *FP should be a frame which indicates which display to ask about. 12181 *FP should be a frame which indicates which display to ask about.
10785 12182
@@ -10805,8 +12202,9 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
10805 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y, 12202 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
10806 Time *timestamp) 12203 Time *timestamp)
10807{ 12204{
10808 struct frame *f1; 12205 struct frame *f1, *maybe_tooltip;
10809 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp); 12206 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
12207 bool unrelated_tooltip;
10810 12208
10811 block_input (); 12209 block_input ();
10812 12210
@@ -10861,9 +12259,11 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
10861 Window first_win = 0; 12259 Window first_win = 0;
10862#endif 12260#endif
10863 int win_x, win_y; 12261 int win_x, win_y;
10864 int parent_x = 0, parent_y = 0; 12262 int parent_x, parent_y;
10865 12263
10866 win = root; 12264 win = root;
12265 parent_x = root_x;
12266 parent_y = root_y;
10867 12267
10868 /* XTranslateCoordinates can get errors if the window 12268 /* XTranslateCoordinates can get errors if the window
10869 structure is changing at the same time this function 12269 structure is changing at the same time this function
@@ -10898,6 +12298,22 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
10898 root_x, root_y, &win_x, &win_y, 12298 root_x, root_y, &win_x, &win_y,
10899 /* Child of win. */ 12299 /* Child of win. */
10900 &child); 12300 &child);
12301
12302 /* If CHILD is a tooltip frame, look below it if
12303 track-mouse is drag-source. */
12304 if (child != None
12305 && (EQ (track_mouse, Qdrag_source)
12306 || EQ (track_mouse, Qdropping)))
12307 {
12308 maybe_tooltip = x_tooltip_window_to_frame (dpyinfo, child,
12309 &unrelated_tooltip);
12310
12311 if (maybe_tooltip || unrelated_tooltip)
12312 child = x_get_window_below (dpyinfo->display, child,
12313 parent_x, parent_y, &win_x,
12314 &win_y);
12315 }
12316
10901 if (child == None || child == win) 12317 if (child == None || child == win)
10902 { 12318 {
10903#ifdef USE_GTK 12319#ifdef USE_GTK
@@ -13695,6 +15111,13 @@ x_filter_event (struct x_display_info *dpyinfo, XEvent *event)
13695 result = xg_filter_key (f1, event); 15111 result = xg_filter_key (f1, event);
13696 unblock_input (); 15112 unblock_input ();
13697 15113
15114 /* Clear `xg_pending_quit_event' so we don't end up reacting to quit
15115 events sent outside the main event loop (i.e. those sent from
15116 inside a popup menu event loop). */
15117
15118 if (popup_activated ())
15119 xg_pending_quit_event.kind = NO_EVENT;
15120
13698 if (result && f1) 15121 if (result && f1)
13699 /* There will probably be a GDK event generated soon, so 15122 /* There will probably be a GDK event generated soon, so
13700 exercise the wire to make pselect return. */ 15123 exercise the wire to make pselect return. */
@@ -13900,6 +15323,132 @@ mouse_or_wdesc_frame (struct x_display_info *dpyinfo, int wdesc)
13900 } 15323 }
13901} 15324}
13902 15325
15326static void
15327x_dnd_compute_tip_xy (int *root_x, int *root_y, Lisp_Object attributes)
15328{
15329 Lisp_Object monitor, geometry;
15330 int min_x, min_y, max_x, max_y;
15331 int width, height;
15332
15333 width = FRAME_PIXEL_WIDTH (XFRAME (tip_frame));
15334 height = FRAME_PIXEL_HEIGHT (XFRAME (tip_frame));
15335
15336 max_y = -1;
15337
15338 /* Try to determine the monitor where the mouse pointer is and
15339 its geometry. See bug#22549. */
15340 while (CONSP (attributes))
15341 {
15342 monitor = XCAR (attributes);
15343 geometry = assq_no_quit (Qgeometry, monitor);
15344
15345 if (CONSP (geometry))
15346 {
15347 min_x = XFIXNUM (Fnth (make_fixnum (1), geometry));
15348 min_y = XFIXNUM (Fnth (make_fixnum (2), geometry));
15349 max_x = min_x + XFIXNUM (Fnth (make_fixnum (3), geometry));
15350 max_y = min_y + XFIXNUM (Fnth (make_fixnum (4), geometry));
15351
15352 if (min_x <= *root_x && *root_x < max_x
15353 && min_y <= *root_y && *root_y < max_y)
15354 break;
15355
15356 max_y = -1;
15357 }
15358
15359 attributes = XCDR (attributes);
15360 }
15361
15362 /* It was not possible to determine the monitor's geometry, so we
15363 assign some sane defaults here: */
15364 if (max_y < 0)
15365 {
15366 min_x = 0;
15367 min_y = 0;
15368 max_x = x_display_pixel_width (FRAME_DISPLAY_INFO (x_dnd_frame));
15369 max_y = x_display_pixel_height (FRAME_DISPLAY_INFO (x_dnd_frame));
15370 }
15371
15372 if (*root_y + XFIXNUM (tip_dy) <= min_y)
15373 *root_y = min_y; /* Can happen for negative dy */
15374 else if (*root_y + XFIXNUM (tip_dy) + height <= max_y)
15375 /* It fits below the pointer */
15376 *root_y += XFIXNUM (tip_dy);
15377 else if (height + XFIXNUM (tip_dy) + min_y <= *root_y)
15378 /* It fits above the pointer. */
15379 *root_y -= height + XFIXNUM (tip_dy);
15380 else
15381 /* Put it on the top. */
15382 *root_y = min_y;
15383
15384 if (*root_x + XFIXNUM (tip_dx) <= min_x)
15385 *root_x = 0; /* Can happen for negative dx */
15386 else if (*root_x + XFIXNUM (tip_dx) + width <= max_x)
15387 /* It fits to the right of the pointer. */
15388 *root_x += XFIXNUM (tip_dx);
15389 else if (width + XFIXNUM (tip_dx) + min_x <= *root_x)
15390 /* It fits to the left of the pointer. */
15391 *root_x -= width + XFIXNUM (tip_dx);
15392 else
15393 /* Put it left justified on the screen -- it ought to fit that way. */
15394 *root_x = min_x;
15395}
15396
15397static void
15398x_dnd_update_tooltip_position (int root_x, int root_y)
15399{
15400 struct frame *tip_f;
15401
15402 if (!x_dnd_in_progress || !x_dnd_update_tooltip)
15403 return;
15404
15405 if (!FRAMEP (tip_frame))
15406 return;
15407
15408 tip_f = XFRAME (tip_frame);
15409
15410 if (!FRAME_LIVE_P (tip_f)
15411 || !FRAME_VISIBLE_P (tip_f)
15412 || (FRAME_X_DISPLAY (tip_f)
15413 != FRAME_X_DISPLAY (x_dnd_frame)))
15414 return;
15415
15416 if (tip_window != None
15417 && FIXNUMP (tip_dx) && FIXNUMP (tip_dy))
15418 {
15419 x_dnd_compute_tip_xy (&root_x, &root_y,
15420 x_dnd_monitors);
15421
15422 XMoveWindow (FRAME_X_DISPLAY (x_dnd_frame),
15423 tip_window, root_x, root_y);
15424 }
15425}
15426
15427static void
15428x_dnd_update_tooltip_now (void)
15429{
15430 int root_x, root_y;
15431 Window root, child;
15432 int win_x, win_y;
15433 unsigned int mask;
15434 Bool rc;
15435 struct x_display_info *dpyinfo;
15436
15437 if (!x_dnd_in_progress || !x_dnd_update_tooltip)
15438 return;
15439
15440 dpyinfo = FRAME_DISPLAY_INFO (x_dnd_frame);
15441
15442 rc = XQueryPointer (dpyinfo->display,
15443 dpyinfo->root_window,
15444 &root, &child, &root_x,
15445 &root_y, &win_x, &win_y,
15446 &mask);
15447
15448 if (rc)
15449 x_dnd_update_tooltip_position (root_x, root_y);
15450}
15451
13903/* Get the window underneath the pointer, see if it moved, and update 15452/* Get the window underneath the pointer, see if it moved, and update
13904 the DND state accordingly. */ 15453 the DND state accordingly. */
13905static void 15454static void
@@ -13912,6 +15461,7 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
13912 xm_top_level_enter_message emsg; 15461 xm_top_level_enter_message emsg;
13913 xm_drag_motion_message dmsg; 15462 xm_drag_motion_message dmsg;
13914 xm_drop_start_message dsmsg; 15463 xm_drop_start_message dsmsg;
15464 bool was_frame;
13915 15465
13916 if (XQueryPointer (dpyinfo->display, 15466 if (XQueryPointer (dpyinfo->display,
13917 dpyinfo->root_window, 15467 dpyinfo->root_window,
@@ -13922,7 +15472,8 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
13922 { 15472 {
13923 target = x_dnd_get_target_window (dpyinfo, root_x, 15473 target = x_dnd_get_target_window (dpyinfo, root_x,
13924 root_y, &target_proto, 15474 root_y, &target_proto,
13925 &motif_style, &toplevel); 15475 &motif_style, &toplevel,
15476 &was_frame);
13926 15477
13927 if (toplevel != x_dnd_last_seen_toplevel) 15478 if (toplevel != x_dnd_last_seen_toplevel)
13928 { 15479 {
@@ -13939,6 +15490,7 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
13939 x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window); 15490 x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
13940 else if (x_dnd_last_seen_window != None 15491 else if (x_dnd_last_seen_window != None
13941 && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) 15492 && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
15493 && !x_dnd_disable_motif_drag
13942 && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame)) 15494 && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
13943 { 15495 {
13944 if (!x_dnd_motif_setup_p) 15496 if (!x_dnd_motif_setup_p)
@@ -13978,6 +15530,7 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
13978 x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window); 15530 x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
13979 else if (x_dnd_last_seen_window != None 15531 else if (x_dnd_last_seen_window != None
13980 && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) 15532 && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
15533 && !x_dnd_disable_motif_drag
13981 && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame)) 15534 && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
13982 { 15535 {
13983 if (!x_dnd_motif_setup_p) 15536 if (!x_dnd_motif_setup_p)
@@ -13999,11 +15552,13 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
13999 x_dnd_last_seen_window = target; 15552 x_dnd_last_seen_window = target;
14000 x_dnd_last_protocol_version = target_proto; 15553 x_dnd_last_protocol_version = target_proto;
14001 x_dnd_last_motif_style = motif_style; 15554 x_dnd_last_motif_style = motif_style;
15555 x_dnd_last_window_is_frame = was_frame;
14002 15556
14003 if (target != None && x_dnd_last_protocol_version != -1) 15557 if (target != None && x_dnd_last_protocol_version != -1)
14004 x_dnd_send_enter (x_dnd_frame, target, 15558 x_dnd_send_enter (x_dnd_frame, target,
14005 x_dnd_last_protocol_version); 15559 x_dnd_last_protocol_version);
14006 else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)) 15560 else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
15561 && !x_dnd_disable_motif_drag)
14007 { 15562 {
14008 if (!x_dnd_motif_setup_p) 15563 if (!x_dnd_motif_setup_p)
14009 xm_setup_drag_info (dpyinfo, x_dnd_frame); 15564 xm_setup_drag_info (dpyinfo, x_dnd_frame);
@@ -14022,7 +15577,9 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
14022 } 15577 }
14023 } 15578 }
14024 15579
14025 if (x_dnd_last_protocol_version != -1 && target != None) 15580 if (x_dnd_last_window_is_frame && target != None)
15581 x_dnd_note_self_position (dpyinfo, target, root_x, root_y);
15582 else if (x_dnd_last_protocol_version != -1 && target != None)
14026 x_dnd_send_position (x_dnd_frame, target, 15583 x_dnd_send_position (x_dnd_frame, target,
14027 x_dnd_last_protocol_version, 15584 x_dnd_last_protocol_version,
14028 root_x, root_y, 15585 root_x, root_y,
@@ -14034,7 +15591,8 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
14034 0 15591 0
14035#endif 15592#endif
14036 ); 15593 );
14037 else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None) 15594 else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None
15595 && !x_dnd_disable_motif_drag)
14038 { 15596 {
14039 if (!x_dnd_motif_setup_p) 15597 if (!x_dnd_motif_setup_p)
14040 xm_setup_drag_info (dpyinfo, x_dnd_frame); 15598 xm_setup_drag_info (dpyinfo, x_dnd_frame);
@@ -14045,9 +15603,7 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
14045 dmsg.side_effects 15603 dmsg.side_effects
14046 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo, 15604 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
14047 x_dnd_wanted_action), 15605 x_dnd_wanted_action),
14048 XM_DROP_SITE_VALID, 15606 XM_DROP_SITE_VALID, x_dnd_motif_operations,
14049 xm_side_effect_from_action (dpyinfo,
14050 x_dnd_wanted_action),
14051 (!x_dnd_xm_use_help 15607 (!x_dnd_xm_use_help
14052 ? XM_DROP_ACTION_DROP 15608 ? XM_DROP_ACTION_DROP
14053 : XM_DROP_ACTION_DROP_HELP)); 15609 : XM_DROP_ACTION_DROP_HELP));
@@ -14059,6 +15615,8 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
14059 xm_send_drag_motion_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame), 15615 xm_send_drag_motion_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame),
14060 target, &dmsg); 15616 target, &dmsg);
14061 } 15617 }
15618
15619 x_dnd_update_tooltip_position (root_x, root_y);
14062 } 15620 }
14063 /* The pointer moved out of the screen. */ 15621 /* The pointer moved out of the screen. */
14064 else if (x_dnd_last_protocol_version != -1) 15622 else if (x_dnd_last_protocol_version != -1)
@@ -14079,9 +15637,7 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
14079 dsmsg.side_effects 15637 dsmsg.side_effects
14080 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo, 15638 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
14081 x_dnd_wanted_action), 15639 x_dnd_wanted_action),
14082 XM_DROP_SITE_VALID, 15640 XM_DROP_SITE_VALID, x_dnd_motif_operations,
14083 xm_side_effect_from_action (dpyinfo,
14084 x_dnd_wanted_action),
14085 XM_DROP_ACTION_DROP_CANCEL); 15641 XM_DROP_ACTION_DROP_CANCEL);
14086 dsmsg.x = 0; 15642 dsmsg.x = 0;
14087 dsmsg.y = 0; 15643 dsmsg.y = 0;
@@ -14104,6 +15660,236 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
14104 } 15660 }
14105} 15661}
14106 15662
15663int
15664x_display_pixel_height (struct x_display_info *dpyinfo)
15665{
15666 if (dpyinfo->screen_height)
15667 return dpyinfo->screen_height;
15668
15669 return HeightOfScreen (dpyinfo->screen);
15670}
15671
15672int
15673x_display_pixel_width (struct x_display_info *dpyinfo)
15674{
15675 if (dpyinfo->screen_width)
15676 return dpyinfo->screen_width;
15677
15678 return WidthOfScreen (dpyinfo->screen);
15679}
15680
15681/* Handle events from each display until CELL's car becomes non-nil,
15682 or TIMEOUT elapses. */
15683void
15684x_wait_for_cell_change (Lisp_Object cell, struct timespec timeout)
15685{
15686 struct x_display_info *dpyinfo;
15687 fd_set fds;
15688 int fd, maxfd;
15689#ifndef USE_GTK
15690 int finish, rc;
15691 XEvent event;
15692 fd_set rfds;
15693#endif
15694 struct input_event hold_quit;
15695 struct timespec current, at;
15696
15697 at = timespec_add (current_timespec (), timeout);
15698
15699#ifndef USE_GTK
15700 FD_ZERO (&rfds);
15701 rc = -1;
15702#endif
15703
15704 while (true)
15705 {
15706 FD_ZERO (&fds);
15707 maxfd = -1;
15708
15709 for (dpyinfo = x_display_list; dpyinfo;
15710 dpyinfo = dpyinfo->next)
15711 {
15712 fd = ConnectionNumber (dpyinfo->display);
15713
15714#ifndef USE_GTK
15715 if ((rc < 0 || FD_ISSET (fd, &rfds))
15716 /* If pselect failed, the erroring display's IO error
15717 handler will eventually be called. */
15718 && XPending (dpyinfo->display))
15719 {
15720 while (XPending (dpyinfo->display))
15721 {
15722 EVENT_INIT (hold_quit);
15723
15724 XNextEvent (dpyinfo->display, &event);
15725 handle_one_xevent (dpyinfo, &event,
15726 &finish, &hold_quit);
15727
15728 if (!NILP (XCAR (cell)))
15729 return;
15730
15731 if (finish == X_EVENT_GOTO_OUT)
15732 break;
15733
15734 /* Make us quit now. */
15735 if (hold_quit.kind != NO_EVENT)
15736 kbd_buffer_store_event (&hold_quit);
15737 }
15738 }
15739#endif
15740
15741 if (fd > maxfd)
15742 maxfd = fd;
15743
15744 eassert (fd < FD_SETSIZE);
15745 FD_SET (fd, &fds);
15746 }
15747
15748 /* Prevent events from being lost (from GTK's point of view) by
15749 using GDK to run the event loop. */
15750#ifdef USE_GTK
15751 while (gtk_events_pending ())
15752 {
15753 EVENT_INIT (hold_quit);
15754 current_count = 0;
15755 current_hold_quit = &hold_quit;
15756 current_finish = X_EVENT_NORMAL;
15757
15758 gtk_main_iteration ();
15759
15760 current_count = -1;
15761 current_hold_quit = NULL;
15762
15763 /* Make us quit now. */
15764 if (hold_quit.kind != NO_EVENT)
15765 kbd_buffer_store_event (&hold_quit);
15766
15767 if (!NILP (XCAR (cell)))
15768 return;
15769
15770 if (current_finish == X_EVENT_GOTO_OUT)
15771 break;
15772 }
15773#endif
15774
15775 eassert (maxfd >= 0);
15776
15777 current = current_timespec ();
15778
15779 if (timespec_cmp (at, current) < 0
15780 || !NILP (XCAR (cell)))
15781 return;
15782
15783 timeout = timespec_sub (at, current);
15784
15785#ifndef USE_GTK
15786 rc = pselect (maxfd + 1, &fds, NULL, NULL, &timeout, NULL);
15787
15788 if (rc >= 0)
15789 rfds = fds;
15790#else
15791 pselect (maxfd + 1, &fds, NULL, NULL, &timeout, NULL);
15792#endif
15793 }
15794}
15795
15796#ifdef USE_GTK
15797static void
15798x_monitors_changed_cb (GdkScreen *gscr, gpointer user_data)
15799{
15800 struct x_display_info *dpyinfo;
15801 struct input_event ie;
15802 Lisp_Object current_monitors, terminal;
15803 GdkDisplay *gdpy;
15804 Display *dpy;
15805
15806 gdpy = gdk_screen_get_display (gscr);
15807 dpy = gdk_x11_display_get_xdisplay (gdpy);
15808 dpyinfo = x_display_info_for_display (dpy);
15809
15810 if (!dpyinfo)
15811 return;
15812
15813 XSETTERMINAL (terminal, dpyinfo->terminal);
15814
15815 current_monitors
15816 = Fx_display_monitor_attributes_list (terminal);
15817
15818 if (NILP (Fequal (current_monitors,
15819 dpyinfo->last_monitor_attributes_list)))
15820 {
15821 EVENT_INIT (ie);
15822 ie.kind = MONITORS_CHANGED_EVENT;
15823 ie.arg = terminal;
15824
15825 kbd_buffer_store_event (&ie);
15826
15827 if (x_dnd_in_progress && x_dnd_update_tooltip)
15828 x_dnd_monitors = current_monitors;
15829
15830 x_dnd_update_tooltip_now ();
15831 }
15832
15833 dpyinfo->last_monitor_attributes_list = current_monitors;
15834}
15835#endif
15836
15837/* Extract the root window coordinates from the client message EVENT
15838 if it is a message that we already understand. Return false if the
15839 event was not understood. */
15840static bool
15841x_coords_from_dnd_message (struct x_display_info *dpyinfo,
15842 XEvent *event, int *x_out, int *y_out)
15843{
15844 xm_drag_motion_message dmsg;
15845 xm_drop_start_message smsg;
15846 xm_drop_start_reply reply;
15847
15848 if (event->type != ClientMessage)
15849 return false;
15850
15851 if (event->xclient.message_type == dpyinfo->Xatom_XdndPosition)
15852 {
15853 if (event->xclient.format != 32)
15854 return false;
15855
15856 *x_out = (((unsigned long) event->xclient.data.l[2]) >> 16
15857 & 0xffff);
15858 *y_out = (event->xclient.data.l[2] & 0xffff);
15859
15860 return true;
15861 }
15862
15863 if ((event->xclient.message_type
15864 == dpyinfo->Xatom_MOTIF_DRAG_AND_DROP_MESSAGE)
15865 && event->xclient.format == 8)
15866 {
15867 if (!xm_read_drag_motion_message (event, &dmsg))
15868 {
15869 *x_out = dmsg.x;
15870 *y_out = dmsg.y;
15871
15872 return true;
15873 }
15874 else if (!xm_read_drop_start_message (event, &smsg))
15875 {
15876 *x_out = smsg.x;
15877 *y_out = smsg.y;
15878
15879 return true;
15880 }
15881 else if (!xm_read_drop_start_reply (event, &reply))
15882 {
15883 *x_out = reply.better_x;
15884 *y_out = reply.better_y;
15885
15886 return true;
15887 }
15888 }
15889
15890 return false;
15891}
15892
14107/* Handles the XEvent EVENT on display DPYINFO. 15893/* Handles the XEvent EVENT on display DPYINFO.
14108 15894
14109 *FINISH is X_EVENT_GOTO_OUT if caller should stop reading events. 15895 *FINISH is X_EVENT_GOTO_OUT if caller should stop reading events.
@@ -14146,6 +15932,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
14146 GdkEvent *copy = NULL; 15932 GdkEvent *copy = NULL;
14147 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpyinfo->display); 15933 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpyinfo->display);
14148#endif 15934#endif
15935 int dx, dy;
15936 USE_SAFE_ALLOCA;
14149 15937
14150 *finish = X_EVENT_NORMAL; 15938 *finish = X_EVENT_NORMAL;
14151 15939
@@ -14176,11 +15964,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
14176 { 15964 {
14177 case ClientMessage: 15965 case ClientMessage:
14178 { 15966 {
15967 int rc;
15968
14179 if (x_dnd_in_progress 15969 if (x_dnd_in_progress
14180 && FRAME_DISPLAY_INFO (x_dnd_frame) == dpyinfo 15970 && FRAME_DISPLAY_INFO (x_dnd_frame) == dpyinfo
14181 && event->xclient.message_type == dpyinfo->Xatom_XdndStatus) 15971 && event->xclient.message_type == dpyinfo->Xatom_XdndStatus)
14182 { 15972 {
14183 Window target; 15973 Window target;
15974 unsigned long r1, r2;
14184 15975
14185 target = event->xclient.data.l[0]; 15976 target = event->xclient.data.l[0];
14186 15977
@@ -14188,11 +15979,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
14188 && target == x_dnd_last_seen_window 15979 && target == x_dnd_last_seen_window
14189 && event->xclient.data.l[1] & 2) 15980 && event->xclient.data.l[1] & 2)
14190 { 15981 {
15982 r1 = event->xclient.data.l[2];
15983 r2 = event->xclient.data.l[2];
15984
14191 x_dnd_mouse_rect_target = target; 15985 x_dnd_mouse_rect_target = target;
14192 x_dnd_mouse_rect.x = (event->xclient.data.l[2] & 0xffff0000) >> 16; 15986 x_dnd_mouse_rect.x = (r1 & 0xffff0000) >> 16;
14193 x_dnd_mouse_rect.y = (event->xclient.data.l[2] & 0xffff); 15987 x_dnd_mouse_rect.y = (r1 & 0xffff);
14194 x_dnd_mouse_rect.width = (event->xclient.data.l[3] & 0xffff0000) >> 16; 15988 x_dnd_mouse_rect.width = (r2 & 0xffff0000) >> 16;
14195 x_dnd_mouse_rect.height = (event->xclient.data.l[3] & 0xffff); 15989 x_dnd_mouse_rect.height = (r2 & 0xffff);
14196 } 15990 }
14197 else 15991 else
14198 x_dnd_mouse_rect_target = None; 15992 x_dnd_mouse_rect_target = None;
@@ -14377,25 +16171,23 @@ handle_one_xevent (struct x_display_info *dpyinfo,
14377 16171
14378 16172
14379 if (event->xclient.data.l[0] == dpyinfo->Xatom_net_wm_ping 16173 if (event->xclient.data.l[0] == dpyinfo->Xatom_net_wm_ping
16174 /* Handling window stacking changes during
16175 drag-and-drop requires Emacs to select for
16176 SubstructureNotifyMask, which in turn causes the
16177 message to be sent to Emacs itself using the event
16178 mask specified by the EWMH. To avoid an infinite
16179 loop, make sure the client message's window is not
16180 the root window if DND is in progress. */
16181 && (!(x_dnd_in_progress
16182 || x_dnd_waiting_for_finish)
16183 || event->xclient.window != dpyinfo->root_window)
14380 && event->xclient.format == 32) 16184 && event->xclient.format == 32)
14381 { 16185 {
14382 XEvent send_event = *event; 16186 XEvent send_event = *event;
14383 16187
14384 send_event.xclient.window = dpyinfo->root_window; 16188 send_event.xclient.window = dpyinfo->root_window;
14385 XSendEvent (dpyinfo->display, dpyinfo->root_window, False, 16189 XSendEvent (dpyinfo->display, dpyinfo->root_window, False,
14386 /* FIXME: handling window stacking changes 16190 SubstructureRedirectMask | SubstructureNotifyMask,
14387 during drag-and-drop requires Emacs to
14388 select for SubstructureNotifyMask,
14389 which in turn causes the message to be
14390 sent to Emacs itself using the event
14391 mask specified by the EWMH. To avoid
14392 an infinite loop, just use
14393 SubstructureRedirectMask when a
14394 drag-and-drop operation is in
14395 progress. */
14396 ((x_dnd_in_progress || x_dnd_waiting_for_finish)
14397 ? SubstructureRedirectMask
14398 : SubstructureRedirectMask | SubstructureNotifyMask),
14399 &send_event); 16191 &send_event);
14400 16192
14401 *finish = X_EVENT_DROP; 16193 *finish = X_EVENT_DROP;
@@ -14435,17 +16227,21 @@ handle_one_xevent (struct x_display_info *dpyinfo,
14435 *finish = X_EVENT_DROP; 16227 *finish = X_EVENT_DROP;
14436#else 16228#else
14437 widget = FRAME_GTK_OUTER_WIDGET (f); 16229 widget = FRAME_GTK_OUTER_WIDGET (f);
16230 window = gtk_widget_get_window (widget);
16231 eassert (window);
16232
16233 /* This could be a (former) child frame for which
16234 frame synchronization was disabled. Enable it
16235 now. */
16236 gdk_x11_window_set_frame_sync_enabled (window, TRUE);
14438 16237
14439 if (widget && !FRAME_X_OUTPUT (f)->xg_sync_end_pending_p) 16238 if (widget && !FRAME_X_OUTPUT (f)->xg_sync_end_pending_p)
14440 { 16239 {
14441 window = gtk_widget_get_window (widget);
14442 eassert (window);
14443 frame_clock = gdk_window_get_frame_clock (window); 16240 frame_clock = gdk_window_get_frame_clock (window);
14444 eassert (frame_clock); 16241 eassert (frame_clock);
14445 16242
14446 gdk_frame_clock_request_phase (frame_clock, 16243 gdk_frame_clock_request_phase (frame_clock,
14447 GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT); 16244 GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT);
14448
14449 FRAME_X_OUTPUT (f)->xg_sync_end_pending_p = true; 16245 FRAME_X_OUTPUT (f)->xg_sync_end_pending_p = true;
14450 } 16246 }
14451#endif 16247#endif
@@ -14503,7 +16299,11 @@ handle_one_xevent (struct x_display_info *dpyinfo,
14503 goto OTHER; 16299 goto OTHER;
14504#ifndef USE_CAIRO 16300#ifndef USE_CAIRO
14505 Pixmap pixmap = (Pixmap) event->xclient.data.l[1]; 16301 Pixmap pixmap = (Pixmap) event->xclient.data.l[1];
16302 /* FIXME: why does this sometimes generate a BadMatch
16303 error? */
16304 x_catch_errors (dpyinfo->display);
14506 x_kill_gs_process (pixmap, f); 16305 x_kill_gs_process (pixmap, f);
16306 x_uncatch_errors ();
14507 expose_frame (f, 0, 0, 0, 0); 16307 expose_frame (f, 0, 0, 0, 0);
14508#endif /* !USE_CAIRO */ 16308#endif /* !USE_CAIRO */
14509 goto done; 16309 goto done;
@@ -14542,24 +16342,34 @@ handle_one_xevent (struct x_display_info *dpyinfo,
14542 f = any; 16342 f = any;
14543 if (!f) 16343 if (!f)
14544 goto OTHER; 16344 goto OTHER;
14545 if (x_handle_dnd_message (f, &event->xclient, dpyinfo, &inev.ie)) 16345
16346 /* These values are always used initialized, but GCC doesn't
16347 know that. */
16348 dx = 0;
16349 dy = 0;
16350
16351 rc = x_coords_from_dnd_message (dpyinfo, (XEvent *) event,
16352 &dx, &dy);
16353
16354 if (x_handle_dnd_message (f, &event->xclient, dpyinfo, &inev.ie,
16355 rc, dx, dy))
14546 *finish = X_EVENT_DROP; 16356 *finish = X_EVENT_DROP;
14547 } 16357 }
14548 break; 16358 break;
14549 16359
14550 case SelectionNotify: 16360 case SelectionNotify:
14551#ifdef USE_X_TOOLKIT 16361#if defined USE_X_TOOLKIT || defined USE_GTK
14552 if (! x_window_to_frame (dpyinfo, event->xselection.requestor)) 16362 if (!x_window_to_frame (dpyinfo, event->xselection.requestor))
14553 goto OTHER; 16363 goto OTHER;
14554#endif /* not USE_X_TOOLKIT */ 16364#endif /* not USE_X_TOOLKIT and not USE_GTK */
14555 x_handle_selection_notify (&event->xselection); 16365 x_handle_selection_notify (&event->xselection);
14556 break; 16366 break;
14557 16367
14558 case SelectionClear: /* Someone has grabbed ownership. */ 16368 case SelectionClear: /* Someone has grabbed ownership. */
14559#ifdef USE_X_TOOLKIT 16369#if defined USE_X_TOOLKIT || defined USE_GTK
14560 if (! x_window_to_frame (dpyinfo, event->xselectionclear.window)) 16370 if (!x_window_to_frame (dpyinfo, event->xselectionclear.window))
14561 goto OTHER; 16371 goto OTHER;
14562#endif /* USE_X_TOOLKIT */ 16372#endif /* not USE_X_TOOLKIT and not USE_GTK */
14563 { 16373 {
14564 const XSelectionClearEvent *eventp = &event->xselectionclear; 16374 const XSelectionClearEvent *eventp = &event->xselectionclear;
14565 16375
@@ -14567,6 +16377,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
14567 SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo; 16377 SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo;
14568 SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection; 16378 SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection;
14569 SELECTION_EVENT_TIME (&inev.sie) = eventp->time; 16379 SELECTION_EVENT_TIME (&inev.sie) = eventp->time;
16380
16381 if (x_use_pending_selection_requests)
16382 {
16383 x_push_selection_request (&inev.sie);
16384 EVENT_INIT (inev.ie);
16385 }
14570 } 16386 }
14571 break; 16387 break;
14572 16388
@@ -14590,11 +16406,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
14590 events immediately, by setting hold_quit to the input 16406 events immediately, by setting hold_quit to the input
14591 event. */ 16407 event. */
14592 16408
14593 if (x_dnd_in_progress || x_dnd_waiting_for_finish) 16409 if (x_use_pending_selection_requests)
14594 { 16410 {
14595 eassume (hold_quit); 16411 x_push_selection_request (&inev.sie);
14596
14597 *hold_quit = inev.ie;
14598 EVENT_INIT (inev.ie); 16412 EVENT_INIT (inev.ie);
14599 } 16413 }
14600 16414
@@ -14604,7 +16418,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
14604 && eventp->selection == dpyinfo->Xatom_XdndSelection 16418 && eventp->selection == dpyinfo->Xatom_XdndSelection
14605 && (eventp->target == dpyinfo->Xatom_XmTRANSFER_SUCCESS 16419 && (eventp->target == dpyinfo->Xatom_XmTRANSFER_SUCCESS
14606 || eventp->target == dpyinfo->Xatom_XmTRANSFER_FAILURE)) 16420 || eventp->target == dpyinfo->Xatom_XmTRANSFER_FAILURE))
14607 x_dnd_waiting_for_finish = false; 16421 {
16422 x_dnd_waiting_for_finish = false;
16423
16424 /* If the transfer failed, then return nil from
16425 `x-begin-drag'. */
16426 if (eventp->target == dpyinfo->Xatom_XmTRANSFER_FAILURE)
16427 x_dnd_action = None;
16428 }
14608 } 16429 }
14609 break; 16430 break;
14610 16431
@@ -14625,7 +16446,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
14625 unsigned long nitems, bytesafter; 16446 unsigned long nitems, bytesafter;
14626 unsigned char *data = NULL; 16447 unsigned char *data = NULL;
14627 16448
14628
14629 if (event->xproperty.state == PropertyDelete) 16449 if (event->xproperty.state == PropertyDelete)
14630 { 16450 {
14631 if (!last) 16451 if (!last)
@@ -14714,6 +16534,107 @@ handle_one_xevent (struct x_display_info *dpyinfo,
14714 } 16534 }
14715 } 16535 }
14716 16536
16537 if (f && FRAME_X_OUTPUT (f)->alpha_identical_p
16538 && (event->xproperty.atom
16539 == dpyinfo->Xatom_net_wm_window_opacity))
16540 {
16541#ifndef USE_XCB
16542 int rc, actual_format;
16543 Atom actual;
16544 unsigned char *tmp_data;
16545 unsigned long n, left, opacity;
16546
16547 tmp_data = NULL;
16548#else
16549 xcb_get_property_cookie_t opacity_cookie;
16550 xcb_get_property_reply_t *opacity_reply;
16551 xcb_generic_error_t *error;
16552 bool rc;
16553 uint32_t value;
16554#endif
16555
16556 if (event->xproperty.state == PropertyDelete)
16557 {
16558 f->alpha[0] = 1.0;
16559 f->alpha[1] = 1.0;
16560
16561 store_frame_param (f, Qalpha, Qnil);
16562 }
16563 else
16564 {
16565#ifndef USE_XCB
16566 rc = XGetWindowProperty (dpyinfo->display, FRAME_OUTER_WINDOW (f),
16567 dpyinfo->Xatom_net_wm_window_opacity,
16568 0, 1, False, AnyPropertyType, &actual,
16569 &actual_format, &n, &left, &tmp_data);
16570
16571 if (rc == Success && actual_format == 32
16572 && (actual == XA_CARDINAL
16573 /* Some broken programs set the opacity property
16574 to those types, but window managers accept
16575 them anyway. */
16576 || actual == XA_ATOM
16577 || actual == XA_WINDOW) && n)
16578 {
16579 opacity = *(unsigned long *) tmp_data & OPAQUE;
16580 f->alpha[0] = (double) opacity / (double) OPAQUE;
16581 f->alpha[1] = (double) opacity / (double) OPAQUE;
16582
16583 store_frame_param (f, Qalpha, make_float (f->alpha[0]));
16584 }
16585 else
16586 {
16587 f->alpha[0] = 1.0;
16588 f->alpha[1] = 1.0;
16589
16590 store_frame_param (f, Qalpha, Qnil);
16591 }
16592#else
16593 opacity_cookie
16594 = xcb_get_property (dpyinfo->xcb_connection, 0,
16595 (xcb_window_t) FRAME_OUTER_WINDOW (f),
16596 (xcb_atom_t) dpyinfo->Xatom_net_wm_window_opacity,
16597 XCB_ATOM_CARDINAL, 0, 1);
16598 opacity_reply
16599 = xcb_get_property_reply (dpyinfo->xcb_connection,
16600 opacity_cookie, &error);
16601
16602 if (!opacity_reply)
16603 free (error), rc = false;
16604 else
16605 rc = (opacity_reply->format == 32
16606 && (opacity_reply->type == XCB_ATOM_CARDINAL
16607 || opacity_reply->type == XCB_ATOM_ATOM
16608 || opacity_reply->type == XCB_ATOM_WINDOW)
16609 && (xcb_get_property_value_length (opacity_reply) >= 4));
16610
16611 if (rc)
16612 {
16613 value = *(uint32_t *) xcb_get_property_value (opacity_reply);
16614
16615 f->alpha[0] = (double) value / (double) OPAQUE;
16616 f->alpha[1] = (double) value / (double) OPAQUE;
16617 store_frame_param (f, Qalpha, make_float (f->alpha[0]));
16618 }
16619 else
16620 {
16621 f->alpha[0] = 1.0;
16622 f->alpha[1] = 1.0;
16623
16624 store_frame_param (f, Qalpha, Qnil);
16625 }
16626
16627 if (opacity_reply)
16628 free (opacity_reply);
16629#endif
16630 }
16631
16632#ifndef USE_XCB
16633 if (tmp_data)
16634 XFree (tmp_data);
16635#endif
16636 }
16637
14717 if (event->xproperty.window == dpyinfo->root_window 16638 if (event->xproperty.window == dpyinfo->root_window
14718 && (event->xproperty.atom == dpyinfo->Xatom_net_client_list_stacking 16639 && (event->xproperty.atom == dpyinfo->Xatom_net_client_list_stacking
14719 || event->xproperty.atom == dpyinfo->Xatom_net_current_desktop) 16640 || event->xproperty.atom == dpyinfo->Xatom_net_current_desktop)
@@ -14722,11 +16643,11 @@ handle_one_xevent (struct x_display_info *dpyinfo,
14722 { 16643 {
14723 if (x_dnd_use_toplevels) 16644 if (x_dnd_use_toplevels)
14724 { 16645 {
14725 x_dnd_free_toplevels (); 16646 x_dnd_free_toplevels (true);
14726 16647
14727 if (x_dnd_compute_toplevels (dpyinfo)) 16648 if (x_dnd_compute_toplevels (dpyinfo))
14728 { 16649 {
14729 x_dnd_free_toplevels (); 16650 x_dnd_free_toplevels (true);
14730 x_dnd_use_toplevels = false; 16651 x_dnd_use_toplevels = false;
14731 } 16652 }
14732 } 16653 }
@@ -15223,9 +17144,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
15223 memset (&compose_status, 0, sizeof (compose_status)); 17144 memset (&compose_status, 0, sizeof (compose_status));
15224 17145
15225#ifdef HAVE_XKB 17146#ifdef HAVE_XKB
15226 if (FRAME_DISPLAY_INFO (f)->xkb_desc) 17147 if (dpyinfo->xkb_desc)
15227 { 17148 {
15228 XkbDescRec *rec = FRAME_DISPLAY_INFO (f)->xkb_desc; 17149 XkbDescRec *rec = dpyinfo->xkb_desc;
15229 17150
15230 if (rec->map->modmap && rec->map->modmap[xkey.keycode]) 17151 if (rec->map->modmap && rec->map->modmap[xkey.keycode])
15231 goto done_keysym; 17152 goto done_keysym;
@@ -15256,7 +17177,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
15256 if (status_return == XBufferOverflow) 17177 if (status_return == XBufferOverflow)
15257 { 17178 {
15258 copy_bufsiz = nbytes + 1; 17179 copy_bufsiz = nbytes + 1;
15259 copy_bufptr = alloca (copy_bufsiz); 17180 copy_bufptr = SAFE_ALLOCA (copy_bufsiz);
15260 nbytes = XmbLookupString (FRAME_XIC (f), 17181 nbytes = XmbLookupString (FRAME_XIC (f),
15261 &xkey, (char *) copy_bufptr, 17182 &xkey, (char *) copy_bufptr,
15262 copy_bufsiz, &keysym, 17183 copy_bufsiz, &keysym,
@@ -15594,7 +17515,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
15594 17515
15595 if (f && x_mouse_click_focus_ignore_position) 17516 if (f && x_mouse_click_focus_ignore_position)
15596 { 17517 {
15597 ignore_next_mouse_click_timeout = event->xmotion.time + 200; 17518 ignore_next_mouse_click_timeout = (event->xmotion.time
17519 + x_mouse_click_focus_ignore_time);
15598 mouse_click_timeout_display = dpyinfo; 17520 mouse_click_timeout_display = dpyinfo;
15599 } 17521 }
15600 17522
@@ -15693,7 +17615,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
15693 Do it only if there's something to cancel. 17615 Do it only if there's something to cancel.
15694 Otherwise, the startup message is cleared when 17616 Otherwise, the startup message is cleared when
15695 the mouse leaves the frame. */ 17617 the mouse leaves the frame. */
15696 if (any_help_event_p) 17618 if (any_help_event_p
17619 /* But never if `mouse-drag-and-drop-region' is in
17620 progress, since that results in the tooltip being
17621 dismissed when the mouse moves on top. */
17622 && !((EQ (track_mouse, Qdrag_source)
17623 || EQ (track_mouse, Qdropping))
17624 && gui_mouse_grabbed (dpyinfo)))
15697 do_help = -1; 17625 do_help = -1;
15698 } 17626 }
15699#ifdef USE_GTK 17627#ifdef USE_GTK
@@ -15724,6 +17652,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
15724 f = mouse_or_wdesc_frame (dpyinfo, event->xmotion.window); 17652 f = mouse_or_wdesc_frame (dpyinfo, event->xmotion.window);
15725 17653
15726 if (x_dnd_in_progress 17654 if (x_dnd_in_progress
17655 /* Handle these events normally if the recursion
17656 level is higher than when the drag-and-drop
17657 operation was initiated. This is so that mouse
17658 input works while we're in the debugger for, say,
17659 `x-dnd-movement-function`. */
17660 && (command_loop_level + minibuf_level
17661 <= x_dnd_recursion_depth)
15727 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) 17662 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
15728 { 17663 {
15729 Window target, toplevel; 17664 Window target, toplevel;
@@ -15731,6 +17666,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
15731 xm_top_level_leave_message lmsg; 17666 xm_top_level_leave_message lmsg;
15732 xm_top_level_enter_message emsg; 17667 xm_top_level_enter_message emsg;
15733 xm_drag_motion_message dmsg; 17668 xm_drag_motion_message dmsg;
17669 XRectangle *r;
17670 bool was_frame;
17671
17672 /* Always clear mouse face. */
17673 clear_mouse_face (hlinfo);
17674 hlinfo->mouse_face_hidden = true;
15734 17675
15735 /* Sometimes the drag-and-drop operation starts with the 17676 /* Sometimes the drag-and-drop operation starts with the
15736 pointer of a frame invisible due to input. Since 17677 pointer of a frame invisible due to input. Since
@@ -15738,13 +17679,35 @@ handle_one_xevent (struct x_display_info *dpyinfo,
15738 visible manually. */ 17679 visible manually. */
15739 17680
15740 if (f) 17681 if (f)
15741 XTtoggle_invisible_pointer (f, false); 17682 {
17683 XTtoggle_invisible_pointer (f, false);
17684
17685 r = &dpyinfo->last_mouse_glyph;
17686
17687 /* Also remember the mouse glyph and set
17688 mouse_moved. */
17689 if (f != dpyinfo->last_mouse_glyph_frame
17690 || event->xmotion.x < r->x
17691 || event->xmotion.x >= r->x + r->width
17692 || event->xmotion.y < r->y
17693 || event->xmotion.y >= r->y + r->height)
17694 {
17695 f->mouse_moved = true;
17696 f->last_mouse_device = Qnil;
17697 dpyinfo->last_mouse_scroll_bar = NULL;
17698
17699 remember_mouse_glyph (f, event->xmotion.x,
17700 event->xmotion.y, r);
17701 dpyinfo->last_mouse_glyph_frame = f;
17702 }
17703 }
15742 17704
15743 target = x_dnd_get_target_window (dpyinfo, 17705 target = x_dnd_get_target_window (dpyinfo,
15744 event->xmotion.x_root, 17706 event->xmotion.x_root,
15745 event->xmotion.y_root, 17707 event->xmotion.y_root,
15746 &target_proto, 17708 &target_proto,
15747 &motif_style, &toplevel); 17709 &motif_style, &toplevel,
17710 &was_frame);
15748 17711
15749 if (toplevel != x_dnd_last_seen_toplevel) 17712 if (toplevel != x_dnd_last_seen_toplevel)
15750 { 17713 {
@@ -15761,6 +17724,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
15761 x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window); 17724 x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
15762 else if (x_dnd_last_seen_window != None 17725 else if (x_dnd_last_seen_window != None
15763 && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) 17726 && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
17727 && !x_dnd_disable_motif_drag
15764 && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame)) 17728 && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
15765 { 17729 {
15766 if (!x_dnd_motif_setup_p) 17730 if (!x_dnd_motif_setup_p)
@@ -15800,6 +17764,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
15800 x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window); 17764 x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
15801 else if (x_dnd_last_seen_window != None 17765 else if (x_dnd_last_seen_window != None
15802 && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) 17766 && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
17767 && x_dnd_disable_motif_drag
15803 && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame)) 17768 && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
15804 { 17769 {
15805 if (!x_dnd_motif_setup_p) 17770 if (!x_dnd_motif_setup_p)
@@ -15816,7 +17781,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
15816 dmsg.byteorder = XM_BYTE_ORDER_CUR_FIRST; 17781 dmsg.byteorder = XM_BYTE_ORDER_CUR_FIRST;
15817 dmsg.side_effects = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo, 17782 dmsg.side_effects = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
15818 x_dnd_wanted_action), 17783 x_dnd_wanted_action),
15819 XM_DROP_SITE_NONE, XM_DRAG_NOOP, 17784 XM_DROP_SITE_NONE, x_dnd_motif_operations,
15820 XM_DROP_ACTION_DROP_CANCEL); 17785 XM_DROP_ACTION_DROP_CANCEL);
15821 dmsg.timestamp = event->xmotion.time; 17786 dmsg.timestamp = event->xmotion.time;
15822 dmsg.x = event->xmotion.x_root; 17787 dmsg.x = event->xmotion.x_root;
@@ -15842,11 +17807,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
15842 x_dnd_last_seen_window = target; 17807 x_dnd_last_seen_window = target;
15843 x_dnd_last_protocol_version = target_proto; 17808 x_dnd_last_protocol_version = target_proto;
15844 x_dnd_last_motif_style = motif_style; 17809 x_dnd_last_motif_style = motif_style;
17810 x_dnd_last_window_is_frame = was_frame;
15845 17811
15846 if (target != None && x_dnd_last_protocol_version != -1) 17812 if (target != None && x_dnd_last_protocol_version != -1)
15847 x_dnd_send_enter (x_dnd_frame, target, 17813 x_dnd_send_enter (x_dnd_frame, target,
15848 x_dnd_last_protocol_version); 17814 x_dnd_last_protocol_version);
15849 else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)) 17815 else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
17816 && !x_dnd_disable_motif_drag)
15850 { 17817 {
15851 if (!x_dnd_motif_setup_p) 17818 if (!x_dnd_motif_setup_p)
15852 xm_setup_drag_info (dpyinfo, x_dnd_frame); 17819 xm_setup_drag_info (dpyinfo, x_dnd_frame);
@@ -15865,7 +17832,11 @@ handle_one_xevent (struct x_display_info *dpyinfo,
15865 } 17832 }
15866 } 17833 }
15867 17834
15868 if (x_dnd_last_protocol_version != -1 && target != None) 17835 if (x_dnd_last_window_is_frame && target != None)
17836 x_dnd_note_self_position (dpyinfo, target,
17837 event->xbutton.x_root,
17838 event->xbutton.y_root);
17839 else if (x_dnd_last_protocol_version != -1 && target != None)
15869 x_dnd_send_position (x_dnd_frame, target, 17840 x_dnd_send_position (x_dnd_frame, target,
15870 x_dnd_last_protocol_version, 17841 x_dnd_last_protocol_version,
15871 event->xmotion.x_root, 17842 event->xmotion.x_root,
@@ -15873,7 +17844,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
15873 x_dnd_selection_timestamp, 17844 x_dnd_selection_timestamp,
15874 x_dnd_wanted_action, 0, 17845 x_dnd_wanted_action, 0,
15875 event->xmotion.state); 17846 event->xmotion.state);
15876 else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None) 17847 else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None
17848 && !x_dnd_disable_motif_drag)
15877 { 17849 {
15878 if (!x_dnd_motif_setup_p) 17850 if (!x_dnd_motif_setup_p)
15879 xm_setup_drag_info (dpyinfo, x_dnd_frame); 17851 xm_setup_drag_info (dpyinfo, x_dnd_frame);
@@ -15883,9 +17855,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
15883 dmsg.byteorder = XM_BYTE_ORDER_CUR_FIRST; 17855 dmsg.byteorder = XM_BYTE_ORDER_CUR_FIRST;
15884 dmsg.side_effects = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo, 17856 dmsg.side_effects = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
15885 x_dnd_wanted_action), 17857 x_dnd_wanted_action),
15886 XM_DROP_SITE_VALID, 17858 XM_DROP_SITE_VALID, x_dnd_motif_operations,
15887 xm_side_effect_from_action (dpyinfo,
15888 x_dnd_wanted_action),
15889 (!x_dnd_xm_use_help 17859 (!x_dnd_xm_use_help
15890 ? XM_DROP_ACTION_DROP 17860 ? XM_DROP_ACTION_DROP
15891 : XM_DROP_ACTION_DROP_HELP)); 17861 : XM_DROP_ACTION_DROP_HELP));
@@ -15898,6 +17868,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
15898 target, &dmsg); 17868 target, &dmsg);
15899 } 17869 }
15900 17870
17871 x_dnd_update_tooltip_position (event->xmotion.x_root,
17872 event->xmotion.y_root);
17873
15901 goto OTHER; 17874 goto OTHER;
15902 } 17875 }
15903 17876
@@ -16000,6 +17973,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
16000 So if this ConfigureNotify is immediately followed by another 17973 So if this ConfigureNotify is immediately followed by another
16001 for the same window, use the info from the latest update, and 17974 for the same window, use the info from the latest update, and
16002 consider the events all handled. */ 17975 consider the events all handled. */
17976
16003 /* Opaque resize may be trickier; ConfigureNotify events are 17977 /* Opaque resize may be trickier; ConfigureNotify events are
16004 mixed with Expose events for multiple windows. */ 17978 mixed with Expose events for multiple windows. */
16005 configureEvent = *event; 17979 configureEvent = *event;
@@ -16021,6 +17995,36 @@ handle_one_xevent (struct x_display_info *dpyinfo,
16021 configureEvent = next_event; 17995 configureEvent = next_event;
16022 } 17996 }
16023 17997
17998 /* If we get a ConfigureNotify for the root window, this means
17999 the dimensions of the screen it's on changed. */
18000
18001 if (configureEvent.xconfigure.window == dpyinfo->root_window)
18002 {
18003#ifdef HAVE_XRANDR
18004 /* This function is OK to call even if the X server doesn't
18005 support RandR. */
18006 XRRUpdateConfiguration (&configureEvent);
18007#elif !defined USE_GTK
18008 /* Catch screen size changes even if RandR is not available
18009 on the client. GTK does this internally. */
18010
18011 if (configureEvent.xconfigure.width != dpyinfo->screen_width
18012 || configureEvent.xconfigure.height != dpyinfo->screen_height)
18013 {
18014 inev.ie.kind = MONITORS_CHANGED_EVENT;
18015 XSETTERMINAL (inev.ie.arg, dpyinfo->terminal);
18016
18017 /* Store this event now since inev.ie.type could be set to
18018 MOVE_FRAME_EVENT later. */
18019 kbd_buffer_store_event (&inev.ie);
18020 inev.ie.kind = NO_EVENT;
18021 }
18022#endif
18023
18024 dpyinfo->screen_width = configureEvent.xconfigure.width;
18025 dpyinfo->screen_height = configureEvent.xconfigure.height;
18026 }
18027
16024 if (x_dnd_in_progress && x_dnd_use_toplevels 18028 if (x_dnd_in_progress && x_dnd_use_toplevels
16025 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) 18029 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
16026 { 18030 {
@@ -16182,15 +18186,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
16182#endif 18186#endif
16183 x_net_wm_state (f, configureEvent.xconfigure.window); 18187 x_net_wm_state (f, configureEvent.xconfigure.window);
16184 18188
16185#ifdef USE_X_TOOLKIT 18189#if defined USE_X_TOOLKIT || defined USE_GTK
16186 /* Tip frames are pure X window, set size for them. */ 18190 /* Tip frames are pure X window, set size for them. */
16187 if (FRAME_TOOLTIP_P (f)) 18191 if (FRAME_TOOLTIP_P (f))
16188 { 18192 {
16189 if (FRAME_PIXEL_HEIGHT (f) != configureEvent.xconfigure.height 18193 if (FRAME_PIXEL_HEIGHT (f) != configureEvent.xconfigure.height
16190 || FRAME_PIXEL_WIDTH (f) != configureEvent.xconfigure.width) 18194 || FRAME_PIXEL_WIDTH (f) != configureEvent.xconfigure.width)
16191 { 18195 SET_FRAME_GARBAGED (f);
16192 SET_FRAME_GARBAGED (f); 18196
16193 }
16194 FRAME_PIXEL_HEIGHT (f) = configureEvent.xconfigure.height; 18197 FRAME_PIXEL_HEIGHT (f) = configureEvent.xconfigure.height;
16195 FRAME_PIXEL_WIDTH (f) = configureEvent.xconfigure.width; 18198 FRAME_PIXEL_WIDTH (f) = configureEvent.xconfigure.width;
16196 } 18199 }
@@ -16317,8 +18320,31 @@ handle_one_xevent (struct x_display_info *dpyinfo,
16317 bool dnd_grab = false; 18320 bool dnd_grab = false;
16318 18321
16319 if (x_dnd_in_progress 18322 if (x_dnd_in_progress
18323 /* Handle these events normally if the recursion
18324 level is higher than when the drag-and-drop
18325 operation was initiated. This is so that mouse
18326 input works while we're in the debugger for, say,
18327 `x-dnd-movement-function`. */
18328 && (command_loop_level + minibuf_level
18329 <= x_dnd_recursion_depth)
16320 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) 18330 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
16321 { 18331 {
18332 f = mouse_or_wdesc_frame (dpyinfo, event->xbutton.window);
18333
18334 if (event->type == ButtonPress)
18335 {
18336 dpyinfo->grabbed |= (1 << event->xbutton.button);
18337 dpyinfo->last_mouse_frame = f;
18338 if (f && !tab_bar_p)
18339 f->last_tab_bar_item = -1;
18340#if ! defined (USE_GTK)
18341 if (f && !tool_bar_p)
18342 f->last_tool_bar_item = -1;
18343#endif /* not USE_GTK */
18344 }
18345 else
18346 dpyinfo->grabbed &= ~(1 << event->xbutton.button);
18347
16322 if (event->xbutton.type == ButtonPress 18348 if (event->xbutton.type == ButtonPress
16323 && x_dnd_last_seen_window != None 18349 && x_dnd_last_seen_window != None
16324 && x_dnd_last_protocol_version != -1) 18350 && x_dnd_last_protocol_version != -1)
@@ -16350,7 +18376,26 @@ handle_one_xevent (struct x_display_info *dpyinfo,
16350 x_dnd_end_window = x_dnd_last_seen_window; 18376 x_dnd_end_window = x_dnd_last_seen_window;
16351 x_dnd_in_progress = false; 18377 x_dnd_in_progress = false;
16352 18378
18379 if (x_dnd_update_tooltip
18380 && FRAMEP (tip_frame)
18381 && FRAME_LIVE_P (XFRAME (tip_frame))
18382 && (FRAME_X_DISPLAY (XFRAME (tip_frame))
18383 == FRAME_X_DISPLAY (x_dnd_frame)))
18384 Fx_hide_tip ();
18385
18386 x_dnd_finish_frame = x_dnd_frame;
18387
16353 if (x_dnd_last_seen_window != None 18388 if (x_dnd_last_seen_window != None
18389 && x_dnd_last_window_is_frame)
18390 {
18391 x_dnd_waiting_for_finish = false;
18392 x_dnd_note_self_drop (dpyinfo,
18393 x_dnd_last_seen_window,
18394 event->xbutton.x_root,
18395 event->xbutton.y_root,
18396 event->xbutton.time);
18397 }
18398 else if (x_dnd_last_seen_window != None
16354 && x_dnd_last_protocol_version != -1) 18399 && x_dnd_last_protocol_version != -1)
16355 { 18400 {
16356 x_dnd_pending_finish_target = x_dnd_last_seen_window; 18401 x_dnd_pending_finish_target = x_dnd_last_seen_window;
@@ -16386,9 +18431,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
16386 dmsg.side_effects 18431 dmsg.side_effects
16387 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo, 18432 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
16388 x_dnd_wanted_action), 18433 x_dnd_wanted_action),
16389 XM_DROP_SITE_VALID, 18434 XM_DROP_SITE_VALID, x_dnd_motif_operations,
16390 xm_side_effect_from_action (dpyinfo,
16391 x_dnd_wanted_action),
16392 (!x_dnd_xm_use_help 18435 (!x_dnd_xm_use_help
16393 ? XM_DROP_ACTION_DROP 18436 ? XM_DROP_ACTION_DROP
16394 : XM_DROP_ACTION_DROP_HELP)); 18437 : XM_DROP_ACTION_DROP_HELP));
@@ -16436,15 +18479,17 @@ handle_one_xevent (struct x_display_info *dpyinfo,
16436 x_dnd_last_motif_style = XM_DRAG_STYLE_NONE; 18479 x_dnd_last_motif_style = XM_DRAG_STYLE_NONE;
16437 x_dnd_last_seen_window = None; 18480 x_dnd_last_seen_window = None;
16438 x_dnd_last_seen_toplevel = None; 18481 x_dnd_last_seen_toplevel = None;
18482 x_dnd_last_window_is_frame = false;
16439 x_dnd_frame = NULL; 18483 x_dnd_frame = NULL;
16440 x_set_dnd_targets (NULL, 0);
16441 } 18484 }
16442 } 18485 }
16443 18486
16444 goto OTHER; 18487 goto OTHER;
16445 } 18488 }
16446 18489
16447 if (x_dnd_in_progress) 18490 if (x_dnd_in_progress
18491 && (command_loop_level + minibuf_level
18492 <= x_dnd_recursion_depth))
16448 goto OTHER; 18493 goto OTHER;
16449 18494
16450 memset (&compose_status, 0, sizeof (compose_status)); 18495 memset (&compose_status, 0, sizeof (compose_status));
@@ -16480,7 +18525,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
16480 f = x_any_window_to_frame (dpyinfo, event->xbutton.window); 18525 f = x_any_window_to_frame (dpyinfo, event->xbutton.window);
16481 18526
16482 if (event->xbutton.button > 3 18527 if (event->xbutton.button > 3
16483 && event->xbutton.button < 9 18528 && event->xbutton.button < 8
16484 && f) 18529 && f)
16485 { 18530 {
16486 if (ignore_next_mouse_click_timeout 18531 if (ignore_next_mouse_click_timeout
@@ -16794,7 +18839,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
16794 ev.window = enter->event; 18839 ev.window = enter->event;
16795 ev.time = enter->time; 18840 ev.time = enter->time;
16796 18841
16797 x_display_set_last_user_time (dpyinfo, xi_event->time); 18842 x_display_set_last_user_time (dpyinfo, enter->time);
16798 18843
16799#ifdef USE_MOTIF 18844#ifdef USE_MOTIF
16800 use_copy = true; 18845 use_copy = true;
@@ -16852,7 +18897,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
16852 18897
16853 if (f && x_mouse_click_focus_ignore_position) 18898 if (f && x_mouse_click_focus_ignore_position)
16854 { 18899 {
16855 ignore_next_mouse_click_timeout = xev->time + 200; 18900 ignore_next_mouse_click_timeout = (enter->time
18901 + x_mouse_click_focus_ignore_time);
16856 mouse_click_timeout_display = dpyinfo; 18902 mouse_click_timeout_display = dpyinfo;
16857 } 18903 }
16858 18904
@@ -16896,7 +18942,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
16896 18942
16897#ifdef USE_X_TOOLKIT 18943#ifdef USE_X_TOOLKIT
16898 if (popup_activated () 18944 if (popup_activated ()
16899 && leave->mode == XINotifyPassiveUngrab) 18945 && (leave->mode == XINotifyPassiveUngrab
18946 || leave->mode == XINotifyUngrab))
16900 any = x_any_window_to_frame (dpyinfo, leave->event); 18947 any = x_any_window_to_frame (dpyinfo, leave->event);
16901#endif 18948#endif
16902 18949
@@ -16941,7 +18988,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
16941 leave->deviceid, false); 18988 leave->deviceid, false);
16942#endif 18989#endif
16943 18990
16944 x_display_set_last_user_time (dpyinfo, xi_event->time); 18991 x_display_set_last_user_time (dpyinfo, leave->time);
16945 18992
16946#ifdef HAVE_XWIDGETS 18993#ifdef HAVE_XWIDGETS
16947 { 18994 {
@@ -16968,6 +19015,16 @@ handle_one_xevent (struct x_display_info *dpyinfo,
16968 masks are set on the frame widget's window. */ 19015 masks are set on the frame widget's window. */
16969 f = x_window_to_frame (dpyinfo, leave->event); 19016 f = x_window_to_frame (dpyinfo, leave->event);
16970 19017
19018 /* Also do this again here, since the test for `any'
19019 above may not have found a frame, as that usually
19020 just looks up a top window on Xt builds. */
19021
19022#ifdef HAVE_XINPUT2_1
19023 if (leave->detail != XINotifyInferior && f)
19024 xi_reset_scroll_valuators_for_device_id (dpyinfo,
19025 leave->deviceid, false);
19026#endif
19027
16971 if (!f) 19028 if (!f)
16972 f = x_top_window_to_frame (dpyinfo, leave->event); 19029 f = x_top_window_to_frame (dpyinfo, leave->event);
16973#endif 19030#endif
@@ -16985,7 +19042,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
16985 Do it only if there's something to cancel. 19042 Do it only if there's something to cancel.
16986 Otherwise, the startup message is cleared when 19043 Otherwise, the startup message is cleared when
16987 the mouse leaves the frame. */ 19044 the mouse leaves the frame. */
16988 if (any_help_event_p) 19045 if (any_help_event_p
19046 /* But never if `mouse-drag-and-drop-region' is
19047 in progress, since that results in the
19048 tooltip being dismissed when the mouse moves
19049 on top. */
19050 && !((EQ (track_mouse, Qdrag_source)
19051 || EQ (track_mouse, Qdropping))
19052 && gui_mouse_grabbed (dpyinfo)))
16989 do_help = -1; 19053 do_help = -1;
16990 } 19054 }
16991#ifdef USE_GTK 19055#ifdef USE_GTK
@@ -17004,6 +19068,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17004 XIValuatorState *states; 19068 XIValuatorState *states;
17005 double *values; 19069 double *values;
17006 bool found_valuator = false; 19070 bool found_valuator = false;
19071 bool other_valuators_found = false;
17007#endif 19072#endif
17008 /* A fake XMotionEvent for x_note_mouse_movement. */ 19073 /* A fake XMotionEvent for x_note_mouse_movement. */
17009 XMotionEvent ev; 19074 XMotionEvent ev;
@@ -17061,6 +19126,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17061 i, *values, &val); 19126 i, *values, &val);
17062 values++; 19127 values++;
17063 19128
19129 if (!val)
19130 {
19131 other_valuators_found = true;
19132 continue;
19133 }
19134
17064 if (delta != DBL_MAX) 19135 if (delta != DBL_MAX)
17065 { 19136 {
17066 if (!f) 19137 if (!f)
@@ -17208,12 +19279,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17208 So instead of that, just ignore XI wheel 19279 So instead of that, just ignore XI wheel
17209 events which land on a scroll bar. 19280 events which land on a scroll bar.
17210 19281
17211 Here we assume anything which isn't the edit 19282 Here we assume anything which isn't the edit
17212 widget window is a scroll bar. */ 19283 widget window is a scroll bar. */
17213 19284
17214 if (xev->child != None 19285 if (xev->child != None
17215 && xev->child != FRAME_X_WINDOW (f)) 19286 && xev->child != FRAME_X_WINDOW (f))
17216 goto OTHER; 19287 goto XI_OTHER;
17217#endif 19288#endif
17218 19289
17219 if (fabs (total_x) > 0 || fabs (total_y) > 0) 19290 if (fabs (total_x) > 0 || fabs (total_y) > 0)
@@ -17249,7 +19320,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17249 if (source && !NILP (source->name)) 19320 if (source && !NILP (source->name))
17250 inev.ie.device = source->name; 19321 inev.ie.device = source->name;
17251 19322
17252 goto XI_OTHER; 19323 if (!other_valuators_found)
19324 goto XI_OTHER;
17253 } 19325 }
17254#ifdef HAVE_XWIDGETS 19326#ifdef HAVE_XWIDGETS
17255 } 19327 }
@@ -17304,10 +19376,23 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17304 f = mouse_or_wdesc_frame (dpyinfo, xev->event); 19376 f = mouse_or_wdesc_frame (dpyinfo, xev->event);
17305 19377
17306 if (x_dnd_in_progress 19378 if (x_dnd_in_progress
19379 /* Handle these events normally if the recursion
19380 level is higher than when the drag-and-drop
19381 operation was initiated. This is so that mouse
19382 input works while we're in the debugger for, say,
19383 `x-dnd-movement-function`. */
19384 && (command_loop_level + minibuf_level
19385 <= x_dnd_recursion_depth)
17307 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) 19386 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
17308 { 19387 {
17309 Window target, toplevel; 19388 Window target, toplevel;
17310 int target_proto, motif_style; 19389 int target_proto, motif_style;
19390 XRectangle *r;
19391 bool was_frame;
19392
19393 /* Always clear mouse face. */
19394 clear_mouse_face (hlinfo);
19395 hlinfo->mouse_face_hidden = true;
17311 19396
17312 /* Sometimes the drag-and-drop operation starts with the 19397 /* Sometimes the drag-and-drop operation starts with the
17313 pointer of a frame invisible due to input. Since 19398 pointer of a frame invisible due to input. Since
@@ -17315,14 +19400,37 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17315 visible manually. */ 19400 visible manually. */
17316 19401
17317 if (f) 19402 if (f)
17318 XTtoggle_invisible_pointer (f, false); 19403 {
19404 XTtoggle_invisible_pointer (f, false);
19405
19406 r = &dpyinfo->last_mouse_glyph;
19407
19408 /* Also remember the mouse glyph and set
19409 mouse_moved. */
19410 if (f != dpyinfo->last_mouse_glyph_frame
19411 || xev->event_x < r->x
19412 || xev->event_x >= r->x + r->width
19413 || xev->event_y < r->y
19414 || xev->event_y >= r->y + r->height)
19415 {
19416 f->mouse_moved = true;
19417 f->last_mouse_device = (source ? source->name
19418 : Qnil);
19419 dpyinfo->last_mouse_scroll_bar = NULL;
19420
19421 remember_mouse_glyph (f, xev->event_x,
19422 xev->event_y, r);
19423 dpyinfo->last_mouse_glyph_frame = f;
19424 }
19425 }
17319 19426
17320 target = x_dnd_get_target_window (dpyinfo, 19427 target = x_dnd_get_target_window (dpyinfo,
17321 xev->root_x, 19428 xev->root_x,
17322 xev->root_y, 19429 xev->root_y,
17323 &target_proto, 19430 &target_proto,
17324 &motif_style, 19431 &motif_style,
17325 &toplevel); 19432 &toplevel,
19433 &was_frame);
17326 19434
17327 if (toplevel != x_dnd_last_seen_toplevel) 19435 if (toplevel != x_dnd_last_seen_toplevel)
17328 { 19436 {
@@ -17339,6 +19447,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17339 x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window); 19447 x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
17340 else if (x_dnd_last_seen_window != None 19448 else if (x_dnd_last_seen_window != None
17341 && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) 19449 && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
19450 && !x_dnd_disable_motif_drag
17342 && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame)) 19451 && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
17343 { 19452 {
17344 if (!x_dnd_motif_setup_p) 19453 if (!x_dnd_motif_setup_p)
@@ -17378,6 +19487,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17378 x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window); 19487 x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
17379 else if (x_dnd_last_seen_window != None 19488 else if (x_dnd_last_seen_window != None
17380 && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) 19489 && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
19490 && !x_dnd_disable_motif_drag
17381 && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame)) 19491 && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
17382 { 19492 {
17383 if (!x_dnd_motif_setup_p) 19493 if (!x_dnd_motif_setup_p)
@@ -17396,7 +19506,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17396 dmsg.side_effects 19506 dmsg.side_effects
17397 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo, 19507 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
17398 x_dnd_wanted_action), 19508 x_dnd_wanted_action),
17399 XM_DROP_SITE_NONE, XM_DRAG_NOOP, 19509 XM_DROP_SITE_NONE, x_dnd_motif_operations,
17400 XM_DROP_ACTION_DROP_CANCEL); 19510 XM_DROP_ACTION_DROP_CANCEL);
17401 dmsg.timestamp = xev->time; 19511 dmsg.timestamp = xev->time;
17402 dmsg.x = lrint (xev->root_x); 19512 dmsg.x = lrint (xev->root_x);
@@ -17422,11 +19532,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17422 x_dnd_last_seen_window = target; 19532 x_dnd_last_seen_window = target;
17423 x_dnd_last_protocol_version = target_proto; 19533 x_dnd_last_protocol_version = target_proto;
17424 x_dnd_last_motif_style = motif_style; 19534 x_dnd_last_motif_style = motif_style;
19535 x_dnd_last_window_is_frame = was_frame;
17425 19536
17426 if (target != None && x_dnd_last_protocol_version != -1) 19537 if (target != None && x_dnd_last_protocol_version != -1)
17427 x_dnd_send_enter (x_dnd_frame, target, 19538 x_dnd_send_enter (x_dnd_frame, target,
17428 x_dnd_last_protocol_version); 19539 x_dnd_last_protocol_version);
17429 else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)) 19540 else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
19541 && !x_dnd_disable_motif_drag)
17430 { 19542 {
17431 if (!x_dnd_motif_setup_p) 19543 if (!x_dnd_motif_setup_p)
17432 xm_setup_drag_info (dpyinfo, x_dnd_frame); 19544 xm_setup_drag_info (dpyinfo, x_dnd_frame);
@@ -17445,7 +19557,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17445 } 19557 }
17446 } 19558 }
17447 19559
17448 if (x_dnd_last_protocol_version != -1 && target != None) 19560 if (x_dnd_last_window_is_frame && target != None)
19561 x_dnd_note_self_position (dpyinfo, target,
19562 xev->root_x, xev->root_y);
19563 else if (x_dnd_last_protocol_version != -1 && target != None)
17449 { 19564 {
17450 dnd_state = xev->mods.effective; 19565 dnd_state = xev->mods.effective;
17451 19566
@@ -17466,7 +19581,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17466 x_dnd_wanted_action, 0, 19581 x_dnd_wanted_action, 0,
17467 dnd_state); 19582 dnd_state);
17468 } 19583 }
17469 else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None) 19584 else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None
19585 && !x_dnd_disable_motif_drag)
17470 { 19586 {
17471 if (!x_dnd_motif_setup_p) 19587 if (!x_dnd_motif_setup_p)
17472 xm_setup_drag_info (dpyinfo, x_dnd_frame); 19588 xm_setup_drag_info (dpyinfo, x_dnd_frame);
@@ -17477,9 +19593,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17477 dmsg.side_effects 19593 dmsg.side_effects
17478 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo, 19594 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
17479 x_dnd_wanted_action), 19595 x_dnd_wanted_action),
17480 XM_DROP_SITE_VALID, 19596 XM_DROP_SITE_VALID, x_dnd_motif_operations,
17481 xm_side_effect_from_action (dpyinfo,
17482 x_dnd_wanted_action),
17483 (!x_dnd_xm_use_help 19597 (!x_dnd_xm_use_help
17484 ? XM_DROP_ACTION_DROP 19598 ? XM_DROP_ACTION_DROP
17485 : XM_DROP_ACTION_DROP_HELP)); 19599 : XM_DROP_ACTION_DROP_HELP));
@@ -17492,6 +19606,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17492 target, &dmsg); 19606 target, &dmsg);
17493 } 19607 }
17494 19608
19609 x_dnd_update_tooltip_position (xev->root_x, xev->root_y);
19610
17495 goto XI_OTHER; 19611 goto XI_OTHER;
17496 } 19612 }
17497 19613
@@ -17558,7 +19674,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17558 { 19674 {
17559#ifndef USE_TOOLKIT_SCROLL_BARS 19675#ifndef USE_TOOLKIT_SCROLL_BARS
17560 struct scroll_bar *bar 19676 struct scroll_bar *bar
17561 = x_window_to_scroll_bar (xi_event->display, xev->event, 2); 19677 = x_window_to_scroll_bar (dpyinfo->display, xev->event, 2);
17562 19678
17563 if (bar) 19679 if (bar)
17564 x_scroll_bar_note_movement (bar, &ev); 19680 x_scroll_bar_note_movement (bar, &ev);
@@ -17595,8 +19711,26 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17595 int dnd_state; 19711 int dnd_state;
17596 19712
17597 if (x_dnd_in_progress 19713 if (x_dnd_in_progress
19714 && (command_loop_level + minibuf_level
19715 <= x_dnd_recursion_depth)
17598 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) 19716 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
17599 { 19717 {
19718 f = mouse_or_wdesc_frame (dpyinfo, xev->event);
19719
19720 if (xev->evtype == XI_ButtonPress)
19721 {
19722 dpyinfo->grabbed |= (1 << xev->detail);
19723 dpyinfo->last_mouse_frame = f;
19724 if (f && !tab_bar_p)
19725 f->last_tab_bar_item = -1;
19726#if ! defined (USE_GTK)
19727 if (f && !tool_bar_p)
19728 f->last_tool_bar_item = -1;
19729#endif /* not USE_GTK */
19730 }
19731 else
19732 dpyinfo->grabbed &= ~(1 << xev->detail);
19733
17600 if (xev->evtype == XI_ButtonPress 19734 if (xev->evtype == XI_ButtonPress
17601 && x_dnd_last_seen_window != None 19735 && x_dnd_last_seen_window != None
17602 && x_dnd_last_protocol_version != -1) 19736 && x_dnd_last_protocol_version != -1)
@@ -17634,8 +19768,33 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17634 x_dnd_end_window = x_dnd_last_seen_window; 19768 x_dnd_end_window = x_dnd_last_seen_window;
17635 x_dnd_in_progress = false; 19769 x_dnd_in_progress = false;
17636 19770
19771 /* If a tooltip that we're following is
19772 displayed, hide it now. */
19773
19774 if (x_dnd_update_tooltip
19775 && FRAMEP (tip_frame)
19776 && FRAME_LIVE_P (XFRAME (tip_frame))
19777 && (FRAME_X_DISPLAY (XFRAME (tip_frame))
19778 == FRAME_X_DISPLAY (x_dnd_frame)))
19779 Fx_hide_tip ();
19780
19781 /* This doesn't have to be marked since it
19782 is only accessed if
19783 x_dnd_waiting_for_finish is true, which
19784 is only possible inside the DND event
19785 loop where that frame is on the
19786 stack. */
19787 x_dnd_finish_frame = x_dnd_frame;
19788
17637 if (x_dnd_last_seen_window != None 19789 if (x_dnd_last_seen_window != None
17638 && x_dnd_last_protocol_version != -1) 19790 && x_dnd_last_window_is_frame)
19791 {
19792 x_dnd_waiting_for_finish = false;
19793 x_dnd_note_self_drop (dpyinfo, x_dnd_last_seen_window,
19794 xev->root_x, xev->root_y, xev->time);
19795 }
19796 else if (x_dnd_last_seen_window != None
19797 && x_dnd_last_protocol_version != -1)
17639 { 19798 {
17640 x_dnd_pending_finish_target = x_dnd_last_seen_window; 19799 x_dnd_pending_finish_target = x_dnd_last_seen_window;
17641 x_dnd_waiting_for_finish_proto = x_dnd_last_protocol_version; 19800 x_dnd_waiting_for_finish_proto = x_dnd_last_protocol_version;
@@ -17670,9 +19829,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17670 dmsg.side_effects 19829 dmsg.side_effects
17671 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo, 19830 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
17672 x_dnd_wanted_action), 19831 x_dnd_wanted_action),
17673 XM_DROP_SITE_VALID, 19832 XM_DROP_SITE_VALID, x_dnd_motif_operations,
17674 xm_side_effect_from_action (dpyinfo,
17675 x_dnd_wanted_action),
17676 (!x_dnd_xm_use_help 19833 (!x_dnd_xm_use_help
17677 ? XM_DROP_ACTION_DROP 19834 ? XM_DROP_ACTION_DROP
17678 : XM_DROP_ACTION_DROP_HELP)); 19835 : XM_DROP_ACTION_DROP_HELP));
@@ -17727,15 +19884,17 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17727 x_dnd_last_motif_style = XM_DRAG_STYLE_NONE; 19884 x_dnd_last_motif_style = XM_DRAG_STYLE_NONE;
17728 x_dnd_last_seen_window = None; 19885 x_dnd_last_seen_window = None;
17729 x_dnd_last_seen_toplevel = None; 19886 x_dnd_last_seen_toplevel = None;
19887 x_dnd_last_window_is_frame = false;
17730 x_dnd_frame = NULL; 19888 x_dnd_frame = NULL;
17731 x_set_dnd_targets (NULL, 0);
17732 19889
17733 goto XI_OTHER; 19890 goto XI_OTHER;
17734 } 19891 }
17735 } 19892 }
17736 } 19893 }
17737 19894
17738 if (x_dnd_in_progress) 19895 if (x_dnd_in_progress
19896 && (command_loop_level + minibuf_level
19897 <= x_dnd_recursion_depth))
17739 goto XI_OTHER; 19898 goto XI_OTHER;
17740 19899
17741#ifdef USE_MOTIF 19900#ifdef USE_MOTIF
@@ -17801,9 +19960,17 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17801 19960
17802 g_object_ref (copy->button.window); 19961 g_object_ref (copy->button.window);
17803 19962
17804 if (popup_activated () 19963 if (popup_activated ())
17805 && xev->evtype == XI_ButtonRelease) 19964 {
17806 goto XI_OTHER; 19965 /* GTK+ popup menus don't respond to core buttons
19966 after Button3, so don't dismiss popup menus upon
19967 wheel movement here either. */
19968 if (xev->detail > 3)
19969 *finish = X_EVENT_DROP;
19970
19971 if (xev->evtype == XI_ButtonRelease)
19972 goto XI_OTHER;
19973 }
17807#endif 19974#endif
17808 19975
17809#ifdef HAVE_XINPUT2_1 19976#ifdef HAVE_XINPUT2_1
@@ -17896,7 +20063,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17896 20063
17897 f = x_any_window_to_frame (dpyinfo, xev->event); 20064 f = x_any_window_to_frame (dpyinfo, xev->event);
17898 20065
17899 if (xev->detail > 3 && xev->detail < 9 && f) 20066 if (xev->detail > 3 && xev->detail < 8 && f)
17900 { 20067 {
17901 if (xev->evtype == XI_ButtonRelease) 20068 if (xev->evtype == XI_ButtonRelease)
17902 { 20069 {
@@ -17939,7 +20106,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17939 20106
17940 if (f) 20107 if (f)
17941 { 20108 {
17942 if (xev->detail >= 4 && xev->detail <= 8) 20109 if (xev->detail >= 4 && xev->detail < 8)
17943 { 20110 {
17944 if (xev->evtype == XI_ButtonRelease) 20111 if (xev->evtype == XI_ButtonRelease)
17945 { 20112 {
@@ -18260,9 +20427,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
18260 state |= x_emacs_to_x_modifiers (dpyinfo, extra_keyboard_modifiers); 20427 state |= x_emacs_to_x_modifiers (dpyinfo, extra_keyboard_modifiers);
18261 20428
18262#ifdef HAVE_XKB 20429#ifdef HAVE_XKB
18263 if (FRAME_DISPLAY_INFO (f)->xkb_desc) 20430 if (dpyinfo->xkb_desc)
18264 { 20431 {
18265 XkbDescRec *rec = FRAME_DISPLAY_INFO (f)->xkb_desc; 20432 XkbDescRec *rec = dpyinfo->xkb_desc;
18266 20433
18267 if (rec->map->modmap && rec->map->modmap[xev->detail]) 20434 if (rec->map->modmap && rec->map->modmap[xev->detail])
18268 goto xi_done_keysym; 20435 goto xi_done_keysym;
@@ -18352,7 +20519,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
18352 if (status_return == XBufferOverflow) 20519 if (status_return == XBufferOverflow)
18353 { 20520 {
18354 copy_bufsiz = nbytes + 1; 20521 copy_bufsiz = nbytes + 1;
18355 copy_bufptr = alloca (copy_bufsiz); 20522 copy_bufptr = SAFE_ALLOCA (copy_bufsiz);
18356 nbytes = XmbLookupString (FRAME_XIC (f), 20523 nbytes = XmbLookupString (FRAME_XIC (f),
18357 &xkey, (char *) copy_bufptr, 20524 &xkey, (char *) copy_bufptr,
18358 copy_bufsiz, &keysym, 20525 copy_bufsiz, &keysym,
@@ -18384,8 +20551,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
18384 copy_bufsiz, &overflow); 20551 copy_bufsiz, &overflow);
18385 if (overflow) 20552 if (overflow)
18386 { 20553 {
18387 copy_bufptr = alloca ((copy_bufsiz += overflow) 20554 copy_bufptr = SAFE_ALLOCA ((copy_bufsiz += overflow)
18388 * sizeof *copy_bufptr); 20555 * sizeof *copy_bufptr);
18389 overflow = 0; 20556 overflow = 0;
18390 nbytes = XkbTranslateKeySym (dpyinfo->display, &sym, 20557 nbytes = XkbTranslateKeySym (dpyinfo->display, &sym,
18391 state & ~mods_rtrn, copy_bufptr, 20558 state & ~mods_rtrn, copy_bufptr,
@@ -18696,7 +20863,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
18696 struct xi_touch_point_t *tem, *last; 20863 struct xi_touch_point_t *tem, *last;
18697#endif 20864#endif
18698 20865
18699 disabled = alloca (sizeof *disabled * hev->num_info); 20866 disabled = SAFE_ALLOCA (sizeof *disabled * hev->num_info);
18700 n_disabled = 0; 20867 n_disabled = 0;
18701 20868
18702 for (i = 0; i < hev->num_info; ++i) 20869 for (i = 0; i < hev->num_info; ++i)
@@ -18995,6 +21162,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
18995 21162
18996 if (!menu_bar_p && !tool_bar_p) 21163 if (!menu_bar_p && !tool_bar_p)
18997 { 21164 {
21165 x_catch_errors (dpyinfo->display);
21166
18998 if (f && device->direct_p) 21167 if (f && device->direct_p)
18999 { 21168 {
19000 *finish = X_EVENT_DROP; 21169 *finish = X_EVENT_DROP;
@@ -19023,6 +21192,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
19023 XIAllowTouchEvents (dpyinfo->display, xev->deviceid, 21192 XIAllowTouchEvents (dpyinfo->display, xev->deviceid,
19024 xev->detail, xev->event, XIRejectTouch); 21193 xev->detail, xev->event, XIRejectTouch);
19025#endif 21194#endif
21195 x_uncatch_errors ();
19026 } 21196 }
19027 else 21197 else
19028 { 21198 {
@@ -19135,7 +21305,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
19135 21305
19136 device = xi_device_from_id (dpyinfo, pev->deviceid); 21306 device = xi_device_from_id (dpyinfo, pev->deviceid);
19137 source = xi_device_from_id (dpyinfo, pev->sourceid); 21307 source = xi_device_from_id (dpyinfo, pev->sourceid);
19138 x_display_set_last_user_time (dpyinfo, xi_event->time); 21308 x_display_set_last_user_time (dpyinfo, pev->time);
19139 21309
19140 if (!device) 21310 if (!device)
19141 goto XI_OTHER; 21311 goto XI_OTHER;
@@ -19466,7 +21636,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
19466 } 21636 }
19467 21637
19468 /* And the common case where there is no input rect and the 21638 /* And the common case where there is no input rect and the
19469 bouding rect equals the window dimensions. */ 21639 bounding rect equals the window dimensions. */
19470 21640
19471 if (tem->n_input_rects == -1 21641 if (tem->n_input_rects == -1
19472 && tem->n_bounding_rects == 1 21642 && tem->n_bounding_rects == 1
@@ -19484,6 +21654,75 @@ handle_one_xevent (struct x_display_info *dpyinfo,
19484 } 21654 }
19485 } 21655 }
19486#endif 21656#endif
21657#if defined HAVE_XRANDR && !defined USE_GTK
21658 if (dpyinfo->xrandr_supported_p
21659 && (event->type == (dpyinfo->xrandr_event_base
21660 + RRScreenChangeNotify)
21661 || event->type == (dpyinfo->xrandr_event_base
21662 + RRNotify)))
21663 {
21664 union buffered_input_event *ev;
21665 Time timestamp;
21666 Lisp_Object current_monitors;
21667 XRRScreenChangeNotifyEvent *notify;
21668
21669 if (event->type == (dpyinfo->xrandr_event_base
21670 + RRScreenChangeNotify))
21671 XRRUpdateConfiguration (event);
21672
21673 if (event->type == (dpyinfo->xrandr_event_base
21674 + RRScreenChangeNotify))
21675 {
21676 notify = ((XRRScreenChangeNotifyEvent *) event);
21677 timestamp = notify->timestamp;
21678
21679 /* Don't set screen dimensions if the notification is
21680 for a different screen. */
21681 if (notify->root == dpyinfo->root_window)
21682 {
21683 dpyinfo->screen_width = notify->width;
21684 dpyinfo->screen_height = notify->height;
21685 dpyinfo->screen_mm_width = notify->mwidth;
21686 dpyinfo->screen_mm_height = notify->mheight;
21687 }
21688 }
21689 else
21690 timestamp = 0;
21691
21692 ev = (kbd_store_ptr == kbd_buffer
21693 ? kbd_buffer + KBD_BUFFER_SIZE - 1
21694 : kbd_store_ptr - 1);
21695
21696 if (kbd_store_ptr != kbd_fetch_ptr
21697 && ev->ie.kind == MONITORS_CHANGED_EVENT
21698 && XTERMINAL (ev->ie.arg) == dpyinfo->terminal)
21699 /* Don't store a MONITORS_CHANGED_EVENT if there is
21700 already an undelivered event on the queue. */
21701 goto OTHER;
21702
21703 inev.ie.kind = MONITORS_CHANGED_EVENT;
21704 inev.ie.timestamp = timestamp;
21705 XSETTERMINAL (inev.ie.arg, dpyinfo->terminal);
21706
21707 /* Also don't do anything if the monitor configuration
21708 didn't really change. */
21709
21710 current_monitors
21711 = Fx_display_monitor_attributes_list (inev.ie.arg);
21712
21713 if (!NILP (Fequal (current_monitors,
21714 dpyinfo->last_monitor_attributes_list)))
21715 inev.ie.kind = NO_EVENT;
21716
21717 dpyinfo->last_monitor_attributes_list = current_monitors;
21718
21719 if (x_dnd_in_progress && x_dnd_update_tooltip)
21720 x_dnd_monitors = current_monitors;
21721
21722 if (inev.ie.kind != NO_EVENT)
21723 x_dnd_update_tooltip_now ();
21724 }
21725#endif
19487 OTHER: 21726 OTHER:
19488#ifdef USE_X_TOOLKIT 21727#ifdef USE_X_TOOLKIT
19489 block_input (); 21728 block_input ();
@@ -19566,6 +21805,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
19566 if (any && any != f) 21805 if (any && any != f)
19567 flush_dirty_back_buffer_on (any); 21806 flush_dirty_back_buffer_on (any);
19568#endif 21807#endif
21808
21809 SAFE_FREE ();
19569 return count; 21810 return count;
19570} 21811}
19571 21812
@@ -19611,8 +21852,18 @@ XTread_socket (struct terminal *terminal, struct input_event *hold_quit)
19611 /* Don't allow XTread_socket to do anything if drag-and-drop is in 21852 /* Don't allow XTread_socket to do anything if drag-and-drop is in
19612 progress. If unblock_input causes XTread_socket to be called and 21853 progress. If unblock_input causes XTread_socket to be called and
19613 read X events while the drag-and-drop event loop is in progress, 21854 read X events while the drag-and-drop event loop is in progress,
19614 things can go wrong very quick. */ 21855 things can go wrong very quick.
19615 if (x_dnd_in_progress || x_dnd_waiting_for_finish) 21856
21857 When x_dnd_unwind_flag is true, the above doesn't apply, since
21858 the surrounding code takes special precautions to keep it safe.
21859
21860 That doesn't matter for events from displays other than the
21861 display of the drag-and-drop operation, though. */
21862 if (!x_dnd_unwind_flag
21863 && ((x_dnd_in_progress
21864 && dpyinfo->display == FRAME_X_DISPLAY (x_dnd_frame))
21865 || (x_dnd_waiting_for_finish
21866 && dpyinfo->display == x_dnd_finish_display)))
19616 return 0; 21867 return 0;
19617 21868
19618 block_input (); 21869 block_input ();
@@ -20129,70 +22380,131 @@ x_text_icon (struct frame *f, const char *icon_name)
20129 return false; 22380 return false;
20130} 22381}
20131 22382
20132#define X_ERROR_MESSAGE_SIZE 200
20133
20134/* If non-nil, this should be a string.
20135 It means catch X errors and store the error message in this string.
20136 22383
20137 The reason we use a stack is that x_catch_error/x_uncatch_error can 22384struct x_error_message_stack
20138 be called from a signal handler. 22385{
20139*/ 22386 /* Pointer to the error message of any error that was generated, or
22387 NULL. */
22388 char *string;
20140 22389
20141struct x_error_message_stack { 22390 /* The display this error handler applies to. */
20142 char string[X_ERROR_MESSAGE_SIZE];
20143 Display *dpy; 22391 Display *dpy;
22392
22393 /* A function to call upon an error if non-NULL. */
20144 x_special_error_handler handler; 22394 x_special_error_handler handler;
22395
22396 /* Some data to pass to that handler function. */
20145 void *handler_data; 22397 void *handler_data;
22398
22399 /* The previous handler in this stack. */
20146 struct x_error_message_stack *prev; 22400 struct x_error_message_stack *prev;
22401
22402 /* The first request that this error handler applies to. Keeping
22403 track of this allows us to avoid an XSync yet still have errors
22404 for previously made requests be handled correctly. */
22405 unsigned long first_request;
20147}; 22406};
22407
22408/* Stack of X error message handlers. Whenever an error is generated
22409 on a display, look in this stack for an appropriate error handler,
22410 set its `string' to the error message and call its `handler' with
22411 `handler_data'. If no handler applies to the error, don't catch
22412 it, and let it crash Emacs instead.
22413
22414 This used to be a pointer to a string in which any error would be
22415 placed before 2006. */
20148static struct x_error_message_stack *x_error_message; 22416static struct x_error_message_stack *x_error_message;
20149 22417
20150/* An X error handler which stores the error message in 22418/* The amount of items (depth) in that stack. */
20151 *x_error_message. This is called from x_error_handler if 22419int x_error_message_count;
20152 x_catch_errors is in effect. */ 22420
22421static struct x_error_message_stack *
22422x_find_error_handler (Display *dpy, XErrorEvent *event)
22423{
22424 struct x_error_message_stack *stack;
22425
22426 stack = x_error_message;
22427
22428 while (stack)
22429 {
22430 if (X_COMPARE_SERIALS (event->serial, >=,
22431 stack->first_request)
22432 && dpy == stack->dpy)
22433 return stack;
22434
22435 stack = stack->prev;
22436 }
22437
22438 return NULL;
22439}
22440
22441void
22442x_unwind_errors_to (int depth)
22443{
22444 while (x_error_message_count > depth)
22445 /* This is safe to call because we check whether or not
22446 x_error_message->dpy is still alive before calling XSync. */
22447 x_uncatch_errors ();
22448}
22449
22450#define X_ERROR_MESSAGE_SIZE 200
22451
22452/* An X error handler which stores the error message in the first
22453 applicable handler in the x_error_message stack. This is called
22454 from *x_error_handler if an x_catch_errors for DISPLAY is in
22455 effect. */
20153 22456
20154static void 22457static void
20155x_error_catcher (Display *display, XErrorEvent *event) 22458x_error_catcher (Display *display, XErrorEvent *event,
22459 struct x_error_message_stack *stack)
20156{ 22460{
22461 char buf[X_ERROR_MESSAGE_SIZE];
22462
20157 XGetErrorText (display, event->error_code, 22463 XGetErrorText (display, event->error_code,
20158 x_error_message->string, 22464 buf, X_ERROR_MESSAGE_SIZE);
20159 X_ERROR_MESSAGE_SIZE); 22465
20160 if (x_error_message->handler) 22466 if (stack->string)
20161 x_error_message->handler (display, event, x_error_message->string, 22467 xfree (stack->string);
20162 x_error_message->handler_data); 22468
22469 stack->string = xstrdup (buf);
22470
22471 if (stack->handler)
22472 stack->handler (display, event, stack->string,
22473 stack->handler_data);
20163} 22474}
20164 22475
20165/* Begin trapping X errors for display DPY. Actually we trap X errors 22476/* Begin trapping X errors for display DPY.
20166 for all displays, but DPY should be the display you are actually
20167 operating on.
20168 22477
20169 After calling this function, X protocol errors no longer cause 22478 After calling this function, X protocol errors generated on DPY no
20170 Emacs to exit; instead, they are recorded in the string 22479 longer cause Emacs to exit; instead, they are recorded in an error
20171 stored in *x_error_message. 22480 handler pushed onto the stack `x_error_message'.
20172 22481
20173 Calling x_check_errors signals an Emacs error if an X error has 22482 Calling x_check_errors signals an Emacs error if an X error has
20174 occurred since the last call to x_catch_errors or x_check_errors. 22483 occurred since the last call to x_catch_errors or x_check_errors.
20175 22484
20176 Calling x_uncatch_errors resumes the normal error handling. 22485 Calling x_uncatch_errors resumes the normal error handling,
20177 Calling x_uncatch_errors_after_check is similar, but skips an XSync 22486 skipping an XSync if the last request made is known to have been
20178 to the server, and should be used only immediately after 22487 processed. Calling x_uncatch_errors_after_check is similar, but
20179 x_had_errors_p or x_check_errors. */ 22488 always skips an XSync to the server, and should be used only
22489 immediately after x_had_errors_p or x_check_errors, or when it is
22490 known that no requests have been made since the last x_catch_errors
22491 call for DPY. */
20180 22492
20181void 22493void
20182x_catch_errors_with_handler (Display *dpy, x_special_error_handler handler, 22494x_catch_errors_with_handler (Display *dpy, x_special_error_handler handler,
20183 void *handler_data) 22495 void *handler_data)
20184{ 22496{
20185 struct x_error_message_stack *data = xmalloc (sizeof *data); 22497 struct x_error_message_stack *data;
20186
20187 /* Make sure any errors from previous requests have been dealt with. */
20188 XSync (dpy, False);
20189 22498
22499 data = xzalloc (sizeof *data);
20190 data->dpy = dpy; 22500 data->dpy = dpy;
20191 data->string[0] = 0;
20192 data->handler = handler; 22501 data->handler = handler;
20193 data->handler_data = handler_data; 22502 data->handler_data = handler_data;
20194 data->prev = x_error_message; 22503 data->prev = x_error_message;
22504 data->first_request = NextRequest (dpy);
20195 x_error_message = data; 22505 x_error_message = data;
22506
22507 ++x_error_message_count;
20196} 22508}
20197 22509
20198void 22510void
@@ -20216,12 +22528,14 @@ x_uncatch_errors_after_check (void)
20216 block_input (); 22528 block_input ();
20217 tmp = x_error_message; 22529 tmp = x_error_message;
20218 x_error_message = x_error_message->prev; 22530 x_error_message = x_error_message->prev;
22531 --x_error_message_count;
22532 if (tmp->string)
22533 xfree (tmp->string);
20219 xfree (tmp); 22534 xfree (tmp);
20220 unblock_input (); 22535 unblock_input ();
20221} 22536}
20222 22537
20223/* Undo the last x_catch_errors call. 22538/* Undo the last x_catch_errors call. */
20224 DPY should be the display that was passed to x_catch_errors. */
20225 22539
20226void 22540void
20227x_uncatch_errors (void) 22541x_uncatch_errors (void)
@@ -20239,11 +22553,22 @@ x_uncatch_errors (void)
20239 22553
20240 /* The display may have been closed before this function is called. 22554 /* The display may have been closed before this function is called.
20241 Check if it is still open before calling XSync. */ 22555 Check if it is still open before calling XSync. */
20242 if (x_display_info_for_display (x_error_message->dpy) != 0) 22556 if (x_display_info_for_display (x_error_message->dpy) != 0
22557 /* There is no point in making this extra sync if all requests
22558 are known to have been fully processed. */
22559 && (LastKnownRequestProcessed (x_error_message->dpy)
22560 != NextRequest (x_error_message->dpy) - 1)
22561 /* Likewise if no request was made since the trap was
22562 installed. */
22563 && (NextRequest (x_error_message->dpy)
22564 > x_error_message->first_request))
20243 XSync (x_error_message->dpy, False); 22565 XSync (x_error_message->dpy, False);
20244 22566
20245 tmp = x_error_message; 22567 tmp = x_error_message;
20246 x_error_message = x_error_message->prev; 22568 x_error_message = x_error_message->prev;
22569 --x_error_message_count;
22570 if (tmp->string)
22571 xfree (tmp->string);
20247 xfree (tmp); 22572 xfree (tmp);
20248 unblock_input (); 22573 unblock_input ();
20249} 22574}
@@ -20255,36 +22580,64 @@ x_uncatch_errors (void)
20255void 22580void
20256x_check_errors (Display *dpy, const char *format) 22581x_check_errors (Display *dpy, const char *format)
20257{ 22582{
20258 /* Make sure to catch any errors incurred so far. */ 22583 char *string;
20259 XSync (dpy, False); 22584
22585 /* This shouldn't happen, since x_check_errors should be called
22586 immediately inside an x_catch_errors block. */
22587 if (dpy != x_error_message->dpy)
22588 emacs_abort ();
20260 22589
20261 if (x_error_message->string[0]) 22590 /* There is no point in making this extra sync if all requests
22591 are known to have been fully processed. */
22592 if ((LastKnownRequestProcessed (dpy)
22593 != NextRequest (dpy) - 1)
22594 && (NextRequest (dpy)
22595 > x_error_message->first_request))
22596 XSync (dpy, False);
22597
22598 if (x_error_message->string)
20262 { 22599 {
20263 char string[X_ERROR_MESSAGE_SIZE]; 22600 string = alloca (strlen (x_error_message->string) + 1);
20264 memcpy (string, x_error_message->string, X_ERROR_MESSAGE_SIZE); 22601 strcpy (string, x_error_message->string);
20265 x_uncatch_errors (); 22602
20266 error (format, string); 22603 error (format, string);
20267 } 22604 }
20268} 22605}
20269 22606
20270/* Nonzero if we had any X protocol errors 22607/* Nonzero if any X protocol errors were generated since the last call
20271 since we did x_catch_errors on DPY. */ 22608 to x_catch_errors on DPY. */
20272 22609
20273bool 22610bool
20274x_had_errors_p (Display *dpy) 22611x_had_errors_p (Display *dpy)
20275{ 22612{
22613 /* This shouldn't happen, since x_check_errors should be called
22614 immediately inside an x_catch_errors block. */
22615 if (dpy != x_error_message->dpy)
22616 emacs_abort ();
22617
20276 /* Make sure to catch any errors incurred so far. */ 22618 /* Make sure to catch any errors incurred so far. */
20277 XSync (dpy, False); 22619 if ((LastKnownRequestProcessed (dpy)
22620 != NextRequest (dpy) - 1)
22621 && (NextRequest (dpy)
22622 > x_error_message->first_request))
22623 XSync (dpy, False);
20278 22624
20279 return x_error_message->string[0] != 0; 22625 return x_error_message->string;
20280} 22626}
20281 22627
20282/* Forget about any errors we have had, since we did x_catch_errors on DPY. */ 22628/* Forget about any errors we have had, since we did x_catch_errors on
22629 DPY. */
20283 22630
20284void 22631void
20285x_clear_errors (Display *dpy) 22632x_clear_errors (Display *dpy)
20286{ 22633{
20287 x_error_message->string[0] = 0; 22634 /* This shouldn't happen, since x_check_errors should be called
22635 immediately inside an x_catch_errors block. */
22636 if (dpy != x_error_message->dpy)
22637 emacs_abort ();
22638
22639 xfree (x_error_message->string);
22640 x_error_message->string = NULL;
20288} 22641}
20289 22642
20290#if false 22643#if false
@@ -20302,9 +22655,12 @@ x_fully_uncatch_errors (void)
20302 22655
20303#if false 22656#if false
20304static unsigned int x_wire_count; 22657static unsigned int x_wire_count;
20305x_trace_wire (void) 22658
22659static int
22660x_trace_wire (Display *dpy)
20306{ 22661{
20307 fprintf (stderr, "Lib call: %d\n", ++x_wire_count); 22662 fprintf (stderr, "Lib call: %u\n", ++x_wire_count);
22663 return 0;
20308} 22664}
20309#endif 22665#endif
20310 22666
@@ -20344,63 +22700,64 @@ x_connection_closed (Display *dpy, const char *error_message, bool ioerror)
20344 22700
20345 if (x_dnd_in_progress || x_dnd_waiting_for_finish) 22701 if (x_dnd_in_progress || x_dnd_waiting_for_finish)
20346 { 22702 {
20347 /* Handle display disconnect errors here because this function 22703 if (!ioerror)
20348 is not reentrant at this particular spot. */
20349 io_error_handler = XSetIOErrorHandler (x_dnd_io_error_handler);
20350
20351 if (!sigsetjmp (x_dnd_disconnect_handler, 1)
20352 && x_dnd_in_progress
20353 && dpy != (x_dnd_waiting_for_finish
20354 ? x_dnd_finish_display
20355 : FRAME_X_DISPLAY (x_dnd_frame)))
20356 { 22704 {
20357 /* Clean up drag and drop if the drag frame's display isn't 22705 /* Handle display disconnect errors here because this function
20358 the one being disconnected. */ 22706 is not reentrant at this particular spot. */
20359 f = x_dnd_frame; 22707 io_error_handler = XSetIOErrorHandler (x_dnd_io_error_handler);
20360 22708
20361 if (x_dnd_last_seen_window != None 22709 if (!!sigsetjmp (x_dnd_disconnect_handler, 1)
20362 && x_dnd_last_protocol_version != -1) 22710 && x_dnd_in_progress
20363 x_dnd_send_leave (x_dnd_frame, 22711 && dpy == (x_dnd_waiting_for_finish
20364 x_dnd_last_seen_window); 22712 ? x_dnd_finish_display
20365 else if (x_dnd_last_seen_window != None 22713 : FRAME_X_DISPLAY (x_dnd_frame)))
20366 && !XM_DRAG_STYLE_IS_DROP_ONLY (x_dnd_last_motif_style)
20367 && x_dnd_last_motif_style != XM_DRAG_STYLE_NONE
20368 && x_dnd_motif_setup_p)
20369 { 22714 {
20370 dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR, 22715 /* Clean up drag and drop if the drag frame's display isn't
20371 XM_DRAG_REASON_DROP_START); 22716 the one being disconnected. */
20372 dmsg.byte_order = XM_BYTE_ORDER_CUR_FIRST; 22717 f = x_dnd_frame;
20373 dmsg.timestamp = FRAME_DISPLAY_INFO (f)->last_user_time; 22718
20374 dmsg.side_effects 22719 if (x_dnd_last_seen_window != None
20375 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (FRAME_DISPLAY_INFO (f), 22720 && x_dnd_last_protocol_version != -1)
20376 x_dnd_wanted_action), 22721 x_dnd_send_leave (x_dnd_frame,
20377 XM_DROP_SITE_VALID, 22722 x_dnd_last_seen_window);
20378 xm_side_effect_from_action (FRAME_DISPLAY_INFO (f), 22723 else if (x_dnd_last_seen_window != None
20379 x_dnd_wanted_action), 22724 && !XM_DRAG_STYLE_IS_DROP_ONLY (x_dnd_last_motif_style)
20380 XM_DROP_ACTION_DROP_CANCEL); 22725 && x_dnd_last_motif_style != XM_DRAG_STYLE_NONE
20381 dmsg.x = 0; 22726 && x_dnd_motif_setup_p)
20382 dmsg.y = 0; 22727 {
20383 dmsg.index_atom = FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection; 22728 dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
20384 dmsg.source_window = FRAME_X_WINDOW (f); 22729 XM_DRAG_REASON_DROP_START);
20385 22730 dmsg.byte_order = XM_BYTE_ORDER_CUR_FIRST;
20386 x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f, 22731 dmsg.timestamp = FRAME_DISPLAY_INFO (f)->last_user_time;
20387 x_dnd_last_seen_window, 0); 22732 dmsg.side_effects
20388 xm_send_drop_message (FRAME_DISPLAY_INFO (f), FRAME_X_WINDOW (f), 22733 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
20389 x_dnd_last_seen_window, &dmsg); 22734 x_dnd_wanted_action),
22735 XM_DROP_SITE_VALID, x_dnd_motif_operations,
22736 XM_DROP_ACTION_DROP_CANCEL);
22737 dmsg.x = 0;
22738 dmsg.y = 0;
22739 dmsg.index_atom = FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection;
22740 dmsg.source_window = FRAME_X_WINDOW (f);
22741
22742 x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
22743 x_dnd_last_seen_window, 0);
22744 xm_send_drop_message (FRAME_DISPLAY_INFO (f), FRAME_X_WINDOW (f),
22745 x_dnd_last_seen_window, &dmsg);
22746 }
20390 } 22747 }
22748
22749 XSetIOErrorHandler (io_error_handler);
20391 } 22750 }
20392 22751
20393 XSetIOErrorHandler (io_error_handler);
20394 dpyinfo = x_display_info_for_display (dpy); 22752 dpyinfo = x_display_info_for_display (dpy);
20395 22753
20396 x_dnd_last_seen_window = None; 22754 x_dnd_last_seen_window = None;
20397 x_dnd_last_seen_toplevel = None; 22755 x_dnd_last_seen_toplevel = None;
20398 x_dnd_in_progress = false; 22756 x_dnd_in_progress = false;
20399 x_set_dnd_targets (NULL, 0);
20400 x_dnd_waiting_for_finish = false; 22757 x_dnd_waiting_for_finish = false;
20401 22758
20402 if (x_dnd_use_toplevels) 22759 if (x_dnd_use_toplevels)
20403 x_dnd_free_toplevels (); 22760 x_dnd_free_toplevels (!ioerror);
20404 22761
20405 x_dnd_return_frame_object = NULL; 22762 x_dnd_return_frame_object = NULL;
20406 x_dnd_movement_frame = NULL; 22763 x_dnd_movement_frame = NULL;
@@ -20417,6 +22774,12 @@ x_connection_closed (Display *dpy, const char *error_message, bool ioerror)
20417 dpyinfo->display = 0; 22774 dpyinfo->display = 0;
20418 } 22775 }
20419 22776
22777 /* delete_frame can still try to read async input (even though we
22778 tell pass `noelisp'), because looking up the `delete-before'
22779 parameter calls Fassq which then calls maybe_quit. So block
22780 input while deleting frames. */
22781 block_input ();
22782
20420 /* First delete frames whose mini-buffers are on frames 22783 /* First delete frames whose mini-buffers are on frames
20421 that are on the dead display. */ 22784 that are on the dead display. */
20422 FOR_EACH_FRAME (tail, frame) 22785 FOR_EACH_FRAME (tail, frame)
@@ -20481,6 +22844,8 @@ For details, see etc/PROBLEMS.\n",
20481 } 22844 }
20482 } 22845 }
20483 22846
22847 unblock_input ();
22848
20484 if (terminal_list == 0) 22849 if (terminal_list == 0)
20485 { 22850 {
20486 fprintf (stderr, "%s\n", error_msg); 22851 fprintf (stderr, "%s\n", error_msg);
@@ -20506,16 +22871,16 @@ static void x_error_quitter (Display *, XErrorEvent *);
20506static int 22871static int
20507x_error_handler (Display *display, XErrorEvent *event) 22872x_error_handler (Display *display, XErrorEvent *event)
20508{ 22873{
22874 struct x_error_message_stack *stack;
20509#ifdef HAVE_XINPUT2 22875#ifdef HAVE_XINPUT2
20510 struct x_display_info *dpyinfo; 22876 struct x_display_info *dpyinfo;
20511#endif 22877#endif
20512 22878
20513#if defined USE_GTK && defined HAVE_GTK3 22879#if defined USE_GTK && defined HAVE_GTK3
20514 if ((event->error_code == BadMatch || event->error_code == BadWindow) 22880 if ((event->error_code == BadMatch
22881 || event->error_code == BadWindow)
20515 && event->request_code == X_SetInputFocus) 22882 && event->request_code == X_SetInputFocus)
20516 { 22883 return 0;
20517 return 0;
20518 }
20519#endif 22884#endif
20520 22885
20521 /* If we try to ungrab or grab a device that doesn't exist anymore 22886 /* 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)
20536 return 0; 22901 return 0;
20537#endif 22902#endif
20538 22903
20539 if (x_error_message) 22904 stack = x_find_error_handler (display, event);
20540 x_error_catcher (display, event); 22905
22906 if (stack)
22907 x_error_catcher (display, event, stack);
20541 else 22908 else
20542 x_error_quitter (display, event); 22909 x_error_quitter (display, event);
20543 return 0; 22910 return 0;
@@ -21043,17 +23410,16 @@ x_set_offset (struct frame *f, int xoff, int yoff, int change_gravity)
21043 https://freedesktop.org/wiki/Specifications/wm-spec/. */ 23410 https://freedesktop.org/wiki/Specifications/wm-spec/. */
21044 23411
21045bool 23412bool
21046x_wm_supports (struct frame *f, Atom want_atom) 23413x_wm_supports_1 (struct x_display_info *dpyinfo, Atom want_atom)
21047{ 23414{
21048 Atom actual_type; 23415 Atom actual_type;
21049 unsigned long actual_size, bytes_remaining; 23416 unsigned long actual_size, bytes_remaining;
21050 int i, rc, actual_format; 23417 int i, rc, actual_format;
21051 bool ret; 23418 bool ret;
21052 Window wmcheck_window; 23419 Window wmcheck_window;
21053 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
21054 Window target_window = dpyinfo->root_window; 23420 Window target_window = dpyinfo->root_window;
21055 int max_len = 65536; 23421 int max_len = 65536;
21056 Display *dpy = FRAME_X_DISPLAY (f); 23422 Display *dpy = dpyinfo->display;
21057 unsigned char *tmp_data = NULL; 23423 unsigned char *tmp_data = NULL;
21058 Atom target_type = XA_WINDOW; 23424 Atom target_type = XA_WINDOW;
21059 23425
@@ -21127,6 +23493,13 @@ x_wm_supports (struct frame *f, Atom want_atom)
21127 return ret; 23493 return ret;
21128} 23494}
21129 23495
23496bool
23497x_wm_supports (struct frame *f, Atom want_atom)
23498{
23499 return x_wm_supports_1 (FRAME_DISPLAY_INFO (f),
23500 want_atom);
23501}
23502
21130static void 23503static void
21131set_wm_state (Lisp_Object frame, bool add, Atom atom, Atom value) 23504set_wm_state (Lisp_Object frame, bool add, Atom atom, Atom value)
21132{ 23505{
@@ -21289,15 +23662,20 @@ x_get_current_wm_state (struct frame *f,
21289#ifdef USE_XCB 23662#ifdef USE_XCB
21290 xcb_get_property_cookie_t prop_cookie; 23663 xcb_get_property_cookie_t prop_cookie;
21291 xcb_get_property_reply_t *prop; 23664 xcb_get_property_reply_t *prop;
21292 xcb_atom_t *reply_data UNINIT; 23665 typedef xcb_atom_t reply_data_object;
21293#else 23666#else
21294 Display *dpy = FRAME_X_DISPLAY (f); 23667 Display *dpy = FRAME_X_DISPLAY (f);
21295 unsigned long bytes_remaining; 23668 unsigned long bytes_remaining;
21296 int rc, actual_format; 23669 int rc, actual_format;
21297 Atom actual_type; 23670 Atom actual_type;
21298 unsigned char *tmp_data = NULL; 23671 unsigned char *tmp_data = NULL;
21299 Atom *reply_data UNINIT; 23672 typedef Atom reply_data_object;
21300#endif 23673#endif
23674 reply_data_object *reply_data;
23675# if defined GCC_LINT || defined lint
23676 reply_data_object reply_data_dummy;
23677 reply_data = &reply_data_dummy;
23678# endif
21301 23679
21302 *sticky = false; 23680 *sticky = false;
21303 *size_state = FULLSCREEN_NONE; 23681 *size_state = FULLSCREEN_NONE;
@@ -21648,7 +24026,7 @@ x_check_expected_move (struct frame *f, int expected_left, int expected_top)
21648 int adjusted_left; 24026 int adjusted_left;
21649 int adjusted_top; 24027 int adjusted_top;
21650 24028
21651 FRAME_DISPLAY_INFO (f)->wm_type = X_WMTYPE_A; 24029 FRAME_DISPLAY_INFO (f)->wm_type = X_WMTYPE_A;
21652 FRAME_X_OUTPUT (f)->move_offset_left = expected_left - current_left; 24030 FRAME_X_OUTPUT (f)->move_offset_left = expected_left - current_left;
21653 FRAME_X_OUTPUT (f)->move_offset_top = expected_top - current_top; 24031 FRAME_X_OUTPUT (f)->move_offset_top = expected_top - current_top;
21654 24032
@@ -21665,7 +24043,6 @@ x_check_expected_move (struct frame *f, int expected_left, int expected_top)
21665 else 24043 else
21666 /* It's a "Type B" window manager. We don't have to adjust the 24044 /* It's a "Type B" window manager. We don't have to adjust the
21667 frame's position. */ 24045 frame's position. */
21668
21669 FRAME_DISPLAY_INFO (f)->wm_type = X_WMTYPE_B; 24046 FRAME_DISPLAY_INFO (f)->wm_type = X_WMTYPE_B;
21670} 24047}
21671 24048
@@ -21679,11 +24056,17 @@ x_check_expected_move (struct frame *f, int expected_left, int expected_top)
21679static void 24056static void
21680x_sync_with_move (struct frame *f, int left, int top, bool fuzzy) 24057x_sync_with_move (struct frame *f, int left, int top, bool fuzzy)
21681{ 24058{
21682 int count = 0; 24059 sigset_t emptyset;
24060 int count, current_left, current_top;
24061 struct timespec fallback;
24062
24063 sigemptyset (&emptyset);
24064 count = 0;
21683 24065
21684 while (count++ < 50) 24066 while (count++ < 50)
21685 { 24067 {
21686 int current_left = 0, current_top = 0; 24068 current_left = 0;
24069 current_top = 0;
21687 24070
21688 /* In theory, this call to XSync only needs to happen once, but in 24071 /* In theory, this call to XSync only needs to happen once, but in
21689 practice, it doesn't seem to work, hence the need for the surrounding 24072 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)
21708 /* As a last resort, just wait 0.5 seconds and hope that XGetGeometry 24091 /* As a last resort, just wait 0.5 seconds and hope that XGetGeometry
21709 will then return up-to-date position info. */ 24092 will then return up-to-date position info. */
21710 24093
21711 wait_reading_process_output (0, 500000000, 0, false, Qnil, NULL, 0); 24094 fallback = dtotimespec (0.5);
24095
24096 /* This will hang if input is blocked, so use pselect to wait
24097 instead. */
24098 if (input_blocked_p ())
24099 pselect (0, NULL, NULL, NULL, &fallback, &emptyset);
24100 else
24101 wait_reading_process_output (0, 500000000, 0, false, Qnil, NULL, 0);
21712} 24102}
21713 24103
21714 24104
@@ -22375,6 +24765,18 @@ x_make_frame_visible_invisible (struct frame *f, bool visible)
22375 x_make_frame_invisible (f); 24765 x_make_frame_invisible (f);
22376} 24766}
22377 24767
24768Cursor
24769x_create_font_cursor (struct x_display_info *dpyinfo, int glyph)
24770{
24771 if (glyph <= 65535)
24772 return XCreateFontCursor (dpyinfo->display, glyph);
24773
24774 /* x-pointer-invisible cannot fit in CARD16, and thus cannot be any
24775 existing cursor. */
24776 return make_invisible_cursor (dpyinfo);
24777}
24778
24779
22378/* Change window state from mapped to iconified. */ 24780/* Change window state from mapped to iconified. */
22379 24781
22380void 24782void
@@ -22462,6 +24864,10 @@ x_iconify_frame (struct frame *f)
22462 msg.xclient.message_type = FRAME_DISPLAY_INFO (f)->Xatom_wm_change_state; 24864 msg.xclient.message_type = FRAME_DISPLAY_INFO (f)->Xatom_wm_change_state;
22463 msg.xclient.format = 32; 24865 msg.xclient.format = 32;
22464 msg.xclient.data.l[0] = IconicState; 24866 msg.xclient.data.l[0] = IconicState;
24867 msg.xclient.data.l[1] = 0;
24868 msg.xclient.data.l[2] = 0;
24869 msg.xclient.data.l[3] = 0;
24870 msg.xclient.data.l[4] = 0;
22465 24871
22466 if (! XSendEvent (FRAME_X_DISPLAY (f), 24872 if (! XSendEvent (FRAME_X_DISPLAY (f),
22467 FRAME_DISPLAY_INFO (f)->root_window, 24873 FRAME_DISPLAY_INFO (f)->root_window,
@@ -22691,7 +25097,6 @@ x_destroy_window (struct frame *f)
22691 x_free_frame_resources (f); 25097 x_free_frame_resources (f);
22692 25098
22693 xfree (f->output_data.x->saved_menu_event); 25099 xfree (f->output_data.x->saved_menu_event);
22694 xfree (f->output_data.x);
22695 25100
22696#ifdef HAVE_X_I18N 25101#ifdef HAVE_X_I18N
22697 if (f->output_data.x->preedit_chars) 25102 if (f->output_data.x->preedit_chars)
@@ -22703,11 +25108,162 @@ x_destroy_window (struct frame *f)
22703 XFree (f->output_data.x->xi_masks); 25108 XFree (f->output_data.x->xi_masks);
22704#endif 25109#endif
22705 25110
25111 xfree (f->output_data.x);
22706 f->output_data.x = NULL; 25112 f->output_data.x = NULL;
22707 25113
22708 dpyinfo->reference_count--; 25114 dpyinfo->reference_count--;
22709} 25115}
22710 25116
25117/* Intern NAME in DPYINFO, but check to see if the atom was already
25118 interned when the X connection was opened, and use that instead.
25119
25120 If PREDEFINED_ONLY, return None if the atom was not interned during
25121 connection setup or is predefined. */
25122Atom
25123x_intern_cached_atom (struct x_display_info *dpyinfo,
25124 const char *name, bool predefined_only)
25125{
25126 int i;
25127 char *ptr;
25128 Atom *atom;
25129
25130 /* Special atoms that depend on the screen number. */
25131 char xsettings_atom_name[sizeof "_XSETTINGS_S%d" - 2
25132 + INT_STRLEN_BOUND (int)];
25133 char cm_atom_name[sizeof "_NET_WM_CM_S%d" - 2
25134 + INT_STRLEN_BOUND (int)];
25135
25136 sprintf (xsettings_atom_name, "_XSETTINGS_S%d",
25137 XScreenNumberOfScreen (dpyinfo->screen));
25138 sprintf (cm_atom_name, "_NET_WM_CM_S%d",
25139 XScreenNumberOfScreen (dpyinfo->screen));
25140
25141 if (!strcmp (name, xsettings_atom_name))
25142 return dpyinfo->Xatom_xsettings_sel;
25143
25144 if (!strcmp (name, cm_atom_name))
25145 return dpyinfo->Xatom_NET_WM_CM_Sn;
25146
25147 /* Now do some common predefined atoms. */
25148 if (!strcmp (name, "PRIMARY"))
25149 return XA_PRIMARY;
25150
25151 if (!strcmp (name, "SECONDARY"))
25152 return XA_SECONDARY;
25153
25154 if (!strcmp (name, "STRING"))
25155 return XA_STRING;
25156
25157 if (!strcmp (name, "INTEGER"))
25158 return XA_INTEGER;
25159
25160 if (!strcmp (name, "ATOM"))
25161 return XA_ATOM;
25162
25163 if (!strcmp (name, "CARDINAL"))
25164 return XA_CARDINAL;
25165
25166 if (!strcmp (name, "WINDOW"))
25167 return XA_WINDOW;
25168
25169 for (i = 0; i < ARRAYELTS (x_atom_refs); ++i)
25170 {
25171 ptr = (char *) dpyinfo;
25172
25173 if (!strcmp (x_atom_refs[i].name, name))
25174 {
25175 atom = (Atom *) (ptr + x_atom_refs[i].offset);
25176
25177 return *atom;
25178 }
25179 }
25180
25181 if (predefined_only)
25182 return None;
25183
25184 return XInternAtom (dpyinfo->display, name, False);
25185}
25186
25187/* Get the name of ATOM, but try not to make a request to the X
25188 server. Whether or not a request to the X server happened is
25189 placed in NEED_SYNC. */
25190char *
25191x_get_atom_name (struct x_display_info *dpyinfo, Atom atom,
25192 bool *need_sync)
25193{
25194 char *dpyinfo_pointer, *name, *value, *buffer;
25195 int i;
25196 Atom ref_atom;
25197
25198 dpyinfo_pointer = (char *) dpyinfo;
25199 value = NULL;
25200
25201 if (need_sync)
25202 *need_sync = false;
25203
25204 buffer = alloca (45 + INT_STRLEN_BOUND (int));
25205
25206 switch (atom)
25207 {
25208 case XA_PRIMARY:
25209 return xstrdup ("PRIMARY");
25210
25211 case XA_SECONDARY:
25212 return xstrdup ("SECONDARY");
25213
25214 case XA_INTEGER:
25215 return xstrdup ("INTEGER");
25216
25217 case XA_ATOM:
25218 return xstrdup ("ATOM");
25219
25220 case XA_CARDINAL:
25221 return xstrdup ("CARDINAL");
25222
25223 case XA_WINDOW:
25224 return xstrdup ("WINDOW");
25225
25226 default:
25227 if (atom == dpyinfo->Xatom_xsettings_sel)
25228 {
25229 sprintf (buffer, "_XSETTINGS_S%d",
25230 XScreenNumberOfScreen (dpyinfo->screen));
25231 return xstrdup (buffer);
25232 }
25233
25234 if (atom == dpyinfo->Xatom_NET_WM_CM_Sn)
25235 {
25236 sprintf (buffer, "_NET_WM_CM_S%d",
25237 XScreenNumberOfScreen (dpyinfo->screen));
25238 return xstrdup (buffer);
25239 }
25240
25241 for (i = 0; i < ARRAYELTS (x_atom_refs); ++i)
25242 {
25243 ref_atom = *(Atom *) (dpyinfo_pointer
25244 + x_atom_refs[i].offset);
25245
25246 if (atom == ref_atom)
25247 return xstrdup (x_atom_refs[i].name);
25248 }
25249
25250 name = XGetAtomName (dpyinfo->display, atom);
25251
25252 if (need_sync)
25253 *need_sync = true;
25254
25255 if (name)
25256 {
25257 value = xstrdup (name);
25258 XFree (name);
25259 }
25260
25261 break;
25262 }
25263
25264 return value;
25265}
25266
22711 25267
22712/* Setting window manager hints. */ 25268/* Setting window manager hints. */
22713 25269
@@ -23152,7 +25708,12 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
23152#ifdef USE_XCB 25708#ifdef USE_XCB
23153 xcb_connection_t *xcb_conn; 25709 xcb_connection_t *xcb_conn;
23154#endif 25710#endif
23155 char *cm_atom_sprintf; 25711 static char const cm_atom_fmt[] = "_NET_WM_CM_S%d";
25712 char cm_atom_sprintf[sizeof cm_atom_fmt - 2 + INT_STRLEN_BOUND (int)];
25713#ifdef USE_GTK
25714 GdkDisplay *gdpy;
25715 GdkScreen *gscr;
25716#endif
23156 25717
23157 block_input (); 25718 block_input ();
23158 25719
@@ -23314,6 +25875,11 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
23314 } 25875 }
23315#endif 25876#endif
23316 25877
25878 /* Select for structure events on the root window, since this allows
25879 us to record changes to the size of the screen. */
25880
25881 XSelectInput (dpy, DefaultRootWindow (dpy), StructureNotifyMask);
25882
23317 /* We have definitely succeeded. Record the new connection. */ 25883 /* We have definitely succeeded. Record the new connection. */
23318 25884
23319 dpyinfo = xzalloc (sizeof *dpyinfo); 25885 dpyinfo = xzalloc (sizeof *dpyinfo);
@@ -23332,7 +25898,8 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
23332 { 25898 {
23333 terminal->kboard = allocate_kboard (Qx); 25899 terminal->kboard = allocate_kboard (Qx);
23334 25900
23335 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->u.s.function, Qunbound)) 25901 if (!BASE_EQ (XSYMBOL (Qvendor_specific_keysyms)->u.s.function,
25902 Qunbound))
23336 { 25903 {
23337 char *vendor = ServerVendor (dpy); 25904 char *vendor = ServerVendor (dpy);
23338 25905
@@ -23375,12 +25942,14 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
23375 dpyinfo->color_names_size = 256; 25942 dpyinfo->color_names_size = 256;
23376 dpyinfo->color_names = xzalloc (dpyinfo->color_names_size 25943 dpyinfo->color_names = xzalloc (dpyinfo->color_names_size
23377 * sizeof *dpyinfo->color_names); 25944 * sizeof *dpyinfo->color_names);
25945 dpyinfo->color_names_length = xzalloc (dpyinfo->color_names_size
25946 * sizeof *dpyinfo->color_names_length);
23378 25947
23379 /* Set the name of the terminal. */ 25948 /* Set the name of the terminal. */
23380 terminal->name = xlispstrdup (display_name); 25949 terminal->name = xlispstrdup (display_name);
23381 25950
23382#if false 25951#if false
23383 XSetAfterFunction (x_current_display, x_trace_wire); 25952 XSetAfterFunction (dpyinfo->display, x_trace_wire);
23384#endif 25953#endif
23385 25954
23386 Lisp_Object system_name = Fsystem_name (); 25955 Lisp_Object system_name = Fsystem_name ();
@@ -23754,17 +26323,59 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
23754 ; 26323 ;
23755#endif 26324#endif
23756 26325
26326#if defined HAVE_XRANDR || defined USE_GTK
26327 Lisp_Object term;
26328
26329 XSETTERMINAL (term, terminal);
26330#endif
26331
23757#ifdef HAVE_XRANDR 26332#ifdef HAVE_XRANDR
23758 int xrr_event_base, xrr_error_base; 26333 dpyinfo->xrandr_supported_p
23759 bool xrr_ok = false; 26334 = XRRQueryExtension (dpy, &dpyinfo->xrandr_event_base,
23760 xrr_ok = XRRQueryExtension (dpy, &xrr_event_base, &xrr_error_base); 26335 &dpyinfo->xrandr_error_base);
23761 if (xrr_ok) 26336
26337#ifndef USE_GTK
26338 dpyinfo->last_monitor_attributes_list = Qnil;
26339#endif
26340
26341 if (dpyinfo->xrandr_supported_p)
23762 { 26342 {
23763 XRRQueryVersion (dpy, &dpyinfo->xrandr_major_version, 26343 XRRQueryVersion (dpy, &dpyinfo->xrandr_major_version,
23764 &dpyinfo->xrandr_minor_version); 26344 &dpyinfo->xrandr_minor_version);
26345
26346#ifndef USE_GTK
26347 if (dpyinfo->xrandr_major_version == 1
26348 && dpyinfo->xrandr_minor_version >= 2)
26349 {
26350 XRRSelectInput (dpyinfo->display,
26351 dpyinfo->root_window,
26352 (RRScreenChangeNotifyMask
26353 | RRCrtcChangeNotifyMask
26354 | RROutputChangeNotifyMask
26355 /* Emacs doesn't actually need this, but GTK
26356 selects for it when the display is
26357 initialized. */
26358 | RROutputPropertyNotifyMask));
26359
26360 dpyinfo->last_monitor_attributes_list
26361 = Fx_display_monitor_attributes_list (term);
26362 }
26363#endif
23765 } 26364 }
23766#endif 26365#endif
23767 26366
26367#ifdef USE_GTK
26368 dpyinfo->last_monitor_attributes_list
26369 = Fx_display_monitor_attributes_list (term);
26370
26371 gdpy = gdk_x11_lookup_xdisplay (dpyinfo->display);
26372 gscr = gdk_display_get_default_screen (gdpy);
26373
26374 g_signal_connect (G_OBJECT (gscr), "monitors-changed",
26375 G_CALLBACK (x_monitors_changed_cb),
26376 NULL);
26377#endif
26378
23768#ifdef HAVE_XKB 26379#ifdef HAVE_XKB
23769 int xkb_major, xkb_minor, xkb_op, xkb_error_code; 26380 int xkb_major, xkb_minor, xkb_op, xkb_error_code;
23770 xkb_major = XkbMajorVersion; 26381 xkb_major = XkbMajorVersion;
@@ -23843,141 +26454,12 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
23843 dpyinfo->resx = (mm < 1) ? 100 : pixels * 25.4 / mm; 26454 dpyinfo->resx = (mm < 1) ? 100 : pixels * 25.4 / mm;
23844 } 26455 }
23845 26456
23846 { 26457 sprintf (cm_atom_sprintf, cm_atom_fmt,
23847 int n = snprintf (NULL, 0, "_NET_WM_CM_S%d", 26458 XScreenNumberOfScreen (dpyinfo->screen));
23848 XScreenNumberOfScreen (dpyinfo->screen));
23849 cm_atom_sprintf = alloca (n + 1);
23850
23851 snprintf (cm_atom_sprintf, n + 1, "_NET_WM_CM_S%d",
23852 XScreenNumberOfScreen (dpyinfo->screen));
23853 }
23854 26459
23855 { 26460 {
23856 static const struct
23857 {
23858 const char *name;
23859 int offset;
23860 } atom_refs[] = {
23861#define ATOM_REFS_INIT(string, member) \
23862 { string, offsetof (struct x_display_info, member) },
23863 ATOM_REFS_INIT ("WM_PROTOCOLS", Xatom_wm_protocols)
23864 ATOM_REFS_INIT ("WM_TAKE_FOCUS", Xatom_wm_take_focus)
23865 ATOM_REFS_INIT ("WM_SAVE_YOURSELF", Xatom_wm_save_yourself)
23866 ATOM_REFS_INIT ("WM_DELETE_WINDOW", Xatom_wm_delete_window)
23867 ATOM_REFS_INIT ("WM_CHANGE_STATE", Xatom_wm_change_state)
23868 ATOM_REFS_INIT ("WM_STATE", Xatom_wm_state)
23869 ATOM_REFS_INIT ("WM_CONFIGURE_DENIED", Xatom_wm_configure_denied)
23870 ATOM_REFS_INIT ("WM_MOVED", Xatom_wm_window_moved)
23871 ATOM_REFS_INIT ("WM_CLIENT_LEADER", Xatom_wm_client_leader)
23872 ATOM_REFS_INIT ("WM_TRANSIENT_FOR", Xatom_wm_transient_for)
23873 ATOM_REFS_INIT ("Editres", Xatom_editres)
23874 ATOM_REFS_INIT ("CLIPBOARD", Xatom_CLIPBOARD)
23875 ATOM_REFS_INIT ("TIMESTAMP", Xatom_TIMESTAMP)
23876 ATOM_REFS_INIT ("TEXT", Xatom_TEXT)
23877 ATOM_REFS_INIT ("COMPOUND_TEXT", Xatom_COMPOUND_TEXT)
23878 ATOM_REFS_INIT ("UTF8_STRING", Xatom_UTF8_STRING)
23879 ATOM_REFS_INIT ("DELETE", Xatom_DELETE)
23880 ATOM_REFS_INIT ("MULTIPLE", Xatom_MULTIPLE)
23881 ATOM_REFS_INIT ("INCR", Xatom_INCR)
23882 ATOM_REFS_INIT ("_EMACS_TMP_", Xatom_EMACS_TMP)
23883 ATOM_REFS_INIT ("EMACS_SERVER_TIME_PROP", Xatom_EMACS_SERVER_TIME_PROP)
23884 ATOM_REFS_INIT ("TARGETS", Xatom_TARGETS)
23885 ATOM_REFS_INIT ("NULL", Xatom_NULL)
23886 ATOM_REFS_INIT ("ATOM", Xatom_ATOM)
23887 ATOM_REFS_INIT ("ATOM_PAIR", Xatom_ATOM_PAIR)
23888 ATOM_REFS_INIT ("CLIPBOARD_MANAGER", Xatom_CLIPBOARD_MANAGER)
23889 ATOM_REFS_INIT ("_XEMBED_INFO", Xatom_XEMBED_INFO)
23890 ATOM_REFS_INIT ("_MOTIF_WM_HINTS", Xatom_MOTIF_WM_HINTS)
23891 /* For properties of font. */
23892 ATOM_REFS_INIT ("PIXEL_SIZE", Xatom_PIXEL_SIZE)
23893 ATOM_REFS_INIT ("AVERAGE_WIDTH", Xatom_AVERAGE_WIDTH)
23894 ATOM_REFS_INIT ("_MULE_BASELINE_OFFSET", Xatom_MULE_BASELINE_OFFSET)
23895 ATOM_REFS_INIT ("_MULE_RELATIVE_COMPOSE", Xatom_MULE_RELATIVE_COMPOSE)
23896 ATOM_REFS_INIT ("_MULE_DEFAULT_ASCENT", Xatom_MULE_DEFAULT_ASCENT)
23897 /* Ghostscript support. */
23898 ATOM_REFS_INIT ("DONE", Xatom_DONE)
23899 ATOM_REFS_INIT ("PAGE", Xatom_PAGE)
23900 ATOM_REFS_INIT ("SCROLLBAR", Xatom_Scrollbar)
23901 ATOM_REFS_INIT ("HORIZONTAL_SCROLLBAR", Xatom_Horizontal_Scrollbar)
23902 ATOM_REFS_INIT ("_XEMBED", Xatom_XEMBED)
23903 /* EWMH */
23904 ATOM_REFS_INIT ("_NET_WM_STATE", Xatom_net_wm_state)
23905 ATOM_REFS_INIT ("_NET_WM_STATE_FULLSCREEN", Xatom_net_wm_state_fullscreen)
23906 ATOM_REFS_INIT ("_NET_WM_STATE_MAXIMIZED_HORZ",
23907 Xatom_net_wm_state_maximized_horz)
23908 ATOM_REFS_INIT ("_NET_WM_STATE_MAXIMIZED_VERT",
23909 Xatom_net_wm_state_maximized_vert)
23910 ATOM_REFS_INIT ("_NET_WM_STATE_STICKY", Xatom_net_wm_state_sticky)
23911 ATOM_REFS_INIT ("_NET_WM_STATE_SHADED", Xatom_net_wm_state_shaded)
23912 ATOM_REFS_INIT ("_NET_WM_STATE_HIDDEN", Xatom_net_wm_state_hidden)
23913 ATOM_REFS_INIT ("_NET_WM_WINDOW_TYPE", Xatom_net_window_type)
23914 ATOM_REFS_INIT ("_NET_WM_WINDOW_TYPE_TOOLTIP",
23915 Xatom_net_window_type_tooltip)
23916 ATOM_REFS_INIT ("_NET_WM_ICON_NAME", Xatom_net_wm_icon_name)
23917 ATOM_REFS_INIT ("_NET_WM_NAME", Xatom_net_wm_name)
23918 ATOM_REFS_INIT ("_NET_SUPPORTED", Xatom_net_supported)
23919 ATOM_REFS_INIT ("_NET_SUPPORTING_WM_CHECK", Xatom_net_supporting_wm_check)
23920 ATOM_REFS_INIT ("_NET_WM_WINDOW_OPACITY", Xatom_net_wm_window_opacity)
23921 ATOM_REFS_INIT ("_NET_ACTIVE_WINDOW", Xatom_net_active_window)
23922 ATOM_REFS_INIT ("_NET_FRAME_EXTENTS", Xatom_net_frame_extents)
23923 ATOM_REFS_INIT ("_NET_CURRENT_DESKTOP", Xatom_net_current_desktop)
23924 ATOM_REFS_INIT ("_NET_WORKAREA", Xatom_net_workarea)
23925 ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST", Xatom_net_wm_sync_request)
23926 ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST_COUNTER", Xatom_net_wm_sync_request_counter)
23927 ATOM_REFS_INIT ("_NET_WM_FRAME_DRAWN", Xatom_net_wm_frame_drawn)
23928 ATOM_REFS_INIT ("_NET_WM_USER_TIME", Xatom_net_wm_user_time)
23929 ATOM_REFS_INIT ("_NET_WM_USER_TIME_WINDOW", Xatom_net_wm_user_time_window)
23930 ATOM_REFS_INIT ("_NET_CLIENT_LIST_STACKING", Xatom_net_client_list_stacking)
23931 /* Session management */
23932 ATOM_REFS_INIT ("SM_CLIENT_ID", Xatom_SM_CLIENT_ID)
23933 ATOM_REFS_INIT ("_XSETTINGS_SETTINGS", Xatom_xsettings_prop)
23934 ATOM_REFS_INIT ("MANAGER", Xatom_xsettings_mgr)
23935 ATOM_REFS_INIT ("_NET_WM_STATE_SKIP_TASKBAR", Xatom_net_wm_state_skip_taskbar)
23936 ATOM_REFS_INIT ("_NET_WM_STATE_ABOVE", Xatom_net_wm_state_above)
23937 ATOM_REFS_INIT ("_NET_WM_STATE_BELOW", Xatom_net_wm_state_below)
23938 ATOM_REFS_INIT ("_NET_WM_OPAQUE_REGION", Xatom_net_wm_opaque_region)
23939 ATOM_REFS_INIT ("_NET_WM_PING", Xatom_net_wm_ping)
23940 ATOM_REFS_INIT ("_NET_WM_PID", Xatom_net_wm_pid)
23941#ifdef HAVE_XKB
23942 ATOM_REFS_INIT ("Meta", Xatom_Meta)
23943 ATOM_REFS_INIT ("Super", Xatom_Super)
23944 ATOM_REFS_INIT ("Hyper", Xatom_Hyper)
23945 ATOM_REFS_INIT ("ShiftLock", Xatom_ShiftLock)
23946 ATOM_REFS_INIT ("Alt", Xatom_Alt)
23947#endif
23948 /* DND source. */
23949 ATOM_REFS_INIT ("XdndAware", Xatom_XdndAware)
23950 ATOM_REFS_INIT ("XdndSelection", Xatom_XdndSelection)
23951 ATOM_REFS_INIT ("XdndTypeList", Xatom_XdndTypeList)
23952 ATOM_REFS_INIT ("XdndActionCopy", Xatom_XdndActionCopy)
23953 ATOM_REFS_INIT ("XdndActionMove", Xatom_XdndActionMove)
23954 ATOM_REFS_INIT ("XdndActionLink", Xatom_XdndActionLink)
23955 ATOM_REFS_INIT ("XdndActionAsk", Xatom_XdndActionAsk)
23956 ATOM_REFS_INIT ("XdndActionPrivate", Xatom_XdndActionPrivate)
23957 ATOM_REFS_INIT ("XdndActionList", Xatom_XdndActionList)
23958 ATOM_REFS_INIT ("XdndActionDescription", Xatom_XdndActionDescription)
23959 ATOM_REFS_INIT ("XdndProxy", Xatom_XdndProxy)
23960 ATOM_REFS_INIT ("XdndEnter", Xatom_XdndEnter)
23961 ATOM_REFS_INIT ("XdndPosition", Xatom_XdndPosition)
23962 ATOM_REFS_INIT ("XdndStatus", Xatom_XdndStatus)
23963 ATOM_REFS_INIT ("XdndLeave", Xatom_XdndLeave)
23964 ATOM_REFS_INIT ("XdndDrop", Xatom_XdndDrop)
23965 ATOM_REFS_INIT ("XdndFinished", Xatom_XdndFinished)
23966 /* Motif drop protocol support. */
23967 ATOM_REFS_INIT ("_MOTIF_DRAG_WINDOW", Xatom_MOTIF_DRAG_WINDOW)
23968 ATOM_REFS_INIT ("_MOTIF_DRAG_TARGETS", Xatom_MOTIF_DRAG_TARGETS)
23969 ATOM_REFS_INIT ("_MOTIF_DRAG_AND_DROP_MESSAGE",
23970 Xatom_MOTIF_DRAG_AND_DROP_MESSAGE)
23971 ATOM_REFS_INIT ("_MOTIF_DRAG_INITIATOR_INFO",
23972 Xatom_MOTIF_DRAG_INITIATOR_INFO)
23973 ATOM_REFS_INIT ("_MOTIF_DRAG_RECEIVER_INFO",
23974 Xatom_MOTIF_DRAG_RECEIVER_INFO)
23975 ATOM_REFS_INIT ("XmTRANSFER_SUCCESS", Xatom_XmTRANSFER_SUCCESS)
23976 ATOM_REFS_INIT ("XmTRANSFER_FAILURE", Xatom_XmTRANSFER_FAILURE)
23977 };
23978
23979 int i; 26461 int i;
23980 enum { atom_count = ARRAYELTS (atom_refs) }; 26462 enum { atom_count = ARRAYELTS (x_atom_refs) };
23981 /* 1 for _XSETTINGS_SN. */ 26463 /* 1 for _XSETTINGS_SN. */
23982 enum { total_atom_count = 2 + atom_count }; 26464 enum { total_atom_count = 2 + atom_count };
23983 Atom atoms_return[total_atom_count]; 26465 Atom atoms_return[total_atom_count];
@@ -23987,7 +26469,7 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
23987 + INT_STRLEN_BOUND (int)]; 26469 + INT_STRLEN_BOUND (int)];
23988 26470
23989 for (i = 0; i < atom_count; i++) 26471 for (i = 0; i < atom_count; i++)
23990 atom_names[i] = (char *) atom_refs[i].name; 26472 atom_names[i] = (char *) x_atom_refs[i].name;
23991 26473
23992 /* Build _XSETTINGS_SN atom name. */ 26474 /* Build _XSETTINGS_SN atom name. */
23993 sprintf (xsettings_atom_name, xsettings_fmt, 26475 sprintf (xsettings_atom_name, xsettings_fmt,
@@ -23999,7 +26481,7 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
23999 False, atoms_return); 26481 False, atoms_return);
24000 26482
24001 for (i = 0; i < atom_count; i++) 26483 for (i = 0; i < atom_count; i++)
24002 *(Atom *) ((char *) dpyinfo + atom_refs[i].offset) = atoms_return[i]; 26484 *(Atom *) ((char *) dpyinfo + x_atom_refs[i].offset) = atoms_return[i];
24003 26485
24004 /* Manually copy last two atoms. */ 26486 /* Manually copy last two atoms. */
24005 dpyinfo->Xatom_xsettings_sel = atoms_return[i]; 26487 dpyinfo->Xatom_xsettings_sel = atoms_return[i];
@@ -24126,7 +26608,7 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
24126 /* Only do this for the very first display in the Emacs session. 26608 /* Only do this for the very first display in the Emacs session.
24127 Ignore X session management when Emacs was first started on a 26609 Ignore X session management when Emacs was first started on a
24128 tty or started as a daemon. */ 26610 tty or started as a daemon. */
24129 if (terminal->id == 1 && ! IS_DAEMON) 26611 if (!dpyinfo->next && ! IS_DAEMON)
24130 x_session_initialize (dpyinfo); 26612 x_session_initialize (dpyinfo);
24131#endif 26613#endif
24132 26614
@@ -24154,6 +26636,7 @@ x_delete_display (struct x_display_info *dpyinfo)
24154 struct terminal *t; 26636 struct terminal *t;
24155 struct color_name_cache_entry *color_entry, *next_color_entry; 26637 struct color_name_cache_entry *color_entry, *next_color_entry;
24156 int i; 26638 int i;
26639 struct x_selection_request_event *ie, *last, *temp;
24157 26640
24158 /* Close all frames and delete the generic struct terminal for this 26641 /* Close all frames and delete the generic struct terminal for this
24159 X display. */ 26642 X display. */
@@ -24169,6 +26652,30 @@ x_delete_display (struct x_display_info *dpyinfo)
24169 break; 26652 break;
24170 } 26653 }
24171 26654
26655 /* Find any pending selection requests for this display and unchain
26656 them. */
26657
26658 last = NULL;
26659
26660 for (ie = pending_selection_requests; ie; ie = ie->next)
26661 {
26662 again:
26663
26664 if (SELECTION_EVENT_DPYINFO (&ie->se) == dpyinfo)
26665 {
26666 if (last)
26667 last->next = ie->next;
26668
26669 temp = ie;
26670 ie = ie->next;
26671 xfree (temp);
26672
26673 goto again;
26674 }
26675
26676 last = ie;
26677 }
26678
24172 if (next_noop_dpyinfo == dpyinfo) 26679 if (next_noop_dpyinfo == dpyinfo)
24173 next_noop_dpyinfo = dpyinfo->next; 26680 next_noop_dpyinfo = dpyinfo->next;
24174 26681
@@ -24199,6 +26706,7 @@ x_delete_display (struct x_display_info *dpyinfo)
24199 } 26706 }
24200 26707
24201 xfree (dpyinfo->color_names); 26708 xfree (dpyinfo->color_names);
26709 xfree (dpyinfo->color_names_length);
24202 xfree (dpyinfo->x_id_name); 26710 xfree (dpyinfo->x_id_name);
24203 xfree (dpyinfo->x_dnd_atoms); 26711 xfree (dpyinfo->x_dnd_atoms);
24204 xfree (dpyinfo->color_cells); 26712 xfree (dpyinfo->color_cells);
@@ -24335,11 +26843,12 @@ x_delete_terminal (struct terminal *terminal)
24335 x_dnd_last_seen_window = None; 26843 x_dnd_last_seen_window = None;
24336 x_dnd_last_seen_toplevel = None; 26844 x_dnd_last_seen_toplevel = None;
24337 x_dnd_in_progress = false; 26845 x_dnd_in_progress = false;
24338 x_set_dnd_targets (NULL, 0);
24339 x_dnd_waiting_for_finish = false; 26846 x_dnd_waiting_for_finish = false;
24340 26847
26848 /* The display is going away, so there's no point in
26849 de-selecting for input on the DND toplevels. */
24341 if (x_dnd_use_toplevels) 26850 if (x_dnd_use_toplevels)
24342 x_dnd_free_toplevels (); 26851 x_dnd_free_toplevels (false);
24343 26852
24344 x_dnd_return_frame_object = NULL; 26853 x_dnd_return_frame_object = NULL;
24345 x_dnd_movement_frame = NULL; 26854 x_dnd_movement_frame = NULL;
@@ -24576,7 +27085,8 @@ mark_xterm (void)
24576 mark_object (val); 27085 mark_object (val);
24577 } 27086 }
24578 27087
24579#if defined HAVE_XINPUT2 || defined USE_TOOLKIT_SCROLL_BARS 27088#if defined HAVE_XINPUT2 || defined USE_TOOLKIT_SCROLL_BARS \
27089 || defined HAVE_XRANDR || defined USE_GTK
24580 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) 27090 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
24581 { 27091 {
24582#ifdef HAVE_XINPUT2 27092#ifdef HAVE_XINPUT2
@@ -24587,6 +27097,9 @@ mark_xterm (void)
24587 for (i = 0; i < dpyinfo->n_protected_windows; ++i) 27097 for (i = 0; i < dpyinfo->n_protected_windows; ++i)
24588 mark_object (dpyinfo->protected_windows[i]); 27098 mark_object (dpyinfo->protected_windows[i]);
24589#endif 27099#endif
27100#if defined HAVE_XRANDR || defined USE_GTK
27101 mark_object (dpyinfo->last_monitor_attributes_list);
27102#endif
24590 } 27103 }
24591#endif 27104#endif
24592} 27105}
@@ -24597,9 +27110,16 @@ syms_of_xterm (void)
24597 x_error_message = NULL; 27110 x_error_message = NULL;
24598 PDUMPER_IGNORE (x_error_message); 27111 PDUMPER_IGNORE (x_error_message);
24599 27112
27113 x_dnd_monitors = Qnil;
27114 staticpro (&x_dnd_monitors);
27115
27116 x_dnd_action_symbol = Qnil;
27117 staticpro (&x_dnd_action_symbol);
27118
24600 DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms"); 27119 DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms");
24601 DEFSYM (Qlatin_1, "latin-1"); 27120 DEFSYM (Qlatin_1, "latin-1");
24602 DEFSYM (Qnow, "now"); 27121 DEFSYM (Qnow, "now");
27122 DEFSYM (Qx_dnd_targets_list, "x-dnd-targets-list");
24603 27123
24604#ifdef USE_GTK 27124#ifdef USE_GTK
24605 xg_default_icon_file = build_pure_c_string ("icons/hicolor/scalable/apps/emacs.svg"); 27125 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
24637click on a frame to select it (give it focus). In that case, a value 27157click on a frame to select it (give it focus). In that case, a value
24638of nil, means that the selected window and cursor position changes to 27158of nil, means that the selected window and cursor position changes to
24639reflect the mouse click position, while a non-nil value means that the 27159reflect the mouse click position, while a non-nil value means that the
24640selected window or cursor position is preserved. */); 27160selected window or cursor position is preserved.
27161
27162This option works by ignoring button press events for a given amount
27163of time after a frame might've been focused. If it does not work for
27164you, try increasing the value of
27165`x-mouse-click-focus-ignore-time'. */);
24641 x_mouse_click_focus_ignore_position = false; 27166 x_mouse_click_focus_ignore_position = false;
24642 27167
27168 DEFVAR_INT ("x-mouse-click-focus-ignore-time", x_mouse_click_focus_ignore_time,
27169 doc: /* Number of miliseconds for which to ignore buttons after focus change.
27170This variable only takes effect if
27171`x-mouse-click-focus-ignore-position' is non-nil, and should be
27172adjusted if the default value does not work for whatever reason. */);
27173 x_mouse_click_focus_ignore_time = 200;
27174
24643 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars, 27175 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
24644 doc: /* Which toolkit scroll bars Emacs uses, if any. 27176 doc: /* Which toolkit scroll bars Emacs uses, if any.
24645A value of nil means Emacs doesn't use toolkit scroll bars. 27177A 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
24791of Motif. */); 27323of Motif. */);
24792 x_dnd_fix_motif_leave = true; 27324 x_dnd_fix_motif_leave = true;
24793 27325
27326 DEFVAR_BOOL ("x-dnd-disable-motif-drag", x_dnd_disable_motif_drag,
27327 doc: /* Disable the Motif drag protocol during DND.
27328This reduces network usage, but also means you can no longer scroll
27329around inside the Motif window underneath the cursor during
27330drag-and-drop. */);
27331 x_dnd_disable_motif_drag = false;
27332
24794 DEFVAR_LISP ("x-dnd-movement-function", Vx_dnd_movement_function, 27333 DEFVAR_LISP ("x-dnd-movement-function", Vx_dnd_movement_function,
24795 doc: /* Function called upon mouse movement on a frame during drag-and-drop. 27334 doc: /* Function called upon mouse movement on a frame during drag-and-drop.
24796It should either be nil, or accept two arguments FRAME and POSITION, 27335It should either be nil, or accept two arguments FRAME and POSITION,
@@ -24800,16 +27339,41 @@ mouse position list. */);
24800 27339
24801 DEFVAR_LISP ("x-dnd-unsupported-drop-function", Vx_dnd_unsupported_drop_function, 27340 DEFVAR_LISP ("x-dnd-unsupported-drop-function", Vx_dnd_unsupported_drop_function,
24802 doc: /* Function called when trying to drop on an unsupported window. 27341 doc: /* Function called when trying to drop on an unsupported window.
24803This function is called whenever the user tries to drop 27342This function is called whenever the user tries to drop something on a
24804something on a window that does not support either the XDND or 27343window that does not support either the XDND or Motif protocols for
24805Motif protocols for drag-and-drop. It should return a non-nil 27344drag-and-drop. It should return a non-nil value if the drop was
24806value if the drop was handled by the function, and nil if it was 27345handled by the function, and nil if it was not. It should accept
24807not. It should accept several arguments TARGETS, X, Y, ACTION, 27346several arguments TARGETS, X, Y, ACTION, WINDOW-ID, FRAME and TIME,
24808WINDOW-ID and FRAME, where TARGETS is the list of targets that 27347where TARGETS is the list of targets that was passed to
24809was passed to `x-begin-drag', WINDOW-ID is the numeric XID of 27348`x-begin-drag', WINDOW-ID is the numeric XID of the window that is
24810the window that is being dropped on, X and Y are the root 27349being dropped on, X and Y are the root window-relative coordinates
24811window-relative coordinates where the drop happened, ACTION 27350where the drop happened, ACTION is the action that was passed to
24812is the action that was passed to `x-begin-drag', and FRAME is 27351`x-begin-drag', FRAME is the frame which initiated the drag-and-drop
24813the frame which initiated the drag-and-drop operation. */); 27352operation, and TIME is the X server time when the drop happened. */);
24814 Vx_dnd_unsupported_drop_function = Qnil; 27353 Vx_dnd_unsupported_drop_function = Qnil;
27354
27355 DEFVAR_INT ("x-color-cache-bucket-size", x_color_cache_bucket_size,
27356 doc: /* Max number of buckets allowed per display in the internal color cache.
27357Values less than 1 mean 128. This option is for debugging only. */);
27358 x_color_cache_bucket_size = 128;
27359
27360 DEFVAR_LISP ("x-dnd-targets-list", Vx_dnd_targets_list,
27361 doc: /* List of drag-and-drop targets.
27362This variable contains the list of drag-and-drop selection targets
27363during a drag-and-drop operation, in the same format as the TARGET
27364argument to `x-begin-drag'. */);
27365 Vx_dnd_targets_list = Qnil;
27366
27367 DEFVAR_LISP ("x-dnd-native-test-function", Vx_dnd_native_test_function,
27368 doc: /* Function that determines return value of drag-and-drop on Emacs frames.
27369If the value is a function, `x-begin-drag' will call it with two
27370arguments, POS and ACTION, where POS is a mouse position list
27371that specifies the location of the drop, and ACTION is the
27372action specified by the caller of `x-begin-drag'. The function
27373should return a symbol describing what to return from
27374`x-begin-drag' if the drop happens on an Emacs frame.
27375
27376If the value is nil, or the function returns a value that is not
27377a symbol, a drop on an Emacs frame will be canceled. */);
27378 Vx_dnd_native_test_function = Qnil;
24815} 27379}
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);
196struct color_name_cache_entry 196struct color_name_cache_entry
197{ 197{
198 struct color_name_cache_entry *next; 198 struct color_name_cache_entry *next;
199
200 /* The color values of the cached color entry. */
199 XColor rgb; 201 XColor rgb;
202
203 /* The name of the cached color. */
200 char *name; 204 char *name;
205
206 /* Whether or not RGB is valid (i.e. the color actually exists). */
207 bool_bf valid : 1;
201}; 208};
202 209
203#ifdef HAVE_XINPUT2 210#ifdef HAVE_XINPUT2
@@ -513,6 +520,9 @@ struct x_display_info
513 /* A cache mapping color names to RGB values. */ 520 /* A cache mapping color names to RGB values. */
514 struct color_name_cache_entry **color_names; 521 struct color_name_cache_entry **color_names;
515 522
523 /* The number of buckets for each hash in that hash table. */
524 ptrdiff_t *color_names_length;
525
516 /* The size of that hash table. */ 526 /* The size of that hash table. */
517 int color_names_size; 527 int color_names_size;
518 528
@@ -595,10 +605,19 @@ struct x_display_info
595 XModifierKeymap *modmap; 605 XModifierKeymap *modmap;
596 606
597#ifdef HAVE_XRANDR 607#ifdef HAVE_XRANDR
608 bool xrandr_supported_p;
609 int xrandr_event_base;
610 int xrandr_error_base;
598 int xrandr_major_version; 611 int xrandr_major_version;
599 int xrandr_minor_version; 612 int xrandr_minor_version;
600#endif 613#endif
601 614
615#if defined HAVE_XRANDR || defined USE_GTK
616 /* This is used to determine if the monitor configuration really
617 changed upon receiving a monitor change event. */
618 Lisp_Object last_monitor_attributes_list;
619#endif
620
602#if defined USE_CAIRO || defined HAVE_XRENDER 621#if defined USE_CAIRO || defined HAVE_XRENDER
603 XExtCodes *ext_codes; 622 XExtCodes *ext_codes;
604#endif 623#endif
@@ -683,6 +702,17 @@ struct x_display_info
683 int n_protected_windows; 702 int n_protected_windows;
684 int protected_windows_max; 703 int protected_windows_max;
685#endif 704#endif
705
706 /* The current dimensions of the screen. This is updated when a
707 ConfigureNotify is received for the root window, and is zero if
708 that didn't happen. */
709 int screen_width;
710 int screen_height;
711
712 /* The mm width and height of the screen. Updated on
713 RRScreenChangeNotify. */
714 int screen_mm_width;
715 int screen_mm_height;
686}; 716};
687 717
688#ifdef HAVE_X_I18N 718#ifdef HAVE_X_I18N
@@ -706,6 +736,9 @@ extern bool x_display_ok (const char *);
706extern void select_visual (struct x_display_info *); 736extern void select_visual (struct x_display_info *);
707 737
708extern Window tip_window; 738extern Window tip_window;
739extern Lisp_Object tip_dx;
740extern Lisp_Object tip_dy;
741extern Lisp_Object tip_frame;
709 742
710/* Each X frame object points to its own struct x_output object 743/* Each X frame object points to its own struct x_output object
711 in the output_data.x field. The x_output structure contains 744 in the output_data.x field. The x_output structure contains
@@ -925,6 +958,10 @@ struct x_output
925 false, tell Xt not to wait. */ 958 false, tell Xt not to wait. */
926 bool_bf wait_for_wm : 1; 959 bool_bf wait_for_wm : 1;
927 960
961 /* True if this frame's alpha value is the same for both the active
962 and inactive states. */
963 bool_bf alpha_identical_p : 1;
964
928#ifdef HAVE_X_I18N 965#ifdef HAVE_X_I18N
929 /* Input context (currently, this means Compose key handler setup). */ 966 /* Input context (currently, this means Compose key handler setup). */
930 XIC xic; 967 XIC xic;
@@ -1352,8 +1389,8 @@ extern const char *x_get_string_resource (void *, const char *, const char *);
1352 1389
1353/* Defined in xterm.c */ 1390/* Defined in xterm.c */
1354 1391
1355typedef void (*x_special_error_handler)(Display *, XErrorEvent *, char *, 1392typedef void (*x_special_error_handler) (Display *, XErrorEvent *, char *,
1356 void *); 1393 void *);
1357 1394
1358extern bool x_text_icon (struct frame *, const char *); 1395extern bool x_text_icon (struct frame *, const char *);
1359extern void x_catch_errors (Display *); 1396extern void x_catch_errors (Display *);
@@ -1362,6 +1399,7 @@ extern void x_catch_errors_with_handler (Display *, x_special_error_handler,
1362extern void x_check_errors (Display *, const char *) 1399extern void x_check_errors (Display *, const char *)
1363 ATTRIBUTE_FORMAT_PRINTF (2, 0); 1400 ATTRIBUTE_FORMAT_PRINTF (2, 0);
1364extern bool x_had_errors_p (Display *); 1401extern bool x_had_errors_p (Display *);
1402extern void x_unwind_errors_to (int);
1365extern void x_uncatch_errors (void); 1403extern void x_uncatch_errors (void);
1366extern void x_uncatch_errors_after_check (void); 1404extern void x_uncatch_errors_after_check (void);
1367extern void x_clear_errors (Display *); 1405extern void x_clear_errors (Display *);
@@ -1372,7 +1410,8 @@ extern void x_iconify_frame (struct frame *f);
1372extern void x_free_frame_resources (struct frame *); 1410extern void x_free_frame_resources (struct frame *);
1373extern void x_wm_set_size_hint (struct frame *, long, bool); 1411extern void x_wm_set_size_hint (struct frame *, long, bool);
1374 1412
1375extern void x_delete_terminal (struct terminal *terminal); 1413extern void x_delete_terminal (struct terminal *);
1414extern Cursor x_create_font_cursor (struct x_display_info *, int);
1376extern unsigned long x_copy_color (struct frame *, unsigned long); 1415extern unsigned long x_copy_color (struct frame *, unsigned long);
1377#ifdef USE_X_TOOLKIT 1416#ifdef USE_X_TOOLKIT
1378extern XtAppContext Xt_app_con; 1417extern XtAppContext Xt_app_con;
@@ -1390,6 +1429,7 @@ extern void x_clear_area (struct frame *f, int, int, int, int);
1390 || (!defined USE_X_TOOLKIT && !defined USE_GTK) 1429 || (!defined USE_X_TOOLKIT && !defined USE_GTK)
1391extern void x_mouse_leave (struct x_display_info *); 1430extern void x_mouse_leave (struct x_display_info *);
1392#endif 1431#endif
1432extern void x_wait_for_cell_change (Lisp_Object, struct timespec);
1393 1433
1394#ifndef USE_GTK 1434#ifndef USE_GTK
1395extern int x_dispatch_event (XEvent *, Display *); 1435extern int x_dispatch_event (XEvent *, Display *);
@@ -1419,25 +1459,24 @@ extern void x_xr_reset_ext_clip (struct frame *f);
1419extern void x_scroll_bar_configure (GdkEvent *); 1459extern void x_scroll_bar_configure (GdkEvent *);
1420#endif 1460#endif
1421 1461
1462#define DEFER_SELECTIONS \
1463 x_defer_selection_requests (); \
1464 record_unwind_protect_void (x_release_selection_requests_and_flush)
1465
1466extern void x_defer_selection_requests (void);
1467extern void x_release_selection_requests_and_flush (void);
1468extern void x_handle_pending_selection_requests (void);
1469extern bool x_detect_pending_selection_requests (void);
1422extern Lisp_Object x_dnd_begin_drag_and_drop (struct frame *, Time, Atom, 1470extern Lisp_Object x_dnd_begin_drag_and_drop (struct frame *, Time, Atom,
1423 Lisp_Object, Atom *, const char **, 1471 Lisp_Object, Atom *, const char **,
1424 size_t, bool); 1472 size_t, bool, Atom *, int,
1473 Lisp_Object, bool);
1425extern void x_dnd_do_unsupported_drop (struct x_display_info *, Lisp_Object, 1474extern void x_dnd_do_unsupported_drop (struct x_display_info *, Lisp_Object,
1426 Lisp_Object, Lisp_Object, Window, int, 1475 Lisp_Object, Lisp_Object, Window, int,
1427 int, Time); 1476 int, Time);
1428extern void x_set_dnd_targets (Atom *, int);
1429
1430INLINE int
1431x_display_pixel_height (struct x_display_info *dpyinfo)
1432{
1433 return HeightOfScreen (dpyinfo->screen);
1434}
1435 1477
1436INLINE int 1478extern int x_display_pixel_height (struct x_display_info *);
1437x_display_pixel_width (struct x_display_info *dpyinfo) 1479extern int x_display_pixel_width (struct x_display_info *);
1438{
1439 return WidthOfScreen (dpyinfo->screen);
1440}
1441 1480
1442INLINE unsigned long 1481INLINE unsigned long
1443x_make_truecolor_pixel (struct x_display_info *dpyinfo, int r, int g, int b) 1482x_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);
1471extern void x_set_skip_taskbar (struct frame *, Lisp_Object, Lisp_Object); 1510extern void x_set_skip_taskbar (struct frame *, Lisp_Object, Lisp_Object);
1472extern void x_set_z_group (struct frame *, Lisp_Object, Lisp_Object); 1511extern void x_set_z_group (struct frame *, Lisp_Object, Lisp_Object);
1473extern bool x_wm_supports (struct frame *, Atom); 1512extern bool x_wm_supports (struct frame *, Atom);
1513extern bool x_wm_supports_1 (struct x_display_info *, Atom);
1474extern void x_wait_for_event (struct frame *, int); 1514extern void x_wait_for_event (struct frame *, int);
1475extern void x_clear_under_internal_border (struct frame *f); 1515extern void x_clear_under_internal_border (struct frame *f);
1476 1516
@@ -1495,11 +1535,13 @@ extern void x_handle_property_notify (const XPropertyEvent *);
1495extern void x_handle_selection_notify (const XSelectionEvent *); 1535extern void x_handle_selection_notify (const XSelectionEvent *);
1496extern void x_handle_selection_event (struct selection_input_event *); 1536extern void x_handle_selection_event (struct selection_input_event *);
1497extern void x_clear_frame_selections (struct frame *); 1537extern void x_clear_frame_selections (struct frame *);
1538extern Lisp_Object x_atom_to_symbol (struct x_display_info *, Atom);
1498 1539
1499extern bool x_handle_dnd_message (struct frame *, 1540extern bool x_handle_dnd_message (struct frame *,
1500 const XClientMessageEvent *, 1541 const XClientMessageEvent *,
1501 struct x_display_info *, 1542 struct x_display_info *,
1502 struct input_event *); 1543 struct input_event *,
1544 bool, int, int);
1503extern int x_check_property_data (Lisp_Object); 1545extern int x_check_property_data (Lisp_Object);
1504extern void x_fill_property_data (Display *, 1546extern void x_fill_property_data (Display *,
1505 Lisp_Object, 1547 Lisp_Object,
@@ -1518,6 +1560,10 @@ extern Lisp_Object x_timestamp_for_selection (struct x_display_info *,
1518 Lisp_Object); 1560 Lisp_Object);
1519extern void x_set_pending_dnd_time (Time); 1561extern void x_set_pending_dnd_time (Time);
1520extern void x_own_selection (Lisp_Object, Lisp_Object, Lisp_Object); 1562extern void x_own_selection (Lisp_Object, Lisp_Object, Lisp_Object);
1563extern Atom x_intern_cached_atom (struct x_display_info *, const char *,
1564 bool);
1565extern char *x_get_atom_name (struct x_display_info *, Atom, bool *)
1566 ATTRIBUTE_MALLOC ATTRIBUTE_DEALLOC_FREE;
1521 1567
1522#ifdef USE_GTK 1568#ifdef USE_GTK
1523extern bool xg_set_icon (struct frame *, Lisp_Object); 1569extern bool xg_set_icon (struct frame *, Lisp_Object);
@@ -1578,7 +1624,11 @@ extern struct input_event xg_pending_quit_event;
1578#endif 1624#endif
1579 1625
1580extern bool x_dnd_in_progress; 1626extern bool x_dnd_in_progress;
1627extern bool x_dnd_waiting_for_finish;
1581extern struct frame *x_dnd_frame; 1628extern struct frame *x_dnd_frame;
1629extern struct frame *x_dnd_finish_frame;
1630extern unsigned x_dnd_unsupported_event_level;
1631extern int x_error_message_count;
1582 1632
1583#ifdef HAVE_XINPUT2 1633#ifdef HAVE_XINPUT2
1584extern struct xi_device_t *xi_device_from_id (struct x_display_info *, int); 1634extern struct xi_device_t *xi_device_from_id (struct x_display_info *, int);