Misc #204: Add glx_take_screenshot() & others

- Add glx_take_screenshot() for taking a screenshot. With ImageMagick
  the output data could be viewed in this way:

    display -size [SCREEN-WIDTH]x[SCREEN-HEIGHT] -depth 8 -flip
    rgb:[PATH]

  (#204)

- Add D-Bus command `opts_get string:paint_on_overlay_id` to get X
  Composite overlay window ID. (#204)

- Code cleanup.
This commit is contained in:
Richard Grenville 2014-09-07 18:58:09 +08:00
parent c5f45c8e3c
commit 8c88b4d6f1
4 changed files with 105 additions and 25 deletions

View File

@ -2208,6 +2208,9 @@ glx_render_(session_t *ps, const glx_texture_t *ptex,
void
glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg);
unsigned char *
glx_take_screenshot(session_t *ps, int *out_length);
#ifdef CONFIG_VSYNC_OPENGL_GLSL
GLuint
glx_create_shader(GLenum shader_type, const char *shader_str);
@ -2484,6 +2487,28 @@ c2_matchd(session_t *ps, win *w, const c2_lptr_t *condlst,
#endif
/**
* @brief Dump the given data to a file.
*/
static inline bool
write_binary_data(const char *path, const unsigned char *data, int length) {
if (!data)
return false;
FILE *f = fopen(path, "wb");
if (!f) {
printf_errf("(\"%s\"): Failed to open file for writing.", path);
return false;
}
int wrote_len = fwrite(data, sizeof(unsigned char), length, f);
fclose(f);
if (wrote_len != length) {
printf_errf("(\"%s\"): Failed to write all blocks: %d / %d", path,
wrote_len, length);
return false;
}
return true;
}
/**
* @brief Dump raw bytes in HEX format.
*

View File

@ -1411,6 +1411,20 @@ xr_blur_dst(session_t *ps, Picture tgt_buffer,
return true;
}
/*
* WORK-IN-PROGRESS!
static void
xr_take_screenshot(session_t *ps) {
XImage *img = XGetImage(ps->dpy, get_tgt_window(ps), 0, 0,
ps->root_width, ps->root_height, AllPlanes, XYPixmap);
if (!img) {
printf_errf("(): Failed to get XImage.");
return NULL;
}
assert(0 == img->xoffset);
}
*/
/**
* Blur the background of a window.
*/
@ -7530,6 +7544,16 @@ session_destroy(session_t *ps) {
ps_g = NULL;
}
/*
static inline void
dump_img(session_t *ps) {
int len = 0;
unsigned char *d = glx_take_screenshot(ps, &len);
write_binary_data("/tmp/dump.raw", d, len);
free(d);
}
*/
/**
* Do the actual work.
*

View File

@ -901,6 +901,11 @@ cdbus_process_opts_get(session_t *ps, DBusMessage *msg) {
cdbus_m_opts_get_do(fork_after_register, cdbus_reply_bool);
cdbus_m_opts_get_do(detect_rounded_corners, cdbus_reply_bool);
cdbus_m_opts_get_do(paint_on_overlay, cdbus_reply_bool);
// paint_on_overlay_id: Get ID of the X composite overlay window
if (!strcmp("paint_on_overlay_id", target)) {
cdbus_reply_uint32(ps, msg, ps->overlay);
return true;
}
cdbus_m_opts_get_do(unredir_if_possible, cdbus_reply_bool);
cdbus_m_opts_get_do(unredir_if_possible_delay, cdbus_reply_int32);
cdbus_m_opts_get_do(redirected_force, cdbus_reply_enum);

View File

@ -1442,7 +1442,7 @@ glx_render_(session_t *ps, const glx_texture_t *ptex,
#endif
argb = argb || (GLX_TEXTURE_FORMAT_RGBA_EXT ==
ps->psglx->fbconfigs[ptex->depth]->texture_fmt);
ps->psglx->fbconfigs[ptex->depth]->texture_fmt);
#ifdef CONFIG_VSYNC_OPENGL_GLSL
const bool has_prog = pprogram && pprogram->prog;
#endif
@ -1754,6 +1754,32 @@ glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg) {
cxfree(rects);
}
/**
* @brief Get tightly packed RGB888 data from GL front buffer.
*
* Don't expect any sort of decent performance.
*
* @returns tightly packed RGB888 data of the size of the screen,
* to be freed with `free()`
*/
unsigned char *
glx_take_screenshot(session_t *ps, int *out_length) {
int length = 3 * ps->root_width * ps->root_height;
GLint unpack_align_old = 0;
glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_align_old);
assert(unpack_align_old > 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
unsigned char *buf = cmalloc(length, unsigned char);
glReadBuffer(GL_FRONT);
glReadPixels(0, 0, ps->root_width, ps->root_height, GL_RGB,
GL_UNSIGNED_BYTE, buf);
glReadBuffer(GL_BACK);
glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_align_old);
if (out_length)
*out_length = sizeof(unsigned char) * length;
return buf;
}
#ifdef CONFIG_VSYNC_OPENGL_GLSL
GLuint
glx_create_shader(GLenum shader_type, const char *shader_str) {
@ -1847,34 +1873,34 @@ glx_create_program_end:
*/
GLuint
glx_create_program_from_str(const char *vert_shader_str,
const char *frag_shader_str) {
GLuint vert_shader = 0;
GLuint frag_shader = 0;
GLuint prog = 0;
const char *frag_shader_str) {
GLuint vert_shader = 0;
GLuint frag_shader = 0;
GLuint prog = 0;
if (vert_shader_str)
vert_shader = glx_create_shader(GL_VERTEX_SHADER, vert_shader_str);
if (frag_shader_str)
frag_shader = glx_create_shader(GL_FRAGMENT_SHADER, frag_shader_str);
if (vert_shader_str)
vert_shader = glx_create_shader(GL_VERTEX_SHADER, vert_shader_str);
if (frag_shader_str)
frag_shader = glx_create_shader(GL_FRAGMENT_SHADER, frag_shader_str);
{
GLuint shaders[2];
int count = 0;
if (vert_shader)
shaders[count++] = vert_shader;
if (frag_shader)
shaders[count++] = frag_shader;
assert(count <= sizeof(shaders) / sizeof(shaders[0]));
if (count)
prog = glx_create_program(shaders, count);
}
{
GLuint shaders[2];
int count = 0;
if (vert_shader)
shaders[count++] = vert_shader;
if (frag_shader)
shaders[count++] = frag_shader;
assert(count <= sizeof(shaders) / sizeof(shaders[0]));
if (count)
prog = glx_create_program(shaders, count);
}
if (vert_shader)
glDeleteShader(vert_shader);
if (frag_shader)
glDeleteShader(frag_shader);
if (vert_shader)
glDeleteShader(vert_shader);
if (frag_shader)
glDeleteShader(frag_shader);
return prog;
return prog;
}
#endif