macOS: Fix a regression that could cause a crash on exit if any books were deleted while calibre was running. Fixes #1839044 [calibre crash when deleting ebook](https://bugs.launchpad.net/calibre/+bug/1839044)

This commit is contained in:
Kovid Goyal 2019-08-06 11:46:15 +05:30
parent ec0515d409
commit 520cf5f39f
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 25 additions and 15 deletions

View File

@ -8,6 +8,7 @@ __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
import os, tempfile, shutil, errno, time, atexit import os, tempfile, shutil, errno, time, atexit
from threading import Thread from threading import Thread
from calibre.constants import isosx, plugins
from calibre.ptempfile import remove_dir from calibre.ptempfile import remove_dir
from calibre.utils.filenames import remove_dir_if_empty from calibre.utils.filenames import remove_dir_if_empty
from calibre.utils.recycle_bin import delete_tree, delete_file from calibre.utils.recycle_bin import delete_tree, delete_file
@ -33,6 +34,8 @@ class DeleteService(Thread):
def __init__(self): def __init__(self):
Thread.__init__(self) Thread.__init__(self)
self.requests = Queue() self.requests = Queue()
if isosx:
plugins['cocoa'][0].enable_cocoa_multithreading()
def shutdown(self, timeout=20): def shutdown(self, timeout=20):
self.requests.put(None) self.requests.put(None)

View File

@ -9,19 +9,22 @@
#include <Cocoa/Cocoa.h> #include <Cocoa/Cocoa.h>
#include <string.h> #include <string.h>
void
activate_cocoa_multithreading(void) {
if (![NSThread isMultiThreaded]) [[NSThread new] start];
}
const char* const char*
cocoa_send2trash(const char *utf8_path) { cocoa_send2trash(const char *utf8_path) {
NSString *path = [[NSString alloc] initWithUTF8String:utf8_path]; @autoreleasepool {
NSURL *url = [NSURL fileURLWithPath:path];
const char *ret = NULL; const char *ret = NULL;
NSError* ns_error = nil; NSError* ns_error = nil;
if (![[NSFileManager defaultManager] trashItemAtURL:url resultingItemURL:nil error:&ns_error]) { if (![[NSFileManager defaultManager] trashItemAtURL:[NSURL fileURLWithPath:@(utf8_path)] resultingItemURL:nil error:&ns_error]) {
ret = strdup([[ns_error localizedDescription] UTF8String]); ret = strdup([[ns_error localizedDescription] UTF8String]);
} }
[url release];
[path release];
return ret; return ret;
} }
}
extern void macos_notification_callback(const char*); extern void macos_notification_callback(const char*);
@ -32,16 +35,14 @@ extern void macos_notification_callback(const char*);
void void
cocoa_send_notification(const char *identifier, const char *title, const char *subtitle, const char *informativeText, const char* path_to_image) { cocoa_send_notification(const char *identifier, const char *title, const char *subtitle, const char *informativeText, const char* path_to_image) {
@autoreleasepool {
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter]; NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
if (!center) {return;} if (!center) {return;}
if (!center.delegate) center.delegate = [[NotificationDelegate alloc] init]; if (!center.delegate) center.delegate = [[NotificationDelegate alloc] init];
NSUserNotification *n = [NSUserNotification new]; NSUserNotification *n = [NSUserNotification new];
NSImage *img = nil; NSImage *img = nil;
if (path_to_image) { if (path_to_image) {
NSString *p = [NSString stringWithUTF8String:path_to_image]; img = [[NSImage alloc] initWithContentsOfURL:[NSURL fileURLWithPath:@(path_to_image)]];
NSURL *url = [NSURL fileURLWithPath:p];
img = [[NSImage alloc] initWithContentsOfURL:url];
[url release]; [p release];
if (img) { if (img) {
[n setValue:img forKey:@"_identityImage"]; [n setValue:img forKey:@"_identityImage"];
[n setValue:@(false) forKey:@"_identityImageHasBorder"]; [n setValue:@(false) forKey:@"_identityImageHasBorder"];
@ -50,17 +51,15 @@ cocoa_send_notification(const char *identifier, const char *title, const char *s
} }
#define SET(x) { \ #define SET(x) { \
if (x) { \ if (x) { \
NSString *t = [NSString stringWithUTF8String:x]; \ n.x = @(x); \
n.x = t; \
[t release]; \
}} }}
SET(title); SET(subtitle); SET(informativeText); SET(title); SET(subtitle); SET(informativeText);
#undef SET #undef SET
if (identifier) { if (identifier) {
n.userInfo = @{@"user_id": [NSString stringWithUTF8String:identifier]}; n.userInfo = @{@"user_id": @(identifier)};
} }
[center deliverNotification:n]; [center deliverNotification:n];
}
} }
@implementation NotificationDelegate @implementation NotificationDelegate

View File

@ -10,6 +10,7 @@
extern double cocoa_cursor_blink_time(void); 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 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); extern const char* cocoa_send2trash(const char *utf8_path);
extern void activate_cocoa_multithreading(void);
static PyObject *notification_activated_callback = NULL; static PyObject *notification_activated_callback = NULL;
@ -63,8 +64,15 @@ send2trash(PyObject *self, PyObject *args) {
Py_RETURN_NONE; Py_RETURN_NONE;
} }
static PyObject*
enable_cocoa_multithreading(PyObject *self, PyObject *args) {
activate_cocoa_multithreading();
Py_RETURN_NONE;
}
static PyMethodDef module_methods[] = { static PyMethodDef module_methods[] = {
{"cursor_blink_time", (PyCFunction)cursor_blink_time, METH_NOARGS, ""}, {"cursor_blink_time", (PyCFunction)cursor_blink_time, METH_NOARGS, ""},
{"enable_cocoa_multithreading", (PyCFunction)enable_cocoa_multithreading, METH_NOARGS, ""},
{"set_notification_activated_callback", (PyCFunction)set_notification_activated_callback, METH_O, ""}, {"set_notification_activated_callback", (PyCFunction)set_notification_activated_callback, METH_O, ""},
{"send_notification", (PyCFunction)send_notification, METH_VARARGS, ""}, {"send_notification", (PyCFunction)send_notification, METH_VARARGS, ""},
{"send2trash", (PyCFunction)send2trash, METH_VARARGS, ""}, {"send2trash", (PyCFunction)send2trash, METH_VARARGS, ""},