예제 #1
0
파일: sxhkd.c 프로젝트: lernisto/sxhkd
void key_button_event(xcb_generic_event_t *evt, uint8_t event_type)
{
	xcb_keysym_t keysym = XCB_NO_SYMBOL;
	xcb_button_t button = XCB_NONE;
	bool replay_event = false;
	uint16_t modfield = 0;
	uint16_t lockfield = num_lock | caps_lock | scroll_lock;
	parse_event(evt, event_type, &keysym, &button, &modfield);
	modfield &= ~lockfield & MOD_STATE_FIELD;
	if (keysym != XCB_NO_SYMBOL || button != XCB_NONE) {
		hotkey_t *hk = find_hotkey(keysym, button, modfield, event_type, &replay_event);
		if (hk != NULL) {
			run(hk->command, hk->sync);
			if (status_fifo != NULL)
				put_status(COMMAND_PREFIX, hk->command);
		}
	}
	switch (event_type) {
		case XCB_BUTTON_PRESS:
		case XCB_BUTTON_RELEASE:
			if (replay_event)
				xcb_allow_events(dpy, XCB_ALLOW_REPLAY_POINTER, XCB_CURRENT_TIME);
			else
				xcb_allow_events(dpy, XCB_ALLOW_SYNC_POINTER, XCB_CURRENT_TIME);
			break;
		case XCB_KEY_PRESS:
		case XCB_KEY_RELEASE:
			if (replay_event)
				xcb_allow_events(dpy, XCB_ALLOW_REPLAY_KEYBOARD, XCB_CURRENT_TIME);
			else
				xcb_allow_events(dpy, XCB_ALLOW_SYNC_KEYBOARD, XCB_CURRENT_TIME);
			break;
	}
	xcb_flush(dpy);
}
예제 #2
0
bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray &eventType,
                                                 void *message, long *result)
{
    Q_UNUSED(result);
    if (eventType != "xcb_generic_event_t")
        return false;

    xcb_generic_event_t *event = reinterpret_cast<xcb_generic_event_t*>(message);
    if ((event->response_type & ~0x80) != XCB_KEY_PRESS)
        return false;

    xcb_key_press_event_t *keyPressEvent = reinterpret_cast<xcb_key_press_event_t *>(event);

    // Avoid keyboard freeze
    xcb_connection_t *xcbConnection = QX11Info::connection();
    xcb_allow_events(xcbConnection, XCB_ALLOW_REPLAY_KEYBOARD, keyPressEvent->time);
    xcb_flush(xcbConnection);

    unsigned int keycode = keyPressEvent->detail;
    unsigned int keystate = 0;
    if (keyPressEvent->state & XCB_MOD_MASK_1)
        keystate |= XCB_MOD_MASK_1;
    if (keyPressEvent->state & XCB_MOD_MASK_CONTROL)
        keystate |= XCB_MOD_MASK_CONTROL;
    if (keyPressEvent->state & XCB_MOD_MASK_4)
        keystate |= XCB_MOD_MASK_4;
    if (keyPressEvent->state & XCB_MOD_MASK_SHIFT)
        keystate |= XCB_MOD_MASK_SHIFT;

    return activateShortcut(keycode, keystate);
}
예제 #3
0
파일: event.c 프로젝트: nqv/nilwm
/** Handle the ButtonPress event
 */
static
void handle_button_press(xcb_button_press_event_t *e) {
    NIL_LOG("event: mouse %d pressed: event %d, child %d (%d,%d)",
        e->detail, e->event, e->child, e->event_x, e->event_y);

    if (e->event == bar_.win) {
        if (click_bar(e->event_x)) {
            xcb_flush(nil_.con);
        }
        return;
    }
    /* click on client with modkey */
    if (MOD_MASK_(e->state) == cfg_.mod_key) {
        mouse_evt_.client = find_client(e->child, &mouse_evt_.ws);
        if (!mouse_evt_.client) {
            NIL_ERR("no client %d", e->child);
            goto end;
        }
        NIL_LOG("button on win=%d", mouse_evt_.client->win);
        switch (e->detail) {
        case XCB_BUTTON_INDEX_3:
            mouse_evt_.mode = CURSOR_RESIZE;
            /* warp pointer to lower right */
            mouse_evt_.x1 = mouse_evt_.client->x + mouse_evt_.client->w;
            mouse_evt_.y1 = mouse_evt_.client->y + mouse_evt_.client->h;
            xcb_warp_pointer(nil_.con, XCB_NONE, mouse_evt_.client->win,
                0, 0, 0, 0, mouse_evt_.x1, mouse_evt_.y1);
            break;
        case XCB_BUTTON_INDEX_1:
        default:
            mouse_evt_.mode = CURSOR_MOVE;
            mouse_evt_.x1 = e->event_x;
            mouse_evt_.y1 = e->event_y;
            break;
        }
        /* take control of the pointer in the root window */
        xcb_grab_pointer(nil_.con, 0, nil_.scr->root,
            XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION,
            XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE,
            nil_.cursor[mouse_evt_.mode], XCB_CURRENT_TIME);
        xcb_flush(nil_.con);
        return;
    }
end:
    /* if unhandled, forward the click to the application */
    xcb_allow_events(nil_.con, XCB_ALLOW_REPLAY_POINTER, e->time);
}
예제 #4
0
파일: event.c 프로젝트: paul/awesome
/** The button press event handler.
 * \param data The type of mouse event.
 * \param connection The connection to the X server.
 * \param ev The event.
 */
static int
event_handle_button(void *data, xcb_connection_t *connection, xcb_button_press_event_t *ev)
{
    int screen;
    const int nb_screen = xcb_setup_roots_length(xcb_get_setup(connection));
    client_t *c;
    wibox_t *wibox;

    if(event_handle_mousegrabber(ev->root_x, ev->root_y, 1 << (ev->detail - 1 + 8)))
        return 0;

    /* ev->state is
     * button status (8 bits) + modifiers status (8 bits)
     * we don't care for button status that we get, especially on release, so
     * drop them */
    ev->state &= 0x00ff;

    if((wibox = wibox_getbywin(ev->event))
       || (wibox = wibox_getbywin(ev->child)))
    {
        /* If the wibox is child, then x,y are
         * relative to root window */
        if(wibox->window == ev->child)
        {
            ev->event_x -= wibox->geometry.x;
            ev->event_y -= wibox->geometry.y;
        }

        /* Push the wibox */
        luaA_object_push(globalconf.L, wibox);
        /* Duplicate the wibox */
        lua_pushvalue(globalconf.L, -1);
        /* Handle the button event on it */
        event_button_callback(ev, &wibox->buttons, -1, 1, NULL);

        /* then try to match a widget binding */
        widget_t *w = widget_getbycoords(wibox->orientation, &wibox->widgets,
                                         wibox->geometry.width,
                                         wibox->geometry.height,
                                         &ev->event_x, &ev->event_y);
        if(w)
        {
            /* Push widget (the wibox is already on stack) */
            luaA_object_push_item(globalconf.L, -1, w);
            /* Move widget before wibox */
            lua_insert(globalconf.L, -2);
            event_button_callback(ev, &w->buttons, -2, 2, NULL);
        }
        else
            /* Remove the wibox, we did not use it */
            lua_pop(globalconf.L, 1);

    }
    else if((c = client_getbywin(ev->event)))
    {
        luaA_object_push(globalconf.L, c);
        event_button_callback(ev, &c->buttons, -1, 1, NULL);
        xcb_allow_events(globalconf.connection,
                         XCB_ALLOW_REPLAY_POINTER,
                         XCB_CURRENT_TIME);
    }
    else if(ev->child == XCB_NONE)
        for(screen = 0; screen < nb_screen; screen++)
            if(xutil_screen_get(connection, screen)->root == ev->event)
            {
                event_button_callback(ev, &globalconf.buttons, 0, 0, NULL);
                return 0;
            }

    return 0;
}
예제 #5
0
파일: dsimple.c 프로젝트: aosm/X11apps
xcb_window_t Select_Window(xcb_connection_t *dpy,
			   const xcb_screen_t *screen,
			   int descend)
{
    xcb_cursor_t cursor;
    xcb_generic_event_t *event;
    xcb_window_t target_win = XCB_WINDOW_NONE;
    xcb_window_t root = screen->root;
    int buttons = 0;
    xcb_generic_error_t *err;
    xcb_grab_pointer_cookie_t grab_cookie;
    xcb_grab_pointer_reply_t *grab_reply;

    /* Make the target cursor */
    cursor = Create_Font_Cursor (dpy, XC_crosshair);

    /* Grab the pointer using target cursor, letting it room all over */
    grab_cookie = xcb_grab_pointer
	(dpy, False, root,
	 XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE,
	 XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC,
	 root, cursor, XCB_TIME_CURRENT_TIME);
    grab_reply = xcb_grab_pointer_reply (dpy, grab_cookie, &err);
    if (grab_reply->status != XCB_GRAB_STATUS_SUCCESS)
	Fatal_Error ("Can't grab the mouse.");

    /* Let the user select a window... */
    while ((target_win == XCB_WINDOW_NONE) || (buttons != 0)) {
	/* allow one more event */
	xcb_allow_events (dpy, XCB_ALLOW_SYNC_POINTER, XCB_TIME_CURRENT_TIME);
	xcb_flush (dpy);
	event = xcb_wait_for_event (dpy);
	switch (event->response_type & 0x7f) {
	case XCB_BUTTON_PRESS:
	{
	    xcb_button_press_event_t *bp = (xcb_button_press_event_t *)event;

	    if (target_win == XCB_WINDOW_NONE) {
		target_win = bp->child; /* window selected */
		if (target_win == XCB_WINDOW_NONE)
		    target_win = root;
	    }
	    buttons++;
	    break;
	}
	case XCB_BUTTON_RELEASE:
	    if (buttons > 0) /* there may have been some down before we started */
		buttons--;
	    break;
	default:
	    /* just discard all other events */
	    break;
	}
	free (event);
    }

    xcb_ungrab_pointer (dpy, XCB_TIME_CURRENT_TIME); /* Done with pointer */

    if (!descend || (target_win == root))
	return (target_win);

    target_win = Find_Client (dpy, root, target_win);

    return (target_win);
}
예제 #6
0
/** The button press event handler.
 * \param ev The event.
 */
static void
event_handle_button(xcb_button_press_event_t *ev)
{
    lua_State *L = globalconf_get_lua_State();
    client_t *c;
    drawin_t *drawin;

    globalconf.timestamp = ev->time;

    {
        /* ev->state contains the state before the event. Compute the state
         * after the event for the mousegrabber.
         */
        uint16_t state = ev->state, change = 1 << (ev->detail - 1 + 8);
        if (XCB_EVENT_RESPONSE_TYPE(ev) == XCB_BUTTON_PRESS)
            state |= change;
        else
            state &= ~change;
        if(event_handle_mousegrabber(ev->root_x, ev->root_y, state))
            return;
    }

    /* ev->state is
     * button status (8 bits) + modifiers status (8 bits)
     * we don't care for button status that we get, especially on release, so
     * drop them */
    ev->state &= 0x00ff;

    if((drawin = drawin_getbywin(ev->event))
       || (drawin = drawin_getbywin(ev->child)))
    {
        /* If the drawin is child, then x,y are
         * relative to root window */
        if(drawin->window == ev->child)
        {
            ev->event_x -= drawin->geometry.x + drawin->border_width;
            ev->event_y -= drawin->geometry.y + drawin->border_width;
        }

        /* Push the drawable */
        luaA_object_push(L, drawin);
        luaA_object_push_item(L, -1, drawin->drawable);
        /* and handle the button raw button event */
        event_emit_button(L, ev);
        lua_pop(L, 1);
        /* check if any button object matches */
        event_button_callback(ev, &drawin->buttons, L, -1, 1, NULL);
        /* Either we are receiving this due to ButtonPress/Release on the root
         * window or because we grabbed the button on the window. In the later
         * case we have to call AllowEvents.
         * Use AsyncPointer instead of ReplayPointer so that the event is
         * "eaten" instead of being handled again on the root window.
         */
        if(ev->child == XCB_NONE)
            xcb_allow_events(globalconf.connection,
                             XCB_ALLOW_ASYNC_POINTER,
                             ev->time);
    }
    else if((c = client_getbyframewin(ev->event)) || (c = client_getbywin(ev->event)))
    {
        /* For clicks inside of c->window, we get two events. Once because of a
         * passive grab on c->window and then again for c->frame_window.
         * Ignore the second event (identifiable by ev->child != XCB_NONE).
         */
        if (ev->event != c->frame_window || ev->child == XCB_NONE)
        {
            luaA_object_push(L, c);
            if (c->window == ev->event)
            {
                /* Button event into the client itself (not titlebar), translate
                 * into the frame window.
                 */
                ev->event_x += c->titlebar[CLIENT_TITLEBAR_LEFT].size;
                ev->event_y += c->titlebar[CLIENT_TITLEBAR_TOP].size;
            }
            /* And handle the button raw button event */
            event_emit_button(L, ev);
            /* then check if a titlebar was "hit" */
            if (c->frame_window == ev->event)
            {
                int x = ev->event_x, y = ev->event_y;
                drawable_t *d = client_get_drawable_offset(c, &x, &y);
                if (d)
                {
                    /* Copy the event so that we can fake x/y */
                    xcb_button_press_event_t event = *ev;
                    event.event_x = x;
                    event.event_y = y;
                    luaA_object_push_item(L, -1, d);
                    event_emit_button(L, &event);
                    lua_pop(L, 1);
                }
            }
            /* then check if any button objects match */
            event_button_callback(ev, &c->buttons, L, -1, 1, NULL);
        }
        xcb_allow_events(globalconf.connection,
                         XCB_ALLOW_REPLAY_POINTER,
                         ev->time);
    }
    else if(ev->child == XCB_NONE)
        if(globalconf.screen->root == ev->event)
        {
            event_button_callback(ev, &globalconf.buttons, L, 0, 0, NULL);
            return;
        }
}
예제 #7
0
파일: dri_test.c 프로젝트: wwzbwwzb/truck
int main(void)
{
	xcb_connection_t    *c;
	xcb_screen_t        *s;
	xcb_window_t         w;
	xcb_gcontext_t       g;
	xcb_generic_event_t *e;
	uint32_t             mask;
	uint32_t             values[2];
	int                  done = 0;

	/* open connection with the server */
	c = xcb_connect(NULL,NULL);
	if (xcb_connection_has_error(c)) {
		printf("Cannot open display\n");
		exit(1);
	}

	/* get the first screen */
	s = xcb_setup_roots_iterator( xcb_get_setup(c) ).data;

  G.conn = c;
  G.s= s;

  //enable mouse event
  xcb_cursor_t cursor;
  xcb_font_t cursor_font=0;
  short glyph = 0x34; //cross
  xcb_grab_pointer_cookie_t grab_cookie;
  xcb_grab_pointer_reply_t *grab_reply;
  xcb_generic_error_t *err;
  cursor = xcb_generate_id (c);
  if (!cursor_font) {
    cursor_font = xcb_generate_id (c);
    xcb_open_font (c, cursor_font, strlen ("cursor"), "cursor");
  }

  xcb_create_glyph_cursor (c, cursor, cursor_font, cursor_font,
      glyph, glyph + 1,
      0, 0, 0, 0xffff, 0xffff, 0xffff);  /* rgb, rgb */

  grab_cookie = xcb_grab_pointer(c, 0, s->root,
  		XCB_EVENT_MASK_POINTER_MOTION |
     XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE,
     XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC,
     s->root, cursor, XCB_TIME_CURRENT_TIME);

  assert(grab_reply!=NULL);
  grab_reply = xcb_grab_pointer_reply (c, grab_cookie, &err);
  if (grab_reply->status != XCB_GRAB_STATUS_SUCCESS)
    printf("Can't grab the mouse.");

  printf("grab pointer cookie=0x%x\n", grab_cookie);
  xcb_allow_events (c, XCB_ALLOW_ASYNC_POINTER, XCB_TIME_CURRENT_TIME);  xcb_flush (c);
//  xcb_allow_events (c, XCB_ALLOW_SYNC_POINTER, XCB_TIME_CURRENT_TIME);  xcb_flush (c);

	while (!done ) {
 e = xcb_wait_for_event(c);
 if(e==NULL) printf("wait event error\n");
		//printf("\revent=>%d", e->response_type);
		switch (e->response_type & ~0x80) {
			case XCB_EXPOSE:    /* draw or redraw the window */
          printf("XCB_EXPOSE\n");
          draw_gc(w);
				break;
			case XCB_MOTION_NOTIFY:
				{
					static xcb_window_t    oldw;
        xcb_button_press_event_t *bp = (xcb_button_press_event_t *)e;
        w = bp->child; /* window selected */
        if(oldw!=w){
					oldw = w;
					printf("windowid = %x\n", w);
				}
				//draw it 
				draw_gc(w);
					}
				break;
      case XCB_BUTTON_PRESS:
        {
        xcb_button_press_event_t *bp = (xcb_button_press_event_t *)e;
        w = bp->child; /* window selected */
        if (w== XCB_WINDOW_NONE){
          printf("window select is root\n");
          w=s->root;
        }
        else
          printf("window = %x\n", w);
				draw_gc(w);
        done=1; printf("grab a child\n");
        break;
        }
		}
		free(e);
	}

  xcb_ungrab_pointer(c, XCB_TIME_CURRENT_TIME);

  draw_byxid(w);
  return 0;

#if 0
	/* create window */
	w = xcb_generate_id(c);
	mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
	values[0] = s->white_pixel;
	values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS;
	xcb_create_window(c, s->root_depth, w, s->root,
			10, 10, 100, 100, 1,
			XCB_WINDOW_CLASS_INPUT_OUTPUT, s->root_visual,
			mask, values);

	/* map (show) the window */
	xcb_map_window(c, w);

	xcb_flush(c);

	/* event loop */
	while (!done && (e = xcb_wait_for_event(c))) {
		switch (e->response_type & ~0x80) {
			case XCB_EXPOSE:    /* draw or redraw the window */
				xcb_poly_fill_rectangle(c, w, g,  1, &r);
				xcb_flush(c);
				break;
			case XCB_KEY_PRESS:  /* exit on key press */
				//gwj done = 1;
				break;
		}
		free(e);
	}
	/* close connection to server */
	xcb_disconnect(c);

	return 0;
  if(0){
  //draw image with xcb_put_image
  // creat gc and draw to parent window
	xcb_gcontext_t       g;
	g = xcb_generate_id(c);
	xcb_create_gc(c, g, child, 0,NULL);
  //xcb_poly_fill_rectangle(c, w, g,  1, &r); xcb_flush(c);

  int psize=geo->width * geo->height* (geo->depth/8);
  uint8_t *pbuf = malloc(psize);
  xcb_void_cookie_t ck;
  printf("malloc pbuf=0x%x size=%d\n",pbuf, psize);
  memset(pbuf, 0x18, psize);

  ck = xcb_put_image_checked(c, XCB_IMAGE_FORMAT_Z_PIXMAP,
      child, g,
      geo->width, geo->height , 0, 0,
       0, geo->depth,
     psize, pbuf);

	//BadMatch=8 BadLength=16
    xcb_generic_error_t *err;
    err = xcb_request_check (c, ck);
    if (err)
    {
      int code = err->error_code;
      free (err);
      printf("put image error %d\n", code);
      assert (code != 0);
    }   
  }
  printf("depth =%d\n", geo->depth);
	/* create black graphics context */
#endif
}
bool ZealNativeEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
    enabled = true;
#ifdef WIN32
    MSG* msg = static_cast<MSG*>(message);

    if(WM_HOTKEY == msg->message && msg->wParam == 10) {
        emit gotHotKey();
        return true;
    }
#elsif LINUX // WIN32 or LINUX
    xcb_generic_event_t* ev = static_cast<xcb_generic_event_t*>(message);
    if(((ev->response_type&127) == XCB_KEY_PRESS || (ev->response_type&127) == XCB_KEY_RELEASE) && !hotKey.isEmpty()) {
        // XCB_KEY_RELEASE must be ignored by Qt because otherwise it causes SIGSEGV in QXcbKeyboard::handleKeyReleaseEvent
        xcb_connection_t  *c = static_cast<xcb_connection_t*>(
              ((QGuiApplication*)QGuiApplication::instance())->
                    platformNativeInterface()->nativeResourceForWindow("connection", 0));
        xcb_key_press_event_t *event = (xcb_key_press_event_t *)ev;

        xcb_key_symbols_t *keysyms = xcb_key_symbols_alloc(c);
        xcb_keycode_t *keycodes = xcb_key_symbols_get_keycode(keysyms, GetX11Key(hotKey[0]));

        bool found = false;
        // found=true means either (a) complete hotkey was pressed, or (b) any of its separate
        // keys was released. We return true in both cases, because key releases while window
        // is not present cause SIGSEGV in QXcbKeyboard::handleKeyReleaseEvent
        if((ev->response_type&127) == XCB_KEY_RELEASE) {
            QList<QPair<int, Qt::Modifier> > modifiers;
            modifiers.append(qMakePair(XK_Alt_L, Qt::ALT));
            modifiers.append(qMakePair(XK_Alt_R, Qt::ALT));
            modifiers.append(qMakePair(XK_Control_L, Qt::CTRL));
            modifiers.append(qMakePair(XK_Control_R, Qt::CTRL));
            modifiers.append(qMakePair(XK_Meta_L, Qt::META));
            modifiers.append(qMakePair(XK_Meta_R, Qt::META));
            for(auto modifier : modifiers) {
                if(!(hotKey[0] & modifier.second)) {
                    continue;
                }
                xcb_keycode_t *mod_keycodes = xcb_key_symbols_get_keycode(keysyms, modifier.first);
                if(mod_keycodes == nullptr) continue;
                int i = 0;
                while(mod_keycodes[i] != XCB_NO_SYMBOL) {
                    if(event->detail == mod_keycodes[i]) {
                        found = true;
                    }
                    i += 1;
                }
                free(mod_keycodes);
            }
        }
        int i = 0;
        while(keycodes[i] != XCB_NO_SYMBOL) {
            if(event->detail == keycodes[i]) {
                bool modifiers_present = true;
                if(hotKey[0] & Qt::ALT) {
                    if(!(event->state & GetModifier(c, keysyms, XK_Alt_L) || event->state & GetModifier(c, keysyms,  XK_Alt_R))) {
                        modifiers_present = false;
                    }
                }
                if(hotKey[0] & Qt::CTRL) {
                    if(!(event->state & GetModifier(c, keysyms, XK_Control_L) || event->state & GetModifier(c, keysyms,  XK_Control_R))) {
                        modifiers_present = false;
                    }
                }
                if(hotKey[0] & Qt::META) {
                    if(!(event->state & GetModifier(c, keysyms, XK_Meta_L) || event->state & GetModifier(c, keysyms,  XK_Meta_R))) {
                        modifiers_present = false;
                    }
                }
                if(hotKey[0] & Qt::SHIFT) {
                    if(!(event->state & GetModifier(c, keysyms, XK_Shift_L) || event->state & GetModifier(c, keysyms,  XK_Shift_R))) {
                        modifiers_present = false;
                    }
                }
                if(enabled && modifiers_present) {
                    xcb_allow_events(c, XCB_ALLOW_ASYNC_KEYBOARD, event->time);
                    if((ev->response_type&127) == XCB_KEY_PRESS) {
                        emit gotHotKey();
                    }
                    found = true;
                } else {
                    if((ev->response_type&127) == XCB_KEY_RELEASE) {
                        found = true;
                    }
                    xcb_allow_events(c, XCB_ALLOW_REPLAY_KEYBOARD, event->time);
                }
                break;
            }
            i += 1;
        }
        free(keysyms);
        free(keycodes);
        if(found) return true;
    }
#endif // WIN32 or LINUX
    return false;
}
예제 #9
0
파일: event.c 프로젝트: azuwis/awesome
/** The button press event handler.
 * \param data The type of mouse event.
 * \param connection The connection to the X server.
 * \param ev The event.
 */
static int
event_handle_button(void *data, xcb_connection_t *connection, xcb_button_press_event_t *ev)
{
    int screen;
    const int nb_screen = xcb_setup_roots_length(xcb_get_setup(connection));
    client_t *c;
    wibox_t *wibox;

    /* ev->state is
     * button status (8 bits) + modifiers status (8 bits)
     * we don't care for button status that we get, especially on release, so
     * drop them */
    ev->state &= 0x00ff;

    event_handle_mousegrabber(ev->root_x, ev->root_y, ev->state);

    if((wibox = wibox_getbywin(ev->event))
       || (wibox = wibox_getbywin(ev->child)))
    {
        /* If the wibox is child, then x,y are
         * relative to root window */
        if(wibox->sw.window == ev->child)
        {
            ev->event_x -= wibox->sw.geometry.x;
            ev->event_y -= wibox->sw.geometry.y;
        }

        /* check if we match a binding on the wibox */
        button_array_t *b = &wibox->buttons;

        for(int i = 0; i < b->len; i++)
            if(ev->detail == b->tab[i]->button
               && ev->state == b->tab[i]->mod)
                switch(ev->response_type)
                {
                  case XCB_BUTTON_PRESS:
                    if(b->tab[i]->press != LUA_REFNIL)
                    {
                        wibox_push(globalconf.L, wibox);
                        luaA_dofunction(globalconf.L, b->tab[i]->press, 1, 0);
                    }
                    break;
                  case XCB_BUTTON_RELEASE:
                    if(b->tab[i]->release != LUA_REFNIL)
                    {
                        wibox_push(globalconf.L, wibox);
                        luaA_dofunction(globalconf.L, b->tab[i]->release, 1, 0);
                    }
                    break;
                }

        /* then try to match a widget binding */
        widget_t *w = widget_getbycoords(wibox->position, &wibox->widgets,
                                         wibox->sw.geometry.width,
                                         wibox->sw.geometry.height,
                                         &ev->event_x, &ev->event_y);
        if(w)
        {
            b = &w->buttons;

            for(int i = 0; i < b->len; i++)
                if(ev->detail == b->tab[i]->button
                   && ev->state == b->tab[i]->mod)
                    switch(ev->response_type)
                    {
                      case XCB_BUTTON_PRESS:
                        if(b->tab[i]->press != LUA_REFNIL)
                        {
                            wibox_push(globalconf.L, wibox);
                            luaA_dofunction(globalconf.L, b->tab[i]->press, 1, 0);
                        }
                        break;
                      case XCB_BUTTON_RELEASE:
                        if(b->tab[i]->release != LUA_REFNIL)
                        {
                            wibox_push(globalconf.L, wibox);
                            luaA_dofunction(globalconf.L, b->tab[i]->release, 1, 0);
                        }
                        break;
                    }
        }
        /* return even if no widget match */
        return 0;
    }
    else if((c = client_getbywin(ev->event)))
    {
        event_handle_mouse_button(c, ev->response_type, ev->detail, ev->state, &c->buttons);
        xcb_allow_events(globalconf.connection,
                         XCB_ALLOW_REPLAY_POINTER,
                         XCB_CURRENT_TIME);
    }
    else if(ev->child == XCB_NONE)
    {
        for(screen = 0; screen < nb_screen; screen++)
            if(xutil_screen_get(connection, screen)->root == ev->event)
            {
                event_handle_mouse_button(NULL, ev->response_type, ev->detail, ev->state, &globalconf.buttons);
                return 0;
            }
    }

    return 0;
}