mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Modernize the code used to interact with macOS
Recycle bin and notifications code. The old recycle bin code was deprecated. Notifications support has been moved in-process.
This commit is contained in:
parent
b5230d9bd8
commit
cff789f12c
@ -53,27 +53,6 @@
|
||||
|
||||
#define NUKE(x) Py_XDECREF(x); x = NULL;
|
||||
|
||||
/* This function only works on 10.5 and later. Pass in a unicode object as path */
|
||||
static PyObject* usbobserver_send2trash(PyObject *self, PyObject *args)
|
||||
{
|
||||
UInt8 *utf8_chars;
|
||||
FSRef fp;
|
||||
OSStatus op_result;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "es", "utf-8", &utf8_chars)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FSPathMakeRefWithOptions(utf8_chars, kFSPathMakeRefDoNotFollowLeafSymlink, &fp, NULL);
|
||||
op_result = FSMoveObjectToTrashSync(&fp, NULL, kFSFileOperationDefaultOptions);
|
||||
PyMem_Free(utf8_chars);
|
||||
if (op_result != noErr) {
|
||||
PyErr_SetString(PyExc_OSError, GetMacOSStatusCommentString(op_result));
|
||||
return NULL;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
usbobserver_get_iokit_string_property(io_service_t dev, CFStringRef prop) {
|
||||
@ -469,9 +448,6 @@ static PyMethodDef usbobserver_methods[] = {
|
||||
{"get_mounted_filesystems", usbobserver_get_mounted_filesystems, METH_VARARGS,
|
||||
"Get mapping of mounted filesystems. Mapping is from BSD name to mount point."
|
||||
},
|
||||
{"send2trash", usbobserver_send2trash, METH_VARARGS,
|
||||
"send2trash(unicode object) -> Send specified file/dir to trash"
|
||||
},
|
||||
{"user_locale", usbobserver_user_locale, METH_VARARGS,
|
||||
"user_locale() -> The name of the current user's locale or None if an error occurred"
|
||||
},
|
||||
|
@ -9,7 +9,7 @@ __docformat__ = 'restructuredtext en'
|
||||
|
||||
import time
|
||||
from calibre import prints
|
||||
from calibre.constants import islinux, isosx, get_osx_version, DEBUG, ispy3
|
||||
from calibre.constants import islinux, isosx, get_osx_version, DEBUG, plugins
|
||||
from polyglot.builtins import unicode_type
|
||||
|
||||
|
||||
@ -132,32 +132,15 @@ class DummyNotifier(Notifier):
|
||||
class AppleNotifier(Notifier):
|
||||
|
||||
def __init__(self):
|
||||
self.ok = False
|
||||
import os, sys
|
||||
try:
|
||||
self.exe = os.path.join(sys.console_binaries_path.replace(
|
||||
'console.app', 'calibre-notifier.app'), 'Calibre')
|
||||
self.ok = os.access(self.exe, os.X_OK)
|
||||
import subprocess
|
||||
self.call = subprocess.Popen
|
||||
except:
|
||||
pass
|
||||
self.cocoa, err = plugins['cocoa']
|
||||
self.ok = not err
|
||||
|
||||
def notify(self, body, summary):
|
||||
def encode(x):
|
||||
if ispy3:
|
||||
if isinstance(x, bytes):
|
||||
x = x.decode('utf-8')
|
||||
else:
|
||||
if isinstance(x, unicode_type):
|
||||
x = x.encode('utf-8')
|
||||
return x
|
||||
|
||||
cmd = [self.exe, '-activate',
|
||||
'net.kovidgoyal.calibre', '-message', encode(body)]
|
||||
if summary:
|
||||
cmd += ['-title', encode(summary)]
|
||||
self.call(cmd)
|
||||
title, informative_text = summary, body
|
||||
else:
|
||||
title, informative_text = body, None
|
||||
self.cocoa.send_notification(None, title, informative_text)
|
||||
|
||||
def __call__(self, body, summary=None, replaces_id=None, timeout=0):
|
||||
timeout, body, summary = self.get_msg_parms(timeout, body, summary)
|
||||
|
@ -7,6 +7,80 @@
|
||||
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <string.h>
|
||||
|
||||
const char*
|
||||
cocoa_send2trash(const char *utf8_path) {
|
||||
NSString *path = [[NSString alloc] initWithUTF8String:utf8_path];
|
||||
NSURL *url = [NSURL fileURLWithPath:path];
|
||||
const char *ret = NULL;
|
||||
NSError* ns_error = nil;
|
||||
if (![[NSFileManager defaultManager] trashItemAtURL:url resultingItemURL:nil error:&ns_error]) {
|
||||
ret = strdup([[ns_error localizedDescription] UTF8String]);
|
||||
}
|
||||
[url release];
|
||||
[path release];
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
extern void macos_notification_callback(const char*);
|
||||
|
||||
@interface NotificationDelegate : NSObject <NSUserNotificationCenterDelegate>
|
||||
@end
|
||||
|
||||
|
||||
void
|
||||
cocoa_send_notification(const char *identifier, const char *title, const char *subtitle, const char *informativeText, const char* path_to_image) {
|
||||
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
|
||||
if (!center) {return;}
|
||||
if (!center.delegate) center.delegate = [[NotificationDelegate alloc] init];
|
||||
NSUserNotification *n = [NSUserNotification new];
|
||||
NSImage *img = nil;
|
||||
if (path_to_image) {
|
||||
NSString *p = [NSString stringWithUTF8String:path_to_image];
|
||||
NSURL *url = [NSURL fileURLWithPath:p];
|
||||
img = [[NSImage alloc] initWithContentsOfURL:url];
|
||||
[url release]; [p release];
|
||||
if (img) {
|
||||
[n setValue:img forKey:@"_identityImage"];
|
||||
[n setValue:@(false) forKey:@"_identityImageHasBorder"];
|
||||
}
|
||||
[img release];
|
||||
}
|
||||
#define SET(x) { \
|
||||
if (x) { \
|
||||
NSString *t = [NSString stringWithUTF8String:x]; \
|
||||
n.x = t; \
|
||||
[t release]; \
|
||||
}}
|
||||
SET(title); SET(subtitle); SET(informativeText);
|
||||
#undef SET
|
||||
if (identifier) {
|
||||
n.userInfo = @{@"user_id": [NSString stringWithUTF8String:identifier]};
|
||||
}
|
||||
[center deliverNotification:n];
|
||||
|
||||
}
|
||||
|
||||
@implementation NotificationDelegate
|
||||
- (void)userNotificationCenter:(NSUserNotificationCenter *)center
|
||||
didDeliverNotification:(NSUserNotification *)notification {
|
||||
(void)(center); (void)(notification);
|
||||
}
|
||||
|
||||
- (BOOL) userNotificationCenter:(NSUserNotificationCenter *)center
|
||||
shouldPresentNotification:(NSUserNotification *)notification {
|
||||
(void)(center); (void)(notification);
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void) userNotificationCenter:(NSUserNotificationCenter *)center
|
||||
didActivateNotification:(NSUserNotification *)notification {
|
||||
(void)(center);
|
||||
macos_notification_callback(notification.userInfo[@"user_id"] ? [notification.userInfo[@"user_id"] UTF8String] : NULL);
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
double
|
||||
|
@ -8,6 +8,10 @@
|
||||
#include <Python.h>
|
||||
|
||||
extern double cocoa_cursor_blink_time(void);
|
||||
extern void cocoa_send_notification(const char *identitifer, const char *title, const char *subtitle, const char *informativeText, const char* path_to_image);
|
||||
extern const char* cocoa_send2trash(const char *utf8_path);
|
||||
|
||||
static PyObject *notification_activated_callback = NULL;
|
||||
|
||||
static PyObject*
|
||||
cursor_blink_time(PyObject *self) {
|
||||
@ -16,8 +20,54 @@ cursor_blink_time(PyObject *self) {
|
||||
return PyFloat_FromDouble(ans);
|
||||
}
|
||||
|
||||
void
|
||||
macos_notification_callback(const char* user_id) {
|
||||
if (notification_activated_callback) {
|
||||
PyObject *ret = PyObject_CallFunction(notification_activated_callback, "z", user_id);
|
||||
if (ret == NULL) PyErr_Print();
|
||||
else Py_DECREF(ret);
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
set_notification_activated_callback(PyObject *self, PyObject *callback) {
|
||||
(void)self;
|
||||
if (notification_activated_callback) Py_DECREF(notification_activated_callback);
|
||||
notification_activated_callback = callback;
|
||||
Py_INCREF(callback);
|
||||
Py_RETURN_NONE;
|
||||
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
send_notification(PyObject *self, PyObject *args) {
|
||||
(void)self;
|
||||
char *identifier = NULL, *title = NULL, *subtitle = NULL, *informativeText = NULL, *path_to_image = NULL;
|
||||
if (!PyArg_ParseTuple(args, "zsz|zz", &identifier, &title, &informativeText, &path_to_image, &subtitle)) return NULL;
|
||||
cocoa_send_notification(identifier, title, subtitle, informativeText, path_to_image);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
send2trash(PyObject *self, PyObject *args) {
|
||||
(void)self;
|
||||
char *path = NULL;
|
||||
if (!PyArg_ParseTuple(args, "s", &path)) return NULL;
|
||||
const char *err = cocoa_send2trash(path);
|
||||
if (err) {
|
||||
PyErr_SetString(PyExc_OSError, err);
|
||||
free((void*)err);
|
||||
return NULL;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
{"cursor_blink_time", (PyCFunction)cursor_blink_time, METH_NOARGS, ""},
|
||||
{"set_notification_activated_callback", (PyCFunction)set_notification_activated_callback, METH_O, ""},
|
||||
{"send_notification", (PyCFunction)send_notification, METH_VARARGS, ""},
|
||||
{"send2trash", (PyCFunction)send2trash, METH_VARARGS, ""},
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
@ -89,7 +89,7 @@ if iswindows:
|
||||
return delegate_recycle(path)
|
||||
|
||||
elif isosx:
|
||||
u = plugins['usbobserver'][0]
|
||||
u = plugins['cocoa'][0]
|
||||
if hasattr(u, 'send2trash'):
|
||||
def osx_recycle(path):
|
||||
if isbytestring(path):
|
||||
|
Loading…
x
Reference in New Issue
Block a user