"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/main.c" between
scrot-0.8.tar.gz and scrot-1.6.tar.bz2

About: scrot (SCReenshOT) is a simple command line screen capture utility using imlib2 to grab and save images.

main.c  (scrot-0.8):main.c  (scrot-1.6.tar.bz2)
/* main.c /* main.c
Copyright (C) 1999,2000 Tom Gilbert. Copyright 1999-2000 Tom Gilbert <tom@linuxbrit.co.uk,
gilbertt@linuxbrit.co.uk,
scrot_sucks@linuxbrit.co.uk>
Copyright 2009 James Cameron <quozl@us.netrek.org>
Copyright 2010 Ibragimov Rinat <ibragimovrinat@mail.ru>
Copyright 2017 Stoney Sauce <stoneysauce@gmail.com>
Copyright 2019-2021 Daniel T. Borelli <daltomi@disroot.org>
Copyright 2019 Jade Auer <jade@trashwitch.dev>
Copyright 2020 blockparole
Copyright 2020 Cungsten Tarbide <ctarbide@tuta.io>
Copyright 2020 Hinigatsu <hinigatsu@protonmail.com>
Copyright 2020 nothub
Copyright 2020 Sean Brennan <zettix1@gmail.com>
Copyright 2021 c0dev0id <sh+github@codevoid.de>
Copyright 2021 Christopher R. Nelson <christopher.nelson@languidnights.com>
Copyright 2021 Guilherme Janczak <guilherme.janczak@yandex.com>
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in The above copyright notice and this permission notice shall be included in
all copies of the Software and its documentation and acknowledgment shall be all copies of the Software and its documentation and acknowledgment shall be
skipping to change at line 28 skipping to change at line 43
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include "scrot.h" #include "scrot.h"
#include "options.h" #include "options.h"
#include "slist.h"
#include <assert.h>
/* atexit register func. */
static void uninit_x_and_imlib(void)
{
if (disp) {
XCloseDisplay(disp);
disp = NULL;
}
}
// It assumes that the local variable 'main.c:Imlib_Image image' is in context
static void apply_filter_if_required(void)
{
if (opt.script != NULL) {
imlib_apply_filter(opt.script);
}
}
int int
main(int argc, main(int argc,
char **argv) char **argv)
{ {
Imlib_Image image; Imlib_Image image;
Imlib_Image thumbnail; Imlib_Image thumbnail;
Imlib_Load_Error err; Imlib_Load_Error err;
char *filename_im = NULL, *filename_thumb = NULL; char *filename_im = NULL, *filename_thumb = NULL;
char *have_extension = NULL;
time_t t; time_t t;
struct tm *tm; struct tm *tm;
init_parse_options(argc, argv); init_parse_options(argc, argv);
init_x_and_imlib(NULL, 0); init_x_and_imlib(opt.display, 0);
atexit(uninit_x_and_imlib);
if (!opt.output_file) { if (!opt.output_file) {
opt.output_file = gib_estrdup("%Y-%m-%d-%H%M%S_$wx$h_scrot.png"); opt.output_file = strdup("%Y-%m-%d-%H%M%S_$wx$h_scrot.png");
opt.thumb_file = gib_estrdup("%Y-%m-%d-%H%M%S_$wx$h_scrot-thumb.png"); opt.thumb_file = strdup("%Y-%m-%d-%H%M%S_$wx$h_scrot-thumb.png");
} else {
scrot_have_file_extension(opt.output_file, &have_extension);
} }
if (opt.select) if (opt.focused)
image = scrot_grab_focused();
else if (opt.select)
image = scrot_sel_and_grab_image(); image = scrot_sel_and_grab_image();
else { else if (opt.autoselect)
image = scrot_grab_autoselect();
else
{
scrot_do_delay(); scrot_do_delay();
if (opt.multidisp) { if (opt.multidisp) {
image = scrot_grab_shot_multi(); image = scrot_grab_shot_multi();
} else if (opt.stack) {
image = scrot_grab_stack_windows();
} else { } else {
image = scrot_grab_shot(); image = scrot_grab_shot();
} }
} }
if (!image) if (opt.note != NULL)
gib_eprintf("no image grabbed"); scrot_note_draw(image);
if (!image) {
fprintf(stderr, "no image grabbed: %s", strerror(errno));
exit(EXIT_FAILURE);
}
time(&t); /* Get the time directly after the screenshot */ time(&t); /* Get the time directly after the screenshot */
tm = localtime(&t); tm = localtime(&t);
imlib_context_set_image(image); imlib_context_set_image(image);
imlib_image_attach_data_value("quality", NULL, opt.quality, NULL); imlib_image_attach_data_value("quality", NULL, opt.quality, NULL);
if (!have_extension) {
imlib_image_set_format("png");
}
filename_im = im_printf(opt.output_file, tm, NULL, NULL, image); filename_im = im_printf(opt.output_file, tm, NULL, NULL, image);
gib_imlib_save_image_with_error_return(image, filename_im, &err); scrot_check_if_overwrite_file(&filename_im);
if (err)
gib_eprintf("Saving to file %s failed\n", filename_im); apply_filter_if_required();
imlib_save_image_with_error_return(filename_im, &err);
if (err) {
fprintf(stderr, "Saving to file %s failed: %s\n", filename_im, strerror(errn
o));
exit(EXIT_FAILURE);
}
if (opt.thumb) if (opt.thumb)
{ {
int cwidth, cheight; int cwidth, cheight;
int twidth, theight; int twidth, theight;
cwidth = gib_imlib_image_get_width(image); cwidth = imlib_image_get_width();
cheight = gib_imlib_image_get_height(image); cheight = imlib_image_get_height();
/* Geometry based thumb size */ /* Geometry based thumb size */
if (opt.thumb_width || opt.thumb_height) if (opt.thumb_width || opt.thumb_height)
{ {
if (!opt.thumb_width) if (!opt.thumb_width)
{ {
twidth = cwidth * opt.thumb_height / cheight; twidth = cwidth * opt.thumb_height / cheight;
theight = opt.thumb_height; theight = opt.thumb_height;
} }
else if (!opt.thumb_height) else if (!opt.thumb_height)
skipping to change at line 107 skipping to change at line 169
twidth = opt.thumb_width; twidth = opt.thumb_width;
theight = opt.thumb_height; theight = opt.thumb_height;
} }
} }
else else
{ {
twidth = cwidth * opt.thumb / 100; twidth = cwidth * opt.thumb / 100;
theight = cheight * opt.thumb / 100; theight = cheight * opt.thumb / 100;
} }
imlib_context_set_anti_alias(1);
thumbnail = thumbnail =
gib_imlib_create_cropped_scaled_image(image, 0, 0, cwidth, cheight, imlib_create_cropped_scaled_image(0, 0, cwidth, cheight,
twidth, theight, 1); twidth, theight);
if (thumbnail == NULL) if (thumbnail == NULL) {
gib_eprintf("Unable to create scaled Image\n"); fprintf(stderr, "Unable to create scaled Image: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
else else
{ {
if (opt.note != NULL)
scrot_note_draw(image);
scrot_have_file_extension(opt.thumb_file, &have_extension);
if (!have_extension) {
imlib_context_set_image(thumbnail);
imlib_image_set_format("png");
}
filename_thumb = im_printf(opt.thumb_file, tm, NULL, NULL, thumbnail); filename_thumb = im_printf(opt.thumb_file, tm, NULL, NULL, thumbnail);
gib_imlib_save_image_with_error_return(thumbnail, filename_thumb, &err); scrot_check_if_overwrite_file(&filename_thumb);
if (err)
gib_eprintf("Saving thumbnail %s failed\n", filename_thumb); apply_filter_if_required();
imlib_save_image_with_error_return(filename_thumb, &err);
if (err) {
fprintf(stderr, "Saving thumbnail %s failed: %s\n", filename_thumb, stre
rror(errno));
exit(EXIT_FAILURE);
}
} }
} }
if (opt.exec) if (opt.exec)
scrot_exec_app(image, tm, filename_im, filename_thumb); scrot_exec_app(image, tm, filename_im, filename_thumb);
gib_imlib_free_image_and_decache(image); imlib_free_image_and_decache();
return 0; return 0;
} }
void void
scrot_do_delay(void) scrot_do_delay(void)
{ {
if (opt.delay) { if (opt.delay) {
if (opt.countdown) { if (opt.countdown) {
int i; int i;
skipping to change at line 149 skipping to change at line 230
fflush(stdout); fflush(stdout);
sleep(1); sleep(1);
} }
printf("0.\n"); printf("0.\n");
fflush(stdout); fflush(stdout);
} else } else
sleep(opt.delay); sleep(opt.delay);
} }
} }
size_t scrot_have_file_extension(char const *filename, char **ext)
{
*ext = strrchr(filename, '.');
if (*ext) {
return strlen(*ext);
}
return 0;
}
void scrot_check_if_overwrite_file(char **filename)
{
char *curfile = *filename;
if (opt.overwrite == 1) return;
if (access(curfile, F_OK) == -1) return;
const size_t max_counter = 999;
size_t counter = 0;
char *ext = NULL;
size_t ext_len = 0;
const size_t slen = strlen(curfile);
size_t nalloc = slen + 4 + 1; // _000 + NUL byte
char fmt[5];
char *newname = NULL;
ext_len = scrot_have_file_extension(curfile, &ext);
if (ext)
nalloc += ext_len; // .ext
newname = calloc(nalloc, sizeof(char));
if (ext)
// exclude ext
memcpy(newname, curfile, slen - ext_len);
else
memcpy(newname, curfile, slen);
do {
snprintf(fmt, 5, "_%03zu", counter++);
if (!ext) {
strncpy(newname + slen, fmt, 5);
} else {
strncpy((newname + slen) - ext_len, fmt, 5);
strncat(newname, ext, ext_len);
}
curfile = newname;
} while ((counter < max_counter) && (access(curfile, F_OK) == 0));
free(*filename);
*filename = newname;
if (counter == max_counter) {
fprintf(stderr, "scrot can no longer generate new file names.\n"
"The last attempt is %s\n", newname);
free(newname);
exit(EXIT_FAILURE);
}
}
int scrot_match_window_class_name(Window target)
{
assert(disp != NULL);
const int NOT_MATCH = 0;
const int MATCH = 1;
/* By default all class names match since window_class_name by default is NU
LL*/
int retval = MATCH;
if (opt.window_class_name == NULL) {
return retval;
}
XClassHint classHint;
retval = NOT_MATCH; // window_class_name != NULL, by default NOT_MATCH
if (XGetClassHint(disp, target, &classHint) != BadWindow) {
retval = options_cmp_window_class_name(classHint.res_class);
XFree(classHint.res_name);
XFree(classHint.res_class);
}
return retval;
}
void
scrot_grab_mouse_pointer(const Imlib_Image image,
const int ix_off, const int iy_off)
{
XFixesCursorImage *xcim = XFixesGetCursorImage(disp);
const unsigned short width = xcim->width;
const unsigned short height = xcim->height;
const int x = (xcim->x - xcim->xhot) - ix_off;
const int y = (xcim->y - xcim->yhot) - iy_off;
DATA32 *pixels = NULL;
#ifdef __i386__
pixels = (DATA32*)xcim->pixels;
#else
DATA32 data[width * height * 4];
unsigned int i;
for (i = 0; i < (width * height); i++)
((DATA32*)data)[i] = (DATA32)xcim->pixels[i];
pixels = data;
#endif
Imlib_Image imcursor = imlib_create_image_using_data(width, height, pixels);
XFree(xcim);
if (!imcursor) {
fprintf(stderr, "scrot_grab_mouse_pointer: Failed create image using data.\
n");
exit(EXIT_FAILURE);
}
imlib_context_set_image(imcursor);
imlib_image_set_has_alpha(1);
imlib_context_set_image(image);
imlib_blend_image_onto_image(imcursor, 0, 0, 0, width, height, x, y, width, he
ight);
imlib_context_set_image(imcursor);
imlib_free_image();
}
Imlib_Image Imlib_Image
scrot_grab_shot(void) scrot_grab_shot(void)
{ {
Imlib_Image im; Imlib_Image im;
XBell(disp, 0); if (! opt.silent) XBell(disp, 0);
im = im =
gib_imlib_create_image_from_drawable(root, 0, 0, 0, scr->width, imlib_create_image_from_drawable(0, 0, 0, scr->width,
scr->height, 1); scr->height, 1);
if (opt.pointer == 1)
scrot_grab_mouse_pointer(im, 0, 0);
return im; return im;
} }
void void
scrot_exec_app(Imlib_Image image, struct tm *tm, scrot_exec_app(Imlib_Image image, struct tm *tm,
char *filename_im, char *filename_thumb) char *filename_im, char *filename_thumb)
{ {
char *execstr; char *execstr;
int ret;
execstr = im_printf(opt.exec, tm, filename_im, filename_thumb, image); execstr = im_printf(opt.exec, tm, filename_im, filename_thumb, image);
system(execstr);
errno = 0;
ret = system(execstr);
if (ret == -1) {
fprintf(stderr, "The child process could not be created: %s\n", strerror(err
no));
} else if (WEXITSTATUS(ret) == 127) {
fprintf(stderr, "scrot could not execute the command: %s.\n", execstr);
}
exit(0); exit(0);
} }
Imlib_Image Imlib_Image
scrot_grab_focused(void)
{
Imlib_Image im = NULL;
int rx = 0, ry = 0, rw = 0, rh = 0;
Window target = None;
int ignored;
scrot_do_delay();
XGetInputFocus(disp, &target, &ignored);
if (!scrot_get_geometry(target, &rx, &ry, &rw, &rh)) return NULL;
scrot_nice_clip(&rx, &ry, &rw, &rh);
im = imlib_create_image_from_drawable(0, rx, ry, rw, rh, 1);
if (opt.pointer == 1)
scrot_grab_mouse_pointer(im, rx, ry);
return im;
}
Imlib_Image
scrot_sel_and_grab_image(void) scrot_sel_and_grab_image(void)
{ {
Imlib_Image im = NULL; Imlib_Image im = NULL;
static int xfd = 0; static int xfd = 0;
static int fdsize = 0; static int fdsize = 0;
XEvent ev; XEvent ev;
fd_set fdset; fd_set fdset;
int count = 0, done = 0; int count = 0, done = 0;
int rx = 0, ry = 0, rw = 0, rh = 0, btn_pressed = 0; int rx = 0, ry = 0, rw = 0, rh = 0, btn_pressed = 0;
int rect_x = 0, rect_y = 0, rect_w = 0, rect_h = 0;
Cursor cursor, cursor2;
Window target = None; Window target = None;
GC gc; Status ret;
XGCValues gcval;
scrot_selection_create();
xfd = ConnectionNumber(disp); xfd = ConnectionNumber(disp);
fdsize = xfd + 1; fdsize = xfd + 1;
cursor = XCreateFontCursor(disp, XC_left_ptr); ret = XGrabKeyboard(disp, root, False, GrabModeAsync, GrabModeAsync, CurrentTi
cursor2 = XCreateFontCursor(disp, XC_lr_angle); me);
if (ret == AlreadyGrabbed) {
gcval.foreground = XWhitePixel(disp, 0); int attempts = 20;
gcval.function = GXxor; struct timespec delay = {0, 50 * 1000L * 1000L};
gcval.background = XBlackPixel(disp, 0); do {
gcval.plane_mask = gcval.background ^ gcval.foreground; nanosleep(&delay, NULL);
gcval.subwindow_mode = IncludeInferiors; ret = XGrabKeyboard(disp, root, False, GrabModeAsync, GrabModeAsync, Curre
ntTime);
gc = } while (--attempts > 0 && ret == AlreadyGrabbed);
XCreateGC(disp, root, }
GCFunction | GCForeground | GCBackground | GCSubwindowMode, if (ret != GrabSuccess) {
&gcval); fprintf(stderr, "failed to grab keyboard\n");
scrot_selection_destroy();
if ((XGrabPointer exit(EXIT_FAILURE);
(disp, root, False, }
ButtonMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync,
GrabModeAsync, root, cursor, CurrentTime) != GrabSuccess))
gib_eprintf("couldn't grab pointer:");
if ((XGrabKeyboard
(disp, root, False, GrabModeAsync, GrabModeAsync,
CurrentTime) != GrabSuccess))
gib_eprintf("couldn't grab keyboard:");
while (1) { while (1) {
/* handle events here */ /* handle events here */
while (!done && XPending(disp)) { while (!done && XPending(disp)) {
XNextEvent(disp, &ev); XNextEvent(disp, &ev);
switch (ev.type) { switch (ev.type) {
case MotionNotify: case MotionNotify:
if (btn_pressed) { if (btn_pressed) {
if (rect_w) { scrot_selection_motion_draw(rx, ry, ev.xbutton.x, ev.xbutton.y);
/* re-draw the last rect to clear it */
XDrawRectangle(disp, root, gc, rect_x, rect_y, rect_w, rect_h);
} else {
/* Change the cursor to show we're selecting a region */
XChangeActivePointerGrab(disp,
ButtonMotionMask | ButtonReleaseMask,
cursor2, CurrentTime);
}
rect_x = rx;
rect_y = ry;
rect_w = ev.xmotion.x - rect_x;
rect_h = ev.xmotion.y - rect_y;
if (rect_w < 0) {
rect_x += rect_w;
rect_w = 0 - rect_w;
}
if (rect_h < 0) {
rect_y += rect_h;
rect_h = 0 - rect_h;
}
/* draw rectangle */
XDrawRectangle(disp, root, gc, rect_x, rect_y, rect_w, rect_h);
XFlush(disp);
} }
break; break;
case ButtonPress: case ButtonPress:
btn_pressed = 1; btn_pressed = 1;
rx = ev.xbutton.x; rx = ev.xbutton.x;
ry = ev.xbutton.y; ry = ev.xbutton.y;
target = target = scrot_get_window(disp, ev.xbutton.subwindow, ev.xbutton.x, ev
scrot_get_window(disp, ev.xbutton.subwindow, ev.xbutton.x, .xbutton.y);
ev.xbutton.y);
if (target == None) if (target == None)
target = root; target = root;
break; break;
case ButtonRelease: case ButtonRelease:
done = 1; done = 1;
break; break;
case KeyPress: case KeyPress:
fprintf(stderr, "Key was pressed, aborting shot\n");
done = 2; if (!btn_pressed) {
key_abort_shot:
fprintf(stderr, "Key was pressed, aborting shot\n");
done = 2;
break;
}
KeySym *keysym = NULL;
int keycode; /*dummy*/
keysym = XGetKeyboardMapping(disp, ev.xkey.keycode, 1, &keycode);
if (keysym == NULL) break;
switch (*keysym) {
case XK_Right:
if (++rx > scr->width) rx = scr->width;
break;
case XK_Left:
if (--rx < 0 ) rx = 0;
break;
case XK_Down:
if (++ry > scr->height) ry = scr->height;
break;
case XK_Up:
if (--ry < 0 ) ry = 0;
break;
default:
goto key_abort_shot;
}
XFree(keysym);
scrot_selection_motion_draw(rx, ry, ev.xbutton.x, ev.xbutton.y);
break; break;
case KeyRelease: case KeyRelease:
/* ignore */ /* ignore */
break; break;
default: default:
break; break;
} }
} }
if (done) if (done)
break; break;
/* now block some */ /* now block some */
FD_ZERO(&fdset); FD_ZERO(&fdset);
FD_SET(xfd, &fdset); FD_SET(xfd, &fdset);
errno = 0; errno = 0;
count = select(fdsize, &fdset, NULL, NULL, NULL); count = select(fdsize, &fdset, NULL, NULL, NULL);
if ((count < 0) if ((count < 0)
&& ((errno == ENOMEM) || (errno == EINVAL) || (errno == EBADF))) && ((errno == ENOMEM) || (errno == EINVAL) || (errno == EBADF))) {
gib_eprintf("Connection to X display lost"); fprintf(stderr, "Connection to X display lost\n");
} scrot_selection_destroy();
if (rect_w) { exit(EXIT_FAILURE);
XDrawRectangle(disp, root, gc, rect_x, rect_y, rect_w, rect_h); }
XFlush(disp);
} }
XUngrabPointer(disp, CurrentTime); scrot_selection_draw();
XUngrabKeyboard(disp, CurrentTime); XUngrabKeyboard(disp, CurrentTime);
XFreeCursor(disp, cursor);
XFreeGC(disp, gc); bool const isAreaSelect = (bool)(scrot_selection_get_rect()->w > 5);
XSync(disp, True);
scrot_selection_destroy();
if (done < 2) { if (done < 2) {
scrot_do_delay(); scrot_do_delay();
if (rect_w > 5) { if (isAreaSelect) {
/* if a rect has been drawn, it's an area selection */ /* if a rect has been drawn, it's an area selection */
rw = ev.xbutton.x - rx; rw = ev.xbutton.x - rx;
rh = ev.xbutton.y - ry; rh = ev.xbutton.y - ry;
if ((ev.xbutton.x + 1) == WidthOfScreen(scr)) {
++rw;
}
if ((ev.xbutton.y + 1) == HeightOfScreen(scr)) {
++rh;
}
if (rw < 0) { if (rw < 0) {
rx += rw; rx += rw;
rw = 0 - rw; rw = 0 - rw;
} }
if (rh < 0) { if (rh < 0) {
ry += rh; ry += rh;
rh = 0 - rh; rh = 0 - rh;
} }
} else {
Window child;
XWindowAttributes attr;
int stat;
// Not record pointer if there is a selection area because it is busy on t
hat,
// unless the delay option is used
if (opt.delay == 0) {
opt.pointer = 0;
}
} else {
/* else it's a window click */ /* else it's a window click */
/* get geometry of window and use that */ if (!scrot_get_geometry(target, &rx, &ry, &rw, &rh)) return NULL;
/* get windowmanager frame of window */ }
if (target != root) { scrot_nice_clip(&rx, &ry, &rw, &rh);
unsigned int d, x;
int status; if (! opt.silent) XBell(disp, 0);
im = imlib_create_image_from_drawable(0, rx, ry, rw, rh, 1);
status = XGetGeometry(disp, target, &root, &x, &x, &d, &d, &d, &d);
if (status != 0) { if (opt.pointer == 1)
Window rt, *children, parent; scrot_grab_mouse_pointer(im, rx, ry);
}
for (;;) { return im;
/* Find window manager frame. */ }
status = XQueryTree(disp, target, &rt, &parent, &children, &d);
if (status && (children != None)) Imlib_Image
XFree((char *) children); scrot_grab_autoselect(void)
if (!status || (parent == None) || (parent == rt)) {
break; Imlib_Image im = NULL;
target = parent; int rx = opt.autoselect_x, ry = opt.autoselect_y, rw = opt.autoselect_w, rh =
} opt.autoselect_h;
/* Get client window. */
if (!opt.border) scrot_do_delay();
target = scrot_get_client_window(disp, target); scrot_nice_clip(&rx, &ry, &rw, &rh);
XRaiseWindow(disp, target); im = imlib_create_image_from_drawable(0, rx, ry, rw, rh, 1);
if (opt.pointer == 1)
scrot_grab_mouse_pointer(im, rx, ry);
return im;
}
/* clip rectangle nicely */
void
scrot_nice_clip(int *rx,
int *ry,
int *rw,
int *rh)
{
if (*rx < 0) {
*rw += *rx;
*rx = 0;
}
if (*ry < 0) {
*rh += *ry;
*ry = 0;
}
if ((*rx + *rw) > scr->width)
*rw = scr->width - *rx;
if ((*ry + *rh) > scr->height)
*rh = scr->height - *ry;
}
static Bool scrot_xevent_visibility(Display *dpy, XEvent *ev, XPointer arg)
{
(void) dpy; // unused
Window *win = (Window*)arg;
return (ev->xvisibility.window == *win);
}
/* get geometry of window and use that */
int
scrot_get_geometry(Window target,
int *rx,
int *ry,
int *rw,
int *rh)
{
Window child;
XWindowAttributes attr;
int stat, frames = 0;
/* get windowmanager frame of window */
if (target != root) {
unsigned int d;
int x;
int status;
status = XGetGeometry(disp, target, &root, &x, &x, &d, &d, &d, &d);
if (status != 0) {
Window rt, *children, parent;
XEvent ev;
for (;;) {
/* Find window manager frame. */
status = XQueryTree(disp, target, &rt, &parent, &children, &d);
if (status && (children != None)) {
XFree((char *) children);
} }
if (!status || (parent == None) || (parent == rt)) {
break;
}
target = parent;
++frames;
}
/* Get client window. */
if (!opt.border) {
target = scrot_get_client_window(disp, target);
} }
stat = XGetWindowAttributes(disp, target, &attr); XRaiseWindow(disp, target);
if ((stat == False) || (attr.map_state != IsViewable))
return NULL;
rw = attr.width;
rh = attr.height;
XTranslateCoordinates(disp, target, root, 0, 0, &rx, &ry, &child);
}
/* clip rectangle nicely */
if (rx < 0) {
rw += rx;
rx = 0;
}
if (ry < 0) {
rh += ry;
ry = 0;
}
if ((rx + rw) > scr->width)
rw = scr->width - rx;
if ((ry + rh) > scr->height)
rh = scr->height - ry;
XBell(disp, 0); /* Give the WM time to update the hidden area of the window.
im = gib_imlib_create_image_from_drawable(root, 0, rx, ry, rw, rh, 1); Some windows never send the event, a time limit is placed.
*/
XSelectInput(disp, target, FocusChangeMask);
for(short i = 0; i < 30; ++i) {
if (XCheckIfEvent(disp, &ev, &scrot_xevent_visibility, (XPointer)&target
) == True) {
break;
}
usleep(2000);
}
}
} }
return im; stat = XGetWindowAttributes(disp, target, &attr);
if ((stat == False) || (attr.map_state != IsViewable))
return 0;
*rw = attr.width;
*rh = attr.height;
XTranslateCoordinates(disp, target, root, 0, 0, rx, ry, &child);
/* Special case when the TWM emulates the border directly on the window. */
if (opt.border == 1 && frames < 2 && attr.border_width > 0) {
*rw += attr.border_width * 2;
*rh += attr.border_width * 2;
*rx -= attr.border_width;
*ry -= attr.border_width;
}
return 1;
} }
Window Window
scrot_get_window(Display * display, scrot_get_window(Display * display,
Window window, Window window,
int x, int x,
int y) int y)
{ {
Window source, target; Window source, target;
skipping to change at line 417 skipping to change at line 738
Imlib_Image im) Imlib_Image im)
{ {
char *c; char *c;
char buf[20]; char buf[20];
char ret[4096]; char ret[4096];
char strf[4096]; char strf[4096];
char *tmp; char *tmp;
struct stat st; struct stat st;
ret[0] = '\0'; ret[0] = '\0';
strftime(strf, 4095, str, tm);
if (strftime(strf, 4095, str, tm) == 0) {
fprintf(stderr, "strftime returned 0\n");
exit(EXIT_FAILURE);
}
imlib_context_set_image(im);
for (c = strf; *c != '\0'; c++) { for (c = strf; *c != '\0'; c++) {
if (*c == '$') { if (*c == '$') {
c++; c++;
switch (*c) { switch (*c) {
case 'a':
gethostname(buf, sizeof(buf));
strcat(ret, buf);
break;
case 'f': case 'f':
if (filename_im) if (filename_im)
strcat(ret, filename_im); strcat(ret, filename_im);
break; break;
case 'm': /* t was allready taken, so m as in mini */ case 'm': /* t was already taken, so m as in mini */
if (filename_thumb) if (filename_thumb)
strcat(ret, filename_thumb); strcat(ret, filename_thumb);
break; break;
case 'n': case 'n':
if (filename_im) { if (filename_im) {
tmp = strrchr(filename_im, '/'); tmp = strrchr(filename_im, '/');
if (tmp) if (tmp)
strcat(ret, tmp + 1); strcat(ret, tmp + 1);
else else
strcat(ret, filename_im); strcat(ret, filename_im);
} }
break; break;
case 'w': case 'w':
snprintf(buf, sizeof(buf), "%d", gib_imlib_image_get_width(im)); snprintf(buf, sizeof(buf), "%d", imlib_image_get_width());
strcat(ret, buf); strcat(ret, buf);
break; break;
case 'h': case 'h':
snprintf(buf, sizeof(buf), "%d", gib_imlib_image_get_height(im)); snprintf(buf, sizeof(buf), "%d", imlib_image_get_height());
strcat(ret, buf); strcat(ret, buf);
break; break;
case 's': case 's':
if (filename_im) { if (filename_im) {
if (!stat(filename_im, &st)) { if (!stat(filename_im, &st)) {
int size; int size;
size = st.st_size; size = st.st_size;
snprintf(buf, sizeof(buf), "%d", size); snprintf(buf, sizeof(buf), "%d", size);
strcat(ret, buf); strcat(ret, buf);
} else } else
strcat(ret, "[err]"); strcat(ret, "[err]");
} }
break; break;
case 'p': case 'p':
snprintf(buf, sizeof(buf), "%d", snprintf(buf, sizeof(buf), "%d",
gib_imlib_image_get_width(im) * imlib_image_get_width() *
gib_imlib_image_get_height(im)); imlib_image_get_height());
strcat(ret, buf); strcat(ret, buf);
break; break;
case 't': case 't':
strcat(ret, gib_imlib_image_format(im)); tmp = imlib_image_format();
if (tmp) {
strcat(ret, tmp);
}
break; break;
case '$': case '$':
strcat(ret, "$"); strcat(ret, "$");
break; break;
default: default:
strncat(ret, c, 1); strncat(ret, c, 1);
break; break;
} }
} else if (*c == '\\') { } else if (*c == '\\') {
c++; c++;
switch (*c) { switch (*c) {
case 'n': case 'n':
if (filename_im) if (filename_im)
strcat(ret, "\n"); strcat(ret, "\n");
break; break;
default: default:
strncat(ret, c, 1); strncat(ret, c, 1);
break; break;
} }
} else } else {
strncat(ret, c, 1); const size_t len = strlen(ret);
ret[len] = *c;
ret[len + 1] = '\0';
}
} }
return gib_estrdup(ret); return strdup(ret);
} }
Window Window
scrot_get_client_window(Display * display, scrot_get_client_window(Display * display,
Window target) Window target)
{ {
Atom state; Atom state;
Atom type = None; Atom type = None;
int format, status; int format, status;
unsigned char *data; unsigned char *data;
skipping to change at line 553 skipping to change at line 889
child = children[i]; child = children[i];
} }
for (i = 0; (i < number_children) && (child == None); i++) for (i = 0; (i < number_children) && (child == None); i++)
child = scrot_find_window_by_property(display, children[i], property); child = scrot_find_window_by_property(display, children[i], property);
if (children != None) if (children != None)
XFree(children); XFree(children);
return (child); return (child);
} }
Imlib_Image Imlib_Image
scrot_grab_stack_windows(void)
{
if (XGetSelectionOwner(disp, XInternAtom(disp, "_NET_WM_CM_S0", False)) == N
one) {
fprintf(stderr, "Composite Manager is not running, required to use this
option.\n");
exit(EXIT_FAILURE);
}
unsigned long nitems_return;
unsigned long bytes_after_return;
unsigned char *prop_return;
long long_offset = 0L;
long long_length = ~0L;
Bool delete = False;
int actual_format_return;
Atom actual_type_return;
Scrot_Imlib_List *list_images = NULL;
Imlib_Image im = NULL;
XImage *ximage = NULL;
XWindowAttributes attr;
unsigned long i = 0;
#define EWMH_CLIENT_LIST "_NET_CLIENT_LIST" // spec EWMH
Atom atom_prop = XInternAtom(disp, EWMH_CLIENT_LIST, False);
Atom atom_type = AnyPropertyType;
int result = XGetWindowProperty(disp, root, atom_prop, long_offset, long_len
gth,
delete, atom_type, &actual_type_return, &actual_
format_return,
&nitems_return, &bytes_after_return, &prop_retur
n);
if (result != Success || nitems_return == 0) {
fprintf(stderr, "Failed XGetWindowProperty: " EWMH_CLIENT_LIST "\n");
exit(EXIT_FAILURE);
}
XCompositeRedirectSubwindows(disp, root, CompositeRedirectAutomatic);
for (i = 0; i < nitems_return; i++) {
Window win = *((Window*)prop_return + i);
if (0 == XGetWindowAttributes(disp, win, &attr)) {
fprintf(stderr, "Failed XGetWindowAttributes\n");
exit(EXIT_FAILURE);
}
/* Only visible windows */
if (attr.map_state != IsViewable) {
continue;
}
if (!scrot_match_window_class_name(win)) {
continue;
}
ximage = XGetImage(disp, win, 0, 0, attr.width, attr.height, AllPlanes,
ZPixmap);
if (ximage == NULL) {
fprintf(stderr, "Failed XGetImage: Window id 0x%lx.\n", win);
exit(EXIT_FAILURE);
}
im = imlib_create_image_from_ximage(ximage, NULL, attr.x, attr.y, attr.w
idth, attr.height, 1);
XFree(ximage);
list_images = append_to_scrot_imlib(list_images, im);
}
return stalk_image_concat(list_images);
}
Imlib_Image
scrot_grab_shot_multi(void) scrot_grab_shot_multi(void)
{ {
int screens; int screens;
int i; int i;
char *dispstr, *subdisp; char *dispstr, *subdisp;
char newdisp[255]; char newdisp[255];
gib_list *images = NULL; Scrot_Imlib_List *images = NULL;
Imlib_Image ret = NULL; Imlib_Image ret = NULL;
screens = ScreenCount(disp); screens = ScreenCount(disp);
if (screens < 2) if (screens < 2)
return scrot_grab_shot(); return scrot_grab_shot();
dispstr = DisplayString(disp); subdisp = strdup(DisplayString(disp));
subdisp = gib_estrdup(DisplayString(disp));
for (i = 0; i < screens; i++) { for (i = 0; i < screens; i++) {
dispstr = strchr(subdisp, ':'); dispstr = strchr(subdisp, ':');
if (dispstr) { if (dispstr) {
dispstr = strchr(dispstr, '.'); dispstr = strchr(dispstr, '.');
if (NULL != dispstr) if (NULL != dispstr)
*dispstr = '\0'; *dispstr = '\0';
} }
snprintf(newdisp, sizeof(newdisp), "%s.%d", subdisp, i); snprintf(newdisp, sizeof(newdisp), "%s.%d", subdisp, i);
init_x_and_imlib(newdisp, i); init_x_and_imlib(newdisp, i);
ret = ret =
gib_imlib_create_image_from_drawable(root, 0, 0, 0, scr->width, imlib_create_image_from_drawable(0, 0, 0, scr->width,
scr->height, 1); scr->height, 1);
images = gib_list_add_end(images, ret); images = append_to_scrot_imlib(images, ret);
} }
free(subdisp); free(subdisp);
ret = stalk_image_concat(images); ret = stalk_image_concat(images);
return ret; return ret;
} }
Imlib_Image Imlib_Image
stalk_image_concat(gib_list * images) stalk_image_concat(Scrot_Imlib_List * images)
{ {
int tot_w = 0, max_h = 0, w, h; int tot_w = 0, max_h = 0, w, h;
int x = 0; int x = 0;
gib_list *l, *item; Scrot_Imlib_List *l, *item;
Imlib_Image ret, im; Imlib_Image ret, im;
if (gib_list_length(images) == 0) if (is_scrot_imlib_list_empty(images))
return NULL; return NULL;
l = images; l = images;
while (l) { while (l) {
im = (Imlib_Image) l->data; im = (Imlib_Image) l->data;
h = gib_imlib_image_get_height(im); imlib_context_set_image(im);
w = gib_imlib_image_get_width(im); h = imlib_image_get_height();
w = imlib_image_get_width();
if (h > max_h) if (h > max_h)
max_h = h; max_h = h;
tot_w += w; tot_w += w;
l = l->next; l = l->next;
} }
ret = imlib_create_image(tot_w, max_h); ret = imlib_create_image(tot_w, max_h);
gib_imlib_image_fill_rectangle(ret, 0, 0, tot_w, max_h, 255, 0, 0, 0); imlib_context_set_image(ret);
imlib_context_set_color(255, 0, 0, 0);
imlib_image_fill_rectangle(0, 0, tot_w, max_h);
l = images; l = images;
while (l) { while (l) {
im = (Imlib_Image) l->data; im = (Imlib_Image) l->data;
item = l; item = l;
l = l->next; l = l->next;
h = gib_imlib_image_get_height(im); imlib_context_set_image(im);
w = gib_imlib_image_get_width(im); h = imlib_image_get_height();
gib_imlib_blend_image_onto_image(ret, im, 0, 0, 0, w, h, x, 0, w, h, 1, 0, w = imlib_image_get_width();
0); imlib_context_set_image(ret);
imlib_context_set_anti_alias(0);
imlib_context_set_dither(1);
imlib_context_set_blend(0);
imlib_context_set_angle(0);
imlib_blend_image_onto_image(im, 0, 0, 0, w, h, x, 0, w, h);
x += w; x += w;
gib_imlib_free_image_and_decache(im); imlib_context_set_image(im);
imlib_free_image_and_decache();
free(item); free(item);
} }
return ret; return ret;
} }
 End of changes. 64 change blocks. 
172 lines changed or deleted 607 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)