This is an automated email from the git hooks/post-receive script.

git pushed a commit to branch fix-modern-macos
in repository efl.

View the commit online.

commit c3b2aeab7784900fda1ac320042f70de8c1f7894
Author: Cedric BAIL <[email protected]>
AuthorDate: Wed Apr 29 17:16:26 2026 -0600

    feat(elementary): add elm_open_url/_file/_email portable helpers
    
    Three small wrappers around the OS's 'open this externally' primitive:
      - Linux/BSD:  xdg-open / xdg-email
      - macOS:      open
      - Windows:    ShellExecuteW with 'open' verb
    
    Lets apps replace #ifdef __APPLE__ snprintf+ecore_exe_run boilerplate
    with a single portable call. Existing user customization (apps with
    their own configurable helper field) layers on top: pass-through if the
    custom helper is set, fall back to elm_open_* otherwise.
---
 src/lib/elementary/Elementary.h |   1 +
 src/lib/elementary/elm_open.c   | 166 ++++++++++++++++++++++++++++++++++++++++
 src/lib/elementary/elm_open.h   |  49 ++++++++++++
 src/lib/elementary/meson.build  |   6 +-
 4 files changed, 220 insertions(+), 2 deletions(-)

diff --git a/src/lib/elementary/Elementary.h b/src/lib/elementary/Elementary.h
index a64406de43..e3e409598e 100644
--- a/src/lib/elementary/Elementary.h
+++ b/src/lib/elementary/Elementary.h
@@ -242,6 +242,7 @@ EAPI extern Elm_Version *elm_version;
 #include <elm_need.h>
 #include <elm_notify.h>
 #include <elm_object.h>
+#include <elm_open.h>
 
 #include <elm_panel.h>
 #include <elm_panes.h>
diff --git a/src/lib/elementary/elm_open.c b/src/lib/elementary/elm_open.c
new file mode 100644
index 0000000000..ca40406387
--- /dev/null
+++ b/src/lib/elementary/elm_open.c
@@ -0,0 +1,166 @@
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#include <Elementary.h>
+#include "elm_priv.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef _WIN32
+# include <windows.h>
+# include <shellapi.h>
+#endif
+
+#ifndef _WIN32
+/* POSIX single-quote shell escaping. Wraps the argument in single quotes
+ * and escapes any embedded single-quote via the standard '"'"' dance.
+ *
+ * Returns a newly malloc'd string. Caller frees. Returns NULL on
+ * allocation failure.
+ *
+ * Single-quoted strings in POSIX sh are immune to ALL metacharacters
+ * (backtick, $, \, newline, etc.) — the only character that cannot
+ * appear literally is ' itself, which is why we close-quote, insert
+ * an escaped quote, and re-open. */
+static char *
+_shell_quote(const char *arg)
+{
+   const char *p;
+   char       *quoted, *q;
+   size_t      quoted_len;
+
+   /* Size the output:
+    *   2 chars for outer quotes
+    *   each ' in arg expands to 5 chars: '"'"'  (close-SQ, open-DQ,
+    *     literal SQ, close-DQ, open-SQ)
+    *   all other chars are 1 char each
+    *   +1 for trailing NUL
+    */
+   quoted_len = 2;
+   for (p = arg; *p; p++)
+     quoted_len += (*p == '\'') ? 5 : 1;
+
+   quoted = malloc(quoted_len + 1);
+   if (!quoted) return NULL;
+
+   q = quoted;
+   *q++ = '\'';
+   for (p = arg; *p; p++)
+     {
+        if (*p == '\'')
+          {
+             /* Close current quote, insert escaped quote, reopen */
+             *q++ = '\'';
+             *q++ = '"';
+             *q++ = '\'';
+             *q++ = '"';
+             *q++ = '\'';
+          }
+        else
+          *q++ = *p;
+     }
+   *q++ = '\'';
+   *q   = '\0';
+   return quoted;
+}
+
+static Eina_Bool
+_run_helper(const char *cmd, const char *arg)
+{
+   char     *quoted = NULL;
+   char     *line   = NULL;
+   Eina_Bool ok     = EINA_FALSE;
+
+   if (!arg || !arg[0]) return EINA_FALSE;
+
+   quoted = _shell_quote(arg);
+   if (!quoted) return EINA_FALSE;
+
+   if (asprintf(&line, "%s %s", cmd, quoted) < 0)
+     {
+        free(quoted);
+        return EINA_FALSE;
+     }
+
+   ok = (ecore_exe_run(line, NULL) != NULL);
+
+   free(line);
+   free(quoted);
+   return ok;
+}
+#endif /* !_WIN32 */
+
+#ifdef _WIN32
+static Eina_Bool
+_win_shellexecute(const wchar_t *verb, const char *arg_utf8)
+{
+   wchar_t *warg;
+   int n;
+   HINSTANCE rc;
+
+   if (!arg_utf8 || !arg_utf8[0]) return EINA_FALSE;
+
+   n = MultiByteToWideChar(CP_UTF8, 0, arg_utf8, -1, NULL, 0);
+   if (n <= 0) return EINA_FALSE;
+   warg = malloc(n * sizeof(wchar_t));
+   if (!warg) return EINA_FALSE;
+   if (MultiByteToWideChar(CP_UTF8, 0, arg_utf8, -1, warg, n) <= 0)
+     {
+        free(warg);
+        return EINA_FALSE;
+     }
+
+   rc = ShellExecuteW(NULL, verb, warg, NULL, NULL, SW_SHOWNORMAL);
+   free(warg);
+   /* ShellExecute returns >32 on success */
+   return ((INT_PTR)rc > 32);
+}
+#endif /* _WIN32 */
+
+EAPI Eina_Bool
+elm_open_url(const char *url)
+{
+#if defined(__APPLE__)
+   return _run_helper("open", url);
+#elif defined(_WIN32)
+   return _win_shellexecute(L"open", url);
+#else
+   return _run_helper("xdg-open", url);
+#endif
+}
+
+EAPI Eina_Bool
+elm_open_file(const char *path)
+{
+   /* On Unix-like platforms, the same command handles both files and URLs. */
+#if defined(_WIN32)
+   return _win_shellexecute(L"open", path);
+#else
+   return elm_open_url(path);
+#endif
+}
+
+EAPI Eina_Bool
+elm_open_email(const char *address)
+{
+   char buf[1024];
+   int n;
+
+   if (!address || !address[0]) return EINA_FALSE;
+
+#if defined(__APPLE__) || defined(_WIN32)
+   n = snprintf(buf, sizeof(buf), "mailto:%s", address);
+   if (n < 0 || n >= (int)sizeof(buf)) return EINA_FALSE;
+#endif
+
+#if defined(__APPLE__)
+   return _run_helper("open", buf);
+#elif defined(_WIN32)
+   return _win_shellexecute(L"open", buf);
+#else
+   (void)buf; (void)n;
+   return _run_helper("xdg-email", address);
+#endif
+}
diff --git a/src/lib/elementary/elm_open.h b/src/lib/elementary/elm_open.h
new file mode 100644
index 0000000000..209806cb30
--- /dev/null
+++ b/src/lib/elementary/elm_open.h
@@ -0,0 +1,49 @@
+/**
+ * @file elm_open.h
+ *
+ * Portable wrappers for opening URLs, files, and email recipients with
+ * the user's default external handler. Hides platform differences:
+ *   - Linux/BSD: spawns xdg-open / xdg-email
+ *   - macOS:     spawns open
+ *   - Windows:   ShellExecute with verb "open"
+ */
+#ifndef ELM_OPEN_H
+#define ELM_OPEN_H
+
+/**
+ * Opens a URL in the user's default browser.
+ *
+ * @param url Absolute URL (http://, https://, ftp://, ...). UTF-8.
+ * @return EINA_TRUE on successful spawn, EINA_FALSE on failure
+ *         (NULL/empty input, no handler available, exec failed).
+ *
+ * @since 1.28
+ * @ingroup Elm_App
+ */
+EAPI Eina_Bool elm_open_url(const char *url);
+
+/**
+ * Opens a local file with the user's default application for that
+ * file's MIME type.
+ *
+ * @param path Local filesystem path (absolute or relative). UTF-8.
+ * @return EINA_TRUE on success, EINA_FALSE on failure.
+ *
+ * @since 1.28
+ * @ingroup Elm_App
+ */
+EAPI Eina_Bool elm_open_file(const char *path);
+
+/**
+ * Composes a new email message addressed to the given recipient,
+ * using the user's default mail client.
+ *
+ * @param address Recipient email address (no "mailto:" prefix needed).
+ * @return EINA_TRUE on success, EINA_FALSE on failure.
+ *
+ * @since 1.28
+ * @ingroup Elm_App
+ */
+EAPI Eina_Bool elm_open_email(const char *address);
+
+#endif
diff --git a/src/lib/elementary/meson.build b/src/lib/elementary/meson.build
index 0cf8436191..a7004ce742 100644
--- a/src/lib/elementary/meson.build
+++ b/src/lib/elementary/meson.build
@@ -514,6 +514,7 @@ elementary_pub_headers = [
   'elm_notify_legacy.h',
   'elm_object.h',
   'elm_object_item.h',
+  'elm_open.h',
   'elm_panel.h',
   'elm_panel_common.h',
   'elm_panel_legacy.h',
@@ -806,8 +807,9 @@ elementary_src = files([
   'elm_mapbuf.c',
   'elm_menu.c',
   'elm_module.c',
-  'elm_notify.c',
-  'elm_panel.c',
+   'elm_notify.c',
+   'elm_open.c',
+   'elm_panel.c',
   'efl_ui_panes.c',
   'elm_photo.c',
   'efl_ui_image_zoomable.c',

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to