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

git pushed a commit to branch improve-macos-support
in repository terminology.

View the commit online.

commit 962d13a02c4cab16e0af7ebeb0305422479c9fa7
Author: Cedric BAIL <[email protected]>
AuthorDate: Thu Mar 26 15:28:50 2026 -0600

    feat(macos): add native menu bar with New Window, Copy, Paste, Quit
    
    Wire up macOS-native menu bar using elm_win_main_menu_get() and the
    new EFL Cocoa menu bridge. Menu is set up once on first window
    creation via static guard.
    
    Menu structure:
    - Terminology > Quit Terminology
    - File > New Window (creates full window+term via main_config_get)
    - Edit > Copy / Paste (operates on focused terminal)
    
    Includes review fixes:
    - Resource leak fix: term_unref + win_free on win_term_set failure
    - Vtable guard: check focused_term_get before calling
    - Null checks on parent menu item creation
    - DBG trace on focused-window fallback path
---
 src/bin/win.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 134 insertions(+)

diff --git a/src/bin/win.c b/src/bin/win.c
index 7ed9f58a..2e35eb9e 100644
--- a/src/bin/win.c
+++ b/src/bin/win.c
@@ -1196,6 +1196,136 @@ terms_from_win_object(Evas_Object *win)
 }
 
 
+#ifdef __APPLE__
+/* Find the focused Win, or fall back to list head */
+static Win *
+_macos_focused_win_get(void)
+{
+   Eina_List *l;
+   Win *wn;
+
+   EINA_LIST_FOREACH(wins, l, wn)
+     {
+        if (wn->focused) return wn;
+     }
+   /* No focused window — return list head as last resort */
+   DBG("No focused Win found, falling back to list head");
+   return wins ? (Win *)eina_list_data_get(wins) : NULL;
+}
+
+static void
+_cb_macos_new_window(void *data EINA_UNUSED,
+                     Evas_Object *obj EINA_UNUSED,
+                     void *event_info EINA_UNUSED)
+{
+   Win *wn;
+   Term *term;
+
+   wn = win_new(NULL, NULL, NULL, NULL, main_config_get(),
+                EINA_FALSE, EINA_FALSE, EINA_FALSE, EINA_FALSE, EINA_FALSE);
+   if (!wn)
+     {
+        ERR("macOS New Window: win_new() failed");
+        return;
+     }
+   /* Initial size hints — win_sizing_handle() below will correct to theme geometry */
+   term = term_new(wn, win_config_get(wn), NULL, EINA_FALSE,
+                   NULL, 80, 24, EINA_FALSE, NULL);
+   if (!term)
+     {
+        ERR("macOS New Window: term_new() failed");
+        win_free(wn);
+        return;
+     }
+   if (win_term_set(wn, term) < 0)
+     {
+        ERR("macOS New Window: win_term_set() failed");
+        term_unref(term);
+        win_free(wn);
+        return;
+     }
+   win_sizing_handle(wn);
+   evas_object_show(win_evas_object_get(wn));
+}
+
+static void
+_cb_macos_copy(void *data EINA_UNUSED,
+               Evas_Object *obj EINA_UNUSED,
+               void *event_info EINA_UNUSED)
+{
+   Win *wn;
+   Term *term;
+
+   wn = _macos_focused_win_get();
+   if (!wn) return;
+   if ((!wn->child) || (!wn->child->focused_term_get)) return;
+   term = wn->child->focused_term_get(wn->child);
+   if (!term) return;
+   termio_take_selection(term->termio, ELM_SEL_TYPE_CLIPBOARD);
+}
+
+static void
+_cb_macos_paste(void *data EINA_UNUSED,
+                Evas_Object *obj EINA_UNUSED,
+                void *event_info EINA_UNUSED)
+{
+   Win *wn;
+   Term *term;
+
+   wn = _macos_focused_win_get();
+   if (!wn) return;
+   if ((!wn->child) || (!wn->child->focused_term_get)) return;
+   term = wn->child->focused_term_get(wn->child);
+   if (!term) return;
+   termio_paste_selection(term->termio, ELM_SEL_TYPE_CLIPBOARD);
+}
+
+static void
+_cb_macos_quit(void *data EINA_UNUSED,
+               Evas_Object *obj EINA_UNUSED,
+               void *event_info EINA_UNUSED)
+{
+   elm_exit();
+}
+
+static void
+_win_macos_menu_setup(Evas_Object *win)
+{
+   static Eina_Bool   done = EINA_FALSE;
+   Evas_Object       *menu;
+   Elm_Object_Item   *app_item, *file_item, *edit_item;
+
+   if (done) return;
+
+   menu = elm_win_main_menu_get(win);
+   if (!menu) return;
+   done = EINA_TRUE; /* committed to this menu — prevent duplicate setup */
+
+   /* "Terminology" app menu — macOS convention: first = app name */
+   app_item = elm_menu_item_add(menu, NULL, NULL, "Terminology", NULL, NULL);
+   if (!app_item) return;
+   elm_menu_item_add(menu, app_item, NULL, "Quit Terminology",
+                     _cb_macos_quit, NULL);
+
+   /* "File" menu */
+   file_item = elm_menu_item_add(menu, NULL, NULL, "File", NULL, NULL);
+   if (!file_item) return;
+   elm_menu_item_add(menu, file_item, NULL, "New Window",
+                     _cb_macos_new_window, NULL);
+
+   /* "Edit" menu */
+   edit_item = elm_menu_item_add(menu, NULL, NULL, "Edit", NULL, NULL);
+   if (!edit_item) return;
+   elm_menu_item_add(menu, edit_item, NULL, "Copy",
+                     _cb_macos_copy, NULL);
+   elm_menu_item_add(menu, edit_item, NULL, "Paste",
+                     _cb_macos_paste, NULL);
+   /* TODO: investigate setting keyboard equivalents (Cmd+C/V) via Cocoa bridge */
+
+   done = EINA_TRUE;
+}
+#endif /* __APPLE__ */
+
 static Evas_Object *
 win_add(const char *name, const char *role,
         const char *title, const char *icon_name)
@@ -1213,6 +1343,10 @@ win_add(const char *name, const char *role,
 
    elm_win_autodel_set(win, EINA_TRUE);
 
+#ifdef __APPLE__
+   _win_macos_menu_setup(win);
+#endif
+
    return win;
 }
 

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

Reply via email to