From: =?utf-8?q?Andreas_R=C3=B6nnquist?= <gusnan@debian.org>
Date: Tue, 11 Aug 2020 17:27:18 +0200
Subject: Migrate GTK2 to GTK3
Bug: https://github.com/liballeg/allegro5/pull/1155

---
 addons/native_dialog/CMakeLists.txt |  2 +-
 addons/native_dialog/gtk_dialog.c   | 18 ++++++----
 addons/native_dialog/gtk_filesel.c  |  4 +--
 addons/native_dialog/gtk_menu.c     | 67 +++++--------------------------------
 addons/native_dialog/gtk_textlog.c  | 17 +++++++---
 addons/native_dialog/gtk_xgtk.c     |  3 +-
 6 files changed, 37 insertions(+), 74 deletions(-)

diff --git a/addons/native_dialog/CMakeLists.txt b/addons/native_dialog/CMakeLists.txt
index 7d02dfa..e34e14e 100644
--- a/addons/native_dialog/CMakeLists.txt
+++ b/addons/native_dialog/CMakeLists.txt
@@ -37,7 +37,7 @@ if(WIN32)
 endif(WIN32)
 
 if(NOT SUPPORT_NATIVE_DIALOG AND SUPPORT_X11 AND NOT ALLEGRO_RASPBERRYPI)
-    pkg_check_modules(GTK gtk+-2.0)
+    pkg_check_modules(GTK gtk+-3.0)
     pkg_check_modules(GT gthread-2.0)
     if(GTK_FOUND AND GT_FOUND)
         list(APPEND NATIVE_DIALOG_SOURCES ${GTK_NATIVE_DIALOG_SOURCES})
diff --git a/addons/native_dialog/gtk_dialog.c b/addons/native_dialog/gtk_dialog.c
index 7a7560c..38ca1c2 100644
--- a/addons/native_dialog/gtk_dialog.c
+++ b/addons/native_dialog/gtk_dialog.c
@@ -1,4 +1,5 @@
 #include <gtk/gtk.h>
+#include <gdk/gdkx.h>
 
 #include "allegro5/allegro.h"
 #include "allegro5/allegro_native_dialog.h"
@@ -29,16 +30,19 @@ void _al_shutdown_native_dialog_addon(void)
    _al_gtk_set_display_overridable_interface(false);
 }
 
-
 static void really_make_transient(GtkWidget *window, ALLEGRO_DISPLAY_XGLX *glx)
 {
-   GdkDisplay *gdk = gdk_drawable_get_display(GDK_DRAWABLE(window->window));
-   GdkWindow *parent = gdk_window_lookup_for_display(gdk, glx->window);
+
+   GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(window));
+   GdkDisplay *gdk = GDK_DISPLAY(gdk_window_get_display(gdk_window));
+
+   GdkWindow *parent = gdk_x11_window_lookup_for_display(gdk, glx->window);
    if (!parent)
-      parent = gdk_window_foreign_new_for_display(gdk, glx->window);
-   gdk_window_set_transient_for(window->window, parent);
-}
+      parent = gdk_x11_window_foreign_new_for_display(gdk, glx->window);
 
+   if (gdk_window != NULL)
+      gdk_window_set_transient_for(gdk_window, parent);
+}
 
 static void realized(GtkWidget *window, gpointer data)
 {
@@ -51,7 +55,7 @@ void _al_gtk_make_transient(ALLEGRO_DISPLAY *display, GtkWidget *window)
    /* Set the current display window (if any) as the parent of the dialog. */
    ALLEGRO_DISPLAY_XGLX *glx = (void *)display;
    if (glx) {
-      if (!GTK_WIDGET_REALIZED(window))
+      if (!gtk_widget_get_realized(window))
          g_signal_connect(window, "realize", G_CALLBACK(realized), (void *)glx);
       else
          really_make_transient(window, glx);
diff --git a/addons/native_dialog/gtk_filesel.c b/addons/native_dialog/gtk_filesel.c
index c3f45d5..4976736 100644
--- a/addons/native_dialog/gtk_filesel.c
+++ b/addons/native_dialog/gtk_filesel.c
@@ -42,8 +42,8 @@ static gboolean create_gtk_file_dialog(gpointer data)
       gtk_file_chooser_dialog_new(al_cstr(fd->title),
                                   NULL,
                                   save ? GTK_FILE_CHOOSER_ACTION_SAVE : folder ? GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER : GTK_FILE_CHOOSER_ACTION_OPEN,
-                                  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-                                  save ? GTK_STOCK_SAVE : GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
+                                  "_Cancel", GTK_RESPONSE_CANCEL,
+                                  save ? "_Save" : "_Open", GTK_RESPONSE_ACCEPT, NULL);
 
    _al_gtk_make_transient(display, window);
 
diff --git a/addons/native_dialog/gtk_menu.c b/addons/native_dialog/gtk_menu.c
index 87f559f..a0b645b 100644
--- a/addons/native_dialog/gtk_menu.c
+++ b/addons/native_dialog/gtk_menu.c
@@ -84,14 +84,6 @@ static void checkbox_on_toggle(ALLEGRO_MENU_ITEM *item)
    }
 }
 
-/* [gtk thread] */
-static void destroy_pixbuf(guchar *pixels, gpointer data)
-{
-   (void) data;
-   
-   al_free(pixels);
-}
-
 /* [gtk thread] */
 static GtkWidget *build_menu_item(ALLEGRO_MENU_ITEM *aitem)
 {
@@ -116,39 +108,8 @@ static GtkWidget *build_menu_item(ALLEGRO_MENU_ITEM *aitem)
       }
       else {
          /* always create an image menu item, in case the user ever sets an icon */
-         gitem = gtk_image_menu_item_new_with_mnemonic(al_cstr(caption));
-         
-         if (aitem->icon) {
-            const int w = al_get_bitmap_width(aitem->icon), h = al_get_bitmap_height(aitem->icon);
-            const int stride = w * 4;
-            int x, y, i;
-            GdkPixbuf *pixbuf;
-            uint8_t *data = al_malloc(stride * h);
-            
-            if (data) {
-               for (y = 0, i = 0; y < h; ++y) {
-                  for (x = 0; x < w; ++x, i += 4) {
-                     al_unmap_rgba(al_get_pixel(aitem->icon, x, y),
-                        &data[i],
-                        &data[i + 1],
-                        &data[i + 2],
-                        &data[i + 3]
-                     );
-                  }
-               }
-               
-               pixbuf = gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB, TRUE, 8,
-                  w, h, stride, destroy_pixbuf, NULL);
-               
-               aitem->extra2 = gtk_image_new_from_pixbuf(pixbuf);
-               
-               gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(gitem), aitem->extra2);
-               
-               /* Subtract the main reference. the image still holds a reference, so the
-                * pixbuf won't be destroyed until the image itself is. */
-               g_object_unref(pixbuf);
-            }
-         }
+         gitem = gtk_menu_item_new_with_mnemonic(al_cstr(caption));
+
       }
       
       al_ustr_free(caption);
@@ -404,20 +365,6 @@ static void popop_on_hide(ALLEGRO_MENU *menu)
    /* in case we want to notify on popup close */
 }
 
-/* [gtk thread]
- *
- * gtk_menu_popup has a propencity of failing silently, and having this *
- * function called seems to be the only reliable way of detecting when this
- * happens.
- */
-static void position_func(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data) {
-   (void)menu;
-   (void)x;
-   (void)y;
-   (void)push_in;
-   *((bool*)user_data) = true;
-}
-
 /* [gtk thread] */
 static gboolean do_show_popup_menu(gpointer data)
 {
@@ -425,8 +372,9 @@ static gboolean do_show_popup_menu(gpointer data)
    
    _al_gtk_lock_args(args);
    
+   GtkWidget *menu = NULL;
    if (!args->menu->extra1) {
-      GtkWidget *menu = gtk_menu_new();
+      menu = gtk_menu_new();
       
       build_menu(menu, args->menu);
       
@@ -438,8 +386,11 @@ static gboolean do_show_popup_menu(gpointer data)
    }
 
    bool position_called = false;
-   gtk_menu_popup(args->menu->extra1, NULL, NULL, position_func, &position_called, 0,
-      gtk_get_current_event_time());
+   if (menu)
+      gtk_menu_popup_at_widget(args->menu->extra1, menu,  GDK_GRAVITY_SOUTH_WEST,
+                              GDK_GRAVITY_NORTH_WEST,
+                              NULL);
+
    if (!position_called) {
       ALLEGRO_DEBUG("Position canary not called, most likely the menu didn't show "
       "up due to outstanding mouse events.\n");
diff --git a/addons/native_dialog/gtk_textlog.c b/addons/native_dialog/gtk_textlog.c
index 349044e..ed21fd5 100644
--- a/addons/native_dialog/gtk_textlog.c
+++ b/addons/native_dialog/gtk_textlog.c
@@ -59,7 +59,7 @@ static gboolean textlog_key_press(GtkWidget *w, GdkEventKey *gevent,
    ALLEGRO_NATIVE_DIALOG *textlog = userdata;
    (void)w;
 
-   if (gevent->keyval == GDK_Escape) {
+   if (gevent->keyval == GDK_KEY_Escape) {
       emit_close_event(textlog, true);
    }
 
@@ -80,6 +80,8 @@ static gboolean create_native_text_log(gpointer data)
 {
    Msg *msg = data;
    ALLEGRO_NATIVE_DIALOG *textlog = msg->dialog;
+   GtkCssProvider *css_provider;
+   GtkStyleContext *context;
 
    /* Create a new text log window. */
    GtkWidget *top = gtk_window_new(GTK_WINDOW_TOPLEVEL);
@@ -100,11 +102,16 @@ static gboolean create_native_text_log(gpointer data)
    gtk_container_add(GTK_CONTAINER(top), scroll);
    GtkWidget *view = gtk_text_view_new();
    gtk_text_view_set_editable(GTK_TEXT_VIEW(view), false);
+   gtk_widget_set_name(GTK_WIDGET(view), "native_text_log");
    if (textlog->flags & ALLEGRO_TEXTLOG_MONOSPACE) {
-      PangoFontDescription *font_desc;
-      font_desc = pango_font_description_from_string("Monospace");
-      gtk_widget_modify_font(view, font_desc);
-      pango_font_description_free(font_desc);
+      css_provider = gtk_css_provider_new();
+      gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(css_provider),
+                                      "#native_text_log {\n"
+                                      "   font-family: monospace;\n"
+                                      "}\n", -1, NULL);
+      context = gtk_widget_get_style_context(GTK_WIDGET(view));
+      gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+      g_object_unref(css_provider);
    }
    gtk_container_add(GTK_CONTAINER(scroll), view);
    gtk_widget_show(view);
diff --git a/addons/native_dialog/gtk_xgtk.c b/addons/native_dialog/gtk_xgtk.c
index 4ba61ae..5780c65 100644
--- a/addons/native_dialog/gtk_xgtk.c
+++ b/addons/native_dialog/gtk_xgtk.c
@@ -1,4 +1,5 @@
 #include <gtk/gtk.h>
+#include <gtk/gtkx.h>
 
 #include "allegro5/allegro.h"
 #include "allegro5/internal/aintern_native_dialog_cfg.h"
@@ -94,7 +95,7 @@ static gboolean do_create_display_hook(gpointer data)
    g_signal_connect(G_OBJECT(window), "configure-event",
       G_CALLBACK(xgtk_handle_configure_event), display);
 
-   vbox = gtk_vbox_new(FALSE, 0);
+   vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    gtk_container_add(GTK_CONTAINER(window), vbox);
 
    socket = gtk_socket_new();
