]> git.lizzy.rs Git - bspwm.git/commitdiff
Reinstate built-in pointer bindings
authorBastien Dejean <nihilhill@gmail.com>
Thu, 7 Apr 2016 16:08:32 +0000 (18:08 +0200)
committerBastien Dejean <nihilhill@gmail.com>
Thu, 7 Apr 2016 16:08:32 +0000 (18:08 +0200)
32 files changed:
Makefile
bspwm.c
bspwm.h
contrib/bash_completion
contrib/zsh_completion
doc/TODO.md
doc/bspwm.1
doc/bspwm.1.asciidoc
events.c
events.h
ewmh.c
ewmh.h
examples/sxhkdrc
helpers.h
messages.c
messages.h
monitor.c
parse.c
parse.h
pointer.c
pointer.h
query.c
query.h
restore.c
rule.c
settings.c
settings.h
subscribe.c
tree.c
types.h
window.c
window.h

index 331408f463d0d6c3306631973f2df7a8468e65ed..41c833834d1fc0eb78b0cdf48f7b4077c13dd1c7 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ VERSION := $(shell $(VERCMD) || cat VERSION)
 
 CPPFLAGS += -D_POSIX_C_SOURCE=200112L -DVERSION=\"$(VERSION)\"
 CFLAGS   += -std=c99 -pedantic -Wall -Wextra
-LDLIBS    = -lm -lxcb -lxcb-util -lxcb-icccm -lxcb-ewmh -lxcb-randr -lxcb-xinerama
+LDLIBS    = -lm -lxcb -lxcb-util -lxcb-keysyms -lxcb-icccm -lxcb-ewmh -lxcb-randr -lxcb-xinerama
 
 PREFIX    ?= /usr/local
 BINPREFIX ?= $(PREFIX)/bin
diff --git a/bspwm.c b/bspwm.c
index a2ae55fa31eac64b5fa94b48e138588cc54c506e..52b9a7749562e16524f7967a4524545b658728ec 100644 (file)
--- a/bspwm.c
+++ b/bspwm.c
@@ -39,6 +39,7 @@
 #include "monitor.h"
 #include "settings.h"
 #include "messages.h"
+#include "pointer.h"
 #include "events.h"
 #include "common.h"
 #include "window.h"
@@ -191,6 +192,7 @@ int main(int argc, char *argv[])
        cleanup();
        close(sock_fd);
        unlink(socket_path);
+       ungrab_buttons();
        xcb_ewmh_connection_wipe(ewmh);
        xcb_destroy_window(dpy, meta_window);
        xcb_destroy_window(dpy, motion_recorder);
@@ -209,7 +211,6 @@ void init(void)
        stack_head = stack_tail = NULL;
        subscribe_head = subscribe_tail = NULL;
        pending_rule_head = pending_rule_tail = NULL;
-       last_motion_time = last_motion_x = last_motion_y = 0;
        auto_raise = sticky_still = record_history = true;
        randr_base = 0;
        exit_status = 0;
@@ -219,6 +220,8 @@ void setup(void)
 {
        init();
        ewmh_init();
+       pointer_init();
+
        screen = xcb_setup_roots_iterator(xcb_get_setup(dpy)).data;
 
        if (screen == NULL) {
@@ -227,6 +230,7 @@ void setup(void)
 
        root = screen->root;
        register_events();
+       grab_buttons();
 
        screen_width = screen->width_in_pixels;
        screen_height = screen->height_in_pixels;
@@ -315,7 +319,6 @@ void setup(void)
        ewmh_update_number_of_desktops();
        ewmh_update_desktop_names();
        ewmh_update_current_desktop();
-       frozen_pointer = make_pointer_state();
        xcb_get_input_focus_reply_t *ifo = xcb_get_input_focus_reply(dpy, xcb_get_input_focus(dpy), NULL);
        if (ifo != NULL && (ifo->focus == XCB_INPUT_FOCUS_POINTER_ROOT || ifo->focus == XCB_NONE)) {
                clear_input_focus();
@@ -351,7 +354,6 @@ void cleanup(void)
        }
 
        empty_history();
-       free(frozen_pointer);
 }
 
 bool check_connection (xcb_connection_t *dpy)
diff --git a/bspwm.h b/bspwm.h
index 61942e5b03cc531a8907f98b1ce5f8463e443d16..3db471b61be009e4d87ec4ac4388ad9998048ef1 100644 (file)
--- a/bspwm.h
+++ b/bspwm.h
@@ -59,7 +59,6 @@ subscriber_list_t *subscribe_tail;
 pending_rule_t *pending_rule_head;
 pending_rule_t *pending_rule_tail;
 
-pointer_state_t *frozen_pointer;
 xcb_window_t meta_window;
 xcb_window_t motion_recorder;
 xcb_atom_t WM_TAKE_FOCUS;
index a568221349e4d0e4b1efcb35419ef1e1eca45313..99efd9853cc6aa77cb46ef610d2d0c9ab131a30a 100644 (file)
@@ -1,7 +1,7 @@
 _bspc() {
-       local commands='node desktop monitor query pointer rule restore wm subscribe config quit'
+       local commands='node desktop monitor query rule restore wm subscribe config quit'
 
-       local settings='external_rules_command status_prefix normal_border_color active_border_color focused_border_color presel_feedback_color border_width window_gap top_padding right_padding bottom_padding left_padding split_ratio initial_polarity borderless_monocle gapless_monocle leaf_monocle focus_follows_pointer pointer_follows_focus pointer_follows_monitor history_aware_focus focus_by_distance ignore_ewmh_focus center_pseudo_tiled remove_disabled_monitors remove_unplugged_monitors merge_overlapping_monitors'
+       local settings='external_rules_command status_prefix normal_border_color active_border_color focused_border_color presel_feedback_color border_width window_gap top_padding right_padding bottom_padding left_padding split_ratio initial_polarity borderless_monocle gapless_monocle leaf_monocle pointer_modifier click_to_focus focus_follows_pointer pointer_follows_focus pointer_follows_monitor history_aware_focus focus_by_distance ignore_ewmh_focus center_pseudo_tiled honor_size_hints remove_disabled_monitors remove_unplugged_monitors merge_overlapping_monitors'
 
        COMPREPLY=()
 
index 31807937621f063a6684f1e5624552126c754e67..fbcbc853d1c1e3c193dde349d2b7a798170f6bfc 100644 (file)
@@ -2,8 +2,8 @@
 
 _bspc() {
        local -a commands settings
-       commands=('node' 'desktop' 'monitor' 'query' 'pointer' 'rule' 'restore' 'wm' 'subscribe' 'config' 'quit')
-       settings=('external_rules_command' 'status_prefix' 'normal_border_color' 'active_border_color' 'focused_border_color' 'presel_feedback_color' 'border_width' 'window_gap' 'top_padding' 'right_padding' 'bottom_padding' 'left_padding' 'split_ratio' 'initial_polarity' 'borderless_monocle' 'gapless_monocle' 'leaf_monocle' 'focus_follows_pointer' 'pointer_follows_focus' 'pointer_follows_monitor' 'history_aware_focus' 'focus_by_distance' 'ignore_ewmh_focus' 'center_pseudo_tiled' 'remove_disabled_monitors' 'remove_unplugged_monitors' 'merge_overlapping_monitors')
+       commands=('node' 'desktop' 'monitor' 'query' 'rule' 'restore' 'wm' 'subscribe' 'config' 'quit')
+       settings=('external_rules_command' 'status_prefix' 'normal_border_color' 'active_border_color' 'focused_border_color' 'presel_feedback_color' 'border_width' 'window_gap' 'top_padding' 'right_padding' 'bottom_padding' 'left_padding' 'split_ratio' 'initial_polarity' 'borderless_monocle' 'gapless_monocle' 'leaf_monocle' 'pointer_modifier' 'click_to_focus' 'focus_follows_pointer' 'pointer_follows_focus' 'pointer_follows_monitor' 'history_aware_focus' 'focus_by_distance' 'ignore_ewmh_focus' 'center_pseudo_tiled' 'honor_size_hints' 'remove_disabled_monitors' 'remove_unplugged_monitors' 'merge_overlapping_monitors')
        if (( CURRENT == 2 )) ; then
                _values 'command' "$commands[@]"
        elif (( CURRENT == 3 )) ; then
index 0eff848a0d21f036abc5c6dc51f6f5af9d39cdd9..602c175efc746760ef86f696016edf0cfb7bf3ca 100644 (file)
@@ -1,8 +1,3 @@
-- Add zoom feature (view point distinct from root).
-- Add receptacles (leaves with NULL client pointer).
-- Handle window size constraints specified by size hints.
 - Add support for showing/hiding nodes.
-- Implement all the MUSTs in the EWMH specification.
-- Set more attributes in `make_client` (instead of doing it in `apply_rules`) and don't pass `XCB_NONE` as argument.
+- Add zoom feature (view point distinct from root).
 - Use BSD `sys/{queue/tree}.h` for {list,tree} structures?
-- Handle malloc failure everywhere.
index 4f5931ea46e1737cc249f1513f173bf36d913828..b4f9fd1e90f10c9fc809237166b6cb05237f974e 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: bspwm
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 03/26/2016
+.\"      Date: 04/07/2016
 .\"    Manual: Bspwm Manual
-.\"    Source: Bspwm 0.9.1-7-geb209d8
+.\"    Source: Bspwm 0.9.1-11-ge1b5f77
 .\"  Language: English
 .\"
-.TH "BSPWM" "1" "03/26/2016" "Bspwm 0\&.9\&.1\-7\-geb209d8" "Bspwm Manual"
+.TH "BSPWM" "1" "04/07/2016" "Bspwm 0\&.9\&.1\-11\-ge1b5f77" "Bspwm Manual"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -552,6 +552,24 @@ and the current preselection direction matches
 Set the splitting ratio of the preselection area\&.
 .RE
 .PP
+\fB\-v\fR, \fB\-\-move\fR \fIdx\fR \fIdy\fR
+.RS 4
+Move the selected window by
+\fIdx\fR
+pixels horizontally and
+\fIdy\fR
+pixels vertically\&.
+.RE
+.PP
+\fB\-z\fR, \fB\-\-resize\fR top|left|bottom|right|top_left|top_right|bottom_right|bottom_left \fIdx\fR \fIdy\fR
+.RS 4
+Resize the selected window by moving the given handle by
+\fIdx\fR
+pixels horizontally and
+\fIdy\fR
+pixels vertically\&.
+.RE
+.PP
 \fB\-r\fR, \fB\-\-ratio\fR \fIRATIO\fR|(+|\-)\fIPIXELS\fR
 .RS 4
 Set the splitting ratio of the selected node (0 <
@@ -848,42 +866,6 @@ Enable or disable the recording of node focus history\&.
 Print the current status information\&.
 .RE
 .RE
-.SS "Pointer"
-.sp
-.it 1 an-trap
-.nr an-no-space-flag 1
-.nr an-break-flag 1
-.br
-.ps +1
-\fBGeneral Syntax\fR
-.RS 4
-.sp
-pointer \fICOMMANDS\fR
-.RE
-.sp
-.it 1 an-trap
-.nr an-no-space-flag 1
-.nr an-break-flag 1
-.br
-.ps +1
-\fBCommands\fR
-.RS 4
-.PP
-\fB\-g\fR, \fB\-\-grab\fR focus|move|resize_side|resize_corner
-.RS 4
-Initiate the given pointer action\&.
-.RE
-.PP
-\fB\-t\fR, \fB\-\-track\fR <x> <y>
-.RS 4
-Pass the pointer root coordinates for the current pointer action\&.
-.RE
-.PP
-\fB\-u\fR, \fB\-\-ungrab\fR
-.RS 4
-Terminate the current pointer action\&.
-.RE
-.RE
 .SS "Rule"
 .sp
 .it 1 an-trap
@@ -1063,6 +1045,24 @@ Set the desktop layout to
 if there\(cqs only one tiled window in the tree\&.
 .RE
 .PP
+\fIpointer_modifier\fR
+.RS 4
+Keyboard modifier used for moving or resizing windows\&. Accept the following values:
+\fBshift\fR,
+\fBcontrol\fR,
+\fBlock\fR,
+\fBmod1\fR,
+\fBmod2\fR,
+\fBmod3\fR,
+\fBmod4\fR,
+\fBmod5\fR\&.
+.RE
+.PP
+\fIclick_to_focus\fR
+.RS 4
+Focus a window (or a monitor) by clicking it\&.
+.RE
+.PP
 \fIfocus_follows_pointer\fR
 .RS 4
 Focus the window under the pointer\&.
@@ -1089,6 +1089,11 @@ Center pseudo tiled windows into their tiling rectangles\&. Defaults to
 \fItrue\fR\&.
 .RE
 .PP
+\fIhonor_size_hints\fR
+.RS 4
+Apply ICCCM window size hints\&.
+.RE
+.PP
 \fIremove_disabled_monitors\fR
 .RS 4
 Consider disabled monitors as disconnected\&.
@@ -1121,6 +1126,29 @@ Size of the gap that separates windows\&.
 .RS 4
 Window border width\&.
 .RE
+.SH "POINTER BINDINGS"
+.PP
+\fIbutton1\fR
+.RS 4
+Focus the window under the pointer if
+\fIclick_to_focus\fR
+is set\&.
+.RE
+.PP
+\fIpointer_modifier\fR + \fIbutton1\fR
+.RS 4
+Move the window under the pointer\&.
+.RE
+.PP
+\fIpointer_modifier\fR + \fIbutton2\fR
+.RS 4
+Resize the window under the pointer by dragging the nearest side\&.
+.RE
+.PP
+\fIpointer_modifier\fR + \fIbutton3\fR
+.RS 4
+Resize the window under the pointer by dragging the nearest corner\&.
+.RE
 .SH "EVENTS"
 .PP
 \fIreport\fR
index a30b95a7bbd1c2de0ab1669e2b6a8631450cad29..e324f793c1ff77ffe2dad1def6a433399fee84d0 100644 (file)
@@ -340,6 +340,12 @@ Commands
 *-o*, *--presel-ratio* 'RATIO'::
        Set the splitting ratio of the preselection area.
 
+*-v*, *--move* 'dx' 'dy'::
+       Move the selected window by 'dx' pixels horizontally and 'dy' pixels vertically.
+
+*-z*, *--resize* top|left|bottom|right|top_left|top_right|bottom_right|bottom_left 'dx' 'dy'::
+       Resize the selected window by moving the given handle by 'dx' pixels horizontally and 'dy' pixels vertically.
+
 *-r*, *--ratio* 'RATIO'|(+|-)'PIXELS'::
        Set the splitting ratio of the selected node (0 < 'RATIO' < 1).
 
@@ -502,26 +508,6 @@ Commands
 *-g*, *--get-status*::
        Print the current status information.
 
-Pointer
-~~~~~~~
-
-General Syntax
-^^^^^^^^^^^^^^
-
-pointer 'COMMANDS'
-
-Commands
-^^^^^^^^
-
-*-g*, *--grab* focus|move|resize_side|resize_corner::
-       Initiate the given pointer action.
-
-*-t*, *--track* <x> <y>::
-       Pass the pointer root coordinates for the current pointer action.
-
-*-u*, *--ungrab*::
-       Terminate the current pointer action.
-
 Rule
 ~~~~
 
@@ -624,6 +610,12 @@ Global Settings
 'single_monocle'::
        Set the desktop layout to *monocle* if there's only one tiled window in the tree.
 
+'pointer_modifier'::
+       Keyboard modifier used for moving or resizing windows. Accept the following values: *shift*, *control*, *lock*, *mod1*, *mod2*, *mod3*, *mod4*, *mod5*.
+
+'click_to_focus'::
+       Focus a window (or a monitor) by clicking it.
+
 'focus_follows_pointer'::
        Focus the window under the pointer.
 
@@ -639,6 +631,9 @@ Global Settings
 'center_pseudo_tiled'::
        Center pseudo tiled windows into their tiling rectangles. Defaults to 'true'.
 
+'honor_size_hints'::
+       Apply ICCCM window size hints.
+
 'remove_disabled_monitors'::
        Consider disabled monitors as disconnected.
 
@@ -669,6 +664,20 @@ Node Settings
 'border_width'::
        Window border width.
 
+Pointer Bindings
+----------------
+
+'button1'::
+       Focus the window under the pointer if 'click_to_focus' is set.
+
+'pointer_modifier' + 'button1'::
+       Move the window under the pointer.
+
+'pointer_modifier' + 'button2'::
+       Resize the window under the pointer by dragging the nearest side.
+
+'pointer_modifier' + 'button3'::
+       Resize the window under the pointer by dragging the nearest corner.
 
 Events
 ------
index 9b5753ca0d124f876ee42f9a9359c02060104c32..e2095d3cbede4a992ad557d818c602763b51401d 100644 (file)
--- a/events.c
+++ b/events.c
@@ -32,6 +32,7 @@
 #include "subscribe.h"
 #include "tree.h"
 #include "window.h"
+#include "pointer.h"
 #include "events.h"
 
 void handle_event(xcb_generic_event_t *evt)
@@ -59,6 +60,9 @@ void handle_event(xcb_generic_event_t *evt)
                case XCB_ENTER_NOTIFY:
                        enter_notify(evt);
                        break;
+               case XCB_BUTTON_PRESS:
+                       button_press(evt);
+                       break;
                case XCB_MOTION_NOTIFY:
                        motion_notify(evt);
                        break;
@@ -90,54 +94,9 @@ void configure_request(xcb_generic_event_t *evt)
        coordinates_t loc;
        bool is_managed = locate_window(e->window, &loc);
        client_t *c = (is_managed ? loc.node->client : NULL);
-       int w = 0, h = 0;
-
-       if (is_managed && !IS_FLOATING(c)) {
-               if (e->value_mask & XCB_CONFIG_WINDOW_X) {
-                       c->floating_rectangle.x = e->x;
-               }
-               if (e->value_mask & XCB_CONFIG_WINDOW_Y) {
-                       c->floating_rectangle.y = e->y;
-               }
-               if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
-                       w = e->width;
-               }
-               if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
-                       h = e->height;
-               }
-
-               if (w != 0) {
-                       restrain_floating_width(c, &w);
-                       c->floating_rectangle.width = w;
-               }
-
-               if (h != 0) {
-                       restrain_floating_height(c, &h);
-                       c->floating_rectangle.height = h;
-               }
-
-               xcb_configure_notify_event_t evt;
-               unsigned int bw = c->border_width;
-
-               xcb_rectangle_t rect = get_rectangle(loc.desktop, loc.node);
-
-               evt.response_type = XCB_CONFIGURE_NOTIFY;
-               evt.event = e->window;
-               evt.window = e->window;
-               evt.above_sibling = XCB_NONE;
-               evt.x = rect.x;
-               evt.y = rect.y;
-               evt.width = rect.width;
-               evt.height = rect.height;
-               evt.border_width = bw;
-               evt.override_redirect = false;
+       uint16_t width, height;
 
-               xcb_send_event(dpy, false, e->window, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *) &evt);
-
-               if (c->state == STATE_PSEUDO_TILED) {
-                       arrange(loc.monitor, loc.desktop);
-               }
-       } else {
+       if (!is_managed) {
                uint16_t mask = 0;
                uint32_t values[7];
                unsigned short i = 0;
@@ -145,67 +104,109 @@ void configure_request(xcb_generic_event_t *evt)
                if (e->value_mask & XCB_CONFIG_WINDOW_X) {
                        mask |= XCB_CONFIG_WINDOW_X;
                        values[i++] = e->x;
-                       if (is_managed) {
-                               c->floating_rectangle.x = e->x;
-                       }
                }
 
                if (e->value_mask & XCB_CONFIG_WINDOW_Y) {
                        mask |= XCB_CONFIG_WINDOW_Y;
                        values[i++] = e->y;
-                       if (is_managed) {
-                               c->floating_rectangle.y = e->y;
-                       }
                }
 
                if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
                        mask |= XCB_CONFIG_WINDOW_WIDTH;
-                       w = e->width;
-                       if (is_managed) {
-                               restrain_floating_width(c, &w);
-                               c->floating_rectangle.width = w;
-                       }
-                       values[i++] = w;
+                       values[i++] = e->width;
                }
 
                if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
                        mask |= XCB_CONFIG_WINDOW_HEIGHT;
-                       h = e->height;
-                       if (is_managed) {
-                               restrain_floating_height(c, &h);
-                               c->floating_rectangle.height = h;
-                       }
-                       values[i++] = h;
+                       values[i++] = e->height;
                }
 
-               if (!is_managed && e->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) {
+               if (e->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) {
                        mask |= XCB_CONFIG_WINDOW_BORDER_WIDTH;
                        values[i++] = e->border_width;
                }
 
-               if (!is_managed && e->value_mask & XCB_CONFIG_WINDOW_SIBLING) {
+               if (e->value_mask & XCB_CONFIG_WINDOW_SIBLING) {
                        mask |= XCB_CONFIG_WINDOW_SIBLING;
                        values[i++] = e->sibling;
                }
 
-               if (!is_managed && e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) {
+               if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) {
                        mask |= XCB_CONFIG_WINDOW_STACK_MODE;
                        values[i++] = e->stack_mode;
                }
 
                xcb_configure_window(dpy, e->window, mask, values);
 
-               if (is_managed && mask & XCB_CONFIG_WINDOW_X_Y_WIDTH_HEIGHT) {
-                       xcb_rectangle_t r = c->floating_rectangle;
-                       put_status(SBSC_MASK_NODE_GEOMETRY, "node_geometry 0x%08X 0x%08X 0x%08X %ux%u+%i+%i\n", loc.monitor->id, loc.desktop->id, e->window, r.width, r.height, r.x, r.y);
+       } else if (IS_FLOATING(c)) {
+               width = c->floating_rectangle.width;
+               height = c->floating_rectangle.height;
+
+               if (e->value_mask & XCB_CONFIG_WINDOW_X) {
+                       c->floating_rectangle.x = e->x;
                }
-       }
 
-       if (is_managed) {
+               if (e->value_mask & XCB_CONFIG_WINDOW_Y) {
+                       c->floating_rectangle.y = e->y;
+               }
+
+               if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
+                       width = e->width;
+               }
+
+               if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
+                       height = e->height;
+               }
+
+               apply_size_hints(c, &width, &height);
+               c->floating_rectangle.width = width;
+               c->floating_rectangle.height = height;
+               xcb_rectangle_t r = c->floating_rectangle;
+
+               window_move_resize(e->window, r.x, r.y, r.width, r.height);
+
+               put_status(SBSC_MASK_NODE_GEOMETRY, "node_geometry 0x%08X 0x%08X 0x%08X %ux%u+%i+%i\n", loc.monitor->id, loc.desktop->id, e->window, r.width, r.height, r.x, r.y);
+
                monitor_t *m = monitor_from_client(c);
                if (m != loc.monitor) {
                        transfer_node(loc.monitor, loc.desktop, loc.node, m, m->desk, m->desk->focus);
                }
+       } else {
+               if (c->state == STATE_PSEUDO_TILED) {
+                       width = c->floating_rectangle.width;
+                       height = c->floating_rectangle.height;
+                       if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
+                               width = e->width;
+                       }
+                       if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
+                               height = e->height;
+                       }
+                       apply_size_hints(c, &width, &height);
+                       if (width != c->floating_rectangle.width || height != c->floating_rectangle.height) {
+                               c->floating_rectangle.width = width;
+                               c->floating_rectangle.height = height;
+                               arrange(loc.monitor, loc.desktop);
+                       }
+               }
+
+
+               xcb_configure_notify_event_t evt;
+               unsigned int bw = c->border_width;
+
+               xcb_rectangle_t r = IS_FULLSCREEN(c) ? loc.monitor->rectangle : c->tiled_rectangle;
+
+               evt.response_type = XCB_CONFIGURE_NOTIFY;
+               evt.event = e->window;
+               evt.window = e->window;
+               evt.above_sibling = XCB_NONE;
+               evt.x = r.x;
+               evt.y = r.y;
+               evt.width = r.width;
+               evt.height = r.height;
+               evt.border_width = bw;
+               evt.override_redirect = false;
+
+               xcb_send_event(dpy, false, e->window, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *) &evt);
        }
 }
 
@@ -243,18 +244,7 @@ void property_notify(xcb_generic_event_t *evt)
                        set_urgent(loc.monitor, loc.desktop, loc.node, xcb_icccm_wm_hints_get_urgency(&hints));
        } else if (e->atom == XCB_ATOM_WM_NORMAL_HINTS) {
                client_t *c = loc.node->client;
-               xcb_size_hints_t size_hints;
-               if (xcb_icccm_get_wm_normal_hints_reply(dpy, xcb_icccm_get_wm_normal_hints(dpy, e->window), &size_hints, NULL) == 1 &&
-                   (size_hints.flags & (XCB_ICCCM_SIZE_HINT_P_MIN_SIZE | XCB_ICCCM_SIZE_HINT_P_MAX_SIZE))) {
-                       c->min_width = size_hints.min_width;
-                       c->max_width = size_hints.max_width;
-                       c->min_height = size_hints.min_height;
-                       c->max_height = size_hints.max_height;
-                       int w = c->floating_rectangle.width;
-                       int h = c->floating_rectangle.height;
-                       restrain_floating_size(c, &w, &h);
-                       c->floating_rectangle.width = w;
-                       c->floating_rectangle.height = h;
+               if (xcb_icccm_get_wm_normal_hints_reply(dpy, xcb_icccm_get_wm_normal_hints(dpy, e->window), &c->size_hints, NULL) == 1) {
                        arrange(loc.monitor, loc.desktop);
                }
        }
@@ -317,6 +307,28 @@ void focus_in(xcb_generic_event_t *evt)
        }
 }
 
+void button_press(xcb_generic_event_t *evt)
+{
+    xcb_button_press_event_t *e = (xcb_button_press_event_t *) evt;
+    switch (e->detail) {
+               case XCB_BUTTON_INDEX_1:
+                       if (click_to_focus && cleaned_mask(e->state) == XCB_NONE) {
+                               xcb_allow_events(dpy, XCB_ALLOW_REPLAY_POINTER, e->time);
+                               xcb_flush(dpy);
+                               grab_pointer(ACTION_FOCUS);
+                       } else {
+                               grab_pointer(ACTION_MOVE);
+                       }
+                       break;
+               case XCB_BUTTON_INDEX_2:
+                       grab_pointer(ACTION_RESIZE_SIDE);
+                       break;
+               case XCB_BUTTON_INDEX_3:
+                       grab_pointer(ACTION_RESIZE_CORNER);
+                       break;
+       }
+}
+
 void enter_notify(xcb_generic_event_t *evt)
 {
        xcb_enter_notify_event_t *e = (xcb_enter_notify_event_t *) evt;
@@ -345,7 +357,11 @@ void motion_notify(xcb_generic_event_t *evt)
 {
        xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *) evt;
 
-       int dtime = e->time - last_motion_time;
+       static uint16_t last_motion_x = 0, last_motion_y = 0;
+       static xcb_timestamp_t last_motion_time = 0;
+
+       int64_t dtime = e->time - last_motion_time;
+
        if (dtime > 1000) {
                last_motion_time = e->time;
                last_motion_x = e->event_x;
@@ -434,7 +450,25 @@ void handle_state(monitor_t *m, desktop_t *d, node_t *n, xcb_atom_t state, unsig
                } else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
                        set_urgent(m, d, n, !n->client->urgent);
                }
+#define HANDLE_WM_STATE(s)  \
+       } else if (state == ewmh->_NET_WM_STATE_##s) { \
+               if (action == XCB_EWMH_WM_STATE_ADD) { \
+                       n->client->wm_flags |= WM_FLAG_##s; \
+               } else if (action == XCB_EWMH_WM_STATE_REMOVE) { \
+                       n->client->wm_flags &= ~WM_FLAG_##s; \
+               } else if (action == XCB_EWMH_WM_STATE_TOGGLE) { \
+                       n->client->wm_flags ^= WM_FLAG_##s; \
+               } \
+               ewmh_wm_state_update(n);
+       HANDLE_WM_STATE(MODAL)
+       HANDLE_WM_STATE(MAXIMIZED_VERT)
+       HANDLE_WM_STATE(MAXIMIZED_HORZ)
+       HANDLE_WM_STATE(SHADED)
+       HANDLE_WM_STATE(SKIP_TASKBAR)
+       HANDLE_WM_STATE(SKIP_PAGER)
+       HANDLE_WM_STATE(HIDDEN)
        }
+#undef HANDLE_WM_STATE
 }
 
 void process_error(xcb_generic_event_t *evt)
index 06588fc00e710facfda56b6382016698d777efae..b704d78801685429680cc90449ce85d51cab9f3b 100644 (file)
--- a/events.h
+++ b/events.h
@@ -29,8 +29,6 @@
 #include <xcb/xcb_event.h>
 
 uint8_t randr_base;
-uint16_t last_motion_x, last_motion_y;
-xcb_timestamp_t last_motion_time;
 
 void handle_event(xcb_generic_event_t *evt);
 void map_request(xcb_generic_event_t *evt);
@@ -40,6 +38,7 @@ void unmap_notify(xcb_generic_event_t *evt);
 void property_notify(xcb_generic_event_t *evt);
 void client_message(xcb_generic_event_t *evt);
 void focus_in(xcb_generic_event_t *evt);
+void button_press(xcb_generic_event_t *evt);
 void enter_notify(xcb_generic_event_t *evt);
 void motion_notify(xcb_generic_event_t *evt);
 void handle_state(monitor_t *m, desktop_t *d, node_t *n, xcb_atom_t state, unsigned int action);
diff --git a/ewmh.c b/ewmh.c
index 80734a418257a6e307cf4d2d549a76dacecb0b12..b53faad85dc7a4ef65094935b149238aed9c7fbd 100644 (file)
--- a/ewmh.c
+++ b/ewmh.c
@@ -180,43 +180,29 @@ void ewmh_update_client_list(bool stacking)
        }
 }
 
-bool ewmh_wm_state_add(node_t *n, xcb_atom_t state)
+void ewmh_wm_state_update(node_t *n)
 {
        client_t *c = n->client;
-
-       if (c == NULL || c->wm_states_count >= MAX_WM_STATES) {
-               return false;
-       }
-
-       for (int i = 0; i < c->wm_states_count; i++) {
-               if (c->wm_state[i] == state) {
-                       return false;
-               }
-       }
-
-       c->wm_state[c->wm_states_count] = state;
-       c->wm_states_count++;
-       xcb_ewmh_set_wm_state(ewmh, n->id, c->wm_states_count, c->wm_state);
-       return true;
-}
-
-bool ewmh_wm_state_remove(node_t *n, xcb_atom_t state)
-{
-       client_t *c = n->client;
-       if (c == NULL) {
-               return false;
+       size_t count = 0;
+       uint32_t values[12];
+#define HANDLE_WM_STATE(s)  \
+       if (WM_FLAG_##s & c->wm_flags) { \
+               values[count++] = ewmh->_NET_WM_STATE_##s; \
        }
-       for (int i = 0; i < c->wm_states_count; i++) {
-               if (c->wm_state[i] == state) {
-                       for (int j = i; j < (c->wm_states_count - 1); j++) {
-                               c->wm_state[j] = c->wm_state[j + 1];
-                       }
-                       c->wm_states_count--;
-                       xcb_ewmh_set_wm_state(ewmh, n->id, c->wm_states_count, c->wm_state);
-                       return true;
-               }
-       }
-       return false;
+       HANDLE_WM_STATE(MODAL)
+       HANDLE_WM_STATE(STICKY)
+       HANDLE_WM_STATE(MAXIMIZED_VERT)
+       HANDLE_WM_STATE(MAXIMIZED_HORZ)
+       HANDLE_WM_STATE(SHADED)
+       HANDLE_WM_STATE(SKIP_TASKBAR)
+       HANDLE_WM_STATE(SKIP_PAGER)
+       HANDLE_WM_STATE(HIDDEN)
+       HANDLE_WM_STATE(FULLSCREEN)
+       HANDLE_WM_STATE(ABOVE)
+       HANDLE_WM_STATE(BELOW)
+       HANDLE_WM_STATE(DEMANDS_ATTENTION)
+#undef HANDLE_WM_STATE
+       xcb_ewmh_set_wm_state(ewmh, n->id, count, values);
 }
 
 void ewmh_set_supporting(xcb_window_t win)
diff --git a/ewmh.h b/ewmh.h
index 579ae552630c7e9cf523ea0320e70a5469b47a8d..f0761634bff05e0078af96b84e0193762e6a862e 100644 (file)
--- a/ewmh.h
+++ b/ewmh.h
@@ -39,8 +39,7 @@ void ewmh_set_wm_desktop(node_t *n, desktop_t *d);
 void ewmh_update_wm_desktops(void);
 void ewmh_update_desktop_names(void);
 void ewmh_update_client_list(bool stacking);
-bool ewmh_wm_state_add(node_t *n, xcb_atom_t state);
-bool ewmh_wm_state_remove(node_t *n, xcb_atom_t state);
+void ewmh_wm_state_update(node_t *n);
 void ewmh_set_supporting(xcb_window_t win);
 
 #endif
index f8d4422a22feab548fe4906d1c4e2fcc34a77b03..8ef45e0447588d4c31ff3430f4edae7d342a8d00 100644 (file)
@@ -105,33 +105,17 @@ super + ctrl + shift + space
        bspc query -N -d | xargs -I id -n 1 bspc node id -p cancel
 
 #
-# resize tiled/floating
+# move/resize
 #
 
-# expand the tiled space in the given direction
+# expand a window by moving one of its side outward
 super + alt + {h,j,k,l}
-       bspc node {@west -r -10,@south -r +10,@north -r -10,@east -r +10}
+       bspc node -z {left -20 0,bottom 0 20,top 0 -20,right 20 0}
 
-# contract the tiled space in the given direction
-super + alt + shift + {h,j,k,l}
-       bspc node {@east -r -10,@north -r +10,@south -r -10,@west -r +10}
+# contract a window by moving one of its side inward
+super + alt + shit + {h,j,k,l}
+       bspc node -z {right -20 0,top 0 20,bottom 0 -20,left 20 0}
 
 # move a floating window
 super + {Left,Down,Up,Right}
-       xdo move {-x -20,-y +20,-y -20,-x +20}
-
-#
-# pointer focus/move/resize
-#
-
-# focus
-~button1
-       bspc pointer -g focus
-
-# start move/resize
-super + button{1-3}
-       ; bspc pointer -g {move,resize_side,resize_corner}
-
-# end move/resize
-super + @button{1-3}
-       bspc pointer -u
+       bspc node -v {-20 0,0 20,0 -20,20 0}
index 416696ac544d23010ec00af22cf13db3e7b42d96..b8d481c3e6f170c75f7ae978b6d2b45ffe118871 100644 (file)
--- a/helpers.h
+++ b/helpers.h
 #define SMALEN     32
 #define INIT_CAP    8
 
+#define cleaned_mask(m)   (m & ~(num_lock | scroll_lock | caps_lock))
 #define streq(s1, s2)     (strcmp((s1), (s2)) == 0)
+#define unsigned_subtract(a, b)  \
+       do {                         \
+               if (b > a) {             \
+                       a = 0;               \
+               } else {                 \
+                       a -= b;              \
+               }                        \
+       } while (false)
+
 
 void warn(char *fmt, ...);
 void err(char *fmt, ...);
index 3f03d4d881f4fc61e14779a34a46a9606909ccc2..903b96ad4025b7e986ccb627dd3f1c5193df3577 100644 (file)
@@ -100,8 +100,6 @@ void process_message(char **args, int num, FILE *rsp)
                cmd_wm(++args, --num, rsp);
        } else if (streq("rule", *args)) {
                cmd_rule(++args, --num, rsp);
-       } else if (streq("pointer", *args)) {
-               cmd_pointer(++args, --num, rsp);
        } else if (streq("config", *args)) {
                cmd_config(++args, --num, rsp);
        } else if (streq("quit", *args)) {
@@ -375,6 +373,57 @@ void cmd_node(char **args, int num, FILE *rsp)
                                presel_ratio(trg.monitor, trg.desktop, trg.node, rat);
                                draw_presel_feedback(trg.monitor, trg.desktop, trg.node);
                        }
+               } else if (streq("-v", *args) || streq("--move", *args)) {
+                       num--, args++;
+                       if (num < 2) {
+                               fail(rsp, "node %s: Not enough arguments.\n", *(args - 1));
+                               break;
+                       }
+                       int dx = 0, dy = 0;
+                       if (sscanf(*args, "%i", &dx) == 1) {
+                               num--, args++;
+                               if (sscanf(*args, "%i", &dy) == 1) {
+                                       if (!move_client(&trg, dx, dy)) {
+                                               fail(rsp, "");
+                                               break;
+                                       }
+                               } else {
+                                       fail(rsp, "node %s: Invalid dy argument: '%s'.\n", *(args - 3), *args);
+                                       break;
+                               }
+                       } else {
+                               fail(rsp, "node %s: Invalid dx argument: '%s'.\n", *(args - 2), *args);
+                               break;
+                       }
+               } else if (streq("-z", *args) || streq("--resize", *args)) {
+                       num--, args++;
+                       if (num < 3) {
+                               fail(rsp, "node %s: Not enough arguments.\n", *(args - 1));
+                               break;
+                       }
+                       resize_handle_t rh;
+                       if (parse_resize_handle(*args, &rh)) {
+                               num--, args++;
+                               int dx = 0, dy = 0;
+                               if (sscanf(*args, "%i", &dx) == 1) {
+                                       num--, args++;
+                                       if (sscanf(*args, "%i", &dy) == 1) {
+                                               if (!resize_client(&trg, rh, dx, dy)) {
+                                                       fail(rsp, "");
+                                                       break;
+                                               }
+                                       } else {
+                                               fail(rsp, "node %s: Invalid dy argument: '%s'.\n", *(args - 3), *args);
+                                               break;
+                                       }
+                               } else {
+                                       fail(rsp, "node %s: Invalid dx argument: '%s'.\n", *(args - 2), *args);
+                                       break;
+                               }
+                       } else {
+                               fail(rsp, "node %s: Invalid resize handle argument: '%s'.\n", *(args - 1), *args);
+                               break;
+                       }
                } else if (streq("-r", *args) || streq("--ratio", *args)) {
                        num--, args++;
                        if (num < 1) {
@@ -1028,51 +1077,6 @@ void cmd_rule(char **args, int num, FILE *rsp)
        }
 }
 
-void cmd_pointer(char **args, int num, FILE *rsp)
-{
-       if (num < 1) {
-               fail(rsp, "pointer: Missing commands.\n");
-               return;
-       }
-
-       while (num > 0) {
-               if (streq("-t", *args) || streq("--track", *args)) {
-                       num--, args++;
-                       if (num < 2) {
-                               fail(rsp, "pointer %s: Not enough arguments.\n", *(args - 1));
-                               return;
-                       }
-                       int x, y;
-                       if (sscanf(*args, "%i", &x) == 1 && sscanf(*(args + 1), "%i", &y) == 1) {
-                               track_pointer(x, y);
-                       } else {
-                               fail(rsp, "");
-                               return;
-                       }
-                       num--, args++;
-               } else if (streq("-g", *args) || streq("--grab", *args)) {
-                       num--, args++;
-                       if (num < 1) {
-                               fail(rsp, "pointer %s: Not enough arguments.\n", *(args - 1));
-                               return;
-                       }
-                       pointer_action_t pac;
-                       if (parse_pointer_action(*args, &pac)) {
-                               grab_pointer(pac);
-                       } else {
-                               fail(rsp, "pointer %s: Invalid argument: '%s'.\n", *(args - 1), *args);
-                               return;
-                       }
-               } else if (streq("-u", *args) || streq("--ungrab", *args)) {
-                       ungrab_pointer();
-               } else {
-                       fail(rsp, "pointer: Unknown command: '%s'.\n", *args);
-                       return;
-               }
-               num--, args++;
-       }
-}
-
 void cmd_wm(char **args, int num, FILE *rsp)
 {
        if (num < 1) {
@@ -1377,6 +1381,22 @@ void set_setting(coordinates_t loc, char *name, char *value, FILE *rsp)
                        fail(rsp, "config: %s: Invalid value: '%s'.\n", name, value);
                        return;
                }
+       } else if (streq("pointer_modifier", name)) {
+               if (parse_modifier_mask(value, &pointer_modifier)) {
+                       ungrab_buttons();
+                       grab_buttons();
+               } else {
+                       fail(rsp, "config: %s: Invalid value: '%s'.\n", name, value);
+                       return;
+               }
+       } else if (streq("click_to_focus", name)) {
+               if (parse_bool(value, &click_to_focus)) {
+                       ungrab_buttons();
+                       grab_buttons();
+               } else {
+                       fail(rsp, "config: %s: Invalid value: '%s'.\n", name, value);
+                       return;
+               }
        } else if (streq("focus_follows_pointer", name)) {
                bool b;
                if (parse_bool(value, &b)) {
@@ -1426,6 +1446,7 @@ void set_setting(coordinates_t loc, char *name, char *value, FILE *rsp)
                SET_BOOL(focus_by_distance)
                SET_BOOL(ignore_ewmh_focus)
                SET_BOOL(center_pseudo_tiled)
+               SET_BOOL(honor_size_hints)
 #undef SET_BOOL
 #define SET_MON_BOOL(s) \
        } else if (streq(#s, name)) { \
@@ -1500,6 +1521,8 @@ void get_setting(coordinates_t loc, char *name, FILE* rsp)
                fprintf(rsp, "%s", status_prefix);
        } else if (streq("initial_polarity", name)) {
                fprintf(rsp, "%s", CHILD_POL_STR(initial_polarity));
+       } else if (streq("pointer_modifier", name)) {
+               print_modifier_mask(pointer_modifier, rsp);
 #define GET_COLOR(s) \
        } else if (streq(#s, name)) { \
                fprintf(rsp, "%s", s);
@@ -1515,6 +1538,7 @@ void get_setting(coordinates_t loc, char *name, FILE* rsp)
        GET_BOOL(gapless_monocle)
        GET_BOOL(paddingless_monocle)
        GET_BOOL(single_monocle)
+       GET_BOOL(click_to_focus)
        GET_BOOL(focus_follows_pointer)
        GET_BOOL(pointer_follows_focus)
        GET_BOOL(pointer_follows_monitor)
@@ -1522,6 +1546,7 @@ void get_setting(coordinates_t loc, char *name, FILE* rsp)
        GET_BOOL(focus_by_distance)
        GET_BOOL(ignore_ewmh_focus)
        GET_BOOL(center_pseudo_tiled)
+       GET_BOOL(honor_size_hints)
        GET_BOOL(remove_disabled_monitors)
        GET_BOOL(remove_unplugged_monitors)
        GET_BOOL(merge_overlapping_monitors)
index 1e91792c0560eee44238800dc9c01073da2acd5f..a80ff714b99c0b9c26173ac1684910ed32a73439 100644 (file)
@@ -40,7 +40,6 @@ void cmd_desktop(char **args, int num, FILE *rsp);
 void cmd_monitor(char **args, int num, FILE *rsp);
 void cmd_query(char **args, int num, FILE *rsp);
 void cmd_rule(char **args, int num, FILE *rsp);
-void cmd_pointer(char **args, int num, FILE *rsp);
 void cmd_wm(char **args, int num, FILE *rsp);
 int cmd_subscribe(char **args, int num, FILE *rsp);
 void cmd_quit(char **args, int num, FILE *rsp);
index ec4d8e9fd745def76a0ae594a04d73dc44025208..5365dcc50cc5a93a669664b3bbe2047a69860efa 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -139,10 +139,6 @@ void embrace_client(monitor_t *m, client_t *c)
 
 void adapt_geometry(xcb_rectangle_t *rs, xcb_rectangle_t *rd, node_t *n)
 {
-       if (frozen_pointer->action != ACTION_NONE) {
-               return;
-       }
-
        for (node_t *f = first_extrema(n); f != NULL; f = next_leaf(f, n)) {
                if (f->client == NULL) {
                        continue;
@@ -189,7 +185,12 @@ void focus_monitor(monitor_t *m)
        mon = m;
 
        if (pointer_follows_monitor) {
-               center_pointer(m->rectangle);
+               xcb_point_t pt;
+               query_pointer(NULL, &pt);
+               monitor_t *mp = monitor_from_point(pt);
+               if (mp != m) {
+                       center_pointer(m->rectangle);
+               }
        }
 
        put_status(SBSC_MASK_MONITOR_FOCUS, "monitor_focus 0x%08X\n", m->id);
diff --git a/parse.c b/parse.c
index c2b4f1ee6d8845594512a2aebb3f06a73d28daee..aad97f749533e22aca5c8397f877030c5af91ad2 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -153,6 +153,66 @@ bool parse_flip(char *s, flip_t *f)
        return false;
 }
 
+bool parse_resize_handle(char *s, resize_handle_t *h)
+{
+       if (streq("left", s)) {
+               *h = HANDLE_LEFT;
+               return true;
+       } else if (streq("top", s)) {
+               *h = HANDLE_TOP;
+               return true;
+       } else if (streq("right", s)) {
+               *h = HANDLE_RIGHT;
+               return true;
+       } else if (streq("bottom", s)) {
+               *h = HANDLE_BOTTOM;
+               return true;
+       } else if (streq("top_left", s)) {
+               *h = HANDLE_TOP_LEFT;
+               return true;
+       } else if (streq("top_right", s)) {
+               *h = HANDLE_TOP_RIGHT;
+               return true;
+       } else if (streq("bottom_right", s)) {
+               *h = HANDLE_BOTTOM_RIGHT;
+               return true;
+       } else if (streq("bottom_left", s)) {
+               *h = HANDLE_BOTTOM_LEFT;
+               return true;
+       }
+       return false;
+}
+
+bool parse_modifier_mask(char *s, uint16_t *m)
+{
+       if (strcmp(s, "shift") == 0) {
+               *m = XCB_MOD_MASK_SHIFT;
+               return true;
+       } else if (strcmp(s, "control") == 0) {
+               *m = XCB_MOD_MASK_CONTROL;
+               return true;
+       } else if (strcmp(s, "lock") == 0) {
+               *m = XCB_MOD_MASK_LOCK;
+               return true;
+       } else if (strcmp(s, "mod1") == 0) {
+               *m = XCB_MOD_MASK_1;
+               return true;
+       } else if (strcmp(s, "mod2") == 0) {
+               *m = XCB_MOD_MASK_2;
+               return true;
+       } else if (strcmp(s, "mod3") == 0) {
+               *m = XCB_MOD_MASK_3;
+               return true;
+       } else if (strcmp(s, "mod4") == 0) {
+               *m = XCB_MOD_MASK_4;
+               return true;
+       } else if (strcmp(s, "mod5") == 0) {
+               *m = XCB_MOD_MASK_5;
+               return true;
+       }
+       return false;
+}
+
 bool parse_pointer_action(char *s, pointer_action_t *a)
 {
        if (streq("move", s)) {
diff --git a/parse.h b/parse.h
index 61e8502677856be45a6846e853adb256ee55b32d..bb257998293feb7820286df5c653816bbdd6730f 100644 (file)
--- a/parse.h
+++ b/parse.h
@@ -20,6 +20,8 @@ bool parse_cycle_direction(char *s, cycle_dir_t *d);
 bool parse_circulate_direction(char *s, circulate_dir_t *d);
 bool parse_history_direction(char *s, history_dir_t *d);
 bool parse_flip(char *s, flip_t *f);
+bool parse_resize_handle(char *s, resize_handle_t *h);
+bool parse_modifier_mask(char *s, uint16_t *m);
 bool parse_pointer_action(char *s, pointer_action_t *a);
 bool parse_child_polarity(char *s, child_polarity_t *p);
 bool parse_degree(char *s, int *d);
index 52ea0f0902a904c9ebcb6795f9e5c63720b1b761..9091ecadf9c54dddfe94d973c37cf8a52324cc13 100644 (file)
--- a/pointer.c
+++ b/pointer.c
@@ -22,6 +22,8 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <xcb/xcb_keysyms.h>
+#include <stdlib.h>
 #include <stdbool.h>
 #include "bspwm.h"
 #include "query.h"
 #include "tree.h"
 #include "monitor.h"
 #include "subscribe.h"
+#include "events.h"
 #include "window.h"
+#include "pointer.h"
+
+void pointer_init(void)
+{
+       num_lock = modfield_from_keysym(XK_Num_Lock);
+       caps_lock = modfield_from_keysym(XK_Caps_Lock);
+       scroll_lock = modfield_from_keysym(XK_Scroll_Lock);
+       if (caps_lock == XCB_NO_SYMBOL) {
+               caps_lock = XCB_MOD_MASK_LOCK;
+       }
+       grabbing = false;
+       grabbed_node = NULL;
+}
+
+void grab_buttons(void)
+{
+#define GRAB(b, m) \
+       xcb_grab_button(dpy, false, root, XCB_EVENT_MASK_BUTTON_PRESS, \
+                       XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, b, m)
+       uint8_t buttons[] = {XCB_BUTTON_INDEX_1, XCB_BUTTON_INDEX_2, XCB_BUTTON_INDEX_3};
+       for (unsigned int i = 0; i < LENGTH(buttons); i++) {
+               uint8_t button = buttons[i];
+               if (click_to_focus && button == XCB_BUTTON_INDEX_1) {
+                       GRAB(button, XCB_MOD_MASK_ANY);
+                       continue;
+               }
+               GRAB(button, pointer_modifier);
+               if (num_lock != XCB_NO_SYMBOL && caps_lock != XCB_NO_SYMBOL && scroll_lock != XCB_NO_SYMBOL) {
+                       GRAB(button, pointer_modifier | num_lock | caps_lock | scroll_lock);
+               }
+               if (num_lock != XCB_NO_SYMBOL && caps_lock != XCB_NO_SYMBOL) {
+                       GRAB(button, pointer_modifier | num_lock | caps_lock);
+               }
+               if (caps_lock != XCB_NO_SYMBOL && scroll_lock != XCB_NO_SYMBOL) {
+                       GRAB(button, pointer_modifier | caps_lock | scroll_lock);
+               }
+               if (num_lock != XCB_NO_SYMBOL && scroll_lock != XCB_NO_SYMBOL) {
+                       GRAB(button, pointer_modifier | num_lock | scroll_lock);
+               }
+               if (num_lock != XCB_NO_SYMBOL) {
+                       GRAB(button, pointer_modifier | num_lock);
+               }
+               if (caps_lock != XCB_NO_SYMBOL) {
+                       GRAB(button, pointer_modifier | caps_lock);
+               }
+               if (scroll_lock != XCB_NO_SYMBOL) {
+                       GRAB(button, pointer_modifier | scroll_lock);
+               }
+       }
+#undef GRAB
+}
+
+void ungrab_buttons(void)
+{
+       xcb_ungrab_button(dpy, XCB_BUTTON_INDEX_ANY, root, XCB_MOD_MASK_ANY);
+}
+
+int16_t modfield_from_keysym(xcb_keysym_t keysym)
+{
+       uint16_t modfield = 0;
+       xcb_keycode_t *keycodes = NULL, *mod_keycodes = NULL;
+       xcb_get_modifier_mapping_reply_t *reply = NULL;
+       xcb_key_symbols_t *symbols = xcb_key_symbols_alloc(dpy);
+
+       if ((keycodes = xcb_key_symbols_get_keycode(symbols, keysym)) == NULL ||
+           (reply = xcb_get_modifier_mapping_reply(dpy, xcb_get_modifier_mapping(dpy), NULL)) == NULL ||
+           reply->keycodes_per_modifier < 1 ||
+           (mod_keycodes = xcb_get_modifier_mapping_keycodes(reply)) == NULL) {
+               goto end;
+       }
+
+       unsigned int num_mod = xcb_get_modifier_mapping_keycodes_length(reply) / reply->keycodes_per_modifier;
+       for (unsigned int i = 0; i < num_mod; i++) {
+               for (unsigned int j = 0; j < reply->keycodes_per_modifier; j++) {
+                       xcb_keycode_t mk = mod_keycodes[i * reply->keycodes_per_modifier + j];
+                       if (mk == XCB_NO_SYMBOL) {
+                               continue;
+                       }
+                       for (xcb_keycode_t *k = keycodes; *k != XCB_NO_SYMBOL; k++) {
+                               if (*k == mk) {
+                                       modfield |= (1 << i);
+                               }
+                       }
+               }
+       }
+
+end:
+       xcb_key_symbols_free(symbols);
+       free(keycodes);
+       free(reply);
+       return modfield;
+}
+
+resize_handle_t get_handle(node_t *n, xcb_point_t pos, pointer_action_t pac)
+{
+       resize_handle_t rh = HANDLE_BOTTOM_RIGHT;
+       xcb_rectangle_t rect = get_rectangle(NULL, n);
+       if (pac == ACTION_RESIZE_SIDE) {
+               float W = rect.width;
+               float H = rect.height;
+               float ratio = W / H;
+               float x = pos.x - rect.x;
+               float y = pos.y - rect.y;
+               float diag_a = ratio * y;
+               float diag_b = W - diag_a;
+               if (x < diag_a) {
+                       if (x < diag_b) {
+                               rh = HANDLE_LEFT;
+                       } else {
+                               rh = HANDLE_BOTTOM;
+                       }
+               } else {
+                       if (x < diag_b) {
+                               rh = HANDLE_TOP;
+                       } else {
+                               rh = HANDLE_RIGHT;
+                       }
+               }
+       } else if (pac == ACTION_RESIZE_CORNER) {
+               int16_t mid_x = rect.x + (rect.width / 2);
+               int16_t mid_y = rect.y + (rect.height / 2);
+               if (pos.x > mid_x) {
+                       if (pos.y > mid_y) {
+                               rh = HANDLE_BOTTOM_RIGHT;
+                       } else {
+                               rh = HANDLE_TOP_RIGHT;
+                       }
+               } else {
+                       if (pos.y > mid_y) {
+                               rh = HANDLE_BOTTOM_LEFT;
+                       } else {
+                               rh = HANDLE_TOP_LEFT;
+                       }
+               }
+       }
+       return rh;
+}
 
 void grab_pointer(pointer_action_t pac)
 {
@@ -40,321 +180,90 @@ void grab_pointer(pointer_action_t pac)
        query_pointer(&win, &pos);
 
        coordinates_t loc;
-       if (locate_window(win, &loc)) {
-               client_t *c = loc.node->client;
 
-               frozen_pointer->position = pos;
-               frozen_pointer->action = pac;
-               frozen_pointer->monitor = loc.monitor;
-               frozen_pointer->desktop = loc.desktop;
-               frozen_pointer->node = loc.node;
-               frozen_pointer->client = c;
-               frozen_pointer->window = loc.node->id;
-               frozen_pointer->horizontal_fence = NULL;
-               frozen_pointer->vertical_fence = NULL;
-
-               switch (pac)  {
-                       case ACTION_FOCUS:
-                               if (loc.node != mon->desk->focus) {
-                                       bool backup = pointer_follows_monitor;
-                                       pointer_follows_monitor = false;
-                                       focus_node(loc.monitor, loc.desktop, loc.node);
-                                       pointer_follows_monitor = backup;
-                               } else if (focus_follows_pointer) {
-                                       stack(loc.desktop, loc.node, true);
-                               }
-                               frozen_pointer->action = ACTION_NONE;
-                               break;
-                       case ACTION_MOVE:
-                       case ACTION_RESIZE_SIDE:
-                       case ACTION_RESIZE_CORNER:
-                               if (IS_FLOATING(c)) {
-                                       frozen_pointer->rectangle = c->floating_rectangle;
-                                       frozen_pointer->is_tiled = false;
-                               } else if (IS_TILED(c)) {
-                                       frozen_pointer->rectangle = c->tiled_rectangle;
-                                       frozen_pointer->is_tiled = (pac == ACTION_MOVE || c->state != STATE_PSEUDO_TILED);
-                               } else {
-                                       frozen_pointer->action = ACTION_NONE;
-                                       return;
-                               }
-                               if (pac == ACTION_RESIZE_SIDE) {
-                                       float W = frozen_pointer->rectangle.width;
-                                       float H = frozen_pointer->rectangle.height;
-                                       float ratio = W / H;
-                                       float x = pos.x - frozen_pointer->rectangle.x;
-                                       float y = pos.y - frozen_pointer->rectangle.y;
-                                       float diag_a = ratio * y;
-                                       float diag_b = W - diag_a;
-                                       if (x < diag_a) {
-                                               if (x < diag_b) {
-                                                       frozen_pointer->side = SIDE_LEFT;
-                                               } else {
-                                                       frozen_pointer->side = SIDE_BOTTOM;
-                                               }
-                                       } else {
-                                               if (x < diag_b) {
-                                                       frozen_pointer->side = SIDE_TOP;
-                                               } else {
-                                                       frozen_pointer->side = SIDE_RIGHT;
-                                               }
-                                       }
-                               } else if (pac == ACTION_RESIZE_CORNER) {
-                                       int16_t mid_x = frozen_pointer->rectangle.x + (frozen_pointer->rectangle.width / 2);
-                                       int16_t mid_y = frozen_pointer->rectangle.y + (frozen_pointer->rectangle.height / 2);
-                                       if (pos.x > mid_x) {
-                                               if (pos.y > mid_y) {
-                                                       frozen_pointer->corner = CORNER_BOTTOM_RIGHT;
-                                               } else {
-                                                       frozen_pointer->corner = CORNER_TOP_RIGHT;
-                                               }
-                                       } else {
-                                               if (pos.y > mid_y) {
-                                                       frozen_pointer->corner = CORNER_BOTTOM_LEFT;
-                                               } else {
-                                                       frozen_pointer->corner = CORNER_TOP_LEFT;
-                                               }
-                                       }
-                               }
-                               if (frozen_pointer->is_tiled) {
-                                       if (pac == ACTION_RESIZE_SIDE) {
-                                               switch (frozen_pointer->side) {
-                                                       case SIDE_TOP:
-                                                               frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_NORTH);
-                                                               break;
-                                                       case SIDE_RIGHT:
-                                                               frozen_pointer->vertical_fence = find_fence(loc.node, DIR_EAST);
-                                                               break;
-                                                       case SIDE_BOTTOM:
-                                                               frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_SOUTH);
-                                                               break;
-                                                       case SIDE_LEFT:
-                                                               frozen_pointer->vertical_fence = find_fence(loc.node, DIR_WEST);
-                                                               break;
-                                               }
-                                       } else if (pac == ACTION_RESIZE_CORNER) {
-                                               switch (frozen_pointer->corner) {
-                                                       case CORNER_TOP_LEFT:
-                                                               frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_NORTH);
-                                                               frozen_pointer->vertical_fence = find_fence(loc.node, DIR_WEST);
-                                                               break;
-                                                       case CORNER_TOP_RIGHT:
-                                                               frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_NORTH);
-                                                               frozen_pointer->vertical_fence = find_fence(loc.node, DIR_EAST);
-                                                               break;
-                                                       case CORNER_BOTTOM_RIGHT:
-                                                               frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_SOUTH);
-                                                               frozen_pointer->vertical_fence = find_fence(loc.node, DIR_EAST);
-                                                               break;
-                                                       case CORNER_BOTTOM_LEFT:
-                                                               frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_SOUTH);
-                                                               frozen_pointer->vertical_fence = find_fence(loc.node, DIR_WEST);
-                                                               break;
-                                               }
-                                       }
-                                       if (frozen_pointer->horizontal_fence != NULL) {
-                                               frozen_pointer->horizontal_ratio = frozen_pointer->horizontal_fence->split_ratio;
-                                       }
-                                       if (frozen_pointer->vertical_fence != NULL) {
-                                               frozen_pointer->vertical_ratio = frozen_pointer->vertical_fence->split_ratio;
-                                       }
-                               }
-                               break;
-                       case ACTION_NONE:
-                               break;
-               }
-       } else {
+       if (!locate_window(win, &loc)) {
                if (pac == ACTION_FOCUS) {
                        monitor_t *m = monitor_from_point(pos);
                        if (m != NULL && m != mon && (win == XCB_NONE || win == m->root)) {
                                focus_node(m, m->desk, m->desk->focus);
                        }
                }
-               frozen_pointer->action = ACTION_NONE;
+               return;
        }
-}
 
-void track_pointer(int root_x, int root_y)
-{
-       if (frozen_pointer->action == ACTION_NONE) {
+       if (pac == ACTION_FOCUS) {
+               if (loc.node != mon->desk->focus) {
+                       focus_node(loc.monitor, loc.desktop, loc.node);
+               } else if (focus_follows_pointer) {
+                       stack(loc.desktop, loc.node, true);
+               }
                return;
        }
 
-       int delta_x, delta_y, x = 0, y = 0, w = 1, h = 1;
+       if (loc.node->client->state == STATE_FULLSCREEN) {
+               return;
+       }
 
-       pointer_action_t pac = frozen_pointer->action;
-       monitor_t *m = frozen_pointer->monitor;
-       desktop_t *d = frozen_pointer->desktop;
-       node_t *n = frozen_pointer->node;
-       client_t *c = frozen_pointer->client;
-       xcb_window_t win = frozen_pointer->window;
-       xcb_rectangle_t rect = frozen_pointer->rectangle;
-       node_t *vertical_fence = frozen_pointer->vertical_fence;
-       node_t *horizontal_fence = frozen_pointer->horizontal_fence;
+       xcb_grab_pointer_reply_t *reply = xcb_grab_pointer_reply(dpy, xcb_grab_pointer(dpy, 0, root, XCB_EVENT_MASK_BUTTON_RELEASE|XCB_EVENT_MASK_BUTTON_MOTION, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_CURRENT_TIME), NULL);
 
-       delta_x = root_x - frozen_pointer->position.x;
-       delta_y = root_y - frozen_pointer->position.y;
+       if (reply == NULL || reply->status != XCB_GRAB_STATUS_SUCCESS) {
+               return;
+       }
 
-       switch (pac) {
-               case ACTION_MOVE:
-                       if (frozen_pointer->is_tiled) {
-                               xcb_window_t pwin = XCB_NONE;
-                               query_pointer(&pwin, NULL);
-                               if (pwin == win) {
-                                       return;
-                               }
-                               coordinates_t loc;
-                               bool is_managed = (pwin == XCB_NONE ? false : locate_window(pwin, &loc));
-                               if (is_managed && !IS_FLOATING(loc.node->client) && loc.monitor == m) {
-                                       swap_nodes(m, d, n, m, d, loc.node);
-                               } else {
-                                       if (is_managed && loc.monitor == m) {
-                                               return;
-                                       } else if (!is_managed) {
-                                               xcb_point_t pt = (xcb_point_t) {root_x, root_y};
-                                               monitor_t *pmon = monitor_from_point(pt);
-                                               if (pmon == NULL || pmon == m) {
-                                                       return;
-                                               } else {
-                                                       loc.monitor = pmon;
-                                                       loc.desktop = pmon->desk;
-                                               }
-                                       }
-                                       bool focused = (n == mon->desk->focus);
-                                       transfer_node(m, d, n, loc.monitor, loc.desktop, loc.desktop->focus);
-                                       if (focused) {
-                                               focus_node(loc.monitor, loc.desktop, n);
-                                       }
-                                       frozen_pointer->monitor = loc.monitor;
-                                       frozen_pointer->desktop = loc.desktop;
-                               }
-                       } else {
-                               x = rect.x + delta_x;
-                               y = rect.y + delta_y;
-                               window_move(win, x, y);
-                               c->floating_rectangle.x = x;
-                               c->floating_rectangle.y = y;
-                               xcb_point_t pt = (xcb_point_t) {root_x, root_y};
-                               monitor_t *pmon = monitor_from_point(pt);
-                               if (pmon == NULL || pmon == m) {
-                                       return;
-                               }
-                               bool focused = (n == mon->desk->focus);
-                               transfer_node(m, d, n, pmon, pmon->desk, pmon->desk->focus);
-                               if (focused) {
-                                       focus_node(pmon, pmon->desk, n);
-                               }
-                               frozen_pointer->monitor = pmon;
-                               frozen_pointer->desktop = pmon->desk;
+       track_pointer(loc, pac, pos);
+}
+
+void track_pointer(coordinates_t loc, pointer_action_t pac, xcb_point_t pos)
+{
+       node_t *n = loc.node;
+       resize_handle_t rh = get_handle(loc.node, pos, pac);
+
+       uint16_t last_motion_x = pos.x, last_motion_y = pos.y;
+       xcb_timestamp_t last_motion_time = 0;
+
+       xcb_generic_event_t *evt = NULL;
+
+       grabbing = true;
+       grabbed_node = n;
+
+       do {
+               free(evt);
+               while ((evt = xcb_wait_for_event(dpy)) == NULL) {
+                       xcb_flush(dpy);
+               }
+               uint8_t resp_type = XCB_EVENT_RESPONSE_TYPE(evt);
+               if (resp_type == XCB_MOTION_NOTIFY) {
+                       xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t*) evt;
+                       int64_t dtime = e->time - last_motion_time;
+                       if (dtime < 20) {
+                               continue;
                        }
-                       break;
-               case ACTION_RESIZE_SIDE:
-               case ACTION_RESIZE_CORNER:
-                       if (frozen_pointer->is_tiled) {
-                               if (vertical_fence != NULL) {
-                                       double sr = frozen_pointer->vertical_ratio + (double) delta_x / vertical_fence->rectangle.width;
-                                       sr = MAX(0, sr);
-                                       sr = MIN(1, sr);
-                                       vertical_fence->split_ratio = sr;
-                               }
-                               if (horizontal_fence != NULL) {
-                                       double sr = frozen_pointer->horizontal_ratio + (double) delta_y / horizontal_fence->rectangle.height;
-                                       sr = MAX(0, sr);
-                                       sr = MIN(1, sr);
-                                       horizontal_fence->split_ratio = sr;
-                               }
-                               arrange(m, d);
+                       last_motion_time = e->time;
+                       int16_t dx = e->root_x - last_motion_x;
+                       int16_t dy = e->root_y - last_motion_y;
+                       if (pac == ACTION_MOVE) {
+                               move_client(&loc, dx, dy);
                        } else {
-                               if (pac == ACTION_RESIZE_SIDE) {
-                                       switch (frozen_pointer->side) {
-                                               case SIDE_TOP:
-                                                       x = rect.x;
-                                                       y = rect.y + delta_y;
-                                                       w = rect.width;
-                                                       h = rect.height - delta_y;
-                                                       break;
-                                               case SIDE_RIGHT:
-                                                       x = rect.x;
-                                                       y = rect.y;
-                                                       w = rect.width + delta_x;
-                                                       h = rect.height;
-                                                       break;
-                                               case SIDE_BOTTOM:
-                                                       x = rect.x;
-                                                       y = rect.y;
-                                                       w = rect.width;
-                                                       h = rect.height + delta_y;
-                                                       break;
-                                               case SIDE_LEFT:
-                                                       x = rect.x + delta_x;
-                                                       y = rect.y;
-                                                       w = rect.width - delta_x;
-                                                       h = rect.height;
-                                                       break;
-                                       }
-                               } else if (pac == ACTION_RESIZE_CORNER) {
-                                       switch (frozen_pointer->corner) {
-                                               case CORNER_TOP_LEFT:
-                                                       x = rect.x + delta_x;
-                                                       y = rect.y + delta_y;
-                                                       w = rect.width - delta_x;
-                                                       h = rect.height - delta_y;
-                                                       break;
-                                               case CORNER_TOP_RIGHT:
-                                                       x = rect.x;
-                                                       y = rect.y + delta_y;
-                                                       w = rect.width + delta_x;
-                                                       h = rect.height - delta_y;
-                                                       break;
-                                               case CORNER_BOTTOM_LEFT:
-                                                       x = rect.x + delta_x;
-                                                       y = rect.y;
-                                                       w = rect.width - delta_x;
-                                                       h = rect.height + delta_y;
-                                                       break;
-                                               case CORNER_BOTTOM_RIGHT:
-                                                       x = rect.x;
-                                                       y = rect.y;
-                                                       w = rect.width + delta_x;
-                                                       h = rect.height + delta_y;
-                                                       break;
-                                       }
-                               }
+                               resize_client(&loc, rh, dx, dy);
+                       }
+                       last_motion_x = e->root_x;
+                       last_motion_y = e->root_y;
+                       xcb_flush(dpy);
+               } else if (resp_type == XCB_BUTTON_RELEASE) {
+                       grabbing = false;
+               } else {
+                       handle_event(evt);
+               }
+       } while (grabbing && grabbed_node != NULL);
 
-                               int oldw = w, oldh = h;
-                               restrain_floating_size(c, &w, &h);
+       xcb_ungrab_pointer(dpy, XCB_CURRENT_TIME);
 
-                               if (c->state == STATE_FLOATING) {
-                                       if (oldw == w) {
-                                               c->floating_rectangle.x = x;
-                                               c->floating_rectangle.width = w;
-                                       }
-                                       if (oldh == h) {
-                                               c->floating_rectangle.y = y;
-                                               c->floating_rectangle.height = h;
-                                       }
-                                       window_move_resize(win, c->floating_rectangle.x,
-                                                               c->floating_rectangle.y,
-                                                               c->floating_rectangle.width,
-                                                               c->floating_rectangle.height);
-                               } else {
-                                       c->floating_rectangle.width = w;
-                                       c->floating_rectangle.height = h;
-                                       arrange(m, d);
-                               }
-                       }
-                       break;
-               case ACTION_FOCUS:
-               case ACTION_NONE:
-                       break;
+       if (grabbed_node == NULL) {
+               grabbing = false;
+               return;
        }
-}
 
-void ungrab_pointer(void)
-{
-       if (frozen_pointer->action != ACTION_NONE) {
-               xcb_rectangle_t r = get_rectangle(frozen_pointer->desktop, frozen_pointer->node);
-               put_status(SBSC_MASK_NODE_GEOMETRY, "node_geometry 0x%08X 0x%08X 0x%08X %ux%u+%i+%i\n", frozen_pointer->monitor->id, frozen_pointer->desktop->id, frozen_pointer->window, r.width, r.height, r.x, r.y);
-       }
-       frozen_pointer->action = ACTION_NONE;
+       xcb_rectangle_t r = get_rectangle(NULL, n);
+
+       put_status(SBSC_MASK_NODE_GEOMETRY, "node_geometry 0x%08X 0x%08X 0x%08X %ux%u+%i+%i\n", loc.monitor->id, loc.desktop->id, loc.node->id, r.width, r.height, r.x, r.y);
 }
index 592157c5c284e975bce51f2704314d3fdcda45e5..38c539491049a8dd7fd871bdf1ea5b765dc6399d 100644 (file)
--- a/pointer.h
+++ b/pointer.h
 #ifndef BSPWM_POINTER_H
 #define BSPWM_POINTER_H
 
+#define XK_Num_Lock     0xff7f
+#define XK_Caps_Lock    0xffe5
+#define XK_Scroll_Lock  0xff14
+
+uint16_t num_lock;
+uint16_t caps_lock;
+uint16_t scroll_lock;
+
+bool grabbing;
+node_t *grabbed_node;
+
+void pointer_init(void);
+void grab_buttons(void);
+void ungrab_buttons(void);
+int16_t modfield_from_keysym(xcb_keysym_t keysym);
+resize_handle_t get_handle(node_t *n, xcb_point_t pos, pointer_action_t pac);
 void grab_pointer(pointer_action_t pac);
-void track_pointer(int root_x, int root_y);
+void track_pointer(coordinates_t loc, pointer_action_t pac, xcb_point_t pos);
 void ungrab_pointer(void);
 
 #endif
diff --git a/query.c b/query.c
index b84c1e795154cd7bc7d61dc0f092ffcdfe3ec090..ef2cb2a1434fe46dabe57e9e35426672e1615cc9 100644 (file)
--- a/query.c
+++ b/query.c
@@ -30,6 +30,7 @@
 #include "history.h"
 #include "parse.h"
 #include "monitor.h"
+#include "window.h"
 #include "tree.h"
 #include "query.h"
 
@@ -162,16 +163,6 @@ void query_client(client_t *c, FILE *rsp)
                fprintf(rsp, "\"lastLayer\":\"%s\",", LAYER_STR(c->last_layer));
                fprintf(rsp, "\"urgent\":%s,", BOOL_STR(c->urgent));
                fprintf(rsp, "\"visible\":%s,", BOOL_STR(c->visible));
-               fprintf(rsp, "\"icccmFocus\":%s,", BOOL_STR(c->icccm_focus));
-               fprintf(rsp, "\"icccmInput\":%s,", BOOL_STR(c->icccm_input));
-               fprintf(rsp, "\"minWidth\":%u,", c->min_width);
-               fprintf(rsp, "\"maxWidth\":%u,", c->max_width);
-               fprintf(rsp, "\"minHeight\":%u,", c->min_height);
-               fprintf(rsp, "\"maxHeight\":%u,", c->max_height);
-               fprintf(rsp, "\"wmStatesCount\":%i,", c->wm_states_count);
-               fprintf(rsp, "\"wmState\":");
-               query_wm_state(c->wm_state, c->wm_states_count, rsp);
-               fprintf(rsp,",");
                fprintf(rsp, "\"tiledRectangle\":");
                query_rectangle(c->tiled_rectangle, rsp);
                fprintf(rsp,",");
@@ -191,18 +182,6 @@ void query_padding(padding_t p, FILE *rsp)
        fprintf(rsp, "{\"top\":%i,\"right\":%i,\"bottom\":%i,\"left\":%i}", p.top, p.right, p.bottom, p.left);
 }
 
-void query_wm_state(xcb_atom_t *wm_state, int wm_states_count, FILE *rsp)
-{
-       fprintf(rsp, "[");
-       for (int i = 0; i < wm_states_count; i++) {
-               fprintf(rsp, "%u", wm_state[i]);
-               if (i < wm_states_count - 1) {
-                       fprintf(rsp, ",");
-               }
-       }
-       fprintf(rsp, "]");
-}
-
 void query_history(FILE *rsp)
 {
        fprintf(rsp, "[");
@@ -305,6 +284,36 @@ int query_monitor_ids(coordinates_t loc, monitor_select_t *sel, FILE *rsp)
        return count;
 }
 
+void print_modifier_mask(uint16_t m, FILE *rsp)
+{
+       switch (m) {
+               case XCB_MOD_MASK_SHIFT:
+                       fprintf(rsp, "shift");
+                       break;
+               case XCB_MOD_MASK_CONTROL:
+                       fprintf(rsp, "control");
+                       break;
+               case XCB_MOD_MASK_LOCK:
+                       fprintf(rsp, "lock");
+                       break;
+               case XCB_MOD_MASK_1:
+                       fprintf(rsp, "mod1");
+                       break;
+               case XCB_MOD_MASK_2:
+                       fprintf(rsp, "mod2");
+                       break;
+               case XCB_MOD_MASK_3:
+                       fprintf(rsp, "mod3");
+                       break;
+               case XCB_MOD_MASK_4:
+                       fprintf(rsp, "mod4");
+                       break;
+               case XCB_MOD_MASK_5:
+                       fprintf(rsp, "mod5");
+                       break;
+       }
+}
+
 node_select_t make_node_select(void)
 {
        node_select_t sel = {
@@ -396,6 +405,14 @@ int node_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
                        dst->desktop = mon->desk;
                        dst->node = mon->desk->focus;
                }
+       } else if (streq("pointed", desc)) {
+               xcb_window_t win;
+               query_pointer(&win, NULL);
+               if (locate_window(win, dst) && node_matches(dst, ref, sel)) {
+                       return SELECTOR_OK;
+               } else {
+                       return SELECTOR_INVALID;
+               }
        } else if (*desc == '@') {
                desc++;
                if (colon != NULL) {
diff --git a/query.h b/query.h
index 96b19b7b2793511f1759228d2f168b6e46f3c329..09d3d2f18fdae3155ea038b22c946411a35b7fd3 100644 (file)
--- a/query.h
+++ b/query.h
@@ -49,7 +49,6 @@ void query_presel(presel_t *p, FILE *rsp);
 void query_client(client_t *c, FILE *rsp);
 void query_rectangle(xcb_rectangle_t r, FILE *rsp);
 void query_padding(padding_t p, FILE *rsp);
-void query_wm_state(xcb_atom_t *wm_state, int wm_states_count, FILE *rsp);
 void query_history(FILE *rsp);
 void query_coordinates(coordinates_t *loc, FILE *rsp);
 void query_stack(FILE *rsp);
@@ -57,6 +56,7 @@ int query_node_ids(coordinates_t loc, node_select_t *sel, FILE *rsp);
 int query_node_ids_in(node_t *n, desktop_t *d, monitor_t *m, coordinates_t loc, node_select_t *sel, FILE *rsp);
 int query_desktop_ids(coordinates_t loc, desktop_select_t *sel, FILE *rsp);
 int query_monitor_ids(coordinates_t loc, monitor_select_t *sel, FILE *rsp);
+void print_modifier_mask(uint16_t m, FILE *rsp);
 node_select_t make_node_select(void);
 desktop_select_t make_desktop_select(void);
 monitor_select_t make_monitor_select(void);
index b3b98b2dd9a647257c3db8e7c45faf7b290edc78..2b436461ad218eff6d4fa68d00d11dda8bfc91a2 100644 (file)
--- a/restore.c
+++ b/restore.c
@@ -175,6 +175,7 @@ bool restore_tree(const char *file_path)
                                if (n->client == NULL) {
                                        continue;
                                }
+                               initialize_client(n);
                                uint32_t values[] = {CLIENT_EVENT_MASK | (focus_follows_pointer ? XCB_EVENT_MASK_ENTER_WINDOW : 0)};
                                xcb_change_window_attributes(dpy, n->id, XCB_CW_EVENT_MASK, values);
                        }
@@ -433,17 +434,6 @@ client_t *restore_client(jsmntok_t **t, char *json)
                        RESTORE_UINT(borderWidth, &c->border_width)
                        RESTORE_BOOL(urgent, &c->urgent)
                        RESTORE_BOOL(visible, &c->visible)
-                       RESTORE_BOOL(icccmFocus, &c->icccm_focus)
-                       RESTORE_BOOL(icccmInput, &c->icccm_input)
-                       RESTORE_USINT(minWidth, &c->min_width)
-                       RESTORE_USINT(maxWidth, &c->max_width)
-                       RESTORE_USINT(minHeight, &c->min_height)
-                       RESTORE_USINT(maxHeight, &c->max_height)
-                       RESTORE_INT(wmStatesCount, &c->wm_states_count)
-                       } else if (keyeq("wmState", *t, json)) {
-                               (*t)++;
-                               restore_wm_state(c->wm_state, t, json);
-                               continue;
                        } else if (keyeq("tiledRectangle", *t, json)) {
                                (*t)++;
                                restore_rectangle(&c->tiled_rectangle, t, json);
@@ -566,17 +556,6 @@ void restore_stack(jsmntok_t **t, char *json)
        }
 }
 
-void restore_wm_state(xcb_atom_t *w, jsmntok_t **t, char *json)
-{
-       int s = (*t)->size;
-       (*t)++;
-
-       for (int i = 0; i < s; i++) {
-               sscanf(json + (*t)->start, "%u", &w[i]);
-               (*t)++;
-       }
-}
-
 #undef RESTORE_INT
 #undef RESTORE_UINT
 #undef RESTORE_USINT
diff --git a/rule.c b/rule.c
index 1a26b78c1ae52790a8e3d63376c606d6f0358e92..9e2f5ef38889a73d0545427b1b55493378854e71 100644 (file)
--- a/rule.c
+++ b/rule.c
@@ -210,22 +210,6 @@ void apply_rules(xcb_window_t win, rule_consequence_t *csq)
                xcb_ewmh_get_atoms_reply_wipe(&win_state);
        }
 
-       xcb_size_hints_t size_hints;
-       if (xcb_icccm_get_wm_normal_hints_reply(dpy, xcb_icccm_get_wm_normal_hints(dpy, win), &size_hints, NULL) == 1) {
-               if (size_hints.min_width > 0 && size_hints.min_height > 0 &&
-                   size_hints.min_width == size_hints.max_width &&
-                   size_hints.min_height == size_hints.max_height) {
-                       if (csq->state == NULL) {
-                               csq->state = malloc(sizeof(client_state_t));
-                       }
-                       *(csq->state) = STATE_FLOATING;
-               }
-               csq->min_width = size_hints.min_width;
-               csq->max_width = size_hints.max_width;
-               csq->min_height = size_hints.min_height;
-               csq->max_height = size_hints.max_height;
-       }
-
        xcb_window_t transient_for = XCB_NONE;
        xcb_icccm_get_wm_transient_for_reply(dpy, xcb_icccm_get_wm_transient_for(dpy, win), &transient_for, NULL);
        if (transient_for != XCB_NONE) {
@@ -235,6 +219,17 @@ void apply_rules(xcb_window_t win, rule_consequence_t *csq)
                *(csq->state) = STATE_FLOATING;
        }
 
+       xcb_size_hints_t size_hints;
+       if (xcb_icccm_get_wm_normal_hints_reply(dpy, xcb_icccm_get_wm_normal_hints(dpy, win), &size_hints, NULL) == 1) {
+               if ((size_hints.flags & (XCB_ICCCM_SIZE_HINT_P_MIN_SIZE|XCB_ICCCM_SIZE_HINT_P_MAX_SIZE)) &&
+                   size_hints.min_width == size_hints.max_width && size_hints.min_height == size_hints.max_height) {
+                       if (csq->state == NULL) {
+                               csq->state = malloc(sizeof(client_state_t));
+                       }
+                       *(csq->state) = STATE_FLOATING;
+               }
+       }
+
        xcb_icccm_get_wm_class_reply_t reply;
        if (xcb_icccm_get_wm_class_reply(dpy, xcb_icccm_get_wm_class(dpy, win), &reply, NULL) == 1) {
                snprintf(csq->class_name, sizeof(csq->class_name), "%s", reply.class_name);
index 3f6f2d79fbff671ed8241b3bdb0dfecb4eb96d13..1d988c8a1029bd1ea4766713fd137682e0e5e791 100644 (file)
@@ -55,6 +55,7 @@ void load_settings(void)
        border_width = BORDER_WIDTH;
        split_ratio = SPLIT_RATIO;
        initial_polarity = FIRST_CHILD;
+       pointer_modifier = POINTER_MODIFIER;
 
        borderless_monocle = BORDERLESS_MONOCLE;
        gapless_monocle = GAPLESS_MONOCLE;
@@ -66,6 +67,8 @@ void load_settings(void)
        history_aware_focus = HISTORY_AWARE_FOCUS;
        ignore_ewmh_focus = IGNORE_EWMH_FOCUS;
        center_pseudo_tiled = CENTER_PSEUDO_TILED;
+       click_to_focus = CLICK_TO_FOCUS;
+       honor_size_hints = HONOR_SIZE_HINTS;
        remove_disabled_monitors = REMOVE_DISABLED_MONITORS;
        remove_unplugged_monitors = REMOVE_UNPLUGGED_MONITORS;
        merge_overlapping_monitors = MERGE_OVERLAPPING_MONITORS;
index cd627de5e7b256842eba228fee6a54eb0672b8db..ea4dbbcf216866d60566fe332f1236b946068fea 100644 (file)
 #define WM_NAME                 "bspwm"
 #define CONFIG_NAME             WM_NAME "rc"
 #define CONFIG_HOME_ENV         "XDG_CONFIG_HOME"
+#define POINTER_MODIFIER        XCB_MOD_MASK_4
 #define EXTERNAL_RULES_COMMAND  ""
 #define STATUS_PREFIX           "W"
 
+
 #define NORMAL_BORDER_COLOR           "#30302f"
 #define ACTIVE_BORDER_COLOR           "#474645"
 #define FOCUSED_BORDER_COLOR          "#817f7f"
@@ -54,6 +56,8 @@
 #define POINTER_FOLLOWS_MONITOR     false
 #define IGNORE_EWMH_FOCUS           false
 #define CENTER_PSEUDO_TILED         true
+#define CLICK_TO_FOCUS              false
+#define HONOR_SIZE_HINTS            false
 #define REMOVE_DISABLED_MONITORS    false
 #define REMOVE_UNPLUGGED_MONITORS   false
 #define MERGE_OVERLAPPING_MONITORS  false
@@ -72,6 +76,7 @@ unsigned int border_width;
 double split_ratio;
 
 child_polarity_t initial_polarity;
+uint16_t pointer_modifier;
 
 bool borderless_monocle;
 bool gapless_monocle;
@@ -84,6 +89,8 @@ bool history_aware_focus;
 bool focus_by_distance;
 bool ignore_ewmh_focus;
 bool center_pseudo_tiled;
+bool click_to_focus;
+bool honor_size_hints;
 bool remove_disabled_monitors;
 bool remove_unplugged_monitors;
 bool merge_overlapping_monitors;
index bc1c03fe2e02f2273364a6b91ce548045a2e1de2..3dc4aaae1894db589f4661f7fe29efd28f7a2b79 100644 (file)
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdbool.h>
 #include <ctype.h>
 #include <stdarg.h>
 #include "bspwm.h"
-#include "tree.h"
 #include "desktop.h"
 #include "settings.h"
 #include "subscribe.h"
diff --git a/tree.c b/tree.c
index 9054a38e01af82f5a7c6a9af39d30b402115e8ae..1a46ca372af8a375bc8632570bce21d505b7212a 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -36,6 +36,7 @@
 #include "geometry.h"
 #include "subscribe.h"
 #include "settings.h"
+#include "pointer.h"
 #include "stack.h"
 #include "window.h"
 #include "tree.h"
@@ -81,7 +82,7 @@ void apply_layout(monitor_t *m, desktop_t *d, node_t *n, xcb_rectangle_t rect, x
 
        n->rectangle = rect;
 
-       if (pointer_follows_focus && mon->desk->focus == n && frozen_pointer->action == ACTION_NONE) {
+       if (pointer_follows_focus && mon->desk->focus == n) {
                xcb_rectangle_t r = rect;
                r.width -= d->window_gap;
                r.height -= d->window_gap;
@@ -137,9 +138,11 @@ void apply_layout(monitor_t *m, desktop_t *d, node_t *n, xcb_rectangle_t rect, x
                        r = m->rectangle;
                }
 
+               apply_size_hints(n->client, &r.width, &r.height);
+
                if (!rect_eq(r, cr)) {
                        window_move_resize(n->id, r.x, r.y, r.width, r.height);
-                       if (frozen_pointer->action == ACTION_NONE) {
+                       if (!grabbing) {
                                put_status(SBSC_MASK_NODE_GEOMETRY, "node_geometry 0x%08X 0x%08X 0x%08X %ux%u+%i+%i\n", m->id, d->id, n->id, r.width, r.height, r.x, r.y);
                        }
                }
@@ -614,43 +617,55 @@ node_t *make_node(uint32_t id)
 
 client_t *make_client(void)
 {
-       client_t *c = malloc(sizeof(client_t));
+       client_t *c = calloc(1, sizeof(client_t));
        c->state = c->last_state = STATE_TILED;
        c->layer = c->last_layer = LAYER_NORMAL;
        snprintf(c->class_name, sizeof(c->class_name), "%s", MISSING_VALUE);
        snprintf(c->instance_name, sizeof(c->instance_name), "%s", MISSING_VALUE);
        c->border_width = border_width;
-       c->urgent = c->visible = c->icccm_focus = false;
-       c->icccm_input = true;
-       c->wm_states_count = 0;
        return c;
 }
 
 void initialize_client(node_t *n)
 {
        xcb_window_t win = n->id;
-       if (win != XCB_NONE) {
-               client_t *c = n->client;
-               xcb_icccm_get_wm_protocols_reply_t protocols;
-               if (xcb_icccm_get_wm_protocols_reply(dpy, xcb_icccm_get_wm_protocols(dpy, win, ewmh->WM_PROTOCOLS), &protocols, NULL) == 1) {
-                       if (has_proto(WM_TAKE_FOCUS, &protocols)) {
-                               c->icccm_focus = true;
-                       }
-                       xcb_icccm_get_wm_protocols_reply_wipe(&protocols);
-               }
-               xcb_ewmh_get_atoms_reply_t wm_state;
-               if (xcb_ewmh_get_wm_state_reply(ewmh, xcb_ewmh_get_wm_state(ewmh, win), &wm_state, NULL) == 1) {
-                       for (unsigned int i = 0; i < wm_state.atoms_len && i < MAX_WM_STATES; i++) {
-                               ewmh_wm_state_add(n, wm_state.atoms[i]);
+       client_t *c = n->client;
+       xcb_icccm_get_wm_protocols_reply_t protos;
+       if (xcb_icccm_get_wm_protocols_reply(dpy, xcb_icccm_get_wm_protocols(dpy, win, ewmh->WM_PROTOCOLS), &protos, NULL) == 1) {
+               if (has_proto(WM_TAKE_FOCUS, &protos)) {
+                       c->icccm_props.take_focus = true;
+               }
+               xcb_icccm_get_wm_protocols_reply_wipe(&protos);
+       }
+       xcb_ewmh_get_atoms_reply_t wm_state;
+       if (xcb_ewmh_get_wm_state_reply(ewmh, xcb_ewmh_get_wm_state(ewmh, win), &wm_state, NULL) == 1) {
+               for (unsigned int i = 0; i < wm_state.atoms_len && i < MAX_WM_STATES; i++) {
+#define HANDLE_WM_STATE(s) \
+                       if (wm_state.atoms[i] == ewmh->_NET_WM_STATE_##s) { \
+                               c->wm_flags |= WM_FLAG_##s; continue; \
                        }
-                       xcb_ewmh_get_atoms_reply_wipe(&wm_state);
-               }
-               xcb_icccm_wm_hints_t hints;
-               if (xcb_icccm_get_wm_hints_reply(dpy, xcb_icccm_get_wm_hints(dpy, win), &hints, NULL) == 1
-                   && (hints.flags & XCB_ICCCM_WM_HINT_INPUT)) {
-                       c->icccm_input = hints.input;
-               }
-       }
+                       HANDLE_WM_STATE(MODAL)
+                       HANDLE_WM_STATE(STICKY)
+                       HANDLE_WM_STATE(MAXIMIZED_VERT)
+                       HANDLE_WM_STATE(MAXIMIZED_HORZ)
+                       HANDLE_WM_STATE(SHADED)
+                       HANDLE_WM_STATE(SKIP_TASKBAR)
+                       HANDLE_WM_STATE(SKIP_PAGER)
+                       HANDLE_WM_STATE(HIDDEN)
+                       HANDLE_WM_STATE(FULLSCREEN)
+                       HANDLE_WM_STATE(ABOVE)
+                       HANDLE_WM_STATE(BELOW)
+                       HANDLE_WM_STATE(DEMANDS_ATTENTION)
+#undef HANDLE_WM_STATE
+               }
+               xcb_ewmh_get_atoms_reply_wipe(&wm_state);
+       }
+       xcb_icccm_wm_hints_t hints;
+       if (xcb_icccm_get_wm_hints_reply(dpy, xcb_icccm_get_wm_hints(dpy, win), &hints, NULL) == 1
+               && (hints.flags & XCB_ICCCM_WM_HINT_INPUT)) {
+               c->icccm_props.input_hint = hints.input;
+       }
+       xcb_icccm_get_wm_normal_hints_reply(dpy, xcb_icccm_get_wm_normal_hints(dpy, win), &c->size_hints, NULL);
 }
 
 bool is_leaf(node_t *n)
@@ -1261,6 +1276,9 @@ void remove_node(monitor_t *m, desktop_t *d, node_t *n)
                m->sticky_count -= sticky_count(n);
        }
        clients_count -= clients_count_in(n);
+       if (grabbed_node == n) {
+               grabbed_node = NULL;
+       }
        free(n->client);
        free(n);
 
@@ -1592,6 +1610,18 @@ bool set_layer(monitor_t *m, desktop_t *d, node_t *n, stack_layer_t l)
        n->client->last_layer = n->client->layer;
        n->client->layer = l;
 
+       if (l == LAYER_ABOVE) {
+               n->client->wm_flags |= WM_FLAG_ABOVE;
+               n->client->wm_flags &= ~WM_FLAG_BELOW;
+       } else if (l == LAYER_BELOW) {
+               n->client->wm_flags |= WM_FLAG_BELOW;
+               n->client->wm_flags &= ~WM_FLAG_ABOVE;
+       } else {
+               n->client->wm_flags &= ~(WM_FLAG_ABOVE | WM_FLAG_BELOW);
+       }
+
+       ewmh_wm_state_update(n);
+
        put_status(SBSC_MASK_NODE_LAYER, "node_layer 0x%08X 0x%08X 0x%08X %s\n", m->id, d->id, n->id, LAYER_STR(l));
 
        if (d->focus == n) {
@@ -1677,17 +1707,18 @@ void set_fullscreen(monitor_t *m, desktop_t *d, node_t *n, bool value)
        set_vacant_state(m, d, n, value);
 
        if (value) {
-               ewmh_wm_state_add(n, ewmh->_NET_WM_STATE_FULLSCREEN);
+               c->wm_flags |= WM_FLAG_FULLSCREEN;
                c->last_layer = c->layer;
                c->layer = LAYER_ABOVE;
        } else {
-               ewmh_wm_state_remove(n, ewmh->_NET_WM_STATE_FULLSCREEN);
+               c->wm_flags &= ~WM_FLAG_FULLSCREEN;
                c->layer = c->last_layer;
                if (d->focus == n) {
                        neutralize_occluding_windows(m, d, n);
                }
        }
 
+       ewmh_wm_state_update(n);
        stack(d, n, (d->focus == n));
 }
 
@@ -1736,13 +1767,20 @@ void set_sticky(monitor_t *m, desktop_t *d, node_t *n, bool value)
        n->sticky = value;
 
        if (value) {
-               ewmh_wm_state_add(n, ewmh->_NET_WM_STATE_STICKY);
                m->sticky_count++;
        } else {
-               ewmh_wm_state_remove(n, ewmh->_NET_WM_STATE_STICKY);
                m->sticky_count--;
        }
 
+       if (n->client != NULL) {
+               if (value) {
+                       n->client->wm_flags |= WM_FLAG_STICKY;
+               } else {
+                       n->client->wm_flags &= ~WM_FLAG_STICKY;
+               }
+               ewmh_wm_state_update(n);
+       }
+
        put_status(SBSC_MASK_NODE_FLAG, "node_flag 0x%08X 0x%08X 0x%08X sticky %s\n", m->id, d->id, n->id, ON_OFF_STR(value));
 
        if (n == m->desk->focus) {
@@ -1774,6 +1812,14 @@ void set_urgent(monitor_t *m, desktop_t *d, node_t *n, bool value)
 
        n->client->urgent = value;
 
+       if (value) {
+               n->client->wm_flags |= WM_FLAG_DEMANDS_ATTENTION;
+       } else {
+               n->client->wm_flags &= ~WM_FLAG_DEMANDS_ATTENTION;
+       }
+
+       ewmh_wm_state_update(n);
+
        put_status(SBSC_MASK_NODE_FLAG, "node_flag 0x%08X 0x%08X 0x%08X urgent %s\n", m->id, d->id, n->id, ON_OFF_STR(value));
        put_status(SBSC_MASK_REPORT);
 }
diff --git a/types.h b/types.h
index e58139037bd3b94344fe22c53c25f2985c894c2b..4fdeedc28710a9ae5cff951c890fd67bc4e56bad 100644 (file)
--- a/types.h
+++ b/types.h
@@ -26,6 +26,7 @@
 #define BSPWM_TYPES_H
 #include <stdbool.h>
 #include <xcb/xcb.h>
+#include <xcb/xcb_icccm.h>
 #include <xcb/randr.h>
 #include <xcb/xcb_event.h>
 #include "helpers.h"
@@ -50,6 +51,21 @@ typedef enum {
        STATE_FULLSCREEN
 } client_state_t;
 
+typedef enum {
+       WM_FLAG_MODAL = 1 << 0,
+       WM_FLAG_STICKY = 1 << 1,
+       WM_FLAG_MAXIMIZED_VERT = 1 << 2,
+       WM_FLAG_MAXIMIZED_HORZ = 1 << 3,
+       WM_FLAG_SHADED = 1 << 4,
+       WM_FLAG_SKIP_TASKBAR = 1 << 5,
+       WM_FLAG_SKIP_PAGER = 1 << 6,
+       WM_FLAG_HIDDEN = 1 << 7,
+       WM_FLAG_FULLSCREEN = 1 << 8,
+       WM_FLAG_ABOVE = 1 << 9,
+       WM_FLAG_BELOW = 1 << 10,
+       WM_FLAG_DEMANDS_ATTENTION = 1 << 11,
+} wm_flags_t;
+
 typedef enum {
        LAYER_BELOW,
        LAYER_NORMAL,
@@ -90,21 +106,17 @@ typedef enum {
 } direction_t;
 
 typedef enum {
-       CORNER_TOP_LEFT,
-       CORNER_TOP_RIGHT,
-       CORNER_BOTTOM_RIGHT,
-       CORNER_BOTTOM_LEFT
-} corner_t;
-
-typedef enum {
-       SIDE_LEFT,
-       SIDE_TOP,
-       SIDE_RIGHT,
-       SIDE_BOTTOM
-} side_t;
+       HANDLE_LEFT = 1 << 0,
+       HANDLE_TOP = 1 << 1,
+       HANDLE_RIGHT = 1 << 2,
+       HANDLE_BOTTOM = 1 << 3,
+       HANDLE_TOP_LEFT = HANDLE_TOP | HANDLE_LEFT,
+       HANDLE_TOP_RIGHT = HANDLE_TOP | HANDLE_RIGHT,
+       HANDLE_BOTTOM_RIGHT = HANDLE_BOTTOM | HANDLE_RIGHT,
+       HANDLE_BOTTOM_LEFT = HANDLE_BOTTOM | HANDLE_LEFT
+} resize_handle_t;
 
 typedef enum {
-       ACTION_NONE,
        ACTION_FOCUS,
        ACTION_MOVE,
        ACTION_RESIZE_SIDE,
@@ -158,6 +170,12 @@ typedef struct {
        option_bool_t focused;
 } monitor_select_t;
 
+typedef struct icccm_props_t icccm_props_t;
+struct icccm_props_t {
+       bool take_focus;
+       bool input_hint;
+};
+
 typedef struct {
        char class_name[3 * SMALEN / 2];
        char instance_name[3 * SMALEN / 2];
@@ -170,14 +188,9 @@ typedef struct {
        stack_layer_t last_layer;
        xcb_rectangle_t floating_rectangle;
        xcb_rectangle_t tiled_rectangle;
-       bool icccm_focus;
-       bool icccm_input;
-       uint16_t min_width;
-       uint16_t max_width;
-       uint16_t min_height;
-       uint16_t max_height;
-       xcb_atom_t wm_state[MAX_WM_STATES];
-       int wm_states_count;
+       xcb_size_hints_t size_hints;
+       icccm_props_t icccm_props;
+       wm_flags_t wm_flags;
 } client_t;
 
 typedef struct presel_t presel_t;
@@ -296,10 +309,6 @@ typedef struct {
        double split_ratio;
        stack_layer_t *layer;
        client_state_t *state;
-       uint16_t min_width;
-       uint16_t max_width;
-       uint16_t min_height;
-       uint16_t max_height;
        bool locked;
        bool sticky;
        bool private;
@@ -319,27 +328,4 @@ struct pending_rule_t {
        pending_rule_t *next;
 };
 
-typedef struct {
-       xcb_point_t position;
-       pointer_action_t action;
-       xcb_rectangle_t rectangle;
-       node_t *vertical_fence;
-       node_t *horizontal_fence;
-       monitor_t *monitor;
-       desktop_t *desktop;
-       node_t *node;
-       client_t *client;
-       xcb_window_t window;
-       bool is_tiled;
-       double vertical_ratio;
-       double horizontal_ratio;
-       corner_t corner;
-       side_t side;
-} pointer_state_t;
-
-typedef struct {
-       node_t *fence;
-       unsigned int distance;
-} fence_distance_t;
-
 #endif
index 57f48a773fdaeb2361246683f60477454fe47e78..b456fa56b9623bbfb89a347a950de36d18094d0d 100644 (file)
--- a/window.c
+++ b/window.c
@@ -33,6 +33,7 @@
 #include "rule.h"
 #include "settings.h"
 #include "geometry.h"
+#include "pointer.h"
 #include "stack.h"
 #include "tree.h"
 #include "parse.h"
@@ -131,17 +132,12 @@ void manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
        c->border_width = csq->border ? d->border_width : 0;
        n->client = c;
        initialize_client(n);
-       update_floating_rectangle(n);
+       initialize_floating_rectangle(n);
 
        if (c->floating_rectangle.x == 0 && c->floating_rectangle.y == 0) {
                csq->center = true;
        }
 
-       c->min_width = csq->min_width;
-       c->max_width = csq->max_width;
-       c->min_height = csq->min_height;
-       c->max_height = csq->max_height;
-
        monitor_t *mm = monitor_from_client(c);
        embrace_client(mm, c);
        adapt_geometry(&mm->rectangle, &m->rectangle, n);
@@ -213,9 +209,6 @@ void unmanage_window(xcb_window_t win)
        if (locate_window(win, &loc)) {
                put_status(SBSC_MASK_NODE_UNMANAGE, "node_unmanage 0x%08X 0x%08X 0x%08X\n", loc.monitor->id, loc.desktop->id, win);
                remove_node(loc.monitor, loc.desktop, loc.node);
-               if (frozen_pointer->window == win) {
-                       frozen_pointer->action = ACTION_NONE;
-               }
                arrange(loc.monitor, loc.desktop);
        } else {
                for (pending_rule_t *pr = pending_rule_head; pr != NULL; pr = pr->next) {
@@ -377,18 +370,6 @@ void window_draw_border(xcb_window_t win, uint32_t border_color_pxl)
        xcb_change_window_attributes(dpy, win, XCB_CW_BORDER_PIXEL, &border_color_pxl);
 }
 
-pointer_state_t *make_pointer_state(void)
-{
-       pointer_state_t *p = malloc(sizeof(pointer_state_t));
-       p->monitor = NULL;
-       p->desktop = NULL;
-       p->node = p->vertical_fence = p->horizontal_fence = NULL;
-       p->client = NULL;
-       p->window = XCB_NONE;
-       p->action = ACTION_NONE;
-       return p;
-}
-
 void adopt_orphans(void)
 {
        xcb_query_tree_reply_t *qtr = xcb_query_tree_reply(dpy, xcb_query_tree(dpy, root), NULL);
@@ -421,7 +402,7 @@ uint32_t get_border_color(bool focused_node, bool focused_monitor)
        }
 }
 
-void update_floating_rectangle(node_t *n)
+void initialize_floating_rectangle(node_t *n)
 {
        client_t *c = n->client;
 
@@ -434,34 +415,218 @@ void update_floating_rectangle(node_t *n)
        free(geo);
 }
 
-void restrain_floating_width(client_t *c, int *width)
+bool move_client(coordinates_t *loc, int dx, int dy)
 {
-       if (*width < 1) {
-               *width = 1;
+       node_t *n = loc->node;
+
+       if (n == NULL || n->client == NULL) {
+               return false;
+       }
+
+       monitor_t *pm = NULL;
+
+       if (IS_TILED(n->client)) {
+               if (!grabbing) {
+                       return false;
+               }
+               xcb_window_t pwin = XCB_NONE;
+               query_pointer(&pwin, NULL);
+               if (pwin == n->id) {
+                       return false;
+               }
+               coordinates_t dst;
+               bool is_managed = (pwin != XCB_NONE && locate_window(pwin, &dst));
+               if (is_managed && dst.monitor == loc->monitor && IS_TILED(dst.node->client)) {
+                       swap_nodes(loc->monitor, loc->desktop, n, loc->monitor, loc->desktop, dst.node);
+                       return true;
+               } else {
+                       if (is_managed && dst.monitor == loc->monitor) {
+                               return false;
+                       } else {
+                               xcb_point_t pt = {0, 0};
+                               query_pointer(NULL, &pt);
+                               pm = monitor_from_point(pt);
+                       }
+               }
+       } else {
+               client_t *c = n->client;
+               xcb_rectangle_t rect = c->floating_rectangle;
+               int16_t x = rect.x + dx;
+               int16_t y = rect.y + dy;
+               window_move(n->id, x, y);
+               c->floating_rectangle.x = x;
+               c->floating_rectangle.y = y;
+               if (!grabbing) {
+                       put_status(SBSC_MASK_NODE_GEOMETRY, "node_geometry 0x%08X 0x%08X 0x%08X %ux%u+%i+%i\n", loc->monitor->id, loc->desktop->id, loc->node->id, rect.width, rect.height, x, y);
+               }
+               pm = monitor_from_client(c);
        }
-       if (c->min_width > 0 && *width < c->min_width) {
-               *width = c->min_width;
-       } else if (c->max_width > 0 && *width > c->max_width) {
-               *width = c->max_width;
+
+       if (pm == NULL || pm == loc->monitor) {
+               return true;
        }
+
+       bool focused = (n == mon->desk->focus);
+       transfer_node(loc->monitor, loc->desktop, n, pm, pm->desk, pm->desk->focus);
+       loc->monitor = pm;
+       loc->desktop = pm->desk;
+       if (focused) {
+               focus_node(pm, pm->desk, n);
+       }
+
+       return true;
 }
 
-void restrain_floating_height(client_t *c, int *height)
+bool resize_client(coordinates_t *loc, resize_handle_t rh, int dx, int dy)
 {
-       if (*height < 1) {
-               *height = 1;
+       node_t *n = loc->node;
+       if (n == NULL || n->client == NULL || n->client->state == STATE_FULLSCREEN) {
+               return false;
        }
-       if (c->min_height > 0 && *height < c->min_height) {
-               *height = c->min_height;
-       } else if (c->max_height > 0 && *height > c->max_height) {
-               *height = c->max_height;
+       node_t *horizontal_fence = NULL, *vertical_fence = NULL;
+       xcb_rectangle_t rect = get_rectangle(NULL, n);
+       uint16_t width = rect.width, height = rect.height;
+       int16_t x = rect.x, y = rect.y;
+       if (n->client->state == STATE_TILED) {
+               if (rh & HANDLE_LEFT) {
+                       vertical_fence = find_fence(n, DIR_WEST);
+               } else if (rh & HANDLE_RIGHT) {
+                       vertical_fence = find_fence(n, DIR_EAST);
+               }
+               if (rh & HANDLE_TOP) {
+                       horizontal_fence = find_fence(n, DIR_NORTH);
+               } else if (rh & HANDLE_BOTTOM) {
+                       horizontal_fence = find_fence(n, DIR_SOUTH);
+               }
+               if (vertical_fence != NULL) {
+                       double sr = vertical_fence->split_ratio + (double) dx / vertical_fence->rectangle.width;
+                       sr = MAX(0, sr);
+                       sr = MIN(1, sr);
+                       vertical_fence->split_ratio = sr;
+               }
+               if (horizontal_fence != NULL) {
+                       double sr = horizontal_fence->split_ratio + (double) dy / horizontal_fence->rectangle.height;
+                       sr = MAX(0, sr);
+                       sr = MIN(1, sr);
+                       horizontal_fence->split_ratio = sr;
+               }
+               arrange(loc->monitor, loc->desktop);
+       } else {
+               int w = width + dx * (rh & HANDLE_LEFT ? -1 : (rh & HANDLE_RIGHT ? 1 : 0));
+               int h = height + dy * (rh & HANDLE_TOP ? -1 : (rh & HANDLE_BOTTOM ? 1 : 0));
+               width = MAX(1, w);
+               height = MAX(1, h);
+               apply_size_hints(n->client, &width, &height);
+               if (rh & HANDLE_LEFT) {
+                       x += rect.width - width;
+               }
+               if (rh & HANDLE_TOP) {
+                       y += rect.height - height;
+               }
+               n->client->floating_rectangle = (xcb_rectangle_t) {x, y, width, height};
+               if (n->client->state == STATE_FLOATING) {
+                       window_move_resize(n->id, x, y, width, height);
+                       if (!grabbing) {
+                               put_status(SBSC_MASK_NODE_GEOMETRY, "node_geometry 0x%08X 0x%08X 0x%08X %ux%u+%i+%i\n", loc->monitor->id, loc->desktop->id, loc->node->id, width, height, x, y);
+                       }
+               } else {
+                       arrange(loc->monitor, loc->desktop);
+               }
        }
+       return true;
 }
 
-void restrain_floating_size(client_t *c, int *width, int *height)
+/* taken from awesomeWM */
+void apply_size_hints(client_t *c, uint16_t *width, uint16_t *height)
 {
-       restrain_floating_width(c, width);
-       restrain_floating_height(c, height);
+       if (!honor_size_hints) {
+               return;
+       }
+
+       int32_t minw = 0, minh = 0;
+       int32_t basew = 0, baseh = 0, real_basew = 0, real_baseh = 0;
+
+       if (c->state == STATE_FULLSCREEN) {
+               return;
+       }
+
+       if (c->size_hints.flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE) {
+               basew = c->size_hints.base_width;
+               baseh = c->size_hints.base_height;
+               real_basew = basew;
+               real_baseh = baseh;
+       } else if (c->size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) {
+               /* base size is substituted with min size if not specified */
+               basew = c->size_hints.min_width;
+               baseh = c->size_hints.min_height;
+       }
+
+       if (c->size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) {
+               minw = c->size_hints.min_width;
+               minh = c->size_hints.min_height;
+       } else if (c->size_hints.flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE) {
+               /* min size is substituted with base size if not specified */
+               minw = c->size_hints.base_width;
+               minh = c->size_hints.base_height;
+       }
+
+       /* Handle the size aspect ratio */
+       if (c->size_hints.flags & XCB_ICCCM_SIZE_HINT_P_ASPECT &&
+           c->size_hints.min_aspect_den > 0 &&
+           c->size_hints.max_aspect_den > 0 &&
+           *height > real_baseh &&
+           *width > real_basew) {
+               /* ICCCM mandates:
+                * If a base size is provided along with the aspect ratio fields, the base size should be subtracted from the
+                * window size prior to checking that the aspect ratio falls in range. If a base size is not provided, nothing
+                * should be subtracted from the window size. (The minimum size is not to be used in place of the base size for
+                * this purpose.)
+                */
+               double dx = *width - real_basew;
+               double dy = *height - real_baseh;
+               double ratio = dx / dy;
+               double min = c->size_hints.min_aspect_num / (double) c->size_hints.min_aspect_den;
+               double max = c->size_hints.max_aspect_num / (double) c->size_hints.max_aspect_den;
+
+               if (max > 0 && min > 0 && ratio > 0) {
+                       if (ratio < min) {
+                               /* dx is lower than allowed, make dy lower to compensate this (+ 0.5 to force proper rounding). */
+                               dy = dx / min + 0.5;
+                               *width  = dx + real_basew;
+                               *height = dy + real_baseh;
+                       } else if (ratio > max) {
+                               /* dx is too high, lower it (+0.5 for proper rounding) */
+                               dx = dy * max + 0.5;
+                               *width  = dx + real_basew;
+                               *height = dy + real_baseh;
+                       }
+               }
+       }
+
+       /* Handle the minimum size */
+       *width = MAX(*width, minw);
+       *height = MAX(*height, minh);
+
+       /* Handle the maximum size */
+       if (c->size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE)
+       {
+               if (c->size_hints.max_width > 0) {
+                       *width = MIN(*width, c->size_hints.max_width);
+               }
+               if (c->size_hints.max_height > 0) {
+                       *height = MIN(*height, c->size_hints.max_height);
+               }
+       }
+
+       /* Handle the size increment */
+       if (c->size_hints.flags & (XCB_ICCCM_SIZE_HINT_P_RESIZE_INC | XCB_ICCCM_SIZE_HINT_BASE_SIZE) &&
+           c->size_hints.width_inc > 0 && c->size_hints.height_inc > 0) {
+               uint16_t t1 = *width, t2 = *height;
+               unsigned_subtract(t1, basew);
+               unsigned_subtract(t2, baseh);
+               *width -= t1 % c->size_hints.width_inc;
+               *height -= t2 % c->size_hints.height_inc;
+       }
 }
 
 void query_pointer(xcb_window_t *win, xcb_point_t *pt)
@@ -626,9 +791,9 @@ void set_input_focus(node_t *n)
        if (n == NULL || n->client == NULL) {
                clear_input_focus();
        } else {
-               if (n->client->icccm_input) {
+               if (n->client->icccm_props.input_hint) {
                        xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_PARENT, n->id, XCB_CURRENT_TIME);
-               } else if (n->client->icccm_focus) {
+               } else if (n->client->icccm_props.take_focus) {
                        send_client_message(n->id, ewmh->WM_PROTOCOLS, WM_TAKE_FOCUS);
                }
        }
@@ -641,6 +806,9 @@ void clear_input_focus(void)
 
 void center_pointer(xcb_rectangle_t r)
 {
+       if (grabbing) {
+               return;
+       }
        int16_t cx = r.x + r.width / 2;
        int16_t cy = r.y + r.height / 2;
        window_lower(motion_recorder);
index dbd8dad8e7319ab20339664c0cfec257ba0d0f8c..3bc464742baa5600a084c9113f11bd0005f51d93 100644 (file)
--- a/window.h
+++ b/window.h
@@ -42,13 +42,12 @@ void update_colors(void);
 void update_colors_in(node_t *n, desktop_t *d, monitor_t *m);
 void draw_border(node_t *n, bool focused_node, bool focused_monitor);
 void window_draw_border(xcb_window_t win, uint32_t border_color_pxl);
-pointer_state_t *make_pointer_state(void);
 void adopt_orphans(void);
 uint32_t get_border_color(bool focused_node, bool focused_monitor);
-void update_floating_rectangle(node_t *n);
-void restrain_floating_width(client_t *c, int *width);
-void restrain_floating_height(client_t *c, int *height);
-void restrain_floating_size(client_t *c, int *width, int *height);
+void initialize_floating_rectangle(node_t *n);
+bool move_client(coordinates_t *loc, int dx, int dy);
+bool resize_client(coordinates_t *loc, resize_handle_t rh, int dx, int dy);
+void apply_size_hints(client_t *c, uint16_t *width, uint16_t *height);
 void query_pointer(xcb_window_t *win, xcb_point_t *pt);
 void window_border_width(xcb_window_t win, uint32_t bw);
 void window_move(xcb_window_t win, int16_t x, int16_t y);