take a (quick) shot

interpretive language scripts


Moderator: Forum moderators

Post Reply
HerrBert
Posts: 339
Joined: Mon Jul 13, 2020 6:14 pm
Location: Germany, NRW
Has thanked: 17 times
Been thanked: 113 times

take a (quick) shot

Post by HerrBert »

Hello.

Not sure if this is the right place to post, so feel free to move this to according place...

All the time i'm using puppy linux now i've been missing the ability to do a 'quick' screenshot of the active window like in Windows with ALT+PRINT.
TBH, in Windows you had to open a graphics editor and paste the image from clipboard, so it was not OOTB.
Here is a way to take the shot of the active window instantly:

Code: Select all

#!/bin/bash

[ -z "`which ffmpeg`" ] && echo "${0}: ffmpeg not found. Exiting..." 1>&2 && exit
[ -z "`which xdotool`" ] && echo "${0}: xdotool not found. Exiting..." 1>&2 && exit

WINID="-id `xdotool getactivewindow`"
[ "$WINID" = "-id " ] && WINID="-root" # if no window open

read MAXX MAXY <<< `xwininfo -root | awk 'NR>=8&&NR<=9 {print $2}' | tr '\n' ' '`

#xwininfo doesn't accept -frame and -id - need to manually calculate frame
read XPOS YPOS FRAME TITLE WIDTH HEIGHT <<< `xwininfo $WINID | sed -e '4,9!d' -e 's/.*: *//g' | tr '\n' ' '`
XPOS=$((XPOS - FRAME))
YPOS=$((YPOS - TITLE))
WIDTH=$((WIDTH + (2 * FRAME)))
HEIGHT=$((HEIGHT + FRAME + TITLE))
[ ${XPOS} -lt 0 ] && WIDTH=$((WIDTH + XPOS)) && XPOS=0
[ ${YPOS} -lt 0 ] && HEIGHT=$((HEIGHT + YPOS)) && YPOS=0
[ $((WIDTH + XPOS)) -ge $MAXX ] && WIDTH=$((MAXX - XPOS))
[ $((HEIGHT + YPOS)) -ge $MAXY ] && HEIGHT=$((MAXY - YPOS))
OFFSET="+${XPOS},${YPOS}"

OUTNAME="/root/quickshot-`date +%y%m%d-%H%M%S`.jpg"

ffmpeg -y -f x11grab -r 25 -s ${WIDTH}x${HEIGHT} -i ${DISPLAY}${OFFSET}+nomouse -c mjpeg -frames 1 "$OUTNAME" 2> /dev/null

defaultimageviewer "$OUTNAME" &

Paste code to a file in /usr/bin or /usr/local/bin, name it quickshot and make it executable.
NOTE: dependencies are ffmpeg and xdotool

If then you add/change in your /root/.jwm/jwmrc-personal:

Code: Select all

<Key mask="A" key="Print">exec:quickshot</Key>

you can take a shot of the active window without clicking any dialogs...

Last edited by HerrBert on Wed Jan 20, 2021 2:33 pm, edited 1 time in total.
User avatar
rockedge
Site Admin
Posts: 5810
Joined: Mon Dec 02, 2019 1:38 am
Location: Connecticut,U.S.A.
Has thanked: 2071 times
Been thanked: 2156 times
Contact:

Re: take a (quick) shot

Post by rockedge »

@HerrBert gut gemacht!

A useful tool.

TerryH
Posts: 578
Joined: Mon Jun 15, 2020 2:08 am
Has thanked: 111 times
Been thanked: 131 times

Re: take a (quick) shot

Post by TerryH »

A handy little tool. Thanks.

New Laptop - ASUS ZenBook Ryzen 7 5800H Vega 7 iGPU / 16 GB RAM

User avatar
cobaka
Posts: 521
Joined: Thu Jul 16, 2020 6:04 am
Location: Central Coast, NSW - au
Has thanked: 87 times
Been thanked: 49 times

Re: take a (quick) shot

Post by cobaka »

Hello @HerrBert
Pls read the note in the screenshot below

snapshot_n.jpg
snapshot_n.jpg (71.19 KiB) Viewed 920 times

Cobaka

собака --> это Русский --> an old dog
"so-baka" (not "co", as in coast or crib).

HerrBert
Posts: 339
Joined: Mon Jul 13, 2020 6:14 pm
Location: Germany, NRW
Has thanked: 17 times
Been thanked: 113 times

Re: take a (quick) shot

Post by HerrBert »

I have added [ "$WINID" = "-id " ] && WINID="-root" to the code in the first post to take a screenshot of the whole screen if there is no window open. Otherwise defaultimageviewer gives an error.

User avatar
takenp
Posts: 42
Joined: Tue Aug 25, 2020 10:38 am
Has thanked: 72 times
Been thanked: 12 times

Re: take a (quick) shot

Post by takenp »

@HerrBert

There is no xdotool on my Bionicpup by default so I tried to find the way how to use what is in the system.
It is xprop. Xprop can find the active window's id:

Code: Select all

WINID="-id $(xprop -root -f _NET_ACTIVE_WINDOW 0x " \$0\\n" _NET_ACTIVE_WINDOW | awk "{print \$2}")"

=~=~=~=~
I'm running online-radio called Melodymaker
Listen it here https://radio.melodymaker.org

User avatar
MochiMoppel
Posts: 1132
Joined: Mon Jun 15, 2020 6:25 am
Location: Japan
Has thanked: 18 times
Been thanked: 367 times

Re: take a (quick) shot

Post by MochiMoppel »

@takenp Same here. Also on my system xdotool is not preinstalled so I always use xprop. But how does your code work? What does the format switch -f do?

I usually do it this way:
WINID=$(xprop -root _NET_ACTIVE_WINDOW)
WINID="-id ${WINID##* }"

which is faster (using bash, not awk)

User avatar
takenp
Posts: 42
Joined: Tue Aug 25, 2020 10:38 am
Has thanked: 72 times
Been thanked: 12 times

Re: take a (quick) shot

Post by takenp »

which is faster (using bash, not awk)

I've got above xprop string from stackoverflow's example and of course you are absolutely right. Your sample is more clear, shorter and better ;)

=~=~=~=~
I'm running online-radio called Melodymaker
Listen it here https://radio.melodymaker.org

HerrBert
Posts: 339
Joined: Mon Jul 13, 2020 6:14 pm
Location: Germany, NRW
Has thanked: 17 times
Been thanked: 113 times

Re: take a (quick) shot

Post by HerrBert »

@takenp @MochiMoppel
Thanks for suggesting xprop. Very much appreciated...

I had to fiddle a bit with the case that no window is open and also replaced remaining awk with sed.

Code: Select all

#!/bin/bash

[ -z "`which ffmpeg`" ] && echo "${0}: ffmpeg not found. Exiting..." 1>&2 && exit

WINID=$(xprop -root _NET_ACTIVE_WINDOW)
WINID="${WINID##* }"

[ "$WINID" = "0x0" -o "$WINID" = "found." ] && WINID="-root" || WINID="-id $WINID" # if no window open

read MAXX MAXY <<< `xwininfo -root | sed -e '8,9!d;s/.*: *//g' | tr '\n' ' '`

#xwininfo doesn't accept -frame and -id - need to manually calculate frame
read XPOS YPOS FRAME TITLE WIDTH HEIGHT <<< `xwininfo $WINID | sed -e '4,9!d;s/.*: *//g' | tr '\n' ' '`
XPOS=$((XPOS - FRAME))
YPOS=$((YPOS - TITLE))
WIDTH=$((WIDTH + (2 * FRAME)))
HEIGHT=$((HEIGHT + FRAME + TITLE))
[ ${XPOS} -lt 0 ] && WIDTH=$((WIDTH + XPOS)) && XPOS=0
[ ${YPOS} -lt 0 ] && HEIGHT=$((HEIGHT + YPOS)) && YPOS=0
[ $((WIDTH + XPOS)) -ge $MAXX ] && WIDTH=$((MAXX - XPOS))
[ $((HEIGHT + YPOS)) -ge $MAXY ] && HEIGHT=$((MAXY - YPOS))
OFFSET="+${XPOS},${YPOS}"

OUTNAME="/root/quickshot-`date +%y%m%d-%H%M%S`.jpg"

ffmpeg -y -f x11grab -r 25 -s ${WIDTH}x${HEIGHT} -i ${DISPLAY}${OFFSET}+nomouse -c mjpeg -frames 1 "$OUTNAME" 2> /dev/null

defaultimageviewer "$OUTNAME" &

So no longer depending on xdotool.

Thank you very much.

User avatar
MochiMoppel
Posts: 1132
Joined: Mon Jun 15, 2020 6:25 am
Location: Japan
Has thanked: 18 times
Been thanked: 367 times

Re: take a (quick) shot

Post by MochiMoppel »

HerrBert wrote: Thu Jan 21, 2021 11:23 am

I had to fiddle a bit with the case that no window is open

If no window is open in the current desktop you most likely have a currently active window on another desktop, so your script takes a shot of the windowless desktop with the size of whatever the size of the (not visible) current window. This can hardly be what the user expects. Do I miss something here?

and also replaced remaining awk with sed

You could even replace sed with faster bash but may not be as compact.
If you want to keep sed you could also try
read MAXX MAXY <<< `xwininfo -root | sed -n '/Width/,/Height/ s/[^0-9]*//p'`
Not much of a difference but may be easier to understand. In any case there should be no need for tr.

HerrBert
Posts: 339
Joined: Mon Jul 13, 2020 6:14 pm
Location: Germany, NRW
Has thanked: 17 times
Been thanked: 113 times

Re: take a (quick) shot

Post by HerrBert »

@MochiMoppel

In any case there should be no need for tr.

Weird situation here. When initially written this code in ScPup64 it didn't work until i added tr.
On Slacko64 7.0 i can remove tr and all works as expected.

I think it won't hurt to keep tr.

Many thanks again.

User avatar
MochiMoppel
Posts: 1132
Joined: Mon Jun 15, 2020 6:25 am
Location: Japan
Has thanked: 18 times
Been thanked: 367 times

Re: take a (quick) shot

Post by MochiMoppel »

HerrBert wrote: Thu Jan 21, 2021 2:14 pm

Weird situation here. When initially written this code in ScPup64 it didn't work until i added tr.
On Slacko64 7.0 i can remove tr and all works as expected.

This can only happen if your IFS variable in ScPup64 does not include the linefeed character. However your code can fail even if you add tr , e.g. if IFS is not set at all.

Here is another idea. Since you already call xprop to get WINID why not use the same call for also getting MAXX and MAXY. Fast and does not depend on IFS, tr, read or sed:

XPROP=$(xprop -root _NET_DESKTOP_GEOMETRY _NET_ACTIVE_WINDOW)
WINID=${XPROP##* }
MAXX=${XPROP%,*}
MAXX=${MAXX##* }
MAXY=${XPROP%$'\n'*}
MAXY=${MAXY##* }

HerrBert
Posts: 339
Joined: Mon Jul 13, 2020 6:14 pm
Location: Germany, NRW
Has thanked: 17 times
Been thanked: 113 times

Re: take a (quick) shot

Post by HerrBert »

@MochiMoppel

  • I saw there is also _NET_WORKAREA. Assuming that all virtual desktops are of the same size i am using that now.
    Thanks again.

  • On the tr-thing i did some very trivial testing on ScPup64:

    Code: Select all

    # set | grep IFS
    IFS=$' \t\n'
    # read A B <<<`echo -e "eins zwei"`
    # echo $A $B
    eins zwei
    # read A B <<<`echo -e "eins\nzwei"`
    # echo $A $B
    eins
    # echo -e "eins\nzwei"
    eins
    zwei
    # read -d "\n" A B <<<`echo -e "eins\nzwei"`
    # echo $A $B
    eins zwei
    # 

    Looks like read ignores IFS...
    Since the used ScPup64 is 20.06 and i don't have the latest version 'installed' i'll leave this as a note for all, who have problems with the read command in ScPup64_20.06.

Eastler_Dart
Posts: 80
Joined: Wed Aug 05, 2020 3:34 am
Has thanked: 1 time
Been thanked: 8 times

Re: take a (quick) shot

Post by Eastler_Dart »

You know about the 'screenshot-functionality' of mtpaint ?

I press Print-Key on keyboard, which automatically opens mtpaint with the shot image of the (whole) screen (one keypress, its done).
If I want only the shot of a window, its quick and easy in mtpaint to drag a border around the Window in the screenshot and chose in menu 'image'->'crop'.
On my Lappy without separate NumBlock, I had to press 'Fn' + 'Print' keys together.

For this, you need mtpaint to be installed (is in most puppies),
and add the Key-shortcut in jwmrc or the included /root/jwm/jwmrc-personal (upup-ef).
the line is: <Key key="Print">exec:mtpaint -s</Key>

If you want to take a shot from a menu (which blocks the print-key while opened),
go to terminal, start command: mtpaint -s 10
so mtpaint waits 10 seconds with the shot, you can minimize the terminalwindow and open the menu you want to have,
wait until the 10 seconds are over, mtpaint comes up with the shot of the menu.

Hope it helps

HerrBert
Posts: 339
Joined: Mon Jul 13, 2020 6:14 pm
Location: Germany, NRW
Has thanked: 17 times
Been thanked: 113 times

Re: take a (quick) shot

Post by HerrBert »

I know about mtpaint -s and i'm using it as defaultscreenshot, which is way faster than ffmpeg.
This script is just about to grab a shot of the active window without clicking in tas or editing in mtpaint.
Last but not least it is an exercise for me...

Recent versions of mtpaint can be run by script. Maybe it is possible to crop the screenshot by commandline. I don't know if this can be done. Never tried it.

User avatar
rockedge
Site Admin
Posts: 5810
Joined: Mon Dec 02, 2019 1:38 am
Location: Connecticut,U.S.A.
Has thanked: 2071 times
Been thanked: 2156 times
Contact:

Re: take a (quick) shot

Post by rockedge »

@HerrBert
Have you tried using 'scrot' for taking screenshots?

Code: Select all

scrot -s   # select a window or full screen
scrot -d 1 # set a delay for 1 second for a full screenshot
User avatar
cobaka
Posts: 521
Joined: Thu Jul 16, 2020 6:04 am
Location: Central Coast, NSW - au
Has thanked: 87 times
Been thanked: 49 times

Re: take a (quick) shot

Post by cobaka »

@rockedge asked:

Have you tried using 'scrot' for taking screenshots?

Cobaka: I'm using uPupBB32.

Code: Select all

# 
# scrot --help
bash: scrot: command not found
# which scrot  
#

Scrot does not appear to be part of the Puppy I have (or at least I don't know where to look for it).

Cobaka

собака --> это Русский --> an old dog
"so-baka" (not "co", as in coast or crib).

User avatar
MochiMoppel
Posts: 1132
Joined: Mon Jun 15, 2020 6:25 am
Location: Japan
Has thanked: 18 times
Been thanked: 367 times

Re: take a (quick) shot

Post by MochiMoppel »

HerrBert wrote: Sat Jan 23, 2021 10:20 am

Maybe it is possible to crop the screenshot by commandline. I don't know if this can be done. Never tried it.

I tried and couldn't make it work. Crop is not the problem. Before applying the crop the crop area has to be selected. Mtpaint seems to have no way to select an area via input parameters. Selection is a hand job.

HerrBert
Posts: 339
Joined: Mon Jul 13, 2020 6:14 pm
Location: Germany, NRW
Has thanked: 17 times
Been thanked: 113 times

Re: take a (quick) shot

Post by HerrBert »

scrot also not part of Slacko64 7.0...

@MochiMoppel
I've also tried some things with mtpaint without success, but it fails early at taking a screenshot via

Code: Select all

mtpaint --cmd -file/new screenshot create

Digging a bit deeper i found handbook for recent version of mtpaint at https://github.com/wjaguar/mtpaint_handbook
In chapter 10 there is:

10.5.1 The File Menu

New
The unnamed control is the image type radiobutton pack: "24 bit RGB", ...
In commandline mode, the "Grab Screenshot" option is not present.

so i guess we're out of luck...

User avatar
rockedge
Site Admin
Posts: 5810
Joined: Mon Dec 02, 2019 1:38 am
Location: Connecticut,U.S.A.
Has thanked: 2071 times
Been thanked: 2156 times
Contact:

Re: take a (quick) shot

Post by rockedge »

Using the PPM search for and install scrot. It is not included in the the later Puppy's but easy to install, very small footprint, easy to use and script.
test in a terminal :

Code: Select all

individual window or full screen
scrot -s 

Code: Select all

full window with time delay (seconds)
scrot -d 2

Code: Select all

name image like 2021-1-28_2560x1024_scrot.png and move to screenshots directory
scrot '%Y-%m-%d_$wx$h_scrot.png' -e 'mv $f ~/my-documents/screenshots

Code: Select all

Usage : scrot [OPTIONS]... [FILE]
  Where FILE is the target file for the screenshot.
  If FILE is not specified, a date-stamped file will be dropped in the
  current directory.
  See man scrot for more details
  -h, --help                display this help and exit
  -v, --version             output version information and exit
  -b, --border              When selecting a window, grab wm border too
  -c, --count               show a countdown before taking the shot
  -d, --delay NUM           wait NUM seconds before taking a shot
  -e, --exec APP            run APP on the resulting screenshot
  -q, --quality NUM         Image quality (1-100) high value means
                            high size, low compression. Default: 75.
                            For lossless compression formats, like png,
                            low quality means high compression.
  -m, --multidisp           For multiple heads, grab shot from each
                            and join them together.
  -s, --select              interactively choose a window or rectangle
                            with the mouse
  -u, --focused             use the currently focused window
  -t, --thumb NUM           generate thumbnail too. NUM is the percentage
                            of the original size for the thumbnail to be,
                            or the geometry in percent, e.g. 50x60 or 80x20.
  -z, --silent              Prevent beeping

  SPECIAL STRINGS
  Both the --exec and filename parameters can take format specifiers
  that are expanded by scrot when encountered.
  There are two types of format specifier. Characters preceded by a '%'
  are interpreted by strftime(2). See man strftime for examples.
  These options may be used to refer to the current date and time.
  The second kind are internal to scrot  and are prefixed by '$'
  The following specifiers are recognised:
                  $f image path/filename (ignored when used in the filename)
                  $m thumbnail path/filename
                  $n image name (ignored when used in the filename)
                  $s image size (bytes) (ignored when used in the filename)
                  $p image pixel size
                  $w image width
                  $h image height
                  $t image format
                  $$  prints a literal '$'
                  \n prints a newline (ignored when used in the filename)
  Example:
          scrot '%Y-%m-%d_$wx$h_scrot.png' -e 'mv $f ~/images/shots/'
          Creates a file called something like 2000-10-30_2560x1024_scrot.png
          and moves it to your images directory.

This program is free software see the file COPYING for licensing info.
Copyright Tom Gilbert 2000
Email bugs to <scrot_sucks@linuxbrit.co.uk>
HerrBert
Posts: 339
Joined: Mon Jul 13, 2020 6:14 pm
Location: Germany, NRW
Has thanked: 17 times
Been thanked: 113 times

Re: take a (quick) shot

Post by HerrBert »

@rockedge
May be worth to keep an eye on, but ATM installing 3 more dependencies on Slacko64 7.0 is not what i would call a small footprint...

HerrBert
Posts: 339
Joined: Mon Jul 13, 2020 6:14 pm
Location: Germany, NRW
Has thanked: 17 times
Been thanked: 113 times

Re: take a (quick) shot

Post by HerrBert »

MochiMoppel wrote: Thu Jan 28, 2021 7:14 am
HerrBert wrote: Sat Jan 23, 2021 10:20 am

Maybe it is possible to crop the screenshot by commandline. I don't know if this can be done. Never tried it.

I tried and couldn't make it work. Crop is not the problem. Before applying the crop the crop area has to be selected. Mtpaint seems to have no way to select an area via input parameters. Selection is a hand job.

Apart from crop there's also 'Resize canvas' which was my initial idea, but nothing helps due to not beeing able to take a shot in commandline mode.

User avatar
wiak
Posts: 3671
Joined: Tue Dec 03, 2019 6:10 am
Location: Packing - big job
Has thanked: 57 times
Been thanked: 1028 times
Contact:

Re: take a (quick) shot

Post by wiak »

rockedge wrote: Thu Jan 28, 2021 4:13 pm

Using the PPM search for and install scrot. It is not included in the the later Puppy's but easy to install, very small footprint, easy to use and script.

So, anyway, I just stumbled across this thread and noted that HerrBert didn't like the idea of using the wonderful scrot utility because it requires a couple of extra (small, I'd say) libs at least one of which may not be in some Pups.

Well... for more bang for your buck you could install the fantastic program weX (I say, fantastic, that's cos I wrote it, so just saying fantastic for amusement). What has that got to do with the screenshot issue you may ask?...

Well, weX is a pretty accurate, high resolution, X11 screen recorder program, plus can record audio only or webcam (video recorder with audio) or all of screen, webcam (in wee window at bottom right) and audio - or whatever combination of these you wish... It's a bit like Precord on steroids but equally small size being created using bash script and gtkdialog... Yeah, you say, but this thread isn't about capturing X11 so what has weX got to do with that? Well... as it happens weX uses a fork of scrot called 'scrox', which is basically scrot on steroids - actually it is only a few chunks of code added that allow scrox to be used by other programs (in this case weX) to select an area or window on the screen and report the coordinates for further processing. In other words, scrox is scrot, but with a couple of extra options added, so it obeys correctly all the same commands as normal scrot and pretty much same binary size and efficiency. Yeah, it is scrot pretty much so also needs these wee extra libs same as scrot but with just that few kB extra you also get weX screencast, audio, and webcam recorder included (and unlike for Simple Screen Recorder there are no qt libs required)! Now that, ladies and gentlemen, is value for money. Truth to tell, you can actually install scrox on its own (just as a directly compatible substitute for scrot), but why would you when you might as well add tiny wee bash/gtkdialog script weX usefully too? You can find both weX and scrox dotpets here:

viewtopic.php?p=1102#p1102

Note that weX will work on pretty much all recent pups. It should also work on many old ones but may need some config file modifications for that - if you have trouble getting it to work, just ask me and maybe I can help you overcome such difficulties. I don't expect you to have problems at all with scrox since that is just going to work (same as scrot) but notice that if you want to use weX then weX needs scrox (weX won't work with scrot, though having both scrot and scrox is fine - but why have both when scrox contains all of scrot anyway? - you can even make a symlink called scrot that points to scrox if some other program expects scrot to be present...).

Attachments
wex.png
wex.png (50.48 KiB) Viewed 767 times

https://www.tinylinux.info/
DOWNLOAD wd_multi for hundreds of 'distros' at your fingertips: viewtopic.php?p=99154#p99154
Αξίζει να μεταφραστεί;

User avatar
misko_2083
Posts: 196
Joined: Wed Dec 09, 2020 11:59 pm
Has thanked: 10 times
Been thanked: 20 times

Re: take a (quick) shot

Post by misko_2083 »

^Thanks for sharing Wiak.

HerrBert wrote: Thu Jan 28, 2021 8:26 pm
MochiMoppel wrote: Thu Jan 28, 2021 7:14 am
HerrBert wrote: Sat Jan 23, 2021 10:20 am

Maybe it is possible to crop the screenshot by commandline. I don't know if this can be done. Never tried it.

I tried and couldn't make it work. Crop is not the problem. Before applying the crop the crop area has to be selected. Mtpaint seems to have no way to select an area via input parameters. Selection is a hand job.

Apart from crop there's also 'Resize canvas' which was my initial idea, but nothing helps due to not beeing able to take a shot in commandline mode.

Check out this old thread https://bbs.archlinux.org/viewtopic.php ... 47#p660547

Now the CPU hog issue is easy to fix and I would Print the output like this:

Code: Select all

X=
Y=
WIDTH=
HEIGHT=

So that eval can be used to set the variables.

What's required is gcc and X development libtrary (Xlib) .
In debian it's libx11-dev.
Save it as xrectsel.c

Code: Select all

#include<stdio.h>
#include<stdlib.h>
#include<X11/Xlib.h>
#include<X11/cursorfont.h>
#include<unistd.h>
/* Select area
   Needs Xlib, in Debian it's libx11-dev
   compile with
        gcc  xrectsel.c -Wall -o xrectsel `pkg-config --cflags --libs x11`

    https://bbs.archlinux.org/viewtopic.php?pid=660547#p660547
*/

int main(void)
{
  int rx = 0, ry = 0, rw = 0, rh = 0;
  int rect_x = 0, rect_y = 0, rect_w = 0, rect_h = 0;
  int btn_pressed = 0, done = 0;

  XEvent ev;
  Display *disp = XOpenDisplay(NULL);

  if(!disp)
    return EXIT_FAILURE;

  Screen *scr = NULL;
  scr = ScreenOfDisplay(disp, DefaultScreen(disp));

  Window root = 0;
  root = RootWindow(disp, XScreenNumberOfScreen(scr));

  Cursor cursor, cursor2;
  cursor = XCreateFontCursor(disp, XC_cross);
  cursor2 = XCreateFontCursor(disp, XC_crosshair);

  XGCValues gcval;
  gcval.foreground = XWhitePixel(disp, 0);
  gcval.function = GXxor;
  gcval.background = XBlackPixel(disp, 0);
  gcval.plane_mask = gcval.background ^ gcval.foreground;
  gcval.subwindow_mode = IncludeInferiors;
  gcval.line_width = 2;

  GC gc;
  gc = XCreateGC(disp, root,
                 GCFunction | GCForeground | GCBackground | GCSubwindowMode | GCLineWidth ,
                 &gcval);

  /* this XGrab* stuff makes XPending true ? */
  if ((XGrabPointer
       (disp, root, False,
        ButtonMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync,
        GrabModeAsync, root, cursor, CurrentTime) != GrabSuccess))
    printf("couldn't grab pointer:");

  if ((XGrabKeyboard
       (disp, root, False, GrabModeAsync, GrabModeAsync,
        CurrentTime) != GrabSuccess))
    printf("couldn't grab keyboard:");

  while (!done) {
//  while (!done && XPending(disp)) {
//    XNextEvent(disp, &ev);
    if (!XPending(disp)) { usleep(1000); continue; } // fixes the 100% CPU hog issue in original code
    if ( (XNextEvent(disp, &ev) >= 0) ) {
      switch (ev.type) {
        case MotionNotify:
        /* this case is purely for drawing rect on screen */
          if (btn_pressed) {
            if (rect_w) {
              /* 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;
        case ButtonPress:
          btn_pressed = 1;
          rx = ev.xbutton.x;
          ry = ev.xbutton.y;
          break;
        case ButtonRelease:
          done = 1;
          break;
      }
    }
  }
  /* clear the drawn rectangle */
  if (rect_w) {
    XDrawRectangle(disp, root, gc, rect_x, rect_y, rect_w, rect_h);
    XFlush(disp);
  }
  rw = ev.xbutton.x - rx;
  rh = ev.xbutton.y - ry;
  /* cursor moves backwards */
  if (rw < 0) {
    rx += rw;
    rw = 0 - rw;
  }
  if (rh < 0) {
    ry += rh;
    rh = 0 - rh;
  }

  XCloseDisplay(disp);

  printf("X=%i\nY=%i\nWIDTH=%i\nHEIGHT=%i\n", rx, ry, rw, rh);

  return EXIT_SUCCESS;
}

Compile with

Code: Select all

gcc  xrectsel.c -Wall -o  xrectsel `pkg-config --cflags --libs x11`

Now run and select area when the cursor changes.

Code: Select all

./xrectsel
X=534
Y=391
WIDTH=403
HEIGHT=331

Or with eval

Code: Select all

eval $(./xrectsel)
echo $X
564
echo $Y
305

Do you want to exit the Circus? The Harsh Truth
https://www.youtube.com/watch?v=ZJwQicZHp_c

Post Reply

Return to “Scripts”