Subject: bug#31223: [PATCH] Fix empty/incorrect GTK menus on HiDPI monitors with window scaling factor > 1

From: Robert Pluim <[email-masked]>
Date: Thu, 28 Nov 2019 09:20:35 +0100

>>>>> On Wed, 27 Nov 2019 17:03:32 +0100, Tobias Bading <[email-masked]> said:

    Tobias> This should fix Bug#31223, Bug#28106, Bug#23672 as well as Ubuntu bug
    Tobias> https://bugs.launchpad.net/ubuntu/+source/emacs25/+bug/1695228

If those are all the same bug we should merge them.

    Tobias> Also fixes the formerly unscaled Y value returned by
    Tobias> frame-monitor-workarea (and display-monitor-attributes-list).

    Tobias> For details on why some GTK menus were empty please see thread
    Tobias> https://lists.gnu.org/archive/html/emacs-devel/2019-11/msg01061.html

Thanks for that, I can reproduce with that (I never use the Dired
menus).

    Tobias> diff --git a/src/gtkutil.c b/src/gtkutil.c
    Tobias> index cf5c31aa20..7e6db57c9d 100644
    Tobias> --- a/src/gtkutil.c
    Tobias> +++ b/src/gtkutil.c
    Tobias> @@ -3471,6 +3471,7 @@ menubar_map_cb (GtkWidget *w, gpointer user_data)
    Tobias>    GtkRequisition req;
    Tobias>    struct frame *f = user_data;
    Tobias>    gtk_widget_get_preferred_size (w, NULL, &req);
    Tobias> +  req.height *= xg_get_scale (f);
    Tobias>    if (FRAME_MENUBAR_HEIGHT (f) != req.height)
    Tobias>      {
    Tobias>        FRAME_MENUBAR_HEIGHT (f) = req.height;
    Tobias> @@ -3502,7 +3503,7 @@ xg_update_frame_menubar (struct frame *f)
    Tobias>    g_signal_connect (x->menubar_widget, "map", G_CALLBACK (menubar_map_cb), f);
    Tobias>    gtk_widget_show_all (x->menubar_widget);
    Tobias>    gtk_widget_get_preferred_size (x->menubar_widget, NULL, &req);
    Tobias> -
    Tobias> +  req.height *= xg_get_scale (f);
    Tobias>    if (FRAME_MENUBAR_HEIGHT (f) != req.height)
    Tobias>      {
    Tobias>        FRAME_MENUBAR_HEIGHT (f) = req.height;

Yes.

    Tobias> @@ -3568,8 +3569,9 @@ xg_event_is_for_menubar (struct frame *f, const XEvent *event)

    Tobias>    list = gtk_container_get_children (GTK_CONTAINER (x->menubar_widget));
    Tobias>    if (! list) return 0;
    Tobias> -  rec.x = event->xbutton.x;
    Tobias> -  rec.y = event->xbutton.y;
    Tobias> +  int scale = xg_get_scale (f);
    Tobias> +  rec.x = event->xbutton.x / scale;
    Tobias> +  rec.y = event->xbutton.y / scale;
    Tobias>    rec.width = 1;
    Tobias>    rec.height = 1;

Yes. You need this as well, I think:

diff --git a/src/gtkutil.c b/src/gtkutil.c
index cf5c31aa20..4f8b06941b 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -3503,6 +3503,8 @@ xg_update_frame_menubar (struct frame *f)
   gtk_widget_show_all (x->menubar_widget);
   gtk_widget_get_preferred_size (x->menubar_widget, NULL, &req);
 
+  req.height *= xg_get_scale (f);
   if (FRAME_MENUBAR_HEIGHT (f) != req.height)
     {
       FRAME_MENUBAR_HEIGHT (f) = req.height;

    Tobias> diff --git a/src/xfns.c b/src/xfns.c
    Tobias> index b1b40702c2..47aa19607f 100644
    Tobias> --- a/src/xfns.c
    Tobias> +++ b/src/xfns.c
    Tobias> @@ -5093,6 +5093,8 @@ DEFUN ("x-display-monitor-attributes-list", Fx_display_monitor_attributes_list,
    Tobias>  #endif
    Tobias>        rec.width *= scale;
    Tobias>        rec.height *= scale;
    Tobias> +      work.x *= scale;
    Tobias> +      work.y *= scale;
    Tobias>        work.width *= scale;
    Tobias>        work.height *= scale;

This seems correct as well. Probably rec.x and rec.y need scaling as well, for
the multi-monitor case, which will require some cabling for me to test.

Robert