diff --git a/news.d/bugfix/1822.osx.md b/news.d/bugfix/1822.osx.md new file mode 100644 index 000000000..4c3742d3b --- /dev/null +++ b/news.d/bugfix/1822.osx.md @@ -0,0 +1 @@ +Fix missing menu bar icon on macOS 26. diff --git a/osx/app_resources/plover_launcher.c b/osx/app_resources/plover_launcher.c deleted file mode 100644 index f26f19f24..000000000 --- a/osx/app_resources/plover_launcher.c +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include -#include -#include -#include -#include - -int main(int argc, char *argv[]) -{ - char python_path[PATH_MAX]; - char *new_argv[4 + argc]; - char *app_dir; - - // Get this app bundle directory. - app_dir = realpath(argv[0], NULL); - app_dir = dirname(dirname(app_dir)); - - // Get path to the Python interpreter. - snprintf( - python_path, sizeof (python_path), - "%s/Frameworks/Python.framework/Versions/Current/bin/python", - app_dir - ); - - // Build new arguments list, forwarding original arguments. - new_argv[0] = python_path; - new_argv[1] = "-s"; - new_argv[2] = "-m"; - new_argv[3] = "plover.scripts.dist_main"; - memcpy(new_argv + 4, argv + 1, argc * sizeof (argv[0])); - - return execv(new_argv[0], new_argv); -} diff --git a/osx/app_resources/plover_launcher.m b/osx/app_resources/plover_launcher.m new file mode 100644 index 000000000..eba4f9edd --- /dev/null +++ b/osx/app_resources/plover_launcher.m @@ -0,0 +1,91 @@ +#import +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + @autoreleasepool { + char python_home[PATH_MAX]; + char app_dir_c[PATH_MAX]; + char *app_dir = realpath(argv[0], NULL); + app_dir = dirname(dirname(app_dir)); + strncpy(app_dir_c, app_dir, sizeof(app_dir_c) - 1); + app_dir_c[sizeof(app_dir_c) - 1] = '\0'; + + snprintf(python_home, sizeof(python_home), "%s/Frameworks/Python.framework/Versions/Current", app_dir_c); + + // Set PYTHONUSERBASE to enable user plugins + char *home = getenv("HOME"); + if (home) { + char python_user_base[PATH_MAX]; + snprintf(python_user_base, sizeof(python_user_base), "%s/Library/Application Support/plover/plugins/mac", home); + setenv("PYTHONUSERBASE", python_user_base, 1); + } + + wchar_t *python_home_w = Py_DecodeLocale(python_home, NULL); + if (python_home_w == NULL) { + fprintf(stderr, "Fatal error: unable to decode python_home\n"); + return 1; + } + + // Set program name + wchar_t* program = Py_DecodeLocale(argv[0], NULL); + + PyConfig config; + PyConfig_InitPythonConfig(&config); + PyConfig_SetString(&config, &config.home, python_home_w); + PyConfig_SetString(&config, &config.program_name, program); + PyConfig_SetBytesArgv(&config, argc, argv); // This automatically populates sys.argv + + Py_InitializeFromConfig(&config); + PyConfig_Clear(&config); + // ------------------------------ + + // After this point, we are in a Python interpreter. + + // Prepend the site-packages to sys.path + char site_packages[PATH_MAX]; + snprintf(site_packages, sizeof(site_packages), "%s/lib/python3.13/site-packages", python_home); + wchar_t *site_packages_w = Py_DecodeLocale(site_packages, NULL); + PyObject* sys_path = PySys_GetObject("path"); + PyList_Insert(sys_path, 0, PyUnicode_FromWideChar(site_packages_w, -1)); + PyMem_RawFree(site_packages_w); + + // Run the main script + PyObject* pName = PyUnicode_FromString("plover.scripts.main"); + PyObject* pModule = PyImport_Import(pName); + Py_DECREF(pName); + + if (pModule != NULL) { + PyObject* pFunc = PyObject_GetAttrString(pModule, "main"); + if (pFunc && PyCallable_Check(pFunc)) { + + // Call main() - argv is already set in sys.argv! + PyObject* pResult = PyObject_CallObject(pFunc, NULL); + + if (pResult == NULL) { + PyErr_Print(); + fprintf(stderr, "Call to main failed.\n"); + return 1; + } + Py_DECREF(pResult); + + } else { + if (PyErr_Occurred()) PyErr_Print(); + fprintf(stderr, "Cannot find function \"main\"\n"); + } + Py_XDECREF(pFunc); + Py_DECREF(pModule); + } else { + PyErr_Print(); + fprintf(stderr, "Failed to load \"plover.scripts.main\"\n"); + return 1; + } + + Py_Finalize(); + PyMem_RawFree(python_home_w); + PyMem_RawFree(program); + return 0; + } +} diff --git a/osx/make_app.sh b/osx/make_app.sh index ba80ce656..b50c46305 100644 --- a/osx/make_app.sh +++ b/osx/make_app.sh @@ -94,7 +94,8 @@ bootstrap_dist "$plover_wheel" "${extra_args[@]}" run bash osx/check_universal.sh "$frameworks_dir/Python.framework" "${py_version%.*}" # Create launcher. -run gcc -Wall -O2 -arch x86_64 -arch arm64 'osx/app_resources/plover_launcher.c' -o "$macos_dir/Plover" +run gcc -Wall -O2 -arch x86_64 -arch arm64 -F"$appdir/Contents/Frameworks" -Wl,-rpath,@executable_path/../Frameworks -Wl,-rpath,@executable_path/../Frameworks/Python.framework -I"$py_home/include/python${py_version%.*}" -framework Cocoa -framework Python 'osx/app_resources/plover_launcher.m' -o "$macos_dir/Plover" +run install_name_tool -change "@rpath/Versions/${py_version%.*}/Python" "@rpath/Python.framework/Versions/${py_version%.*}/Python" "$macos_dir/Plover" # Copy icon. run cp 'osx/app_resources/plover.icns' "$resources_dir/plover.icns" diff --git a/pyproject.toml b/pyproject.toml index 08ab9e348..ccbf3557c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [build-system] requires = [ - "Babel", + "babel", "PySide6>=6.9.0", "setuptools>=79.0.0", "wheel", diff --git a/reqs/setup.txt b/reqs/setup.txt index dd0bfbddc..3423c3ab9 100644 --- a/reqs/setup.txt +++ b/reqs/setup.txt @@ -1,4 +1,4 @@ -Babel +babel PySide6 setuptools wheel