Use gdk_rectangle_intersect() in pan-view
[geeqie.git] / src / ui-utildlg.cc
index f66924c..1130b47 100644 (file)
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+#include "ui-utildlg.h"
+
+#include <cstdint>
+#include <cstdio>
 #include <cstring>
+#include <ctime>
 
-#include "main.h"
-#include "ui-utildlg.h"
+#include <gdk/gdk.h>
+#include <gio/gio.h>
+#include <glib-object.h>
+
+#include <config.h>
 
+#include "compat.h"
+#include "debug.h"
 #include "filedata.h"
+#include "intl.h"
+#include "main-defines.h"
 #include "misc.h"
+#include "options.h"
 #include "rcfile.h"
 #include "ui-fileops.h"
 #include "ui-misc.h"
 #include "ui-tabcomp.h"
 #include "window.h"
 
+namespace
+{
+
+constexpr gint max_buffer_size = 16384;
+} // namespace
+
 /*
  *-----------------------------------------------------------------------------
  * generic dialog
@@ -108,7 +127,10 @@ void generic_dialog_close(GenericDialog *gd)
        gchar *ident_string;
        gchar *full_title;
        gchar *actual_title;
-       gint x, y, h, w;
+       gint x;
+       gint y;
+       gint h;
+       gint w;
 
        gdk_window_get_root_origin(gtk_widget_get_window (gd->dialog), &x, &y);
        w = gdk_window_get_width(gtk_widget_get_window (gd->dialog));
@@ -123,7 +145,7 @@ void generic_dialog_close(GenericDialog *gd)
 
        generic_dialog_save_window(actual_title, gtk_window_get_role(GTK_WINDOW(gd->dialog)), x, y, w, h);
 
-       gtk_widget_destroy(gd->dialog);
+       gq_gtk_widget_destroy(gd->dialog);
        g_free(gd);
        g_free(ident_string);
        g_free(full_title);
@@ -241,7 +263,7 @@ GtkWidget *generic_dialog_add_button(GenericDialog *gd, const gchar *icon_name,
        gtk_widget_set_can_default(button, TRUE);
        g_object_set_data(G_OBJECT(button), "dialog_function", reinterpret_cast<void *>(func_cb));
 
-       gtk_container_add(GTK_CONTAINER(gd->hbox), button);
+       gq_gtk_container_add(GTK_WIDGET(gd->hbox), button);
 
        alternative_order = generic_dialog_get_alternative_button_order(gd->hbox);
 
@@ -269,7 +291,7 @@ GtkWidget *generic_dialog_add_button(GenericDialog *gd, const gchar *icon_name,
  * @param icon_stock_id
  * @param heading
  * @param text
- * @param expand Used as the "expand" and "fill" parameters in the eventual call to gtk_box_pack_start()
+ * @param expand Used as the "expand" and "fill" parameters in the eventual call to gq_gtk_box_pack_start()
  * @returns
  *
  *
@@ -289,7 +311,7 @@ GtkWidget *generic_dialog_add_message(GenericDialog *gd, const gchar *icon_name,
                image = gtk_image_new_from_icon_name(icon_name, GTK_ICON_SIZE_DIALOG);
                gtk_widget_set_halign(GTK_WIDGET(image), GTK_ALIGN_CENTER);
                gtk_widget_set_valign(GTK_WIDGET(image), GTK_ALIGN_START);
-               gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
+               gq_gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
                gtk_widget_show(image);
                }
 
@@ -384,14 +406,17 @@ static void generic_dialog_setup(GenericDialog *gd,
                                 void (*cancel_cb)(GenericDialog *, gpointer), gpointer data)
 {
        GtkWidget *vbox;
-       gint x, y, w, h;
+       gint x;
+       gint y;
+       gint w;
+       gint h;
        GtkWidget *scrolled;
 
        gd->auto_close = auto_close;
        gd->data = data;
        gd->cancel_cb = cancel_cb;
 
-       gd->dialog = window_new(GTK_WINDOW_TOPLEVEL, role, nullptr, nullptr, title);
+       gd->dialog = window_new(role, nullptr, nullptr, title);
        DEBUG_NAME(gd->dialog);
        gtk_window_set_type_hint(GTK_WINDOW(gd->dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
 
@@ -400,7 +425,7 @@ static void generic_dialog_setup(GenericDialog *gd,
                if (generic_dialog_find_window(title, role, &x, &y, &w, &h))
                        {
                        gtk_window_set_default_size(GTK_WINDOW(gd->dialog), w, h);
-                       gtk_window_move(GTK_WINDOW(gd->dialog), x, y);
+                       gq_gtk_window_move(GTK_WINDOW(gd->dialog), x, y);
                        }
                }
 
@@ -435,20 +460,20 @@ static void generic_dialog_setup(GenericDialog *gd,
        gtk_scrolled_window_set_propagate_natural_height(GTK_SCROLLED_WINDOW(scrolled), TRUE);
        gtk_scrolled_window_set_propagate_natural_width(GTK_SCROLLED_WINDOW(scrolled), TRUE);
        vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, PREF_PAD_BUTTON_SPACE);
-       gtk_container_add(GTK_CONTAINER(scrolled), vbox);
-       gtk_container_add(GTK_CONTAINER(gd->dialog), scrolled);
+       gq_gtk_container_add(GTK_WIDGET(scrolled), vbox);
+       gq_gtk_container_add(GTK_WIDGET(gd->dialog), scrolled);
        gtk_widget_show(scrolled);
 
        gtk_widget_show(vbox);
 
        gd->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
-       gtk_box_pack_start(GTK_BOX(vbox), gd->vbox, TRUE, TRUE, 0);
+       gq_gtk_box_pack_start(GTK_BOX(vbox), gd->vbox, TRUE, TRUE, 0);
        gtk_widget_show(gd->vbox);
 
        gd->hbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
        gtk_button_box_set_layout(GTK_BUTTON_BOX(gd->hbox), GTK_BUTTONBOX_END);
        gtk_box_set_spacing(GTK_BOX(gd->hbox), PREF_PAD_BUTTON_GAP);
-       gtk_box_pack_start(GTK_BOX(vbox), gd->hbox, FALSE, FALSE, 0);
+       gq_gtk_box_pack_start(GTK_BOX(vbox), gd->hbox, FALSE, FALSE, 0);
        gtk_widget_show(gd->hbox);
 
        if (gd->cancel_cb)
@@ -527,14 +552,14 @@ static gboolean appimage_notification_close_cb(gpointer data)
 {
        auto appimage_data = static_cast<AppImageData *>(data);
 
-       if (appimage_data->window && gtk_window_get_opacity(GTK_WINDOW(appimage_data->window)) != 0)
+       if (appimage_data->window && gtk_widget_get_opacity(appimage_data->window) != 0)
                {
                g_source_remove(appimage_data->id);
                }
 
        if (appimage_data->window)
                {
-               gtk_widget_destroy(appimage_data->window);
+               gq_gtk_widget_destroy(appimage_data->window);
                }
 
        g_thread_pool_free(appimage_data->thread_pool, TRUE, TRUE);
@@ -547,9 +572,9 @@ static gboolean appimage_notification_fade_cb(gpointer data)
 {
        auto appimage_data = static_cast<AppImageData *>(data);
 
-       gtk_window_set_opacity(GTK_WINDOW(appimage_data->window), (gtk_window_get_opacity(GTK_WINDOW(appimage_data->window)) - 0.02));
+       gtk_widget_set_opacity(appimage_data->window, (gtk_widget_get_opacity(appimage_data->window) - 0.02));
 
-       if (gtk_window_get_opacity(GTK_WINDOW(appimage_data->window)) == 0)
+       if (gtk_widget_get_opacity(appimage_data->window) == 0)
                {
                g_idle_add(appimage_notification_close_cb, data);
 
@@ -576,7 +601,10 @@ static void show_notification_message(AppImageData *appimage_data)
 
        appimage_data->window = GTK_WIDGET(gtk_builder_get_object(builder, "appimage_notification"));
 
-       gtk_window_move(GTK_WINDOW(appimage_data->window), (gdk_screen_width() * 0.8), (gdk_screen_height() / 20));
+       GdkRectangle workarea;
+       gdk_monitor_get_workarea(gdk_display_get_primary_monitor(gdk_display_get_default()),
+                             &workarea);
+       gq_gtk_window_move(GTK_WINDOW(appimage_data->window), workarea.width * 0.8, workarea.height / 20);
        g_signal_connect(appimage_data->window, "focus-in-event", G_CALLBACK(user_close_cb), appimage_data);
        appimage_data->id = g_timeout_add(100, appimage_notification_fade_cb, appimage_data);
 
@@ -586,16 +614,21 @@ static void show_notification_message(AppImageData *appimage_data)
 
 void appimage_notification_func(gpointer data, gpointer)
 {
+       FILE *pipe;
+       GNetworkMonitor *net_mon;
+       GSocketConnectable *geeqie_github;
        auto appimage_data = static_cast<AppImageData *>(data);
+       char buffer[max_buffer_size];
+       char result[max_buffer_size];
        gboolean internet_available = FALSE;
+       gchar **github_split;
        gchar **version_split;
-       GFile *file_github;
-       GFileInfo *file_info;
-       GNetworkMonitor *net_mon;
-       GSocketConnectable *geeqie_github;
+       gchar *start_date;
        struct tm current_version_date;
-       int64_t file_github_date;
-       unsigned int year, month, day;
+       struct tm github_version_date;
+       unsigned int day;
+       unsigned int month;
+       unsigned int year;
 
        /* If this is a release version, do not check for updates */
        if (g_strrstr(VERSION, "git"))
@@ -614,11 +647,6 @@ void appimage_notification_func(gpointer data, gpointer)
                        /* VERSION looks like: 2.0.1+git20220116-c791cbee */
                        version_split = g_strsplit_set(VERSION, "+-", -1);
 
-                       file_github = g_file_new_for_uri("https://github.com/BestImageViewer/geeqie/releases/download/continuous/Geeqie-latest-x86_64.AppImage");
-                       file_info = g_file_query_info(file_github, "time::modified", G_FILE_QUERY_INFO_NONE, nullptr, nullptr);
-
-                       file_github_date = g_file_info_get_attribute_uint64(file_info, "time::modified");
-
                        sscanf(version_split[1] + 3, "%4u%2u%2u", &year, &month, &day);
                        current_version_date.tm_year  = year - 1900;
                        current_version_date.tm_mon   = month - 1;
@@ -628,13 +656,45 @@ void appimage_notification_func(gpointer data, gpointer)
                        current_version_date.tm_sec   = 0;
                        current_version_date.tm_isdst = 0;
 
-                       if (file_github_date > mktime(&current_version_date))
+                       pipe = popen("curl --max-time 2 --silent https://api.github.com/repos/BestImageViewer/geeqie/releases/tags/continuous", "r");
+
+                       if (pipe == nullptr)
                                {
-                               show_notification_message(appimage_data);
+                               log_printf("Failed to get date from GitHub");
+                               }
+                       else
+                               {
+                               while (fgets(buffer, max_buffer_size, pipe) != nullptr)
+                                       {
+                                       strcat(result, buffer);
+                                       }
+                               pclose(pipe);
+
+                               /* GitHub date looks like: "published_at": "2024-04-17T08:50:08Z" */
+                               start_date = g_strstr_len(result, -1, "published");
+                               start_date[26] = '\0';
+
+                               github_split = g_strsplit_set(start_date, "\"-", -1);
+
+                               sscanf(github_split[2], "%4u", &year);
+                               sscanf(github_split[3], "%2u", &month);
+                               sscanf(github_split[4], "%2u", &day);
+
+                               github_version_date.tm_year  = year - 1900;
+                               github_version_date.tm_mon   = month - 1;
+                               github_version_date.tm_mday  = day;
+                               github_version_date.tm_hour  = 0;
+                               github_version_date.tm_min   = 0;
+                               github_version_date.tm_sec   = 0;
+                               github_version_date.tm_isdst = 0;
+
+                               if (mktime(&github_version_date) > mktime(&current_version_date))
+                                       {
+                                       show_notification_message(appimage_data);
+                                       }
+
+                               g_strfreev(github_split);
                                }
-
-                       g_object_unref(file_github);
-                       g_object_unref(file_info);
                        g_strfreev(version_split);
                        }
                }
@@ -692,7 +752,7 @@ static void file_dialog_entry_cb(GtkWidget *, gpointer data)
 {
        auto fdlg = static_cast<FileDialog *>(data);
        g_free(fdlg->dest_path);
-       fdlg->dest_path = remove_trailing_slash(gtk_entry_get_text(GTK_ENTRY(fdlg->entry)));
+       fdlg->dest_path = remove_trailing_slash(gq_gtk_entry_get_text(GTK_ENTRY(fdlg->entry)));
 }
 
 static void file_dialog_entry_enter_cb(const gchar *, gpointer data)
@@ -714,7 +774,7 @@ void file_dialog_add_path_widgets(FileDialog *fdlg, const gchar *default_path, c
 
        tabcomp = tab_completion_new_with_history(&fdlg->entry, nullptr,
                  history_key, -1, file_dialog_entry_enter_cb, fdlg);
-       gtk_box_pack_end(GTK_BOX(GENERIC_DIALOG(fdlg)->vbox), tabcomp, FALSE, FALSE, 0);
+       gq_gtk_box_pack_end(GTK_BOX(GENERIC_DIALOG(fdlg)->vbox), tabcomp, FALSE, FALSE, 0);
        generic_dialog_attach_default(GENERIC_DIALOG(fdlg), fdlg->entry);
        gtk_widget_show(tabcomp);
 
@@ -743,13 +803,13 @@ void file_dialog_add_path_widgets(FileDialog *fdlg, const gchar *default_path, c
 
        list = path_selection_new_with_files(fdlg->entry, fdlg->dest_path, filter, filter_desc);
        path_selection_add_select_func(fdlg->entry, file_dialog_entry_enter_cb, fdlg);
-       gtk_box_pack_end(GTK_BOX(GENERIC_DIALOG(fdlg)->vbox), list, TRUE, TRUE, 0);
+       gq_gtk_box_pack_end(GTK_BOX(GENERIC_DIALOG(fdlg)->vbox), list, TRUE, TRUE, 0);
        gtk_widget_show(list);
 
        gtk_widget_grab_focus(fdlg->entry);
        if (fdlg->dest_path)
                {
-               gtk_entry_set_text(GTK_ENTRY(fdlg->entry), fdlg->dest_path);
+               gq_gtk_entry_set_text(GTK_ENTRY(fdlg->entry), fdlg->dest_path);
                gtk_editable_set_position(GTK_EDITABLE(fdlg->entry), strlen(fdlg->dest_path));
                }