You are not logged in.

#1 2009-11-23 03:32:31

lolilolicon
Member
Registered: 2009-03-05
Posts: 1,722

Select a screen area with mouse and return the geometry of this area?

is there a program that does this:
you select a rectangle area on screen and it returns the geometry or size, position of this area?

say i put my mouse pointer at position (a,b), then i drag it to position (c,d), it will return something like "+a+b -x+y -c-d +m-n" or 'LxW+a+b' or just 'a,b c,d'

PS1: i think Xlib can easily do that, and i would have written it in C if i knew how..
PS2: i don't like the approach of resizing a window to that area and run xwininfo.
PS3: advertising: tongue
       this is for my new script ffcast :: thread :: AUR page

Regards


This silver ladybug at line 28...

Offline

#2 2009-11-23 06:40:34

lolilolicon
Member
Registered: 2009-03-05
Posts: 1,722

Re: Select a screen area with mouse and return the geometry of this area?

I can't believe it, I've done it!

#include<stdio.h>
#include<stdlib.h>
#include<X11/Xlib.h>
#include<X11/cursorfont.h>

int main(void)
{
  int rx = 0, ry = 0, rw = 0, rh = 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;
  cursor = XCreateFontCursor(disp, XC_left_ptr);

  /* 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);
      switch (ev.type) {
        case ButtonPress:
          btn_pressed = 1;
          rx = ev.xbutton.x;
          ry = ev.xbutton.y;
          break;
        case ButtonRelease:
          done = 1;
          break;
      }
    }
  }
  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("%dx%d+%d+%d\n",rw,rh,rx,ry);

  return EXIT_SUCCESS;
}

I was thinking about scrot -s... then I grabbed the sources of scrot... then, it's freaking done!

$ gcc -Wall -lX11 xrectsel.c -o xrectsel
$ ./xrectsel
492x538+552+54

Woot!
Any further suggestions?

Last edited by lolilolicon (2009-11-23 06:56:32)


This silver ladybug at line 28...

Offline

#3 2009-11-23 07:08:00

lolilolicon
Member
Registered: 2009-03-05
Posts: 1,722

Re: Select a screen area with mouse and return the geometry of this area?

Now it draws a rectangle on screen while you drag!

#include<stdio.h>
#include<stdlib.h>
#include<X11/Xlib.h>
#include<X11/cursorfont.h>

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_left_ptr);
  cursor2 = XCreateFontCursor(disp, XC_lr_angle);

  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;

  GC gc;
  gc = XCreateGC(disp, root,
                 GCFunction | GCForeground | GCBackground | GCSubwindowMode,
                 &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);
      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("%dx%d+%d+%d\n",rw,rh,rx,ry);

  return EXIT_SUCCESS;
}

It makes me excited, which may be, well, trivial to you.
I have to say, credit goes to main.c from src of scrot!

Last edited by lolilolicon (2009-11-23 07:11:35)


This silver ladybug at line 28...

Offline

#4 2009-11-23 07:24:58

HashBox
Member
Registered: 2009-01-22
Posts: 271

Re: Select a screen area with mouse and return the geometry of this area?

Edit: awwww I was too late XD


I'm sorry I can't be a little more helpful right now, but this little utility I made a while back contains basically the functionality you need, but will need to be hacked a little and have some unnecessary stuff removed.

Basically this lets you drag a rectangle out on the root window which it can then pass to an external script or something. You will want to remove the stuff that deals with external scripts and just make it output the dimensions, and also you will probably need to modify it to allow dragging anywhere, rather than just the root window (should be just removing a line).


Actually now that I look at it most of the unneeded stuff has already been commented out for some reason tongue

/*
 * Run stuff on root window clicks
 */

#include <X11/Xlib.h>
#include <X11/Xresource.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main()
{
    Display *dpy;
    XEvent ev;
    XSetWindowAttributes wa;

    GC gc;

/*    XrmDatabase db;
    XrmValue up;
    XrmValue down;
    XrmValue left;
    XrmValue right;
    char xdb_path[128];
    char *type;*/

    int x, y;


    if (!(dpy = XOpenDisplay(NULL))) {
        fprintf(stderr, "Could not open display %s", getenv("DISPLAY"));
    }

    int black = BlackPixel(dpy, DefaultScreen(dpy));
    int white = WhitePixel(dpy, DefaultScreen(dpy));

    wa.override_redirect = True;

    Window w = XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, 100, 40, 0, DefaultDepth(dpy, DefaultScreen(dpy)), CopyFromParent, DefaultVisual(dpy, DefaultScreen(dpy)), CWOverrideRedirect | CWEventMask, &wa);

    gc = XCreateGC(dpy, w, 0, NULL);

    XSelectInput(dpy, w, StructureNotifyMask);

//    sprintf(xdb_path, "%s/.rootdragrc", getenv("HOME"));

/*    XrmInitialize();

    db = XrmGetFileDatabase(xdb_path);

    XrmGetResource(db, "up", "up", &type, &up);
    XrmGetResource(db, "down", "down", &type, &down);
    XrmGetResource(db, "left", "left", &type, &left);
    XrmGetResource(db, "right", "right", &type, &right);*/
    XGrabButton(dpy, 2, 0, DefaultRootWindow(dpy), True, ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);

    for (;;) {
        XNextEvent(dpy, &ev);

        if (ev.type == ButtonPress) {
            if (ev.xbutton.subwindow == None) { /* Root Window */
                /* Grab pointer so we receive ButtonRelease */
                XGrabPointer(dpy, DefaultRootWindow(dpy), True, PointerMotionMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
                x = ev.xbutton.x_root;
                y = ev.xbutton.y_root;

                // Open Window
                XMapWindow(dpy, w);
                XMoveWindow(dpy, w, ev.xbutton.x_root + 20, ev.xbutton.y_root + 20);
            }

            XAllowEvents(dpy, ReplayPointer, CurrentTime); /* Allow other apps to process this message */
        } else if (ev.type == MotionNotify) {
            while (XCheckTypedEvent(dpy, MotionNotify, &ev));

            // Update Window Position
            XMoveWindow(dpy, w, ev.xbutton.x_root + 20, ev.xbutton.y_root + 20);
        } else if (ev.type == ButtonRelease) {
            XUngrabPointer(dpy, CurrentTime);
            XUnmapWindow(dpy, w);

            XSync(dpy, 1);

/*            char shell_buff[256];

            sprintf(shell_buff, "%s &", button[ev.xbutton.button-1].addr);

            system(shell_buff);*/
        } else if (ev.type == Expose) {
            while (XCheckTypedEvent(dpy, Expose, &ev));

//            XSetForeground(dpy, gc, black);

//            XDrawRectangle(dpy, w, gc, 1, 1, 100, 40);
        }
    }

    XDestroyWindow(dpy, w);

    XCloseDisplay(dpy);

    return 0;
}

Hope this helps..

Last edited by HashBox (2009-11-23 07:25:46)

Offline

#5 2009-11-23 14:21:51

lolilolicon
Member
Registered: 2009-03-05
Posts: 1,722

Re: Select a screen area with mouse and return the geometry of this area?

Hi, HashBox. I can't get your program to work.

I was pretty satisfied with my xrectsel.c, but not now.
The thing is it freaks my CPU out, one of 2 cores goes up to 100%, then the other.

Thoughts?

Last edited by lolilolicon (2009-11-23 14:53:42)


This silver ladybug at line 28...

Offline

#6 2009-11-23 19:38:43

HashBox
Member
Registered: 2009-01-22
Posts: 271

Re: Select a screen area with mouse and return the geometry of this area?

Edit: On second thought my version uses XCheckTypedEvent so that might be causing it to skip some unnecessary stuff.

Hmmm not sure why yours would do that, I guess mine would do the same thing as they both loop and use XNextEvent. I also noticed that I've obviously decided to use that program as a test bed for something, since I don't think the XMapWindow and stuff should be there :\ hmm.

Wait a sec I found another version which should at least compile. (With gcc -Wall -Wextra -o rootgrab main.c -lX11)

Edit: I've just modified it so it should do what you want, but it is untested

#include <X11/Xlib.h>
//#include <X11/Xresource.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main()
{
    Display *dpy;
    XEvent ev;

    GC sel_gc;
    XGCValues sel_gv;

    int x, y, i;
    int start_x, start_y, width, height;


    if (!(dpy = XOpenDisplay(NULL))) {
        fprintf(stderr, "Could not open display %s", getenv("DISPLAY"));
    }

    XGrabButton(dpy, 1, 0, DefaultRootWindow(dpy), True, ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);

    sel_gv.function = GXinvert;
    sel_gv.subwindow_mode = IncludeInferiors;
    sel_gv.line_width = 1;
    sel_gc = XCreateGC(dpy, DefaultRootWindow(dpy), GCFunction | GCSubwindowMode | GCLineWidth, &sel_gv);

    for (;;) {
        XNextEvent(dpy, &ev);

        if (ev.type == ButtonPress) {
            /* Grab pointer so we receive ButtonRelease */
            XGrabPointer(dpy, DefaultRootWindow(dpy), True, PointerMotionMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
            x = start_x = ev.xbutton.x_root;
            y = start_y = ev.xbutton.y_root;

            width = height = 0;

            //XAllowEvents(dpy, ReplayPointer, CurrentTime); /* Allow other apps to process this message */
        } else if (ev.type == MotionNotify) {
            while (XCheckTypedEvent(dpy, MotionNotify, &ev));

            XDrawRectangle(dpy, DefaultRootWindow(dpy), sel_gc, x, y, width, height); /* Clear Rectangle */

            width = ev.xbutton.x_root - start_x;
            height = ev.xbutton.y_root - start_y;

            /* Ugliness to make width/height positive and put the start positions
             * in the right place so we can draw backwards basically. */
            if (width < 0) { width = abs(width); x = ev.xbutton.x_root; } else { x = start_x; }
            if (height < 0) { height = abs(height); y = ev.xbutton.y_root; } else { y = start_y; }

            XDrawRectangle(dpy, DefaultRootWindow(dpy), sel_gc, x, y, width, height); /* Draw Rectangle */
        } else if (ev.type == ButtonRelease) {
            XUngrabPointer(dpy, CurrentTime);

            XDrawRectangle(dpy, DefaultRootWindow(dpy), sel_gc, x, y, width, height); /* Clear Rectangle */

            XSync(dpy, 1); /* Needed to Ungrab Pointer NOW otherwise we continue receiving MotionNotify events and the previous line is useless */

            printf("%i %i %i %i\n", x, y, width, height);
        }
    }

    XFreeGC(dpy, sel_gc);

    XCloseDisplay(dpy);

    return 0;
}

Last edited by HashBox (2009-11-23 19:44:45)

Offline

#7 2009-11-24 09:52:46

lolilolicon
Member
Registered: 2009-03-05
Posts: 1,722

Re: Select a screen area with mouse and return the geometry of this area?

Thank you that is simpler than what is in scrot's main.c. It does not eat up CPU (scrot doesn't either, of course.. I haven't figured out what I missed though.)
So I'm gonna update xrectsel.c for ffcast smile (basically merge your code with the old version)
Thanks again.

Credits to HashBox
Cheers


This silver ladybug at line 28...

Offline

#8 2009-11-24 20:14:34

HashBox
Member
Registered: 2009-01-22
Posts: 271

Re: Select a screen area with mouse and return the geometry of this area?

No problem man glad you got it working smile

Offline

#9 2014-06-25 10:48:41

kenn
Member
Registered: 2014-06-25
Posts: 6

Re: Select a screen area with mouse and return the geometry of this area?

It's been a long time. I hope somebody help me with it. I am on Ubuntu 14.04 platform, I compiled and run HashBox' code, while dragging mouse I get flickering and partially missing rectangle. I wonder if it's specific to my system or xlib library deprecated?

Offline

#10 2014-06-25 11:58:48

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,422
Website

Re: Select a screen area with mouse and return the geometry of this area?

kenn, this was almost 5 years ago - a *lot* has changed since then.

I'd say open a new thread and refer back to this one - but that should be done on the unbuntu forums as these are for archlinux only.  There are many differences between the distros that might explain why this doesn't work for you.

Closing.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

Board footer

Powered by FluxBB