Subject: bug#40513: Tooltips with images

From: martin rudalics <[email-masked]>
Date: Sat, 11 Apr 2020 10:32:37 +0200

> This bug report is probably related to #40047.

Despite the fact that both reports ask for tooltips to show images, they
are not related.  The behavior you see can be easily reproduced without
using an image as display property.

 > I experience some weird behavior with tooltips.
 >
 > (progn
 >    (let* ((start (point))
 >           (end (progn (insert "test") (point)))
 >           (ov (make-overlay start end)))
 >      (overlay-put ov 'help-echo
 >                   (propertize "xxx" 'display '(image :type jpeg :file
 > "~/foo.jpg"))))
 >    (display-buffer-other-frame (get-buffer-create "dummy")))
 >
 >
 > After evaluating this code (Do not click anywhere, this is important.)
 > and moving the mouse pointer over "test" I get a tooltip displaying the
 > image file foo.jpg. The tooltip appears as a box with a light yellow
 > background color with sharp corners.
 >
 > But the moment I click anywhere on the desktop (not necessarily on an
 > emacs frame) this tooltip changes it's appearance. Now
 > the tooltip contains no image but the text "xxx". Furthermore the tooltip
 > appears as a transparent black box with rounded corners.
 >
 > I suppose that the first tooltip I'm seeing is an emacs-tooltip while
 > the second one is a gtk-tooltip.

Correct.

 > The code line creating an empty buffer is important. Without this line I
 > never see the emacs-tooltip, but always the gtk-tooltip.

The crucial aspect here is that of popping up a new frame.

 > The tests were done with (setq x-gtk-use-system-tooltips t).
 >
 > After setting (setq x-gtk-use-system-tooltips nil) the tooltip does not
 > change any more. Now I always get an emacs-tooltip.

The behavior you experience is strange and I have no full explanation
for it.  From the Emacs side it's all quite clear: When you move the
mouse over "test", Emacs is informed that it should provide a tooltip
text and position.  When it tries to show that tooltip via 'x-show-tip'
in xfns.c, that function calls xg_prepare_tooltip in gtkutil.c which
returns FALSE because the value of the tooltip label (ttip_lbl) for the
frame showing dummy has not been assigned yet (qttip_cb has not been run
for that frame yet).

As a consequence, the value of OK in 'x-show-tip' is false and due to
its logic 'x-show-tip' assumes that for some reason GTK cannot show the
tooltip and it will try to show a native Emacs tooltip instead.  That's
what you see first.  Later, and in particular after you have clicked
into any of your frames, the values of ttip_lbl will have been orderly
set up for all frames and you will see the GTK tooltips as requested.

Why GTK asks us to display the tooltip _for_ the dummy frame is beyond
my knowledge.  It's probably due to the fact that our window managers
automatically put focus on the new, dummy frame while the mouse pointer
hovers over the old *scratch* frame without selecting/focusing it.  Try
your example with

(setq default-frame-alist '((no-focus-on-map . t)))

set initially and you shouldn't be able to reproduce your scenario.

Note that I can reproduce your behavior despite of the fact that I'm
using focus follows mouse - as long as I don't move the mouse from
_elsewhere_ into the *scratch* frame, that frame does not get focus.  So
here I just have to make sure that the mouse pointer will be over the
*scratch* frame when the dummy frame gets created.  Unfortunately, the
problem cannot be debugged via GDB because anything you do in the
debugger window will distract the original focus.

In either case, I don't think that all this should be of any importance
for you: If you want to show an image in a tooltip, you will have to use
the native Emacs tooltip anyway, so set 'x-gtk-use-system-tooltips' to
nil and you are done.  If you insist on using GTK tooltips (something I
recommend only to hardcore GTK fans) you will have to live with the fact
that sometimes a native Emacs tooltip will pop up in case GTK has not
caught up with initializing the tooltip data for a new frame.

martin