macOS: Allow opening URLs with kitty

This commit is contained in:
pagedown
2022-02-03 22:10:59 +08:00
parent 80a62c8d71
commit 51d591e177
11 changed files with 72 additions and 54 deletions

View File

@@ -358,32 +358,49 @@ static GLFWapplicationwillfinishlaunchingfun finish_launching_callback = NULL;
finish_launching_callback();
}
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename {
(void)theApplication;
if (!filename || !_glfw.ns.file_open_callback) return NO;
const char *path = NULL;
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
(void)sender;
if (!filename || !_glfw.ns.url_open_callback) return NO;
const char *url = NULL;
@try {
path = [[NSFileManager defaultManager] fileSystemRepresentationWithPath: filename];
url = [[[NSURL fileURLWithPath:filename] absoluteString] UTF8String];
} @catch(NSException *exc) {
NSLog(@"Converting openFile filename: %@ failed with error: %@", filename, exc.reason);
return NO;
}
if (!path) return NO;
return _glfw.ns.file_open_callback(path);
if (!url) return NO;
return _glfw.ns.url_open_callback(url);
}
- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames {
(void)sender;
if (!_glfw.ns.file_open_callback || !filenames) return;
if (!_glfw.ns.url_open_callback || !filenames) return;
for (id x in filenames) {
NSString *filename = x;
const char *path = NULL;
const char *url = NULL;
@try {
path = [[NSFileManager defaultManager] fileSystemRepresentationWithPath: filename];
url = [[[NSURL fileURLWithPath:filename] absoluteString] UTF8String];
} @catch(NSException *exc) {
NSLog(@"Converting openFiles filename: %@ failed with error: %@", filename, exc.reason);
}
if (path) _glfw.ns.file_open_callback(path);
if (url) _glfw.ns.url_open_callback(url);
}
}
// Remove openFile and openFiles when the minimum supported macOS version is 10.13
- (void)application:(NSApplication *)sender openURLs:(NSArray<NSURL *> *)urls
{
(void)sender;
if (!_glfw.ns.url_open_callback || !urls) return;
for (id x in urls) {
NSURL *ns_url = x;
const char *url = NULL;
@try {
url = [[ns_url absoluteString] UTF8String];
} @catch(NSException *exc) {
NSLog(@"Converting openURLs url: %@ failed with error: %@", ns_url, exc.reason);
}
if (url) _glfw.ns.url_open_callback(url);
}
}
@@ -391,7 +408,7 @@ static GLFWapplicationwillfinishlaunchingfun finish_launching_callback = NULL;
{
(void)notification;
[NSApp stop:nil];
if (_glfw.ns.file_open_callback) _glfw.ns.file_open_callback(":cocoa::application launched::");
if (_glfw.ns.url_open_callback) _glfw.ns.url_open_callback(":cocoa::application launched::");
CGDisplayRegisterReconfigurationCallback(display_reconfigured, NULL);
_glfwCocoaPostEmptyEvent();

View File

@@ -68,7 +68,7 @@ typedef void* CVDisplayLinkRef;
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int, unsigned long);
typedef bool (* GLFWapplicationshouldhandlereopenfun)(int);
typedef bool (* GLFWhandlefileopen)(const char*);
typedef bool (* GLFWhandleurlopen)(const char*);
typedef void (* GLFWapplicationwillfinishlaunchingfun)(void);
typedef bool (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
typedef void (* GLFWcocoarenderframefun)(GLFWwindow*);
@@ -199,8 +199,8 @@ typedef struct _GLFWlibraryNS
_GLFWDisplayLinkNS entries[256];
size_t count;
} displayLinks;
// the callback to handle file open events
GLFWhandlefileopen file_open_callback;
// the callback to handle url open events
GLFWhandleurlopen url_open_callback;
} _GLFWlibraryNS;

View File

@@ -2642,10 +2642,10 @@ GLFWAPI GLFWcocoatextinputfilterfun glfwSetCocoaTextInputFilter(GLFWwindow *hand
return previous;
}
GLFWAPI GLFWhandlefileopen glfwSetCocoaFileOpenCallback(GLFWhandlefileopen callback) {
GLFWAPI GLFWhandleurlopen glfwSetCocoaURLOpenCallback(GLFWhandleurlopen callback) {
_GLFW_REQUIRE_INIT_OR_RETURN(nil);
GLFWhandlefileopen prev = _glfw.ns.file_open_callback;
_glfw.ns.file_open_callback = callback;
GLFWhandleurlopen prev = _glfw.ns.url_open_callback;
_glfw.ns.url_open_callback = callback;
return prev;
}

View File

@@ -233,7 +233,7 @@ def generate_wrappers(glfw_header: str) -> None:
void* glfwGetNSGLContext(GLFWwindow *window)
uint32_t glfwGetCocoaMonitor(GLFWmonitor* monitor)
GLFWcocoatextinputfilterfun glfwSetCocoaTextInputFilter(GLFWwindow* window, GLFWcocoatextinputfilterfun callback)
GLFWhandlefileopen glfwSetCocoaFileOpenCallback(GLFWhandlefileopen callback)
GLFWhandleurlopen glfwSetCocoaURLOpenCallback(GLFWhandleurlopen callback)
GLFWcocoatogglefullscreenfun glfwSetCocoaToggleFullscreenIntercept(GLFWwindow *window, GLFWcocoatogglefullscreenfun callback)
GLFWapplicationshouldhandlereopenfun glfwSetApplicationShouldHandleReopen(GLFWapplicationshouldhandlereopenfun callback)
GLFWapplicationwillfinishlaunchingfun glfwSetApplicationWillFinishLaunching(GLFWapplicationwillfinishlaunchingfun callback)
@@ -277,7 +277,7 @@ const char *action_text, int32_t timeout, GLFWDBusnotificationcreatedfun callbac
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int,unsigned long);
typedef bool (* GLFWapplicationshouldhandlereopenfun)(int);
typedef bool (* GLFWhandlefileopen)(const char*);
typedef bool (* GLFWhandleurlopen)(const char*);
typedef void (* GLFWapplicationwillfinishlaunchingfun)(void);
typedef bool (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
typedef void (* GLFWcocoarenderframefun)(GLFWwindow*);

View File

@@ -2234,13 +2234,13 @@ class Boss:
output = '\n'.join(f'{k}={v}' for k, v in os.environ.items())
self.display_scrollback(w, output, title=_('Current kitty env vars'), report_cursor=False)
def open_file(self, path: str) -> None:
if path == ":cocoa::application launched::":
def launch_url(self, url: str) -> None:
if url == ":cocoa::application launched::":
self.cocoa_application_launched = True
return
from .open_actions import actions_for_launch
from .launch import force_window_launch
actions = list(actions_for_launch(path))
actions = list(actions_for_launch(url))
tab = self.active_tab
if tab is not None:
w = tab.active_window
@@ -2254,7 +2254,7 @@ class Boss:
if not actions:
with force_window_launch(needs_window_replaced):
self.launch(kitty_exe(), '+runpy', f'print("The file:", {path!r}, "is of unknown type, cannot open it.");'
self.launch(kitty_exe(), '+runpy', f'print("The url:", {url!r}, "is of unknown type, cannot open it.");'
'from kitty.utils import hold_till_enter; hold_till_enter(); raise SystemExit(1)')
clear_initial_window()
else:

View File

@@ -1001,18 +1001,18 @@ static bool cocoa_pending_actions[NUM_COCOA_PENDING_ACTIONS] = {0};
static bool has_cocoa_pending_actions = false;
typedef struct {
char* wd;
char **open_files;
size_t open_files_count;
size_t open_files_capacity;
char **open_urls;
size_t open_urls_count;
size_t open_urls_capacity;
} CocoaPendingActionsData;
static CocoaPendingActionsData cocoa_pending_actions_data = {0};
void
set_cocoa_pending_action(CocoaPendingAction action, const char *wd) {
if (wd) {
if (action == OPEN_FILE) {
ensure_space_for(&cocoa_pending_actions_data, open_files, char*, cocoa_pending_actions_data.open_files_count + 8, open_files_capacity, 8, true);
cocoa_pending_actions_data.open_files[cocoa_pending_actions_data.open_files_count++] = strdup(wd);
if (action == LAUNCH_URL) {
ensure_space_for(&cocoa_pending_actions_data, open_urls, char*, cocoa_pending_actions_data.open_urls_count + 8, open_urls_capacity, 8, true);
cocoa_pending_actions_data.open_urls[cocoa_pending_actions_data.open_urls_count++] = strdup(wd);
} else {
if (cocoa_pending_actions_data.wd) free(cocoa_pending_actions_data.wd);
cocoa_pending_actions_data.wd = strdup(wd);
@@ -1047,15 +1047,15 @@ process_cocoa_pending_actions(void) {
free(cocoa_pending_actions_data.wd);
cocoa_pending_actions_data.wd = NULL;
}
if (cocoa_pending_actions_data.open_files_count) {
for (unsigned cpa = 0; cpa < cocoa_pending_actions_data.open_files_count; cpa++) {
if (cocoa_pending_actions_data.open_files[cpa]) {
call_boss(open_file, "s", cocoa_pending_actions_data.open_files[cpa]);
free(cocoa_pending_actions_data.open_files[cpa]);
cocoa_pending_actions_data.open_files[cpa] = NULL;
if (cocoa_pending_actions_data.open_urls_count) {
for (unsigned cpa = 0; cpa < cocoa_pending_actions_data.open_urls_count; cpa++) {
if (cocoa_pending_actions_data.open_urls[cpa]) {
call_boss(launch_url, "s", cocoa_pending_actions_data.open_urls[cpa]);
free(cocoa_pending_actions_data.open_urls[cpa]);
cocoa_pending_actions_data.open_urls[cpa] = NULL;
}
}
cocoa_pending_actions_data.open_files_count = 0;
cocoa_pending_actions_data.open_urls_count = 0;
}
memset(cocoa_pending_actions, 0, sizeof(cocoa_pending_actions));
has_cocoa_pending_actions = false;
@@ -1115,11 +1115,11 @@ main_loop(ChildMonitor *self, PyObject *a UNUSED) {
run_main_loop(process_global_state, self);
#ifdef __APPLE__
if (cocoa_pending_actions_data.wd) { free(cocoa_pending_actions_data.wd); cocoa_pending_actions_data.wd = NULL; }
if (cocoa_pending_actions_data.open_files) {
for (unsigned cpa = 0; cpa < cocoa_pending_actions_data.open_files_count; cpa++) {
if (cocoa_pending_actions_data.open_files[cpa]) free(cocoa_pending_actions_data.open_files[cpa]);
if (cocoa_pending_actions_data.open_urls) {
for (unsigned cpa = 0; cpa < cocoa_pending_actions_data.open_urls_count; cpa++) {
if (cocoa_pending_actions_data.open_urls[cpa]) free(cocoa_pending_actions_data.open_urls[cpa]);
}
free(cocoa_pending_actions_data.open_files); cocoa_pending_actions_data.open_files = NULL;
free(cocoa_pending_actions_data.open_urls); cocoa_pending_actions_data.open_urls = NULL;
}
#endif
if (PyErr_Occurred()) return NULL;

6
kitty/glfw-wrapper.c generated
View File

@@ -1,4 +1,6 @@
// generated by glfw.py DO NOT edit
#define GFW_EXTERN
#include "data-types.h"
#include "glfw-wrapper.h"
@@ -405,8 +407,8 @@ load_glfw(const char* path) {
*(void **) (&glfwSetCocoaTextInputFilter_impl) = dlsym(handle, "glfwSetCocoaTextInputFilter");
if (glfwSetCocoaTextInputFilter_impl == NULL) dlerror(); // clear error indicator
*(void **) (&glfwSetCocoaFileOpenCallback_impl) = dlsym(handle, "glfwSetCocoaFileOpenCallback");
if (glfwSetCocoaFileOpenCallback_impl == NULL) dlerror(); // clear error indicator
*(void **) (&glfwSetCocoaURLOpenCallback_impl) = dlsym(handle, "glfwSetCocoaURLOpenCallback");
if (glfwSetCocoaURLOpenCallback_impl == NULL) dlerror(); // clear error indicator
*(void **) (&glfwSetCocoaToggleFullscreenIntercept_impl) = dlsym(handle, "glfwSetCocoaToggleFullscreenIntercept");
if (glfwSetCocoaToggleFullscreenIntercept_impl == NULL) dlerror(); // clear error indicator

8
kitty/glfw-wrapper.h generated
View File

@@ -1597,7 +1597,7 @@ typedef struct GLFWgamepadstate
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int,unsigned long);
typedef bool (* GLFWapplicationshouldhandlereopenfun)(int);
typedef bool (* GLFWhandlefileopen)(const char*);
typedef bool (* GLFWhandleurlopen)(const char*);
typedef void (* GLFWapplicationwillfinishlaunchingfun)(void);
typedef bool (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
typedef void (* GLFWcocoarenderframefun)(GLFWwindow*);
@@ -2124,9 +2124,9 @@ typedef GLFWcocoatextinputfilterfun (*glfwSetCocoaTextInputFilter_func)(GLFWwind
GFW_EXTERN glfwSetCocoaTextInputFilter_func glfwSetCocoaTextInputFilter_impl;
#define glfwSetCocoaTextInputFilter glfwSetCocoaTextInputFilter_impl
typedef GLFWhandlefileopen (*glfwSetCocoaFileOpenCallback_func)(GLFWhandlefileopen);
GFW_EXTERN glfwSetCocoaFileOpenCallback_func glfwSetCocoaFileOpenCallback_impl;
#define glfwSetCocoaFileOpenCallback glfwSetCocoaFileOpenCallback_impl
typedef GLFWhandleurlopen (*glfwSetCocoaURLOpenCallback_func)(GLFWhandleurlopen);
GFW_EXTERN glfwSetCocoaURLOpenCallback_func glfwSetCocoaURLOpenCallback_impl;
#define glfwSetCocoaURLOpenCallback glfwSetCocoaURLOpenCallback_impl
typedef GLFWcocoatogglefullscreenfun (*glfwSetCocoaToggleFullscreenIntercept_func)(GLFWwindow*, GLFWcocoatogglefullscreenfun);
GFW_EXTERN glfwSetCocoaToggleFullscreenIntercept_func glfwSetCocoaToggleFullscreenIntercept_impl;

View File

@@ -429,8 +429,8 @@ static void get_window_dpi(GLFWwindow *w, double *x, double *y);
#ifdef __APPLE__
static bool
apple_file_open_callback(const char* filepath) {
set_cocoa_pending_action(OPEN_FILE, filepath);
apple_url_open_callback(const char* url) {
set_cocoa_pending_action(LAUNCH_URL, url);
return true;
}
@@ -1003,7 +1003,7 @@ glfw_init(PyObject UNUSED *self, PyObject *args) {
PyObject *ans = glfwInit(monotonic_start_time) ? Py_True: Py_False;
if (ans == Py_True) {
#ifdef __APPLE__
glfwSetCocoaFileOpenCallback(apple_file_open_callback);
glfwSetCocoaURLOpenCallback(apple_url_open_callback);
#else
glfwSetDrawTextFunction(draw_text_callback);
#endif

View File

@@ -9,7 +9,7 @@ from contextlib import suppress
from typing import (
Any, Dict, Iterable, Iterator, List, NamedTuple, Optional, Tuple, cast
)
from urllib.parse import ParseResult, quote, unquote, urlparse
from urllib.parse import ParseResult, unquote, urlparse
from .conf.utils import KeyAction, to_cmdline_implementation
from .constants import config_dir
@@ -254,8 +254,7 @@ def actions_for_url(url: str, actions_spec: Optional[str] = None) -> Iterator[Ke
yield from actions_for_url_from_list(url, actions)
def actions_for_launch(path: str) -> Iterator[KeyAction]:
url = f'file://{quote(path)}'
def actions_for_launch(url: str) -> Iterator[KeyAction]:
found = False
for action in actions_for_url_from_list(url, load_launch_actions()):
found = True

View File

@@ -298,7 +298,7 @@ typedef enum {
NEXT_TAB,
PREVIOUS_TAB,
DETACH_TAB,
OPEN_FILE,
LAUNCH_URL,
NEW_WINDOW,
CLOSE_WINDOW,
RESET_TERMINAL,