mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
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:
parent
ec0515d409
commit
520cf5f39f
@ -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)
|
||||||
|
@ -9,18 +9,21 @@
|
|||||||
#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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -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
|
||||||
|
@ -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, ""},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user