Xlib: Drag to move window (XMoveWindow) - Xwindows

This is a discussion on Xlib: Drag to move window (XMoveWindow) - Xwindows ; I have a simple window, no child windows. All I want to do is use the mouse to move it about the screen. I had no problems specifying a new position programatically, but now I want the mouse to be ...

+ Reply to Thread
Results 1 to 7 of 7

Thread: Xlib: Drag to move window (XMoveWindow)

  1. Xlib: Drag to move window (XMoveWindow)

    I have a simple window, no child windows. All I want to do is use the
    mouse to move it about the screen. I had no problems specifying a new
    position programatically, but now I want the mouse to be able to drage it
    around.

    I'm having the following problems:
    1. I can get the window to move, but after a few times through the loop,
    it suddenly jumps to the center of the screen. I thought I might be
    getting an event from some other window, so I filtered out events that
    weren't from the same window id. Same problem.
    2. I can't get a procedure tied to motion events to evaluate the window
    state against Button1Mask and consistently return the proper results.
    Since this is such a simple problem, I'm sure I'm doing something wrong.
    NOTE: If I'm not moving the window, I can get this to work fine and can
    trace around the screen with no problem. It's when the window jumps that
    the comparison fails. Perhaps it is the change in the window state?

    The code below is simple and has a lot of "hacks" in it as I was trying
    different examples in attempt of solving the problem. Originally, I was
    trying to move the window based on an offset of the original mouse
    position, but when I started having trouble, I changed it to just move the
    NorthWest corner of the window to the mouse position.

    Any insight is appreciated. Thanks!
    Tom Junior

    The code follows below.

    Here is the button_down handler:
    ================================
    void
    handle_button_down( Display* display, Window win, GC gc, GC rev_gc,
    XButtonEvent* button_event,
    unsigned int win_width, unsigned int win_height,
    short pixels[1000][1000] )
    {

    int x;
    int y;
    Window focus_r;
    int revert_to_focus;
    XWindowAttributes *this_window;

    printf( "\tButton #:%i", button_event->button );

    x = button_event->x;
    y = button_event->y;

    /* Get the attributes of this window */
    XGetWindowAttributes ( display, button_event->window, this_window
    );


    switch (button_event->button) {
    case Button1:
    /* Who has focus? Us? */
    XGetInputFocus(display, &focus_r, &revert_to_focus
    );
    /* printf( "\n\tFocus: %d\t Window: %d\n",
    focus_r, win ); */
    if ( focus_r != win ) {
    /* XSetInputFocus(display, focus,
    revert_to, time) */
    XSetInputFocus( display,
    button_event->window, RevertToPointerRoot, CurrentTime );
    /* Set the window to an active border */
    XChangeWindowAttributes(display,
    button_event->window, StandardMask, &JMWindowActive);
    XClearWindow( display,
    button_event->window );
    JMRefresh( display, button_event->window,
    gc, rev_gc, pixels );

    }

    /* Where are we on the screen? */
    /* in the "titlebar"? */
    if ( (y - this_window->y) < 10 ) {
    printf ("\t\tToolbar\n");
    WINDOW_MOVING = 1;
    JMMoveWindow( display,
    button_event->window, this_window, button_event );
    break;

    } else {
    XDrawPoint( display, button_event->window,
    gc, x, y );
    pixels[x][y] = 1;
    break;
    }

    case Button3:
    XDrawPoint( display, button_event->window, rev_gc,
    x, y );
    pixels[x][y] = -1;
    printf( "Erase... \t");
    JMRefresh( display, win, gc, rev_gc, pixels );
    break;
    }

    } /* handle_button_down */



    And here is where I do the moving:
    ==================================

    void
    JMMoveWindow( Display *display, Window window, XWindowAttributes*
    window_attributes, XButtonEvent* button_event )
    {

    int end = 0;
    int mouse_last_x;
    int mouse_last_y;
    int win_last_x = window_attributes->x;
    int win_last_y = window_attributes->y;
    int new_x;
    int new_y;
    int i;
    XWindowAttributes win_attr;
    int x, y;
    int scr_x, scr_y;
    Window child_win;
    Window parent_win;

    XEvent an_event;

    mouse_last_x = an_event.xbutton.x;
    mouse_last_y = an_event.xbutton.y;


    while (end == 0) {

    XNextEvent(display, &an_event);

    /* added this to make sure I only got events pertaining to this window
    */
    if ( an_event.xbutton.window == window ) {

    printf( "Mouse is at: %i, %i with window %d\n",
    an_event.xmotion.x, an_event.xmotion.y, an_event.xmotion.state );

    new_x = an_event.xmotion.x; /* win_last_x
    + ( mouse_last_x - an_event.xmotion.x ); */
    new_y = an_event.xmotion.y; /* win_last_y
    + ( mouse_last_y - an_event.xmotion.y ); */


    /* XSync( display, window ); */
    XMoveWindow( display, window, new_x, new_y );

    /* I've tried several things here. I don't remember what I originally
    had */
    if ( an_event.xmotion.state || Button1Mask ) {
    end = 0;
    } else {
    printf (" Leaving move...");
    end = 1;
    }
    }
    }

    } /* JMMoveWindow */

  2. Re: Xlib: Drag to move window (XMoveWindow)

    Tom Junior wrote:

    > I have a simple window, no child windows. All I want to do is use the
    > mouse to move it about the screen. I had no problems specifying a new
    > position programatically, but now I want the mouse to be able to drage it
    > around.

    [...]
    > The code follows below.

    [...]
    > XNextEvent(display, &an_event);
    >
    > /* added this to make sure I only got events pertaining to this window
    > */
    > if ( an_event.xbutton.window == window ) {


    Maybe you selected for button events only, but generally before accessing
    the specific event, check if the event type matches! Here is an example,
    how I would do (assuming override_redirect is set):

    static int move(Display *display, Window window, unsigned release_button,
    int pressed_x, int pressed_y)
    {

    Window root_return, child;
    int current_x=pressed_x;
    int current_y=pressed_y;
    int initial_x, initial_y;
    int win_x, win_y;
    int dummy;
    unsigned int mask;
    XWindowAttributes attr;
    static Cursor cursor=XCreateFontCursor(display, XC_hand2);

    XGetWindowAttributes(display, window, &attr);
    win_x=initial_x=attr.x;
    win_y=initial_y=attr.y;

    XGrabPointer(display, window, False,
    PointerMotionHintMask | ButtonMotionMask | ButtonReleaseMask |
    OwnerGrabButtonMask | Expose, GrabModeAsync, GrabModeAsync, None,
    cursor, CurrentTime);

    for (;{
    XEvent event;

    XNextEvent(display, &event);
    switch(event.type){
    case ButtonRelease:
    if (event.xbutton.button==release_button){
    XUngrabPointer(display, CurrentTime);
    XFlush(display);
    /* throw away all pending button events */
    while(XCheckMaskEvent(display, ButtonPressMask|ButtonReleaseMask,
    &event));

    /* return, if something has changed */
    return (initial_x!=win_x || initial_y!=win_y);
    }
    break;
    case MotionNotify:
    /* throw away all pending motion events */
    while(XCheckTypedEvent(display, MotionNotify, &event));

    /* get mouse position */
    XQueryPointer(display, DefaultRootWindow(display), &root_return,
    &child, &current_x, &current_y, &dummy, &dummy,
    &mask);
    win_x=initial_x+current_x-pressed_x;
    win_y=initial_y+current_y-pressed_y;
    XMoveWindow(display, window, win_x, win_y); break;
    case Expose:
    printf("However, Expose in move()\n"); break;
    }
    }
    }

    [main]
    XNextEvent(display, &event);
    if (event.type==ButtonPress){
    move(display, window, event.xbutton.button, event.xbutton.x_root,
    event.xbutton.y_root);
    }

    Regards,
    Daniel

  3. Re: Xlib: Drag to move window (XMoveWindow)


    > Maybe you selected for button events only,


    I specified for motion events in the XWindowAttributes when I created the
    window, but I'm not doing the XGrabPointer function you're doing below.
    Perhaps that is the problem.

    I see a few differences between what you're doing below and how I'm doing
    it. I think I see why yours would work and mine might spaz out the screen.

    override_redirect is set. I assume I would have to move the window with WM
    hints instead of XMoveWindow was it not.

    As always, thank you. This continues to be a great learning experience. I
    had only planned to get a rough idea about what was going on under the
    hood, but now I think I'll keep going until I run out of ideas to add to
    the program.

    Thanks again,
    Tom

  4. Re: Xlib: Drag to move window (XMoveWindow)

    Tom Junior wrote:

    >> Maybe you selected for button events only,

    >
    > I specified for motion events in the XWindowAttributes when I created the
    > window, but I'm not doing the XGrabPointer function you're doing below.
    > Perhaps that is the problem.


    When you select for some event, you should not access the event's fields
    through another's event union.

    | XSlectInput(display, window, excluding_button_events_mask);
    | XNextEvent(display, &an_event);
    | if (an_event.xbutton.window == window) {
    | ...
    | }

    You should check the event type and access the related union!

    | if (an_event.xmotion.state || Button1Mask)

    Not doing what you're expecting, but this is a C language problem.

    > override_redirect is set. I assume I would have to move the window with WM
    > hints instead of XMoveWindow was it not.


    You do not move windows with setting hints, they are only hints. When a
    window manager is involved you have to take into account, that window
    coordinates maybe related to the framing window, so you have to translate
    to root window origin. Further, if the window doesn't have static gravity,
    the window coordinates to XMoveWindow() may belong to the framing window,
    not your window.

    Regards,
    Daniel

  5. Re: Xlib: Drag to move window (XMoveWindow)

    Finally got a chance to add in the code.

    I adapted what you sent me into the code and the window moves as expected,
    cursor change and all. Thanks!

    At first, I was disappointed by the flickering/latency of the window as I
    moved it (8 or nine of them trailing behind if I moved the mouse too
    quickly), but then I grabbed a same-size window from the desktop and had
    the same problem. I'm running KDE. Is Qt slow on redrawing windows?



    > | if (an_event.xmotion.state || Button1Mask)


    A hack I was trying to eliminate the problem of the window jumping out of
    the loop and to the center of the screen. In all cases, I've been using a
    switch statement to compare the mouse state to the button masks.

    The problem of other procedures not correctly comparing the state of the
    mouse went away when I implemented your changes. I think I was leaving
    events on the queue that I should not have been.

    Next, resize with the mouse. Then sub-windows.



    >
    > Not doing what you're expecting, but this is a C language problem.
    >
    >> override_redirect is set. I assume I would have to move the window with
    >> WM
    >> hints instead of XMoveWindow was it not.

    >
    > You do not move windows with setting hints, they are only hints. When a
    > window manager is involved you have to take into account, that window
    > coordinates maybe related to the framing window, so you have to translate
    > to root window origin. Further, if the window doesn't have static
    > gravity,
    > the window coordinates to XMoveWindow() may belong to the framing window,
    > not your window.
    >
    > Regards,
    > Daniel




    --
    Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/

  6. Re: Xlib: Drag to move window (XMoveWindow)

    Thomas wrote:

    >> | if (an_event.xmotion.state || Button1Mask)

    >
    > A hack I was trying to eliminate the problem of the window jumping out of
    > the loop and to the center of the screen. In all cases, I've been using a
    > switch statement to compare the mouse state to the button masks.


    How did you do using switch?

    XMotionEvent(3X11):
    | The state member is set to indicate the logical state of the pointer
    | buttons and modifier keys just prior to the event, which is the
    | bitwise inclusive OR of one or more of the button or modifier key
    | masks: But- ton1Mask, Button2Mask, Button3Mask, Button4Mask,
    | Button5Mask, Shift- Mask, LockMask, ControlMask, Mod1Mask,
    | Mod2Mask, Mod3Mask, Mod4Mask, and Mod5Mask.

    Normally you would do:

    if (an_event.xmotion.state & Button1Mask)

    > Next, resize with the mouse. Then sub-windows.


    You ought to have mention this, before I stripped down my move/resize code
    to only move windows ;-)

    Regards,
    Daniel

  7. Re: Xlib: Drag to move window (XMoveWindow)

    Sorry it took so long to get back. Couldn't get to my computer for a
    couple days.

    > How did you do using switch?


    Here's an example of me using the switch statement. Seems to work fine.
    Like I said, I only had a problem when I wasn't clearing events I should
    have been.

    switch (drag_event->state) {
    case Button1Mask :


    >
    > You ought to have mention this, before I stripped down my move/resize
    > code
    > to only move windows ;-)


    The code you sent "implied" the solution. I was able to add the resize
    feature rather quickly.


    Thanks!
    Tom

+ Reply to Thread