Add better icccm support
This commit is contained in:
111
X-kutu.c
111
X-kutu.c
@@ -1,3 +1,4 @@
|
|||||||
|
#include <xcb/xproto.h>
|
||||||
#define CLEANMASK(m) ((m & ~0x80))
|
#define CLEANMASK(m) ((m & ~0x80))
|
||||||
|
|
||||||
// Definitions for modifier keys
|
// Definitions for modifier keys
|
||||||
@@ -12,10 +13,12 @@
|
|||||||
// Standard headers
|
// Standard headers
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
// XCB header
|
// XCB header
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
|
#include <xcb/xcb_icccm.h>
|
||||||
|
|
||||||
// Global variables
|
// Global variables
|
||||||
// Connection to X server
|
// Connection to X server
|
||||||
@@ -72,7 +75,6 @@ void add_mousebind(int button) {
|
|||||||
// Deploy function to initialize the X connection, set up event masks, and
|
// Deploy function to initialize the X connection, set up event masks, and
|
||||||
// prepare the window manager
|
// prepare the window manager
|
||||||
int deploy(void) {
|
int deploy(void) {
|
||||||
uint32_t values[2];
|
|
||||||
int mask;
|
int mask;
|
||||||
|
|
||||||
// Start X connection and return -1 if it fails
|
// Start X connection and return -1 if it fails
|
||||||
@@ -85,7 +87,12 @@ int deploy(void) {
|
|||||||
|
|
||||||
// Setuup event masks
|
// Setuup event masks
|
||||||
mask = XCB_CW_EVENT_MASK;
|
mask = XCB_CW_EVENT_MASK;
|
||||||
values[0] = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
|
|
||||||
|
uint32_t values[] = {XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
|
||||||
|
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
|
||||||
|
XCB_EVENT_MASK_STRUCTURE_NOTIFY |
|
||||||
|
XCB_EVENT_MASK_PROPERTY_CHANGE};
|
||||||
|
|
||||||
xcb_change_window_attributes_checked(conn, scr->root, mask, values);
|
xcb_change_window_attributes_checked(conn, scr->root, mask, values);
|
||||||
|
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
@@ -186,6 +193,52 @@ void resize_window(xcb_window_t win, int width, int height) {
|
|||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xcb_size_hints_t get_wm_n_hints(xcb_window_t win) {
|
||||||
|
xcb_size_hints_t hints;
|
||||||
|
xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_normal_hints(conn, win);
|
||||||
|
xcb_icccm_get_wm_normal_hints_reply(conn, cookie, &hints, NULL);
|
||||||
|
return hints;
|
||||||
|
}
|
||||||
|
|
||||||
|
xcb_icccm_wm_hints_t get_wm_hints(xcb_window_t win) {
|
||||||
|
xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_hints(conn, win);
|
||||||
|
xcb_icccm_wm_hints_t hints;
|
||||||
|
xcb_icccm_get_wm_hints_reply(conn, cookie, &hints, NULL);
|
||||||
|
return hints;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *get_wm_name(xcb_window_t win) {
|
||||||
|
xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_name(conn, win);
|
||||||
|
xcb_icccm_get_text_property_reply_t reply;
|
||||||
|
xcb_icccm_get_wm_name_reply(conn, cookie, &reply, NULL);
|
||||||
|
return reply.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t get_wm_transient_for(xcb_window_t win) {
|
||||||
|
xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_transient_for(conn, win);
|
||||||
|
return xcb_icccm_get_wm_transient_for_reply(conn, cookie, &win, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_wm_state(xcb_window_t win, int state) {
|
||||||
|
xcb_intern_atom_cookie_t cookie =
|
||||||
|
xcb_intern_atom(conn, 0, strlen("WM_STATE"), "WM_STATE");
|
||||||
|
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, cookie, NULL);
|
||||||
|
if (!reply)
|
||||||
|
return;
|
||||||
|
|
||||||
|
xcb_atom_t WM_STATE = reply->atom;
|
||||||
|
free(reply);
|
||||||
|
|
||||||
|
uint32_t data[2];
|
||||||
|
data[0] = state;
|
||||||
|
data[1] = XCB_WINDOW_NONE;
|
||||||
|
|
||||||
|
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win, WM_STATE, WM_STATE, 32,
|
||||||
|
2, data);
|
||||||
|
|
||||||
|
xcb_flush(conn);
|
||||||
|
}
|
||||||
|
|
||||||
// Wait for an event and return it as an Event structure
|
// Wait for an event and return it as an Event structure
|
||||||
// This function is blocking
|
// This function is blocking
|
||||||
// The event is sent by value, so no need to free anything
|
// The event is sent by value, so no need to free anything
|
||||||
@@ -225,7 +278,7 @@ Event wait_for_event(void) {
|
|||||||
case XCB_MAP_NOTIFY: {
|
case XCB_MAP_NOTIFY: {
|
||||||
xcb_map_notify_event_t *e;
|
xcb_map_notify_event_t *e;
|
||||||
e = (xcb_map_notify_event_t *)ev;
|
e = (xcb_map_notify_event_t *)ev;
|
||||||
ret.type = -1;
|
ret.type = 4;
|
||||||
ret.window = e->window;
|
ret.window = e->window;
|
||||||
ret.override_redirect = e->override_redirect;
|
ret.override_redirect = e->override_redirect;
|
||||||
} break;
|
} break;
|
||||||
@@ -233,9 +286,8 @@ Event wait_for_event(void) {
|
|||||||
case XCB_MAP_REQUEST: {
|
case XCB_MAP_REQUEST: {
|
||||||
xcb_map_request_event_t *e;
|
xcb_map_request_event_t *e;
|
||||||
e = (xcb_map_request_event_t *)ev;
|
e = (xcb_map_request_event_t *)ev;
|
||||||
ret.type = 4;
|
ret.type = 5;
|
||||||
ret.window = e->window;
|
ret.window = e->window;
|
||||||
ret.override_redirect = 1;
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case XCB_BUTTON_PRESS: {
|
case XCB_BUTTON_PRESS: {
|
||||||
@@ -249,7 +301,7 @@ Event wait_for_event(void) {
|
|||||||
XCB_EVENT_MASK_POINTER_MOTION_HINT,
|
XCB_EVENT_MASK_POINTER_MOTION_HINT,
|
||||||
XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, e->child,
|
XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, e->child,
|
||||||
XCB_NONE, XCB_CURRENT_TIME);
|
XCB_NONE, XCB_CURRENT_TIME);
|
||||||
ret.type = 5;
|
ret.type = 6;
|
||||||
ret.window = e->child;
|
ret.window = e->child;
|
||||||
ret.is_root = e->child == scr->root;
|
ret.is_root = e->child == scr->root;
|
||||||
ret.x = e->event_x;
|
ret.x = e->event_x;
|
||||||
@@ -259,7 +311,7 @@ Event wait_for_event(void) {
|
|||||||
|
|
||||||
case XCB_MOTION_NOTIFY: {
|
case XCB_MOTION_NOTIFY: {
|
||||||
xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *)ev;
|
xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *)ev;
|
||||||
ret.type = 6;
|
ret.type = 7;
|
||||||
ret.window = e->child;
|
ret.window = e->child;
|
||||||
ret.x = e->event_x;
|
ret.x = e->event_x;
|
||||||
ret.y = e->event_y;
|
ret.y = e->event_y;
|
||||||
@@ -270,7 +322,7 @@ Event wait_for_event(void) {
|
|||||||
xcb_button_release_event_t *e = (xcb_button_release_event_t *)ev;
|
xcb_button_release_event_t *e = (xcb_button_release_event_t *)ev;
|
||||||
// Ungrab pointer after dragging
|
// Ungrab pointer after dragging
|
||||||
xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
|
xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
|
||||||
ret.type = 7;
|
ret.type = 8;
|
||||||
ret.x = e->event_x;
|
ret.x = e->event_x;
|
||||||
ret.y = e->event_y;
|
ret.y = e->event_y;
|
||||||
ret.btn = e->detail;
|
ret.btn = e->detail;
|
||||||
@@ -279,7 +331,7 @@ Event wait_for_event(void) {
|
|||||||
case XCB_KEY_PRESS: {
|
case XCB_KEY_PRESS: {
|
||||||
xcb_key_press_event_t *e;
|
xcb_key_press_event_t *e;
|
||||||
e = (xcb_key_press_event_t *)ev;
|
e = (xcb_key_press_event_t *)ev;
|
||||||
ret.type = 8;
|
ret.type = 9;
|
||||||
ret.window = e->child;
|
ret.window = e->child;
|
||||||
ret.btn = e->detail;
|
ret.btn = e->detail;
|
||||||
ret.state = e->state;
|
ret.state = e->state;
|
||||||
@@ -288,22 +340,49 @@ Event wait_for_event(void) {
|
|||||||
case XCB_KEY_RELEASE: {
|
case XCB_KEY_RELEASE: {
|
||||||
xcb_key_release_event_t *e;
|
xcb_key_release_event_t *e;
|
||||||
e = (xcb_key_release_event_t *)ev;
|
e = (xcb_key_release_event_t *)ev;
|
||||||
ret.type = 9;
|
ret.type = 10;
|
||||||
ret.window = e->child;
|
ret.window = e->child;
|
||||||
ret.btn = e->detail;
|
ret.btn = e->detail;
|
||||||
ret.state = e->state;
|
ret.state = e->state;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case XCB_CONFIGURE_NOTIFY: {
|
case XCB_UNMAP_NOTIFY: {
|
||||||
xcb_configure_notify_event_t *e;
|
xcb_unmap_notify_event_t *e;
|
||||||
e = (xcb_configure_notify_event_t *)ev;
|
e = (xcb_unmap_notify_event_t *)ev;
|
||||||
ret.type = 10;
|
ret.type = 11;
|
||||||
|
ret.window = e->window;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case XCB_CONFIGURE_REQUEST: {
|
||||||
|
xcb_configure_request_event_t *e = (xcb_configure_request_event_t *)ev;
|
||||||
|
ret.type = 12;
|
||||||
|
ret.window = e->window;
|
||||||
|
ret.x = e->x;
|
||||||
|
ret.y = e->y;
|
||||||
|
ret.width = e->width;
|
||||||
|
ret.height = e->height;
|
||||||
|
// ret.stack_mode =
|
||||||
|
// e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE ? e->stack_mode : 0;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case XCB_RESIZE_REQUEST: {
|
||||||
|
xcb_resize_request_event_t *e = (xcb_resize_request_event_t *)ev;
|
||||||
|
ret.type = 13;
|
||||||
ret.window = e->window;
|
ret.window = e->window;
|
||||||
ret.width = e->width;
|
ret.width = e->width;
|
||||||
ret.height = e->height;
|
ret.height = e->height;
|
||||||
ret.x = e->x;
|
|
||||||
ret.y = e->y;
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
// case XCB_CONFIGURE_NOTIFY: {
|
||||||
|
// xcb_configure_notify_event_t *e;
|
||||||
|
// e = (xcb_configure_notify_event_t *)ev;
|
||||||
|
// ret.type = 12;
|
||||||
|
// ret.window = e->window;
|
||||||
|
// ret.width = e->width;
|
||||||
|
// ret.height = e->height;
|
||||||
|
// ret.x = e->x;
|
||||||
|
// ret.y = e->y;
|
||||||
|
// } break;
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ set -euo pipefail
|
|||||||
|
|
||||||
DIR="$(cd -- "$(dirname -- "$0")" && pwd)"
|
DIR="$(cd -- "$(dirname -- "$0")" && pwd)"
|
||||||
|
|
||||||
if ! XCB=$(pkg-config --cflags --libs xcb 2>/dev/null); then
|
if ! XCB=$(pkg-config --cflags --libs xcb xcb-icccm 2>/dev/null); then
|
||||||
echo "Error: lib-xcb not found. Please install lib-xcb." >&2
|
echo "Error: lib-xcb not found. Please install lib-xcb." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
193
kutu.rb
193
kutu.rb
@@ -7,6 +7,8 @@ module X
|
|||||||
ffi_lib File.join(__dir__, "X-kutu.so")
|
ffi_lib File.join(__dir__, "X-kutu.so")
|
||||||
|
|
||||||
typedef :uint32, :window_id
|
typedef :uint32, :window_id
|
||||||
|
typedef :uint32, :xcb_window_t
|
||||||
|
typedef :uint32, :xcb_pixmap_t
|
||||||
|
|
||||||
class Geometry < FFI::Struct
|
class Geometry < FFI::Struct
|
||||||
layout :x, :int16,
|
layout :x, :int16,
|
||||||
@@ -28,6 +30,39 @@ module X
|
|||||||
:is_root, :int8
|
:is_root, :int8
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class SizeHints < FFI::Struct
|
||||||
|
layout :flags, :uint32,
|
||||||
|
:x, :int32,
|
||||||
|
:y, :int32,
|
||||||
|
:width, :int32,
|
||||||
|
:height, :int32,
|
||||||
|
:min_width, :int32,
|
||||||
|
:min_height, :int32,
|
||||||
|
:max_width, :int32,
|
||||||
|
:max_height, :int32,
|
||||||
|
:width_inc, :int32,
|
||||||
|
:height_inc, :int32,
|
||||||
|
:min_aspect_num, :int32,
|
||||||
|
:min_aspect_den, :int32,
|
||||||
|
:max_aspect_num, :int32,
|
||||||
|
:max_aspect_den, :int32,
|
||||||
|
:base_width, :int32,
|
||||||
|
:base_height, :int32,
|
||||||
|
:win_gravity, :uint32
|
||||||
|
end
|
||||||
|
|
||||||
|
class WMHints < FFI::Struct
|
||||||
|
layout :flags, :int32,
|
||||||
|
:input, :uint32,
|
||||||
|
:initial_state,:int32,
|
||||||
|
:icon_pixmap, :xcb_pixmap_t,
|
||||||
|
:icon_window, :xcb_window_t,
|
||||||
|
:icon_x, :int32,
|
||||||
|
:icon_y, :int32,
|
||||||
|
:icon_mask, :xcb_pixmap_t,
|
||||||
|
:window_group, :xcb_window_t
|
||||||
|
end
|
||||||
|
|
||||||
attach_function :deploy, [], :int
|
attach_function :deploy, [], :int
|
||||||
attach_function :add_keybind, [:int], :void
|
attach_function :add_keybind, [:int], :void
|
||||||
attach_function :add_mousebind, [:int], :void
|
attach_function :add_mousebind, [:int], :void
|
||||||
@@ -47,6 +82,11 @@ module X
|
|||||||
attach_function :move_window, [:window_id, :int, :int], :void
|
attach_function :move_window, [:window_id, :int, :int], :void
|
||||||
attach_function :resize_window, [:window_id, :int, :int], :void
|
attach_function :resize_window, [:window_id, :int, :int], :void
|
||||||
attach_function :wait_for_event, [], Event.by_value
|
attach_function :wait_for_event, [], Event.by_value
|
||||||
|
attach_function :get_wm_name, [:window_id], :string
|
||||||
|
attach_function :get_wm_n_hints, [:window_id], SizeHints.by_value
|
||||||
|
attach_function :get_wm_hints, [:window_id], WMHints.by_value
|
||||||
|
attach_function :get_wm_transient_for, [:window_id], :uint8
|
||||||
|
attach_function :set_wm_state, [:window_id, :int], :void
|
||||||
end
|
end
|
||||||
|
|
||||||
if X.deploy < 0
|
if X.deploy < 0
|
||||||
@@ -70,15 +110,20 @@ def refresh_monitors
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
refresh_monitors
|
def fixed_size_or_aspect?(hints)
|
||||||
|
return false unless hints
|
||||||
|
flags = hints[:flags] || 0
|
||||||
|
same_size = (flags & (16 | 256) != 0) && (flags & 32 != 0) &&
|
||||||
|
hints[:max_width] == (hints[:min_width] || hints[:base_width]) &&
|
||||||
|
hints[:max_height] == (hints[:min_height] || hints[:base_height])
|
||||||
|
fixed_aspect = (flags & 128 != 0) &&
|
||||||
|
hints[:min_aspect_num] == hints[:max_aspect_num] &&
|
||||||
|
hints[:min_aspect_den] == hints[:max_aspect_den] &&
|
||||||
|
hints[:min_aspect_num] != 0
|
||||||
|
same_size || fixed_aspect
|
||||||
|
end
|
||||||
|
|
||||||
# def get_wm_normal_hints(window_id)
|
refresh_monitors
|
||||||
# xprop_output = `xprop -id 0x#{window_id.to_s(16)} WM_NORMAL_HINTS`
|
|
||||||
# return {} unless xprop_output =~ /WM_NORMAL_HINTS\(([^)]+)\):\s*(.*)/
|
|
||||||
# hints = {}
|
|
||||||
# # TODO: parse the output properly
|
|
||||||
# hints
|
|
||||||
# end
|
|
||||||
|
|
||||||
$workspaces = {}
|
$workspaces = {}
|
||||||
$windows = {}
|
$windows = {}
|
||||||
@@ -105,20 +150,62 @@ class Node
|
|||||||
end
|
end
|
||||||
|
|
||||||
class Window < Node
|
class Window < Node
|
||||||
attr_accessor :window_id, :x, :y, :width, :height#, :state
|
attr_accessor :window_id, :x, :y, :width, :height, :state, :floating, :workspace
|
||||||
|
|
||||||
def initialize(window_id)
|
def initialize(window_id, workspace)
|
||||||
|
@workspace = workspace
|
||||||
@window_id = window_id
|
@window_id = window_id
|
||||||
# @state = :widthrawn # :iconic, :withdrawn, :normal
|
@name = X.get_wm_name(window_id)
|
||||||
# ADD: properties for https://tronche.com/gui/x/icccm/sec-4.html#s-4 sec 4.1.2.(3, 4)
|
@wm_n_hints = X.get_wm_n_hints(window_id)
|
||||||
|
@floating = false
|
||||||
|
if @wm_n_hints
|
||||||
|
if fixed_size_or_aspect?(@wm_n_hints)
|
||||||
|
@floating = true
|
||||||
|
@width = @wm_n_hints[:max_width]
|
||||||
|
if @wm_n_hints[:flags] & 128 != 0
|
||||||
|
@height = @wm_n_hints[:max_width] * (@wm_n_hints[:min_aspect_num] / @wm_n_hints[:min_aspect_den])
|
||||||
|
else
|
||||||
|
@height = @wm_n_hints[:max_height]
|
||||||
|
end
|
||||||
|
@x = @workspace.width / 2 - @width / 2
|
||||||
|
@y = @workspace.height / 2 - @height / 2
|
||||||
|
apply_geometry!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@wm_hints = X.get_wm_hints(window_id)
|
||||||
|
if @wm_hints
|
||||||
|
if @wm_hints[:flags] & 1 != 0 && @wm_hints[:initial_state] == 3
|
||||||
|
X.set_wm_state window_id, 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@transient_for = X.get_wm_transient_for(window_id)
|
||||||
|
@floating = true unless @transient_for.zero?
|
||||||
super()
|
super()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def delete
|
||||||
|
@workspace.remove self
|
||||||
|
end
|
||||||
|
|
||||||
def each_leaf(&block)
|
def each_leaf(&block)
|
||||||
block.call(self)
|
block.call(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
def apply_geometry
|
def move(x, y)
|
||||||
|
return unless @floating
|
||||||
|
@x, @y = x, y
|
||||||
|
apply_geometry!
|
||||||
|
end
|
||||||
|
|
||||||
|
def resize(width, height)
|
||||||
|
return unless @floating
|
||||||
|
@x = @workspace.width / 2 - width / 2
|
||||||
|
@y = @workspace.height / 2 - height / 2
|
||||||
|
@width, @height = width, height
|
||||||
|
apply_geometry!
|
||||||
|
end
|
||||||
|
|
||||||
|
def apply_geometry!
|
||||||
X.move_window @window_id, @x, @y
|
X.move_window @window_id, @x, @y
|
||||||
X.resize_window @window_id, @width, @height
|
X.resize_window @window_id, @width, @height
|
||||||
end
|
end
|
||||||
@@ -172,7 +259,7 @@ class WindowBlock < Node
|
|||||||
child.height = child_size
|
child.height = child_size
|
||||||
end
|
end
|
||||||
child.compute_geometry! if child.is_a?(WindowBlock)
|
child.compute_geometry! if child.is_a?(WindowBlock)
|
||||||
child.apply_geometry if child.is_a?(Window)
|
child.apply_geometry! if child.is_a?(Window)
|
||||||
pos += child_size
|
pos += child_size
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -210,14 +297,19 @@ class Workspace
|
|||||||
end
|
end
|
||||||
|
|
||||||
def add(window_id)
|
def add(window_id)
|
||||||
@tiled_root_block.add_node Window.new(window_id)
|
window = Window.new(window_id, self)
|
||||||
$windows[window_id] = self
|
if window.floating
|
||||||
|
@untiled_windows << window
|
||||||
|
else
|
||||||
|
@tiled_root_block.add_node window
|
||||||
|
end
|
||||||
|
$windows[window_id] = window
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove(window_id)
|
def remove(window)
|
||||||
@untiled_windows.delete window_id
|
@untiled_windows.delete window
|
||||||
@tiled_root_block.each_node { |node| node.children.delete window_id }
|
@tiled_root_block.each_node { |node| node.children.delete window }
|
||||||
$windows.delete window_id
|
$windows.delete window.window_id
|
||||||
end
|
end
|
||||||
|
|
||||||
def close_all
|
def close_all
|
||||||
@@ -239,16 +331,18 @@ end
|
|||||||
EVENT_TYPES = {
|
EVENT_TYPES = {
|
||||||
0 => :unused,
|
0 => :unused,
|
||||||
1 => :create,
|
1 => :create,
|
||||||
2 => :close,
|
2 => :closed,
|
||||||
3 => :enter,
|
3 => :enter,
|
||||||
-1 => :show_after,
|
4 => :showed,
|
||||||
4 => :show,
|
5 => :show_request,
|
||||||
5 => :mouse_press,
|
6 => :mouse_press,
|
||||||
6 => :mouse_drag,
|
7 => :mouse_drag,
|
||||||
7 => :mouse_release,
|
8 => :mouse_release,
|
||||||
8 => :key_press,
|
9 => :key_press,
|
||||||
9 => :key_release,
|
10 => :key_release,
|
||||||
10 => :configured
|
11 => :closed,
|
||||||
|
12 => :configure_request,
|
||||||
|
13 => :resize_request
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
$workspaces[:main] = Workspace.new(:main)
|
$workspaces[:main] = Workspace.new(:main)
|
||||||
@@ -284,24 +378,32 @@ loop do
|
|||||||
next unless event[:override_redirect].zero?
|
next unless event[:override_redirect].zero?
|
||||||
X.subscribe event[:window]
|
X.subscribe event[:window]
|
||||||
X.focus event[:window]
|
X.focus event[:window]
|
||||||
when :close
|
when :closed
|
||||||
X.kill event[:window]
|
pp "Deleting window #{event[:window]}"
|
||||||
$windows[event[:window]]&.remove event[:window]
|
$windows[event[:window]]&.delete
|
||||||
|
$workspaces[:main].tiled_root_block.compute_geometry!
|
||||||
when :enter
|
when :enter
|
||||||
X.focus event[:window]
|
X.focus event[:window]
|
||||||
X.send_to_top event[:window]
|
X.send_to_top event[:window]
|
||||||
when :show_after
|
when :showed
|
||||||
next unless event[:override_redirect].zero?
|
next unless event[:override_redirect].zero?
|
||||||
X.focus event[:window]
|
X.focus event[:window]
|
||||||
|
X.send_to_top event[:window]
|
||||||
|
when :show_request
|
||||||
|
X.show event[:window]
|
||||||
$workspaces[:main].add event[:window] if $windows[event[:window]].nil?
|
$workspaces[:main].add event[:window] if $windows[event[:window]].nil?
|
||||||
$workspaces[:main].tiled_root_block.compute_geometry!
|
$workspaces[:main].tiled_root_block.compute_geometry!
|
||||||
when :show
|
|
||||||
X.show event[:window]
|
|
||||||
when :mouse_press
|
when :mouse_press
|
||||||
next if event[:is_root] != 0
|
next if event[:is_root] != 0
|
||||||
X.send_to_top event[:window]
|
X.send_to_top event[:window]
|
||||||
|
X.focus event[:window]
|
||||||
$mouse_state = event[:btn]
|
$mouse_state = event[:btn]
|
||||||
$mouse_window = event[:window]
|
$mouse_window = $windows[event[:window]]
|
||||||
|
if $mouse_window.nil?
|
||||||
|
$mouse_state = -1
|
||||||
|
$mouse_window = -1
|
||||||
|
next
|
||||||
|
end
|
||||||
$mouse_pos_start = X.get_pointer
|
$mouse_pos_start = X.get_pointer
|
||||||
$geom_start = X.get_geometry event[:window]
|
$geom_start = X.get_geometry event[:window]
|
||||||
$mousebind_actions[event[:btn]]&.call(event)
|
$mousebind_actions[event[:btn]]&.call(event)
|
||||||
@@ -315,16 +417,15 @@ loop do
|
|||||||
screen_bounds[:x] + screen_bounds[:width] - $geom_start[:width]].min
|
screen_bounds[:x] + screen_bounds[:width] - $geom_start[:width]].min
|
||||||
new_y = [[$geom_start[:y] + dy, screen_bounds[:y]].max,
|
new_y = [[$geom_start[:y] + dy, screen_bounds[:y]].max,
|
||||||
screen_bounds[:y] + screen_bounds[:height] - $geom_start[:height]].min
|
screen_bounds[:y] + screen_bounds[:height] - $geom_start[:height]].min
|
||||||
X.move_window $mouse_window, new_x, new_y
|
$mouse_window.move new_x, new_y
|
||||||
elsif $mouse_state == 3
|
elsif $mouse_state == 3
|
||||||
X.resize_window $mouse_window,
|
$mouse_window.resize [$geom_start[:width] + dx, 50].max,
|
||||||
[$geom_start[:width] + dx, 50].max,
|
|
||||||
[$geom_start[:height] + dy, 50].max
|
[$geom_start[:height] + dy, 50].max
|
||||||
end
|
end
|
||||||
when :mouse_release
|
when :mouse_release
|
||||||
if [1, 3].include?($mouse_state)
|
if [1, 3].include?($mouse_state)
|
||||||
X.focus $mouse_window
|
X.focus $mouse_window.window_id
|
||||||
X.send_to_top $mouse_window
|
X.send_to_top $mouse_window.window_id
|
||||||
$mouse_state = -1
|
$mouse_state = -1
|
||||||
$mouse_window = -1
|
$mouse_window = -1
|
||||||
$mouse_pos_start = { x: -1, y: -1 }
|
$mouse_pos_start = { x: -1, y: -1 }
|
||||||
@@ -334,7 +435,13 @@ loop do
|
|||||||
$keybind_actions[event[:btn]]&.call(event)
|
$keybind_actions[event[:btn]]&.call(event)
|
||||||
when :key_release
|
when :key_release
|
||||||
# TODO
|
# TODO
|
||||||
when :configured
|
when :configure_request
|
||||||
# TODO
|
$windows[event[:window]]&.resize event[:width], event[:height]
|
||||||
|
X.send_to_top event[:window]
|
||||||
|
X.focus event[:window]
|
||||||
|
when :resize_request
|
||||||
|
$windows[event[:window]]&.resize event[:width], event[:height]
|
||||||
|
X.send_to_top event[:window]
|
||||||
|
X.focus event[:window]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
26
list.tmp
26
list.tmp
@@ -1,29 +1,29 @@
|
|||||||
#define XCB_KEY_PRESS 2
|
define XCB_KEY_PRESS 2
|
||||||
#define XCB_KEY_RELEASE 3
|
define XCB_KEY_RELEASE 3
|
||||||
|
|
||||||
#define XCB_BUTTON_PRESS 4
|
define XCB_BUTTON_PRESS 4
|
||||||
#define XCB_BUTTON_RELEASE 5
|
define XCB_BUTTON_RELEASE 5
|
||||||
#define XCB_MOTION_NOTIFY 6
|
define XCB_MOTION_NOTIFY 6
|
||||||
|
|
||||||
#define XCB_ENTER_NOTIFY 7
|
define XCB_ENTER_NOTIFY 7
|
||||||
|
|
||||||
#define XCB_LEAVE_NOTIFY 8 - maybe
|
# define XCB_LEAVE_NOTIFY 8 - maybe
|
||||||
|
|
||||||
#define XCB_CREATE_NOTIFY 16
|
define XCB_CREATE_NOTIFY 16
|
||||||
|
|
||||||
// treat these similarly
|
// treat these similarly
|
||||||
#define XCB_DESTROY_NOTIFY 17 // to remove from struct
|
define XCB_DESTROY_NOTIFY 17 // to remove from struct
|
||||||
#define XCB_UNMAP_NOTIFY 18 // i guess this is minimize but idk if it is icccm IconicState?
|
define XCB_UNMAP_NOTIFY 18 // i guess this is minimize but idk if it is icccm IconicState?
|
||||||
|
|
||||||
#define XCB_MAP_NOTIFY 19 // whatever im doin (dont map this is after mapping)
|
define XCB_MAP_NOTIFY 19 // whatever im doin (dont map this is after mapping)
|
||||||
|
|
||||||
#define XCB_MAP_REQUEST 20 // Actual request to map // so map the window if possible
|
define XCB_MAP_REQUEST 20 // Actual request to map // so map the window if possible
|
||||||
|
|
||||||
#define XCB_CONFIGURE_REQUEST 23 // for floats maybe
|
#define XCB_CONFIGURE_REQUEST 23 // for floats maybe
|
||||||
#define XCB_GRAVITY_NOTIFY 24 // similar to XCB_CONFIGURE_NOTIFY but for pos
|
#define XCB_GRAVITY_NOTIFY 24 // similar to XCB_CONFIGURE_NOTIFY but for pos
|
||||||
#define XCB_RESIZE_REQUEST 25 // similar to XCB_CONFIGURE_REQUEST but for resize
|
#define XCB_RESIZE_REQUEST 25 // similar to XCB_CONFIGURE_REQUEST but for resize
|
||||||
|
|
||||||
#define XCB_CONFIGURE_NOTIFY 22 // prolly remove it
|
# define XCB_CONFIGURE_NOTIFY 22 // prolly remove it
|
||||||
#define XCB_PROPERTY_NOTIFY 28 // only if netwm requires so
|
#define XCB_PROPERTY_NOTIFY 28 // only if netwm requires so
|
||||||
#define XCB_CLIENT_MESSAGE 33 // only if netwm requires
|
#define XCB_CLIENT_MESSAGE 33 // only if netwm requires
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user