summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPo Lu <luangruo@yahoo.com>2022-05-14 11:29:43 +0800
committerPo Lu <luangruo@yahoo.com>2022-05-14 11:30:29 +0800
commit09e86785ce2dae9176f4122c399c61b51240cfec (patch)
tree55df22f34721df629fd1711e477b07de2e60a327
parent949180b8ab4a76ae46389fed9e210d151b328a2a (diff)
downloademacs-09e86785ce2dae9176f4122c399c61b51240cfec.tar.gz
Implement non-system tooltips on NS
* src/nsfns.m (unwind_create_frame): Return Lisp_Object like on X. (do_unwind_create_frame): New function. (Fx_create_frame): Adjust accordingly. (compute_tip_xy): Fix coding style. (unwind_create_tip_frame, ns_create_tip_frame): New functions. (x_hide_tip, Fx_show_tip, Fx_hide_tip): Create and hide actual tooltip frames. (syms_of_nsfns): New defvar `x-max-tooltip-size' and staticpros. * src/nsterm.m (ns_set_window_size): Clean up coding style. ([EmacsWindow initWithEmacsFrame:]): ([EmacsWindow initWithEmacsFrame:fullscreen:screen:]): Handle tooltip frames.
-rw-r--r--src/nsfns.m635
-rw-r--r--src/nsterm.h1
-rw-r--r--src/nsterm.m45
3 files changed, 619 insertions, 62 deletions
diff --git a/src/nsfns.m b/src/nsfns.m
index a67dafe0950..f82665a3000 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -53,6 +53,26 @@ GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
static EmacsTooltip *ns_tooltip = nil;
+/* The frame of the currently visible tooltip, or nil if none. */
+static Lisp_Object tip_frame;
+
+/* The window-system window corresponding to the frame of the
+ currently visible tooltip. */
+static NSWindow *tip_window;
+
+/* A timer that hides or deletes the currently visible tooltip when it
+ fires. */
+static Lisp_Object tip_timer;
+
+/* STRING argument of last `x-show-tip' call. */
+static Lisp_Object tip_last_string;
+
+/* Normalized FRAME argument of last `x-show-tip' call. */
+static Lisp_Object tip_last_frame;
+
+/* PARMS argument of last `x-show-tip' call. */
+static Lisp_Object tip_last_parms;
+
/* Static variables to handle AppleScript execution. */
static Lisp_Object as_script, *as_result;
static int as_status;
@@ -1021,7 +1041,7 @@ frame_parm_handler ns_frame_parm_handlers[] =
/* Handler for signals raised during x_create_frame.
FRAME is the frame which is partially constructed. */
-static void
+static Lisp_Object
unwind_create_frame (Lisp_Object frame)
{
struct frame *f = XFRAME (frame);
@@ -1030,7 +1050,7 @@ unwind_create_frame (Lisp_Object frame)
display is disconnected after the frame has become official, but
before x_create_frame removes the unwind protect. */
if (!FRAME_LIVE_P (f))
- return;
+ return Qnil;
/* If frame is ``official'', nothing to do. */
if (NILP (Fmemq (frame, Vframe_list)))
@@ -1057,7 +1077,18 @@ unwind_create_frame (Lisp_Object frame)
/* Check that reference counts are indeed correct. */
eassert (dpyinfo->terminal->image_cache->refcount == image_cache_refcount);
#endif
+
+ return Qt;
}
+
+ return Qnil;
+}
+
+
+static void
+do_unwind_create_frame (Lisp_Object frame)
+{
+ unwind_create_frame (frame);
}
/*
@@ -1191,7 +1222,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
FRAME_DISPLAY_INFO (f) = dpyinfo;
/* With FRAME_DISPLAY_INFO set up, this unwind-protect is safe. */
- record_unwind_protect (unwind_create_frame, frame);
+ record_unwind_protect (do_unwind_create_frame, frame);
f->output_data.ns->window_desc = desc_ctr++;
if (TYPE_RANGED_FIXNUMP (Window, parent))
@@ -2769,16 +2800,10 @@ DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
return make_fixnum (1 << min (dpyinfo->n_planes, 24));
}
-/* TODO: move to xdisp or similar */
static void
-compute_tip_xy (struct frame *f,
- Lisp_Object parms,
- Lisp_Object dx,
- Lisp_Object dy,
- int width,
- int height,
- int *root_x,
- int *root_y)
+compute_tip_xy (struct frame *f, Lisp_Object parms, Lisp_Object dx,
+ Lisp_Object dy, int width, int height, int *root_x,
+ int *root_y)
{
Lisp_Object left, top, right, bottom;
NSPoint pt;
@@ -2847,6 +2872,299 @@ compute_tip_xy (struct frame *f,
*root_y = screen.frame.origin.y + screen.frame.size.height - height;
}
+static void
+unwind_create_tip_frame (Lisp_Object frame)
+{
+ Lisp_Object deleted;
+
+ deleted = unwind_create_frame (frame);
+ if (EQ (deleted, Qt))
+ {
+ tip_window = NULL;
+ tip_frame = Qnil;
+ }
+}
+
+/* Create a frame for a tooltip on the display described by DPYINFO.
+ PARMS is a list of frame parameters. TEXT is the string to
+ display in the tip frame. Value is the frame.
+
+ Note that functions called here, esp. gui_default_parameter can
+ signal errors, for instance when a specified color name is
+ undefined. We have to make sure that we're in a consistent state
+ when this happens. */
+
+static Lisp_Object
+ns_create_tip_frame (struct ns_display_info *dpyinfo, Lisp_Object parms)
+{
+ struct frame *f;
+ Lisp_Object frame;
+ Lisp_Object name;
+ specpdl_ref count = SPECPDL_INDEX ();
+ bool face_change_before = face_change;
+
+ if (!dpyinfo->terminal->name)
+ error ("Terminal is not live, can't create new frames on it");
+
+ parms = Fcopy_alist (parms);
+
+ /* Get the name of the frame to use for resource lookup. */
+ name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name",
+ RES_TYPE_STRING);
+ if (!STRINGP (name)
+ && !EQ (name, Qunbound)
+ && !NILP (name))
+ error ("Invalid frame name--not a string or nil");
+
+ frame = Qnil;
+ f = make_frame (false);
+ f->wants_modeline = false;
+ XSETFRAME (frame, f);
+ record_unwind_protect (unwind_create_tip_frame, frame);
+
+ f->terminal = dpyinfo->terminal;
+
+ f->output_method = output_ns;
+ f->output_data.ns = xzalloc (sizeof *f->output_data.ns);
+ f->tooltip = true;
+
+ FRAME_FONTSET (f) = -1;
+ FRAME_DISPLAY_INFO (f) = dpyinfo;
+
+ block_input ();
+#ifdef NS_IMPL_COCOA
+ mac_register_font_driver (f);
+#else
+ register_font_driver (&nsfont_driver, f);
+#endif
+ unblock_input ();
+
+ image_cache_refcount =
+ FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
+
+ gui_default_parameter (f, parms, Qfont_backend, Qnil,
+ "fontBackend", "FontBackend", RES_TYPE_STRING);
+
+ {
+#ifdef NS_IMPL_COCOA
+ /* use for default font name */
+ id font = [NSFont userFixedPitchFontOfSize: -1.0]; /* default */
+ gui_default_parameter (f, parms, Qfontsize,
+ make_fixnum (0 /* (int)[font pointSize] */),
+ "fontSize", "FontSize", RES_TYPE_NUMBER);
+ // Remove ' Regular', not handled by backends.
+ char *fontname = xstrdup ([[font displayName] UTF8String]);
+ int len = strlen (fontname);
+ if (len > 8 && strcmp (fontname + len - 8, " Regular") == 0)
+ fontname[len-8] = '\0';
+ gui_default_parameter (f, parms, Qfont,
+ build_string (fontname),
+ "font", "Font", RES_TYPE_STRING);
+ xfree (fontname);
+#else
+ gui_default_parameter (f, parms, Qfont,
+ build_string ("fixed"),
+ "font", "Font", RES_TYPE_STRING);
+#endif
+ }
+
+ gui_default_parameter (f, parms, Qborder_width, make_fixnum (0),
+ "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
+
+ /* This defaults to 1 in order to match xterm. We recognize either
+ internalBorderWidth or internalBorder (which is what xterm calls
+ it). */
+ if (NILP (Fassq (Qinternal_border_width, parms)))
+ {
+ Lisp_Object value;
+
+ value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width,
+ "internalBorder", "internalBorder",
+ RES_TYPE_NUMBER);
+ if (! EQ (value, Qunbound))
+ parms = Fcons (Fcons (Qinternal_border_width, value),
+ parms);
+ }
+
+ gui_default_parameter (f, parms, Qinternal_border_width, make_fixnum (1),
+ "internalBorderWidth", "internalBorderWidth",
+ RES_TYPE_NUMBER);
+ gui_default_parameter (f, parms, Qright_divider_width, make_fixnum (0),
+ NULL, NULL, RES_TYPE_NUMBER);
+ gui_default_parameter (f, parms, Qbottom_divider_width, make_fixnum (0),
+ NULL, NULL, RES_TYPE_NUMBER);
+
+ /* Also do the stuff which must be set before the window exists. */
+ gui_default_parameter (f, parms, Qforeground_color, build_string ("black"),
+ "foreground", "Foreground", RES_TYPE_STRING);
+ gui_default_parameter (f, parms, Qbackground_color, build_string ("white"),
+ "background", "Background", RES_TYPE_STRING);
+ gui_default_parameter (f, parms, Qmouse_color, build_string ("black"),
+ "pointerColor", "Foreground", RES_TYPE_STRING);
+ gui_default_parameter (f, parms, Qcursor_color, build_string ("black"),
+ "cursorColor", "Foreground", RES_TYPE_STRING);
+ gui_default_parameter (f, parms, Qborder_color, build_string ("black"),
+ "borderColor", "BorderColor", RES_TYPE_STRING);
+ gui_default_parameter (f, parms, Qno_special_glyphs, Qnil,
+ NULL, NULL, RES_TYPE_BOOLEAN);
+
+ /* Init faces before gui_default_parameter is called for the
+ scroll-bar-width parameter because otherwise we end up in
+ init_iterator with a null face cache, which should not happen. */
+ init_frame_faces (f);
+
+ f->output_data.ns->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
+
+ gui_default_parameter (f, parms, Qinhibit_double_buffering, Qnil,
+ "inhibitDoubleBuffering", "InhibitDoubleBuffering",
+ RES_TYPE_BOOLEAN);
+
+ gui_figure_window_size (f, parms, false, false);
+
+ block_input ();
+ [[EmacsView alloc] initFrameFromEmacs: f];
+ ns_icon (f, parms);
+ unblock_input ();
+
+ gui_default_parameter (f, parms, Qauto_raise, Qnil,
+ "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
+ gui_default_parameter (f, parms, Qauto_lower, Qnil,
+ "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
+ gui_default_parameter (f, parms, Qcursor_type, Qbox,
+ "cursorType", "CursorType", RES_TYPE_SYMBOL);
+ gui_default_parameter (f, parms, Qalpha, Qnil,
+ "alpha", "Alpha", RES_TYPE_NUMBER);
+
+ /* Add `tooltip' frame parameter's default value. */
+ if (NILP (Fframe_parameter (frame, Qtooltip)))
+ {
+ AUTO_FRAME_ARG (arg, Qtooltip, Qt);
+ Fmodify_frame_parameters (frame, arg);
+ }
+
+ /* FIXME - can this be done in a similar way to normal frames?
+ https://lists.gnu.org/r/emacs-devel/2007-10/msg00641.html */
+
+ /* Set the `display-type' frame parameter before setting up faces. */
+ {
+ Lisp_Object disptype = intern ("color");
+
+ if (NILP (Fframe_parameter (frame, Qdisplay_type)))
+ {
+ AUTO_FRAME_ARG (arg, Qdisplay_type, disptype);
+ Fmodify_frame_parameters (frame, arg);
+ }
+ }
+
+ /* Set up faces after all frame parameters are known. This call
+ also merges in face attributes specified for new frames.
+
+ Frame parameters may be changed if .Xdefaults contains
+ specifications for the default font. For example, if there is an
+ `Emacs.default.attributeBackground: pink', the `background-color'
+ attribute of the frame gets set, which let's the internal border
+ of the tooltip frame appear in pink. Prevent this. */
+ {
+ Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
+
+ call2 (Qface_set_after_frame_default, frame, Qnil);
+
+ if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
+ {
+ AUTO_FRAME_ARG (arg, Qbackground_color, bg);
+ Fmodify_frame_parameters (frame, arg);
+ }
+ }
+
+ f->no_split = true;
+
+ /* Now that the frame will be official, it counts as a reference to
+ its display and terminal. */
+ f->terminal->reference_count++;
+
+ /* It is now ok to make the frame official even if we get an error
+ below. And the frame needs to be on Vframe_list or making it
+ visible won't work. */
+ Vframe_list = Fcons (frame, Vframe_list);
+ f->can_set_window_size = true;
+ adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
+ 0, true, Qtip_frame);
+
+ /* Setting attributes of faces of the tooltip frame from resources
+ and similar will set face_change, which leads to the clearing of
+ all current matrices. Since this isn't necessary here, avoid it
+ by resetting face_change to the value it had before we created
+ the tip frame. */
+ face_change = face_change_before;
+
+ /* Discard the unwind_protect. */
+ return unbind_to (count, frame);
+}
+
+static Lisp_Object
+x_hide_tip (bool delete)
+{
+ if (!NILP (tip_timer))
+ {
+ call1 (intern ("cancel-timer"), tip_timer);
+ tip_timer = Qnil;
+ }
+
+ if (!(ns_tooltip == nil || ![ns_tooltip isActive]))
+ {
+ [ns_tooltip hide];
+ tip_last_frame = Qnil;
+ return Qt;
+ }
+
+ if ((NILP (tip_last_frame) && NILP (tip_frame))
+ || (!use_system_tooltips
+ && !delete
+ && !NILP (tip_frame)
+ && FRAME_LIVE_P (XFRAME (tip_frame))
+ && !FRAME_VISIBLE_P (XFRAME (tip_frame))))
+ /* Either there's no tooltip to hide or it's an already invisible
+ Emacs tooltip and we don't want to change its type. Return
+ quickly. */
+ return Qnil;
+ else
+ {
+ specpdl_ref count;
+ Lisp_Object was_open = Qnil;
+
+ count = SPECPDL_INDEX ();
+ specbind (Qinhibit_redisplay, Qt);
+ specbind (Qinhibit_quit, Qt);
+
+ /* Now look whether there's an Emacs tip around. */
+ if (!NILP (tip_frame))
+ {
+ struct frame *f = XFRAME (tip_frame);
+
+ if (FRAME_LIVE_P (f))
+ {
+ if (delete || use_system_tooltips)
+ {
+ /* Delete the Emacs tooltip frame when DELETE is true
+ or we change the tooltip type from an Emacs one to
+ a GTK+ system one. */
+ delete_frame (tip_frame, Qnil);
+ tip_frame = Qnil;
+ }
+ else
+ ns_make_frame_invisible (f);
+
+ was_open = Qt;
+ }
+ else
+ tip_frame = Qnil;
+ }
+ else
+ tip_frame = Qnil;
+
+ return unbind_to (count, was_open);
+ }
+}
DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
doc: /* SKIP: real doc in xfns.c. */)
@@ -2854,11 +3172,18 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
{
int root_x, root_y;
specpdl_ref count = SPECPDL_INDEX ();
- struct frame *f;
+ struct frame *f, *tip_f;
+ struct window *w;
+ struct buffer *old_buffer;
+ struct text_pos pos;
+ int width, height;
+ int old_windows_or_buffers_changed = windows_or_buffers_changed;
+ specpdl_ref count_1;
+ Lisp_Object window, size, tip_buf;
char *str;
- NSSize size;
- NSColor *color;
- Lisp_Object t;
+ NSWindow *nswindow;
+
+ AUTO_STRING (tip, " *tip*");
specbind (Qinhibit_redisplay, Qt);
@@ -2879,32 +3204,250 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
else
CHECK_FIXNUM (dy);
- block_input ();
- if (ns_tooltip == nil)
- ns_tooltip = [[EmacsTooltip alloc] init];
+ if (use_system_tooltips)
+ {
+ NSSize size;
+ NSColor *color;
+ Lisp_Object t;
+
+ block_input ();
+ if (ns_tooltip == nil)
+ ns_tooltip = [[EmacsTooltip alloc] init];
+ else
+ Fx_hide_tip ();
+
+ t = gui_display_get_arg (NULL, parms, Qbackground_color, NULL, NULL,
+ RES_TYPE_STRING);
+ if (ns_lisp_to_color (t, &color) == 0)
+ [ns_tooltip setBackgroundColor: color];
+
+ t = gui_display_get_arg (NULL, parms, Qforeground_color, NULL, NULL,
+ RES_TYPE_STRING);
+ if (ns_lisp_to_color (t, &color) == 0)
+ [ns_tooltip setForegroundColor: color];
+
+ [ns_tooltip setText: str];
+ size = [ns_tooltip frame].size;
+
+ /* Move the tooltip window where the mouse pointer is. Resize and
+ show it. */
+ compute_tip_xy (f, parms, dx, dy, (int) size.width, (int) size.height,
+ &root_x, &root_y);
+
+ [ns_tooltip showAtX: root_x Y: root_y for: XFIXNUM (timeout)];
+ unblock_input ();
+ }
else
- Fx_hide_tip ();
+ {
+ if (!NILP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
+ {
+ if (FRAME_VISIBLE_P (XFRAME (tip_frame))
+ && EQ (frame, tip_last_frame)
+ && !NILP (Fequal_including_properties (tip_last_string, string))
+ && !NILP (Fequal (tip_last_parms, parms)))
+ {
+ /* Only DX and DY have changed. */
+ tip_f = XFRAME (tip_frame);
+ if (!NILP (tip_timer))
+ {
+ call1 (intern ("cancel-timer"), tip_timer);
+ tip_timer = Qnil;
+ }
+
+ nswindow = [FRAME_NS_VIEW (tip_f) window];
+
+ block_input ();
+ compute_tip_xy (tip_f, parms, dx, dy, FRAME_PIXEL_WIDTH (tip_f),
+ FRAME_PIXEL_HEIGHT (tip_f), &root_x, &root_y);
+ [nswindow setFrame: NSMakeRect (root_x, root_y,
+ FRAME_PIXEL_WIDTH (tip_f),
+ FRAME_PIXEL_HEIGHT (tip_f))
+ display: YES];
+ [nswindow setLevel: NSPopUpMenuWindowLevel];
+ [nswindow orderFront: NSApp];
+ [nswindow display];
+
+ SET_FRAME_VISIBLE (tip_f, 1);
+ unblock_input ();
+
+ goto start_timer;
+ }
+ else if (tooltip_reuse_hidden_frame && EQ (frame, tip_last_frame))
+ {
+ bool delete = false;
+ Lisp_Object tail, elt, parm, last;
+
+ /* Check if every parameter in PARMS has the same value in
+ tip_last_parms. This may destruct tip_last_parms which,
+ however, will be recreated below. */
+ for (tail = parms; CONSP (tail); tail = XCDR (tail))
+ {
+ elt = XCAR (tail);
+ parm = Fcar (elt);
+ /* The left, top, right and bottom parameters are handled
+ by compute_tip_xy so they can be ignored here. */
+ if (!EQ (parm, Qleft) && !EQ (parm, Qtop)
+ && !EQ (parm, Qright) && !EQ (parm, Qbottom))
+ {
+ last = Fassq (parm, tip_last_parms);
+ if (NILP (Fequal (Fcdr (elt), Fcdr (last))))
+ {
+ /* We lost, delete the old tooltip. */
+ delete = true;
+ break;
+ }
+ else
+ tip_last_parms =
+ call2 (intern ("assq-delete-all"), parm, tip_last_parms);
+ }
+ else
+ tip_last_parms =
+ call2 (intern ("assq-delete-all"), parm, tip_last_parms);
+ }
+
+ /* Now check if every parameter in what is left of
+ tip_last_parms with a non-nil value has an association in
+ PARMS. */
+ for (tail = tip_last_parms; CONSP (tail); tail = XCDR (tail))
+ {
+ elt = XCAR (tail);
+ parm = Fcar (elt);
+ if (!EQ (parm, Qleft) && !EQ (parm, Qtop) && !EQ (parm, Qright)
+ && !EQ (parm, Qbottom) && !NILP (Fcdr (elt)))
+ {
+ /* We lost, delete the old tooltip. */
+ delete = true;
+ break;
+ }
+ }
+
+ x_hide_tip (delete);
+ }
+ else
+ x_hide_tip (true);
+ }
+ else
+ x_hide_tip (true);
+
+ tip_last_frame = frame;
+ tip_last_string = string;
+ tip_last_parms = parms;
- t = gui_display_get_arg (NULL, parms, Qbackground_color, NULL, NULL,
- RES_TYPE_STRING);
- if (ns_lisp_to_color (t, &color) == 0)
- [ns_tooltip setBackgroundColor: color];
+ if (NILP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame)))
+ {
+ /* Add default values to frame parameters. */
+ if (NILP (Fassq (Qname, parms)))
+ parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
+ if (NILP (Fassq (Qinternal_border_width, parms)))
+ parms = Fcons (Fcons (Qinternal_border_width, make_fixnum (3)), parms);
+ if (NILP (Fassq (Qborder_width, parms)))
+ parms = Fcons (Fcons (Qborder_width, make_fixnum (1)), parms);
+ if (NILP (Fassq (Qborder_color, parms)))
+ parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
+ if (NILP (Fassq (Qbackground_color, parms)))
+ parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
+ parms);
+
+ /* Create a frame for the tooltip, and record it in the global
+ variable tip_frame. */
+ if (NILP (tip_frame = ns_create_tip_frame (FRAME_DISPLAY_INFO (f), parms)))
+ /* Creating the tip frame failed. */
+ return unbind_to (count, Qnil);
+ }
- t = gui_display_get_arg (NULL, parms, Qforeground_color, NULL, NULL,
- RES_TYPE_STRING);
- if (ns_lisp_to_color (t, &color) == 0)
- [ns_tooltip setForegroundColor: color];
+ tip_f = XFRAME (tip_frame);
+ window = FRAME_ROOT_WINDOW (tip_f);
+ tip_buf = Fget_buffer_create (tip, Qnil);
+ /* We will mark the tip window a "pseudo-window" below, and such
+ windows cannot have display margins. */
+ bset_left_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
+ bset_right_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
+ set_window_buffer (window, tip_buf, false, false);
+ w = XWINDOW (window);
+ w->pseudo_window_p = true;
+ /* Try to avoid that `other-window' select us (Bug#47207). */
+ Fset_window_parameter (window, Qno_other_window, Qt);
+
+ /* Set up the frame's root window. Note: The following code does not
+ try to size the window or its frame correctly. Its only purpose is
+ to make the subsequent text size calculations work. The right
+ sizes should get installed when the toolkit gets back to us. */
+ w->left_col = 0;
+ w->top_line = 0;
+ w->pixel_left = 0;
+ w->pixel_top = 0;
+
+ if (CONSP (Vx_max_tooltip_size)
+ && RANGED_FIXNUMP (1, XCAR (Vx_max_tooltip_size), INT_MAX)
+ && RANGED_FIXNUMP (1, XCDR (Vx_max_tooltip_size), INT_MAX))
+ {
+ w->total_cols = XFIXNAT (XCAR (Vx_max_tooltip_size));
+ w->total_lines = XFIXNAT (XCDR (Vx_max_tooltip_size));
+ }
+ else
+ {
+ w->total_cols = 80;
+ w->total_lines = 40;
+ }
- [ns_tooltip setText: str];
- size = [ns_tooltip frame].size;
+ w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (tip_f);
+ w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (tip_f);
+ FRAME_TOTAL_COLS (tip_f) = w->total_cols;
+ adjust_frame_glyphs (tip_f);
+
+ /* Insert STRING into root window's buffer and fit the frame to the
+ buffer. */
+ count_1 = SPECPDL_INDEX ();
+ old_buffer = current_buffer;
+ set_buffer_internal_1 (XBUFFER (w->contents));
+ bset_truncate_lines (current_buffer, Qnil);
+ specbind (Qinhibit_read_only, Qt);
+ specbind (Qinhibit_modification_hooks, Qt);
+ specbind (Qinhibit_point_motion_hooks, Qt);
+ Ferase_buffer ();
+ Finsert (1, &string);
+ clear_glyph_matrix (w->desired_matrix);
+ clear_glyph_matrix (w->current_matrix);
+ SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
+ try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
+ /* Calculate size of tooltip window. */
+ size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil,
+ make_fixnum (w->pixel_height), Qnil,
+ Qnil);
+ /* Add the frame's internal border to calculated size. */
+ width = XFIXNUM (Fcar (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
+ height = XFIXNUM (Fcdr (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
+
+ /* Calculate position of tooltip frame. */
+ compute_tip_xy (tip_f, parms, dx, dy, width,
+ height, &root_x, &root_y);
+
+ block_input ();
+ nswindow = [FRAME_NS_VIEW (tip_f) window];
+ [nswindow setFrame: NSMakeRect (root_x, root_y,
+ width, height)
+ display: YES];
+ [nswindow setLevel: NSPopUpMenuWindowLevel];
+ [nswindow orderFront: NSApp];
+ [nswindow display];
+
+ SET_FRAME_VISIBLE (tip_f, YES);
+ FRAME_PIXEL_WIDTH (tip_f) = width;
+ FRAME_PIXEL_HEIGHT (tip_f) = height;
+ unblock_input ();
- /* Move the tooltip window where the mouse pointer is. Resize and
- show it. */
- compute_tip_xy (f, parms, dx, dy, (int)size.width, (int)size.height,
- &root_x, &root_y);
+ w->must_be_updated_p = true;
+ update_single_window (w);
+ flush_frame (tip_f);
+ set_buffer_internal_1 (old_buffer);
+ unbind_to (count_1, Qnil);
+ windows_or_buffers_changed = old_windows_or_buffers_changed;
- [ns_tooltip showAtX: root_x Y: root_y for: XFIXNUM (timeout)];
- unblock_input ();
+ start_timer:
+ /* Let the tip disappear after timeout seconds. */
+ tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
+ intern ("x-hide-tip"));
+ }
return unbind_to (count, Qnil);
}
@@ -2914,10 +3457,7 @@ DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
doc: /* SKIP: real doc in xfns.c. */)
(void)
{
- if (ns_tooltip == nil || ![ns_tooltip isActive])
- return Qnil;
- [ns_tooltip hide];
- return Qt;
+ return x_hide_tip (!tooltip_reuse_hidden_frame);
}
/* Return geometric attributes of FRAME. According to the value of
@@ -3260,6 +3800,10 @@ be used as the image of the icon representing the frame. */);
Default is t. */);
ns_use_proxy_icon = true;
+ DEFVAR_LISP ("x-max-tooltip-size", Vx_max_tooltip_size,
+ doc: /* SKIP: real doc in xfns.c. */);
+ Vx_max_tooltip_size = Fcons (make_fixnum (80), make_fixnum (40));
+
defsubr (&Sns_read_file_name);
defsubr (&Sns_get_resource);
defsubr (&Sns_set_resource);
@@ -3309,6 +3853,17 @@ Default is t. */);
defsubr (&Sx_show_tip);
defsubr (&Sx_hide_tip);
+ tip_timer = Qnil;
+ staticpro (&tip_timer);
+ tip_frame = Qnil;
+ staticpro (&tip_frame);
+ tip_last_frame = Qnil;
+ staticpro (&tip_last_frame);
+ tip_last_string = Qnil;
+ staticpro (&tip_last_string);
+ tip_last_parms = Qnil;
+ staticpro (&tip_last_parms);
+
#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
defsubr (&Ssystem_move_file_to_trash);
#endif
diff --git a/src/nsterm.h b/src/nsterm.h
index ce2355e6b1c..1135225e7b1 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -1176,6 +1176,7 @@ extern size_t ns_image_size_in_bytes (void *img);
/* This in nsterm.m */
extern float ns_antialias_threshold;
extern void ns_make_frame_visible (struct frame *f);
+extern void ns_make_frame_invisible (struct frame *f);
extern void ns_iconify_frame (struct frame *f);
extern void ns_set_undecorated (struct frame *f, Lisp_Object new_value,
Lisp_Object old_value);
diff --git a/src/nsterm.m b/src/nsterm.m
index 9dff33da509..a1cbbff1cc6 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -1517,7 +1517,7 @@ ns_make_frame_visible (struct frame *f)
}
-static void
+void
ns_make_frame_invisible (struct frame *f)
/* --------------------------------------------------------------------------
Hide the window (X11 semantics)
@@ -1708,10 +1708,8 @@ ns_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
static void
-ns_set_window_size (struct frame *f,
- bool change_gravity,
- int width,
- int height)
+ns_set_window_size (struct frame *f, bool change_gravity,
+ int width, int height)
/* --------------------------------------------------------------------------
Adjust window pixel size based on native sizes WIDTH and HEIGHT.
Impl is a bit more complex than other terms, need to do some
@@ -8729,17 +8727,18 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
@implementation EmacsWindow
-- (instancetype) initWithEmacsFrame:(struct frame *)f
+- (instancetype) initWithEmacsFrame: (struct frame *) f
{
return [self initWithEmacsFrame:f fullscreen:NO screen:nil];
}
-- (instancetype) initWithEmacsFrame:(struct frame *)f
- fullscreen:(BOOL)fullscreen
- screen:(NSScreen *)screen
+- (instancetype) initWithEmacsFrame: (struct frame *) f
+ fullscreen: (BOOL) fullscreen
+ screen: (NSScreen *) screen
{
NSWindowStyleMask styleMask;
+ int width, height;
NSTRACE ("[EmacsWindow initWithEmacsFrame:fullscreen:screen:]");
@@ -8752,20 +8751,22 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
styleMask |= NSWindowStyleMaskResizable;
#endif
}
+ else if (f->tooltip)
+ styleMask = 0;
else
- styleMask = NSWindowStyleMaskTitled
- | NSWindowStyleMaskResizable
- | NSWindowStyleMaskMiniaturizable
- | NSWindowStyleMaskClosable;
-
- self = [super initWithContentRect:
- NSMakeRect (0, 0,
- FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
- FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines))
- styleMask:styleMask
- backing:NSBackingStoreBuffered
- defer:YES
- screen:screen];
+ styleMask = (NSWindowStyleMaskTitled
+ | NSWindowStyleMaskResizable
+ | NSWindowStyleMaskMiniaturizable
+ | NSWindowStyleMaskClosable);
+
+ width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols);
+ height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines);
+
+ self = [super initWithContentRect: NSMakeRect (0, 0, width, height)
+ styleMask: styleMask
+ backing: NSBackingStoreBuffered
+ defer: YES
+ screen: screen];
if (self)
{
NSString *name;