changeset 2857:59106bf7f9f4

GTK2/3/4: Refactor dw_init(), splitting off path detection into _dw_init_path(). Using argv[0] to detect the executable path is very inaccurate, so we will add platform specific code for Linux and FreeBSD to query the executable path. If platform specific code fails, fall back to argv[0] like before.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Tue, 15 Nov 2022 10:18:52 +0000
parents de1a0cd26691
children ecfbc48e933a
files gtk/dw.c gtk3/dw.c gtk4/dw.c
diffstat 3 files changed, 133 insertions(+), 76 deletions(-) [+]
line wrap: on
line diff
--- a/gtk/dw.c	Tue Nov 15 04:24:25 2022 +0000
+++ b/gtk/dw.c	Tue Nov 15 10:18:52 2022 +0000
@@ -46,6 +46,11 @@
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #endif
 
+#ifdef __FreeBSD__
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#endif
+
 #if __STDC_VERSION__ < 199901L
 # if __GNUC__ >= 2
 #  define __func__ __FUNCTION__
@@ -2092,6 +2097,58 @@
 }
 #endif
 
+void _dw_init_path(char *arg)
+{
+   char path[PATH_MAX+1] = {0};
+
+#ifdef __linux__
+   if(readlink("/proc/self/exe", path, PATH_MAX) == -1)
+#elif defined(__FreeBSD__)
+   int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
+   size_t length = PATH_MAX;
+
+   if(sysctl(name, 4, exe, &length, NULL, 0) == -1 || length <= 1)
+#endif
+      strncpy(path, arg ? arg : "", PATH_MAX);
+
+   if(path[0])
+   {
+      char *pos = strrchr(path, '/');
+      char *binname = path;
+
+      /* If we have a / then...
+       * the binary name should be at the end.
+       */
+      if(pos)
+      {
+         binname = pos + 1;
+         *pos = 0;
+      }
+
+      if(*binname)
+      {
+         char *binpos = strstr(path, "/bin");
+
+         if(binpos)
+            strncpy(_dw_share_path, path, (size_t)(binpos - path));
+         else
+            strcpy(_dw_share_path, "/usr/local");
+         strcat(_dw_share_path, "/share/");
+         strcat(_dw_share_path, binname);
+#if GLIB_CHECK_VERSION(2,28,0)
+         if(!_dw_app_id[0])
+         {
+            /* If we have a binary name, use that for the Application ID instead. */
+            snprintf(_dw_app_id, _DW_APP_ID_SIZE, "%s.%s", DW_APP_DOMAIN_DEFAULT, binname);
+         }
+#endif
+      }
+   }
+   /* If that failed... just get the current directory */
+   if(!_dw_share_path[0] && !getcwd(_dw_share_path, PATH_MAX))
+      _dw_share_path[0] = '/';
+}
+
 /*
  * Initializes the Dynamic Windows engine.
  * Parameters:
@@ -2109,45 +2166,7 @@
    
 
    /* Setup the private data directory */
-   if(argc > 0 && argv[0])
-   {
-      char *pathcopy = strdup(argv[0]);
-      char *pos = strrchr(pathcopy, '/');
-      char *binname = pathcopy;
-
-      /* If we have a / then...
-       * the binary name should be at the end.
-       */
-      if(pos)
-      {
-         binname = pos + 1;
-         *pos = 0;
-      }
-
-      if(*binname)
-      {
-         char *binpos = strstr(pathcopy, "/bin");
-
-         if(binpos)
-            strncpy(_dw_share_path, pathcopy, (size_t)(binpos - pathcopy));
-         else
-            strcpy(_dw_share_path, "/usr/local");
-         strcat(_dw_share_path, "/share/");
-         strcat(_dw_share_path, binname);
-#if GLIB_CHECK_VERSION(2,28,0)
-         if(!_dw_app_id[0])
-         {
-            /* If we have a binary name, use that for the Application ID instead. */
-            snprintf(_dw_app_id, _DW_APP_ID_SIZE, "%s.%s", DW_APP_DOMAIN_DEFAULT, binname);
-         }
-#endif
-      }
-      if(pathcopy)
-         free(pathcopy);
-   }
-   /* If that failed... just get the current directory */
-   if(!_dw_share_path[0] && !getcwd(_dw_share_path, PATH_MAX))
-      _dw_share_path[0] = '/';
+   _dw_init_path(argc > 0 ? argv[0] : NULL);
 
    gtk_set_locale();
 #if !GLIB_CHECK_VERSION(2,32,0)
--- a/gtk3/dw.c	Tue Nov 15 04:24:25 2022 +0000
+++ b/gtk3/dw.c	Tue Nov 15 10:18:52 2022 +0000
@@ -44,6 +44,11 @@
 
 #include <gdk-pixbuf/gdk-pixbuf.h>
 
+#ifdef __FreeBSD__
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#endif
+
 #if !GTK_CHECK_VERSION(3,1,0)
 #error GTK 3.0 is no longer supported, please use 3.2 or later.
 #endif
@@ -2032,20 +2037,24 @@
 }
 #endif
 
-/*
- * Initializes the Dynamic Windows engine.
- * Parameters:
- *           newthread: True if this is the only thread.
- *                      False if there is already a message loop running.
- */
-int dw_init(int newthread, int argc, char *argv[])
-{
-   /* Setup the private data directory */
-   if(argc > 0 && argv[0])
-   {
-      char *pathcopy = strdup(argv[0]);
-      char *pos = strrchr(pathcopy, '/');
-      char *binname = pathcopy;
+void _dw_init_path(char *arg)
+{
+   char path[PATH_MAX+1] = {0};
+
+#ifdef __linux__
+   if(readlink("/proc/self/exe", path, PATH_MAX) == -1)
+#elif defined(__FreeBSD__)
+   int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
+   size_t length = PATH_MAX;
+
+   if(sysctl(name, 4, exe, &length, NULL, 0) == -1 || length <= 1)
+#endif
+      strncpy(path, arg ? arg : "", PATH_MAX);
+
+   if(path[0])
+   {
+      char *pos = strrchr(path, '/');
+      char *binname = path;
 
       /* If we have a / then...
        * the binary name should be at the end.
@@ -2058,10 +2067,10 @@
 
       if(*binname)
       {
-         char *binpos = strstr(pathcopy, "/bin");
+         char *binpos = strstr(path, "/bin");
 
          if(binpos)
-            strncpy(_dw_share_path, pathcopy, (size_t)(binpos - pathcopy));
+            strncpy(_dw_share_path, path, (size_t)(binpos - path));
          else
             strcpy(_dw_share_path, "/usr/local");
          strcat(_dw_share_path, "/share/");
@@ -2074,12 +2083,22 @@
          }
 #endif
       }
-      if(pathcopy)
-         free(pathcopy);
    }
    /* If that failed... just get the current directory */
    if(!_dw_share_path[0] && !getcwd(_dw_share_path, PATH_MAX))
       _dw_share_path[0] = '/';
+}
+
+/*
+ * Initializes the Dynamic Windows engine.
+ * Parameters:
+ *           newthread: True if this is the only thread.
+ *                      False if there is already a message loop running.
+ */
+int dw_init(int newthread, int argc, char *argv[])
+{
+   /* Setup the private data directory */
+   _dw_init_path(argc > 0 ? argv[0] : NULL);
 
 #if !GLIB_CHECK_VERSION(2,31,0)
    g_thread_init(NULL);
--- a/gtk4/dw.c	Tue Nov 15 04:24:25 2022 +0000
+++ b/gtk4/dw.c	Tue Nov 15 10:18:52 2022 +0000
@@ -39,6 +39,11 @@
 
 #include <gdk-pixbuf/gdk-pixbuf.h>
 
+#ifdef __FreeBSD__
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#endif
+
 #if __STDC_VERSION__ < 199901L
 # if __GNUC__ >= 2
 #  define __func__ __FUNCTION__
@@ -1503,20 +1508,24 @@
     */
 }
 
-/*
- * Initializes the Dynamic Windows engine.
- * Parameters:
- *           newthread: True if this is the only thread.
- *                      False if there is already a message loop running.
- */
-int API dw_init(int newthread, int argc, char *argv[])
-{
-   /* Setup the private data directory */
-   if(argc > 0 && argv[0])
-   {
-      char *pathcopy = strdup(argv[0]);
-      char *pos = strrchr(pathcopy, '/');
-      char *binname = pathcopy;
+void _dw_init_path(char *arg)
+{
+   char path[PATH_MAX+1] = {0};
+
+#ifdef __linux__
+   if(readlink("/proc/self/exe", path, PATH_MAX) == -1)
+#elif defined(__FreeBSD__)
+   int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
+   size_t length = PATH_MAX;
+
+   if(sysctl(name, 4, exe, &length, NULL, 0) == -1 || length <= 1)
+#endif
+      strncpy(path, arg ? arg : "", PATH_MAX);
+
+   if(path[0])
+   {
+      char *pos = strrchr(path, '/');
+      char *binname = path;
 
       /* If we have a / then...
        * the binary name should be at the end.
@@ -1529,10 +1538,10 @@
 
       if(*binname)
       {
-         char *binpos = strstr(pathcopy, "/bin");
+         char *binpos = strstr(path, "/bin");
 
          if(binpos)
-            strncpy(_dw_share_path, pathcopy, (size_t)(binpos - pathcopy));
+            strncpy(_dw_share_path, path, (size_t)(binpos - path));
          else
             strcpy(_dw_share_path, "/usr/local");
          strcat(_dw_share_path, "/share/");
@@ -1543,12 +1552,22 @@
             snprintf(_dw_app_id, _DW_APP_ID_SIZE, "%s.%s", DW_APP_DOMAIN_DEFAULT, binname);
          }
       }
-      if(pathcopy)
-         free(pathcopy);
-   }
+  }
    /* If that failed... just get the current directory */
    if(!_dw_share_path[0] && !getcwd(_dw_share_path, PATH_MAX))
       _dw_share_path[0] = '/';
+}
+
+/*
+ * Initializes the Dynamic Windows engine.
+ * Parameters:
+ *           newthread: True if this is the only thread.
+ *                      False if there is already a message loop running.
+ */
+int API dw_init(int newthread, int argc, char *argv[])
+{
+   /* Setup the private data directory */
+   _dw_init_path(argc > 0 ? argv[0] : NULL);
 
    gtk_init();