cocoa: fix some crashes caused by async uninit

Always keep around our private state and destroy it when we are really done in
the async uninit callback.

Fixes #1657
This commit is contained in:
Stefano Pigozzi 2015-03-07 08:48:07 +01:00
parent ddbecd09b0
commit c66b51dab0
1 changed files with 15 additions and 31 deletions

View File

@ -54,7 +54,7 @@
#define cocoa_unlock(s) pthread_mutex_unlock(&s->mutex) #define cocoa_unlock(s) pthread_mutex_unlock(&s->mutex)
static void vo_cocoa_fullscreen(struct vo *vo); static void vo_cocoa_fullscreen(struct vo *vo);
static void cocoa_rm_fs_screen_profile_observer(struct vo *vo); static void cocoa_rm_fs_screen_profile_observer(struct vo_cocoa_state *s);
struct vo_cocoa_state { struct vo_cocoa_state {
NSWindow *window; NSWindow *window;
@ -117,17 +117,15 @@ static void queue_new_video_size(struct vo *vo, int w, int h)
} }
} }
static void enable_power_management(struct vo *vo) static void enable_power_management(struct vo_cocoa_state *s)
{ {
struct vo_cocoa_state *s = vo->cocoa;
if (!s->power_mgmt_assertion) return; if (!s->power_mgmt_assertion) return;
IOPMAssertionRelease(s->power_mgmt_assertion); IOPMAssertionRelease(s->power_mgmt_assertion);
s->power_mgmt_assertion = kIOPMNullAssertionID; s->power_mgmt_assertion = kIOPMNullAssertionID;
} }
static void disable_power_management(struct vo *vo) static void disable_power_management(struct vo_cocoa_state *s)
{ {
struct vo_cocoa_state *s = vo->cocoa;
if (s->power_mgmt_assertion) return; if (s->power_mgmt_assertion) return;
IOPMAssertionCreateWithName( IOPMAssertionCreateWithName(
kIOPMAssertionTypePreventUserIdleDisplaySleep, kIOPMAssertionTypePreventUserIdleDisplaySleep,
@ -226,16 +224,15 @@ static void cocoa_init_light_sensor(struct vo *vo)
}); });
} }
static void cocoa_uninit_light_sensor(struct vo *vo) static void cocoa_uninit_light_sensor(struct vo_cocoa_state *s)
{ {
struct vo_cocoa_state *s = vo->cocoa;
IONotificationPortDestroy(s->light_sensor_io_port); IONotificationPortDestroy(s->light_sensor_io_port);
IOObjectRelease(s->light_sensor); IOObjectRelease(s->light_sensor);
} }
int vo_cocoa_init(struct vo *vo) int vo_cocoa_init(struct vo *vo)
{ {
struct vo_cocoa_state *s = talloc_zero(vo, struct vo_cocoa_state); struct vo_cocoa_state *s = talloc_zero(NULL, struct vo_cocoa_state);
*s = (struct vo_cocoa_state){ *s = (struct vo_cocoa_state){
.waiting_frame = false, .waiting_frame = false,
.power_mgmt_assertion = kIOPMNullAssertionID, .power_mgmt_assertion = kIOPMNullAssertionID,
@ -278,17 +275,11 @@ void vo_cocoa_register_resize_callback(struct vo *vo,
void vo_cocoa_uninit(struct vo *vo) void vo_cocoa_uninit(struct vo *vo)
{ {
struct vo_cocoa_state *s = vo->cocoa; struct vo_cocoa_state *s = vo->cocoa;
NSView *ev = s->view;
// keep the event view around for later in order to call -clear
if (!s->embedded) {
[ev retain];
}
with_cocoa_lock_on_main_thread(vo, ^{ with_cocoa_lock_on_main_thread(vo, ^{
enable_power_management(vo); enable_power_management(s);
cocoa_uninit_light_sensor(vo); cocoa_uninit_light_sensor(s);
cocoa_rm_fs_screen_profile_observer(vo); cocoa_rm_fs_screen_profile_observer(s);
[s->gl_ctx release]; [s->gl_ctx release];
@ -297,21 +288,15 @@ void vo_cocoa_uninit(struct vo *vo)
[s->video removeFromSuperview]; [s->video removeFromSuperview];
[s->view removeFromSuperview]; [s->view removeFromSuperview];
[(MpvEventsView *)s->view clear];
[s->view release]; [s->view release];
// if using --wid + libmpv there's no window to release // if using --wid + libmpv there's no window to release
if (s->window) if (s->window)
[s->window release]; [s->window release];
});
// don't use the mutex, because at that point it could have been destroyed talloc_free(s);
// and no one is accessing the events view anyway });
if (!s->embedded) {
dispatch_async(dispatch_get_main_queue(), ^{
[(MpvEventsView *)ev clear];
[ev release];
});
}
} }
static int get_screen_handle(struct vo *vo, int identifier, NSWindow *window, static int get_screen_handle(struct vo *vo, int identifier, NSWindow *window,
@ -512,9 +497,8 @@ static int cocoa_set_window_title(struct vo *vo, const char *title)
return VO_TRUE; return VO_TRUE;
} }
static void cocoa_rm_fs_screen_profile_observer(struct vo *vo) static void cocoa_rm_fs_screen_profile_observer(struct vo_cocoa_state *s)
{ {
struct vo_cocoa_state *s = vo->cocoa;
[[NSNotificationCenter defaultCenter] [[NSNotificationCenter defaultCenter]
removeObserver:s->fs_icc_changed_ns_observer]; removeObserver:s->fs_icc_changed_ns_observer];
} }
@ -524,7 +508,7 @@ static void cocoa_add_fs_screen_profile_observer(struct vo *vo)
struct vo_cocoa_state *s = vo->cocoa; struct vo_cocoa_state *s = vo->cocoa;
if (s->fs_icc_changed_ns_observer) if (s->fs_icc_changed_ns_observer)
cocoa_rm_fs_screen_profile_observer(vo); cocoa_rm_fs_screen_profile_observer(s);
if (vo->opts->fsscreen_id < 0) if (vo->opts->fsscreen_id < 0)
return; return;
@ -752,10 +736,10 @@ int vo_cocoa_control(struct vo *vo, int *events, int request, void *arg)
case VOCTRL_UPDATE_WINDOW_TITLE: case VOCTRL_UPDATE_WINDOW_TITLE:
return cocoa_set_window_title(vo, (const char *) arg); return cocoa_set_window_title(vo, (const char *) arg);
case VOCTRL_RESTORE_SCREENSAVER: case VOCTRL_RESTORE_SCREENSAVER:
enable_power_management(vo); enable_power_management(vo->cocoa);
return VO_TRUE; return VO_TRUE;
case VOCTRL_KILL_SCREENSAVER: case VOCTRL_KILL_SCREENSAVER:
disable_power_management(vo); disable_power_management(vo->cocoa);
return VO_TRUE; return VO_TRUE;
case VOCTRL_GET_ICC_PROFILE: case VOCTRL_GET_ICC_PROFILE:
vo_cocoa_control_get_icc_profile(vo, arg); vo_cocoa_control_get_icc_profile(vo, arg);