update osx project

This commit is contained in:
2019-07-11 22:33:58 +02:00
parent b89274e7a6
commit c4633a906f
7 changed files with 114 additions and 183 deletions

View File

@@ -17,9 +17,6 @@
#include <deque> #include <deque>
#include <chrono> #include <chrono>
std::deque<std::packaged_task<void()>> tasklist;
std::mutex task_mutex;
@implementation View @implementation View
{ {
NSSharingService *airdrop_service; NSSharingService *airdrop_service;
@@ -192,136 +189,48 @@ std::mutex task_mutex;
} }
- (void)prepareOpenGL - (void)prepareOpenGL
{ {
[super prepareOpenGL];
NSLog(@"prepare"); NSLog(@"prepare");
// Synchronize buffer swaps with vertical refresh rate // Synchronize buffer swaps with vertical refresh rate
GLint swapInt = 1; GLint swapInt = 1;
[[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
// Create a display link capable of being used with all active displays
CVDisplayLinkCreateWithActiveCGDisplays(&dl);
// Set the renderer output callback function
CVDisplayLinkSetOutputCallback(dl, &MyDisplayLinkCallback, (__bridge void*)self);
// Set the display link for the current renderer
CGLContextObj cglContext = [[self openGLContext] CGLContextObj];
CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj];
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(dl, cglContext, cglPixelFormat);
CGLEnable([self.openGLContext CGLContextObj], kCGLCECrashOnRemovedFunctions);
// Activate the display link
CVDisplayLinkStart(dl);
cgl = [[self openGLContext] CGLContextObj]; cgl = [[self openGLContext] CGLContextObj];
glctx = [self openGLContext]; glctx = [self openGLContext];
CGLLockContext([[self openGLContext] CGLContextObj]); CGLLockContext([[self openGLContext] CGLContextObj]);
App::I.init();
[self.window setTitle:[NSString stringWithFormat:@"%s - %s", g_window_title, glGetString(GL_RENDERER)]]; [self.window setTitle:[NSString stringWithFormat:@"%s - %s", g_window_title, glGetString(GL_RENDERER)]];
CGLUnlockContext([[self openGLContext] CGLContextObj]); CGLUnlockContext([[self openGLContext] CGLContextObj]);
gl_ready = true; gl_ready = true;
App::I->render_thread_start();
App::I->render_sync();
if ([file2open length] > 0) if ([file2open length] > 0)
{ {
LOG("open file %s", [file2open UTF8String]); std::string s = [file2open UTF8String];
App::I.open_document([file2open UTF8String]); App::I->render_task([=]
{
LOG("open file %s", s.c_str());
App::I->open_document(s);
});
} }
} }
- (void)terminateGL - (void)terminateGL
{ {
CVDisplayLinkRelease(dl); App::I->ui_thread_stop();
App::I.terminate(); App::I->render_thread_stop();
} App::I->terminate();
delete App::I;
// This is the renderer output callback function App::I = nullptr;
static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now,
const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
{
CVReturn result = [(__bridge View*)displayLinkContext getFrameForTime:outputTime];
return result;
}
- (CVReturn)getFrameForTime:(const CVTimeStamp*)outputTime
{
static double _timeFreq = CVGetHostClockFrequency();
static double _prevTime = (double)outputTime->hostTime / _timeFreq;
static double elapsed = 0;
double hostTime = (double)outputTime->hostTime;
double now = hostTime / _timeFreq;
double dt = now - _prevTime;
_prevTime = now;
// this will not update unless 1/30th of a second has passed since the last update
//if (now < _prevTime + (1.0 / 30.0))
{
std::deque<std::packaged_task<void()>> working_list;
{
std::lock_guard<std::mutex> lock(task_mutex);
working_list = std::move(tasklist);
}
// We draw on a secondary thread through the display link
// When resizing the view, -reshape is called automatically on the main
// thread. Add a mutex around to avoid the threads accessing the context
// simultaneously when resizing
CGLLockContext([glctx CGLContextObj]);
[glctx makeCurrentContext];
while (!working_list.empty())
{
working_list.front()();
working_list.pop_front();
}
App::I.tick(dt);
if (App::I.redraw)
{
App::I.clear();
App::I.update(elapsed);
elapsed = 0;
CGLFlushDrawable([glctx CGLContextObj]);
}
//[[self openGLContext] flushBuffer];
// returning NO will cause the layer to NOT be redrawn
CGLUnlockContext([glctx CGLContextObj]);
return NO;
}
return kCVReturnSuccess;
}
- (void)dealloc
{
// Release the display link
CVDisplayLinkRelease(dl);
} }
- (void)drawRect:(NSRect)dirtyRect - (void)drawRect:(NSRect)dirtyRect
{ {
NSLog(@"drawRect"); return;
// We draw on a secondary thread through the display link
// When resizing the view, -reshape is called automatically on the main
// thread. Add a mutex around to avoid the threads accessing the context
// simultaneously when resizing
CGLLockContext(cgl);
[glctx makeCurrentContext];
App::I.redraw = true;
App::I.clear();
App::I.update(0);
//[[self openGLContext] flushBuffer];
// returning NO will cause the layer to NOT be redrawn
CGLFlushDrawable(cgl);
CGLUnlockContext(cgl);
} }
- (void)updateTrackingAreas - (void)updateTrackingAreas
{ {
@@ -343,7 +252,6 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
// resizing the view, -drawRect is called on the main thread. // resizing the view, -drawRect is called on the main thread.
// Add a mutex around to avoid the threads accessing the context // Add a mutex around to avoid the threads accessing the context
// simultaneously when resizing. // simultaneously when resizing.
CGLLockContext([[self openGLContext] CGLContextObj]);
#if SUPPORT_RETINA_RESOLUTION #if SUPPORT_RETINA_RESOLUTION
@@ -371,9 +279,10 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
NSRect viewRectPixels = viewRectPoints; NSRect viewRectPixels = viewRectPoints;
#endif // !SUPPORT_RETINA_RESOLUTION #endif // !SUPPORT_RETINA_RESOLUTION
App::I.resize(viewRectPixels.size.width, viewRectPixels.size.height); App::I->ui_task_async([=]
{
CGLUnlockContext([[self openGLContext] CGLContextObj]); App::I->resize(viewRectPixels.size.width, viewRectPixels.size.height);
});
} }
- (void)renewGState - (void)renewGState
{ {
@@ -391,57 +300,50 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
- (void)mouseDown:(NSEvent *)theEvent - (void)mouseDown:(NSEvent *)theEvent
{ {
auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil]; auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
std::lock_guard<std::mutex> lock(task_mutex); App::I->ui_task_async([mouseLoc,p=theEvent.pressure] {
tasklist.emplace_back([mouseLoc,p=theEvent.pressure] { App::I->mouse_down(0, mouseLoc.x, App::I->height - mouseLoc.y - 1, p, kEventSource::Mouse, 0);
App::I.mouse_down(0, mouseLoc.x, App::I.height - mouseLoc.y - 1, p, kEventSource::Mouse, 0);
}); });
} }
- (void)rightMouseDown:(NSEvent *)theEvent - (void)rightMouseDown:(NSEvent *)theEvent
{ {
auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil]; auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
std::lock_guard<std::mutex> lock(task_mutex); App::I->ui_task_async([mouseLoc,p=theEvent.pressure] {
tasklist.emplace_back([mouseLoc,p=theEvent.pressure] { App::I->mouse_down(1, mouseLoc.x, App::I->height - mouseLoc.y - 1, p, kEventSource::Mouse, 0);
App::I.mouse_down(1, mouseLoc.x, App::I.height - mouseLoc.y - 1, p, kEventSource::Mouse, 0);
}); });
} }
- (void)mouseUp:(NSEvent *)theEvent - (void)mouseUp:(NSEvent *)theEvent
{ {
auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil]; auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
std::lock_guard<std::mutex> lock(task_mutex); App::I->ui_task_async([mouseLoc] {
tasklist.emplace_back([mouseLoc] { App::I->mouse_up(0, mouseLoc.x, App::I->height - mouseLoc.y - 1, kEventSource::Mouse, 0);
App::I.mouse_up(0, mouseLoc.x, App::I.height - mouseLoc.y - 1, kEventSource::Mouse, 0);
}); });
} }
- (void)rightMouseUp:(NSEvent *)theEvent - (void)rightMouseUp:(NSEvent *)theEvent
{ {
auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil]; auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
std::lock_guard<std::mutex> lock(task_mutex); App::I->ui_task_async([mouseLoc] {
tasklist.emplace_back([mouseLoc] { App::I->mouse_up(1, mouseLoc.x, App::I->height - mouseLoc.y - 1, kEventSource::Mouse, 0);
App::I.mouse_up(1, mouseLoc.x, App::I.height - mouseLoc.y - 1, kEventSource::Mouse, 0);
}); });
} }
- (void)mouseMoved:(NSEvent *)theEvent - (void)mouseMoved:(NSEvent *)theEvent
{ {
auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil]; auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
std::lock_guard<std::mutex> lock(task_mutex); App::I->ui_task_async([mouseLoc,p=theEvent.pressure] {
tasklist.emplace_back([mouseLoc,p=theEvent.pressure] { App::I->mouse_move(mouseLoc.x, App::I->height - mouseLoc.y - 1, p, kEventSource::Mouse, 0);
App::I.mouse_move(mouseLoc.x, App::I.height - mouseLoc.y - 1, p, kEventSource::Mouse, 0);
}); });
} }
-(void)mouseDragged:(NSEvent *)theEvent -(void)mouseDragged:(NSEvent *)theEvent
{ {
auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil]; auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
std::lock_guard<std::mutex> lock(task_mutex); App::I->ui_task_async([mouseLoc,p=theEvent.pressure] {
tasklist.emplace_back([mouseLoc,p=theEvent.pressure] { App::I->mouse_move(mouseLoc.x, App::I->height - mouseLoc.y - 1, p, kEventSource::Mouse, 0);
App::I.mouse_move(mouseLoc.x, App::I.height - mouseLoc.y - 1, p, kEventSource::Mouse, 0);
}); });
} }
- (void)rightMouseDragged:(NSEvent *)theEvent - (void)rightMouseDragged:(NSEvent *)theEvent
{ {
auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil]; auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
std::lock_guard<std::mutex> lock(task_mutex); App::I->ui_task_async([mouseLoc,p=theEvent.pressure] {
tasklist.emplace_back([mouseLoc,p=theEvent.pressure] { App::I->mouse_move(mouseLoc.x, App::I->height - mouseLoc.y - 1, p, kEventSource::Mouse, 0);
App::I.mouse_move(mouseLoc.x, App::I.height - mouseLoc.y - 1, p, kEventSource::Mouse, 0);
}); });
} }
-(void)mouseExited:(NSEvent *)event -(void)mouseExited:(NSEvent *)event
@@ -459,9 +361,8 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
- (void)scrollWheel:(NSEvent *)theEvent - (void)scrollWheel:(NSEvent *)theEvent
{ {
auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil]; auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
std::lock_guard<std::mutex> lock(task_mutex); App::I->ui_task_async([mouseLoc,d=[theEvent deltaY]] {
tasklist.emplace_back([mouseLoc,d=[theEvent deltaY]] { App::I->mouse_scroll(mouseLoc.x, App::I->height - mouseLoc.y - 1, d);
App::I.mouse_scroll(mouseLoc.x, App::I.height - mouseLoc.y - 1, d);
}); });
} }
- (void)keyDown:(NSEvent *)theEvent - (void)keyDown:(NSEvent *)theEvent
@@ -470,27 +371,25 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
auto chars = [theEvent characters]; auto chars = [theEvent characters];
const char* c_str = [chars cStringUsingEncoding:NSASCIIStringEncoding]; const char* c_str = [chars cStringUsingEncoding:NSASCIIStringEncoding];
std::string s = c_str ? c_str : ""; std::string s = c_str ? c_str : "";
std::lock_guard<std::mutex> lock(task_mutex); App::I->ui_task_async([keyCode, s] {
tasklist.emplace_back([keyCode, s] { if (App::I->keys[(int)kKey::KeyCtrl])
if (App::I.keys[(int)kKey::KeyCtrl])
{ {
App::I.key_down(convert_key(keyCode)); App::I->key_down(convert_key(keyCode));
App::I.key_up(convert_key(keyCode)); App::I->key_up(convert_key(keyCode));
} }
else else
{ {
App::I.key_down(convert_key(keyCode)); App::I->key_down(convert_key(keyCode));
if (!s.empty()) if (!s.empty())
App::I.key_char(s[0]); App::I->key_char(s[0]);
} }
}); });
} }
- (void)keyUp:(NSEvent *)theEvent - (void)keyUp:(NSEvent *)theEvent
{ {
auto keyCode = [theEvent keyCode]; auto keyCode = [theEvent keyCode];
std::lock_guard<std::mutex> lock(task_mutex); App::I->ui_task_async([keyCode] {
tasklist.emplace_back([keyCode] { App::I->key_up(convert_key(keyCode));
App::I.key_up(convert_key(keyCode));
}); });
} }
- (void)flagsChanged:(NSEvent *)event - (void)flagsChanged:(NSEvent *)event
@@ -498,25 +397,24 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
[super flagsChanged:event]; [super flagsChanged:event];
auto flags = [event modifierFlags]; auto flags = [event modifierFlags];
std::lock_guard<std::mutex> lock(task_mutex); App::I->ui_task_async([flags] {
tasklist.emplace_back([flags] {
static bool pressed_shift = false; static bool pressed_shift = false;
if (pressed_shift != (flags & NSShiftKeyMask)) if (pressed_shift != (flags & NSShiftKeyMask))
{ {
pressed_shift = (flags & NSShiftKeyMask); pressed_shift = (flags & NSShiftKeyMask);
pressed_shift ? App::I.key_down(kKey::KeyShift) : App::I.key_up(kKey::KeyShift); pressed_shift ? App::I->key_down(kKey::KeyShift) : App::I->key_up(kKey::KeyShift);
} }
static bool pressed_alt = false; static bool pressed_alt = false;
if (pressed_alt != (flags & NSAlternateKeyMask)) if (pressed_alt != (flags & NSAlternateKeyMask))
{ {
pressed_alt = (flags & NSAlternateKeyMask); pressed_alt = (flags & NSAlternateKeyMask);
pressed_alt ? App::I.key_down(kKey::KeyAlt) : App::I.key_up(kKey::KeyAlt); pressed_alt ? App::I->key_down(kKey::KeyAlt) : App::I->key_up(kKey::KeyAlt);
} }
static bool pressed_cmd = false; static bool pressed_cmd = false;
if (pressed_cmd != (flags & NSCommandKeyMask)) if (pressed_cmd != (flags & NSCommandKeyMask))
{ {
pressed_cmd = (flags & NSCommandKeyMask); pressed_cmd = (flags & NSCommandKeyMask);
pressed_cmd ? App::I.key_down(kKey::KeyCtrl) : App::I.key_up(kKey::KeyCtrl); pressed_cmd ? App::I->key_down(kKey::KeyCtrl) : App::I->key_up(kKey::KeyCtrl);
} }
}); });
} }
@@ -532,7 +430,7 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
} }
-(BOOL)windowShouldClose:(NSWindow *)sender -(BOOL)windowShouldClose:(NSWindow *)sender
{ {
return App::I.request_close(); return App::I->request_close();
} }
@end @end
@@ -555,7 +453,12 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
{ {
LOG("open file %s", [filename UTF8String]); LOG("open file %s", [filename UTF8String]);
if (view && view->gl_ready) if (view && view->gl_ready)
App::I.open_document([filename UTF8String]); {
App::I->ui_task_async([=]
{
App::I->open_document([filename UTF8String]);
});
}
file2open = filename; file2open = filename;
return YES; return YES;
} }
@@ -572,17 +475,18 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
// Do some additional configuration if needed here // Do some additional configuration if needed here
[[BITHockeyManager sharedHockeyManager] startManager]; [[BITHockeyManager sharedHockeyManager] startManager];
if (!App::I.check_license()) if (!App::I->check_license())
return; return;
App::I.initLog(); App::I = new App;
App::I.create(); App::I->initLog();
NSRect r = NSMakeRect(0, 0, App::I.width, App::I.height); App::I->create();
NSRect r = NSMakeRect(0, 0, App::I->width, App::I->height);
view = [[View alloc] initWithFrame:r]; view = [[View alloc] initWithFrame:r];
view->file2open = file2open; view->file2open = file2open;
controller = [[Controller alloc] initWithWindow:window]; controller = [[Controller alloc] initWithWindow:window];
App::I.osx_view = view; App::I->osx_view = view;
auto style = NSTitledWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask|NSClosableWindowMask; auto style = NSTitledWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask|NSClosableWindowMask;
window = [[Window alloc] initWithContentRect:r styleMask:style backing:NSBackingStoreBuffered defer:NO]; window = [[Window alloc] initWithContentRect:r styleMask:style backing:NSBackingStoreBuffered defer:NO];
@@ -609,6 +513,7 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
[appMenuItem setSubmenu:appMenu]; [appMenuItem setSubmenu:appMenu];
NSLog(@"app launched"); NSLog(@"app launched");
App::I->ui_thread_start();
} }
@end @end

View File

@@ -12,7 +12,6 @@
@interface View : NSOpenGLView<NSSharingServiceDelegate> @interface View : NSOpenGLView<NSSharingServiceDelegate>
{ {
@public Window* wnd; @public Window* wnd;
CVDisplayLinkRef dl;
NSOpenGLContext* glctx; NSOpenGLContext* glctx;
_CGLContextObject* cgl; _CGLContextObject* cgl;
bool gl_ready; bool gl_ready;

View File

@@ -24,6 +24,20 @@ void destroy_window();
App* App::I = nullptr; // singleton App* App::I = nullptr; // singleton
std::deque<std::packaged_task<void()>> App::render_tasklist;
std::mutex App::render_task_mutex;
std::condition_variable App::render_cv;
std::thread App::render_thread;
std::thread::id App::render_thread_id;
bool App::render_running = false;
std::deque<std::packaged_task<void()>> App::ui_tasklist;
std::mutex App::ui_task_mutex;
std::condition_variable App::ui_cv;
std::thread App::ui_thread;
std::thread::id App::ui_thread_id;
bool App::ui_running = false;
void App::create() void App::create()
{ {
width = 1920/2; width = 1920/2;

View File

@@ -256,12 +256,12 @@ public:
// RENDER THREAD // RENDER THREAD
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
std::deque<std::packaged_task<void()>> render_tasklist; static std::deque<std::packaged_task<void()>> render_tasklist;
std::mutex render_task_mutex; static std::mutex render_task_mutex;
std::condition_variable render_cv; static std::condition_variable render_cv;
std::thread render_thread; static std::thread render_thread;
std::thread::id render_thread_id; static std::thread::id render_thread_id;
bool render_running = false; static bool render_running;
void render_thread_main(); void render_thread_main();
void render_thread_start(); void render_thread_start();
void render_thread_stop(); void render_thread_stop();
@@ -322,12 +322,12 @@ public:
// UI THREAD // UI THREAD
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
std::deque<std::packaged_task<void()>> ui_tasklist; static std::deque<std::packaged_task<void()>> ui_tasklist;
std::mutex ui_task_mutex; static std::mutex ui_task_mutex;
std::condition_variable ui_cv; static std::condition_variable ui_cv;
std::thread ui_thread; static std::thread ui_thread;
std::thread::id ui_thread_id; static std::thread::id ui_thread_id;
bool ui_running = false; static bool ui_running;
void ui_thread_main(); void ui_thread_main();
void ui_thread_start(); void ui_thread_start();
void ui_thread_stop(); void ui_thread_stop();

View File

@@ -508,13 +508,7 @@ void NodeStrokePreview::draw_stroke()
s_running = true; s_running = true;
s_renderer = std::thread([] { s_renderer = std::thread([] {
BT_SetTerminate(); BT_SetTerminate();
#if __OSX__
// There's some weird multithread bug at startup
// This random wait is a temp fix
// Today is 25/05/2019
// Good luck, future Omar
std::this_thread::sleep_for(std::chrono::seconds(1));
#endif
m_sampler_linear.create(); m_sampler_linear.create();
m_sampler_linear_repeat.create(GL_LINEAR, GL_REPEAT); m_sampler_linear_repeat.create(GL_LINEAR, GL_REPEAT);
m_sampler_mipmap.create(); m_sampler_mipmap.create();
@@ -553,6 +547,8 @@ void NodeStrokePreview::draw_stroke()
gl.restore(); gl.restore();
}); });
node->app_redraw();
//std::this_thread::sleep_for(std::chrono::milliseconds(30)); //std::this_thread::sleep_for(std::chrono::milliseconds(30));
std::this_thread::yield(); std::this_thread::yield();

View File

@@ -3,6 +3,9 @@
#include "log.h" #include "log.h"
#include "app.h" #include "app.h"
#include <atomic> #include <atomic>
#include <iomanip>
#include <ctime>
#include <sstream>
#ifdef __OBJC__ #ifdef __OBJC__
@implementation PathWithModDate @implementation PathWithModDate
@@ -45,8 +48,15 @@ void exception_handler(NSException *exception)
LOG("exception %s\n", [[exception name] cStringUsingEncoding:NSUTF8StringEncoding]); LOG("exception %s\n", [[exception name] cStringUsingEncoding:NSUTF8StringEncoding]);
NSString* callstack = [[NSThread callStackSymbols] componentsJoinedByString:@"\n"]; NSString* callstack = [[NSThread callStackSymbols] componentsJoinedByString:@"\n"];
LOG("base:\n%s\ncallstack:\n%s", base_address.c_str(), [callstack cStringUsingEncoding:NSUTF8StringEncoding]); LOG("base:\n%s\ncallstack:\n%s", base_address.c_str(), [callstack cStringUsingEncoding:NSUTF8StringEncoding]);
if (App::I.canvas && App::I.canvas->m_canvas)
App::I.canvas->m_canvas->project_save_thread(App::I.data_path + "/recovery.ppi"); auto t = std::time(nullptr);
auto tm = *std::localtime(&t);
std::ostringstream oss;
oss << std::put_time(&tm, "%d-%m-%Y %H-%M-%S");
auto path = App::I->data_path + "/" + App::I->doc_name + "-recovery (" + oss.str() + ").ppi";
if (App::I->canvas && App::I->canvas->m_canvas)
App::I->canvas->m_canvas->project_save_thread(path);
exit(0); exit(0);
} }
@@ -56,8 +66,15 @@ static void signal_handler (int signo) {
LOG("signal %d\n", signo); LOG("signal %d\n", signo);
NSString* callstack = [[NSThread callStackSymbols] componentsJoinedByString:@"\n"]; NSString* callstack = [[NSThread callStackSymbols] componentsJoinedByString:@"\n"];
LOG("base:\n%s\ncallstack:\n%s", base_address.c_str(), [callstack cStringUsingEncoding:NSUTF8StringEncoding]); LOG("base:\n%s\ncallstack:\n%s", base_address.c_str(), [callstack cStringUsingEncoding:NSUTF8StringEncoding]);
if (App::I.canvas && App::I.canvas->m_canvas)
App::I.canvas->m_canvas->project_save_thread(App::I.data_path + "/recovery.ppi"); auto t = std::time(nullptr);
auto tm = *std::localtime(&t);
std::ostringstream oss;
oss << std::put_time(&tm, "%d-%m-%Y %H-%M-%S");
auto path = App::I->data_path + "/" + App::I->doc_name + "-recovery (" + oss.str() + ").ppi";
if (App::I->canvas && App::I->canvas->m_canvas)
App::I->canvas->m_canvas->project_save_thread(path);
exit(0); exit(0);
} }

View File

@@ -193,7 +193,7 @@ void Shape::draw_stroke() const
void Shape::destroy() void Shape::destroy()
{ {
App::I->render_task_async([b1=buffers[0],b2=buffers[1],a1=arrays[0],a2=arrays[1]] if (App::I) App::I->render_task_async([b1=buffers[0],b2=buffers[1],a1=arrays[0],a2=arrays[1]]
{ {
if (b1 || b2) if (b1 || b2)
{ {