From 2d05c3a37d56d7de8d75fc4f79e07428d82956f4 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 31 Dec 2010 01:38:17 +0100 Subject: [PATCH] Fix dragging floating containers / click handling --- include/con.h | 7 +++++ include/floating.h | 6 ++++ src/click.c | 72 +++++++++++++++++++++++++++++----------------- src/con.c | 21 ++++++++++++++ src/floating.c | 10 +++++++ 5 files changed, 90 insertions(+), 26 deletions(-) diff --git a/include/con.h b/include/con.h index 820d847d..1abc09a0 100644 --- a/include/con.h +++ b/include/con.h @@ -54,6 +54,13 @@ Con *con_get_fullscreen_con(Con *con); */ bool con_is_floating(Con *con); +/** + * Checks if the given container is either floating or inside some floating + * container. It returns the FLOATING_CON container. + * + */ +Con *con_inside_floating(Con *con); + /** * Returns the container with the given client window ID or NULL if no such * container exists. diff --git a/include/floating.h b/include/floating.h index a312daee..c3935252 100644 --- a/include/floating.h +++ b/include/floating.h @@ -53,6 +53,12 @@ void floating_disable(Con *con, bool automatic); */ void toggle_floating_mode(Con *con, bool automatic); +/** + * Raises the given container in the list of floating containers + * + */ +void floating_raise_con(Con *con); + #if 0 /** * Removes the floating client from its workspace and attaches it to the new diff --git a/src/click.c b/src/click.c index a4d9181a..243820cb 100644 --- a/src/click.c +++ b/src/click.c @@ -237,26 +237,47 @@ static bool floating_mod_on_tiled_client(xcb_connection_t *conn, Client *client, #endif int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_event_t *event) { + /* TODO: dragging floating windows by grabbing their decoration does not + * work right now. We need to somehow recognize that special case: either + * we check if the con with the clicked decoration is the only con inside + * its parent (so that you can only drag single floating windows, not + * floating containers with multiple windows) *or* we somehow find out + * which decoration(s) are at the top and enable grabbing for them while + * resizing for the others. Maybe we could process the resizing parameters + * first and check if resizing is possible: if yes, resize, if not, drag. + * + * Also raise on click on decoration is not working. */ Con *con; DLOG("Button %d pressed on window 0x%08x\n", event->state, event->event); con = con_by_window_id(event->event); - bool border_click = false; - if (con == NULL) { + bool border_click = (con == NULL); + const uint32_t mod = config.floating_modifier; + bool mod_pressed = (mod != 0 && (event->state & mod) == mod); + + if (border_click) con = con_by_frame_id(event->event); - border_click = true; + + DLOG("border_click = %d, mod_pressed = %d\n", border_click, mod_pressed); + + Con *clicked_into = NULL; + + Con *child; + TAILQ_FOREACH(child, &(con->nodes_head), nodes) { + if (!rect_contains(child->deco_rect, event->event_x, event->event_y)) + continue; + + clicked_into = child; + break; } - DLOG("border_click = %d\n", border_click); - //if (con && con->type == CT_FLOATING_CON) - //con = TAILQ_FIRST(&(con->nodes_head)); + + DLOG("clicked_into = %p\n", clicked_into); /* See if this was a click with the configured modifier. If so, we need * to move around the client if it was floating. if not, we just process * as usual. */ DLOG("state = %d, floating_modifier = %d\n", event->state, config.floating_modifier); - if (border_click || - (config.floating_modifier != 0 && - (event->state & config.floating_modifier) == config.floating_modifier)) { + if (border_click || mod_pressed) { if (con == NULL) { LOG("Not handling, floating_modifier was pressed and no client found\n"); return 1; @@ -268,11 +289,10 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_ return 1; } #endif + Con *floatingcon = con; if ((border_click && con->type == CT_FLOATING_CON) || - (!border_click && con_is_floating(con))) { - /* floating operations are always on the container around - * the "payload container", so make sure we use the right one */ - Con *floatingcon = (border_click ? con : con->parent); + ((floatingcon = con_inside_floating(con)) != NULL && + clicked_into == NULL)) { LOG("button %d pressed\n", event->detail); if (event->detail == 1) { LOG("left mouse button, dragging\n"); @@ -287,23 +307,23 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_ } } - /* click to focus */ - con_focus(con); - - Con *clicked_into = NULL; - - Con *child; - TAILQ_FOREACH(child, &(con->nodes_head), nodes) { - if (!rect_contains(child->deco_rect, event->event_x, event->event_y)) - continue; + /* click to focus, either on the clicked window or its child if thas was a + * click into a child decoration */ + con_focus((clicked_into ? clicked_into : con)); - clicked_into = child; - con_focus(child); - break; - } + /* for floating containers, we also want to raise them on click */ + Con *floatingcon = con_inside_floating(con); + if (floatingcon != NULL) + floating_raise_con(floatingcon); tree_render(); + /* if we clicked into a child decoration on a stacked/tabbed container, we + * are done and don’t want to resize */ + if (clicked_into && + (con->layout == L_STACKED || con->layout == L_TABBED)) + return 1; + /* check if this was a click on the window border (and on which one) */ Rect bsr = con_border_style_rect(con); DLOG("BORDER x = %d, y = %d for con %p, window 0x%08x, border_click = %d, clicked_into = %p\n", diff --git a/src/con.c b/src/con.c index dc8bc354..0f2374f6 100644 --- a/src/con.c +++ b/src/con.c @@ -157,6 +157,7 @@ void con_detach(Con *con) { */ void con_focus(Con *con) { assert(con != NULL); + DLOG("con_focus = %p\n", con); /* 1: set focused-pointer to the new con */ /* 2: exchange the position of the container in focus stack of the parent all the way up */ @@ -170,6 +171,7 @@ void con_focus(Con *con) { con->urgent = false; workspace_update_urgent_flag(con_get_workspace(con)); } + DLOG("con_focus done = %p\n", con); } /* @@ -287,6 +289,25 @@ bool con_is_floating(Con *con) { return (con->floating >= FLOATING_AUTO_ON); } +/* + * Checks if the given container is either floating or inside some floating + * container. It returns the FLOATING_CON container. + * + */ +Con *con_inside_floating(Con *con) { + assert(con != NULL); + if (con->type == CT_FLOATING_CON) + return con; + + if (con->floating >= FLOATING_AUTO_ON) + return con->parent; + + if (con->type == CT_WORKSPACE) + return NULL; + + return con_inside_floating(con->parent); +} + /* * Returns the container with the given client window ID or NULL if no such * container exists. diff --git a/src/floating.c b/src/floating.c index a88d498a..c50cf494 100644 --- a/src/floating.c +++ b/src/floating.c @@ -172,6 +172,16 @@ void toggle_floating_mode(Con *con, bool automatic) { floating_enable(con, automatic); } +/* + * Raises the given container in the list of floating containers + * + */ +void floating_raise_con(Con *con) { + DLOG("Raising floating con %p / %s\n", con, con->name); + TAILQ_REMOVE(&(con->parent->floating_head), con, floating_windows); + TAILQ_INSERT_TAIL(&(con->parent->floating_head), con, floating_windows); +} + DRAGGING_CB(drag_window_callback) { struct xcb_button_press_event_t *event = extra; -- 2.39.5