diff options
| author | Martin Rudalics | 2016-03-08 08:51:38 +0100 |
|---|---|---|
| committer | Martin Rudalics | 2016-03-08 08:51:38 +0100 |
| commit | 80864c2a04597d31ba453c9af69d35b15c4e1e24 (patch) | |
| tree | 1cbfcba4d5bbb9008014c4a89df2b2aad4d891c2 /src | |
| parent | 59c7a5d71145d88933a535e222bdf30105e7d382 (diff) | |
| download | emacs-80864c2a04597d31ba453c9af69d35b15c4e1e24.tar.gz emacs-80864c2a04597d31ba453c9af69d35b15c4e1e24.zip | |
Optionally reuse tooltip frames instead of deleting/recreating them.
* src/frame.c (tooltip_reuse_hidden_frame): New option.
* src/w32fns.c (x_create_tip_frame): Remove argument TEXT. Fix
handling of dividers.
(x_hide_tip): New function.
(Fx_show_tip): Try to reuse old tooltip frame when
`tooltip-reuse-hidden-frame' is non-nil and frame parameters
have not changed. Insert STRING here instead of passing it to
x_create_tip_frame. Compute size of tooltip window with
Fwindow_text_pixel_size. Obey Vw32_tooltip_extra_pixels when
padding tooltip window.
(Fx_hide_tip): Call x_hide_tip.
(Vw32_tooltip_extra_pixels): New variable.
* src/xdisp.c (Fwindow_text_pixel_size): Don't return negative y
value. Fix doc-string.
* src/xfns.c (x_create_tip_frame): Remove argument TEXT. Call
make_frame with mini_p argument false.
(x_hide_tip): New function.
(Fx_show_tip): Try to reuse old tooltip frame when
`tooltip-reuse-hidden-frame' is non-nil and frame parameters
have not changed. Insert STRING here instead of passing it to
x_create_tip_frame. Compute size of tooltip window with
Fwindow_text_pixel_size.
(Fx_hide_tip): Call x_hide_tip.
* lisp/cus-start.el (tooltip-reuse-hidden-frame): Add
customization entry.
Diffstat (limited to 'src')
| -rw-r--r-- | src/frame.c | 15 | ||||
| -rw-r--r-- | src/w32fns.c | 439 | ||||
| -rw-r--r-- | src/xdisp.c | 73 | ||||
| -rw-r--r-- | src/xfns.c | 439 |
4 files changed, 475 insertions, 491 deletions
diff --git a/src/frame.c b/src/frame.c index fd9f3ce0203..d5364682f61 100644 --- a/src/frame.c +++ b/src/frame.c | |||
| @@ -5262,6 +5262,21 @@ The function `frame--size-history' displays the value of this variable | |||
| 5262 | in a more readable form. */); | 5262 | in a more readable form. */); |
| 5263 | frame_size_history = Qnil; | 5263 | frame_size_history = Qnil; |
| 5264 | 5264 | ||
| 5265 | DEFVAR_BOOL ("tooltip-reuse-hidden-frame", tooltip_reuse_hidden_frame, | ||
| 5266 | doc: /* Non-nil means reuse hidden tooltip frames. | ||
| 5267 | When this is nil, delete a tooltip frame when hiding the associated | ||
| 5268 | tooltip. When this is non-nil, make the tooltip frame invisible only, | ||
| 5269 | so it can be reused when the next tooltip is shown. | ||
| 5270 | |||
| 5271 | Setting this to non-nil may drastically reduce the consing overhead | ||
| 5272 | incurred by creating new tooltip frames. However, a value of non-nil | ||
| 5273 | means also that intermittent changes of faces or `default-frame-alist' | ||
| 5274 | are not applied when showing a tooltip in a reused frame. | ||
| 5275 | |||
| 5276 | This variable is effective only with the X toolkit (and there only when | ||
| 5277 | Gtk+ tooltips are not used) and on Windows. */); | ||
| 5278 | tooltip_reuse_hidden_frame = false; | ||
| 5279 | |||
| 5265 | staticpro (&Vframe_list); | 5280 | staticpro (&Vframe_list); |
| 5266 | 5281 | ||
| 5267 | defsubr (&Sframep); | 5282 | defsubr (&Sframep); |
diff --git a/src/w32fns.c b/src/w32fns.c index 0fe6a6fd2b3..568a45a3114 100644 --- a/src/w32fns.c +++ b/src/w32fns.c | |||
| @@ -6422,8 +6422,6 @@ no value of TYPE (always string in the MS Windows case). */) | |||
| 6422 | Tool tips | 6422 | Tool tips |
| 6423 | ***********************************************************************/ | 6423 | ***********************************************************************/ |
| 6424 | 6424 | ||
| 6425 | static Lisp_Object x_create_tip_frame (struct w32_display_info *, | ||
| 6426 | Lisp_Object, Lisp_Object); | ||
| 6427 | static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, | 6425 | static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, |
| 6428 | Lisp_Object, int, int, int *, int *); | 6426 | Lisp_Object, int, int, int *, int *); |
| 6429 | 6427 | ||
| @@ -6458,8 +6456,7 @@ unwind_create_tip_frame (Lisp_Object frame) | |||
| 6458 | 6456 | ||
| 6459 | 6457 | ||
| 6460 | /* Create a frame for a tooltip on the display described by DPYINFO. | 6458 | /* Create a frame for a tooltip on the display described by DPYINFO. |
| 6461 | PARMS is a list of frame parameters. TEXT is the string to | 6459 | PARMS is a list of frame parameters. Value is the frame. |
| 6462 | display in the tip frame. Value is the frame. | ||
| 6463 | 6460 | ||
| 6464 | Note that functions called here, esp. x_default_parameter can | 6461 | Note that functions called here, esp. x_default_parameter can |
| 6465 | signal errors, for instance when a specified color name is | 6462 | signal errors, for instance when a specified color name is |
| @@ -6467,8 +6464,7 @@ unwind_create_tip_frame (Lisp_Object frame) | |||
| 6467 | when this happens. */ | 6464 | when this happens. */ |
| 6468 | 6465 | ||
| 6469 | static Lisp_Object | 6466 | static Lisp_Object |
| 6470 | x_create_tip_frame (struct w32_display_info *dpyinfo, | 6467 | x_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms) |
| 6471 | Lisp_Object parms, Lisp_Object text) | ||
| 6472 | { | 6468 | { |
| 6473 | struct frame *f; | 6469 | struct frame *f; |
| 6474 | Lisp_Object frame; | 6470 | Lisp_Object frame; |
| @@ -6477,8 +6473,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, | |||
| 6477 | ptrdiff_t count = SPECPDL_INDEX (); | 6473 | ptrdiff_t count = SPECPDL_INDEX (); |
| 6478 | struct kboard *kb; | 6474 | struct kboard *kb; |
| 6479 | bool face_change_before = face_change; | 6475 | bool face_change_before = face_change; |
| 6480 | Lisp_Object buffer; | ||
| 6481 | struct buffer *old_buffer; | ||
| 6482 | int x_width = 0, x_height = 0; | 6476 | int x_width = 0, x_height = 0; |
| 6483 | 6477 | ||
| 6484 | /* Use this general default value to start with until we know if | 6478 | /* Use this general default value to start with until we know if |
| @@ -6502,23 +6496,9 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, | |||
| 6502 | frame = Qnil; | 6496 | frame = Qnil; |
| 6503 | /* Make a frame without minibuffer nor mode-line. */ | 6497 | /* Make a frame without minibuffer nor mode-line. */ |
| 6504 | f = make_frame (false); | 6498 | f = make_frame (false); |
| 6505 | f->wants_modeline = 0; | 6499 | f->wants_modeline = false; |
| 6506 | XSETFRAME (frame, f); | 6500 | XSETFRAME (frame, f); |
| 6507 | 6501 | ||
| 6508 | AUTO_STRING (tip, " *tip*"); | ||
| 6509 | buffer = Fget_buffer_create (tip); | ||
| 6510 | /* Use set_window_buffer instead of Fset_window_buffer (see | ||
| 6511 | discussion of bug#11984, bug#12025, bug#12026). */ | ||
| 6512 | set_window_buffer (FRAME_ROOT_WINDOW (f), buffer, false, false); | ||
| 6513 | old_buffer = current_buffer; | ||
| 6514 | set_buffer_internal_1 (XBUFFER (buffer)); | ||
| 6515 | bset_truncate_lines (current_buffer, Qnil); | ||
| 6516 | specbind (Qinhibit_read_only, Qt); | ||
| 6517 | specbind (Qinhibit_modification_hooks, Qt); | ||
| 6518 | Ferase_buffer (); | ||
| 6519 | Finsert (1, &text); | ||
| 6520 | set_buffer_internal_1 (old_buffer); | ||
| 6521 | |||
| 6522 | record_unwind_protect (unwind_create_tip_frame, frame); | 6502 | record_unwind_protect (unwind_create_tip_frame, frame); |
| 6523 | 6503 | ||
| 6524 | /* By setting the output method, we're essentially saying that | 6504 | /* By setting the output method, we're essentially saying that |
| @@ -6552,7 +6532,7 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, | |||
| 6552 | { | 6532 | { |
| 6553 | fset_name (f, name); | 6533 | fset_name (f, name); |
| 6554 | f->explicit_name = true; | 6534 | f->explicit_name = true; |
| 6555 | /* use the frame's title when getting resources for this frame. */ | 6535 | /* Use the frame's title when getting resources for this frame. */ |
| 6556 | specbind (Qx_resource_name, name); | 6536 | specbind (Qx_resource_name, name); |
| 6557 | } | 6537 | } |
| 6558 | 6538 | ||
| @@ -6582,14 +6562,10 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, | |||
| 6582 | parms = Fcons (Fcons (Qinternal_border_width, value), | 6562 | parms = Fcons (Fcons (Qinternal_border_width, value), |
| 6583 | parms); | 6563 | parms); |
| 6584 | } | 6564 | } |
| 6565 | |||
| 6585 | x_default_parameter (f, parms, Qinternal_border_width, make_number (1), | 6566 | x_default_parameter (f, parms, Qinternal_border_width, make_number (1), |
| 6586 | "internalBorderWidth", "internalBorderWidth", | 6567 | "internalBorderWidth", "internalBorderWidth", |
| 6587 | RES_TYPE_NUMBER); | 6568 | RES_TYPE_NUMBER); |
| 6588 | x_default_parameter (f, parms, Qright_divider_width, make_number (0), | ||
| 6589 | NULL, NULL, RES_TYPE_NUMBER); | ||
| 6590 | x_default_parameter (f, parms, Qbottom_divider_width, make_number (0), | ||
| 6591 | NULL, NULL, RES_TYPE_NUMBER); | ||
| 6592 | |||
| 6593 | /* Also do the stuff which must be set before the window exists. */ | 6569 | /* Also do the stuff which must be set before the window exists. */ |
| 6594 | x_default_parameter (f, parms, Qforeground_color, build_string ("black"), | 6570 | x_default_parameter (f, parms, Qforeground_color, build_string ("black"), |
| 6595 | "foreground", "Foreground", RES_TYPE_STRING); | 6571 | "foreground", "Foreground", RES_TYPE_STRING); |
| @@ -6616,6 +6592,9 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, | |||
| 6616 | f->fringe_cols = 0; | 6592 | f->fringe_cols = 0; |
| 6617 | f->left_fringe_width = 0; | 6593 | f->left_fringe_width = 0; |
| 6618 | f->right_fringe_width = 0; | 6594 | f->right_fringe_width = 0; |
| 6595 | /* No dividers on tip frame. */ | ||
| 6596 | f->right_divider_width = 0; | ||
| 6597 | f->bottom_divider_width = 0; | ||
| 6619 | 6598 | ||
| 6620 | block_input (); | 6599 | block_input (); |
| 6621 | my_create_tip_window (f); | 6600 | my_create_tip_window (f); |
| @@ -6642,7 +6621,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, | |||
| 6642 | SET_FRAME_LINES (f, 0); | 6621 | SET_FRAME_LINES (f, 0); |
| 6643 | adjust_frame_size (f, width * FRAME_COLUMN_WIDTH (f), | 6622 | adjust_frame_size (f, width * FRAME_COLUMN_WIDTH (f), |
| 6644 | height * FRAME_LINE_HEIGHT (f), 0, true, Qtip_frame); | 6623 | height * FRAME_LINE_HEIGHT (f), 0, true, Qtip_frame); |
| 6645 | |||
| 6646 | /* Add `tooltip' frame parameter's default value. */ | 6624 | /* Add `tooltip' frame parameter's default value. */ |
| 6647 | if (NILP (Fframe_parameter (frame, Qtooltip))) | 6625 | if (NILP (Fframe_parameter (frame, Qtooltip))) |
| 6648 | Fmodify_frame_parameters (frame, Fcons (Fcons (Qtooltip, Qt), Qnil)); | 6626 | Fmodify_frame_parameters (frame, Fcons (Fcons (Qtooltip, Qt), Qnil)); |
| @@ -6660,8 +6638,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, | |||
| 6660 | Lisp_Object fg = Fframe_parameter (frame, Qforeground_color); | 6638 | Lisp_Object fg = Fframe_parameter (frame, Qforeground_color); |
| 6661 | Lisp_Object colors = Qnil; | 6639 | Lisp_Object colors = Qnil; |
| 6662 | 6640 | ||
| 6663 | /* Set tip_frame here, so that */ | ||
| 6664 | tip_frame = frame; | ||
| 6665 | call2 (Qface_set_after_frame_default, frame, Qnil); | 6641 | call2 (Qface_set_after_frame_default, frame, Qnil); |
| 6666 | 6642 | ||
| 6667 | if (!EQ (bg, Fframe_parameter (frame, Qbackground_color))) | 6643 | if (!EQ (bg, Fframe_parameter (frame, Qbackground_color))) |
| @@ -6793,6 +6769,48 @@ compute_tip_xy (struct frame *f, | |||
| 6793 | *root_x = min_x; | 6769 | *root_x = min_x; |
| 6794 | } | 6770 | } |
| 6795 | 6771 | ||
| 6772 | /* Hide tooltip. Delete its frame if DELETE is true. */ | ||
| 6773 | static Lisp_Object | ||
| 6774 | x_hide_tip (bool delete) | ||
| 6775 | { | ||
| 6776 | if (!NILP (tip_timer)) | ||
| 6777 | { | ||
| 6778 | call1 (Qcancel_timer, tip_timer); | ||
| 6779 | tip_timer = Qnil; | ||
| 6780 | } | ||
| 6781 | |||
| 6782 | if (NILP (tip_frame) | ||
| 6783 | || (!delete && FRAMEP (tip_frame) | ||
| 6784 | && !FRAME_VISIBLE_P (XFRAME (tip_frame)))) | ||
| 6785 | return Qnil; | ||
| 6786 | else | ||
| 6787 | { | ||
| 6788 | ptrdiff_t count; | ||
| 6789 | Lisp_Object was_open = Qnil; | ||
| 6790 | |||
| 6791 | count = SPECPDL_INDEX (); | ||
| 6792 | specbind (Qinhibit_redisplay, Qt); | ||
| 6793 | specbind (Qinhibit_quit, Qt); | ||
| 6794 | |||
| 6795 | if (FRAMEP (tip_frame)) | ||
| 6796 | { | ||
| 6797 | if (delete) | ||
| 6798 | { | ||
| 6799 | delete_frame (tip_frame, Qnil); | ||
| 6800 | tip_frame = Qnil; | ||
| 6801 | } | ||
| 6802 | else | ||
| 6803 | x_make_frame_invisible (XFRAME (tip_frame)); | ||
| 6804 | |||
| 6805 | was_open = Qt; | ||
| 6806 | } | ||
| 6807 | else | ||
| 6808 | tip_frame = Qnil; | ||
| 6809 | |||
| 6810 | return unbind_to (count, was_open); | ||
| 6811 | } | ||
| 6812 | } | ||
| 6813 | |||
| 6796 | 6814 | ||
| 6797 | DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, | 6815 | DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, |
| 6798 | doc: /* Show STRING in a \"tooltip\" window on frame FRAME. | 6816 | doc: /* Show STRING in a \"tooltip\" window on frame FRAME. |
| @@ -6826,15 +6844,16 @@ A tooltip's maximum size is specified by `x-max-tooltip-size'. | |||
| 6826 | Text larger than the specified size is clipped. */) | 6844 | Text larger than the specified size is clipped. */) |
| 6827 | (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy) | 6845 | (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy) |
| 6828 | { | 6846 | { |
| 6829 | struct frame *f; | 6847 | struct frame *f, *tip_f; |
| 6830 | struct window *w; | 6848 | struct window *w; |
| 6831 | int root_x, root_y; | 6849 | int root_x, root_y; |
| 6832 | struct buffer *old_buffer; | 6850 | struct buffer *old_buffer; |
| 6833 | struct text_pos pos; | 6851 | struct text_pos pos; |
| 6834 | int i, width, height; | 6852 | int i, width, height; |
| 6835 | bool seen_reversed_p; | ||
| 6836 | int old_windows_or_buffers_changed = windows_or_buffers_changed; | 6853 | int old_windows_or_buffers_changed = windows_or_buffers_changed; |
| 6837 | ptrdiff_t count = SPECPDL_INDEX (); | 6854 | ptrdiff_t count = SPECPDL_INDEX (); |
| 6855 | ptrdiff_t count_1; | ||
| 6856 | Lisp_Object window, size; | ||
| 6838 | 6857 | ||
| 6839 | specbind (Qinhibit_redisplay, Qt); | 6858 | specbind (Qinhibit_redisplay, Qt); |
| 6840 | 6859 | ||
| @@ -6858,91 +6877,155 @@ Text larger than the specified size is clipped. */) | |||
| 6858 | if (NILP (last_show_tip_args)) | 6877 | if (NILP (last_show_tip_args)) |
| 6859 | last_show_tip_args = Fmake_vector (make_number (3), Qnil); | 6878 | last_show_tip_args = Fmake_vector (make_number (3), Qnil); |
| 6860 | 6879 | ||
| 6861 | if (!NILP (tip_frame)) | 6880 | if (FRAMEP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame))) |
| 6862 | { | 6881 | { |
| 6863 | Lisp_Object last_string = AREF (last_show_tip_args, 0); | 6882 | Lisp_Object last_string = AREF (last_show_tip_args, 0); |
| 6864 | Lisp_Object last_frame = AREF (last_show_tip_args, 1); | 6883 | Lisp_Object last_frame = AREF (last_show_tip_args, 1); |
| 6865 | Lisp_Object last_parms = AREF (last_show_tip_args, 2); | 6884 | Lisp_Object last_parms = AREF (last_show_tip_args, 2); |
| 6866 | 6885 | ||
| 6867 | if (EQ (frame, last_frame) | 6886 | if (FRAME_VISIBLE_P (XFRAME (tip_frame)) |
| 6868 | && !NILP (Fequal (last_string, string)) | 6887 | && EQ (frame, last_frame) |
| 6888 | && !NILP (Fequal_including_properties (last_string, string)) | ||
| 6869 | && !NILP (Fequal (last_parms, parms))) | 6889 | && !NILP (Fequal (last_parms, parms))) |
| 6870 | { | 6890 | { |
| 6871 | struct frame *f = XFRAME (tip_frame); | ||
| 6872 | |||
| 6873 | /* Only DX and DY have changed. */ | 6891 | /* Only DX and DY have changed. */ |
| 6892 | tip_f = XFRAME (tip_frame); | ||
| 6874 | if (!NILP (tip_timer)) | 6893 | if (!NILP (tip_timer)) |
| 6875 | { | 6894 | { |
| 6876 | Lisp_Object timer = tip_timer; | 6895 | Lisp_Object timer = tip_timer; |
| 6896 | |||
| 6877 | tip_timer = Qnil; | 6897 | tip_timer = Qnil; |
| 6878 | call1 (Qcancel_timer, timer); | 6898 | call1 (Qcancel_timer, timer); |
| 6879 | } | 6899 | } |
| 6880 | 6900 | ||
| 6881 | block_input (); | 6901 | block_input (); |
| 6882 | compute_tip_xy (f, parms, dx, dy, FRAME_PIXEL_WIDTH (f), | 6902 | compute_tip_xy (tip_f, parms, dx, dy, FRAME_PIXEL_WIDTH (tip_f), |
| 6883 | FRAME_PIXEL_HEIGHT (f), &root_x, &root_y); | 6903 | FRAME_PIXEL_HEIGHT (tip_f), &root_x, &root_y); |
| 6884 | 6904 | ||
| 6885 | /* Put tooltip in topmost group and in position. */ | 6905 | /* Put tooltip in topmost group and in position. */ |
| 6886 | SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST, | 6906 | SetWindowPos (FRAME_W32_WINDOW (tip_f), HWND_TOPMOST, |
| 6887 | root_x, root_y, 0, 0, | 6907 | root_x, root_y, 0, 0, |
| 6888 | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER); | 6908 | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER); |
| 6889 | 6909 | ||
| 6890 | /* Ensure tooltip is on top of other topmost windows (eg menus). */ | 6910 | /* Ensure tooltip is on top of other topmost windows (eg menus). */ |
| 6891 | SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP, | 6911 | SetWindowPos (FRAME_W32_WINDOW (tip_f), HWND_TOP, |
| 6892 | 0, 0, 0, 0, | 6912 | 0, 0, 0, 0, |
| 6893 | SWP_NOMOVE | SWP_NOSIZE | 6913 | SWP_NOMOVE | SWP_NOSIZE |
| 6894 | | SWP_NOACTIVATE | SWP_NOOWNERZORDER); | 6914 | | SWP_NOACTIVATE | SWP_NOOWNERZORDER); |
| 6895 | 6915 | ||
| 6916 | /* Let redisplay know that we have made the frame visible already. */ | ||
| 6917 | SET_FRAME_VISIBLE (tip_f, 1); | ||
| 6918 | ShowWindow (FRAME_W32_WINDOW (tip_f), SW_SHOWNOACTIVATE); | ||
| 6896 | unblock_input (); | 6919 | unblock_input (); |
| 6920 | |||
| 6897 | goto start_timer; | 6921 | goto start_timer; |
| 6898 | } | 6922 | } |
| 6899 | } | 6923 | else if (tooltip_reuse_hidden_frame && EQ (frame, last_frame)) |
| 6924 | { | ||
| 6925 | bool delete = false; | ||
| 6926 | Lisp_Object tail, elt, parm, last; | ||
| 6900 | 6927 | ||
| 6901 | /* Hide a previous tip, if any. */ | 6928 | /* Check if every parameter in PARMS has the same value in |
| 6902 | Fx_hide_tip (); | 6929 | last_parms. This may destruct last_parms which, however, |
| 6930 | will be recreated below. */ | ||
| 6931 | for (tail = parms; CONSP (tail); tail = XCDR (tail)) | ||
| 6932 | { | ||
| 6933 | elt = XCAR (tail); | ||
| 6934 | parm = Fcar (elt); | ||
| 6935 | /* The left, top, right and bottom parameters are handled | ||
| 6936 | by compute_tip_xy so they can be ignored here. */ | ||
| 6937 | if (!EQ (parm, Qleft) && !EQ (parm, Qtop) | ||
| 6938 | && !EQ (parm, Qright) && !EQ (parm, Qbottom)) | ||
| 6939 | { | ||
| 6940 | last = Fassq (parm, last_parms); | ||
| 6941 | if (NILP (Fequal (Fcdr (elt), Fcdr (last)))) | ||
| 6942 | { | ||
| 6943 | /* We lost, delete the old tooltip. */ | ||
| 6944 | delete = true; | ||
| 6945 | break; | ||
| 6946 | } | ||
| 6947 | else | ||
| 6948 | last_parms = call2 (Qassq_delete_all, parm, last_parms); | ||
| 6949 | } | ||
| 6950 | else | ||
| 6951 | last_parms = call2 (Qassq_delete_all, parm, last_parms); | ||
| 6952 | } | ||
| 6953 | |||
| 6954 | /* Now check if there's a parameter left in last_parms with a | ||
| 6955 | non-nil value. */ | ||
| 6956 | for (tail = last_parms; CONSP (tail); tail = XCDR (tail)) | ||
| 6957 | { | ||
| 6958 | elt = XCAR (tail); | ||
| 6959 | parm = Fcar (elt); | ||
| 6960 | if (!EQ (parm, Qleft) && !EQ (parm, Qtop) && !EQ (parm, Qright) | ||
| 6961 | && !EQ (parm, Qbottom) && !NILP (Fcdr (elt))) | ||
| 6962 | { | ||
| 6963 | /* We lost, delete the old tooltip. */ | ||
| 6964 | delete = true; | ||
| 6965 | break; | ||
| 6966 | } | ||
| 6967 | } | ||
| 6968 | |||
| 6969 | x_hide_tip (delete); | ||
| 6970 | } | ||
| 6971 | else | ||
| 6972 | x_hide_tip (true); | ||
| 6973 | } | ||
| 6974 | else | ||
| 6975 | x_hide_tip (true); | ||
| 6903 | 6976 | ||
| 6904 | ASET (last_show_tip_args, 0, string); | 6977 | ASET (last_show_tip_args, 0, string); |
| 6905 | ASET (last_show_tip_args, 1, frame); | 6978 | ASET (last_show_tip_args, 1, frame); |
| 6906 | ASET (last_show_tip_args, 2, parms); | 6979 | ASET (last_show_tip_args, 2, parms); |
| 6907 | 6980 | ||
| 6908 | /* Add default values to frame parameters. */ | ||
| 6909 | if (NILP (Fassq (Qname, parms))) | ||
| 6910 | parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms); | ||
| 6911 | if (NILP (Fassq (Qinternal_border_width, parms))) | ||
| 6912 | parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms); | ||
| 6913 | if (NILP (Fassq (Qright_divider_width, parms))) | ||
| 6914 | parms = Fcons (Fcons (Qright_divider_width, make_number (0)), parms); | ||
| 6915 | if (NILP (Fassq (Qbottom_divider_width, parms))) | ||
| 6916 | parms = Fcons (Fcons (Qbottom_divider_width, make_number (0)), parms); | ||
| 6917 | if (NILP (Fassq (Qborder_width, parms))) | ||
| 6918 | parms = Fcons (Fcons (Qborder_width, make_number (1)), parms); | ||
| 6919 | if (NILP (Fassq (Qborder_color, parms))) | ||
| 6920 | parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms); | ||
| 6921 | if (NILP (Fassq (Qbackground_color, parms))) | ||
| 6922 | parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")), | ||
| 6923 | parms); | ||
| 6924 | |||
| 6925 | /* Block input until the tip has been fully drawn, to avoid crashes | 6981 | /* Block input until the tip has been fully drawn, to avoid crashes |
| 6926 | when drawing tips in menus. */ | 6982 | when drawing tips in menus. */ |
| 6927 | block_input (); | 6983 | block_input (); |
| 6928 | 6984 | ||
| 6929 | /* Create a frame for the tooltip, and record it in the global | 6985 | if (!FRAMEP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame))) |
| 6930 | variable tip_frame. */ | 6986 | { |
| 6931 | frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms, string); | 6987 | /* Add default values to frame parameters. */ |
| 6932 | f = XFRAME (frame); | 6988 | if (NILP (Fassq (Qname, parms))) |
| 6989 | parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms); | ||
| 6990 | if (NILP (Fassq (Qinternal_border_width, parms))) | ||
| 6991 | parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms); | ||
| 6992 | if (NILP (Fassq (Qborder_width, parms))) | ||
| 6993 | parms = Fcons (Fcons (Qborder_width, make_number (1)), parms); | ||
| 6994 | if (NILP (Fassq (Qborder_color, parms))) | ||
| 6995 | parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms); | ||
| 6996 | if (NILP (Fassq (Qbackground_color, parms))) | ||
| 6997 | parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")), | ||
| 6998 | parms); | ||
| 6999 | |||
| 7000 | /* Create a frame for the tooltip, and record it in the global | ||
| 7001 | variable tip_frame. */ | ||
| 7002 | if (NILP (tip_frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms))) | ||
| 7003 | { | ||
| 7004 | /* Creating the tip frame failed. */ | ||
| 7005 | unblock_input (); | ||
| 7006 | return unbind_to (count, Qnil); | ||
| 7007 | } | ||
| 7008 | } | ||
| 7009 | |||
| 7010 | tip_f = XFRAME (tip_frame); | ||
| 7011 | window = FRAME_ROOT_WINDOW (tip_f); | ||
| 7012 | AUTO_STRING (tip, " *tip*"); | ||
| 7013 | set_window_buffer (window, Fget_buffer_create (tip), false, false); | ||
| 7014 | w = XWINDOW (window); | ||
| 7015 | w->pseudo_window_p = true; | ||
| 6933 | 7016 | ||
| 6934 | /* Set up the frame's root window. */ | 7017 | /* Set up the frame's root window. Note: The following code does not |
| 6935 | w = XWINDOW (FRAME_ROOT_WINDOW (f)); | 7018 | try to size the window or its frame correctly. Its only purpose is |
| 7019 | to make the subsequent text size calculations work. The right | ||
| 7020 | sizes should get installed when the toolkit gets back to us. */ | ||
| 6936 | w->left_col = 0; | 7021 | w->left_col = 0; |
| 6937 | w->top_line = 0; | 7022 | w->top_line = 0; |
| 6938 | w->pixel_left = 0; | 7023 | w->pixel_left = 0; |
| 6939 | w->pixel_top = 0; | 7024 | w->pixel_top = 0; |
| 6940 | 7025 | ||
| 6941 | if (CONSP (Vx_max_tooltip_size) | 7026 | if (CONSP (Vx_max_tooltip_size) |
| 6942 | && INTEGERP (XCAR (Vx_max_tooltip_size)) | 7027 | && RANGED_INTEGERP (1, XCAR (Vx_max_tooltip_size), INT_MAX) |
| 6943 | && XINT (XCAR (Vx_max_tooltip_size)) > 0 | 7028 | && RANGED_INTEGERP (1, XCDR (Vx_max_tooltip_size), INT_MAX)) |
| 6944 | && INTEGERP (XCDR (Vx_max_tooltip_size)) | ||
| 6945 | && XINT (XCDR (Vx_max_tooltip_size)) > 0) | ||
| 6946 | { | 7029 | { |
| 6947 | w->total_cols = XFASTINT (XCAR (Vx_max_tooltip_size)); | 7030 | w->total_cols = XFASTINT (XCAR (Vx_max_tooltip_size)); |
| 6948 | w->total_lines = XFASTINT (XCDR (Vx_max_tooltip_size)); | 7031 | w->total_lines = XFASTINT (XCDR (Vx_max_tooltip_size)); |
| @@ -6953,164 +7036,71 @@ Text larger than the specified size is clipped. */) | |||
| 6953 | w->total_lines = 40; | 7036 | w->total_lines = 40; |
| 6954 | } | 7037 | } |
| 6955 | 7038 | ||
| 6956 | w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (f); | 7039 | w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (tip_f); |
| 6957 | w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (f); | 7040 | w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (tip_f); |
| 6958 | 7041 | FRAME_TOTAL_COLS (tip_f) = WINDOW_TOTAL_COLS (w); | |
| 6959 | FRAME_TOTAL_COLS (f) = WINDOW_TOTAL_COLS (w); | 7042 | adjust_frame_glyphs (tip_f); |
| 6960 | adjust_frame_glyphs (f); | ||
| 6961 | w->pseudo_window_p = true; | ||
| 6962 | 7043 | ||
| 6963 | /* Display the tooltip text in a temporary buffer. */ | 7044 | /* Insert STRING into the root window's buffer and fit the frame to |
| 7045 | the buffer. */ | ||
| 7046 | count_1 = SPECPDL_INDEX (); | ||
| 6964 | old_buffer = current_buffer; | 7047 | old_buffer = current_buffer; |
| 6965 | set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->contents)); | 7048 | set_buffer_internal_1 (XBUFFER (w->contents)); |
| 6966 | bset_truncate_lines (current_buffer, Qnil); | 7049 | bset_truncate_lines (current_buffer, Qnil); |
| 7050 | specbind (Qinhibit_read_only, Qt); | ||
| 7051 | specbind (Qinhibit_modification_hooks, Qt); | ||
| 7052 | specbind (Qinhibit_point_motion_hooks, Qt); | ||
| 7053 | Ferase_buffer (); | ||
| 7054 | Finsert (1, &string); | ||
| 6967 | clear_glyph_matrix (w->desired_matrix); | 7055 | clear_glyph_matrix (w->desired_matrix); |
| 6968 | clear_glyph_matrix (w->current_matrix); | 7056 | clear_glyph_matrix (w->current_matrix); |
| 6969 | SET_TEXT_POS (pos, BEGV, BEGV_BYTE); | 7057 | SET_TEXT_POS (pos, BEGV, BEGV_BYTE); |
| 6970 | try_window (FRAME_ROOT_WINDOW (f), pos, TRY_WINDOW_IGNORE_FONTS_CHANGE); | 7058 | try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE); |
| 6971 | 7059 | /* Calculate size of tooltip window. */ | |
| 6972 | /* Compute width and height of the tooltip. */ | 7060 | size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil, |
| 6973 | width = height = 0; | 7061 | make_number (w->pixel_height), Qnil); |
| 6974 | seen_reversed_p = false; | 7062 | /* Add the frame's internal border to calculated size. */ |
| 6975 | for (i = 0; i < w->desired_matrix->nrows; ++i) | 7063 | width = XINT (Fcar (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f); |
| 6976 | { | 7064 | height = XINT (Fcdr (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f); |
| 6977 | struct glyph_row *row = &w->desired_matrix->rows[i]; | 7065 | /* Calculate position of tooltip frame. */ |
| 6978 | struct glyph *last; | 7066 | compute_tip_xy (tip_f, parms, dx, dy, width, height, &root_x, &root_y); |
| 6979 | int row_width; | 7067 | |
| 6980 | 7068 | /* Show tooltip frame. */ | |
| 6981 | /* Stop at the first empty row at the end. */ | ||
| 6982 | if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row)) | ||
| 6983 | break; | ||
| 6984 | |||
| 6985 | /* Let the row go over the full width of the frame. */ | ||
| 6986 | row->full_width_p = true; | ||
| 6987 | |||
| 6988 | row_width = row->pixel_width; | ||
| 6989 | if (row->used[TEXT_AREA]) | ||
| 6990 | { | ||
| 6991 | if (!row->reversed_p) | ||
| 6992 | { | ||
| 6993 | /* There's a glyph at the end of rows that is used to | ||
| 6994 | place the cursor there. Don't include the width of | ||
| 6995 | this glyph. */ | ||
| 6996 | last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1]; | ||
| 6997 | if (NILP (last->object)) | ||
| 6998 | row_width -= last->pixel_width; | ||
| 6999 | } | ||
| 7000 | else | ||
| 7001 | { | ||
| 7002 | /* There could be a stretch glyph at the beginning of R2L | ||
| 7003 | rows that is produced by extend_face_to_end_of_line. | ||
| 7004 | Don't count that glyph. */ | ||
| 7005 | struct glyph *g = row->glyphs[TEXT_AREA]; | ||
| 7006 | |||
| 7007 | if (g->type == STRETCH_GLYPH && NILP (g->object)) | ||
| 7008 | { | ||
| 7009 | row_width -= g->pixel_width; | ||
| 7010 | seen_reversed_p = true; | ||
| 7011 | } | ||
| 7012 | } | ||
| 7013 | } | ||
| 7014 | |||
| 7015 | height += row->height; | ||
| 7016 | width = max (width, row_width); | ||
| 7017 | } | ||
| 7018 | |||
| 7019 | /* If we've seen partial-length R2L rows, we need to re-adjust the | ||
| 7020 | tool-tip frame width and redisplay it again, to avoid over-wide | ||
| 7021 | tips due to the stretch glyph that extends R2L lines to full | ||
| 7022 | width of the frame. */ | ||
| 7023 | if (seen_reversed_p) | ||
| 7024 | { | ||
| 7025 | /* PXW: Why do we do the pixel-to-cols conversion only if | ||
| 7026 | seen_reversed_p holds? Don't we have to set other fields of | ||
| 7027 | the window/frame structure? | ||
| 7028 | |||
| 7029 | w->total_cols and FRAME_TOTAL_COLS want the width in columns, | ||
| 7030 | not in pixels. */ | ||
| 7031 | w->pixel_width = width; | ||
| 7032 | width /= WINDOW_FRAME_COLUMN_WIDTH (w); | ||
| 7033 | w->total_cols = width; | ||
| 7034 | FRAME_TOTAL_COLS (f) = width; | ||
| 7035 | SET_FRAME_WIDTH (f, width); | ||
| 7036 | adjust_frame_glyphs (f); | ||
| 7037 | w->pseudo_window_p = 1; | ||
| 7038 | clear_glyph_matrix (w->desired_matrix); | ||
| 7039 | clear_glyph_matrix (w->current_matrix); | ||
| 7040 | try_window (FRAME_ROOT_WINDOW (f), pos, TRY_WINDOW_IGNORE_FONTS_CHANGE); | ||
| 7041 | width = height = 0; | ||
| 7042 | /* Recompute width and height of the tooltip. */ | ||
| 7043 | for (i = 0; i < w->desired_matrix->nrows; ++i) | ||
| 7044 | { | ||
| 7045 | struct glyph_row *row = &w->desired_matrix->rows[i]; | ||
| 7046 | struct glyph *last; | ||
| 7047 | int row_width; | ||
| 7048 | |||
| 7049 | if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row)) | ||
| 7050 | break; | ||
| 7051 | row->full_width_p = true; | ||
| 7052 | row_width = row->pixel_width; | ||
| 7053 | if (row->used[TEXT_AREA] && !row->reversed_p) | ||
| 7054 | { | ||
| 7055 | last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1]; | ||
| 7056 | if (NILP (last->object)) | ||
| 7057 | row_width -= last->pixel_width; | ||
| 7058 | } | ||
| 7059 | |||
| 7060 | height += row->height; | ||
| 7061 | width = max (width, row_width); | ||
| 7062 | } | ||
| 7063 | } | ||
| 7064 | |||
| 7065 | /* Add the frame's internal border to the width and height the w32 | ||
| 7066 | window should have. */ | ||
| 7067 | height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f); | ||
| 7068 | width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f); | ||
| 7069 | |||
| 7070 | /* Move the tooltip window where the mouse pointer is. Resize and | ||
| 7071 | show it. | ||
| 7072 | |||
| 7073 | PXW: This should use the frame's pixel coordinates. */ | ||
| 7074 | compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y); | ||
| 7075 | |||
| 7076 | { | 7069 | { |
| 7077 | /* Adjust Window size to take border into account. */ | ||
| 7078 | RECT rect; | 7070 | RECT rect; |
| 7071 | int pad = (NUMBERP (Vw32_tooltip_extra_pixels) | ||
| 7072 | ? max (0, XINT (Vw32_tooltip_extra_pixels)) | ||
| 7073 | : FRAME_COLUMN_WIDTH (tip_f)); | ||
| 7074 | |||
| 7079 | rect.left = rect.top = 0; | 7075 | rect.left = rect.top = 0; |
| 7080 | rect.right = width; | 7076 | rect.right = width; |
| 7081 | rect.bottom = height; | 7077 | rect.bottom = height; |
| 7082 | AdjustWindowRect (&rect, f->output_data.w32->dwStyle, false); | 7078 | AdjustWindowRect (&rect, tip_f->output_data.w32->dwStyle, |
| 7083 | 7079 | FRAME_EXTERNAL_MENU_BAR (tip_f)); | |
| 7084 | /* Position and size tooltip, and put it in the topmost group. | 7080 | |
| 7085 | The add-on of FRAME_COLUMN_WIDTH to the 5th argument is a | 7081 | /* Position and size tooltip and put it in the topmost group. */ |
| 7086 | peculiarity of w32 display: without it, some fonts cause the | 7082 | SetWindowPos (FRAME_W32_WINDOW (tip_f), HWND_TOPMOST, |
| 7087 | last character of the tip to be truncated or wrapped around to | ||
| 7088 | the next line. */ | ||
| 7089 | SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST, | ||
| 7090 | root_x, root_y, | 7083 | root_x, root_y, |
| 7091 | rect.right - rect.left + FRAME_COLUMN_WIDTH (f), | 7084 | rect.right - rect.left + pad, |
| 7092 | rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER); | 7085 | rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER); |
| 7093 | 7086 | ||
| 7094 | /* Ensure tooltip is on top of other topmost windows (eg menus). */ | 7087 | /* Ensure tooltip is on top of other topmost windows (eg menus). */ |
| 7095 | SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP, | 7088 | SetWindowPos (FRAME_W32_WINDOW (tip_f), HWND_TOP, |
| 7096 | 0, 0, 0, 0, | 7089 | 0, 0, 0, 0, |
| 7097 | SWP_NOMOVE | SWP_NOSIZE | 7090 | SWP_NOMOVE | SWP_NOSIZE |
| 7098 | | SWP_NOACTIVATE | SWP_NOOWNERZORDER); | 7091 | | SWP_NOACTIVATE | SWP_NOOWNERZORDER); |
| 7099 | 7092 | ||
| 7100 | /* Let redisplay know that we have made the frame visible already. */ | 7093 | /* Let redisplay know that we have made the frame visible already. */ |
| 7101 | SET_FRAME_VISIBLE (f, 1); | 7094 | SET_FRAME_VISIBLE (tip_f, 1); |
| 7102 | 7095 | ||
| 7103 | ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE); | 7096 | ShowWindow (FRAME_W32_WINDOW (tip_f), SW_SHOWNOACTIVATE); |
| 7104 | } | 7097 | } |
| 7105 | 7098 | ||
| 7106 | /* Draw into the window. */ | ||
| 7107 | w->must_be_updated_p = true; | 7099 | w->must_be_updated_p = true; |
| 7108 | update_single_window (w); | 7100 | update_single_window (w); |
| 7109 | |||
| 7110 | unblock_input (); | ||
| 7111 | |||
| 7112 | /* Restore original current buffer. */ | ||
| 7113 | set_buffer_internal_1 (old_buffer); | 7101 | set_buffer_internal_1 (old_buffer); |
| 7102 | unbind_to (count_1, Qnil); | ||
| 7103 | unblock_input (); | ||
| 7114 | windows_or_buffers_changed = old_windows_or_buffers_changed; | 7104 | windows_or_buffers_changed = old_windows_or_buffers_changed; |
| 7115 | 7105 | ||
| 7116 | start_timer: | 7106 | start_timer: |
| @@ -7127,31 +7117,7 @@ DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0, | |||
| 7127 | Value is t if tooltip was open, nil otherwise. */) | 7117 | Value is t if tooltip was open, nil otherwise. */) |
| 7128 | (void) | 7118 | (void) |
| 7129 | { | 7119 | { |
| 7130 | ptrdiff_t count; | 7120 | return x_hide_tip (!tooltip_reuse_hidden_frame); |
| 7131 | Lisp_Object deleted, frame, timer; | ||
| 7132 | |||
| 7133 | /* Return quickly if nothing to do. */ | ||
| 7134 | if (NILP (tip_timer) && NILP (tip_frame)) | ||
| 7135 | return Qnil; | ||
| 7136 | |||
| 7137 | frame = tip_frame; | ||
| 7138 | timer = tip_timer; | ||
| 7139 | tip_frame = tip_timer = deleted = Qnil; | ||
| 7140 | |||
| 7141 | count = SPECPDL_INDEX (); | ||
| 7142 | specbind (Qinhibit_redisplay, Qt); | ||
| 7143 | specbind (Qinhibit_quit, Qt); | ||
| 7144 | |||
| 7145 | if (!NILP (timer)) | ||
| 7146 | call1 (Qcancel_timer, timer); | ||
| 7147 | |||
| 7148 | if (FRAMEP (frame)) | ||
| 7149 | { | ||
| 7150 | delete_frame (frame, Qnil); | ||
| 7151 | deleted = Qt; | ||
| 7152 | } | ||
| 7153 | |||
| 7154 | return unbind_to (count, deleted); | ||
| 7155 | } | 7121 | } |
| 7156 | 7122 | ||
| 7157 | /*********************************************************************** | 7123 | /*********************************************************************** |
| @@ -9751,6 +9717,7 @@ syms_of_w32fns (void) | |||
| 9751 | DEFSYM (Qmm_size, "mm-size"); | 9717 | DEFSYM (Qmm_size, "mm-size"); |
| 9752 | DEFSYM (Qframes, "frames"); | 9718 | DEFSYM (Qframes, "frames"); |
| 9753 | DEFSYM (Qtip_frame, "tip-frame"); | 9719 | DEFSYM (Qtip_frame, "tip-frame"); |
| 9720 | DEFSYM (Qassq_delete_all, "assq-delete-all"); | ||
| 9754 | DEFSYM (Qunicode_sip, "unicode-sip"); | 9721 | DEFSYM (Qunicode_sip, "unicode-sip"); |
| 9755 | #if defined WINDOWSNT && !defined HAVE_DBUS | 9722 | #if defined WINDOWSNT && !defined HAVE_DBUS |
| 9756 | DEFSYM (QCicon, ":icon"); | 9723 | DEFSYM (QCicon, ":icon"); |
| @@ -10063,6 +10030,18 @@ Default is nil. | |||
| 10063 | This variable has effect only on Windows Vista and later. */); | 10030 | This variable has effect only on Windows Vista and later. */); |
| 10064 | w32_disable_new_uniscribe_apis = 0; | 10031 | w32_disable_new_uniscribe_apis = 0; |
| 10065 | 10032 | ||
| 10033 | DEFVAR_LISP ("w32-tooltip-extra-pixels", | ||
| 10034 | Vw32_tooltip_extra_pixels, | ||
| 10035 | doc: /* Number of pixels added after tooltip text. | ||
| 10036 | On Windows some fonts may cause the last character of a tooltip be | ||
| 10037 | truncated or wrapped around to the next line. Adding some extra space | ||
| 10038 | at the end of the toooltip works around this problem. | ||
| 10039 | |||
| 10040 | This variable specifies the number of pixels that shall be added. The | ||
| 10041 | default value t means to add the width of one canonical character of the | ||
| 10042 | tip frame. */); | ||
| 10043 | Vw32_tooltip_extra_pixels = Qt; | ||
| 10044 | |||
| 10066 | #if 0 /* TODO: Port to W32 */ | 10045 | #if 0 /* TODO: Port to W32 */ |
| 10067 | defsubr (&Sx_change_window_property); | 10046 | defsubr (&Sx_change_window_property); |
| 10068 | defsubr (&Sx_delete_window_property); | 10047 | defsubr (&Sx_delete_window_property); |
diff --git a/src/xdisp.c b/src/xdisp.c index b9d496ed556..5b961444384 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -9794,26 +9794,28 @@ the maximum pixel-height of all text lines. | |||
| 9794 | 9794 | ||
| 9795 | The optional argument FROM, if non-nil, specifies the first text | 9795 | The optional argument FROM, if non-nil, specifies the first text |
| 9796 | position and defaults to the minimum accessible position of the buffer. | 9796 | position and defaults to the minimum accessible position of the buffer. |
| 9797 | If FROM is t, use the minimum accessible position that is not a newline | 9797 | If FROM is t, use the minimum accessible position that starts a |
| 9798 | character. TO, if non-nil, specifies the last text position and | 9798 | non-empty line. TO, if non-nil, specifies the last text position and |
| 9799 | defaults to the maximum accessible position of the buffer. If TO is t, | 9799 | defaults to the maximum accessible position of the buffer. If TO is t, |
| 9800 | use the maximum accessible position that is not a newline character. | 9800 | use the maximum accessible position that ends a non-empty line. |
| 9801 | 9801 | ||
| 9802 | The optional argument X-LIMIT, if non-nil, specifies the maximum text | 9802 | The optional argument X-LIMIT, if non-nil, specifies the maximum text |
| 9803 | width that can be returned. X-LIMIT nil or omitted, means to use the | 9803 | width that can be returned. X-LIMIT nil or omitted, means to use the |
| 9804 | pixel-width of WINDOW's body; use this if you do not intend to change | 9804 | pixel-width of WINDOW's body; use this if you want to know how high |
| 9805 | the width of WINDOW. Use the maximum width WINDOW may assume if you | 9805 | WINDOW should be become in order to fit all of its buffer's text with |
| 9806 | intend to change WINDOW's width. In any case, text whose x-coordinate | 9806 | the width of WINDOW unaltered. Use the maximum width WINDOW may assume |
| 9807 | is beyond X-LIMIT is ignored. Since calculating the width of long lines | 9807 | if you intend to change WINDOW's width. In any case, text whose |
| 9808 | can take some time, it's always a good idea to make this argument as | 9808 | x-coordinate is beyond X-LIMIT is ignored. Since calculating the width |
| 9809 | small as possible; in particular, if the buffer contains long lines that | 9809 | of long lines can take some time, it's always a good idea to make this |
| 9810 | shall be truncated anyway. | 9810 | argument as small as possible; in particular, if the buffer contains |
| 9811 | long lines that shall be truncated anyway. | ||
| 9811 | 9812 | ||
| 9812 | The optional argument Y-LIMIT, if non-nil, specifies the maximum text | 9813 | The optional argument Y-LIMIT, if non-nil, specifies the maximum text |
| 9813 | height that can be returned. Text lines whose y-coordinate is beyond | 9814 | height (exluding the height of the mode- or header-line, if any) that |
| 9814 | Y-LIMIT are ignored. Since calculating the text height of a large | 9815 | can be returned. Text lines whose y-coordinate is beyond Y-LIMIT are |
| 9815 | buffer can take some time, it makes sense to specify this argument if | 9816 | ignored. Since calculating the text height of a large buffer can take |
| 9816 | the size of the buffer is unknown. | 9817 | some time, it makes sense to specify this argument if the size of the |
| 9818 | buffer is large or unknown. | ||
| 9817 | 9819 | ||
| 9818 | Optional argument MODE-AND-HEADER-LINE nil or omitted means do not | 9820 | Optional argument MODE-AND-HEADER-LINE nil or omitted means do not |
| 9819 | include the height of the mode- or header-line of WINDOW in the return | 9821 | include the height of the mode- or header-line of WINDOW in the return |
| @@ -9831,7 +9833,7 @@ include the height of both, if present, in the return value. */) | |||
| 9831 | ptrdiff_t start, end, pos; | 9833 | ptrdiff_t start, end, pos; |
| 9832 | struct text_pos startp; | 9834 | struct text_pos startp; |
| 9833 | void *itdata = NULL; | 9835 | void *itdata = NULL; |
| 9834 | int c, max_y = -1, x = 0, y = 0; | 9836 | int c, max_x = 0, max_y = 0, x = 0, y = 0; |
| 9835 | 9837 | ||
| 9836 | CHECK_BUFFER (buffer); | 9838 | CHECK_BUFFER (buffer); |
| 9837 | b = XBUFFER (buffer); | 9839 | b = XBUFFER (buffer); |
| @@ -9876,11 +9878,13 @@ include the height of both, if present, in the return value. */) | |||
| 9876 | end = max (start, min (XINT (to), ZV)); | 9878 | end = max (start, min (XINT (to), ZV)); |
| 9877 | } | 9879 | } |
| 9878 | 9880 | ||
| 9879 | if (!NILP (y_limit)) | 9881 | if (!NILP (x_limit) && RANGED_INTEGERP (0, x_limit, INT_MAX)) |
| 9880 | { | 9882 | max_x = XINT (x_limit); |
| 9881 | CHECK_NUMBER (y_limit); | 9883 | |
| 9882 | max_y = min (XINT (y_limit), INT_MAX); | 9884 | if (NILP (y_limit)) |
| 9883 | } | 9885 | max_y = INT_MAX; |
| 9886 | else if (RANGED_INTEGERP (0, y_limit, INT_MAX)) | ||
| 9887 | max_y = XINT (y_limit); | ||
| 9884 | 9888 | ||
| 9885 | itdata = bidi_shelve_cache (); | 9889 | itdata = bidi_shelve_cache (); |
| 9886 | SET_TEXT_POS (startp, start, CHAR_TO_BYTE (start)); | 9890 | SET_TEXT_POS (startp, start, CHAR_TO_BYTE (start)); |
| @@ -9890,27 +9894,30 @@ include the height of both, if present, in the return value. */) | |||
| 9890 | x = move_it_to (&it, end, -1, max_y, -1, MOVE_TO_POS | MOVE_TO_Y); | 9894 | x = move_it_to (&it, end, -1, max_y, -1, MOVE_TO_POS | MOVE_TO_Y); |
| 9891 | else | 9895 | else |
| 9892 | { | 9896 | { |
| 9893 | CHECK_NUMBER (x_limit); | 9897 | it.last_visible_x = max_x; |
| 9894 | it.last_visible_x = min (XINT (x_limit), INFINITY); | ||
| 9895 | /* Actually, we never want move_it_to stop at to_x. But to make | 9898 | /* Actually, we never want move_it_to stop at to_x. But to make |
| 9896 | sure that move_it_in_display_line_to always moves far enough, | 9899 | sure that move_it_in_display_line_to always moves far enough, |
| 9897 | we set it to INT_MAX and specify MOVE_TO_X. */ | 9900 | we set it to INT_MAX and specify MOVE_TO_X. Also bound width |
| 9898 | x = move_it_to (&it, end, INT_MAX, max_y, -1, | 9901 | value by X-LIMIT. */ |
| 9899 | MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y); | 9902 | x = min (move_it_to (&it, end, INT_MAX, max_y, -1, |
| 9903 | MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y), | ||
| 9904 | max_x); | ||
| 9900 | } | 9905 | } |
| 9901 | 9906 | ||
| 9902 | y = it.current_y + it.max_ascent + it.max_descent; | 9907 | /* Subtract height of header-line which was counted automatically by |
| 9908 | start_display. */ | ||
| 9909 | y = min (it.current_y + it.max_ascent + it.max_descent | ||
| 9910 | - WINDOW_HEADER_LINE_HEIGHT (w), | ||
| 9911 | max_y); | ||
| 9903 | 9912 | ||
| 9904 | if (!EQ (mode_and_header_line, Qheader_line) | 9913 | if (EQ (mode_and_header_line, Qheader_line) |
| 9905 | && !EQ (mode_and_header_line, Qt)) | 9914 | || EQ (mode_and_header_line, Qt)) |
| 9906 | /* Do not count the header-line which was counted automatically by | 9915 | /* Re-add height of header-line as requested. */ |
| 9907 | start_display. */ | 9916 | y = y + WINDOW_HEADER_LINE_HEIGHT (w); |
| 9908 | y = y - WINDOW_HEADER_LINE_HEIGHT (w); | ||
| 9909 | 9917 | ||
| 9910 | if (EQ (mode_and_header_line, Qmode_line) | 9918 | if (EQ (mode_and_header_line, Qmode_line) |
| 9911 | || EQ (mode_and_header_line, Qt)) | 9919 | || EQ (mode_and_header_line, Qt)) |
| 9912 | /* Do count the mode-line which is not included automatically by | 9920 | /* Add height of mode-line as requested. */ |
| 9913 | start_display. */ | ||
| 9914 | y = y + WINDOW_MODE_LINE_HEIGHT (w); | 9921 | y = y + WINDOW_MODE_LINE_HEIGHT (w); |
| 9915 | 9922 | ||
| 9916 | bidi_unshelve_cache (itdata, false); | 9923 | bidi_unshelve_cache (itdata, false); |
diff --git a/src/xfns.c b/src/xfns.c index 2a50a5a5f99..c1ce1b73a21 100644 --- a/src/xfns.c +++ b/src/xfns.c | |||
| @@ -5303,8 +5303,6 @@ no value of TYPE (always string in the MS Windows case). */) | |||
| 5303 | Tool tips | 5303 | Tool tips |
| 5304 | ***********************************************************************/ | 5304 | ***********************************************************************/ |
| 5305 | 5305 | ||
| 5306 | static Lisp_Object x_create_tip_frame (struct x_display_info *, | ||
| 5307 | Lisp_Object, Lisp_Object); | ||
| 5308 | static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, | 5306 | static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, |
| 5309 | Lisp_Object, int, int, int *, int *); | 5307 | Lisp_Object, int, int, int *, int *); |
| 5310 | 5308 | ||
| @@ -5348,9 +5346,7 @@ unwind_create_tip_frame (Lisp_Object frame) | |||
| 5348 | when this happens. */ | 5346 | when this happens. */ |
| 5349 | 5347 | ||
| 5350 | static Lisp_Object | 5348 | static Lisp_Object |
| 5351 | x_create_tip_frame (struct x_display_info *dpyinfo, | 5349 | x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms) |
| 5352 | Lisp_Object parms, | ||
| 5353 | Lisp_Object text) | ||
| 5354 | { | 5350 | { |
| 5355 | struct frame *f; | 5351 | struct frame *f; |
| 5356 | Lisp_Object frame; | 5352 | Lisp_Object frame; |
| @@ -5359,7 +5355,6 @@ x_create_tip_frame (struct x_display_info *dpyinfo, | |||
| 5359 | ptrdiff_t count = SPECPDL_INDEX (); | 5355 | ptrdiff_t count = SPECPDL_INDEX (); |
| 5360 | bool face_change_before = face_change; | 5356 | bool face_change_before = face_change; |
| 5361 | Lisp_Object buffer; | 5357 | Lisp_Object buffer; |
| 5362 | struct buffer *old_buffer; | ||
| 5363 | int x_width = 0, x_height = 0; | 5358 | int x_width = 0, x_height = 0; |
| 5364 | 5359 | ||
| 5365 | if (!dpyinfo->terminal->name) | 5360 | if (!dpyinfo->terminal->name) |
| @@ -5375,23 +5370,9 @@ x_create_tip_frame (struct x_display_info *dpyinfo, | |||
| 5375 | error ("Invalid frame name--not a string or nil"); | 5370 | error ("Invalid frame name--not a string or nil"); |
| 5376 | 5371 | ||
| 5377 | frame = Qnil; | 5372 | frame = Qnil; |
| 5378 | f = make_frame (true); | 5373 | f = make_frame (false); |
| 5374 | f->wants_modeline = false; | ||
| 5379 | XSETFRAME (frame, f); | 5375 | XSETFRAME (frame, f); |
| 5380 | |||
| 5381 | AUTO_STRING (tip, " *tip*"); | ||
| 5382 | buffer = Fget_buffer_create (tip); | ||
| 5383 | /* Use set_window_buffer instead of Fset_window_buffer (see | ||
| 5384 | discussion of bug#11984, bug#12025, bug#12026). */ | ||
| 5385 | set_window_buffer (FRAME_ROOT_WINDOW (f), buffer, false, false); | ||
| 5386 | old_buffer = current_buffer; | ||
| 5387 | set_buffer_internal_1 (XBUFFER (buffer)); | ||
| 5388 | bset_truncate_lines (current_buffer, Qnil); | ||
| 5389 | specbind (Qinhibit_read_only, Qt); | ||
| 5390 | specbind (Qinhibit_modification_hooks, Qt); | ||
| 5391 | Ferase_buffer (); | ||
| 5392 | Finsert (1, &text); | ||
| 5393 | set_buffer_internal_1 (old_buffer); | ||
| 5394 | |||
| 5395 | record_unwind_protect (unwind_create_tip_frame, frame); | 5376 | record_unwind_protect (unwind_create_tip_frame, frame); |
| 5396 | 5377 | ||
| 5397 | f->terminal = dpyinfo->terminal; | 5378 | f->terminal = dpyinfo->terminal; |
| @@ -5633,8 +5614,6 @@ x_create_tip_frame (struct x_display_info *dpyinfo, | |||
| 5633 | { | 5614 | { |
| 5634 | Lisp_Object bg = Fframe_parameter (frame, Qbackground_color); | 5615 | Lisp_Object bg = Fframe_parameter (frame, Qbackground_color); |
| 5635 | 5616 | ||
| 5636 | /* Set tip_frame here, so that */ | ||
| 5637 | tip_frame = frame; | ||
| 5638 | call2 (Qface_set_after_frame_default, frame, Qnil); | 5617 | call2 (Qface_set_after_frame_default, frame, Qnil); |
| 5639 | 5618 | ||
| 5640 | if (!EQ (bg, Fframe_parameter (frame, Qbackground_color))) | 5619 | if (!EQ (bg, Fframe_parameter (frame, Qbackground_color))) |
| @@ -5773,6 +5752,85 @@ compute_tip_xy (struct frame *f, Lisp_Object parms, Lisp_Object dx, Lisp_Object | |||
| 5773 | } | 5752 | } |
| 5774 | 5753 | ||
| 5775 | 5754 | ||
| 5755 | /* Hide tooltip. Delete its frame if DELETE is true. */ | ||
| 5756 | static Lisp_Object | ||
| 5757 | x_hide_tip (bool delete) | ||
| 5758 | { | ||
| 5759 | if (!NILP (tip_timer)) | ||
| 5760 | { | ||
| 5761 | call1 (Qcancel_timer, tip_timer); | ||
| 5762 | tip_timer = Qnil; | ||
| 5763 | } | ||
| 5764 | |||
| 5765 | |||
| 5766 | if (NILP (tip_frame) | ||
| 5767 | || (!delete && FRAMEP (tip_frame) | ||
| 5768 | && !FRAME_VISIBLE_P (XFRAME (tip_frame)))) | ||
| 5769 | return Qnil; | ||
| 5770 | else | ||
| 5771 | { | ||
| 5772 | ptrdiff_t count; | ||
| 5773 | Lisp_Object was_open = Qnil; | ||
| 5774 | |||
| 5775 | count = SPECPDL_INDEX (); | ||
| 5776 | specbind (Qinhibit_redisplay, Qt); | ||
| 5777 | specbind (Qinhibit_quit, Qt); | ||
| 5778 | |||
| 5779 | #ifdef USE_GTK | ||
| 5780 | { | ||
| 5781 | /* When using system tooltip, tip_frame is the Emacs frame on | ||
| 5782 | which the tip is shown. */ | ||
| 5783 | struct frame *f = XFRAME (tip_frame); | ||
| 5784 | |||
| 5785 | if (FRAME_LIVE_P (f) && xg_hide_tooltip (f)) | ||
| 5786 | { | ||
| 5787 | tip_frame = Qnil; | ||
| 5788 | was_open = Qt; | ||
| 5789 | } | ||
| 5790 | } | ||
| 5791 | #endif | ||
| 5792 | |||
| 5793 | if (FRAMEP (tip_frame)) | ||
| 5794 | { | ||
| 5795 | if (delete) | ||
| 5796 | { | ||
| 5797 | delete_frame (tip_frame, Qnil); | ||
| 5798 | tip_frame = Qnil; | ||
| 5799 | } | ||
| 5800 | else | ||
| 5801 | x_make_frame_invisible (XFRAME (tip_frame)); | ||
| 5802 | |||
| 5803 | was_open = Qt; | ||
| 5804 | |||
| 5805 | #ifdef USE_LUCID | ||
| 5806 | /* Bloodcurdling hack alert: The Lucid menu bar widget's | ||
| 5807 | redisplay procedure is not called when a tip frame over | ||
| 5808 | menu items is unmapped. Redisplay the menu manually... */ | ||
| 5809 | { | ||
| 5810 | Widget w; | ||
| 5811 | struct frame *f = SELECTED_FRAME (); | ||
| 5812 | if (FRAME_X_P (f) && FRAME_LIVE_P (f)) | ||
| 5813 | { | ||
| 5814 | w = f->output_data.x->menubar_widget; | ||
| 5815 | |||
| 5816 | if (!DoesSaveUnders (FRAME_DISPLAY_INFO (f)->screen) | ||
| 5817 | && w != NULL) | ||
| 5818 | { | ||
| 5819 | block_input (); | ||
| 5820 | xlwmenu_redisplay (w); | ||
| 5821 | unblock_input (); | ||
| 5822 | } | ||
| 5823 | } | ||
| 5824 | } | ||
| 5825 | #endif /* USE_LUCID */ | ||
| 5826 | } | ||
| 5827 | else | ||
| 5828 | tip_frame = Qnil; | ||
| 5829 | |||
| 5830 | return unbind_to (count, was_open); | ||
| 5831 | } | ||
| 5832 | } | ||
| 5833 | |||
| 5776 | DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, | 5834 | DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, |
| 5777 | doc: /* Show STRING in a "tooltip" window on frame FRAME. | 5835 | doc: /* Show STRING in a "tooltip" window on frame FRAME. |
| 5778 | A tooltip window is a small X window displaying a string. | 5836 | A tooltip window is a small X window displaying a string. |
| @@ -5805,15 +5863,16 @@ A tooltip's maximum size is specified by `x-max-tooltip-size'. | |||
| 5805 | Text larger than the specified size is clipped. */) | 5863 | Text larger than the specified size is clipped. */) |
| 5806 | (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy) | 5864 | (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy) |
| 5807 | { | 5865 | { |
| 5808 | struct frame *f; | 5866 | struct frame *f, *tip_f; |
| 5809 | struct window *w; | 5867 | struct window *w; |
| 5810 | int root_x, root_y; | 5868 | int root_x, root_y; |
| 5811 | struct buffer *old_buffer; | 5869 | struct buffer *old_buffer; |
| 5812 | struct text_pos pos; | 5870 | struct text_pos pos; |
| 5813 | int i, width, height; | 5871 | int width, height; |
| 5814 | bool seen_reversed_p; | ||
| 5815 | int old_windows_or_buffers_changed = windows_or_buffers_changed; | 5872 | int old_windows_or_buffers_changed = windows_or_buffers_changed; |
| 5816 | ptrdiff_t count = SPECPDL_INDEX (); | 5873 | ptrdiff_t count = SPECPDL_INDEX (); |
| 5874 | ptrdiff_t count_1; | ||
| 5875 | Lisp_Object window, size; | ||
| 5817 | 5876 | ||
| 5818 | specbind (Qinhibit_redisplay, Qt); | 5877 | specbind (Qinhibit_redisplay, Qt); |
| 5819 | 5878 | ||
| @@ -5862,22 +5921,23 @@ Text larger than the specified size is clipped. */) | |||
| 5862 | if (NILP (last_show_tip_args)) | 5921 | if (NILP (last_show_tip_args)) |
| 5863 | last_show_tip_args = Fmake_vector (make_number (3), Qnil); | 5922 | last_show_tip_args = Fmake_vector (make_number (3), Qnil); |
| 5864 | 5923 | ||
| 5865 | if (!NILP (tip_frame)) | 5924 | if (FRAMEP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame))) |
| 5866 | { | 5925 | { |
| 5867 | Lisp_Object last_string = AREF (last_show_tip_args, 0); | 5926 | Lisp_Object last_string = AREF (last_show_tip_args, 0); |
| 5868 | Lisp_Object last_frame = AREF (last_show_tip_args, 1); | 5927 | Lisp_Object last_frame = AREF (last_show_tip_args, 1); |
| 5869 | Lisp_Object last_parms = AREF (last_show_tip_args, 2); | 5928 | Lisp_Object last_parms = AREF (last_show_tip_args, 2); |
| 5870 | 5929 | ||
| 5871 | if (EQ (frame, last_frame) | 5930 | if (FRAME_VISIBLE_P (XFRAME (tip_frame)) |
| 5872 | && !NILP (Fequal (last_string, string)) | 5931 | && EQ (frame, last_frame) |
| 5932 | && !NILP (Fequal_including_properties (last_string, string)) | ||
| 5873 | && !NILP (Fequal (last_parms, parms))) | 5933 | && !NILP (Fequal (last_parms, parms))) |
| 5874 | { | 5934 | { |
| 5875 | struct frame *tip_f = XFRAME (tip_frame); | ||
| 5876 | |||
| 5877 | /* Only DX and DY have changed. */ | 5935 | /* Only DX and DY have changed. */ |
| 5936 | tip_f = XFRAME (tip_frame); | ||
| 5878 | if (!NILP (tip_timer)) | 5937 | if (!NILP (tip_timer)) |
| 5879 | { | 5938 | { |
| 5880 | Lisp_Object timer = tip_timer; | 5939 | Lisp_Object timer = tip_timer; |
| 5940 | |||
| 5881 | tip_timer = Qnil; | 5941 | tip_timer = Qnil; |
| 5882 | call1 (Qcancel_timer, timer); | 5942 | call1 (Qcancel_timer, timer); |
| 5883 | } | 5943 | } |
| @@ -5888,41 +5948,103 @@ Text larger than the specified size is clipped. */) | |||
| 5888 | XMoveWindow (FRAME_X_DISPLAY (tip_f), FRAME_X_WINDOW (tip_f), | 5948 | XMoveWindow (FRAME_X_DISPLAY (tip_f), FRAME_X_WINDOW (tip_f), |
| 5889 | root_x, root_y); | 5949 | root_x, root_y); |
| 5890 | unblock_input (); | 5950 | unblock_input (); |
| 5951 | |||
| 5891 | goto start_timer; | 5952 | goto start_timer; |
| 5892 | } | 5953 | } |
| 5893 | } | 5954 | else if (tooltip_reuse_hidden_frame && EQ (frame, last_frame)) |
| 5955 | { | ||
| 5956 | bool delete = false; | ||
| 5957 | Lisp_Object tail, elt, parm, last; | ||
| 5958 | |||
| 5959 | /* Check if every parameter in PARMS has the same value in | ||
| 5960 | last_parms unless it should be ignored by means of | ||
| 5961 | Vtooltip_reuse_hidden_frame_parameters. This may destruct | ||
| 5962 | last_parms which, however, will be recreated below. */ | ||
| 5963 | for (tail = parms; CONSP (tail); tail = XCDR (tail)) | ||
| 5964 | { | ||
| 5965 | elt = XCAR (tail); | ||
| 5966 | parm = Fcar (elt); | ||
| 5967 | /* The left, top, right and bottom parameters are handled | ||
| 5968 | by compute_tip_xy so they can be ignored here. */ | ||
| 5969 | if (!EQ (parm, Qleft) && !EQ (parm, Qtop) | ||
| 5970 | && !EQ (parm, Qright) && !EQ (parm, Qbottom)) | ||
| 5971 | { | ||
| 5972 | last = Fassq (parm, last_parms); | ||
| 5973 | if (NILP (Fequal (Fcdr (elt), Fcdr (last)))) | ||
| 5974 | { | ||
| 5975 | /* We lost, delete the old tooltip. */ | ||
| 5976 | delete = true; | ||
| 5977 | break; | ||
| 5978 | } | ||
| 5979 | else | ||
| 5980 | last_parms = call2 (Qassq_delete_all, parm, last_parms); | ||
| 5981 | } | ||
| 5982 | else | ||
| 5983 | last_parms = call2 (Qassq_delete_all, parm, last_parms); | ||
| 5984 | } | ||
| 5894 | 5985 | ||
| 5895 | /* Hide a previous tip, if any. */ | 5986 | /* Now check if every parameter in what is left of last_parms |
| 5896 | Fx_hide_tip (); | 5987 | with a non-nil value has an association in PARMS unless it |
| 5988 | should be ignored by means of | ||
| 5989 | Vtooltip_reuse_hidden_frame_parameters. */ | ||
| 5990 | for (tail = last_parms; CONSP (tail); tail = XCDR (tail)) | ||
| 5991 | { | ||
| 5992 | elt = XCAR (tail); | ||
| 5993 | parm = Fcar (elt); | ||
| 5994 | if (!EQ (parm, Qleft) && !EQ (parm, Qtop) && !EQ (parm, Qright) | ||
| 5995 | && !EQ (parm, Qbottom) && !NILP (Fcdr (elt))) | ||
| 5996 | { | ||
| 5997 | /* We lost, delete the old tooltip. */ | ||
| 5998 | delete = true; | ||
| 5999 | break; | ||
| 6000 | } | ||
| 6001 | } | ||
| 6002 | |||
| 6003 | x_hide_tip (delete); | ||
| 6004 | } | ||
| 6005 | else | ||
| 6006 | x_hide_tip (true); | ||
| 6007 | } | ||
| 6008 | else | ||
| 6009 | x_hide_tip (true); | ||
| 5897 | 6010 | ||
| 5898 | ASET (last_show_tip_args, 0, string); | 6011 | ASET (last_show_tip_args, 0, string); |
| 5899 | ASET (last_show_tip_args, 1, frame); | 6012 | ASET (last_show_tip_args, 1, frame); |
| 5900 | ASET (last_show_tip_args, 2, parms); | 6013 | ASET (last_show_tip_args, 2, parms); |
| 5901 | 6014 | ||
| 5902 | /* Add default values to frame parameters. */ | 6015 | if (!FRAMEP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame))) |
| 5903 | if (NILP (Fassq (Qname, parms))) | 6016 | { |
| 5904 | parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms); | 6017 | /* Add default values to frame parameters. */ |
| 5905 | if (NILP (Fassq (Qinternal_border_width, parms))) | 6018 | if (NILP (Fassq (Qname, parms))) |
| 5906 | parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms); | 6019 | parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms); |
| 5907 | if (NILP (Fassq (Qborder_width, parms))) | 6020 | if (NILP (Fassq (Qinternal_border_width, parms))) |
| 5908 | parms = Fcons (Fcons (Qborder_width, make_number (1)), parms); | 6021 | parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms); |
| 5909 | if (NILP (Fassq (Qbottom_divider_width, parms))) | 6022 | if (NILP (Fassq (Qborder_width, parms))) |
| 5910 | parms = Fcons (Fcons (Qbottom_divider_width, make_number (0)), parms); | 6023 | parms = Fcons (Fcons (Qborder_width, make_number (1)), parms); |
| 5911 | if (NILP (Fassq (Qright_divider_width, parms))) | 6024 | if (NILP (Fassq (Qborder_color, parms))) |
| 5912 | parms = Fcons (Fcons (Qright_divider_width, make_number (0)), parms); | 6025 | parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms); |
| 5913 | if (NILP (Fassq (Qborder_color, parms))) | 6026 | if (NILP (Fassq (Qbackground_color, parms))) |
| 5914 | parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms); | 6027 | parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")), |
| 5915 | if (NILP (Fassq (Qbackground_color, parms))) | 6028 | parms); |
| 5916 | parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")), | 6029 | |
| 5917 | parms); | 6030 | /* Create a frame for the tooltip, and record it in the global |
| 5918 | 6031 | variable tip_frame. */ | |
| 5919 | /* Create a frame for the tooltip, and record it in the global | 6032 | if (NILP (tip_frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms))) |
| 5920 | variable tip_frame. */ | 6033 | /* Creating the tip frame failed. */ |
| 5921 | frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms, string); | 6034 | return unbind_to (count, Qnil); |
| 5922 | f = XFRAME (frame); | 6035 | } |
| 5923 | 6036 | ||
| 5924 | /* Set up the frame's root window. */ | 6037 | tip_f = XFRAME (tip_frame); |
| 5925 | w = XWINDOW (FRAME_ROOT_WINDOW (f)); | 6038 | window = FRAME_ROOT_WINDOW (tip_f); |
| 6039 | AUTO_STRING (tip, " *tip*"); | ||
| 6040 | set_window_buffer (window, Fget_buffer_create (tip), false, false); | ||
| 6041 | w = XWINDOW (window); | ||
| 6042 | w->pseudo_window_p = true; | ||
| 6043 | |||
| 6044 | /* Set up the frame's root window. Note: The following code does not | ||
| 6045 | try to size the window or its frame correctly. Its only purpose is | ||
| 6046 | to make the subsequent text size calculations work. The right | ||
| 6047 | sizes should get installed when the toolkit gets back to us. */ | ||
| 5926 | w->left_col = 0; | 6048 | w->left_col = 0; |
| 5927 | w->top_line = 0; | 6049 | w->top_line = 0; |
| 5928 | w->pixel_left = 0; | 6050 | w->pixel_left = 0; |
| @@ -5941,130 +6063,47 @@ Text larger than the specified size is clipped. */) | |||
| 5941 | w->total_lines = 40; | 6063 | w->total_lines = 40; |
| 5942 | } | 6064 | } |
| 5943 | 6065 | ||
| 5944 | w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (f); | 6066 | w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (tip_f); |
| 5945 | w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (f); | 6067 | w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (tip_f); |
| 5946 | 6068 | FRAME_TOTAL_COLS (tip_f) = w->total_cols; | |
| 5947 | FRAME_TOTAL_COLS (f) = w->total_cols; | 6069 | adjust_frame_glyphs (tip_f); |
| 5948 | adjust_frame_glyphs (f); | ||
| 5949 | w->pseudo_window_p = true; | ||
| 5950 | 6070 | ||
| 5951 | /* Display the tooltip text in a temporary buffer. */ | 6071 | /* Insert STRING into root window's buffer and fit the frame to the |
| 6072 | buffer. */ | ||
| 6073 | count_1 = SPECPDL_INDEX (); | ||
| 5952 | old_buffer = current_buffer; | 6074 | old_buffer = current_buffer; |
| 5953 | set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->contents)); | 6075 | set_buffer_internal_1 (XBUFFER (w->contents)); |
| 5954 | bset_truncate_lines (current_buffer, Qnil); | 6076 | bset_truncate_lines (current_buffer, Qnil); |
| 6077 | specbind (Qinhibit_read_only, Qt); | ||
| 6078 | specbind (Qinhibit_modification_hooks, Qt); | ||
| 6079 | specbind (Qinhibit_point_motion_hooks, Qt); | ||
| 6080 | Ferase_buffer (); | ||
| 6081 | Finsert (1, &string); | ||
| 5955 | clear_glyph_matrix (w->desired_matrix); | 6082 | clear_glyph_matrix (w->desired_matrix); |
| 5956 | clear_glyph_matrix (w->current_matrix); | 6083 | clear_glyph_matrix (w->current_matrix); |
| 5957 | SET_TEXT_POS (pos, BEGV, BEGV_BYTE); | 6084 | SET_TEXT_POS (pos, BEGV, BEGV_BYTE); |
| 5958 | try_window (FRAME_ROOT_WINDOW (f), pos, TRY_WINDOW_IGNORE_FONTS_CHANGE); | 6085 | try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE); |
| 5959 | 6086 | /* Calculate size of tooltip window. */ | |
| 5960 | /* Compute width and height of the tooltip. */ | 6087 | size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil, |
| 5961 | width = height = 0; | 6088 | make_number (w->pixel_height), Qnil); |
| 5962 | seen_reversed_p = false; | 6089 | /* Add the frame's internal border to calculated size. */ |
| 5963 | for (i = 0; i < w->desired_matrix->nrows; ++i) | 6090 | width = XINT (Fcar (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f); |
| 5964 | { | 6091 | height = XINT (Fcdr (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f); |
| 5965 | struct glyph_row *row = &w->desired_matrix->rows[i]; | 6092 | |
| 5966 | struct glyph *last; | 6093 | /* Calculate position of tooltip frame. */ |
| 5967 | int row_width; | 6094 | compute_tip_xy (tip_f, parms, dx, dy, width, height, &root_x, &root_y); |
| 5968 | 6095 | ||
| 5969 | /* Stop at the first empty row at the end. */ | 6096 | /* Show tooltip frame. */ |
| 5970 | if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row)) | ||
| 5971 | break; | ||
| 5972 | |||
| 5973 | /* Let the row go over the full width of the frame. */ | ||
| 5974 | row->full_width_p = true; | ||
| 5975 | |||
| 5976 | row_width = row->pixel_width; | ||
| 5977 | if (row->used[TEXT_AREA]) | ||
| 5978 | { | ||
| 5979 | /* There's a glyph at the end of rows that is used to place | ||
| 5980 | the cursor there. Don't include the width of this glyph. */ | ||
| 5981 | if (!row->reversed_p) | ||
| 5982 | { | ||
| 5983 | last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1]; | ||
| 5984 | if (NILP (last->object)) | ||
| 5985 | row_width -= last->pixel_width; | ||
| 5986 | } | ||
| 5987 | else | ||
| 5988 | { | ||
| 5989 | /* There could be a stretch glyph at the beginning of R2L | ||
| 5990 | rows that is produced by extend_face_to_end_of_line. | ||
| 5991 | Don't count that glyph. */ | ||
| 5992 | struct glyph *g = row->glyphs[TEXT_AREA]; | ||
| 5993 | |||
| 5994 | if (g->type == STRETCH_GLYPH && NILP (g->object)) | ||
| 5995 | { | ||
| 5996 | row_width -= g->pixel_width; | ||
| 5997 | seen_reversed_p = true; | ||
| 5998 | } | ||
| 5999 | } | ||
| 6000 | } | ||
| 6001 | |||
| 6002 | height += row->height; | ||
| 6003 | width = max (width, row_width); | ||
| 6004 | } | ||
| 6005 | |||
| 6006 | /* If we've seen partial-length R2L rows, we need to re-adjust the | ||
| 6007 | tool-tip frame width and redisplay it again, to avoid over-wide | ||
| 6008 | tips due to the stretch glyph that extends R2L lines to full | ||
| 6009 | width of the frame. */ | ||
| 6010 | if (seen_reversed_p) | ||
| 6011 | { | ||
| 6012 | /* w->total_cols and FRAME_TOTAL_COLS want the width in columns, | ||
| 6013 | not in pixels. */ | ||
| 6014 | w->pixel_width = width; | ||
| 6015 | width /= WINDOW_FRAME_COLUMN_WIDTH (w); | ||
| 6016 | w->total_cols = width; | ||
| 6017 | FRAME_TOTAL_COLS (f) = width; | ||
| 6018 | SET_FRAME_WIDTH (f, width); | ||
| 6019 | adjust_frame_glyphs (f); | ||
| 6020 | clear_glyph_matrix (w->desired_matrix); | ||
| 6021 | clear_glyph_matrix (w->current_matrix); | ||
| 6022 | try_window (FRAME_ROOT_WINDOW (f), pos, 0); | ||
| 6023 | width = height = 0; | ||
| 6024 | /* Recompute width and height of the tooltip. */ | ||
| 6025 | for (i = 0; i < w->desired_matrix->nrows; ++i) | ||
| 6026 | { | ||
| 6027 | struct glyph_row *row = &w->desired_matrix->rows[i]; | ||
| 6028 | struct glyph *last; | ||
| 6029 | int row_width; | ||
| 6030 | |||
| 6031 | if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row)) | ||
| 6032 | break; | ||
| 6033 | row->full_width_p = true; | ||
| 6034 | row_width = row->pixel_width; | ||
| 6035 | if (row->used[TEXT_AREA] && !row->reversed_p) | ||
| 6036 | { | ||
| 6037 | last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1]; | ||
| 6038 | if (NILP (last->object)) | ||
| 6039 | row_width -= last->pixel_width; | ||
| 6040 | } | ||
| 6041 | |||
| 6042 | height += row->height; | ||
| 6043 | width = max (width, row_width); | ||
| 6044 | } | ||
| 6045 | } | ||
| 6046 | |||
| 6047 | /* Add the frame's internal border to the width and height the X | ||
| 6048 | window should have. */ | ||
| 6049 | height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f); | ||
| 6050 | width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f); | ||
| 6051 | |||
| 6052 | /* Move the tooltip window where the mouse pointer is. Resize and | ||
| 6053 | show it. */ | ||
| 6054 | compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y); | ||
| 6055 | |||
| 6056 | block_input (); | 6097 | block_input (); |
| 6057 | XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | 6098 | XMoveResizeWindow (FRAME_X_DISPLAY (tip_f), FRAME_X_WINDOW (tip_f), |
| 6058 | root_x, root_y, width, height); | 6099 | root_x, root_y, width, height); |
| 6059 | XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); | 6100 | XMapRaised (FRAME_X_DISPLAY (tip_f), FRAME_X_WINDOW (tip_f)); |
| 6060 | unblock_input (); | 6101 | unblock_input (); |
| 6061 | 6102 | ||
| 6062 | /* Draw into the window. */ | ||
| 6063 | w->must_be_updated_p = true; | 6103 | w->must_be_updated_p = true; |
| 6064 | update_single_window (w); | 6104 | update_single_window (w); |
| 6065 | |||
| 6066 | /* Restore original current buffer. */ | ||
| 6067 | set_buffer_internal_1 (old_buffer); | 6105 | set_buffer_internal_1 (old_buffer); |
| 6106 | unbind_to (count_1, Qnil); | ||
| 6068 | windows_or_buffers_changed = old_windows_or_buffers_changed; | 6107 | windows_or_buffers_changed = old_windows_or_buffers_changed; |
| 6069 | 6108 | ||
| 6070 | start_timer: | 6109 | start_timer: |
| @@ -6081,66 +6120,9 @@ DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0, | |||
| 6081 | Value is t if tooltip was open, nil otherwise. */) | 6120 | Value is t if tooltip was open, nil otherwise. */) |
| 6082 | (void) | 6121 | (void) |
| 6083 | { | 6122 | { |
| 6084 | ptrdiff_t count; | 6123 | return x_hide_tip (!tooltip_reuse_hidden_frame); |
| 6085 | Lisp_Object deleted, frame, timer; | ||
| 6086 | |||
| 6087 | /* Return quickly if nothing to do. */ | ||
| 6088 | if (NILP (tip_timer) && NILP (tip_frame)) | ||
| 6089 | return Qnil; | ||
| 6090 | |||
| 6091 | frame = tip_frame; | ||
| 6092 | timer = tip_timer; | ||
| 6093 | tip_frame = tip_timer = deleted = Qnil; | ||
| 6094 | |||
| 6095 | count = SPECPDL_INDEX (); | ||
| 6096 | specbind (Qinhibit_redisplay, Qt); | ||
| 6097 | specbind (Qinhibit_quit, Qt); | ||
| 6098 | |||
| 6099 | if (!NILP (timer)) | ||
| 6100 | call1 (Qcancel_timer, timer); | ||
| 6101 | |||
| 6102 | #ifdef USE_GTK | ||
| 6103 | { | ||
| 6104 | /* When using system tooltip, tip_frame is the Emacs frame on which | ||
| 6105 | the tip is shown. */ | ||
| 6106 | struct frame *f = XFRAME (frame); | ||
| 6107 | if (FRAME_LIVE_P (f) && xg_hide_tooltip (f)) | ||
| 6108 | frame = Qnil; | ||
| 6109 | } | ||
| 6110 | #endif | ||
| 6111 | |||
| 6112 | if (FRAMEP (frame)) | ||
| 6113 | { | ||
| 6114 | delete_frame (frame, Qnil); | ||
| 6115 | deleted = Qt; | ||
| 6116 | |||
| 6117 | #ifdef USE_LUCID | ||
| 6118 | /* Bloodcurdling hack alert: The Lucid menu bar widget's | ||
| 6119 | redisplay procedure is not called when a tip frame over menu | ||
| 6120 | items is unmapped. Redisplay the menu manually... */ | ||
| 6121 | { | ||
| 6122 | Widget w; | ||
| 6123 | struct frame *f = SELECTED_FRAME (); | ||
| 6124 | if (FRAME_X_P (f) && FRAME_LIVE_P (f)) | ||
| 6125 | { | ||
| 6126 | w = f->output_data.x->menubar_widget; | ||
| 6127 | |||
| 6128 | if (!DoesSaveUnders (FRAME_DISPLAY_INFO (f)->screen) | ||
| 6129 | && w != NULL) | ||
| 6130 | { | ||
| 6131 | block_input (); | ||
| 6132 | xlwmenu_redisplay (w); | ||
| 6133 | unblock_input (); | ||
| 6134 | } | ||
| 6135 | } | ||
| 6136 | } | ||
| 6137 | #endif /* USE_LUCID */ | ||
| 6138 | } | ||
| 6139 | |||
| 6140 | return unbind_to (count, deleted); | ||
| 6141 | } | 6124 | } |
| 6142 | 6125 | ||
| 6143 | |||
| 6144 | 6126 | ||
| 6145 | /*********************************************************************** | 6127 | /*********************************************************************** |
| 6146 | File selection dialog | 6128 | File selection dialog |
| @@ -6802,6 +6784,7 @@ syms_of_xfns (void) | |||
| 6802 | DEFSYM (Qcancel_timer, "cancel-timer"); | 6784 | DEFSYM (Qcancel_timer, "cancel-timer"); |
| 6803 | DEFSYM (Qfont_param, "font-parameter"); | 6785 | DEFSYM (Qfont_param, "font-parameter"); |
| 6804 | DEFSYM (Qmono, "mono"); | 6786 | DEFSYM (Qmono, "mono"); |
| 6787 | DEFSYM (Qassq_delete_all, "assq-delete-all"); | ||
| 6805 | 6788 | ||
| 6806 | #ifdef USE_CAIRO | 6789 | #ifdef USE_CAIRO |
| 6807 | DEFSYM (Qpdf, "pdf"); | 6790 | DEFSYM (Qpdf, "pdf"); |