"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/scrot_selection.c" between
scrot-1.7.tar.bz2 and scrot-1.8.tar.gz

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

scrot_selection.c  (scrot-1.7.tar.bz2):scrot_selection.c  (scrot-1.8)
/* scrot_selection.c /* scrot_selection.c
Copyright 2020-2021 Daniel T. Borelli <danieltborelli@gmail.com> Copyright 2020-2022 Daniel T. Borelli <danieltborelli@gmail.com>
Copyright 2021 Martin C <martincation@protonmail.com> Copyright 2021-2023 Guilherme Janczak <guilherme.janczak@yandex.com>
Copyright 2021 Peter Wu <peterwu@hotmail.com> Copyright 2021 Martin C <martincation@protonmail.com>
Copyright 2021 Wilson Smith <01wsmith+gh@gmail.com> Copyright 2021 Peter Wu <peterwu@hotmail.com>
Copyright 2021 Wilson Smith <01wsmith+gh@gmail.com>
Copyright 2022 NRK <nrk@disroot.org>
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 31 skipping to change at line 33
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.
*/ */
/* /*
This file is part of the scrot project. This file is part of the scrot project.
Part of the code comes from the main.c file and maintains its authorship. Part of the code comes from the scrot.c file and maintains its authorship.
*/ */
#include <sys/select.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <Imlib2.h>
#include <X11/Xlib.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>
#include "imlib.h"
#include "options.h"
#include "scrot.h" #include "scrot.h"
#include "scrot_selection.h"
#include "selection_classic.h" #include "selection_classic.h"
#include "selection_edge.h" #include "selection_edge.h"
struct Selection** selectionGet(void) struct Selection **selectionGet(void)
{ {
static struct Selection* sel = NULL; static struct Selection *sel = NULL;
return &sel; return &sel;
} }
static void selectionAllocate(void) static void selectionAllocate(void)
{ {
struct Selection** sel = selectionGet(); struct Selection **sel = selectionGet();
*sel = calloc(1, sizeof(**sel)); *sel = calloc(1, sizeof(**sel));
} }
static void selectionDeallocate(void) static void selectionDeallocate(void)
{ {
struct Selection** sel = selectionGet(); struct Selection **sel = selectionGet();
free(*sel); free(*sel);
*sel = NULL; *sel = NULL;
} }
static void createCursors(void) static void createCursors(void)
{ {
struct Selection* const sel = *selectionGet(); struct Selection *const sel = *selectionGet();
assert(sel != NULL); assert(sel != NULL);
if (opt.selection.mode == SELECTION_MODE_CAPTURE) if (opt.selection.mode == SELECTION_MODE_CAPTURE)
sel->curCross = XCreateFontCursor(disp, XC_cross); sel->curCross = XCreateFontCursor(disp, XC_cross);
else if (opt.selection.mode == SELECTION_MODE_HIDE) else if (opt.selection.mode == SELECTION_MODE_HIDE)
sel->curCross = XCreateFontCursor(disp, XC_spraycan); sel->curCross = XCreateFontCursor(disp, XC_spraycan);
else if (opt.selection.mode == SELECTION_MODE_BLUR) else if (opt.selection.mode == SELECTION_MODE_BLUR)
sel->curCross = XCreateFontCursor(disp, XC_box_spiral); sel->curCross = XCreateFontCursor(disp, XC_box_spiral);
else // SELECTION_MODE_HOLE else // SELECTION_MODE_HOLE
sel->curCross = XCreateFontCursor(disp, XC_target); sel->curCross = XCreateFontCursor(disp, XC_target);
sel->curAngleNE = XCreateFontCursor(disp, XC_ur_angle); sel->curAngleNE = XCreateFontCursor(disp, XC_ur_angle);
sel->curAngleNW = XCreateFontCursor(disp, XC_ul_angle); sel->curAngleNW = XCreateFontCursor(disp, XC_ul_angle);
sel->curAngleSE = XCreateFontCursor(disp, XC_lr_angle); sel->curAngleSE = XCreateFontCursor(disp, XC_lr_angle);
sel->curAngleSW = XCreateFontCursor(disp, XC_ll_angle); sel->curAngleSW = XCreateFontCursor(disp, XC_ll_angle);
} }
static void freeCursors(void) static void freeCursors(void)
{ {
struct Selection* const sel = *selectionGet(); struct Selection *const sel = *selectionGet();
assert(sel != NULL); assert(sel != NULL);
XFreeCursor(disp, sel->curCross); XFreeCursor(disp, sel->curCross);
XFreeCursor(disp, sel->curAngleNE); XFreeCursor(disp, sel->curAngleNE);
XFreeCursor(disp, sel->curAngleNW); XFreeCursor(disp, sel->curAngleNW);
XFreeCursor(disp, sel->curAngleSE); XFreeCursor(disp, sel->curAngleSE);
XFreeCursor(disp, sel->curAngleSW); XFreeCursor(disp, sel->curAngleSW);
} }
void selectionCalculateRect(int x0, int y0, int x1, int y1) void selectionCalculateRect(int x0, int y0, int x1, int y1)
{ {
struct SelectionRect* const rect = scrotSelectionGetRect(); struct SelectionRect *const rect = scrotSelectionGetRect();
rect->x = x0; rect->x = x0;
rect->y = y0; rect->y = y0;
rect->w = x1 - x0; rect->w = x1 - x0;
rect->h = y1 - y0; rect->h = y1 - y0;
if (rect->w == 0) if (rect->w == 0)
rect->w++; rect->w++;
if (rect->h == 0) if (rect->h == 0)
skipping to change at line 120 skipping to change at line 140
if (rect->h < 0) { if (rect->h < 0) {
rect->y += rect->h; rect->y += rect->h;
rect->h = 0 - rect->h; rect->h = 0 - rect->h;
} }
} }
void scrotSelectionCreate(void) void scrotSelectionCreate(void)
{ {
selectionAllocate(); selectionAllocate();
struct Selection* const sel = *selectionGet(); struct Selection *const sel = *selectionGet();
assert(sel != NULL); assert(sel != NULL);
createCursors(); createCursors();
if (!strncmp(opt.lineMode, LINE_MODE_S_CLASSIC, LINE_MODE_L_CLASSIC)) { if (!strncmp(opt.lineMode, LINE_MODE_S_CLASSIC, LINE_MODE_L_CLASSIC)) {
sel->create = selectionClassicCreate; sel->create = selectionClassicCreate;
sel->draw = selectionClassicDraw; sel->draw = selectionClassicDraw;
sel->motionDraw = selectionClassicMotionDraw; sel->motionDraw = selectionClassicMotionDraw;
sel->destroy = selectionClassicDestroy; sel->destroy = selectionClassicDestroy;
skipping to change at line 155 skipping to change at line 175
if ((XGrabPointer(disp, root, False, EVENT_MASK, GrabModeAsync, if ((XGrabPointer(disp, root, False, EVENT_MASK, GrabModeAsync,
GrabModeAsync, root, sel->curCross, CurrentTime) GrabModeAsync, root, sel->curCross, CurrentTime)
!= GrabSuccess)) { != GrabSuccess)) {
scrotSelectionDestroy(); scrotSelectionDestroy();
errx(EXIT_FAILURE, "couldn't grab pointer"); errx(EXIT_FAILURE, "couldn't grab pointer");
} }
} }
void scrotSelectionDestroy(void) void scrotSelectionDestroy(void)
{ {
struct Selection* const sel = *selectionGet(); struct Selection *const sel = *selectionGet();
XUngrabPointer(disp, CurrentTime); XUngrabPointer(disp, CurrentTime);
freeCursors(); freeCursors();
XSync(disp, True); XSync(disp, True);
sel->destroy(); sel->destroy();
selectionDeallocate(); selectionDeallocate();
} }
void scrotSelectionDraw(void) void scrotSelectionDraw(void)
{ {
struct Selection const* const sel = *selectionGet(); const struct Selection *const sel = *selectionGet();
sel->draw(); sel->draw();
} }
void scrotSelectionMotionDraw(int x0, int y0, int x1, int y1) void scrotSelectionMotionDraw(int x0, int y0, int x1, int y1)
{ {
struct Selection const* const sel = *selectionGet(); const struct Selection *const sel = *selectionGet();
unsigned int const EVENT_MASK = ButtonMotionMask | ButtonReleaseMask; const unsigned int EVENT_MASK = ButtonMotionMask | ButtonReleaseMask;
Cursor cursor = None; Cursor cursor = None;
if (x1 > x0 && y1 > y0) if (x1 > x0 && y1 > y0)
cursor = sel->curAngleSE; cursor = sel->curAngleSE;
else if (x1 > x0) else if (x1 > x0)
cursor = sel->curAngleNE; cursor = sel->curAngleNE;
else if (y1 > y0) else if (y1 > y0)
cursor = sel->curAngleSW; cursor = sel->curAngleSW;
else else
cursor = sel->curAngleNW; cursor = sel->curAngleNW;
XChangeActivePointerGrab(disp, EVENT_MASK, cursor, CurrentTime); XChangeActivePointerGrab(disp, EVENT_MASK, cursor, CurrentTime);
sel->motionDraw(x0, y0, x1, y1); sel->motionDraw(x0, y0, x1, y1);
} }
struct SelectionRect* scrotSelectionGetRect(void) struct SelectionRect *scrotSelectionGetRect(void)
{ {
return &(*selectionGet())->rect; return &(*selectionGet())->rect;
} }
Status scrotSelectionCreateNamedColor(char const* nameColor, XColor* color) Status scrotSelectionCreateNamedColor(const char *nameColor, XColor *color)
{ {
assert(nameColor != NULL); assert(nameColor != NULL);
assert(color != NULL); assert(color != NULL);
return XAllocNamedColor(disp, XDefaultColormap(disp, DefaultScreen(disp)), return XAllocNamedColor(disp, XDefaultColormap(disp, DefaultScreen(disp)),
nameColor, color, &(XColor) {}); nameColor, color, &(XColor){0});
} }
void scrotSelectionGetLineColor(XColor* color) void scrotSelectionGetLineColor(XColor *color)
{ {
scrotSelectionSetDefaultColorLine(); scrotSelectionSetDefaultColorLine();
Status const ret = scrotSelectionCreateNamedColor(opt.lineColor, color); const Status ret = scrotSelectionCreateNamedColor(opt.lineColor, color);
if (!ret) { if (!ret) {
scrotSelectionDestroy(); scrotSelectionDestroy();
errx(EXIT_FAILURE, "Error allocate color:%s", strerror(BadColor)); errx(EXIT_FAILURE, "Error allocate color:%s", strerror(BadColor));
} }
} }
void scrotSelectionSetDefaultColorLine(void) void scrotSelectionSetDefaultColorLine(void)
{ {
if (!opt.lineColor) if (!opt.lineColor)
opt.lineColor = "gray"; opt.lineColor = "gray";
} }
bool scrotSelectionGetUserSel(struct SelectionRect* selectionRect) bool scrotSelectionGetUserSel(struct SelectionRect *selectionRect)
{ {
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, isButtonPressed = 0; int rx = 0, ry = 0, rw = 0, rh = 0, isButtonPressed = 0;
Window target = None; Window target = None;
Status ret; Status ret;
skipping to change at line 271 skipping to change at line 291
ry = ev.xbutton.y; ry = ev.xbutton.y;
target = scrotGetWindow(disp, ev.xbutton.subwindow, ev.xbutton.x , ev.xbutton.y); target = scrotGetWindow(disp, ev.xbutton.subwindow, ev.xbutton.x , 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:
{ {
KeySym* keysym = NULL; KeySym *keysym = NULL;
int keycode; /*dummy*/ int keycode; /*dummy*/
keysym = XGetKeyboardMapping(disp, ev.xkey.keycode, 1, &keycode) ; keysym = XGetKeyboardMapping(disp, ev.xkey.keycode, 1, &keycode) ;
if (!keysym) if (!keysym)
break; break;
if (!isButtonPressed) { if (!isButtonPressed) {
key_abort_shot: key_abort_shot:
if (!opt.ignoreKeyboard || *keysym == XK_Escape) { if (!opt.ignoreKeyboard || *keysym == XK_Escape) {
skipping to change at line 338 skipping to change at line 358
if ((count < 0) if ((count < 0)
&& ((errno == ENOMEM) || (errno == EINVAL) || (errno == EBADF))) { && ((errno == ENOMEM) || (errno == EINVAL) || (errno == EBADF))) {
scrotSelectionDestroy(); scrotSelectionDestroy();
errx(EXIT_FAILURE, "Connection to X display lost"); errx(EXIT_FAILURE, "Connection to X display lost");
} }
} }
scrotSelectionDraw(); scrotSelectionDraw();
XUngrabKeyboard(disp, CurrentTime); XUngrabKeyboard(disp, CurrentTime);
bool const isAreaSelect = (scrotSelectionGetRect()->w > 5); const bool isAreaSelect = (scrotSelectionGetRect()->w > 5);
scrotSelectionDestroy(); scrotSelectionDestroy();
if (done == 2) if (done == 2)
return false; return false;
if (isAreaSelect) { 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;
skipping to change at line 374 skipping to change at line 394
} }
// Not record pointer if there is a selection area because it is busy on that, // Not record pointer if there is a selection area because it is busy on that,
// unless the delay option is used. // unless the delay option is used.
if (opt.delay == 0) if (opt.delay == 0)
opt.pointer = 0; opt.pointer = 0;
} else { } else {
/* else it's a window click */ /* else it's a window click */
if (!scrotGetGeometry(target, &rx, &ry, &rw, &rh)) if (!scrotGetGeometry(target, &rx, &ry, &rw, &rh))
return false; return false;
clientWindow = target;
} }
scrotNiceClip(&rx, &ry, &rw, &rh); scrotNiceClip(&rx, &ry, &rw, &rh);
if (!opt.silent) if (!opt.silent)
XBell(disp, 0); XBell(disp, 0);
selectionRect->x = rx; selectionRect->x = rx;
selectionRect->y = ry; selectionRect->y = ry;
selectionRect->w = rw; selectionRect->w = rw;
selectionRect->h = rh; selectionRect->h = rh;
return true; return true;
} }
static void changeImageOpacity(Imlib_Image image, int const opacity) static void changeImageOpacity(Imlib_Image image, const int opacity)
{ {
#define PIXEL_ARGB(a, r, g, b) ((a) << 24) | ((r) << 16) | ((g) << 8) | (b)
#define PIXEL_A(argb) (((argb) >> 24) & 0xff)
#define PIXEL_R(argb) (((argb) >> 16) & 0xff)
#define PIXEL_G(argb) (((argb) >> 8) & 0xff)
#define PIXEL_B(argb) (((argb) ) & 0xff)
imlib_context_set_image(image); imlib_context_set_image(image);
int const w = imlib_image_get_width(); const int w = imlib_image_get_width();
int const h = imlib_image_get_height(); const int h = imlib_image_get_height();
DATA32* data = imlib_image_get_data(); uint32_t *data = imlib_image_get_data();
DATA32* end = data + (h * w); uint32_t *end = data + (h * w);
for (DATA32* pixel = data; pixel != end; ++pixel) { for (uint32_t *pixel = data; pixel != end; ++pixel) {
DATA8 const a = PIXEL_A(*pixel) * opacity / 255; const uint32_t a = (*pixel >> 24) * opacity / 255;
DATA8 const r = PIXEL_R(*pixel); *pixel = (a << 24) | (*pixel & 0x00FFFFFF);
DATA8 const g = PIXEL_G(*pixel);
DATA8 const b = PIXEL_B(*pixel);
*pixel = (DATA32)PIXEL_ARGB(a, r, g, b);
} }
imlib_image_put_back_data(data); imlib_image_put_back_data(data);
} }
static Imlib_Image loadImage(char const* const fileName, int const opacity) static Imlib_Image loadImage(const char *const fileName, const int opacity)
{ {
Imlib_Image image = imlib_load_image(fileName); Imlib_Image image = imlib_load_image(fileName);
if (!image) { if (!image) {
errx(EXIT_FAILURE, "option --select: Failed to load image:%s", errx(EXIT_FAILURE, "option --select: Failed to load image:%s",
fileName); fileName);
} }
imlib_context_set_image(image); imlib_context_set_image(image);
skipping to change at line 444 skipping to change at line 456
changeImageOpacity(image, opacity); changeImageOpacity(image, opacity);
return image; return image;
} }
Imlib_Image scrotSelectionSelectMode(void) Imlib_Image scrotSelectionSelectMode(void)
{ {
struct SelectionRect rect0, rect1; struct SelectionRect rect0, rect1;
unsigned int const oldMode = opt.selection.mode; const unsigned int oldMode = opt.selection.mode;
opt.selection.mode = SELECTION_MODE_CAPTURE; opt.selection.mode = SELECTION_MODE_CAPTURE;
if (!scrotSelectionGetUserSel(&rect0)) if (!scrotSelectionGetUserSel(&rect0))
return NULL; return NULL;
opt.selection.mode = oldMode; opt.selection.mode = oldMode;
if (opt.selection.mode & SELECTION_MODE_NOT_CAPTURE) if (opt.selection.mode & SELECTION_MODE_NOT_CAPTURE)
if (!scrotSelectionGetUserSel(&rect1)) if (!scrotSelectionGetUserSel(&rect1))
skipping to change at line 471 skipping to change at line 483
if (opt.pointer) if (opt.pointer)
scrotGrabMousePointer(capture, rect0.x, rect0.y); scrotGrabMousePointer(capture, rect0.x, rect0.y);
if (opt.selection.mode == SELECTION_MODE_CAPTURE) if (opt.selection.mode == SELECTION_MODE_CAPTURE)
return capture; return capture;
XColor color; XColor color;
scrotSelectionGetLineColor(&color); scrotSelectionGetLineColor(&color);
int const x = rect1.x - rect0.x; const int x = rect1.x - rect0.x;
int const y = rect1.y - rect0.y; const int y = rect1.y - rect0.y;
int const opacity = optionsParseRequireRange(opt.lineOpacity, const int opacity = opt.lineOpacity;
SELECTION_OPACITY_MIN, SELECTION_OPACITY_MAX);
imlib_context_set_image(capture); imlib_context_set_image(capture);
switch(opt.selection.mode) { switch(opt.selection.mode) {
case SELECTION_MODE_HOLE: case SELECTION_MODE_HOLE:
if (opacity > 0) { if (opacity > 0) {
Imlib_Image hole = imlib_clone_image(); Imlib_Image hole = imlib_clone_image();
imlib_context_set_color(color.red, color.green, color.blue, opacity) ; imlib_context_set_color(color.red, color.green, color.blue, opacity) ;
imlib_image_fill_rectangle(0, 0, rect0.w, rect0.h); imlib_image_fill_rectangle(0, 0, rect0.w, rect0.h);
imlib_blend_image_onto_image(hole, 0, x, y, rect1.w, rect1.h, x, y, rect1.w, rect1.h); imlib_blend_image_onto_image(hole, 0, x, y, rect1.w, rect1.h, x, y, rect1.w, rect1.h);
imlib_context_set_image(hole); imlib_context_set_image(hole);
imlib_free_image_and_decache(); imlib_free_image_and_decache();
} }
break; break;
case SELECTION_MODE_HIDE: case SELECTION_MODE_HIDE:
{ {
char* const fileName = opt.selection.paramStr; char *const fileName = opt.selection.paramStr;
if (fileName) { if (fileName) {
if (opacity > 0) { if (opacity > 0) {
Imlib_Image hide = loadImage(fileName, opacity); Imlib_Image hide = loadImage(fileName, opacity);
imlib_context_set_image(hide); imlib_context_set_image(hide);
int const w = imlib_image_get_width(); int const w = imlib_image_get_width();
int const h = imlib_image_get_height(); int const h = imlib_image_get_height();
imlib_context_set_image(capture); imlib_context_set_image(capture);
imlib_blend_image_onto_image(hide, 0, 0, 0, w, h, x, y, rect1.w, rect1.h); imlib_blend_image_onto_image(hide, 0, 0, 0, w, h, x, y, rect1.w, rect1.h);
imlib_context_set_image(hide); imlib_context_set_image(hide);
skipping to change at line 513 skipping to change at line 524
} }
free(fileName); free(fileName);
} else { } else {
imlib_context_set_color(color.red, color.green, color.blue, opacity) ; imlib_context_set_color(color.red, color.green, color.blue, opacity) ;
imlib_image_fill_rectangle(x, y, rect1.w, rect1.h); imlib_image_fill_rectangle(x, y, rect1.w, rect1.h);
} }
break; break;
} }
case SELECTION_MODE_BLUR: case SELECTION_MODE_BLUR:
{ {
int const amountBlur = opt.selection.paramNum; const int amountBlur = opt.selection.paramNum;
Imlib_Image blur = imlib_clone_image(); Imlib_Image blur = imlib_clone_image();
imlib_context_set_image(blur); imlib_context_set_image(blur);
imlib_image_blur(amountBlur); imlib_image_blur(amountBlur);
imlib_context_set_image(capture); imlib_context_set_image(capture);
imlib_blend_image_onto_image(blur, 0, x, y, rect1.w, rect1.h, x, y, rect 1.w, rect1.h); imlib_blend_image_onto_image(blur, 0, x, y, rect1.w, rect1.h, x, y, rect 1.w, rect1.h);
imlib_context_set_image(blur); imlib_context_set_image(blur);
imlib_free_image_and_decache(); imlib_free_image_and_decache();
break; break;
} }
default: default:
 End of changes. 34 change blocks. 
50 lines changed or deleted 61 lines changed or added

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