mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-09-20 13:08:50 +02:00
Simplify/improve UI exporting a bit more
Reduce and simplify the UI export interface. Having to export functions with designated names was a bit silly for this case, it makes more sense for inputs/outputs/etc because they have more functions associated with them, but in this case the callback can be retrieved simply through the enumeration exports. Makes it a bit easier and a little less awkward for this situation. Also, changed the exports and names to be a bit more consistent, labelling them both as either "modal" or "modeless", and changed the UI function calls to obs_exec_ui and obs_create_ui to imply modal/modeless functionality a bit more.
This commit is contained in:
parent
b31d52d602
commit
6f51567c93
@ -49,17 +49,6 @@ struct obs_display {
|
|||||||
/* TODO: sound output target */
|
/* TODO: sound output target */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* TODO: optimize this later so it's not just O(N) string lookups */
|
|
||||||
struct ui_callback {
|
|
||||||
struct obs_ui_info ui_info;
|
|
||||||
bool (*callback)(void *data, void *ui_data);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ui_modeless {
|
|
||||||
struct obs_ui_info ui_info;
|
|
||||||
void *(*callback)(void *data, void *ui_data);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
struct obs_video {
|
struct obs_video {
|
||||||
@ -111,8 +100,8 @@ struct obs_subsystem {
|
|||||||
DARRAY(struct output_info) output_types;
|
DARRAY(struct output_info) output_types;
|
||||||
DARRAY(struct encoder_info) encoder_types;
|
DARRAY(struct encoder_info) encoder_types;
|
||||||
DARRAY(struct service_info) service_types;
|
DARRAY(struct service_info) service_types;
|
||||||
DARRAY(struct ui_callback) ui_callbacks;
|
DARRAY(struct obs_modal_ui) ui_modal_callbacks;
|
||||||
DARRAY(struct ui_modeless) ui_modeless_callbacks;
|
DARRAY(struct obs_modeless_ui) ui_modeless_callbacks;
|
||||||
|
|
||||||
signal_handler_t signals;
|
signal_handler_t signals;
|
||||||
proc_handler_t procs;
|
proc_handler_t procs;
|
||||||
|
@ -76,46 +76,28 @@ complete:
|
|||||||
dstr_free(&enum_name);
|
dstr_free(&enum_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct generic_ui_callback {
|
static void module_load_modal_ui_exports(struct obs_module *mod)
|
||||||
struct obs_ui_info ui_info;
|
|
||||||
void *callback;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void module_load_ui_exports(struct obs_module *mod,
|
|
||||||
const char *main_export, struct darray *array)
|
|
||||||
{
|
{
|
||||||
bool (*enum_func)(size_t idx, struct obs_ui_info *info);
|
bool (*enum_func)(size_t idx, struct obs_modal_ui *info);
|
||||||
struct obs_ui_info ui_info;
|
struct obs_modal_ui ui_info;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
enum_func = os_dlsym(mod->module, main_export);
|
enum_func = os_dlsym(mod->module, "enum_modal_ui");
|
||||||
if (!enum_func)
|
if (enum_func)
|
||||||
return;
|
while (enum_func(i++, &ui_info))
|
||||||
|
da_push_back(obs->ui_modal_callbacks, &ui_info);
|
||||||
|
}
|
||||||
|
|
||||||
while (enum_func(i++, &ui_info)) {
|
static void module_load_modeless_ui_exports(struct obs_module *mod)
|
||||||
struct generic_ui_callback callback;
|
{
|
||||||
struct dstr name;
|
bool (*enum_func)(size_t idx, struct obs_modeless_ui *info);
|
||||||
|
struct obs_modeless_ui ui_info;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
dstr_init_copy(&name, ui_info.name);
|
enum_func = os_dlsym(mod->module, "enum_modeless_ui");
|
||||||
dstr_cat(&name, "_");
|
if (enum_func)
|
||||||
dstr_cat(&name, ui_info.task);
|
while (enum_func(i++, &ui_info))
|
||||||
dstr_cat(&name, "_");
|
da_push_back(obs->ui_modeless_callbacks, &ui_info);
|
||||||
dstr_cat(&name, ui_info.target);
|
|
||||||
|
|
||||||
callback.ui_info = ui_info;
|
|
||||||
callback.callback = os_dlsym(mod->module, name.array);
|
|
||||||
|
|
||||||
if (!callback.callback) {
|
|
||||||
blog(LOG_WARNING, "Module '%s' enumerated UI callback "
|
|
||||||
"'%s', but the function was not "
|
|
||||||
"found", mod->name, name.array);
|
|
||||||
} else {
|
|
||||||
darray_push_back(sizeof(struct generic_ui_callback),
|
|
||||||
array, &callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
dstr_free(&name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern char *find_plugin(const char *plugin);
|
extern char *find_plugin(const char *plugin);
|
||||||
@ -199,9 +181,8 @@ int obs_load_module(const char *path)
|
|||||||
module_load_exports(&mod, &obs->encoder_types.da, "encoders",
|
module_load_exports(&mod, &obs->encoder_types.da, "encoders",
|
||||||
sizeof(struct encoder_info), load_encoder_info);
|
sizeof(struct encoder_info), load_encoder_info);
|
||||||
|
|
||||||
module_load_ui_exports(&mod, "enum_ui", &obs->ui_callbacks.da);
|
module_load_modal_ui_exports(&mod);
|
||||||
module_load_ui_exports(&mod, "enum_modeless_ui",
|
module_load_modeless_ui_exports(&mod);
|
||||||
&obs->ui_modeless_callbacks.da);
|
|
||||||
|
|
||||||
da_push_back(obs->modules, &mod);
|
da_push_back(obs->modules, &mod);
|
||||||
return MODULE_SUCCESS;
|
return MODULE_SUCCESS;
|
||||||
|
@ -23,10 +23,18 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct obs_ui_info {
|
struct obs_modal_ui {
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *task;
|
const char *task;
|
||||||
const char *target;
|
const char *target;
|
||||||
|
bool (*callback)(void *object, void *ui_data);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct obs_modeless_ui {
|
||||||
|
const char *name;
|
||||||
|
const char *task;
|
||||||
|
const char *target;
|
||||||
|
void *(*callback)(void *object, void *ui_data);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -44,100 +52,73 @@ struct obs_ui_info {
|
|||||||
* languages)
|
* languages)
|
||||||
*
|
*
|
||||||
* A module with UI calls needs to export one or both of these functions:
|
* A module with UI calls needs to export one or both of these functions:
|
||||||
* + enum_ui
|
* + enum_modal_ui
|
||||||
* + enum_modeless_ui
|
* + enum_modeless_ui
|
||||||
*
|
*
|
||||||
* The enum_ui function provides an obs_ui_info structure for each
|
* The enum_ui function provides an obs_ui_info structure for each
|
||||||
* input/output/etc. Modeless UI should be exported enum_modeless_ui. For
|
* input/output/etc. Modeless UI should be exported enum_modeless_ui. For
|
||||||
* example, to export Qt-specific configuration functions, the exports might
|
* example, to export Qt-specific configuration functions, the values given to
|
||||||
* be something like:
|
* enum_modal_ui might look something like this:
|
||||||
* + mysource_config_qt
|
|
||||||
* + myoutput_config_qt
|
|
||||||
* + myencoder_config_qt
|
|
||||||
*
|
*
|
||||||
* ..And the values given to enum_ui would be something this:
|
* struct obs_modal_ui ui_list[] = {
|
||||||
*
|
* {"mysource", "config", "qt", mysource_config},
|
||||||
* struct obs_ui_info ui_list[] = {
|
* {"myoutput", "config", "qt", myoutput_config},
|
||||||
* {"mysource", "config", "qt"},
|
* {"myencoder", "config", "qt", myenoder_config}
|
||||||
* {"myoutput", "config", "qt"},
|
|
||||||
* {"myencoder", "config", "qt"}
|
|
||||||
* };
|
* };
|
||||||
*
|
*
|
||||||
* 'qt' could be replaced with 'wx' or something similar if using wxWidgets,
|
* 'qt' could be replaced with 'wx' or something similar if using wxWidgets,
|
||||||
* or 'win32' if using bare windows API.
|
* or 'win32' if using bare windows API. It could also specify a custom name
|
||||||
|
* if desired (use with discretion).
|
||||||
*
|
*
|
||||||
* ===========================================
|
* ===========================================
|
||||||
* Primary Exports
|
* Primary Exports
|
||||||
* ===========================================
|
* ===========================================
|
||||||
* bool enum_ui(size_t idx, struct obs_ui_info *ui_info);
|
* bool enum_modal_ui(size_t idx, struct obs_modal_ui *ui_info);
|
||||||
*
|
*
|
||||||
* idx: index of the enumeration
|
* idx: index of the enumeration
|
||||||
* ui_info: pointer to the ui data for this enumeration
|
* ui_info: pointer to the ui data for this enumeration
|
||||||
* Return value: false when no more available.
|
* Return value: false when no more available.
|
||||||
*
|
*
|
||||||
* ---------------------------------------------------------
|
* ---------------------------------------------------------
|
||||||
* bool enum_modeless_ui(size_t idx, struct obs_ui_info *ui_info);
|
* bool enum_modeless_ui(size_t idx, struct obs_modeless_ui *ui_info);
|
||||||
*
|
*
|
||||||
* idx: index of the enumeration
|
* idx: index of the enumeration
|
||||||
* ui_info: pointer to the ui data for this enumeration
|
* ui_info: pointer to the ui data for this enumeration
|
||||||
* Return value: false when no more available.
|
* Return value: false when no more available.
|
||||||
*
|
*
|
||||||
* ===========================================
|
* ===========================================
|
||||||
* Export Format
|
* Modal UI Callback
|
||||||
* ===========================================
|
* ===========================================
|
||||||
* Although the 'export' variable specifies the full export name, each
|
* bool modal_callback(void *object, void *ui_data);
|
||||||
* export should be formatted as so:
|
|
||||||
*
|
*
|
||||||
* bool [name]_[task]_[target](void *data, void *ui_data);
|
* The 'object' variable points to the input/output/encoder/etc. The
|
||||||
*
|
* 'ui_data' varaible points to the UI parent or UI-specific data to be used
|
||||||
* [name]: specifies the name of the input/output/encoder/etc.
|
* with the custom user interface.
|
||||||
* [task]: specifies the task of the user interface, most often 'config'
|
|
||||||
* [target]: specifies the target or toolkit of the user interface, such as
|
|
||||||
* but not limited to 'qt', 'wx', 'win32', 'cocoa', etc. If
|
|
||||||
* a custom solution is desired, it can use a program-specific
|
|
||||||
* name, such as 'myprogram'.
|
|
||||||
*
|
|
||||||
* The 'data' variable points to the input/output/encoder/etc. The 'ui_data'
|
|
||||||
* varaible points to the UI parent or UI-specific data to be used with the
|
|
||||||
* custom user interface.
|
|
||||||
*
|
*
|
||||||
* What 'ui_data' points to differs depending on the target, and you should
|
* What 'ui_data' points to differs depending on the target, and you should
|
||||||
* use discretion and consistency when using this variable to relay
|
* use discretion and consistency when using this variable to relay
|
||||||
* information to the UI function. For example, it would be ideal to have
|
* information to the UI function. For example, it would be ideal to have
|
||||||
* 'ui_data' point to a parent, QWidget for Qt, or a wxWindow for wxWidgets,
|
* 'ui_data' point to a parent, QWidget for Qt, or a wxWindow for wxWidgets,
|
||||||
* etc.
|
* etc., though it's up to the discretion of the developer to define that
|
||||||
*
|
* value. Because of the nature of void pointers, discretion and consistency
|
||||||
* For example, if I had a source called 'mysource', and I wanted to export
|
* is advised.
|
||||||
* a function that handles the task 'config' with the Qt library, the export
|
|
||||||
* would be:
|
|
||||||
*
|
|
||||||
* bool mysource_config_qt(void *data, void *ui_data);
|
|
||||||
*
|
|
||||||
* In this example, the ui_data variable should ideally be a pointer to the
|
|
||||||
* QWidget parent, if any.
|
|
||||||
*
|
*
|
||||||
* ===========================================
|
* ===========================================
|
||||||
* Modeless UI
|
* Modeless UI Callback
|
||||||
* ===========================================
|
* ===========================================
|
||||||
* Modeless user interface calls are supported, but they must be exported
|
* void *modeless_callback(void *data, void *ui_data);
|
||||||
* through enum_modeless_ui, and the format is slightly different:
|
|
||||||
*
|
|
||||||
* void *[name]_[task]_[target](void *data, void *ui_data);
|
|
||||||
*
|
*
|
||||||
* Modeless UI calls return immediately, and typically are supposed to return
|
* Modeless UI calls return immediately, and typically are supposed to return
|
||||||
* a pointer or handle to the specific UI object that was created. For
|
* a pointer or handle to the specific UI object that was created. For
|
||||||
* example, a win32 modeless would return an HWND, a Qt object would return
|
* example, a Qt object would ideally return a pointer to a QWidget. Again,
|
||||||
* a pointer to a QWidget.
|
* discretion and consistency is advised for the return value.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ===========================================
|
* ===========================================
|
||||||
* obs_call_ui
|
* obs_exec_ui
|
||||||
* ===========================================
|
* ===========================================
|
||||||
* Requests modal UI to be displayed
|
* Requests modal UI to be displayed. Returns when user is complete.
|
||||||
*
|
|
||||||
* This is typically used for things like creating modal dialogs/etc for
|
|
||||||
* specific toolkits.
|
|
||||||
*
|
*
|
||||||
* name: Name of the input/output/etc type that UI was requested for
|
* name: Name of the input/output/etc type that UI was requested for
|
||||||
* task: Task of the user interface (usually "config")
|
* task: Task of the user interface (usually "config")
|
||||||
@ -153,14 +134,14 @@ struct obs_ui_info {
|
|||||||
#define OBS_UI_CANCEL -1
|
#define OBS_UI_CANCEL -1
|
||||||
#define OBS_UI_NOTFOUND -2
|
#define OBS_UI_NOTFOUND -2
|
||||||
|
|
||||||
EXPORT int obs_call_ui(const char *name, const char *task, const char *target,
|
EXPORT int obs_exec_ui(const char *name, const char *task, const char *target,
|
||||||
void *data, void *ui_data);
|
void *data, void *ui_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ===========================================
|
* ===========================================
|
||||||
* obs_create_ui
|
* obs_create_ui
|
||||||
* ===========================================
|
* ===========================================
|
||||||
* Requests modeless UI to be created
|
* Requests modeless UI to be created. Returns immediately.
|
||||||
*
|
*
|
||||||
* name: Name of the input/output/etc type that UI was requested for
|
* name: Name of the input/output/etc type that UI was requested for
|
||||||
* task: Task of the user interface
|
* task: Task of the user interface
|
||||||
|
33
libobs/obs.c
33
libobs/obs.c
@ -326,7 +326,7 @@ void obs_shutdown(void)
|
|||||||
da_free(obs->transition_types);
|
da_free(obs->transition_types);
|
||||||
da_free(obs->output_types);
|
da_free(obs->output_types);
|
||||||
da_free(obs->service_types);
|
da_free(obs->service_types);
|
||||||
da_free(obs->ui_callbacks);
|
da_free(obs->ui_modal_callbacks);
|
||||||
da_free(obs->ui_modeless_callbacks);
|
da_free(obs->ui_modeless_callbacks);
|
||||||
|
|
||||||
obs_free_data();
|
obs_free_data();
|
||||||
@ -454,44 +454,44 @@ video_t obs_video(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: optimize this later so it's not just O(N) string lookups */
|
/* TODO: optimize this later so it's not just O(N) string lookups */
|
||||||
static inline struct ui_callback *get_ui_callback(const char *name,
|
static inline struct obs_modal_ui *get_modal_ui_callback(const char *name,
|
||||||
const char *task, const char *target)
|
const char *task, const char *target)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < obs->ui_callbacks.num; i++) {
|
for (size_t i = 0; i < obs->ui_modal_callbacks.num; i++) {
|
||||||
struct ui_callback *callback = obs->ui_callbacks.array+i;
|
struct obs_modal_ui *callback = obs->ui_modal_callbacks.array+i;
|
||||||
|
|
||||||
if (strcmp(callback->ui_info.name, name) == 0 &&
|
if (strcmp(callback->name, name) == 0 &&
|
||||||
strcmp(callback->ui_info.task, task) == 0 &&
|
strcmp(callback->task, task) == 0 &&
|
||||||
strcmp(callback->ui_info.target, target) == 0)
|
strcmp(callback->target, target) == 0)
|
||||||
return callback;
|
return callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct ui_modeless *get_modeless_ui_callback(const char *name,
|
static inline struct obs_modeless_ui *get_modeless_ui_callback(const char *name,
|
||||||
const char *task, const char *target)
|
const char *task, const char *target)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < obs->ui_modeless_callbacks.num; i++) {
|
for (size_t i = 0; i < obs->ui_modeless_callbacks.num; i++) {
|
||||||
struct ui_modeless *callback;
|
struct obs_modeless_ui *callback;
|
||||||
callback = obs->ui_modeless_callbacks.array+i;
|
callback = obs->ui_modeless_callbacks.array+i;
|
||||||
|
|
||||||
if (strcmp(callback->ui_info.name, name) == 0 &&
|
if (strcmp(callback->name, name) == 0 &&
|
||||||
strcmp(callback->ui_info.task, task) == 0 &&
|
strcmp(callback->task, task) == 0 &&
|
||||||
strcmp(callback->ui_info.target, target) == 0)
|
strcmp(callback->target, target) == 0)
|
||||||
return callback;
|
return callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int obs_call_ui(const char *name, const char *task, const char *target,
|
int obs_exec_ui(const char *name, const char *task, const char *target,
|
||||||
void *data, void *ui_data)
|
void *data, void *ui_data)
|
||||||
{
|
{
|
||||||
struct ui_callback *callback;
|
struct obs_modal_ui *callback;
|
||||||
int errorcode = OBS_UI_NOTFOUND;
|
int errorcode = OBS_UI_NOTFOUND;
|
||||||
|
|
||||||
callback = get_ui_callback(name, task, target);
|
callback = get_modal_ui_callback(name, task, target);
|
||||||
if (callback) {
|
if (callback) {
|
||||||
bool success = callback->callback(data, ui_data);
|
bool success = callback->callback(data, ui_data);
|
||||||
errorcode = success ? OBS_UI_SUCCESS : OBS_UI_CANCEL;
|
errorcode = success ? OBS_UI_SUCCESS : OBS_UI_CANCEL;
|
||||||
@ -503,8 +503,7 @@ int obs_call_ui(const char *name, const char *task, const char *target,
|
|||||||
void *obs_create_ui(const char *name, const char *task, const char *target,
|
void *obs_create_ui(const char *name, const char *task, const char *target,
|
||||||
void *data, void *ui_data)
|
void *data, void *ui_data)
|
||||||
{
|
{
|
||||||
struct ui_modeless *callback;
|
struct obs_modeless_ui *callback;
|
||||||
int errorcode = OBS_UI_NOTFOUND;
|
|
||||||
|
|
||||||
callback = get_modeless_ui_callback(name, task, target);
|
callback = get_modeless_ui_callback(name, task, target);
|
||||||
return callback ? callback->callback(data, ui_data) : NULL;
|
return callback ? callback->callback(data, ui_data) : NULL;
|
||||||
|
Loading…
Reference in New Issue
Block a user