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.
This commit is contained in:
Martin Rudalics 2016-03-08 08:51:38 +01:00
parent 59c7a5d711
commit 80864c2a04
5 changed files with 470 additions and 485 deletions

View file

@ -311,6 +311,7 @@ Leaving \"Default\" unchecked is equivalent with specifying a default of
(const :tag "Always" t)
(repeat (symbol :tag "Parameter")))
"25.1")
(tooltip-reuse-hidden-frame tooltip boolean "26.1")
;; fringe.c
(overflow-newline-into-fringe fringe boolean)
;; image.c

View file

@ -5262,6 +5262,21 @@ The function `frame--size-history' displays the value of this variable
in a more readable form. */);
frame_size_history = Qnil;
DEFVAR_BOOL ("tooltip-reuse-hidden-frame", tooltip_reuse_hidden_frame,
doc: /* Non-nil means reuse hidden tooltip frames.
When this is nil, delete a tooltip frame when hiding the associated
tooltip. When this is non-nil, make the tooltip frame invisible only,
so it can be reused when the next tooltip is shown.
Setting this to non-nil may drastically reduce the consing overhead
incurred by creating new tooltip frames. However, a value of non-nil
means also that intermittent changes of faces or `default-frame-alist'
are not applied when showing a tooltip in a reused frame.
This variable is effective only with the X toolkit (and there only when
Gtk+ tooltips are not used) and on Windows. */);
tooltip_reuse_hidden_frame = false;
staticpro (&Vframe_list);
defsubr (&Sframep);

View file

@ -6422,8 +6422,6 @@ no value of TYPE (always string in the MS Windows case). */)
Tool tips
***********************************************************************/
static Lisp_Object x_create_tip_frame (struct w32_display_info *,
Lisp_Object, Lisp_Object);
static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object,
Lisp_Object, int, int, int *, int *);
@ -6458,8 +6456,7 @@ unwind_create_tip_frame (Lisp_Object frame)
/* Create a frame for a tooltip on the display described by DPYINFO.
PARMS is a list of frame parameters. TEXT is the string to
display in the tip frame. Value is the frame.
PARMS is a list of frame parameters. Value is the frame.
Note that functions called here, esp. x_default_parameter can
signal errors, for instance when a specified color name is
@ -6467,8 +6464,7 @@ unwind_create_tip_frame (Lisp_Object frame)
when this happens. */
static Lisp_Object
x_create_tip_frame (struct w32_display_info *dpyinfo,
Lisp_Object parms, Lisp_Object text)
x_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms)
{
struct frame *f;
Lisp_Object frame;
@ -6477,8 +6473,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
ptrdiff_t count = SPECPDL_INDEX ();
struct kboard *kb;
bool face_change_before = face_change;
Lisp_Object buffer;
struct buffer *old_buffer;
int x_width = 0, x_height = 0;
/* 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,
frame = Qnil;
/* Make a frame without minibuffer nor mode-line. */
f = make_frame (false);
f->wants_modeline = 0;
f->wants_modeline = false;
XSETFRAME (frame, f);
AUTO_STRING (tip, " *tip*");
buffer = Fget_buffer_create (tip);
/* Use set_window_buffer instead of Fset_window_buffer (see
discussion of bug#11984, bug#12025, bug#12026). */
set_window_buffer (FRAME_ROOT_WINDOW (f), buffer, false, false);
old_buffer = current_buffer;
set_buffer_internal_1 (XBUFFER (buffer));
bset_truncate_lines (current_buffer, Qnil);
specbind (Qinhibit_read_only, Qt);
specbind (Qinhibit_modification_hooks, Qt);
Ferase_buffer ();
Finsert (1, &text);
set_buffer_internal_1 (old_buffer);
record_unwind_protect (unwind_create_tip_frame, frame);
/* By setting the output method, we're essentially saying that
@ -6552,7 +6532,7 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
{
fset_name (f, name);
f->explicit_name = true;
/* use the frame's title when getting resources for this frame. */
/* Use the frame's title when getting resources for this frame. */
specbind (Qx_resource_name, name);
}
@ -6582,14 +6562,10 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
parms = Fcons (Fcons (Qinternal_border_width, value),
parms);
}
x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
"internalBorderWidth", "internalBorderWidth",
RES_TYPE_NUMBER);
x_default_parameter (f, parms, Qright_divider_width, make_number (0),
NULL, NULL, RES_TYPE_NUMBER);
x_default_parameter (f, parms, Qbottom_divider_width, make_number (0),
NULL, NULL, RES_TYPE_NUMBER);
/* Also do the stuff which must be set before the window exists. */
x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
"foreground", "Foreground", RES_TYPE_STRING);
@ -6616,6 +6592,9 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
f->fringe_cols = 0;
f->left_fringe_width = 0;
f->right_fringe_width = 0;
/* No dividers on tip frame. */
f->right_divider_width = 0;
f->bottom_divider_width = 0;
block_input ();
my_create_tip_window (f);
@ -6642,7 +6621,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
SET_FRAME_LINES (f, 0);
adjust_frame_size (f, width * FRAME_COLUMN_WIDTH (f),
height * FRAME_LINE_HEIGHT (f), 0, true, Qtip_frame);
/* Add `tooltip' frame parameter's default value. */
if (NILP (Fframe_parameter (frame, Qtooltip)))
Fmodify_frame_parameters (frame, Fcons (Fcons (Qtooltip, Qt), Qnil));
@ -6660,8 +6638,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
Lisp_Object fg = Fframe_parameter (frame, Qforeground_color);
Lisp_Object colors = Qnil;
/* Set tip_frame here, so that */
tip_frame = frame;
call2 (Qface_set_after_frame_default, frame, Qnil);
if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
@ -6793,6 +6769,48 @@ compute_tip_xy (struct frame *f,
*root_x = min_x;
}
/* Hide tooltip. Delete its frame if DELETE is true. */
static Lisp_Object
x_hide_tip (bool delete)
{
if (!NILP (tip_timer))
{
call1 (Qcancel_timer, tip_timer);
tip_timer = Qnil;
}
if (NILP (tip_frame)
|| (!delete && FRAMEP (tip_frame)
&& !FRAME_VISIBLE_P (XFRAME (tip_frame))))
return Qnil;
else
{
ptrdiff_t count;
Lisp_Object was_open = Qnil;
count = SPECPDL_INDEX ();
specbind (Qinhibit_redisplay, Qt);
specbind (Qinhibit_quit, Qt);
if (FRAMEP (tip_frame))
{
if (delete)
{
delete_frame (tip_frame, Qnil);
tip_frame = Qnil;
}
else
x_make_frame_invisible (XFRAME (tip_frame));
was_open = Qt;
}
else
tip_frame = Qnil;
return unbind_to (count, was_open);
}
}
DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
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'.
Text larger than the specified size is clipped. */)
(Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy)
{
struct frame *f;
struct frame *f, *tip_f;
struct window *w;
int root_x, root_y;
struct buffer *old_buffer;
struct text_pos pos;
int i, width, height;
bool seen_reversed_p;
int old_windows_or_buffers_changed = windows_or_buffers_changed;
ptrdiff_t count = SPECPDL_INDEX ();
ptrdiff_t count_1;
Lisp_Object window, size;
specbind (Qinhibit_redisplay, Qt);
@ -6858,91 +6877,155 @@ Text larger than the specified size is clipped. */)
if (NILP (last_show_tip_args))
last_show_tip_args = Fmake_vector (make_number (3), Qnil);
if (!NILP (tip_frame))
if (FRAMEP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
{
Lisp_Object last_string = AREF (last_show_tip_args, 0);
Lisp_Object last_frame = AREF (last_show_tip_args, 1);
Lisp_Object last_parms = AREF (last_show_tip_args, 2);
if (EQ (frame, last_frame)
&& !NILP (Fequal (last_string, string))
if (FRAME_VISIBLE_P (XFRAME (tip_frame))
&& EQ (frame, last_frame)
&& !NILP (Fequal_including_properties (last_string, string))
&& !NILP (Fequal (last_parms, parms)))
{
struct frame *f = XFRAME (tip_frame);
/* Only DX and DY have changed. */
tip_f = XFRAME (tip_frame);
if (!NILP (tip_timer))
{
Lisp_Object timer = tip_timer;
tip_timer = Qnil;
call1 (Qcancel_timer, timer);
}
block_input ();
compute_tip_xy (f, parms, dx, dy, FRAME_PIXEL_WIDTH (f),
FRAME_PIXEL_HEIGHT (f), &root_x, &root_y);
compute_tip_xy (tip_f, parms, dx, dy, FRAME_PIXEL_WIDTH (tip_f),
FRAME_PIXEL_HEIGHT (tip_f), &root_x, &root_y);
/* Put tooltip in topmost group and in position. */
SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
SetWindowPos (FRAME_W32_WINDOW (tip_f), HWND_TOPMOST,
root_x, root_y, 0, 0,
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
/* Ensure tooltip is on top of other topmost windows (eg menus). */
SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
SetWindowPos (FRAME_W32_WINDOW (tip_f), HWND_TOP,
0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE
| SWP_NOACTIVATE | SWP_NOOWNERZORDER);
/* Let redisplay know that we have made the frame visible already. */
SET_FRAME_VISIBLE (tip_f, 1);
ShowWindow (FRAME_W32_WINDOW (tip_f), SW_SHOWNOACTIVATE);
unblock_input ();
goto start_timer;
}
}
else if (tooltip_reuse_hidden_frame && EQ (frame, last_frame))
{
bool delete = false;
Lisp_Object tail, elt, parm, last;
/* Hide a previous tip, if any. */
Fx_hide_tip ();
/* Check if every parameter in PARMS has the same value in
last_parms. This may destruct last_parms which, however,
will be recreated below. */
for (tail = parms; CONSP (tail); tail = XCDR (tail))
{
elt = XCAR (tail);
parm = Fcar (elt);
/* The left, top, right and bottom parameters are handled
by compute_tip_xy so they can be ignored here. */
if (!EQ (parm, Qleft) && !EQ (parm, Qtop)
&& !EQ (parm, Qright) && !EQ (parm, Qbottom))
{
last = Fassq (parm, last_parms);
if (NILP (Fequal (Fcdr (elt), Fcdr (last))))
{
/* We lost, delete the old tooltip. */
delete = true;
break;
}
else
last_parms = call2 (Qassq_delete_all, parm, last_parms);
}
else
last_parms = call2 (Qassq_delete_all, parm, last_parms);
}
/* Now check if there's a parameter left in last_parms with a
non-nil value. */
for (tail = last_parms; CONSP (tail); tail = XCDR (tail))
{
elt = XCAR (tail);
parm = Fcar (elt);
if (!EQ (parm, Qleft) && !EQ (parm, Qtop) && !EQ (parm, Qright)
&& !EQ (parm, Qbottom) && !NILP (Fcdr (elt)))
{
/* We lost, delete the old tooltip. */
delete = true;
break;
}
}
x_hide_tip (delete);
}
else
x_hide_tip (true);
}
else
x_hide_tip (true);
ASET (last_show_tip_args, 0, string);
ASET (last_show_tip_args, 1, frame);
ASET (last_show_tip_args, 2, parms);
/* Add default values to frame parameters. */
if (NILP (Fassq (Qname, parms)))
parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
if (NILP (Fassq (Qinternal_border_width, parms)))
parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
if (NILP (Fassq (Qright_divider_width, parms)))
parms = Fcons (Fcons (Qright_divider_width, make_number (0)), parms);
if (NILP (Fassq (Qbottom_divider_width, parms)))
parms = Fcons (Fcons (Qbottom_divider_width, make_number (0)), parms);
if (NILP (Fassq (Qborder_width, parms)))
parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
if (NILP (Fassq (Qborder_color, parms)))
parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
if (NILP (Fassq (Qbackground_color, parms)))
parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
parms);
/* Block input until the tip has been fully drawn, to avoid crashes
when drawing tips in menus. */
block_input ();
/* Create a frame for the tooltip, and record it in the global
variable tip_frame. */
frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms, string);
f = XFRAME (frame);
if (!FRAMEP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame)))
{
/* Add default values to frame parameters. */
if (NILP (Fassq (Qname, parms)))
parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
if (NILP (Fassq (Qinternal_border_width, parms)))
parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
if (NILP (Fassq (Qborder_width, parms)))
parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
if (NILP (Fassq (Qborder_color, parms)))
parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
if (NILP (Fassq (Qbackground_color, parms)))
parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
parms);
/* Set up the frame's root window. */
w = XWINDOW (FRAME_ROOT_WINDOW (f));
/* Create a frame for the tooltip, and record it in the global
variable tip_frame. */
if (NILP (tip_frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms)))
{
/* Creating the tip frame failed. */
unblock_input ();
return unbind_to (count, Qnil);
}
}
tip_f = XFRAME (tip_frame);
window = FRAME_ROOT_WINDOW (tip_f);
AUTO_STRING (tip, " *tip*");
set_window_buffer (window, Fget_buffer_create (tip), false, false);
w = XWINDOW (window);
w->pseudo_window_p = true;
/* Set up the frame's root window. Note: The following code does not
try to size the window or its frame correctly. Its only purpose is
to make the subsequent text size calculations work. The right
sizes should get installed when the toolkit gets back to us. */
w->left_col = 0;
w->top_line = 0;
w->pixel_left = 0;
w->pixel_top = 0;
if (CONSP (Vx_max_tooltip_size)
&& INTEGERP (XCAR (Vx_max_tooltip_size))
&& XINT (XCAR (Vx_max_tooltip_size)) > 0
&& INTEGERP (XCDR (Vx_max_tooltip_size))
&& XINT (XCDR (Vx_max_tooltip_size)) > 0)
&& RANGED_INTEGERP (1, XCAR (Vx_max_tooltip_size), INT_MAX)
&& RANGED_INTEGERP (1, XCDR (Vx_max_tooltip_size), INT_MAX))
{
w->total_cols = XFASTINT (XCAR (Vx_max_tooltip_size));
w->total_lines = XFASTINT (XCDR (Vx_max_tooltip_size));
@ -6953,164 +7036,71 @@ Text larger than the specified size is clipped. */)
w->total_lines = 40;
}
w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (f);
w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (f);
w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (tip_f);
w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (tip_f);
FRAME_TOTAL_COLS (tip_f) = WINDOW_TOTAL_COLS (w);
adjust_frame_glyphs (tip_f);
FRAME_TOTAL_COLS (f) = WINDOW_TOTAL_COLS (w);
adjust_frame_glyphs (f);
w->pseudo_window_p = true;
/* Display the tooltip text in a temporary buffer. */
/* Insert STRING into the root window's buffer and fit the frame to
the buffer. */
count_1 = SPECPDL_INDEX ();
old_buffer = current_buffer;
set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->contents));
set_buffer_internal_1 (XBUFFER (w->contents));
bset_truncate_lines (current_buffer, Qnil);
specbind (Qinhibit_read_only, Qt);
specbind (Qinhibit_modification_hooks, Qt);
specbind (Qinhibit_point_motion_hooks, Qt);
Ferase_buffer ();
Finsert (1, &string);
clear_glyph_matrix (w->desired_matrix);
clear_glyph_matrix (w->current_matrix);
SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
try_window (FRAME_ROOT_WINDOW (f), pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
/* Compute width and height of the tooltip. */
width = height = 0;
seen_reversed_p = false;
for (i = 0; i < w->desired_matrix->nrows; ++i)
{
struct glyph_row *row = &w->desired_matrix->rows[i];
struct glyph *last;
int row_width;
/* Stop at the first empty row at the end. */
if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row))
break;
/* Let the row go over the full width of the frame. */
row->full_width_p = true;
row_width = row->pixel_width;
if (row->used[TEXT_AREA])
{
if (!row->reversed_p)
{
/* There's a glyph at the end of rows that is used to
place the cursor there. Don't include the width of
this glyph. */
last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
if (NILP (last->object))
row_width -= last->pixel_width;
}
else
{
/* There could be a stretch glyph at the beginning of R2L
rows that is produced by extend_face_to_end_of_line.
Don't count that glyph. */
struct glyph *g = row->glyphs[TEXT_AREA];
if (g->type == STRETCH_GLYPH && NILP (g->object))
{
row_width -= g->pixel_width;
seen_reversed_p = true;
}
}
}
height += row->height;
width = max (width, row_width);
}
/* If we've seen partial-length R2L rows, we need to re-adjust the
tool-tip frame width and redisplay it again, to avoid over-wide
tips due to the stretch glyph that extends R2L lines to full
width of the frame. */
if (seen_reversed_p)
{
/* PXW: Why do we do the pixel-to-cols conversion only if
seen_reversed_p holds? Don't we have to set other fields of
the window/frame structure?
w->total_cols and FRAME_TOTAL_COLS want the width in columns,
not in pixels. */
w->pixel_width = width;
width /= WINDOW_FRAME_COLUMN_WIDTH (w);
w->total_cols = width;
FRAME_TOTAL_COLS (f) = width;
SET_FRAME_WIDTH (f, width);
adjust_frame_glyphs (f);
w->pseudo_window_p = 1;
clear_glyph_matrix (w->desired_matrix);
clear_glyph_matrix (w->current_matrix);
try_window (FRAME_ROOT_WINDOW (f), pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
width = height = 0;
/* Recompute width and height of the tooltip. */
for (i = 0; i < w->desired_matrix->nrows; ++i)
{
struct glyph_row *row = &w->desired_matrix->rows[i];
struct glyph *last;
int row_width;
if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row))
break;
row->full_width_p = true;
row_width = row->pixel_width;
if (row->used[TEXT_AREA] && !row->reversed_p)
{
last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
if (NILP (last->object))
row_width -= last->pixel_width;
}
height += row->height;
width = max (width, row_width);
}
}
/* Add the frame's internal border to the width and height the w32
window should have. */
height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
/* Move the tooltip window where the mouse pointer is. Resize and
show it.
PXW: This should use the frame's pixel coordinates. */
compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
/* Calculate size of tooltip window. */
size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil,
make_number (w->pixel_height), Qnil);
/* Add the frame's internal border to calculated size. */
width = XINT (Fcar (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
height = XINT (Fcdr (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
/* Calculate position of tooltip frame. */
compute_tip_xy (tip_f, parms, dx, dy, width, height, &root_x, &root_y);
/* Show tooltip frame. */
{
/* Adjust Window size to take border into account. */
RECT rect;
int pad = (NUMBERP (Vw32_tooltip_extra_pixels)
? max (0, XINT (Vw32_tooltip_extra_pixels))
: FRAME_COLUMN_WIDTH (tip_f));
rect.left = rect.top = 0;
rect.right = width;
rect.bottom = height;
AdjustWindowRect (&rect, f->output_data.w32->dwStyle, false);
AdjustWindowRect (&rect, tip_f->output_data.w32->dwStyle,
FRAME_EXTERNAL_MENU_BAR (tip_f));
/* Position and size tooltip, and put it in the topmost group.
The add-on of FRAME_COLUMN_WIDTH to the 5th argument is a
peculiarity of w32 display: without it, some fonts cause the
last character of the tip to be truncated or wrapped around to
the next line. */
SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
/* Position and size tooltip and put it in the topmost group. */
SetWindowPos (FRAME_W32_WINDOW (tip_f), HWND_TOPMOST,
root_x, root_y,
rect.right - rect.left + FRAME_COLUMN_WIDTH (f),
rect.right - rect.left + pad,
rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER);
/* Ensure tooltip is on top of other topmost windows (eg menus). */
SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
SetWindowPos (FRAME_W32_WINDOW (tip_f), HWND_TOP,
0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE
| SWP_NOACTIVATE | SWP_NOOWNERZORDER);
/* Let redisplay know that we have made the frame visible already. */
SET_FRAME_VISIBLE (f, 1);
SET_FRAME_VISIBLE (tip_f, 1);
ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
ShowWindow (FRAME_W32_WINDOW (tip_f), SW_SHOWNOACTIVATE);
}
/* Draw into the window. */
w->must_be_updated_p = true;
update_single_window (w);
unblock_input ();
/* Restore original current buffer. */
set_buffer_internal_1 (old_buffer);
unbind_to (count_1, Qnil);
unblock_input ();
windows_or_buffers_changed = old_windows_or_buffers_changed;
start_timer:
@ -7127,31 +7117,7 @@ DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
Value is t if tooltip was open, nil otherwise. */)
(void)
{
ptrdiff_t count;
Lisp_Object deleted, frame, timer;
/* Return quickly if nothing to do. */
if (NILP (tip_timer) && NILP (tip_frame))
return Qnil;
frame = tip_frame;
timer = tip_timer;
tip_frame = tip_timer = deleted = Qnil;
count = SPECPDL_INDEX ();
specbind (Qinhibit_redisplay, Qt);
specbind (Qinhibit_quit, Qt);
if (!NILP (timer))
call1 (Qcancel_timer, timer);
if (FRAMEP (frame))
{
delete_frame (frame, Qnil);
deleted = Qt;
}
return unbind_to (count, deleted);
return x_hide_tip (!tooltip_reuse_hidden_frame);
}
/***********************************************************************
@ -9751,6 +9717,7 @@ syms_of_w32fns (void)
DEFSYM (Qmm_size, "mm-size");
DEFSYM (Qframes, "frames");
DEFSYM (Qtip_frame, "tip-frame");
DEFSYM (Qassq_delete_all, "assq-delete-all");
DEFSYM (Qunicode_sip, "unicode-sip");
#if defined WINDOWSNT && !defined HAVE_DBUS
DEFSYM (QCicon, ":icon");
@ -10063,6 +10030,18 @@ Default is nil.
This variable has effect only on Windows Vista and later. */);
w32_disable_new_uniscribe_apis = 0;
DEFVAR_LISP ("w32-tooltip-extra-pixels",
Vw32_tooltip_extra_pixels,
doc: /* Number of pixels added after tooltip text.
On Windows some fonts may cause the last character of a tooltip be
truncated or wrapped around to the next line. Adding some extra space
at the end of the toooltip works around this problem.
This variable specifies the number of pixels that shall be added. The
default value t means to add the width of one canonical character of the
tip frame. */);
Vw32_tooltip_extra_pixels = Qt;
#if 0 /* TODO: Port to W32 */
defsubr (&Sx_change_window_property);
defsubr (&Sx_delete_window_property);

View file

@ -9794,26 +9794,28 @@ the maximum pixel-height of all text lines.
The optional argument FROM, if non-nil, specifies the first text
position and defaults to the minimum accessible position of the buffer.
If FROM is t, use the minimum accessible position that is not a newline
character. TO, if non-nil, specifies the last text position and
If FROM is t, use the minimum accessible position that starts a
non-empty line. TO, if non-nil, specifies the last text position and
defaults to the maximum accessible position of the buffer. If TO is t,
use the maximum accessible position that is not a newline character.
use the maximum accessible position that ends a non-empty line.
The optional argument X-LIMIT, if non-nil, specifies the maximum text
width that can be returned. X-LIMIT nil or omitted, means to use the
pixel-width of WINDOW's body; use this if you do not intend to change
the width of WINDOW. Use the maximum width WINDOW may assume if you
intend to change WINDOW's width. In any case, text whose x-coordinate
is beyond X-LIMIT is ignored. Since calculating the width of long lines
can take some time, it's always a good idea to make this argument as
small as possible; in particular, if the buffer contains long lines that
shall be truncated anyway.
pixel-width of WINDOW's body; use this if you want to know how high
WINDOW should be become in order to fit all of its buffer's text with
the width of WINDOW unaltered. Use the maximum width WINDOW may assume
if you intend to change WINDOW's width. In any case, text whose
x-coordinate is beyond X-LIMIT is ignored. Since calculating the width
of long lines can take some time, it's always a good idea to make this
argument as small as possible; in particular, if the buffer contains
long lines that shall be truncated anyway.
The optional argument Y-LIMIT, if non-nil, specifies the maximum text
height that can be returned. Text lines whose y-coordinate is beyond
Y-LIMIT are ignored. Since calculating the text height of a large
buffer can take some time, it makes sense to specify this argument if
the size of the buffer is unknown.
height (exluding the height of the mode- or header-line, if any) that
can be returned. Text lines whose y-coordinate is beyond Y-LIMIT are
ignored. Since calculating the text height of a large buffer can take
some time, it makes sense to specify this argument if the size of the
buffer is large or unknown.
Optional argument MODE-AND-HEADER-LINE nil or omitted means do not
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. */)
ptrdiff_t start, end, pos;
struct text_pos startp;
void *itdata = NULL;
int c, max_y = -1, x = 0, y = 0;
int c, max_x = 0, max_y = 0, x = 0, y = 0;
CHECK_BUFFER (buffer);
b = XBUFFER (buffer);
@ -9876,11 +9878,13 @@ include the height of both, if present, in the return value. */)
end = max (start, min (XINT (to), ZV));
}
if (!NILP (y_limit))
{
CHECK_NUMBER (y_limit);
max_y = min (XINT (y_limit), INT_MAX);
}
if (!NILP (x_limit) && RANGED_INTEGERP (0, x_limit, INT_MAX))
max_x = XINT (x_limit);
if (NILP (y_limit))
max_y = INT_MAX;
else if (RANGED_INTEGERP (0, y_limit, INT_MAX))
max_y = XINT (y_limit);
itdata = bidi_shelve_cache ();
SET_TEXT_POS (startp, start, CHAR_TO_BYTE (start));
@ -9890,27 +9894,30 @@ include the height of both, if present, in the return value. */)
x = move_it_to (&it, end, -1, max_y, -1, MOVE_TO_POS | MOVE_TO_Y);
else
{
CHECK_NUMBER (x_limit);
it.last_visible_x = min (XINT (x_limit), INFINITY);
it.last_visible_x = max_x;
/* Actually, we never want move_it_to stop at to_x. But to make
sure that move_it_in_display_line_to always moves far enough,
we set it to INT_MAX and specify MOVE_TO_X. */
x = move_it_to (&it, end, INT_MAX, max_y, -1,
MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
we set it to INT_MAX and specify MOVE_TO_X. Also bound width
value by X-LIMIT. */
x = min (move_it_to (&it, end, INT_MAX, max_y, -1,
MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y),
max_x);
}
y = it.current_y + it.max_ascent + it.max_descent;
/* Subtract height of header-line which was counted automatically by
start_display. */
y = min (it.current_y + it.max_ascent + it.max_descent
- WINDOW_HEADER_LINE_HEIGHT (w),
max_y);
if (!EQ (mode_and_header_line, Qheader_line)
&& !EQ (mode_and_header_line, Qt))
/* Do not count the header-line which was counted automatically by
start_display. */
y = y - WINDOW_HEADER_LINE_HEIGHT (w);
if (EQ (mode_and_header_line, Qheader_line)
|| EQ (mode_and_header_line, Qt))
/* Re-add height of header-line as requested. */
y = y + WINDOW_HEADER_LINE_HEIGHT (w);
if (EQ (mode_and_header_line, Qmode_line)
|| EQ (mode_and_header_line, Qt))
/* Do count the mode-line which is not included automatically by
start_display. */
/* Add height of mode-line as requested. */
y = y + WINDOW_MODE_LINE_HEIGHT (w);
bidi_unshelve_cache (itdata, false);

View file

@ -5303,8 +5303,6 @@ no value of TYPE (always string in the MS Windows case). */)
Tool tips
***********************************************************************/
static Lisp_Object x_create_tip_frame (struct x_display_info *,
Lisp_Object, Lisp_Object);
static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object,
Lisp_Object, int, int, int *, int *);
@ -5348,9 +5346,7 @@ unwind_create_tip_frame (Lisp_Object frame)
when this happens. */
static Lisp_Object
x_create_tip_frame (struct x_display_info *dpyinfo,
Lisp_Object parms,
Lisp_Object text)
x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms)
{
struct frame *f;
Lisp_Object frame;
@ -5359,7 +5355,6 @@ x_create_tip_frame (struct x_display_info *dpyinfo,
ptrdiff_t count = SPECPDL_INDEX ();
bool face_change_before = face_change;
Lisp_Object buffer;
struct buffer *old_buffer;
int x_width = 0, x_height = 0;
if (!dpyinfo->terminal->name)
@ -5375,23 +5370,9 @@ x_create_tip_frame (struct x_display_info *dpyinfo,
error ("Invalid frame name--not a string or nil");
frame = Qnil;
f = make_frame (true);
f = make_frame (false);
f->wants_modeline = false;
XSETFRAME (frame, f);
AUTO_STRING (tip, " *tip*");
buffer = Fget_buffer_create (tip);
/* Use set_window_buffer instead of Fset_window_buffer (see
discussion of bug#11984, bug#12025, bug#12026). */
set_window_buffer (FRAME_ROOT_WINDOW (f), buffer, false, false);
old_buffer = current_buffer;
set_buffer_internal_1 (XBUFFER (buffer));
bset_truncate_lines (current_buffer, Qnil);
specbind (Qinhibit_read_only, Qt);
specbind (Qinhibit_modification_hooks, Qt);
Ferase_buffer ();
Finsert (1, &text);
set_buffer_internal_1 (old_buffer);
record_unwind_protect (unwind_create_tip_frame, frame);
f->terminal = dpyinfo->terminal;
@ -5633,8 +5614,6 @@ x_create_tip_frame (struct x_display_info *dpyinfo,
{
Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
/* Set tip_frame here, so that */
tip_frame = frame;
call2 (Qface_set_after_frame_default, frame, Qnil);
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
}
/* Hide tooltip. Delete its frame if DELETE is true. */
static Lisp_Object
x_hide_tip (bool delete)
{
if (!NILP (tip_timer))
{
call1 (Qcancel_timer, tip_timer);
tip_timer = Qnil;
}
if (NILP (tip_frame)
|| (!delete && FRAMEP (tip_frame)
&& !FRAME_VISIBLE_P (XFRAME (tip_frame))))
return Qnil;
else
{
ptrdiff_t count;
Lisp_Object was_open = Qnil;
count = SPECPDL_INDEX ();
specbind (Qinhibit_redisplay, Qt);
specbind (Qinhibit_quit, Qt);
#ifdef USE_GTK
{
/* When using system tooltip, tip_frame is the Emacs frame on
which the tip is shown. */
struct frame *f = XFRAME (tip_frame);
if (FRAME_LIVE_P (f) && xg_hide_tooltip (f))
{
tip_frame = Qnil;
was_open = Qt;
}
}
#endif
if (FRAMEP (tip_frame))
{
if (delete)
{
delete_frame (tip_frame, Qnil);
tip_frame = Qnil;
}
else
x_make_frame_invisible (XFRAME (tip_frame));
was_open = Qt;
#ifdef USE_LUCID
/* Bloodcurdling hack alert: The Lucid menu bar widget's
redisplay procedure is not called when a tip frame over
menu items is unmapped. Redisplay the menu manually... */
{
Widget w;
struct frame *f = SELECTED_FRAME ();
if (FRAME_X_P (f) && FRAME_LIVE_P (f))
{
w = f->output_data.x->menubar_widget;
if (!DoesSaveUnders (FRAME_DISPLAY_INFO (f)->screen)
&& w != NULL)
{
block_input ();
xlwmenu_redisplay (w);
unblock_input ();
}
}
}
#endif /* USE_LUCID */
}
else
tip_frame = Qnil;
return unbind_to (count, was_open);
}
}
DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
doc: /* Show STRING in a "tooltip" window on frame FRAME.
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'.
Text larger than the specified size is clipped. */)
(Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy)
{
struct frame *f;
struct frame *f, *tip_f;
struct window *w;
int root_x, root_y;
struct buffer *old_buffer;
struct text_pos pos;
int i, width, height;
bool seen_reversed_p;
int width, height;
int old_windows_or_buffers_changed = windows_or_buffers_changed;
ptrdiff_t count = SPECPDL_INDEX ();
ptrdiff_t count_1;
Lisp_Object window, size;
specbind (Qinhibit_redisplay, Qt);
@ -5862,22 +5921,23 @@ Text larger than the specified size is clipped. */)
if (NILP (last_show_tip_args))
last_show_tip_args = Fmake_vector (make_number (3), Qnil);
if (!NILP (tip_frame))
if (FRAMEP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
{
Lisp_Object last_string = AREF (last_show_tip_args, 0);
Lisp_Object last_frame = AREF (last_show_tip_args, 1);
Lisp_Object last_parms = AREF (last_show_tip_args, 2);
if (EQ (frame, last_frame)
&& !NILP (Fequal (last_string, string))
if (FRAME_VISIBLE_P (XFRAME (tip_frame))
&& EQ (frame, last_frame)
&& !NILP (Fequal_including_properties (last_string, string))
&& !NILP (Fequal (last_parms, parms)))
{
struct frame *tip_f = XFRAME (tip_frame);
/* Only DX and DY have changed. */
tip_f = XFRAME (tip_frame);
if (!NILP (tip_timer))
{
Lisp_Object timer = tip_timer;
tip_timer = Qnil;
call1 (Qcancel_timer, timer);
}
@ -5888,41 +5948,103 @@ Text larger than the specified size is clipped. */)
XMoveWindow (FRAME_X_DISPLAY (tip_f), FRAME_X_WINDOW (tip_f),
root_x, root_y);
unblock_input ();
goto start_timer;
}
}
else if (tooltip_reuse_hidden_frame && EQ (frame, last_frame))
{
bool delete = false;
Lisp_Object tail, elt, parm, last;
/* Hide a previous tip, if any. */
Fx_hide_tip ();
/* Check if every parameter in PARMS has the same value in
last_parms unless it should be ignored by means of
Vtooltip_reuse_hidden_frame_parameters. This may destruct
last_parms which, however, will be recreated below. */
for (tail = parms; CONSP (tail); tail = XCDR (tail))
{
elt = XCAR (tail);
parm = Fcar (elt);
/* The left, top, right and bottom parameters are handled
by compute_tip_xy so they can be ignored here. */
if (!EQ (parm, Qleft) && !EQ (parm, Qtop)
&& !EQ (parm, Qright) && !EQ (parm, Qbottom))
{
last = Fassq (parm, last_parms);
if (NILP (Fequal (Fcdr (elt), Fcdr (last))))
{
/* We lost, delete the old tooltip. */
delete = true;
break;
}
else
last_parms = call2 (Qassq_delete_all, parm, last_parms);
}
else
last_parms = call2 (Qassq_delete_all, parm, last_parms);
}
/* Now check if every parameter in what is left of last_parms
with a non-nil value has an association in PARMS unless it
should be ignored by means of
Vtooltip_reuse_hidden_frame_parameters. */
for (tail = last_parms; CONSP (tail); tail = XCDR (tail))
{
elt = XCAR (tail);
parm = Fcar (elt);
if (!EQ (parm, Qleft) && !EQ (parm, Qtop) && !EQ (parm, Qright)
&& !EQ (parm, Qbottom) && !NILP (Fcdr (elt)))
{
/* We lost, delete the old tooltip. */
delete = true;
break;
}
}
x_hide_tip (delete);
}
else
x_hide_tip (true);
}
else
x_hide_tip (true);
ASET (last_show_tip_args, 0, string);
ASET (last_show_tip_args, 1, frame);
ASET (last_show_tip_args, 2, parms);
/* Add default values to frame parameters. */
if (NILP (Fassq (Qname, parms)))
parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
if (NILP (Fassq (Qinternal_border_width, parms)))
parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
if (NILP (Fassq (Qborder_width, parms)))
parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
if (NILP (Fassq (Qbottom_divider_width, parms)))
parms = Fcons (Fcons (Qbottom_divider_width, make_number (0)), parms);
if (NILP (Fassq (Qright_divider_width, parms)))
parms = Fcons (Fcons (Qright_divider_width, make_number (0)), parms);
if (NILP (Fassq (Qborder_color, parms)))
parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
if (NILP (Fassq (Qbackground_color, parms)))
parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
parms);
if (!FRAMEP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame)))
{
/* Add default values to frame parameters. */
if (NILP (Fassq (Qname, parms)))
parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
if (NILP (Fassq (Qinternal_border_width, parms)))
parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
if (NILP (Fassq (Qborder_width, parms)))
parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
if (NILP (Fassq (Qborder_color, parms)))
parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
if (NILP (Fassq (Qbackground_color, parms)))
parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
parms);
/* Create a frame for the tooltip, and record it in the global
variable tip_frame. */
frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms, string);
f = XFRAME (frame);
/* Create a frame for the tooltip, and record it in the global
variable tip_frame. */
if (NILP (tip_frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms)))
/* Creating the tip frame failed. */
return unbind_to (count, Qnil);
}
/* Set up the frame's root window. */
w = XWINDOW (FRAME_ROOT_WINDOW (f));
tip_f = XFRAME (tip_frame);
window = FRAME_ROOT_WINDOW (tip_f);
AUTO_STRING (tip, " *tip*");
set_window_buffer (window, Fget_buffer_create (tip), false, false);
w = XWINDOW (window);
w->pseudo_window_p = true;
/* Set up the frame's root window. Note: The following code does not
try to size the window or its frame correctly. Its only purpose is
to make the subsequent text size calculations work. The right
sizes should get installed when the toolkit gets back to us. */
w->left_col = 0;
w->top_line = 0;
w->pixel_left = 0;
@ -5941,130 +6063,47 @@ Text larger than the specified size is clipped. */)
w->total_lines = 40;
}
w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (f);
w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (f);
w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (tip_f);
w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (tip_f);
FRAME_TOTAL_COLS (tip_f) = w->total_cols;
adjust_frame_glyphs (tip_f);
FRAME_TOTAL_COLS (f) = w->total_cols;
adjust_frame_glyphs (f);
w->pseudo_window_p = true;
/* Display the tooltip text in a temporary buffer. */
/* Insert STRING into root window's buffer and fit the frame to the
buffer. */
count_1 = SPECPDL_INDEX ();
old_buffer = current_buffer;
set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->contents));
set_buffer_internal_1 (XBUFFER (w->contents));
bset_truncate_lines (current_buffer, Qnil);
specbind (Qinhibit_read_only, Qt);
specbind (Qinhibit_modification_hooks, Qt);
specbind (Qinhibit_point_motion_hooks, Qt);
Ferase_buffer ();
Finsert (1, &string);
clear_glyph_matrix (w->desired_matrix);
clear_glyph_matrix (w->current_matrix);
SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
try_window (FRAME_ROOT_WINDOW (f), pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
/* Calculate size of tooltip window. */
size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil,
make_number (w->pixel_height), Qnil);
/* Add the frame's internal border to calculated size. */
width = XINT (Fcar (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
height = XINT (Fcdr (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
/* Compute width and height of the tooltip. */
width = height = 0;
seen_reversed_p = false;
for (i = 0; i < w->desired_matrix->nrows; ++i)
{
struct glyph_row *row = &w->desired_matrix->rows[i];
struct glyph *last;
int row_width;
/* Stop at the first empty row at the end. */
if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row))
break;
/* Let the row go over the full width of the frame. */
row->full_width_p = true;
row_width = row->pixel_width;
if (row->used[TEXT_AREA])
{
/* There's a glyph at the end of rows that is used to place
the cursor there. Don't include the width of this glyph. */
if (!row->reversed_p)
{
last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
if (NILP (last->object))
row_width -= last->pixel_width;
}
else
{
/* There could be a stretch glyph at the beginning of R2L
rows that is produced by extend_face_to_end_of_line.
Don't count that glyph. */
struct glyph *g = row->glyphs[TEXT_AREA];
if (g->type == STRETCH_GLYPH && NILP (g->object))
{
row_width -= g->pixel_width;
seen_reversed_p = true;
}
}
}
height += row->height;
width = max (width, row_width);
}
/* If we've seen partial-length R2L rows, we need to re-adjust the
tool-tip frame width and redisplay it again, to avoid over-wide
tips due to the stretch glyph that extends R2L lines to full
width of the frame. */
if (seen_reversed_p)
{
/* w->total_cols and FRAME_TOTAL_COLS want the width in columns,
not in pixels. */
w->pixel_width = width;
width /= WINDOW_FRAME_COLUMN_WIDTH (w);
w->total_cols = width;
FRAME_TOTAL_COLS (f) = width;
SET_FRAME_WIDTH (f, width);
adjust_frame_glyphs (f);
clear_glyph_matrix (w->desired_matrix);
clear_glyph_matrix (w->current_matrix);
try_window (FRAME_ROOT_WINDOW (f), pos, 0);
width = height = 0;
/* Recompute width and height of the tooltip. */
for (i = 0; i < w->desired_matrix->nrows; ++i)
{
struct glyph_row *row = &w->desired_matrix->rows[i];
struct glyph *last;
int row_width;
if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row))
break;
row->full_width_p = true;
row_width = row->pixel_width;
if (row->used[TEXT_AREA] && !row->reversed_p)
{
last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
if (NILP (last->object))
row_width -= last->pixel_width;
}
height += row->height;
width = max (width, row_width);
}
}
/* Add the frame's internal border to the width and height the X
window should have. */
height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
/* Move the tooltip window where the mouse pointer is. Resize and
show it. */
compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
/* Calculate position of tooltip frame. */
compute_tip_xy (tip_f, parms, dx, dy, width, height, &root_x, &root_y);
/* Show tooltip frame. */
block_input ();
XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
XMoveResizeWindow (FRAME_X_DISPLAY (tip_f), FRAME_X_WINDOW (tip_f),
root_x, root_y, width, height);
XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
XMapRaised (FRAME_X_DISPLAY (tip_f), FRAME_X_WINDOW (tip_f));
unblock_input ();
/* Draw into the window. */
w->must_be_updated_p = true;
update_single_window (w);
/* Restore original current buffer. */
set_buffer_internal_1 (old_buffer);
unbind_to (count_1, Qnil);
windows_or_buffers_changed = old_windows_or_buffers_changed;
start_timer:
@ -6081,66 +6120,9 @@ DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
Value is t if tooltip was open, nil otherwise. */)
(void)
{
ptrdiff_t count;
Lisp_Object deleted, frame, timer;
/* Return quickly if nothing to do. */
if (NILP (tip_timer) && NILP (tip_frame))
return Qnil;
frame = tip_frame;
timer = tip_timer;
tip_frame = tip_timer = deleted = Qnil;
count = SPECPDL_INDEX ();
specbind (Qinhibit_redisplay, Qt);
specbind (Qinhibit_quit, Qt);
if (!NILP (timer))
call1 (Qcancel_timer, timer);
#ifdef USE_GTK
{
/* When using system tooltip, tip_frame is the Emacs frame on which
the tip is shown. */
struct frame *f = XFRAME (frame);
if (FRAME_LIVE_P (f) && xg_hide_tooltip (f))
frame = Qnil;
}
#endif
if (FRAMEP (frame))
{
delete_frame (frame, Qnil);
deleted = Qt;
#ifdef USE_LUCID
/* Bloodcurdling hack alert: The Lucid menu bar widget's
redisplay procedure is not called when a tip frame over menu
items is unmapped. Redisplay the menu manually... */
{
Widget w;
struct frame *f = SELECTED_FRAME ();
if (FRAME_X_P (f) && FRAME_LIVE_P (f))
{
w = f->output_data.x->menubar_widget;
if (!DoesSaveUnders (FRAME_DISPLAY_INFO (f)->screen)
&& w != NULL)
{
block_input ();
xlwmenu_redisplay (w);
unblock_input ();
}
}
}
#endif /* USE_LUCID */
}
return unbind_to (count, deleted);
return x_hide_tip (!tooltip_reuse_hidden_frame);
}
/***********************************************************************
File selection dialog
@ -6802,6 +6784,7 @@ syms_of_xfns (void)
DEFSYM (Qcancel_timer, "cancel-timer");
DEFSYM (Qfont_param, "font-parameter");
DEFSYM (Qmono, "mono");
DEFSYM (Qassq_delete_all, "assq-delete-all");
#ifdef USE_CAIRO
DEFSYM (Qpdf, "pdf");