mirror of
				https://github.com/kovidgoyal/calibre.git
				synced 2025-11-03 19:17:02 -05: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,35 +35,31 @@ 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"];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        [img release];
 | 
							[img release];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
#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