c00kiemon5ter / monsterwm

tiny but monstrous tiling window manager
https://github.com/c00kiemon5ter/monsterwm
Other
335 stars 44 forks source link

Send Mouse clicks to windows when focus changes. #12

Closed dzava closed 11 years ago

dzava commented 12 years ago

When you click an unfocused window the event should be send to the window.

diff --git a/monsterwm.c b/monsterwm.c
index be31f62..3cb505e 100644
--- a/monsterwm.c
+++ b/monsterwm.c
@@ -235,7 +235,11 @@ void buttonpress(XEvent *e) {

     if (!wintoclient(e->xbutton.window, &c, &d)) return;

-    if (CLICK_TO_FOCUS && d->curr != c && e->xbutton.button == Button1) focus(c, d);
+    if (CLICK_TO_FOCUS && d->curr != c && e->xbutton.button == Button1){
+        focus(c, d);
+        XSendEvent(dis, PointerWindow, False, BUTTONMASK, e);        
+        XFlush(dis);
+    }

     for (unsigned int i = 0; i < LENGTH(buttons); i++)
         if (CLEANMASK(buttons[i].mask) == CLEANMASK(e->xbutton.state)
c00kiemon5ter commented 12 years ago

Hi,

I've been trying this and a couple of other solutions but nothing seems to work as expected. Some apps at some points wont accept the event, ie geany - open file dialog, or opera - select bookmark, or the menus..

I've tried to XPutBack(..) the event, but that didnt work at all .. I've tried XSendEvent(..) a separate ButtonPress and then usleep(50) then XSendEvent(..) a ButtonRelease, but that doesnt work either. It doesn't matter if I XFlush(dis) or XSync(dis, False).

It doesn't do what it's expected to do in all cases - what it would do if the window was previously focused.. If anyone figures this out, I will probably pull it.

dzava commented 12 years ago

Took a while but i think i got it. There are issues with menus not expanding until you move the mouse to another option and with drop-downs not getting the release event so they remain clicked.

diff --git a/monsterwm.c b/monsterwm.c
index 4673e84..db48f50 100644
--- a/monsterwm.c
+++ b/monsterwm.c
@@ -238,7 +238,12 @@ void buttonpress(XEvent *e) {
     Client *c = NULL;

     if (wintoclient(e->xbutton.window, &c, &d) && CLICK_TO_FOCUS &&
-            c != d->curr && e->xbutton.button == Button1) focus(c, d);
+            c != d->curr && e->xbutton.button == Button1){
+        focus(c, d);
+        XSendEvent(dis, PointerWindow,True,NoEventMask,e);
+        e->type = ButtonRelease;
+        XSendEvent(dis, PointerWindow,True,NoEventMask,e);
+    }

     for (unsigned int i = 0; i < LENGTH(buttons); i++)
         if (CLEANMASK(buttons[i].mask) == CLEANMASK(e->xbutton.state) &&
baskerville commented 11 years ago

What I've seen in i3-wm might be helpful here:

For this to work[1], you shall use GrabModeSync as pointer_mode when grabbing:

XGrabButton(dis, FOCUS_BUTTON, AnyModifier, root, False, BUTTONMASK, GrabModeSync, GrabModeAsync, None, None);

Then, the following will replay the pointer event for the underlying client:

XAllowEvents(dis, ReplayPointer, CurrentTime);
XSync(dis, 0);
  1. See man xcb_allow_events.
dzava commented 11 years ago

Much better solution.

Thank you.