From e3717f4f7bf3a0a0a015337454f1e381a6e0278f Mon Sep 17 00:00:00 2001 From: Richard Grenville Date: Sun, 7 Sep 2014 18:58:09 +0800 Subject: [PATCH] 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. --- common.h | 25 +++++++++++++++++ compton.c | 24 ++++++++++++++++ dbus.c | 5 ++++ opengl.c | 84 ++++++++++++++++++++++++++++++++++++------------------- 4 files changed, 109 insertions(+), 29 deletions(-) diff --git a/common.h b/common.h index f9b5d9453..0aa4f18b8 100644 --- a/common.h +++ b/common.h @@ -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. * diff --git a/compton.c b/compton.c index 330155891..b967372ee 100644 --- a/compton.c +++ b/compton.c @@ -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. * diff --git a/dbus.c b/dbus.c index 8aec9ea82..874f565ca 100644 --- a/dbus.c +++ b/dbus.c @@ -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); diff --git a/opengl.c b/opengl.c index 800ebd585..5a98f4e0a 100644 --- a/opengl.c +++ b/opengl.c @@ -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; - - 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); - } - - if (vert_shader) - glDeleteShader(vert_shader); - if (frag_shader) - glDeleteShader(frag_shader); - - return prog; + 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); + + { + 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); + + return prog; } #endif