Skip to content

Commit 597d026

Browse files
committed
use 4 windows for drawing --line mode=edge borders
this uses similar approach to selx by using 4 windows to draw the border. using XShape extension does not work well with compositors but the 4 window method works fine. Fixes: #76
1 parent 4f6f69a commit 597d026

File tree

6 files changed

+45
-46
lines changed

6 files changed

+45
-46
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ scrot requires a few projects and libraries:
6464
- [libbsd](https://libbsd.freedesktop.org/wiki/) (only needed if `<err.h>` is missing)
6565
- An X11 implementation [(e.g. X.Org)](https://www.x.org/wiki/)
6666
- libXcomposite [(can be found in X.Org)](https://gitlab.freedesktop.org/xorg/lib/libxcomposite)
67-
- libXext [(can be found in X.Org)](https://gitlab.freedesktop.org/xorg/lib/libxext)
6867
- libXfixes [(can be found in X.Org)](https://gitlab.freedesktop.org/xorg/lib/libxfixes)
6968
- libXrandr [(can be found in X.Org)](https://gitlab.freedesktop.org/xorg/lib/libxrandr)
7069

deps.pc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ Name: scrot's mandatory dependencies
22
Description: ditto
33
Version: infinite
44
Cflags: -D_XOPEN_SOURCE=700L
5-
Requires: x11 imlib2 >= 1.11.0 xcomposite >= 0.2.0 xext xfixes >= 5.0.1 xrandr >= 1.5
5+
Requires: x11 imlib2 >= 1.11.0 xcomposite >= 0.2.0 xfixes >= 5.0.1 xrandr >= 1.5

man/scrot.txt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,10 @@ SELECTION STYLE
169169

170170
mode=MODE MODE can be "auto", "edge" or "classic" without quotes.
171171
edge is the new selection, classic uses the old one.
172-
"auto" uses "edge" if no compositor is running and -f flag
173-
isn't active, "classic" otherwise. "edge" ignores the style
174-
specifier, "classic" ignores the opacity specifier.
172+
"auto" uses "edge" if -f flag isn't active, "classic"
173+
otherwise. "edge" ignores the style specifier, "classic"
174+
ignores the opacity specifier.
175+
175176

176177
Without the -l option, a default style is used:
177178

src/scrot_selection.c

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -405,16 +405,8 @@ Imlib_Image scrotSelectionSelectMode(void)
405405
opt.selection.mode = SELECTION_MODE_CAPTURE;
406406

407407
if (opt.lineMode == LINE_MODE_AUTO) {
408-
char buf[128];
409-
snprintf(buf, sizeof(buf), "_NET_WM_CM_S%d", DefaultScreen(disp));
410-
Atom cm = XInternAtom(disp, buf, False);
411-
/* edge mode has some issues with compositor.
412-
* also doesn't work well in combination with --freeze.
413-
*/
414-
if (XGetSelectionOwner(disp, cm) == None && !opt.freeze)
415-
opt.lineMode = LINE_MODE_EDGE;
416-
else
417-
opt.lineMode = LINE_MODE_CLASSIC;
408+
/* edge mode doesn't work well in combination with --freeze. */
409+
opt.lineMode = opt.freeze ? LINE_MODE_CLASSIC : LINE_MODE_EDGE;
418410
}
419411

420412
if (opt.lineWidth == 0) {

src/scrot_selection.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ struct SelectionClassic {
8989
GC gc;
9090
};
9191
struct SelectionEdge {
92-
Window wndDraw;
92+
Window windows[4];
9393
bool isMapped;
9494
};
9595

src/selection_edge.c

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Copyright 2020-2021 Daniel T. Borelli <danieltborelli@gmail.com>
44
Copyright 2021-2023 Guilherme Janczak <guilherme.janczak@yandex.com>
55
Copyright 2021 Peter Wu <peterwu@hotmail.com>
6-
Copyright 2023-2025 NRK <nrk@disroot.org>
6+
Copyright 2023-2026 NRK <nrk@disroot.org>
77
88
Permission is hereby granted, free of charge, to any person obtaining a copy
99
of this software and associated documentation files (the "Software"), to
@@ -38,7 +38,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
3838
#include <X11/Xatom.h>
3939
#include <X11/Xlib.h>
4040
#include <X11/Xutil.h>
41-
#include <X11/extensions/shape.h>
4241

4342
#include "options.h"
4443
#include "scrot.h"
@@ -55,26 +54,28 @@ void selectionEdgeCreate(void)
5554
XSetWindowAttributes attr;
5655
attr.background_pixel = color.pixel;
5756
attr.override_redirect = True;
57+
Atom winType = XInternAtom(disp, "_NET_WM_WINDOW_TYPE", False);
58+
Atom winDock = XInternAtom(disp, "_NET_WM_WINDOW_TYPE_DOCK", False);
59+
Atom winOpacity = XInternAtom(disp, "_NET_WM_WINDOW_OPACITY", False);
5860

59-
pe->wndDraw = XCreateWindow(disp, root, 0, 0, WidthOfScreen(scr),
60-
HeightOfScreen(scr), 0, CopyFromParent, InputOutput, CopyFromParent,
61-
CWOverrideRedirect | CWBackPixel, &attr);
62-
pe->isMapped = false;
61+
for (size_t i = 0; i < ARRAY_COUNT(pe->windows); ++i) {
62+
pe->windows[i] = XCreateWindow(disp, root,
63+
0, 0, WidthOfScreen(scr), HeightOfScreen(scr), 0,
64+
CopyFromParent, InputOutput, CopyFromParent,
65+
CWOverrideRedirect | CWBackPixel, &attr);
6366

64-
unsigned long opacity = opt.lineOpacity * (0xFFFFFFFFu / 255);
67+
XChangeProperty(disp, pe->windows[i], winType, XA_ATOM, 32,
68+
PropModeReplace, (unsigned char *)&winDock, 1L);
6569

66-
XChangeProperty(disp, pe->wndDraw,
67-
XInternAtom(disp, "_NET_WM_WINDOW_OPACITY", False), XA_CARDINAL, 32,
68-
PropModeReplace, (unsigned char *) &opacity, 1L);
70+
unsigned long opacity = opt.lineOpacity * (0xFFFFFFFFu / 255);
71+
XChangeProperty(disp, pe->windows[i], winOpacity, XA_CARDINAL, 32,
72+
PropModeReplace, (unsigned char *)&opacity, 1L);
6973

70-
XChangeProperty(disp, pe->wndDraw,
71-
XInternAtom(disp, "_NET_WM_WINDOW_TYPE", False), XA_ATOM, 32,
72-
PropModeReplace,
73-
(unsigned char *) &(Atom) { XInternAtom(disp, "_NET_WM_WINDOW_TYPE_DOCK", False) },
74-
1L);
74+
XClassHint hint = { .res_name = "scrot", .res_class = "scrot" };
75+
XSetClassHint(disp, pe->windows[i], &hint);
76+
}
77+
pe->isMapped = false;
7578

76-
XClassHint hint = { .res_name = "scrot", .res_class = "scrot" };
77-
XSetClassHint(disp, pe->wndDraw, &hint);
7879
}
7980

8081
void selectionEdgeDraw(void)
@@ -83,18 +84,22 @@ void selectionEdgeDraw(void)
8384
struct SelectionEdge *const pe = &sel->edge;
8485

8586
XRectangle rects[4] = {
86-
{ sel->rect.x, sel->rect.y, opt.lineWidth, sel->rect.h }, // left
87+
{ sel->rect.x, sel->rect.y + opt.lineWidth,
88+
opt.lineWidth, sel->rect.h - opt.lineWidth }, // left
8789
{ sel->rect.x, sel->rect.y, sel->rect.w, opt.lineWidth }, // top
88-
// right
89-
{ sel->rect.x + sel->rect.w, sel->rect.y, opt.lineWidth, sel->rect.h },
90-
// bottom
90+
{ sel->rect.x + sel->rect.w, sel->rect.y, opt.lineWidth, sel->rect.h }, // right
9191
{ sel->rect.x, sel->rect.y + sel->rect.h, sel->rect.w + opt.lineWidth,
92-
opt.lineWidth }
92+
opt.lineWidth } // bottom
9393
};
9494

95-
XShapeCombineRectangles(disp, pe->wndDraw, ShapeBounding, 0, 0, rects, 4,
96-
ShapeSet, 0);
97-
XMapWindow(disp, pe->wndDraw);
95+
if (sel->rect.w == 0 || sel->rect.h == 0)
96+
return;
97+
98+
for (size_t i = 0; i < ARRAY_COUNT(pe->windows); ++i) {
99+
XRectangle *rp = rects + i;
100+
XMoveResizeWindow(disp, pe->windows[i], rp->x, rp->y, rp->width, rp->height);
101+
XMapWindow(disp, pe->windows[i]);
102+
}
98103
pe->isMapped = true;
99104
}
100105

@@ -116,15 +121,17 @@ void selectionEdgeDestroy(void)
116121
{
117122
const struct SelectionEdge *pe = &selection.edge;
118123

119-
if (pe->wndDraw != None) {
120-
XSelectInput(disp, pe->wndDraw, StructureNotifyMask);
121-
XDestroyWindow(disp, pe->wndDraw);
124+
for (size_t i = 0; i < ARRAY_COUNT(pe->windows); ++i) {
125+
if (pe->windows[i] == None)
126+
continue;
127+
XSelectInput(disp, pe->windows[i], StructureNotifyMask);
128+
XDestroyWindow(disp, pe->windows[i]);
122129
bool isUnmapped = !pe->isMapped, isDestroyed = false;
123130
for (XEvent ev; !(isUnmapped && isDestroyed);) {
124131
XNextEvent(disp, &ev);
125-
if (ev.type == DestroyNotify && ev.xdestroywindow.window == pe->wndDraw)
132+
if (ev.type == DestroyNotify && ev.xdestroywindow.window == pe->windows[i])
126133
isDestroyed = true;
127-
if (ev.type == UnmapNotify && ev.xunmap.window == pe->wndDraw)
134+
if (ev.type == UnmapNotify && ev.xunmap.window == pe->windows[i])
128135
isUnmapped = true;
129136
}
130137
}

0 commit comments

Comments
 (0)