selection_edge.c (scrot-1.7.tar.bz2) | : | selection_edge.c (scrot-1.8) | ||
---|---|---|---|---|
/* scrot_selection_edge.c | /* scrot_selection_edge.c | |||
Copyright 2020-2021 Daniel T. Borelli <danieltborelli@gmail.com> | Copyright 2020-2021 Daniel T. Borelli <danieltborelli@gmail.com> | |||
Copyright 2021-2023 Guilherme Janczak <guilherme.janczak@yandex.com> | ||||
Copyright 2021 Peter Wu <peterwu@hotmail.com> | Copyright 2021 Peter Wu <peterwu@hotmail.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 | |||
skipping to change at line 29 | skipping to change at line 30 | |||
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 "scrot.h" | ||||
extern void selectionCalculateRect(int, int, int, int); | #include <stdlib.h> | |||
extern struct Selection** selectionGet(void); | #include <time.h> | |||
#include <X11/Xatom.h> | ||||
#include <X11/Xlib.h> | ||||
#include <X11/Xutil.h> | ||||
#include <X11/extensions/shape.h> | ||||
#include "imlib.h" | ||||
#include "options.h" | ||||
#include "scrot_selection.h" | ||||
#include "selection_edge.h" | ||||
struct SelectionEdge { | struct SelectionEdge { | |||
Window wndDraw; | Window wndDraw; | |||
XClassHint* classHint; | XClassHint *classHint; | |||
}; | }; | |||
static Bool xeventUnmap(Display* dpy, XEvent* ev, XPointer arg) | static void waitUnmapWindowNotify(void); | |||
{ | static Bool xeventUnmap(Display *, XEvent *, XPointer); | |||
(void)dpy; // unused | ||||
Window* win = (Window*)arg; | ||||
return (ev->xunmap.window == *win); | ||||
} | ||||
static void waitUnmapWindowNotify(void) | ||||
{ | ||||
struct Selection const* const sel = *selectionGet(); | ||||
struct SelectionEdge const* const pe = sel->edge; | ||||
XEvent ev; | ||||
XSelectInput(disp, pe->wndDraw, StructureNotifyMask); | ||||
XUnmapWindow(disp, pe->wndDraw); | ||||
struct timespec delay = {0, 80000000L}; // 80ms | ||||
for (short i = 0; i < 30; ++i) { | ||||
if (XCheckIfEvent(disp, &ev, &xeventUnmap, (XPointer) & (pe->wndDraw))) | ||||
break; | ||||
nanosleep(&delay, NULL); | ||||
} | ||||
} | ||||
void selectionEdgeCreate(void) | void selectionEdgeCreate(void) | |||
{ | { | |||
struct Selection* const sel = *selectionGet(); | struct Selection *const sel = *selectionGet(); | |||
sel->edge = calloc(1, sizeof(*sel->edge)); | sel->edge = calloc(1, sizeof(*sel->edge)); | |||
struct SelectionEdge* const pe = sel->edge; | struct SelectionEdge *const pe = sel->edge; | |||
XColor color; | XColor color; | |||
scrotSelectionGetLineColor(&color); | scrotSelectionGetLineColor(&color); | |||
XSetWindowAttributes attr; | XSetWindowAttributes attr; | |||
attr.background_pixel = color.pixel; | attr.background_pixel = color.pixel; | |||
attr.override_redirect = True; | attr.override_redirect = True; | |||
pe->classHint = XAllocClassHint(); | pe->classHint = XAllocClassHint(); | |||
pe->classHint->res_name = "scrot"; | pe->classHint->res_name = "scrot"; | |||
pe->classHint->res_class = "scrot"; | pe->classHint->res_class = "scrot"; | |||
pe->wndDraw = XCreateWindow(disp, root, 0, 0, WidthOfScreen(scr), HeightOfSc | pe->wndDraw = XCreateWindow(disp, root, 0, 0, WidthOfScreen(scr), | |||
reen(scr), 0, | HeightOfScreen(scr), 0, CopyFromParent, InputOutput, CopyFromParent, | |||
CopyFromParent, InputOutput, CopyFromParent, CWOverrideRedirect | CWBack | CWOverrideRedirect | CWBackPixel, &attr); | |||
Pixel, &attr); | ||||
unsigned long opacity = opt.lineOpacity * ((unsigned)-1 / 100); | ||||
int const lineOpacity = optionsParseRequireRange(opt.lineOpacity, | ||||
SELECTION_EDGE_OPACITY_MIN, SELECTION_OPACITY_MAX); | XChangeProperty(disp, pe->wndDraw, | |||
XInternAtom(disp, "_NET_WM_WINDOW_OPACITY", False), XA_CARDINAL, 32, | ||||
unsigned long opacity = lineOpacity * ((unsigned)-1 / 100); | PropModeReplace, (unsigned char *) &opacity, 1L); | |||
XChangeProperty(disp, pe->wndDraw, XInternAtom(disp, "_NET_WM_WINDOW_OPACITY | XChangeProperty(disp, pe->wndDraw, | |||
", False), | XInternAtom(disp, "_NET_WM_WINDOW_TYPE", False), XA_ATOM, 32, | |||
XA_CARDINAL, 32, PropModeReplace, | PropModeReplace, | |||
(unsigned char*) &opacity, 1L); | (unsigned char *) &(Atom) { XInternAtom(disp, "_NET_WM_WINDOW_TYPE_DOCK" | |||
, False) }, | ||||
XChangeProperty(disp, pe->wndDraw, XInternAtom(disp, "_NET_WM_WINDOW_TYPE", | ||||
False), | ||||
XA_ATOM, 32, PropModeReplace, | ||||
(unsigned char*) &(Atom) { XInternAtom(disp, "_NET_WM_WINDOW_TYPE_DOCK", | ||||
False) }, | ||||
1L); | 1L); | |||
XSetClassHint(disp, pe->wndDraw, pe->classHint); | XSetClassHint(disp, pe->wndDraw, pe->classHint); | |||
} | } | |||
void selectionEdgeDestroy(void) | ||||
{ | ||||
struct Selection const* const sel = *selectionGet(); | ||||
struct SelectionEdge* pe = sel->edge; | ||||
if (pe->wndDraw != 0) { | ||||
waitUnmapWindowNotify(); | ||||
XFree(pe->classHint); | ||||
XDestroyWindow(disp, pe->wndDraw); | ||||
} | ||||
free(pe); | ||||
} | ||||
void selectionEdgeDraw(void) | void selectionEdgeDraw(void) | |||
{ | { | |||
struct Selection const* const sel = *selectionGet(); | const struct Selection *const sel = *selectionGet(); | |||
struct SelectionEdge const* const pe = sel->edge; | const struct SelectionEdge *const pe = sel->edge; | |||
XRectangle rects[4] = { | XRectangle rects[4] = { | |||
{ sel->rect.x, sel->rect.y, opt.lineWidth, sel->rect.h }, // left | { sel->rect.x, sel->rect.y, opt.lineWidth, sel->rect.h }, // left | |||
{ sel->rect.x, sel->rect.y, sel->rect.w, opt.lineWidth }, // top | { sel->rect.x, sel->rect.y, sel->rect.w, opt.lineWidth }, // top | |||
{ sel->rect.x + sel->rect.w, sel->rect.y, opt.lineWidth, sel->rect.h }, | // right | |||
// right | { sel->rect.x + sel->rect.w, sel->rect.y, opt.lineWidth, sel->rect.h }, | |||
{ sel->rect.x, sel->rect.y + sel->rect.h, sel->rect.w + opt.lineWidth, o | // bottom | |||
pt.lineWidth } // bottom | { sel->rect.x, sel->rect.y + sel->rect.h, sel->rect.w + opt.lineWidth, | |||
opt.lineWidth } | ||||
}; | }; | |||
XShapeCombineRectangles(disp, pe->wndDraw, ShapeBounding, 0, 0, rects, 4, Sh | XShapeCombineRectangles(disp, pe->wndDraw, ShapeBounding, 0, 0, rects, 4, | |||
apeSet, 0); | ShapeSet, 0); | |||
XMapWindow(disp, pe->wndDraw); | XMapWindow(disp, pe->wndDraw); | |||
} | } | |||
void selectionEdgeMotionDraw(int x0, int y0, int x1, int y1) | void selectionEdgeMotionDraw(int x0, int y0, int x1, int y1) | |||
{ | { | |||
struct Selection* const sel = *selectionGet(); | struct Selection *const sel = *selectionGet(); | |||
selectionCalculateRect(x0, y0, x1, y1); | selectionCalculateRect(x0, y0, x1, y1); | |||
sel->rect.x -= opt.lineWidth; | sel->rect.x -= opt.lineWidth; | |||
sel->rect.y -= opt.lineWidth; | sel->rect.y -= opt.lineWidth; | |||
sel->rect.w += opt.lineWidth; | sel->rect.w += opt.lineWidth; | |||
sel->rect.h += opt.lineWidth; | sel->rect.h += opt.lineWidth; | |||
selectionEdgeDraw(); | selectionEdgeDraw(); | |||
} | } | |||
void selectionEdgeDestroy(void) | ||||
{ | ||||
const struct Selection *const sel = *selectionGet(); | ||||
struct SelectionEdge *pe = sel->edge; | ||||
if (pe->wndDraw != 0) { | ||||
waitUnmapWindowNotify(); | ||||
XFree(pe->classHint); | ||||
XDestroyWindow(disp, pe->wndDraw); | ||||
} | ||||
free(pe); | ||||
} | ||||
static void waitUnmapWindowNotify(void) | ||||
{ | ||||
const struct Selection *const sel = *selectionGet(); | ||||
const struct SelectionEdge *const pe = sel->edge; | ||||
XEvent ev; | ||||
XSelectInput(disp, pe->wndDraw, StructureNotifyMask); | ||||
XUnmapWindow(disp, pe->wndDraw); | ||||
struct timespec delay = {0, 80000000L}; // 80ms | ||||
for (short i = 0; i < 30; ++i) { | ||||
if (XCheckIfEvent(disp, &ev, &xeventUnmap, (XPointer) & (pe->wndDraw))) | ||||
break; | ||||
nanosleep(&delay, NULL); | ||||
} | ||||
} | ||||
static Bool xeventUnmap(Display *dpy, XEvent *ev, XPointer arg) | ||||
{ | ||||
(void)dpy; // unused | ||||
Window *win = (Window *)arg; | ||||
return (ev->xunmap.window == *win); | ||||
} | ||||
End of changes. 15 change blocks. | ||||
75 lines changed or deleted | 44 lines changed or added |