|
@@ -191,16 +191,16 @@ struct obs_property {
|
|
|
obs_property_modified_t modified;
|
|
|
obs_property_modified2_t modified2;
|
|
|
|
|
|
- struct obs_property *next;
|
|
|
+ UT_hash_handle hh;
|
|
|
};
|
|
|
|
|
|
struct obs_properties {
|
|
|
void *param;
|
|
|
void (*destroy)(void *param);
|
|
|
uint32_t flags;
|
|
|
+ uint32_t groups;
|
|
|
|
|
|
- struct obs_property *first_property;
|
|
|
- struct obs_property **last;
|
|
|
+ struct obs_property *properties;
|
|
|
struct obs_property *parent;
|
|
|
};
|
|
|
|
|
@@ -208,7 +208,6 @@ obs_properties_t *obs_properties_create(void)
|
|
|
{
|
|
|
struct obs_properties *props;
|
|
|
props = bzalloc(sizeof(struct obs_properties));
|
|
|
- props->last = &props->first_property;
|
|
|
return props;
|
|
|
}
|
|
|
|
|
@@ -277,15 +276,14 @@ static void obs_property_destroy(struct obs_property *property)
|
|
|
void obs_properties_destroy(obs_properties_t *props)
|
|
|
{
|
|
|
if (props) {
|
|
|
- struct obs_property *p = props->first_property;
|
|
|
+ struct obs_property *p, *tmp;
|
|
|
|
|
|
if (props->destroy && props->param)
|
|
|
props->destroy(props->param);
|
|
|
|
|
|
- while (p) {
|
|
|
- struct obs_property *next = p->next;
|
|
|
+ HASH_ITER (hh, props->properties, p, tmp) {
|
|
|
+ HASH_DEL(props->properties, p);
|
|
|
obs_property_destroy(p);
|
|
|
- p = next;
|
|
|
}
|
|
|
|
|
|
bfree(props);
|
|
@@ -294,31 +292,32 @@ void obs_properties_destroy(obs_properties_t *props)
|
|
|
|
|
|
obs_property_t *obs_properties_first(obs_properties_t *props)
|
|
|
{
|
|
|
- return (props != NULL) ? props->first_property : NULL;
|
|
|
+ return (props != NULL) ? props->properties : NULL;
|
|
|
}
|
|
|
|
|
|
obs_property_t *obs_properties_get(obs_properties_t *props, const char *name)
|
|
|
{
|
|
|
- struct obs_property *property;
|
|
|
+ struct obs_property *property, *tmp;
|
|
|
|
|
|
if (!props)
|
|
|
return NULL;
|
|
|
|
|
|
- property = props->first_property;
|
|
|
- while (property) {
|
|
|
- if (strcmp(property->name, name) == 0)
|
|
|
- return property;
|
|
|
-
|
|
|
- if (property->type == OBS_PROPERTY_GROUP) {
|
|
|
- obs_properties_t *group =
|
|
|
- obs_property_group_content(property);
|
|
|
- obs_property_t *found = obs_properties_get(group, name);
|
|
|
- if (found != NULL) {
|
|
|
- return found;
|
|
|
- }
|
|
|
- }
|
|
|
+ HASH_FIND_STR(props->properties, name, property);
|
|
|
+ if (property)
|
|
|
+ return property;
|
|
|
+
|
|
|
+ if (!props->groups)
|
|
|
+ return NULL;
|
|
|
|
|
|
- property = property->next;
|
|
|
+ /* Recursively check groups as well, if any */
|
|
|
+ HASH_ITER (hh, props->properties, property, tmp) {
|
|
|
+ if (property->type != OBS_PROPERTY_GROUP)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ obs_properties_t *group = obs_property_group_content(property);
|
|
|
+ obs_property_t *found = obs_properties_get(group, name);
|
|
|
+ if (found)
|
|
|
+ return found;
|
|
|
}
|
|
|
|
|
|
return NULL;
|
|
@@ -334,51 +333,29 @@ void obs_properties_remove_by_name(obs_properties_t *props, const char *name)
|
|
|
if (!props)
|
|
|
return;
|
|
|
|
|
|
- /* obs_properties_t is a forward-linked-list, so we need to keep both
|
|
|
- * previous and current pointers around. That way we can fix up the
|
|
|
- * pointers for the previous element if we find a match.
|
|
|
- */
|
|
|
- struct obs_property *cur = props->first_property;
|
|
|
- struct obs_property *prev = props->first_property;
|
|
|
-
|
|
|
- while (cur) {
|
|
|
- if (strcmp(cur->name, name) == 0) {
|
|
|
- // Fix props->last pointer.
|
|
|
- if (props->last == &cur->next) {
|
|
|
- if (cur == prev) {
|
|
|
- // If we are the last entry and there
|
|
|
- // is no previous entry, reset.
|
|
|
- props->last = &props->first_property;
|
|
|
- } else {
|
|
|
- // If we are the last entry and there
|
|
|
- // is a previous entry, update.
|
|
|
- props->last = &prev->next;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Fix props->first_property.
|
|
|
- if (props->first_property == cur)
|
|
|
- props->first_property = cur->next;
|
|
|
-
|
|
|
- // Update the previous element next pointer with our
|
|
|
- // next pointer. This is an automatic no-op if both
|
|
|
- // elements alias the same memory.
|
|
|
- prev->next = cur->next;
|
|
|
-
|
|
|
- // Finally clear our own next pointer and destroy.
|
|
|
- cur->next = NULL;
|
|
|
- obs_property_destroy(cur);
|
|
|
-
|
|
|
- break;
|
|
|
- }
|
|
|
+ struct obs_property *cur, *tmp;
|
|
|
|
|
|
- if (cur->type == OBS_PROPERTY_GROUP) {
|
|
|
- obs_properties_remove_by_name(
|
|
|
- obs_property_group_content(cur), name);
|
|
|
- }
|
|
|
+ HASH_FIND_STR(props->properties, name, cur);
|
|
|
+
|
|
|
+ if (cur) {
|
|
|
+ HASH_DELETE(hh, props->properties, cur);
|
|
|
+
|
|
|
+ if (cur->type == OBS_PROPERTY_GROUP)
|
|
|
+ props->groups--;
|
|
|
+
|
|
|
+ obs_property_destroy(cur);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!props->groups)
|
|
|
+ return;
|
|
|
+
|
|
|
+ HASH_ITER (hh, props->properties, cur, tmp) {
|
|
|
+ if (cur->type != OBS_PROPERTY_GROUP)
|
|
|
+ continue;
|
|
|
|
|
|
- prev = cur;
|
|
|
- cur = cur->next;
|
|
|
+ obs_properties_remove_by_name(obs_property_group_content(cur),
|
|
|
+ name);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -386,10 +363,9 @@ void obs_properties_apply_settings_internal(obs_properties_t *props,
|
|
|
obs_data_t *settings,
|
|
|
obs_properties_t *realprops)
|
|
|
{
|
|
|
- struct obs_property *p;
|
|
|
+ struct obs_property *p, *tmp;
|
|
|
|
|
|
- p = props->first_property;
|
|
|
- while (p) {
|
|
|
+ HASH_ITER (hh, props->properties, p, tmp) {
|
|
|
if (p->type == OBS_PROPERTY_GROUP) {
|
|
|
obs_properties_apply_settings_internal(
|
|
|
obs_property_group_content(p), settings,
|
|
@@ -399,7 +375,6 @@ void obs_properties_apply_settings_internal(obs_properties_t *props,
|
|
|
p->modified(realprops, p, settings);
|
|
|
else if (p->modified2)
|
|
|
p->modified2(p->priv, realprops, p, settings);
|
|
|
- p = p->next;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -414,13 +389,6 @@ void obs_properties_apply_settings(obs_properties_t *props,
|
|
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
|
|
-static inline void propertes_add(struct obs_properties *props,
|
|
|
- struct obs_property *p)
|
|
|
-{
|
|
|
- *props->last = p;
|
|
|
- props->last = &p->next;
|
|
|
-}
|
|
|
-
|
|
|
static inline size_t get_property_size(enum obs_property_type type)
|
|
|
{
|
|
|
switch (type) {
|
|
@@ -471,7 +439,8 @@ static inline struct obs_property *new_prop(struct obs_properties *props,
|
|
|
p->type = type;
|
|
|
p->name = bstrdup(name);
|
|
|
p->desc = bstrdup(desc);
|
|
|
- propertes_add(props, p);
|
|
|
+
|
|
|
+ HASH_ADD_STR(props->properties, name, p);
|
|
|
|
|
|
return p;
|
|
|
}
|
|
@@ -489,22 +458,22 @@ static inline obs_properties_t *get_topmost_parent(obs_properties_t *props)
|
|
|
|
|
|
static inline bool contains_prop(struct obs_properties *props, const char *name)
|
|
|
{
|
|
|
- struct obs_property *p = props->first_property;
|
|
|
+ struct obs_property *p, *tmp;
|
|
|
+ HASH_FIND_STR(props->properties, name, p);
|
|
|
|
|
|
- while (p) {
|
|
|
- if (strcmp(p->name, name) == 0) {
|
|
|
- blog(LOG_WARNING, "Property '%s' exists", name);
|
|
|
- return true;
|
|
|
- }
|
|
|
+ if (p) {
|
|
|
+ blog(LOG_WARNING, "Property '%s' exists", name);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
|
|
|
- if (p->type == OBS_PROPERTY_GROUP) {
|
|
|
- if (contains_prop(obs_property_group_content(p),
|
|
|
- name)) {
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
+ if (!props->groups)
|
|
|
+ return false;
|
|
|
|
|
|
- p = p->next;
|
|
|
+ HASH_ITER (hh, props->properties, p, tmp) {
|
|
|
+ if (p->type != OBS_PROPERTY_GROUP)
|
|
|
+ continue;
|
|
|
+ if (contains_prop(obs_property_group_content(p), name))
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
return false;
|
|
@@ -753,24 +722,23 @@ static bool check_property_group_recursion(obs_properties_t *parent,
|
|
|
obs_properties_t *group)
|
|
|
{
|
|
|
/* Scan the group for the parent. */
|
|
|
- obs_property_t *current_property = group->first_property;
|
|
|
- while (current_property) {
|
|
|
- if (current_property->type == OBS_PROPERTY_GROUP) {
|
|
|
- obs_properties_t *cprops =
|
|
|
- obs_property_group_content(current_property);
|
|
|
- if (cprops == parent) {
|
|
|
- /* Contains find_props */
|
|
|
- return true;
|
|
|
- } else if (cprops == group) {
|
|
|
- /* Contains self, shouldn't be possible but
|
|
|
+ obs_property_t *p, *tmp;
|
|
|
+
|
|
|
+ HASH_ITER (hh, group->properties, p, tmp) {
|
|
|
+ if (p->type != OBS_PROPERTY_GROUP)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ obs_properties_t *cprops = obs_property_group_content(p);
|
|
|
+ if (cprops == parent) {
|
|
|
+ /* Contains find_props */
|
|
|
+ return true;
|
|
|
+ } else if (cprops == group) {
|
|
|
+ /* Contains self, shouldn't be possible but
|
|
|
* lets verify anyway. */
|
|
|
- return true;
|
|
|
- }
|
|
|
- if (check_property_group_recursion(parent, cprops))
|
|
|
- return true;
|
|
|
+ return true;
|
|
|
}
|
|
|
-
|
|
|
- current_property = current_property->next;
|
|
|
+ if (check_property_group_recursion(parent, cprops))
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
return false;
|
|
@@ -779,13 +747,11 @@ static bool check_property_group_recursion(obs_properties_t *parent,
|
|
|
static bool check_property_group_duplicates(obs_properties_t *parent,
|
|
|
obs_properties_t *group)
|
|
|
{
|
|
|
- obs_property_t *current_property = group->first_property;
|
|
|
- while (current_property) {
|
|
|
- if (has_prop(parent, current_property->name)) {
|
|
|
- return true;
|
|
|
- }
|
|
|
+ obs_property_t *p, *tmp;
|
|
|
|
|
|
- current_property = current_property->next;
|
|
|
+ HASH_ITER (hh, group->properties, p, tmp) {
|
|
|
+ if (has_prop(parent, p->name))
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
return false;
|
|
@@ -812,6 +778,7 @@ obs_property_t *obs_properties_add_group(obs_properties_t *props,
|
|
|
return NULL;
|
|
|
|
|
|
obs_property_t *p = new_prop(props, name, desc, OBS_PROPERTY_GROUP);
|
|
|
+ props->groups++;
|
|
|
group->parent = p;
|
|
|
|
|
|
struct group_data *data = get_property_data(p);
|
|
@@ -849,7 +816,7 @@ bool obs_property_next(obs_property_t **p)
|
|
|
if (!p || !*p)
|
|
|
return false;
|
|
|
|
|
|
- *p = (*p)->next;
|
|
|
+ *p = (*p)->hh.next;
|
|
|
return *p != NULL;
|
|
|
}
|
|
|
|