• XSendEvent of mouse button events

    From Noel Hunt@21:1/5 to All on Thu May 18 15:33:39 2017
    I have a particular terminal program which has a button 2
    menu, but when button 3 is pressed in this client, I would
    like to pass this event on to the window manager, so that
    it can post its own button 3 menu.

    The current implementation of the terminal has the following
    code (not directly, through a library) which it calls when
    it receives a button 3 event:

    XUngrabPointer(_x.display, m->msec);
    XSendEvent(_x.display, e.root, True, ButtonPressMask, (XEvent*)&e);

    Neglecting the data structures, the intent is to send the
    event back to the root window.

    After button 3 is pressed once in the client, the window manager
    button 3 menu is posted; after dismissing the menu, the next
    pointer movement immediately posts this menu again. That is,
    the loop in the client that waits on mouse events, is getting
    a ButtonPress event. While the window manager menu is posted,
    if the pointer is moved outside the client and the menu is
    unposted, the next pointer motion into the client window causes
    the window manager menu to be posted again, and so on.

    Any help would be appreciated.

    Regards,
    Noel Hunt

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Julian Bradfield@21:1/5 to Noel Hunt on Fri May 19 06:14:46 2017
    On 2017-05-18, Noel Hunt <noel.hunt@gmail.com> wrote:
    XUngrabPointer(_x.display, m->msec);
    XSendEvent(_x.display, e.root, True, ButtonPressMask, (XEvent*)&e);

    There must be more code around it...

    After button 3 is pressed once in the client, the window manager
    button 3 menu is posted; after dismissing the menu, the next
    pointer movement immediately posts this menu again. That is,
    the loop in the client that waits on mouse events, is getting
    a ButtonPress event. While the window manager menu is posted,

    It doesn't follow from the code you posted that the loop is getting a ButtonPress event. It could be that some of the code surrounding the
    two lines you posted is wrong.

    Have you tried running the program under gdb and tracing execution?
    What happens?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Noel Hunt@21:1/5 to All on Fri May 19 00:19:52 2017
    I'll provide the code. The program is '9term' and it is
    written threaded. The thread handling the mouse events is
    thus:

    while(readmouse(mousectl) >= 0){
    if(sending){
    Send:
    /* send to window */
    if(mouse->buttons == 0)
    sending = FALSE;
    else
    wsetcursor(w, 0);
    tmp = mousectl->m;
    send(w->mc.c, &tmp);
    continue;
    }
    if((mouse->buttons&(1|8|16)) || ptinrect(mouse->xy, w->scrollr)){
    sending = TRUE;
    goto Send;
    }else if(mouse->buttons&2)
    button2menu(w);
    else
    bouncemouse(mouse);
    }

    '9term' is written using Plan9 subroutines, which get translated
    into X11 code via another process called 'devdraw', which is what
    9term writes to, indirectly through the library routines; in this
    we find what 'bouncemouse' ends up calling:

    /*
    * Send the mouse event back to the window manager.
    * So that 9term can tell rio to pop up its button3 menu.
    */
    void
    _xbouncemouse(Mouse *m)
    {
    XButtonEvent e;
    XWindow dw;

    e.type = ButtonPress;
    e.state = 0;
    e.button = 0;
    if(m->buttons&1)
    e.button = 1;
    else if(m->buttons&2)
    e.button = 2;
    else if(m->buttons&4)
    e.button = 3;
    e.same_screen = 1;
    XTranslateCoordinates(_x.display, _x.drawable,
    DefaultRootWindow(_x.display),
    m->xy.x, m->xy.y, &e.x_root, &e.y_root, &dw);
    e.root = DefaultRootWindow(_x.display);
    e.window = e.root;
    e.subwindow = None;
    e.x = e.x_root;
    e.y = e.y_root;
    #undef time
    e.time = CurrentTime;
    XUngrabPointer(_x.display, m->msec);
    XSendEvent(_x.display, e.root, True, ButtonPressMask, (XEvent*)&e);
    XFlush(_x.display);
    }

    'rio' is the window manager.

    I have put print statements in the event loop in '9term'
    and it shows that once button 3 has been pressed, each
    time around the loop button 3 is reported as pressed. That
    is, the window manager menu pops up, dismiss it, and the
    next pointer motion in the 9term window posts the window
    manager menu again.

    It seems like a simple enough process, but something is
    going wrong. It looks like no-one else uses XSendEvent like
    this---the manual talks about it normally being used for
    handling selections.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Julian Bradfield@21:1/5 to Noel Hunt on Fri May 19 08:41:28 2017
    On 2017-05-19, Noel Hunt <noel.hunt@gmail.com> wrote:
    I'll provide the code. The program is '9term' and it is
    written threaded. The thread handling the mouse events is
    thus:

    This may be too easy to be true, but:

    is mouse->buttons the button detail from a ButtonPress event, or is it
    the button component of the pointer state? If the latter:

    the 9term loop doesn't check whether the event is a ButtonPress event,
    it just checks whether a button is down; while the bouncemouse event
    doesn't bounce the actual event, it just sends a ButtonPress.

    So if you press the button, and then the mouse moves at all, a
    MotionNotify event comes through with button3 down, and then
    bouncemouse sends a ButtonPress event.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Noel Hunt@21:1/5 to Julian Bradfield on Fri May 19 20:01:57 2017
    On Friday, May 19, 2017 at 6:45:01 PM UTC+10, Julian Bradfield wrote:
    This may be too easy to be true, but:

    is mouse->buttons the button detail from a ButtonPress event, or is it
    the button component of the pointer state? If the latter:
    the 9term loop doesn't check whether the event is a ButtonPress event,
    it just checks whether a button is down; while the bouncemouse event
    doesn't bounce the actual event, it just sends a ButtonPress.

    So if you press the button, and then the mouse moves at all, a
    MotionNotify event comes through with button3 down, and then
    bouncemouse sends a ButtonPress event.

    The code in the process which translates X11 events to Plan9
    structures is this;

    case ButtonPress:
    be = (XButtonEvent*)xev;
    if(be->button == 1) {
    if(kstate & ControlMask)
    be->button = 2;
    else if(kstate & Mod1Mask)
    be->button = 3;
    }
    // fall through
    case ButtonRelease:
    altdown = 0;
    // fall through
    case MotionNotify:
    if(mouse.stall)
    return;
    if(_xtoplan9mouse(xev, &m) < 0)
    return;
    sendmouse(m);
    break;


    'm' is a Plan9 mouse structure, and it is static.

    struct Mouse
    {
    int buttons; /* bit array: LMR=124 */
    Point xy;
    ulong msec;
    };

    Just put some more fprint's into the drawing process and it
    seems that ButtonRelease events are not being reported for
    Button 3. If I look at button 2 events, Press and Release are
    reported for the client but not button 3.

    I assume this is the problem. The client gets a button 3 press
    event, passes this event with XSendEvent to the root window,
    but never gets a ButtonRelease. Since 'm' is static, the
    button 3 flag is never cleared until another button press
    event clears it.

    So, have you any suggestions as to how to fix this? Should
    the window manager detect it has received an event from the
    client and send back the ButtonRelease?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Julian Bradfield@21:1/5 to Noel Hunt on Sat May 20 06:13:04 2017
    On 2017-05-20, Noel Hunt <noel.hunt@gmail.com> wrote:
    Just put some more fprint's into the drawing process and it
    seems that ButtonRelease events are not being reported for
    Button 3. If I look at button 2 events, Press and Release are
    reported for the client but not button 3.

    I assume this is the problem. The client gets a button 3 press
    event, passes this event with XSendEvent to the root window,
    but never gets a ButtonRelease. Since 'm' is static, the
    button 3 flag is never cleared until another button press
    event clears it.

    So, have you any suggestions as to how to fix this? Should
    the window manager detect it has received an event from the
    client and send back the ButtonRelease?

    Not really. I'd find out why release events aren't being reported, and
    fix that:) Or fix the code event to plan9 code that isn't correctly
    setting the mouse structure.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Noel Hunt@21:1/5 to Julian Bradfield on Sat May 20 15:36:07 2017
    On Saturday, May 20, 2017 at 4:15:01 PM UTC+10, Julian Bradfield wrote:
    So, have you any suggestions as to how to fix this? Should
    the window manager detect it has received an event from the
    client and send back the ButtonRelease?

    Not really. I'd find out why release events aren't being reported, and
    fix that:) Or fix the code event to plan9 code that isn't correctly
    setting the mouse structure.

    I realize that is the correct way to proceed, but there is an
    interesting question here concerning ButtonRelease. When the
    terminal program receives ButtonPress and forwards it to the
    window manager, where is the following ButtonRelease is delivered?
    Clearly, the window manager needs a ButtonRelease as well as
    the client. How do you ensure this? Can an event be sent to
    two destinations, assuming they are selecting on that event?

    I suspect you know a lot more about X11 programming than I do
    hence I am asking you.

    I have in the meantime put code in the window manager to detect
    the fake ButtonPress and send a ButtonRelease to the InputFocus,
    which is of course the terminal window. This at least manages
    to clear the mouse structure.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Julian Bradfield@21:1/5 to Noel Hunt on Sun May 21 08:50:39 2017
    On 2017-05-20, Noel Hunt <noel.hunt@gmail.com> wrote:
    I suspect you know a lot more about X11 programming than I do
    hence I am asking you.

    Not much - I haven't written an Xlib program since about 1990, though
    I've occasionally fixed things.
    At this point, I would need to go and read the manuals, but you can do
    that as well as I can.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Noel Hunt@21:1/5 to Julian Bradfield on Sun May 21 21:07:28 2017
    On Sunday, May 21, 2017 at 6:55:01 PM UTC+10, Julian Bradfield wrote:
    On 2017-05-20, Noel Hunt <NigelLuxuryYacht@gmail.com> wrote:
    I suspect you know a lot more about X11 programming than I do
    hence I am asking you.

    Not much - I haven't written an Xlib program since about 1990, though
    I've occasionally fixed things.
    At this point, I would need to go and read the manuals, but you can do
    that as well as I can.

    I'm not averse to reading the manual, but I think the problem
    is related to an XGrabPointer being executed in the window manager.

    It has a main event loop where it catches the ButtonPress, but then
    dispatches to 'button' which generates the menu and handles mouse
    events for traversal of the menu. It does an XGrabPointer at the
    start, so I am assuming that the ButtonRelease is only reported to
    the window manager. I assume any kind of grab means that only one
    client (the grabbing client) gets the events, hence it should never
    be seen by another client.

    Because the terminology of the manuals is some opaque to me, I
    naively thought that changing the owner_events argument to
    XGrabPointer I might be able to change the behaviour. It seems
    to make no difference, however.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)