aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorYuuki Harano2020-08-15 01:13:52 +0900
committerJeff Walsh2020-11-24 12:24:40 +1100
commit2dd20b2d7595877b7c733fa52695905c920a9d2a (patch)
tree54d6b8a7570088e5dd51e543ba8eb2f22155e2de /src
parent51462ce2ccae6461384b44ef7dfbc11d27465be8 (diff)
downloademacs-2dd20b2d7595877b7c733fa52695905c920a9d2a.tar.gz
emacs-2dd20b2d7595877b7c733fa52695905c920a9d2a.zip
Self-implement tooltip
* src/gtkutil.c (xg_create_frame_widgets): Use popup for tooltip. * src/pgtkfns.c (unwind_create_tip_frame): Port X code. (x_create_tip_frame): Re-port X code. (x_hide_tip): Re-port X code. (Fx_show_tip): Re-port X code. (frame_geometry): Get left_pos and top_pos here. (syms_of_pgtkfns): Add variables for tooltip. * src/pgtkterm.c (pgtk_set_event_handler): Set event handler for tooltip.
Diffstat (limited to 'src')
-rw-r--r--src/gtkutil.c7
-rw-r--r--src/pgtkfns.c644
-rw-r--r--src/pgtkterm.c7
3 files changed, 601 insertions, 57 deletions
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 97a8e4a5c1f..3956c581d9d 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -1355,9 +1355,10 @@ xg_create_frame_widgets (struct frame *f)
1355 else 1355 else
1356 wtop = gtk_window_new (type); 1356 wtop = gtk_window_new (type);
1357#else 1357#else
1358 if (!NILP(f->parent_frame)) { 1358 if (!NILP(f->parent_frame) || f->tooltip)
1359 type = GTK_WINDOW_POPUP; 1359 {
1360 } 1360 type = GTK_WINDOW_POPUP;
1361 }
1361 wtop = gtk_window_new (type); 1362 wtop = gtk_window_new (type);
1362 gtk_widget_add_events(wtop, GDK_ALL_EVENTS_MASK); 1363 gtk_widget_add_events(wtop, GDK_ALL_EVENTS_MASK);
1363#endif 1364#endif
diff --git a/src/pgtkfns.c b/src/pgtkfns.c
index a4da3302ef9..53da9b756aa 100644
--- a/src/pgtkfns.c
+++ b/src/pgtkfns.c
@@ -2421,15 +2421,311 @@ If omitted or nil, that stands for the selected frame's display. */)
2421 Tool tips 2421 Tool tips
2422 ***********************************************************************/ 2422 ***********************************************************************/
2423 2423
2424/* The frame of a currently visible tooltip. */ 2424/* The frame of the currently visible tooltip. */
2425static Lisp_Object tip_frame;
2425 2426
2426Lisp_Object tip_frame; 2427/* The window-system window corresponding to the frame of the
2428 currently visible tooltip. */
2429GtkWidget *tip_window;
2427 2430
2428/* If non-nil, a timer started that hides the last tooltip when it 2431/* A timer that hides or deletes the currently visible tooltip when it
2429 fires. */ 2432 fires. */
2430
2431static Lisp_Object tip_timer; 2433static Lisp_Object tip_timer;
2432 2434
2435/* STRING argument of last `x-show-tip' call. */
2436static Lisp_Object tip_last_string;
2437
2438/* Normalized FRAME argument of last `x-show-tip' call. */
2439static Lisp_Object tip_last_frame;
2440
2441/* PARMS argument of last `x-show-tip' call. */
2442static Lisp_Object tip_last_parms;
2443
2444
2445static void
2446unwind_create_tip_frame (Lisp_Object frame)
2447{
2448 Lisp_Object deleted;
2449
2450 deleted = unwind_create_frame (frame);
2451 if (EQ (deleted, Qt))
2452 {
2453 tip_window = NULL;
2454 tip_frame = Qnil;
2455 }
2456}
2457
2458
2459/* Create a frame for a tooltip on the display described by DPYINFO.
2460 PARMS is a list of frame parameters. TEXT is the string to
2461 display in the tip frame. Value is the frame.
2462
2463 Note that functions called here, esp. gui_default_parameter can
2464 signal errors, for instance when a specified color name is
2465 undefined. We have to make sure that we're in a consistent state
2466 when this happens. */
2467
2468static Lisp_Object
2469x_create_tip_frame (struct pgtk_display_info *dpyinfo, Lisp_Object parms, struct frame *p)
2470{
2471 struct frame *f;
2472 Lisp_Object frame;
2473 Lisp_Object name;
2474 int width, height;
2475 ptrdiff_t count = SPECPDL_INDEX ();
2476 bool face_change_before = face_change;
2477 int x_width = 0, x_height = 0;
2478
2479 if (!dpyinfo->terminal->name)
2480 error ("Terminal is not live, can't create new frames on it");
2481
2482 parms = Fcopy_alist (parms);
2483
2484 /* Get the name of the frame to use for resource lookup. */
2485 name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name",
2486 RES_TYPE_STRING);
2487 if (!STRINGP (name)
2488 && !EQ (name, Qunbound)
2489 && !NILP (name))
2490 error ("Invalid frame name--not a string or nil");
2491
2492 frame = Qnil;
2493 f = make_frame (false);
2494 f->wants_modeline = false;
2495 XSETFRAME (frame, f);
2496 record_unwind_protect (unwind_create_tip_frame, frame);
2497
2498 f->terminal = dpyinfo->terminal;
2499
2500 /* By setting the output method, we're essentially saying that
2501 the frame is live, as per FRAME_LIVE_P. If we get a signal
2502 from this point on, x_destroy_window might screw up reference
2503 counts etc. */
2504 f->output_method = output_pgtk;
2505 f->output_data.pgtk = xzalloc (sizeof *f->output_data.pgtk);
2506#if 0
2507 f->output_data.pgtk->icon_bitmap = -1;
2508#endif
2509 FRAME_FONTSET (f) = -1;
2510 f->output_data.pgtk->white_relief.pixel = -1;
2511 f->output_data.pgtk->black_relief.pixel = -1;
2512
2513 f->tooltip = true;
2514 fset_icon_name (f, Qnil);
2515 FRAME_DISPLAY_INFO (f) = dpyinfo;
2516 f->output_data.pgtk->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
2517 f->output_data.pgtk->explicit_parent = false;
2518
2519 /* These colors will be set anyway later, but it's important
2520 to get the color reference counts right, so initialize them! */
2521 {
2522 Lisp_Object black;
2523
2524 /* Function x_decode_color can signal an error. Make
2525 sure to initialize color slots so that we won't try
2526 to free colors we haven't allocated. */
2527 FRAME_FOREGROUND_PIXEL (f) = -1;
2528 FRAME_BACKGROUND_PIXEL (f) = -1;
2529 f->output_data.pgtk->border_pixel = -1;
2530
2531 black = build_string ("black");
2532 FRAME_FOREGROUND_PIXEL (f)
2533 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
2534 FRAME_BACKGROUND_PIXEL (f)
2535 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
2536 f->output_data.pgtk->border_pixel
2537 = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
2538 }
2539
2540 /* Set the name; the functions to which we pass f expect the name to
2541 be set. */
2542 if (EQ (name, Qunbound) || NILP (name))
2543 {
2544 fset_name (f, build_string (dpyinfo->x_id_name));
2545 f->explicit_name = false;
2546 }
2547 else
2548 {
2549 fset_name (f, name);
2550 f->explicit_name = true;
2551 /* use the frame's title when getting resources for this frame. */
2552 specbind (Qx_resource_name, name);
2553 }
2554
2555 register_font_driver (&ftcrfont_driver, f);
2556#ifdef HAVE_HARFBUZZ
2557 register_font_driver (&ftcrhbfont_driver, f);
2558#endif /* HAVE_HARFBUZZ */
2559
2560 image_cache_refcount =
2561 FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
2562#ifdef GLYPH_DEBUG
2563 dpyinfo_refcount = dpyinfo->reference_count;
2564#endif /* GLYPH_DEBUG */
2565
2566 gui_default_parameter (f, parms, Qfont_backend, Qnil,
2567 "fontBackend", "FontBackend", RES_TYPE_STRING);
2568
2569 /* Extract the window parameters from the supplied values that are
2570 needed to determine window geometry. */
2571 pgtk_default_font_parameter (f, parms);
2572
2573 gui_default_parameter (f, parms, Qborder_width, make_fixnum (0),
2574 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
2575
2576 /* This defaults to 2 in order to match xterm. We recognize either
2577 internalBorderWidth or internalBorder (which is what xterm calls
2578 it). */
2579 if (NILP (Fassq (Qinternal_border_width, parms)))
2580 {
2581 Lisp_Object value;
2582
2583 value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width,
2584 "internalBorder", "internalBorder",
2585 RES_TYPE_NUMBER);
2586 if (! EQ (value, Qunbound))
2587 parms = Fcons (Fcons (Qinternal_border_width, value),
2588 parms);
2589 }
2590
2591 gui_default_parameter (f, parms, Qinternal_border_width, make_fixnum (1),
2592 "internalBorderWidth", "internalBorderWidth",
2593 RES_TYPE_NUMBER);
2594 gui_default_parameter (f, parms, Qright_divider_width, make_fixnum (0),
2595 NULL, NULL, RES_TYPE_NUMBER);
2596 gui_default_parameter (f, parms, Qbottom_divider_width, make_fixnum (0),
2597 NULL, NULL, RES_TYPE_NUMBER);
2598
2599 /* Also do the stuff which must be set before the window exists. */
2600 gui_default_parameter (f, parms, Qforeground_color, build_string ("black"),
2601 "foreground", "Foreground", RES_TYPE_STRING);
2602 gui_default_parameter (f, parms, Qbackground_color, build_string ("white"),
2603 "background", "Background", RES_TYPE_STRING);
2604 gui_default_parameter (f, parms, Qmouse_color, build_string ("black"),
2605 "pointerColor", "Foreground", RES_TYPE_STRING);
2606 gui_default_parameter (f, parms, Qcursor_color, build_string ("black"),
2607 "cursorColor", "Foreground", RES_TYPE_STRING);
2608 gui_default_parameter (f, parms, Qborder_color, build_string ("black"),
2609 "borderColor", "BorderColor", RES_TYPE_STRING);
2610 gui_default_parameter (f, parms, Qno_special_glyphs, Qnil,
2611 NULL, NULL, RES_TYPE_BOOLEAN);
2612
2613 /* Init faces before gui_default_parameter is called for the
2614 scroll-bar-width parameter because otherwise we end up in
2615 init_iterator with a null face cache, which should not happen. */
2616 init_frame_faces (f);
2617
2618 f->output_data.pgtk->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
2619
2620 gui_default_parameter (f, parms, Qinhibit_double_buffering, Qnil,
2621 "inhibitDoubleBuffering", "InhibitDoubleBuffering",
2622 RES_TYPE_BOOLEAN);
2623
2624 gui_figure_window_size (f, parms, false, false, &x_width, &x_height);
2625
2626 xg_create_frame_widgets (f);
2627 pgtk_set_event_handler (f);
2628 tip_window = FRAME_GTK_OUTER_WIDGET (f);
2629 gtk_window_set_transient_for (GTK_WINDOW (tip_window),
2630 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (p)));
2631 gtk_window_set_attached_to (GTK_WINDOW (tip_window), FRAME_GTK_WIDGET (p));
2632 gtk_window_set_destroy_with_parent (GTK_WINDOW (tip_window), TRUE);
2633 gtk_window_set_decorated (GTK_WINDOW (tip_window), FALSE);
2634 gtk_window_set_type_hint (GTK_WINDOW (tip_window), GDK_WINDOW_TYPE_HINT_TOOLTIP);
2635 f->output_data.pgtk->current_cursor = f->output_data.pgtk->text_cursor;
2636 gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
2637 gdk_window_set_cursor (gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f)),
2638 f->output_data.pgtk->current_cursor);
2639
2640#if 0
2641 x_make_gc (f);
2642#endif
2643
2644 gui_default_parameter (f, parms, Qauto_raise, Qnil,
2645 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
2646 gui_default_parameter (f, parms, Qauto_lower, Qnil,
2647 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
2648 gui_default_parameter (f, parms, Qcursor_type, Qbox,
2649 "cursorType", "CursorType", RES_TYPE_SYMBOL);
2650 gui_default_parameter (f, parms, Qalpha, Qnil,
2651 "alpha", "Alpha", RES_TYPE_NUMBER);
2652
2653 /* Dimensions, especially FRAME_LINES (f), must be done via change_frame_size.
2654 Change will not be effected unless different from the current
2655 FRAME_LINES (f). */
2656 width = FRAME_COLS (f);
2657 height = FRAME_LINES (f);
2658 SET_FRAME_COLS (f, 0);
2659 SET_FRAME_LINES (f, 0);
2660 change_frame_size (f, width, height, true, false, false, false);
2661
2662 /* Add `tooltip' frame parameter's default value. */
2663 if (NILP (Fframe_parameter (frame, Qtooltip)))
2664 {
2665 AUTO_FRAME_ARG (arg, Qtooltip, Qt);
2666 Fmodify_frame_parameters (frame, arg);
2667 }
2668
2669 /* FIXME - can this be done in a similar way to normal frames?
2670 https://lists.gnu.org/r/emacs-devel/2007-10/msg00641.html */
2671
2672 /* Set the `display-type' frame parameter before setting up faces. */
2673 {
2674 Lisp_Object disptype;
2675
2676 disptype = intern ("color");
2677
2678 if (NILP (Fframe_parameter (frame, Qdisplay_type)))
2679 {
2680 AUTO_FRAME_ARG (arg, Qdisplay_type, disptype);
2681 Fmodify_frame_parameters (frame, arg);
2682 }
2683 }
2684
2685 /* Set up faces after all frame parameters are known. This call
2686 also merges in face attributes specified for new frames.
2687
2688 Frame parameters may be changed if .Xdefaults contains
2689 specifications for the default font. For example, if there is an
2690 `Emacs.default.attributeBackground: pink', the `background-color'
2691 attribute of the frame get's set, which let's the internal border
2692 of the tooltip frame appear in pink. Prevent this. */
2693 {
2694 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
2695
2696 call2 (Qface_set_after_frame_default, frame, Qnil);
2697
2698 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
2699 {
2700 AUTO_FRAME_ARG (arg, Qbackground_color, bg);
2701 Fmodify_frame_parameters (frame, arg);
2702 }
2703 }
2704
2705 f->no_split = true;
2706
2707 /* Now that the frame will be official, it counts as a reference to
2708 its display and terminal. */
2709 FRAME_DISPLAY_INFO (f)->reference_count++;
2710 f->terminal->reference_count++;
2711
2712 /* It is now ok to make the frame official even if we get an error
2713 below. And the frame needs to be on Vframe_list or making it
2714 visible won't work. */
2715 Vframe_list = Fcons (frame, Vframe_list);
2716 f->can_set_window_size = true;
2717
2718 /* Setting attributes of faces of the tooltip frame from resources
2719 and similar will set face_change, which leads to the clearing of
2720 all current matrices. Since this isn't necessary here, avoid it
2721 by resetting face_change to the value it had before we created
2722 the tip frame. */
2723 face_change = face_change_before;
2724
2725 /* Discard the unwind_protect. */
2726 return unbind_to (count, frame);
2727}
2728
2433/* Compute where to display tip frame F. PARMS is the list of frame 2729/* Compute where to display tip frame F. PARMS is the list of frame
2434 parameters for F. DX and DY are specified offsets from the current 2730 parameters for F. DX and DY are specified offsets from the current
2435 location of the mouse. WIDTH and HEIGHT are the width and height 2731 location of the mouse. WIDTH and HEIGHT are the width and height
@@ -2546,9 +2842,20 @@ x_hide_tip (bool delete)
2546 tip_timer = Qnil; 2842 tip_timer = Qnil;
2547 } 2843 }
2548 2844
2549 if (NILP (tip_frame) 2845 /* Any GTK+ system tooltip can be found via the x_output structure of
2550 || (!delete && FRAMEP (tip_frame) 2846 tip_last_frame, provided that frame is still live. Any Emacs
2847 tooltip is found via the tip_frame variable. Note that the current
2848 value of x_gtk_use_system_tooltips might not be the same as used
2849 for the tooltip we have to hide, see Bug#30399. */
2850 if ((NILP (tip_last_frame) && NILP (tip_frame))
2851 || (!x_gtk_use_system_tooltips
2852 && !delete
2853 && FRAMEP (tip_frame)
2854 && FRAME_LIVE_P (XFRAME (tip_frame))
2551 && !FRAME_VISIBLE_P (XFRAME (tip_frame)))) 2855 && !FRAME_VISIBLE_P (XFRAME (tip_frame))))
2856 /* Either there's no tooltip to hide or it's an already invisible
2857 Emacs tooltip and we don't want to change its type. Return
2858 quickly. */
2552 return Qnil; 2859 return Qnil;
2553 else 2860 else
2554 { 2861 {
@@ -2559,29 +2866,46 @@ x_hide_tip (bool delete)
2559 specbind (Qinhibit_redisplay, Qt); 2866 specbind (Qinhibit_redisplay, Qt);
2560 specbind (Qinhibit_quit, Qt); 2867 specbind (Qinhibit_quit, Qt);
2561 2868
2562 { 2869 /* Try to hide the GTK+ system tip first. */
2563 /* When using system tooltip, tip_frame is the Emacs frame on 2870 if (FRAMEP (tip_last_frame))
2564 which the tip is shown. */ 2871 {
2565 struct frame *f = XFRAME (tip_frame); 2872 struct frame *f = XFRAME (tip_last_frame);
2566 2873
2567 if (FRAME_LIVE_P (f) && xg_hide_tooltip (f)) 2874 if (FRAME_LIVE_P (f))
2568 { 2875 {
2569 tip_frame = Qnil; 2876 if (xg_hide_tooltip (f))
2570 was_open = Qt; 2877 was_open = Qt;
2571 } 2878 }
2572 } 2879 }
2573 2880
2881 /* When using GTK+ system tooltips (compare Bug#41200) reset
2882 tip_last_frame. It will be reassigned when showing the next
2883 GTK+ system tooltip. */
2884 if (x_gtk_use_system_tooltips)
2885 tip_last_frame = Qnil;
2886
2887 /* Now look whether there's an Emacs tip around. */
2574 if (FRAMEP (tip_frame)) 2888 if (FRAMEP (tip_frame))
2575 { 2889 {
2576 if (delete) 2890 struct frame *f = XFRAME (tip_frame);
2891
2892 if (FRAME_LIVE_P (f))
2577 { 2893 {
2578 delete_frame (tip_frame, Qnil); 2894 if (delete || x_gtk_use_system_tooltips)
2579 tip_frame = Qnil; 2895 {
2896 /* Delete the Emacs tooltip frame when DELETE is true
2897 or we change the tooltip type from an Emacs one to
2898 a GTK+ system one. */
2899 delete_frame (tip_frame, Qnil);
2900 tip_frame = Qnil;
2901 }
2902 else
2903 pgtk_make_frame_invisible (f);
2904
2905 was_open = Qt;
2580 } 2906 }
2581 else 2907 else
2582 pgtk_make_frame_invisible (XFRAME (tip_frame)); 2908 tip_frame = Qnil;
2583
2584 was_open = Qt;
2585 } 2909 }
2586 else 2910 else
2587 tip_frame = Qnil; 2911 tip_frame = Qnil;
@@ -2623,10 +2947,17 @@ Text larger than the specified size is clipped. */)
2623 (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, 2947 (Lisp_Object string, Lisp_Object frame, Lisp_Object parms,
2624 Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy) 2948 Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy)
2625{ 2949{
2626 struct frame *f; 2950 struct frame *f, *tip_f;
2951 struct window *w;
2627 int root_x, root_y; 2952 int root_x, root_y;
2953 struct buffer *old_buffer;
2954 struct text_pos pos;
2628 int width, height; 2955 int width, height;
2956 int old_windows_or_buffers_changed = windows_or_buffers_changed;
2629 ptrdiff_t count = SPECPDL_INDEX (); 2957 ptrdiff_t count = SPECPDL_INDEX ();
2958 ptrdiff_t count_1;
2959 Lisp_Object window, size, tip_buf;
2960 AUTO_STRING (tip, " *tip*");
2630 2961
2631 specbind (Qinhibit_redisplay, Qt); 2962 specbind (Qinhibit_redisplay, Qt);
2632 2963
@@ -2634,7 +2965,10 @@ Text larger than the specified size is clipped. */)
2634 if (SCHARS (string) == 0) 2965 if (SCHARS (string) == 0)
2635 string = make_unibyte_string (" ", 1); 2966 string = make_unibyte_string (" ", 1);
2636 2967
2968 if (NILP (frame))
2969 frame = selected_frame;
2637 f = decode_window_system_frame (frame); 2970 f = decode_window_system_frame (frame);
2971
2638 if (NILP (timeout)) 2972 if (NILP (timeout))
2639 timeout = make_fixnum (5); 2973 timeout = make_fixnum (5);
2640 else 2974 else
@@ -2643,34 +2977,218 @@ Text larger than the specified size is clipped. */)
2643 if (NILP (dx)) 2977 if (NILP (dx))
2644 dx = make_fixnum (5); 2978 dx = make_fixnum (5);
2645 else 2979 else
2646 CHECK_NUMBER (dx); 2980 CHECK_FIXNUM (dx);
2647 2981
2648 if (NILP (dy)) 2982 if (NILP (dy))
2649 dy = make_fixnum (-10); 2983 dy = make_fixnum (-10);
2650 else 2984 else
2651 CHECK_NUMBER (dy); 2985 CHECK_FIXNUM (dy);
2652 2986
2653 { 2987 if (x_gtk_use_system_tooltips)
2654 bool ok; 2988 {
2989 bool ok;
2655 2990
2656 /* Hide a previous tip, if any. */ 2991 /* Hide a previous tip, if any. */
2657 Fx_hide_tip (); 2992 Fx_hide_tip ();
2658 2993
2659 block_input (); 2994 block_input ();
2660 ok = xg_prepare_tooltip (f, string, &width, &height); 2995 ok = xg_prepare_tooltip (f, string, &width, &height);
2661 if (ok) 2996 if (ok)
2662 { 2997 {
2663 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y); 2998 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
2664 xg_show_tooltip (f, root_x, root_y); 2999 xg_show_tooltip (f, root_x, root_y);
2665 /* This is used in Fx_hide_tip. */ 3000 tip_last_frame = frame;
2666 XSETFRAME (tip_frame, f); 3001 }
2667 } 3002
2668 unblock_input (); 3003 unblock_input ();
2669 if (ok) 3004 if (ok) goto start_timer;
2670 goto start_timer; 3005 }
2671 } 3006
3007 if (FRAMEP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
3008 {
3009 if (FRAME_VISIBLE_P (XFRAME (tip_frame))
3010 && EQ (frame, tip_last_frame)
3011 && !NILP (Fequal_including_properties (tip_last_string, string))
3012 && !NILP (Fequal (tip_last_parms, parms)))
3013 {
3014 /* Only DX and DY have changed. */
3015 tip_f = XFRAME (tip_frame);
3016 if (!NILP (tip_timer))
3017 {
3018 call1 (Qcancel_timer, tip_timer);
3019 tip_timer = Qnil;
3020 }
3021
3022 block_input ();
3023 compute_tip_xy (tip_f, parms, dx, dy, FRAME_PIXEL_WIDTH (tip_f),
3024 FRAME_PIXEL_HEIGHT (tip_f), &root_x, &root_y);
3025 gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (tip_f)), root_x, root_y);
3026 unblock_input ();
3027
3028 goto start_timer;
3029 }
3030 else if (tooltip_reuse_hidden_frame && EQ (frame, tip_last_frame))
3031 {
3032 bool delete = false;
3033 Lisp_Object tail, elt, parm, last;
3034
3035 /* Check if every parameter in PARMS has the same value in
3036 tip_last_parms. This may destruct tip_last_parms which,
3037 however, will be recreated below. */
3038 for (tail = parms; CONSP (tail); tail = XCDR (tail))
3039 {
3040 elt = XCAR (tail);
3041 parm = Fcar (elt);
3042 /* The left, top, right and bottom parameters are handled
3043 by compute_tip_xy so they can be ignored here. */
3044 if (!EQ (parm, Qleft) && !EQ (parm, Qtop)
3045 && !EQ (parm, Qright) && !EQ (parm, Qbottom))
3046 {
3047 last = Fassq (parm, tip_last_parms);
3048 if (NILP (Fequal (Fcdr (elt), Fcdr (last))))
3049 {
3050 /* We lost, delete the old tooltip. */
3051 delete = true;
3052 break;
3053 }
3054 else
3055 tip_last_parms =
3056 call2 (Qassq_delete_all, parm, tip_last_parms);
3057 }
3058 else
3059 tip_last_parms =
3060 call2 (Qassq_delete_all, parm, tip_last_parms);
3061 }
3062
3063 /* Now check if every parameter in what is left of
3064 tip_last_parms with a non-nil value has an association in
3065 PARMS. */
3066 for (tail = tip_last_parms; CONSP (tail); tail = XCDR (tail))
3067 {
3068 elt = XCAR (tail);
3069 parm = Fcar (elt);
3070 if (!EQ (parm, Qleft) && !EQ (parm, Qtop) && !EQ (parm, Qright)
3071 && !EQ (parm, Qbottom) && !NILP (Fcdr (elt)))
3072 {
3073 /* We lost, delete the old tooltip. */
3074 delete = true;
3075 break;
3076 }
3077 }
3078
3079 x_hide_tip (delete);
3080 }
3081 else
3082 x_hide_tip (true);
3083 }
3084 else
3085 x_hide_tip (true);
3086
3087 tip_last_frame = frame;
3088 tip_last_string = string;
3089 tip_last_parms = parms;
2672 3090
2673start_timer: 3091 if (!FRAMEP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame)))
3092 {
3093 /* Add default values to frame parameters. */
3094 if (NILP (Fassq (Qname, parms)))
3095 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
3096 if (NILP (Fassq (Qinternal_border_width, parms)))
3097 parms = Fcons (Fcons (Qinternal_border_width, make_fixnum (3)), parms);
3098 if (NILP (Fassq (Qborder_width, parms)))
3099 parms = Fcons (Fcons (Qborder_width, make_fixnum (1)), parms);
3100 if (NILP (Fassq (Qborder_color, parms)))
3101 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
3102 if (NILP (Fassq (Qbackground_color, parms)))
3103 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
3104 parms);
3105
3106 /* Create a frame for the tooltip, and record it in the global
3107 variable tip_frame. */
3108 if (NILP (tip_frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms, f)))
3109 /* Creating the tip frame failed. */
3110 return unbind_to (count, Qnil);
3111 }
3112
3113 tip_f = XFRAME (tip_frame);
3114 window = FRAME_ROOT_WINDOW (tip_f);
3115 tip_buf = Fget_buffer_create (tip);
3116 /* We will mark the tip window a "pseudo-window" below, and such
3117 windows cannot have display margins. */
3118 bset_left_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
3119 bset_right_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
3120 set_window_buffer (window, tip_buf, false, false);
3121 w = XWINDOW (window);
3122 w->pseudo_window_p = true;
3123
3124 /* Set up the frame's root window. Note: The following code does not
3125 try to size the window or its frame correctly. Its only purpose is
3126 to make the subsequent text size calculations work. The right
3127 sizes should get installed when the toolkit gets back to us. */
3128 w->left_col = 0;
3129 w->top_line = 0;
3130 w->pixel_left = 0;
3131 w->pixel_top = 0;
3132
3133 if (CONSP (Vx_max_tooltip_size)
3134 && RANGED_FIXNUMP (1, XCAR (Vx_max_tooltip_size), INT_MAX)
3135 && RANGED_FIXNUMP (1, XCDR (Vx_max_tooltip_size), INT_MAX))
3136 {
3137 w->total_cols = XFIXNAT (XCAR (Vx_max_tooltip_size));
3138 w->total_lines = XFIXNAT (XCDR (Vx_max_tooltip_size));
3139 }
3140 else
3141 {
3142 w->total_cols = 80;
3143 w->total_lines = 40;
3144 }
3145
3146 w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (tip_f);
3147 w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (tip_f);
3148 FRAME_TOTAL_COLS (tip_f) = w->total_cols;
3149 adjust_frame_glyphs (tip_f);
3150
3151 /* Insert STRING into root window's buffer and fit the frame to the
3152 buffer. */
3153 count_1 = SPECPDL_INDEX ();
3154 old_buffer = current_buffer;
3155 set_buffer_internal_1 (XBUFFER (w->contents));
3156 bset_truncate_lines (current_buffer, Qnil);
3157 specbind (Qinhibit_read_only, Qt);
3158 specbind (Qinhibit_modification_hooks, Qt);
3159 specbind (Qinhibit_point_motion_hooks, Qt);
3160 Ferase_buffer ();
3161 Finsert (1, &string);
3162 clear_glyph_matrix (w->desired_matrix);
3163 clear_glyph_matrix (w->current_matrix);
3164 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
3165 try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
3166 /* Calculate size of tooltip window. */
3167 size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil,
3168 make_fixnum (w->pixel_height), Qnil);
3169 /* Add the frame's internal border to calculated size. */
3170 width = XFIXNUM (Fcar (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
3171 height = XFIXNUM (Fcdr (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
3172
3173 /* Calculate position of tooltip frame. */
3174 compute_tip_xy (tip_f, parms, dx, dy, width, height, &root_x, &root_y);
3175
3176 /* Show tooltip frame. */
3177 block_input ();
3178 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (tip_f)), width, height);
3179 gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (tip_f)), root_x, root_y);
3180 unblock_input ();
3181
3182 pgtk_cr_update_surface_desired_size (tip_f, width, height);
3183
3184 w->must_be_updated_p = true;
3185 update_single_window (w);
3186 flush_frame (tip_f);
3187 set_buffer_internal_1 (old_buffer);
3188 unbind_to (count_1, Qnil);
3189 windows_or_buffers_changed = old_windows_or_buffers_changed;
3190
3191 start_timer:
2674 /* Let the tip disappear after timeout seconds. */ 3192 /* Let the tip disappear after timeout seconds. */
2675 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil, 3193 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
2676 intern ("x-hide-tip")); 3194 intern ("x-hide-tip"));
@@ -2705,10 +3223,16 @@ frame_geometry (Lisp_Object frame, Lisp_Object attribute)
2705 int native_height = FRAME_PIXEL_HEIGHT (f); 3223 int native_height = FRAME_PIXEL_HEIGHT (f);
2706 int outer_width = native_width + 2 * border; 3224 int outer_width = native_width + 2 * border;
2707 int outer_height = native_height + 2 * border + title_height; 3225 int outer_height = native_height + 2 * border + title_height;
2708 int native_left = f->left_pos + border; 3226
2709 int native_top = f->top_pos + border + title_height; 3227 /* Get these here because they can't be got in configure_event(). */
2710 int native_right = f->left_pos + outer_width - border; 3228 int left_pos, top_pos;
2711 int native_bottom = f->top_pos + outer_height - border; 3229 gtk_window_get_position (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
3230 &left_pos, &top_pos);
3231
3232 int native_left = left_pos + border;
3233 int native_top = top_pos + border + title_height;
3234 int native_right = left_pos + outer_width - border;
3235 int native_bottom = top_pos + outer_height - border;
2712 int internal_border_width = FRAME_INTERNAL_BORDER_WIDTH (f); 3236 int internal_border_width = FRAME_INTERNAL_BORDER_WIDTH (f);
2713 int tab_bar_height = 0, tab_bar_width = 0; 3237 int tab_bar_height = 0, tab_bar_width = 0;
2714 int tool_bar_height = FRAME_TOOLBAR_HEIGHT (f); 3238 int tool_bar_height = FRAME_TOOLBAR_HEIGHT (f);
@@ -2722,9 +3246,9 @@ frame_geometry (Lisp_Object frame, Lisp_Object attribute)
2722 3246
2723 /* Construct list. */ 3247 /* Construct list. */
2724 if (EQ (attribute, Qouter_edges)) 3248 if (EQ (attribute, Qouter_edges))
2725 return list4 (make_fixnum (f->left_pos), make_fixnum (f->top_pos), 3249 return list4 (make_fixnum (left_pos), make_fixnum (top_pos),
2726 make_fixnum (f->left_pos + outer_width), 3250 make_fixnum (left_pos + outer_width),
2727 make_fixnum (f->top_pos + outer_height)); 3251 make_fixnum (top_pos + outer_height));
2728 else if (EQ (attribute, Qnative_edges)) 3252 else if (EQ (attribute, Qnative_edges))
2729 return list4 (make_fixnum (native_left), make_fixnum (native_top), 3253 return list4 (make_fixnum (native_left), make_fixnum (native_top),
2730 make_fixnum (native_right), make_fixnum (native_bottom)); 3254 make_fixnum (native_right), make_fixnum (native_bottom));
@@ -2738,8 +3262,8 @@ frame_geometry (Lisp_Object frame, Lisp_Object attribute)
2738 else 3262 else
2739 return 3263 return
2740 list (Fcons (Qouter_position, 3264 list (Fcons (Qouter_position,
2741 Fcons (make_fixnum (f->left_pos), 3265 Fcons (make_fixnum (left_pos),
2742 make_fixnum (f->top_pos))), 3266 make_fixnum (top_pos))),
2743 Fcons (Qouter_size, 3267 Fcons (Qouter_size,
2744 Fcons (make_fixnum (outer_width), 3268 Fcons (make_fixnum (outer_width),
2745 make_fixnum (outer_height))), 3269 make_fixnum (outer_height))),
@@ -3161,10 +3685,16 @@ be used as the image of the icon representing the frame. */);
3161 as_script = Qnil; 3685 as_script = Qnil;
3162 as_result = 0; 3686 as_result = 0;
3163 3687
3164 tip_frame = Qnil;
3165 staticpro (&tip_frame);
3166 tip_timer = Qnil; 3688 tip_timer = Qnil;
3167 staticpro (&tip_timer); 3689 staticpro (&tip_timer);
3690 tip_frame = Qnil;
3691 staticpro (&tip_frame);
3692 tip_last_frame = Qnil;
3693 staticpro (&tip_last_frame);
3694 tip_last_string = Qnil;
3695 staticpro (&tip_last_string);
3696 tip_last_parms = Qnil;
3697 staticpro (&tip_last_parms);
3168 3698
3169 /* This is not ifdef:ed, so other builds than GTK can customize it. */ 3699 /* This is not ifdef:ed, so other builds than GTK can customize it. */
3170 DEFVAR_BOOL ("x-gtk-use-old-file-dialog", x_gtk_use_old_file_dialog, 3700 DEFVAR_BOOL ("x-gtk-use-old-file-dialog", x_gtk_use_old_file_dialog,
@@ -3192,8 +3722,14 @@ Otherwise use Emacs own tooltip implementation.
3192When using Gtk+ tooltips, the tooltip face is not used. */); 3722When using Gtk+ tooltips, the tooltip face is not used. */);
3193 x_gtk_use_system_tooltips = true; 3723 x_gtk_use_system_tooltips = true;
3194 3724
3725 DEFVAR_LISP ("x-max-tooltip-size", Vx_max_tooltip_size,
3726 doc: /* Maximum size for tooltips.
3727Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */);
3728 Vx_max_tooltip_size = Fcons (make_fixnum (80), make_fixnum (40));
3729
3195 3730
3196 DEFSYM (Qmono, "mono"); 3731 DEFSYM (Qmono, "mono");
3732 DEFSYM (Qassq_delete_all, "assq-delete-all");
3197 3733
3198 DEFSYM (Qpdf, "pdf"); 3734 DEFSYM (Qpdf, "pdf");
3199 3735
diff --git a/src/pgtkterm.c b/src/pgtkterm.c
index aeec3f589ff..544436e6e44 100644
--- a/src/pgtkterm.c
+++ b/src/pgtkterm.c
@@ -6369,6 +6369,13 @@ drag_data_received (GtkWidget * widget, GdkDragContext * context,
6369void 6369void
6370pgtk_set_event_handler (struct frame *f) 6370pgtk_set_event_handler (struct frame *f)
6371{ 6371{
6372 if (f->tooltip)
6373 {
6374 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "draw",
6375 G_CALLBACK (pgtk_handle_draw), NULL);
6376 return;
6377 }
6378
6372 gtk_drag_dest_set (FRAME_GTK_WIDGET (f), GTK_DEST_DEFAULT_ALL, NULL, 0, 6379 gtk_drag_dest_set (FRAME_GTK_WIDGET (f), GTK_DEST_DEFAULT_ALL, NULL, 0,
6373 GDK_ACTION_COPY); 6380 GDK_ACTION_COPY);
6374 gtk_drag_dest_add_uri_targets (FRAME_GTK_WIDGET (f)); 6381 gtk_drag_dest_add_uri_targets (FRAME_GTK_WIDGET (f));