|
@@ -27,6 +27,7 @@ NSArray *enumerate_windows(void)
|
|
|
{
|
|
|
NSArray *arr = (NSArray *)CGWindowListCopyWindowInfo(
|
|
|
kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
|
|
+
|
|
|
[arr autorelease];
|
|
|
|
|
|
return [arr sortedArrayUsingComparator:win_info_cmp];
|
|
@@ -36,205 +37,186 @@ NSArray *enumerate_windows(void)
|
|
|
#define WAIT_TIME_US WAIT_TIME_MS * 1000
|
|
|
#define WAIT_TIME_NS WAIT_TIME_US * 1000
|
|
|
|
|
|
-bool find_window(cocoa_window_t cw, obs_data_t *settings)
|
|
|
+bool find_window(cocoa_window_t cw, obs_data_t *settings, bool force)
|
|
|
{
|
|
|
- uint64_t ts = os_gettime_ns();
|
|
|
-
|
|
|
- if (cw->last_search_time + WAIT_TIME_NS > ts)
|
|
|
+ if (!force && cw->next_search_time > os_gettime_ns())
|
|
|
return false;
|
|
|
|
|
|
- cw->last_search_time = ts;
|
|
|
+ cw->next_search_time = os_gettime_ns() + WAIT_TIME_NS;
|
|
|
|
|
|
- if (pthread_mutex_lock(&cw->mutex))
|
|
|
- abort();
|
|
|
+ pthread_mutex_lock(&cw->name_lock);
|
|
|
|
|
|
if (!cw->window_name.length && !cw->owner_name.length)
|
|
|
- goto unlock;
|
|
|
+ goto invalid_name;
|
|
|
|
|
|
for (NSDictionary *dict in enumerate_windows()) {
|
|
|
- bool owner_names_match =
|
|
|
- (!cw->owner_name.length && !dict[OWNER_NAME]) ||
|
|
|
- [cw->owner_name isEqualToString:dict[OWNER_NAME]];
|
|
|
- bool window_names_match =
|
|
|
- (!cw->window_name.length && !dict[WINDOW_NAME]) ||
|
|
|
- [cw->window_name isEqualToString:dict[WINDOW_NAME]];
|
|
|
+ if (![cw->owner_name isEqualToString:dict[OWNER_NAME]])
|
|
|
+ continue;
|
|
|
|
|
|
- if (!owner_names_match || !window_names_match)
|
|
|
+ if (![cw->window_name isEqualToString:dict[WINDOW_NAME]])
|
|
|
continue;
|
|
|
|
|
|
- cw->window_id = [dict[WINDOW_NUMBER] intValue];
|
|
|
- cw->owner_pid = [dict[OWNER_PID] intValue];
|
|
|
+ pthread_mutex_unlock(&cw->name_lock);
|
|
|
+
|
|
|
+ NSNumber *window_id = (NSNumber *)dict[WINDOW_NUMBER];
|
|
|
+ cw->window_id = window_id.intValue;
|
|
|
+ NSNumber *owner_pid = (NSNumber *)dict[OWNER_PID];
|
|
|
+ cw->owner_pid = owner_pid.intValue;
|
|
|
|
|
|
obs_data_set_int(settings, "window", cw->window_id);
|
|
|
obs_data_set_int(settings, "owner_pid", cw->owner_pid);
|
|
|
-
|
|
|
- if (pthread_mutex_unlock(&cw->mutex))
|
|
|
- abort();
|
|
|
-
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-unlock:
|
|
|
- if (pthread_mutex_unlock(&cw->mutex))
|
|
|
- abort();
|
|
|
-
|
|
|
+invalid_name:
|
|
|
+ pthread_mutex_unlock(&cw->name_lock);
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
void init_window(cocoa_window_t cw, obs_data_t *settings)
|
|
|
{
|
|
|
- if (pthread_mutex_init(&cw->mutex, NULL))
|
|
|
- abort();
|
|
|
-
|
|
|
- cw->window_id = obs_data_get_int(settings, "window");
|
|
|
- cw->owner_pid = obs_data_get_int(settings, "owner_pid");
|
|
|
+ pthread_mutex_init(&cw->name_lock, NULL);
|
|
|
|
|
|
cw->owner_name = @(obs_data_get_string(settings, "owner_name"));
|
|
|
cw->window_name = @(obs_data_get_string(settings, "window_name"));
|
|
|
[cw->owner_name retain];
|
|
|
[cw->window_name retain];
|
|
|
|
|
|
- cw->last_search_time = 0;
|
|
|
+ // Find initial window.
|
|
|
+ pthread_mutex_lock(&cw->name_lock);
|
|
|
|
|
|
if (!cw->window_name.length && !cw->owner_name.length)
|
|
|
- return;
|
|
|
-
|
|
|
- NSNumber *window_id = @(cw->window_id);
|
|
|
- NSNumber *owner_pid = @(cw->owner_pid);
|
|
|
+ goto invalid_name;
|
|
|
|
|
|
+ NSNumber *owner_pid = @(obs_data_get_int(settings, "owner_pid"));
|
|
|
+ NSNumber *window_id = @(obs_data_get_int(settings, "window"));
|
|
|
for (NSDictionary *dict in enumerate_windows()) {
|
|
|
bool owner_names_match =
|
|
|
- (!cw->owner_name.length && !dict[OWNER_NAME]) ||
|
|
|
[cw->owner_name isEqualToString:dict[OWNER_NAME]];
|
|
|
bool ids_match =
|
|
|
[owner_pid isEqualToNumber:dict[OWNER_PID]] &&
|
|
|
[window_id isEqualToNumber:dict[WINDOW_NUMBER]];
|
|
|
bool window_names_match =
|
|
|
- (!cw->window_name.length && !dict[WINDOW_NAME]) ||
|
|
|
[cw->window_name isEqualToString:dict[WINDOW_NAME]];
|
|
|
|
|
|
if (owner_names_match && (ids_match || window_names_match)) {
|
|
|
- cw->window_id = [dict[WINDOW_NUMBER] intValue];
|
|
|
- cw->owner_pid = [dict[OWNER_PID] intValue];
|
|
|
+ pthread_mutex_unlock(&cw->name_lock);
|
|
|
+
|
|
|
+ NSNumber *window_id = (NSNumber *)dict[WINDOW_NUMBER];
|
|
|
+ cw->window_id = window_id.intValue;
|
|
|
+ NSNumber *owner_pid = (NSNumber *)dict[OWNER_PID];
|
|
|
+ cw->owner_pid = owner_pid.intValue;
|
|
|
|
|
|
obs_data_set_int(settings, "window", cw->window_id);
|
|
|
obs_data_set_int(settings, "owner_pid", cw->owner_pid);
|
|
|
-
|
|
|
- break;
|
|
|
+ return;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+invalid_name:
|
|
|
+ pthread_mutex_unlock(&cw->name_lock);
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
void destroy_window(cocoa_window_t cw)
|
|
|
{
|
|
|
+ pthread_mutex_destroy(&cw->name_lock);
|
|
|
[cw->owner_name release];
|
|
|
[cw->window_name release];
|
|
|
-
|
|
|
- if (pthread_mutex_destroy(&cw->mutex))
|
|
|
- abort();
|
|
|
}
|
|
|
|
|
|
void update_window(cocoa_window_t cw, obs_data_t *settings)
|
|
|
{
|
|
|
- if (pthread_mutex_lock(&cw->mutex))
|
|
|
- abort();
|
|
|
-
|
|
|
+ pthread_mutex_lock(&cw->name_lock);
|
|
|
[cw->owner_name release];
|
|
|
[cw->window_name release];
|
|
|
-
|
|
|
cw->owner_name = @(obs_data_get_string(settings, "owner_name"));
|
|
|
cw->window_name = @(obs_data_get_string(settings, "window_name"));
|
|
|
[cw->owner_name retain];
|
|
|
[cw->window_name retain];
|
|
|
+ pthread_mutex_unlock(&cw->name_lock);
|
|
|
|
|
|
cw->owner_pid = obs_data_get_int(settings, "owner_pid");
|
|
|
cw->window_id = obs_data_get_int(settings, "window");
|
|
|
-
|
|
|
- if (pthread_mutex_unlock(&cw->mutex))
|
|
|
- abort();
|
|
|
}
|
|
|
|
|
|
-static inline NSString *make_name(NSString *owner, NSString *name)
|
|
|
+static inline const char *make_name(NSString *owner, NSString *name)
|
|
|
{
|
|
|
if (!owner.length)
|
|
|
- return @"";
|
|
|
+ return "";
|
|
|
|
|
|
- return [NSString stringWithFormat:@"[%@] %@", owner, name];
|
|
|
+ NSString *str = [NSString stringWithFormat:@"[%@] %@", owner, name];
|
|
|
+ return str.UTF8String;
|
|
|
+}
|
|
|
+
|
|
|
+static inline NSDictionary *find_window_dict(NSArray *arr, int window_id)
|
|
|
+{
|
|
|
+ for (NSDictionary *dict in arr) {
|
|
|
+ NSNumber *wid = (NSNumber *)dict[WINDOW_NUMBER];
|
|
|
+ if (wid.intValue == window_id)
|
|
|
+ return dict;
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil;
|
|
|
}
|
|
|
|
|
|
static inline bool window_changed_internal(obs_property_t *p,
|
|
|
obs_data_t *settings)
|
|
|
{
|
|
|
- NSNumber *window_id = @(obs_data_get_int(settings, "window"));
|
|
|
- NSNumber *owner_pid = @(obs_data_get_int(settings, "owner_pid"));
|
|
|
- NSString *owner_name = @(obs_data_get_string(settings, "owner_name"));
|
|
|
+ int window_id = obs_data_get_int(settings, "window");
|
|
|
+ NSString *window_owner = @(obs_data_get_string(settings, "owner_name"));
|
|
|
NSString *window_name = @(obs_data_get_string(settings, "window_name"));
|
|
|
|
|
|
- bool show_empty_names = obs_data_get_bool(settings, "show_empty_names");
|
|
|
-
|
|
|
NSDictionary *win_info = @{
|
|
|
- OWNER_NAME: owner_name,
|
|
|
- OWNER_PID: owner_pid,
|
|
|
+ OWNER_NAME: window_owner,
|
|
|
WINDOW_NAME: window_name,
|
|
|
- WINDOW_NUMBER: window_id,
|
|
|
};
|
|
|
|
|
|
NSArray *arr = enumerate_windows();
|
|
|
- NSDictionary *cur = nil;
|
|
|
|
|
|
- for (NSDictionary *dict in arr) {
|
|
|
- if ([window_id isEqualToNumber:dict[WINDOW_NUMBER]]) {
|
|
|
- cur = dict;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
+ bool show_empty_names = obs_data_get_bool(settings, "show_empty_names");
|
|
|
|
|
|
+ NSDictionary *cur = find_window_dict(arr, window_id);
|
|
|
bool window_found = cur != nil;
|
|
|
bool window_added = window_found;
|
|
|
|
|
|
obs_property_list_clear(p);
|
|
|
for (NSDictionary *dict in arr) {
|
|
|
+ NSString *owner = (NSString *)dict[OWNER_NAME];
|
|
|
+ NSString *name = (NSString *)dict[WINDOW_NAME];
|
|
|
+ NSNumber *wid = (NSNumber *)dict[WINDOW_NUMBER];
|
|
|
+
|
|
|
if (!window_added &&
|
|
|
win_info_cmp(win_info, dict) == NSOrderedAscending) {
|
|
|
window_added = true;
|
|
|
-
|
|
|
size_t idx = obs_property_list_add_int(
|
|
|
- p,
|
|
|
- make_name(owner_name, window_name).UTF8String,
|
|
|
- window_id.intValue);
|
|
|
-
|
|
|
+ p, make_name(window_owner, window_name),
|
|
|
+ window_id);
|
|
|
obs_property_list_item_disable(p, idx, true);
|
|
|
}
|
|
|
|
|
|
- if (!show_empty_names &&
|
|
|
- (!dict[WINDOW_NAME] || ![dict[WINDOW_NAME] length]) &&
|
|
|
- ![window_id isEqualToNumber:dict[WINDOW_NUMBER]])
|
|
|
+ if (!show_empty_names && !name.length &&
|
|
|
+ window_id != wid.intValue)
|
|
|
continue;
|
|
|
|
|
|
- obs_property_list_add_int(p,
|
|
|
- make_name(dict[OWNER_NAME],
|
|
|
- dict[WINDOW_NAME])
|
|
|
- .UTF8String,
|
|
|
- [dict[WINDOW_NUMBER] intValue]);
|
|
|
+ obs_property_list_add_int(p, make_name(owner, name),
|
|
|
+ wid.intValue);
|
|
|
}
|
|
|
|
|
|
if (!window_added) {
|
|
|
size_t idx = obs_property_list_add_int(
|
|
|
- p, make_name(owner_name, window_name).UTF8String,
|
|
|
- window_id.intValue);
|
|
|
-
|
|
|
+ p, make_name(window_owner, window_name), window_id);
|
|
|
obs_property_list_item_disable(p, idx, true);
|
|
|
}
|
|
|
|
|
|
if (!window_found)
|
|
|
return true;
|
|
|
|
|
|
- obs_data_set_int(settings, "window", [cur[WINDOW_NUMBER] intValue]);
|
|
|
- obs_data_set_int(settings, "owner_pid", [cur[OWNER_PID] intValue]);
|
|
|
- obs_data_set_string(settings, "owner_name",
|
|
|
- [cur[OWNER_NAME] UTF8String]);
|
|
|
- obs_data_set_string(settings, "window_name",
|
|
|
- [cur[WINDOW_NAME] UTF8String]);
|
|
|
+ NSString *owner = (NSString *)cur[OWNER_NAME];
|
|
|
+ NSString *window = (NSString *)cur[WINDOW_NAME];
|
|
|
+
|
|
|
+ obs_data_set_string(settings, "owner_name", owner.UTF8String);
|
|
|
+ obs_data_set_string(settings, "window_name", window.UTF8String);
|
|
|
|
|
|
return true;
|
|
|
}
|