/** * Get the properties for the capture */ static obs_properties_t *xshm_properties(void *vptr) { XSHM_DATA(vptr); obs_properties_t *props = obs_properties_create(); 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; }
/** * Destroy the capture */ static void xshm_destroy(void *vptr) { XSHM_DATA(vptr); if (!data) return; xshm_capture_stop(data); bfree(data); }
/** * Update the capture with changed settings */ static void xshm_update(void *vptr, obs_data_t *settings) { XSHM_DATA(vptr); xshm_capture_stop(data); 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); }
/** * Render the capture data */ static void xshm_video_render(void *vptr, gs_effect_t effect) { XSHM_DATA(vptr); if (!data->xshm) return; gs_eparam_t image = gs_effect_get_param_by_name(effect, "image"); gs_effect_set_texture(image, data->texture); gs_enable_blending(false); gs_draw_sprite(data->texture, 0, 0, 0); if (data->show_cursor) xcursor_render(data->cursor); gs_reset_blend_state(); }
/** * Prepare the capture data */ static void xshm_video_tick(void *vptr, float seconds) { UNUSED_PARAMETER(seconds); XSHM_DATA(vptr); if (!data->xshm) return; obs_enter_graphics(); XShmGetImage(data->dpy, XRootWindowOfScreen(data->screen), data->xshm->image, data->x_org, data->y_org, AllPlanes); gs_texture_set_image(data->texture, (void *) data->xshm->image->data, data->width * 4, false); xcursor_tick(data->cursor); obs_leave_graphics(); }
/** * Prepare the capture data */ static void xshm_video_tick(void *vptr, float seconds) { UNUSED_PARAMETER(seconds); XSHM_DATA(vptr); if (!data->texture) return; if (!obs_source_showing(data->source)) return; xcb_shm_get_image_cookie_t img_c; xcb_shm_get_image_reply_t *img_r; xcb_xfixes_get_cursor_image_cookie_t cur_c; xcb_xfixes_get_cursor_image_reply_t *cur_r; img_c = xcb_shm_get_image_unchecked(data->xcb, data->xcb_screen->root, data->x_org, data->y_org, data->width, data->height, ~0, XCB_IMAGE_FORMAT_Z_PIXMAP, data->xshm->seg, 0); cur_c = xcb_xfixes_get_cursor_image_unchecked(data->xcb); img_r = xcb_shm_get_image_reply(data->xcb, img_c, NULL); cur_r = xcb_xfixes_get_cursor_image_reply(data->xcb, cur_c, NULL); if (!img_r) goto exit; obs_enter_graphics(); gs_texture_set_image(data->texture, (void *) data->xshm->data, data->width * 4, false); xcb_xcursor_update(data->cursor, cur_r); obs_leave_graphics(); exit: free(img_r); free(cur_r); }
/** * Destroy the capture */ static void xshm_destroy(void *vptr) { XSHM_DATA(vptr); if (!data) return; obs_enter_graphics(); if (data->texture) gs_texture_destroy(data->texture); if (data->cursor) xcursor_destroy(data->cursor); obs_leave_graphics(); if (data->xshm) xshm_detach(data->xshm); if (data->dpy) XCloseDisplay(data->dpy); bfree(data); }
/** * Update the capture with changed settings */ static void xshm_update(void *vptr, obs_data_t settings) { XSHM_DATA(vptr); data->show_cursor = obs_data_get_bool(settings, "show_cursor"); if (data->xshm) xshm_detach(data->xshm); if (xshm_update_geometry(data, settings) < 0) { blog(LOG_ERROR, "xshm-input: failed to update geometry !"); return; } xshm_resize_texture(data); xcursor_offset(data->cursor, data->x_org, data->y_org); data->xshm = xshm_attach(data->dpy, data->screen, data->width, data->height); if (!data->xshm) { blog(LOG_ERROR, "xshm-input: failed to attach shm !"); return; } }
/** * Render the capture data */ static void xshm_video_render(void *vptr, gs_effect_t *effect) { XSHM_DATA(vptr); effect = obs_get_opaque_effect(); if (!data->texture) return; gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image"); gs_effect_set_texture(image, data->texture); while (gs_effect_loop(effect, "Draw")) { gs_draw_sprite(data->texture, 0, 0, 0); } if (data->show_cursor) { effect = obs_get_default_effect(); while (gs_effect_loop(effect, "Draw")) { xcb_xcursor_render(data->cursor); } } }
/** * Height of the captured data */ static uint32_t xshm_getheight(void *vptr) { XSHM_DATA(vptr); return data->height; }
/** * Width of the captured data */ static uint32_t xshm_getwidth(void *vptr) { XSHM_DATA(vptr); return data->width; }