linux-xshm: Add server property.

This adds a property to the source properties which lets the user
specify the X server to capture from. Since this is probably something
thats only useful under certain circumstances it is implemented as
an advanced setting which is only shown when the corresponding option
for advanced settings is checked.
master
fryshorts 2014-11-18 22:18:43 +01:00
parent 04a7db867f
commit 67ca94f7e4
2 changed files with 109 additions and 15 deletions

View File

@ -1,6 +1,8 @@
X11SharedMemoryScreenInput="Screen Capture (XSHM)"
Screen="Screen"
CaptureCursor="Capture Cursor"
AdvancedSettings="Advanced Settings"
XServer="X Server"
XCCapture="Window Capture (Xcomposite)"
Window="Window"
CropTop="Crop Top (pixels)"

View File

@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <X11/Xutil.h>
#include <obs-module.h>
#include <util/dstr.h>
#include "xcursor.h"
#include "xhelpers.h"
@ -30,10 +31,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define blog(level, msg, ...) blog(level, "xshm-input: " msg, ##__VA_ARGS__)
struct xshm_data {
/** The source object */
obs_source_t *source;
/** Xlib display object */
Display *dpy;
/** Xlib screen object */
Screen *screen;
/** user setting - the server name to capture from */
char *server;
/** user setting - the id of the screen that should be captured */
uint_fast32_t screen_id;
/** root coordinates for the capture */
@ -50,6 +55,8 @@ struct xshm_data {
bool show_cursor;
/** set if xinerama is available and active on the screen */
bool use_xinerama;
/** user setting - if advanced settings should be displayed */
bool advanced;
};
/**
@ -146,6 +153,11 @@ static void xshm_capture_stop(struct xshm_data *data)
XCloseDisplay(data->dpy);
data->dpy = NULL;
}
if (data->server) {
bfree(data->server);
data->server = NULL;
}
}
/**
@ -153,7 +165,10 @@ static void xshm_capture_stop(struct xshm_data *data)
*/
static void xshm_capture_start(struct xshm_data *data)
{
data->dpy = XOpenDisplay(NULL);
const char *server = (data->advanced && *data->server)
? data->server : NULL;
data->dpy = XOpenDisplay(server);
if (!data->dpy) {
blog(LOG_ERROR, "Unable to open X display !");
goto fail;
@ -202,6 +217,8 @@ static void xshm_update(void *vptr, obs_data_t *settings)
data->screen_id = obs_data_get_int(settings, "screen");
data->show_cursor = obs_data_get_bool(settings, "show_cursor");
data->advanced = obs_data_get_bool(settings, "advanced");
data->server = bstrdup(obs_data_get_string(settings, "server"));
xshm_capture_start(data);
}
@ -213,29 +230,105 @@ static void xshm_defaults(obs_data_t *defaults)
{
obs_data_set_default_int(defaults, "screen", 0);
obs_data_set_default_bool(defaults, "show_cursor", true);
obs_data_set_default_bool(defaults, "advanced", false);
}
/**
* Toggle visibility of advanced settings
*/
static bool xshm_toggle_advanced(obs_properties_t *props,
obs_property_t *p, obs_data_t *settings)
{
UNUSED_PARAMETER(p);
const bool visible = obs_data_get_bool(settings, "advanced");
obs_property_t *server = obs_properties_get(props, "server");
obs_property_set_visible(server, visible);
/* trigger server changed callback so the screen list is refreshed */
obs_property_modified(server, settings);
return true;
}
/**
* The x server was changed
*/
static bool xshm_server_changed(obs_properties_t *props,
obs_property_t *p, obs_data_t *settings)
{
UNUSED_PARAMETER(p);
bool advanced = obs_data_get_bool(settings, "advanced");
const char *server = obs_data_get_string(settings, "server");
obs_property_t *screens = obs_properties_get(props, "screen");
/* we want a real NULL here in case there is no string here */
server = (advanced && *server) ? server : NULL;
obs_property_list_clear(screens);
Display *dpy = XOpenDisplay(server);
if (!dpy) {
obs_property_set_enabled(screens, false);
return true;
}
struct dstr screen_info;
dstr_init(&screen_info);
bool xinerama = xinerama_is_active(dpy);
int_fast32_t count = (xinerama) ?
xinerama_screen_count(dpy) : XScreenCount(dpy);
for (int_fast32_t i = 0; i < count; ++i) {
int_fast32_t x, y, w, h;
x = y = w = h = 0;
if (xinerama)
xinerama_screen_geo(dpy, i, &x, &y, &w, &h);
else
x11_screen_geo(dpy, i, &w, &h);
dstr_printf(&screen_info, "Screen %"PRIuFAST32" (%"PRIuFAST32
"x%"PRIuFAST32" @ %"PRIuFAST32
",%"PRIuFAST32")", i, w, h, x, y);
obs_property_list_add_int(screens, screen_info.array, i);
}
dstr_free(&screen_info);
XCloseDisplay(dpy);
obs_property_set_enabled(screens, true);
return true;
}
/**
* Get the properties for the capture
*/
static obs_properties_t *xshm_properties(void *unused)
static obs_properties_t *xshm_properties(void *vptr)
{
UNUSED_PARAMETER(unused);
XSHM_DATA(vptr);
obs_properties_t *props = obs_properties_create();
int_fast32_t screen_max;
Display *dpy = XOpenDisplay(NULL);
screen_max = xinerama_is_active(dpy)
? xinerama_screen_count(dpy)
: XScreenCount(dpy);
screen_max = (screen_max) ? screen_max - 1 : 0;
XCloseDisplay(dpy);
obs_properties_add_int(props, "screen",
obs_module_text("Screen"), 0, screen_max, 1);
obs_properties_add_list(props, "screen", obs_module_text("Screen"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_properties_add_bool(props, "show_cursor",
obs_module_text("CaptureCursor"));
obs_property_t *advanced = obs_properties_add_bool(props, "advanced",
obs_module_text("AdvancedSettings"));
obs_property_t *server = obs_properties_add_text(props, "server",
obs_module_text("XServer"), OBS_TEXT_DEFAULT);
obs_property_set_modified_callback(advanced, xshm_toggle_advanced);
obs_property_set_modified_callback(server, xshm_server_changed);
/* trigger server callback to get screen count ... */
obs_data_t *settings = obs_source_get_settings(data->source);
obs_property_modified(server, settings);
obs_data_release(settings);
return props;
}
@ -260,9 +353,8 @@ static void xshm_destroy(void *vptr)
*/
static void *xshm_create(obs_data_t *settings, obs_source_t *source)
{
UNUSED_PARAMETER(source);
struct xshm_data *data = bzalloc(sizeof(struct xshm_data));
data->source = source;
xshm_update(data, settings);