Merge branch 'next' into testcases
Conflicts: docs/userguide
This commit is contained in:
commit
4da54f1279
12
Makefile
12
Makefile
|
@ -28,16 +28,19 @@ install: all
|
||||||
$(INSTALL) -m 0644 i3.desktop $(DESTDIR)/usr/share/xsessions/
|
$(INSTALL) -m 0644 i3.desktop $(DESTDIR)/usr/share/xsessions/
|
||||||
$(MAKE) TOPDIR=$(TOPDIR) -C i3-msg install
|
$(MAKE) TOPDIR=$(TOPDIR) -C i3-msg install
|
||||||
|
|
||||||
dist: clean
|
dist: distclean
|
||||||
[ ! -d i3-${VERSION} ] || rm -rf i3-${VERSION}
|
[ ! -d i3-${VERSION} ] || rm -rf i3-${VERSION}
|
||||||
[ ! -e i3-${VERSION}.tar.bz2 ] || rm i3-${VERSION}.tar.bz2
|
[ ! -e i3-${VERSION}.tar.bz2 ] || rm i3-${VERSION}.tar.bz2
|
||||||
mkdir i3-${VERSION}
|
mkdir i3-${VERSION}
|
||||||
cp DEPENDS GOALS LICENSE PACKAGE-MAINTAINER TODO RELEASE-* i3.config i3.desktop pseudo-doc.doxygen i3-${VERSION}
|
cp DEPENDS GOALS LICENSE PACKAGE-MAINTAINER TODO RELEASE-NOTES-${VERSION} i3.config i3.desktop pseudo-doc.doxygen Makefile i3-${VERSION}
|
||||||
cp -r src include man i3-${VERSION}
|
cp -r src i3-msg include man i3-${VERSION}
|
||||||
# Only copy toplevel documentation (important stuff)
|
# Only copy toplevel documentation (important stuff)
|
||||||
mkdir i3-${VERSION}/docs
|
mkdir i3-${VERSION}/docs
|
||||||
find docs -maxdepth 1 -type f ! -name "*.xcf" -exec cp '{}' i3-${VERSION}/docs \;
|
find docs -maxdepth 1 -type f ! -name "*.xcf" -exec cp '{}' i3-${VERSION}/docs \;
|
||||||
sed -e 's/^GIT_VERSION=\(.*\)/GIT_VERSION=${GIT_VERSION}/g;s/^VERSION=\(.*\)/VERSION=${VERSION}/g' Makefile > i3-${VERSION}/Makefile
|
sed -e 's/^GIT_VERSION=\(.*\)/GIT_VERSION=${GIT_VERSION}/g;s/^VERSION=\(.*\)/VERSION=${VERSION}/g' common.mk > i3-${VERSION}/common.mk
|
||||||
|
# Pre-generate a manpage to allow distributors to skip this step and save some dependencies
|
||||||
|
make -C man
|
||||||
|
cp man/i3.1 i3-${VERSION}/man/i3.1
|
||||||
tar cf i3-${VERSION}.tar i3-${VERSION}
|
tar cf i3-${VERSION}.tar i3-${VERSION}
|
||||||
bzip2 -9 i3-${VERSION}.tar
|
bzip2 -9 i3-${VERSION}.tar
|
||||||
rm -rf i3-${VERSION}
|
rm -rf i3-${VERSION}
|
||||||
|
@ -50,3 +53,4 @@ clean:
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
rm -f i3
|
rm -f i3
|
||||||
|
$(MAKE) TOPDIR=$(TOPDIR) -C i3-msg distclean
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
Release notes for i3 v3.γ
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
This is the third version (3.γ, transcribed 3.c) of i3. It is considered stable.
|
||||||
|
|
||||||
|
This release contains many small improvements like using keysymbols in the
|
||||||
|
configuration file, named workspaces, borderless windows, an IPC interface
|
||||||
|
etc. (see below for a complete list of changes)
|
||||||
|
|
||||||
|
Thanks for this release go out to bapt, badboy, Atsutane, tsdh, xeen, mxf,
|
||||||
|
and all other people who reported bugs/made suggestions.
|
||||||
|
|
||||||
|
Special thanks go to steckdenis, yellowiscool and farvardin who designed a logo
|
||||||
|
for i3.
|
||||||
|
|
||||||
|
A list of changes follows:
|
||||||
|
|
||||||
|
* Implement a reload command
|
||||||
|
* Implement keysymbols in configuration file
|
||||||
|
* Implement assignments of workspaces to screens
|
||||||
|
* Implement named workspaces
|
||||||
|
* Implement borderless/1-px-border windows
|
||||||
|
* Implement command to focus screens
|
||||||
|
* Implement IPC via unix sockets
|
||||||
|
* Correctly render decoration of floating windows
|
||||||
|
* Map floating windows requesting (0x0) to center of their leader/workspace
|
||||||
|
* Optimization: Render stack windows on pixmaps to reduce flickering
|
||||||
|
* Optimization: Directly position new windows to their final position
|
||||||
|
* Bugfix: Repeatedly try to find screens if none are available
|
||||||
|
* Bugfix: Correctly redecorate clients when changing focus
|
||||||
|
* Bugfix: Don’t crash when clients reconfigure themselves
|
||||||
|
* Bugfix: Fix screen wrapping
|
||||||
|
* Bugfix: Fix selecting a different screen with your mouse when not having
|
||||||
|
any windows on the current workspace
|
||||||
|
* Bugfix: Correctly unmap stack windows and don’t re-map them too early
|
||||||
|
* Bugfix: Allow switching layout if there are no clients in the this container
|
||||||
|
* Bugfix: Set WM_STATE_WITHDRAWN when unmapping, unmap windows when
|
||||||
|
destroying
|
||||||
|
* Bugfix: Don’t hide assigned clients to inactive but visible workspaces
|
||||||
|
|
||||||
|
-- Michael Stapelberg, 2009-08-19
|
|
@ -1,14 +1,29 @@
|
||||||
i3-wm (3.c-0) unstable; urgency=low
|
i3-wm (3.c-1) unstable; urgency=low
|
||||||
|
|
||||||
* Implement a reload command
|
* Implement a reload command
|
||||||
|
* Implement keysymbols in configuration file
|
||||||
|
* Implement assignments of workspaces to screens
|
||||||
|
* Implement named workspaces
|
||||||
|
* Implement borderless/1-px-border windows
|
||||||
|
* Implement command to focus screens
|
||||||
* Implement IPC via unix sockets
|
* Implement IPC via unix sockets
|
||||||
|
* Correctly render decoration of floating windows
|
||||||
|
* Map floating windows requesting (0x0) to center of their leader/workspace
|
||||||
* Optimization: Render stack windows on pixmaps to reduce flickering
|
* Optimization: Render stack windows on pixmaps to reduce flickering
|
||||||
* Optimization: Directly position new windows to their final position
|
* Optimization: Directly position new windows to their final position
|
||||||
* Bugfix: Repeatedly try to find screens if none are available
|
* Bugfix: Repeatedly try to find screens if none are available
|
||||||
* Bugfix: Correctly redecorate clients when changing focus
|
* Bugfix: Correctly redecorate clients when changing focus
|
||||||
* Bugfix: Don’t crash when clients reconfigure themselves
|
* Bugfix: Don’t crash when clients reconfigure themselves
|
||||||
|
* Bugfix: Fix screen wrapping
|
||||||
|
* Bugfix: Fix selecting a different screen with your mouse when not having
|
||||||
|
any windows on the current workspace
|
||||||
|
* Bugfix: Correctly unmap stack windows and don’t re-map them too early
|
||||||
|
* Bugfix: Allow switching layout if there are no clients in the this container
|
||||||
|
* Bugfix: Set WM_STATE_WITHDRAWN when unmapping, unmap windows when
|
||||||
|
destroying
|
||||||
|
* Bugfix: Don’t hide assigned clients to inactive but visible workspaces
|
||||||
|
|
||||||
-- Michael Stapelberg <michael@stapelberg.de> Sun, 02 Aug 2009 20:05:58 +0200
|
-- Michael Stapelberg <michael@stapelberg.de> Wed, 19 Aug 2009 13:07:58 +0200
|
||||||
|
|
||||||
i3-wm (3.b-1) unstable; urgency=low
|
i3-wm (3.b-1) unstable; urgency=low
|
||||||
|
|
||||||
|
|
|
@ -127,6 +127,9 @@ src/handlers.c::
|
||||||
Contains all handlers for all kind of X events (new window title, new hints,
|
Contains all handlers for all kind of X events (new window title, new hints,
|
||||||
unmapping, key presses, button presses, …).
|
unmapping, key presses, button presses, …).
|
||||||
|
|
||||||
|
src/ipc.c::
|
||||||
|
Contains code for the IPC interface.
|
||||||
|
|
||||||
src/layout.c::
|
src/layout.c::
|
||||||
Renders your layout (screens, workspaces, containers).
|
Renders your layout (screens, workspaces, containers).
|
||||||
|
|
||||||
|
@ -149,6 +152,9 @@ Manages the most important internal data structure, the design table.
|
||||||
src/util.c::
|
src/util.c::
|
||||||
Contains useful functions which are not really dependant on anything.
|
Contains useful functions which are not really dependant on anything.
|
||||||
|
|
||||||
|
src/workspace.c::
|
||||||
|
Contains all functions related to workspaces (displaying, hiding, renaming…)
|
||||||
|
|
||||||
src/xcb.c::
|
src/xcb.c::
|
||||||
Contains wrappers to use xcb more easily.
|
Contains wrappers to use xcb more easily.
|
||||||
|
|
||||||
|
|
|
@ -505,7 +505,7 @@ or you can specify the position of the client if you always use the same layout.
|
||||||
*Examples*:
|
*Examples*:
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
# Get me to the next open VIM instance
|
# Get me to the next open VIM instance
|
||||||
bind Mod1+38 jump "urxvt/VIM"
|
bindsym Mod1+a jump "urxvt/VIM"
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
|
|
||||||
=== Traveling the focus stack
|
=== Traveling the focus stack
|
||||||
|
|
|
@ -97,4 +97,12 @@ void client_unmap(xcb_connection_t *conn, Client *client);
|
||||||
*/
|
*/
|
||||||
void client_map(xcb_connection_t *conn, Client *client);
|
void client_map(xcb_connection_t *conn, Client *client);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pretty-prints the client’s information into the logfile.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define CLIENT_LOG(client) do { \
|
||||||
|
LOG("Window: frame 0x%08x, child 0x%08x\n", client->frame, client->child); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -346,6 +346,11 @@ struct Client {
|
||||||
int proportional_height;
|
int proportional_height;
|
||||||
int proportional_width;
|
int proportional_width;
|
||||||
|
|
||||||
|
/** contains the minimum increment size as specified for the window
|
||||||
|
* (in pixels). */
|
||||||
|
int width_increment;
|
||||||
|
int height_increment;
|
||||||
|
|
||||||
/** Height which was determined by reading the _NET_WM_STRUT_PARTIAL
|
/** Height which was determined by reading the _NET_WM_STRUT_PARTIAL
|
||||||
* top/bottom of the screen reservation */
|
* top/bottom of the screen reservation */
|
||||||
int desired_height;
|
int desired_height;
|
||||||
|
|
|
@ -57,6 +57,6 @@ i3Screen *get_screen_containing(int x, int y);
|
||||||
* This function always returns a screen.
|
* This function always returns a screen.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
i3Screen *get_screen_most(direction_t direction);
|
i3Screen *get_screen_most(direction_t direction, i3Screen *current);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
i3(1)
|
i3(1)
|
||||||
=====
|
=====
|
||||||
Michael Stapelberg <michael+i3@stapelberg.de>
|
Michael Stapelberg <michael+i3@stapelberg.de>
|
||||||
v3.beta, May 2009
|
v3.gamma, August 2009
|
||||||
|
|
||||||
== NAME
|
== NAME
|
||||||
|
|
||||||
|
@ -232,9 +232,13 @@ your login manager (xdm, slim, gdm, …) as soon as you login.
|
||||||
# Disable DPMS turning off the screen
|
# Disable DPMS turning off the screen
|
||||||
xset dpms force on
|
xset dpms force on
|
||||||
xset s off
|
xset s off
|
||||||
|
|
||||||
# Disable bell
|
# Disable bell
|
||||||
xset -b
|
xset -b
|
||||||
|
|
||||||
|
# Enable zapping (C-A-<Bksp> kills X)
|
||||||
|
setxkbmap -option terminate:ctrl_alt_bksp
|
||||||
|
|
||||||
# Enforce correct locales from the beginning
|
# Enforce correct locales from the beginning
|
||||||
unset LC_COLLATE
|
unset LC_COLLATE
|
||||||
export LC_CTYPE=de_DE.UTF-8
|
export LC_CTYPE=de_DE.UTF-8
|
||||||
|
@ -249,6 +253,9 @@ export LC_TELEPHONE=de_DE.UTF-8
|
||||||
export LC_MEASUREMENT=de_DE.UTF-8
|
export LC_MEASUREMENT=de_DE.UTF-8
|
||||||
export LC_IDENTIFICATION=de_DE.UTF-8
|
export LC_IDENTIFICATION=de_DE.UTF-8
|
||||||
|
|
||||||
|
# Use XToolkit in java applications
|
||||||
|
export AWT_TOOLKIT=XToolkit
|
||||||
|
|
||||||
# Set background color
|
# Set background color
|
||||||
xsetroot -solid "#333333"
|
xsetroot -solid "#333333"
|
||||||
|
|
||||||
|
|
|
@ -104,12 +104,12 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t
|
||||||
LOG("Target screen NULL\n");
|
LOG("Target screen NULL\n");
|
||||||
/* Wrap around if the target screen is out of bounds */
|
/* Wrap around if the target screen is out of bounds */
|
||||||
if (direction == D_RIGHT)
|
if (direction == D_RIGHT)
|
||||||
target = get_screen_most(D_LEFT);
|
target = get_screen_most(D_LEFT, cs);
|
||||||
else if (direction == D_LEFT)
|
else if (direction == D_LEFT)
|
||||||
target = get_screen_most(D_RIGHT);
|
target = get_screen_most(D_RIGHT, cs);
|
||||||
else if (direction == D_UP)
|
else if (direction == D_UP)
|
||||||
target = get_screen_most(D_DOWN);
|
target = get_screen_most(D_DOWN, cs);
|
||||||
else target = get_screen_most(D_UP);
|
else target = get_screen_most(D_UP, cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("Switching to ws %d\n", target->current_workspace + 1);
|
LOG("Switching to ws %d\n", target->current_workspace + 1);
|
||||||
|
@ -146,7 +146,7 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t
|
||||||
if ((screen = get_screen_containing(container->x, destination_y)) == NULL) {
|
if ((screen = get_screen_containing(container->x, destination_y)) == NULL) {
|
||||||
LOG("Wrapping screen around vertically\n");
|
LOG("Wrapping screen around vertically\n");
|
||||||
/* No screen found? Then wrap */
|
/* No screen found? Then wrap */
|
||||||
screen = get_screen_most((direction == D_UP ? D_DOWN : D_UP));
|
screen = get_screen_most((direction == D_UP ? D_DOWN : D_UP), container->workspace->screen);
|
||||||
}
|
}
|
||||||
t_ws = &(workspaces[screen->current_workspace]);
|
t_ws = &(workspaces[screen->current_workspace]);
|
||||||
new_row = (direction == D_UP ? (t_ws->rows - 1) : 0);
|
new_row = (direction == D_UP ? (t_ws->rows - 1) : 0);
|
||||||
|
@ -188,7 +188,7 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t
|
||||||
int destination_x = (direction == D_LEFT ? (container->x - 1) : (container->x + container->width + 1));
|
int destination_x = (direction == D_LEFT ? (container->x - 1) : (container->x + container->width + 1));
|
||||||
if ((screen = get_screen_containing(destination_x, container->y)) == NULL) {
|
if ((screen = get_screen_containing(destination_x, container->y)) == NULL) {
|
||||||
LOG("Wrapping screen around horizontally\n");
|
LOG("Wrapping screen around horizontally\n");
|
||||||
screen = get_screen_most((direction == D_LEFT ? D_RIGHT : D_LEFT));
|
screen = get_screen_most((direction == D_LEFT ? D_RIGHT : D_LEFT), container->workspace->screen);
|
||||||
}
|
}
|
||||||
t_ws = &(workspaces[screen->current_workspace]);
|
t_ws = &(workspaces[screen->current_workspace]);
|
||||||
new_col = (direction == D_LEFT ? (t_ws->cols - 1) : 0);
|
new_col = (direction == D_LEFT ? (t_ws->cols - 1) : 0);
|
||||||
|
@ -1069,6 +1069,4 @@ void parse_command(xcb_connection_t *conn, const char *command) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("--- done ---\n");
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,9 +50,7 @@ static void replace_variable(char *buffer, const char *key, const char *value) {
|
||||||
/* To prevent endless recursions when the user makes an error configuring,
|
/* To prevent endless recursions when the user makes an error configuring,
|
||||||
* we stop after 100 replacements. That should be vastly more than enough. */
|
* we stop after 100 replacements. That should be vastly more than enough. */
|
||||||
int c = 0;
|
int c = 0;
|
||||||
LOG("Replacing %s with %s\n", key, value);
|
|
||||||
while ((pos = strcasestr(buffer, key)) != NULL && c++ < 100) {
|
while ((pos = strcasestr(buffer, key)) != NULL && c++ < 100) {
|
||||||
LOG("replacing variable %s in \"%s\" with \"%s\"\n", key, buffer, value);
|
|
||||||
char *rest = pos + strlen(key);
|
char *rest = pos + strlen(key);
|
||||||
*pos = '\0';
|
*pos = '\0';
|
||||||
char *replaced;
|
char *replaced;
|
||||||
|
@ -103,7 +101,6 @@ void grab_all_keys(xcb_connection_t *conn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We need to translate the symbol to a keycode */
|
/* We need to translate the symbol to a keycode */
|
||||||
LOG("Translating symbol to keycode (\"%s\")\n", bind->symbol);
|
|
||||||
xcb_keysym_t keysym = XStringToKeysym(bind->symbol);
|
xcb_keysym_t keysym = XStringToKeysym(bind->symbol);
|
||||||
if (keysym == NoSymbol) {
|
if (keysym == NoSymbol) {
|
||||||
LOG("Could not translate string to key symbol: \"%s\"\n", bind->symbol);
|
LOG("Could not translate string to key symbol: \"%s\"\n", bind->symbol);
|
||||||
|
@ -116,7 +113,7 @@ void grab_all_keys(xcb_connection_t *conn) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t last_keycode;
|
uint32_t last_keycode = 0;
|
||||||
bind->number_keycodes = 0;
|
bind->number_keycodes = 0;
|
||||||
for (xcb_keycode_t *walk = keycodes; *walk != 0; walk++) {
|
for (xcb_keycode_t *walk = keycodes; *walk != 0; walk++) {
|
||||||
/* We hope duplicate keycodes will be returned in order
|
/* We hope duplicate keycodes will be returned in order
|
||||||
|
@ -127,7 +124,7 @@ void grab_all_keys(xcb_connection_t *conn) {
|
||||||
last_keycode = *walk;
|
last_keycode = *walk;
|
||||||
bind->number_keycodes++;
|
bind->number_keycodes++;
|
||||||
}
|
}
|
||||||
LOG("Got %d different keycodes\n", bind->number_keycodes);
|
LOG("Translated symbol \"%s\" to %d keycode\n", bind->symbol, bind->number_keycodes);
|
||||||
bind->translated_to = smalloc(bind->number_keycodes * sizeof(xcb_keycode_t));
|
bind->translated_to = smalloc(bind->number_keycodes * sizeof(xcb_keycode_t));
|
||||||
memcpy(bind->translated_to, keycodes, bind->number_keycodes * sizeof(xcb_keycode_t));
|
memcpy(bind->translated_to, keycodes, bind->number_keycodes * sizeof(xcb_keycode_t));
|
||||||
free(keycodes);
|
free(keycodes);
|
||||||
|
|
103
src/handlers.c
103
src/handlers.c
|
@ -48,8 +48,6 @@ static void add_ignore_event(const int sequence) {
|
||||||
event->sequence = sequence;
|
event->sequence = sequence;
|
||||||
event->added = time(NULL);
|
event->added = time(NULL);
|
||||||
|
|
||||||
LOG("Adding sequence %d to ignorelist\n", sequence);
|
|
||||||
|
|
||||||
SLIST_INSERT_HEAD(&ignore_events, event, ignore_events);
|
SLIST_INSERT_HEAD(&ignore_events, event, ignore_events);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +69,6 @@ static bool event_is_ignored(const int sequence) {
|
||||||
|
|
||||||
SLIST_FOREACH(event, &ignore_events, ignore_events) {
|
SLIST_FOREACH(event, &ignore_events, ignore_events) {
|
||||||
if (event->sequence == sequence) {
|
if (event->sequence == sequence) {
|
||||||
LOG("Ignoring event (sequence %d)\n", sequence);
|
|
||||||
SLIST_REMOVE(&ignore_events, event, Ignore_Event, ignore_events);
|
SLIST_REMOVE(&ignore_events, event, Ignore_Event, ignore_events);
|
||||||
free(event);
|
free(event);
|
||||||
return true;
|
return true;
|
||||||
|
@ -87,7 +84,6 @@ static bool event_is_ignored(const int sequence) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int handle_key_release(void *ignored, xcb_connection_t *conn, xcb_key_release_event_t *event) {
|
int handle_key_release(void *ignored, xcb_connection_t *conn, xcb_key_release_event_t *event) {
|
||||||
LOG("got key release, just passing\n");
|
|
||||||
xcb_allow_events(conn, XCB_ALLOW_REPLAY_KEYBOARD, event->time);
|
xcb_allow_events(conn, XCB_ALLOW_REPLAY_KEYBOARD, event->time);
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -248,7 +244,10 @@ int handle_enter_notify(void *ignored, xcb_connection_t *conn, xcb_enter_notify_
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int handle_motion_notify(void *ignored, xcb_connection_t *conn, xcb_motion_notify_event_t *event) {
|
int handle_motion_notify(void *ignored, xcb_connection_t *conn, xcb_motion_notify_event_t *event) {
|
||||||
LOG("pointer motion notify, getting screen at %d x %d\n", event->root_x, event->root_y);
|
/* Skip events where the pointer was over a child window, we are only
|
||||||
|
* interested in events on the root window. */
|
||||||
|
if (event->child != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
check_crossing_screen_boundary(event->root_x, event->root_y);
|
check_crossing_screen_boundary(event->root_x, event->root_y);
|
||||||
|
|
||||||
|
@ -261,20 +260,17 @@ int handle_motion_notify(void *ignored, xcb_connection_t *conn, xcb_motion_notif
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int handle_mapping_notify(void *ignored, xcb_connection_t *conn, xcb_mapping_notify_event_t *event) {
|
int handle_mapping_notify(void *ignored, xcb_connection_t *conn, xcb_mapping_notify_event_t *event) {
|
||||||
LOG("\n\nmapping notify\n\n");
|
|
||||||
|
|
||||||
if (event->request != XCB_MAPPING_KEYBOARD &&
|
if (event->request != XCB_MAPPING_KEYBOARD &&
|
||||||
event->request != XCB_MAPPING_MODIFIER)
|
event->request != XCB_MAPPING_MODIFIER)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
LOG("Received mapping_notify for keyboard or modifier mapping, re-grabbing keys\n");
|
||||||
xcb_refresh_keyboard_mapping(keysyms, event);
|
xcb_refresh_keyboard_mapping(keysyms, event);
|
||||||
|
|
||||||
xcb_get_numlock_mask(conn);
|
xcb_get_numlock_mask(conn);
|
||||||
|
|
||||||
ungrab_all_keys(conn);
|
ungrab_all_keys(conn);
|
||||||
LOG("Re-grabbing...\n");
|
|
||||||
grab_all_keys(conn);
|
grab_all_keys(conn);
|
||||||
LOG("Done\n");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -366,8 +362,7 @@ static bool button_press_bar(xcb_connection_t *conn, xcb_button_press_event_t *e
|
||||||
}
|
}
|
||||||
|
|
||||||
int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_event_t *event) {
|
int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_event_t *event) {
|
||||||
LOG("button press!\n");
|
LOG("Button %d pressed\n", event->state);
|
||||||
LOG("state = %d\n", event->state);
|
|
||||||
/* This was either a focus for a client’s parent (= titlebar)… */
|
/* This was either a focus for a client’s parent (= titlebar)… */
|
||||||
Client *client = table_get(&by_child, event->event);
|
Client *client = table_get(&by_child, event->event);
|
||||||
bool border_click = false;
|
bool border_click = false;
|
||||||
|
@ -523,13 +518,11 @@ int handle_map_request(void *prophs, xcb_connection_t *conn, xcb_map_request_eve
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int handle_configure_request(void *prophs, xcb_connection_t *conn, xcb_configure_request_event_t *event) {
|
int handle_configure_request(void *prophs, xcb_connection_t *conn, xcb_configure_request_event_t *event) {
|
||||||
LOG("configure-request, serial %d\n", event->sequence);
|
LOG("window 0x%08x wants to be at %dx%d with %dx%d\n",
|
||||||
LOG("event->window = %08x\n", event->window);
|
event->window, event->x, event->y, event->width, event->height);
|
||||||
LOG("application wants to be at %dx%d with %dx%d\n", event->x, event->y, event->width, event->height);
|
|
||||||
|
|
||||||
Client *client = table_get(&by_child, event->window);
|
Client *client = table_get(&by_child, event->window);
|
||||||
if (client == NULL) {
|
if (client == NULL) {
|
||||||
LOG("This client is not mapped, so we don't care and just tell the client that he will get its size\n");
|
|
||||||
uint32_t mask = 0;
|
uint32_t mask = 0;
|
||||||
uint32_t values[7];
|
uint32_t values[7];
|
||||||
int c = 0;
|
int c = 0;
|
||||||
|
@ -611,15 +604,12 @@ int handle_configure_request(void *prophs, xcb_connection_t *conn, xcb_configure
|
||||||
int handle_configure_event(void *prophs, xcb_connection_t *conn, xcb_configure_notify_event_t *event) {
|
int handle_configure_event(void *prophs, xcb_connection_t *conn, xcb_configure_notify_event_t *event) {
|
||||||
xcb_window_t root = xcb_setup_roots_iterator(xcb_get_setup(conn)).data->root;
|
xcb_window_t root = xcb_setup_roots_iterator(xcb_get_setup(conn)).data->root;
|
||||||
|
|
||||||
LOG("handle_configure_event for window %08x\n", event->window);
|
|
||||||
LOG("event->type = %d, \n", event->response_type);
|
|
||||||
LOG("event->x = %d, ->y = %d, ->width = %d, ->height = %d\n", event->x, event->y, event->width, event->height);
|
|
||||||
|
|
||||||
/* We ignore this sequence twice because events for child and frame should be ignored */
|
/* We ignore this sequence twice because events for child and frame should be ignored */
|
||||||
add_ignore_event(event->sequence);
|
add_ignore_event(event->sequence);
|
||||||
add_ignore_event(event->sequence);
|
add_ignore_event(event->sequence);
|
||||||
|
|
||||||
if (event->event == root) {
|
if (event->event == root) {
|
||||||
|
LOG("event->x = %d, ->y = %d, ->width = %d, ->height = %d\n", event->x, event->y, event->width, event->height);
|
||||||
LOG("reconfigure of the root window, need to xinerama\n");
|
LOG("reconfigure of the root window, need to xinerama\n");
|
||||||
/* FIXME: Somehow, this is occuring too often. Therefore, we check for 0/0,
|
/* FIXME: Somehow, this is occuring too often. Therefore, we check for 0/0,
|
||||||
but is there a better way? */
|
but is there a better way? */
|
||||||
|
@ -645,7 +635,6 @@ int handle_unmap_notify_event(void *data, xcb_connection_t *conn, xcb_unmap_noti
|
||||||
/* First, we need to check if the client is awaiting an unmap-request which
|
/* First, we need to check if the client is awaiting an unmap-request which
|
||||||
was generated by us reparenting the window. In that case, we just ignore it. */
|
was generated by us reparenting the window. In that case, we just ignore it. */
|
||||||
if (client != NULL && client->awaiting_useless_unmap) {
|
if (client != NULL && client->awaiting_useless_unmap) {
|
||||||
LOG("Dropping this unmap request, it was generated by reparenting\n");
|
|
||||||
client->awaiting_useless_unmap = false;
|
client->awaiting_useless_unmap = false;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -723,11 +712,8 @@ int handle_unmap_notify_event(void *data, xcb_connection_t *conn, xcb_unmap_noti
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (workspace_empty) {
|
if (workspace_empty)
|
||||||
LOG("setting ws to NULL for workspace %d (%p)\n", client->workspace->num,
|
|
||||||
client->workspace);
|
|
||||||
client->workspace->screen = NULL;
|
client->workspace->screen = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
FREE(client->window_class);
|
FREE(client->window_class);
|
||||||
FREE(client->name);
|
FREE(client->name);
|
||||||
|
@ -748,7 +734,6 @@ int handle_unmap_notify_event(void *data, xcb_connection_t *conn, xcb_unmap_noti
|
||||||
*/
|
*/
|
||||||
int handle_windowname_change(void *data, xcb_connection_t *conn, uint8_t state,
|
int handle_windowname_change(void *data, xcb_connection_t *conn, uint8_t state,
|
||||||
xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *prop) {
|
xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *prop) {
|
||||||
LOG("window's name changed.\n");
|
|
||||||
if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
|
if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
|
||||||
LOG("_NET_WM_NAME not specified, not changing\n");
|
LOG("_NET_WM_NAME not specified, not changing\n");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -763,7 +748,7 @@ int handle_windowname_change(void *data, xcb_connection_t *conn, uint8_t state,
|
||||||
asprintf(&new_name, "%.*s", xcb_get_property_value_length(prop), (char*)xcb_get_property_value(prop));
|
asprintf(&new_name, "%.*s", xcb_get_property_value_length(prop), (char*)xcb_get_property_value(prop));
|
||||||
/* Convert it to UCS-2 here for not having to convert it later every time we want to pass it to X */
|
/* Convert it to UCS-2 here for not having to convert it later every time we want to pass it to X */
|
||||||
char *ucs2_name = convert_utf8_to_ucs2(new_name, &new_len);
|
char *ucs2_name = convert_utf8_to_ucs2(new_name, &new_len);
|
||||||
LOG("Name should change to \"%s\"\n", new_name);
|
LOG("_NET_WM_NAME changed to \"%s\"\n", new_name);
|
||||||
free(new_name);
|
free(new_name);
|
||||||
|
|
||||||
/* Check if they are the same and don’t update if so.
|
/* Check if they are the same and don’t update if so.
|
||||||
|
@ -773,7 +758,6 @@ int handle_windowname_change(void *data, xcb_connection_t *conn, uint8_t state,
|
||||||
if ((new_len == client->name_len) &&
|
if ((new_len == client->name_len) &&
|
||||||
(client->name != NULL) &&
|
(client->name != NULL) &&
|
||||||
(memcmp(client->name, ucs2_name, new_len * 2) == 0)) {
|
(memcmp(client->name, ucs2_name, new_len * 2) == 0)) {
|
||||||
LOG("Name did not change, not updating\n");
|
|
||||||
free(ucs2_name);
|
free(ucs2_name);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -810,7 +794,6 @@ int handle_windowname_change(void *data, xcb_connection_t *conn, uint8_t state,
|
||||||
*/
|
*/
|
||||||
int handle_windowname_change_legacy(void *data, xcb_connection_t *conn, uint8_t state,
|
int handle_windowname_change_legacy(void *data, xcb_connection_t *conn, uint8_t state,
|
||||||
xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *prop) {
|
xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *prop) {
|
||||||
LOG("window's name changed (legacy).\n");
|
|
||||||
if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
|
if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
|
||||||
LOG("prop == NULL\n");
|
LOG("prop == NULL\n");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -819,10 +802,9 @@ int handle_windowname_change_legacy(void *data, xcb_connection_t *conn, uint8_t
|
||||||
if (client == NULL)
|
if (client == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (client->uses_net_wm_name) {
|
/* Client capable of _NET_WM_NAME, ignore legacy name changes */
|
||||||
LOG("This client is capable of _NET_WM_NAME, ignoring legacy name\n");
|
if (client->uses_net_wm_name)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
|
|
||||||
/* Save the old pointer to make the update atomic */
|
/* Save the old pointer to make the update atomic */
|
||||||
char *new_name;
|
char *new_name;
|
||||||
|
@ -832,18 +814,17 @@ int handle_windowname_change_legacy(void *data, xcb_connection_t *conn, uint8_t
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/* Convert it to UCS-2 here for not having to convert it later every time we want to pass it to X */
|
/* Convert it to UCS-2 here for not having to convert it later every time we want to pass it to X */
|
||||||
LOG("Name should change to \"%s\"\n", new_name);
|
LOG("WM_NAME changed to \"%s\"\n", new_name);
|
||||||
|
|
||||||
/* Check if they are the same and don’t update if so. */
|
/* Check if they are the same and don’t update if so. */
|
||||||
if (client->name != NULL &&
|
if (client->name != NULL &&
|
||||||
strlen(new_name) == strlen(client->name) &&
|
strlen(new_name) == strlen(client->name) &&
|
||||||
strcmp(client->name, new_name) == 0) {
|
strcmp(client->name, new_name) == 0) {
|
||||||
LOG("Name did not change, not updating\n");
|
|
||||||
free(new_name);
|
free(new_name);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("Using legacy window title. Note that in order to get Unicode window titles in i3,"
|
LOG("Using legacy window title. Note that in order to get Unicode window titles in i3, "
|
||||||
"the application has to set _NET_WM_NAME which is in UTF-8 encoding.\n");
|
"the application has to set _NET_WM_NAME which is in UTF-8 encoding.\n");
|
||||||
|
|
||||||
char *old_name = client->name;
|
char *old_name = client->name;
|
||||||
|
@ -871,7 +852,6 @@ int handle_windowname_change_legacy(void *data, xcb_connection_t *conn, uint8_t
|
||||||
*/
|
*/
|
||||||
int handle_windowclass_change(void *data, xcb_connection_t *conn, uint8_t state,
|
int handle_windowclass_change(void *data, xcb_connection_t *conn, uint8_t state,
|
||||||
xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *prop) {
|
xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *prop) {
|
||||||
LOG("window class changed\n");
|
|
||||||
if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
|
if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
|
||||||
LOG("prop == NULL\n");
|
LOG("prop == NULL\n");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -886,15 +866,13 @@ int handle_windowclass_change(void *data, xcb_connection_t *conn, uint8_t state,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("changed to %s\n", new_class);
|
LOG("WM_CLASS changed to %s\n", new_class);
|
||||||
char *old_class = client->window_class;
|
char *old_class = client->window_class;
|
||||||
client->window_class = new_class;
|
client->window_class = new_class;
|
||||||
FREE(old_class);
|
FREE(old_class);
|
||||||
|
|
||||||
if (!client->initialized) {
|
if (!client->initialized)
|
||||||
LOG("Client is not yet initialized, not putting it to floating\n");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(new_class, "tools") == 0 || strcmp(new_class, "Dialog") == 0) {
|
if (strcmp(new_class, "tools") == 0 || strcmp(new_class, "Dialog") == 0) {
|
||||||
LOG("tool/dialog window, should we put it floating?\n");
|
LOG("tool/dialog window, should we put it floating?\n");
|
||||||
|
@ -935,11 +913,8 @@ int handle_expose_event(void *data, xcb_connection_t *conn, xcb_expose_event_t *
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("got client %s\n", client->name);
|
if (client->dock)
|
||||||
if (client->dock) {
|
|
||||||
LOG("this is a dock\n");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
|
|
||||||
if (client->container == NULL || client->container->mode != MODE_STACK)
|
if (client->container == NULL || client->container->mode != MODE_STACK)
|
||||||
decorate_window(conn, client, client->frame, client->titlegc, 0);
|
decorate_window(conn, client, client->frame, client->titlegc, 0);
|
||||||
|
@ -976,14 +951,10 @@ int handle_expose_event(void *data, xcb_connection_t *conn, xcb_expose_event_t *
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int handle_client_message(void *data, xcb_connection_t *conn, xcb_client_message_event_t *event) {
|
int handle_client_message(void *data, xcb_connection_t *conn, xcb_client_message_event_t *event) {
|
||||||
LOG("client_message\n");
|
|
||||||
|
|
||||||
if (event->type == atoms[_NET_WM_STATE]) {
|
if (event->type == atoms[_NET_WM_STATE]) {
|
||||||
if (event->format != 32 || event->data.data32[1] != atoms[_NET_WM_STATE_FULLSCREEN])
|
if (event->format != 32 || event->data.data32[1] != atoms[_NET_WM_STATE_FULLSCREEN])
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
LOG("fullscreen\n");
|
|
||||||
|
|
||||||
Client *client = table_get(&by_child, event->window);
|
Client *client = table_get(&by_child, event->window);
|
||||||
if (client == NULL)
|
if (client == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1021,14 +992,14 @@ int handle_window_type(void *data, xcb_connection_t *conn, uint8_t state, xcb_wi
|
||||||
*/
|
*/
|
||||||
int handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
|
int handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
|
||||||
xcb_atom_t name, xcb_get_property_reply_t *reply) {
|
xcb_atom_t name, xcb_get_property_reply_t *reply) {
|
||||||
LOG("handle_normal_hints\n");
|
|
||||||
Client *client = table_get(&by_child, window);
|
Client *client = table_get(&by_child, window);
|
||||||
if (client == NULL) {
|
if (client == NULL) {
|
||||||
LOG("No such client\n");
|
LOG("Received WM_SIZE_HINTS for unknown client\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
xcb_size_hints_t size_hints;
|
xcb_size_hints_t size_hints;
|
||||||
LOG("client is %08x / child %08x\n", client->frame, client->child);
|
|
||||||
|
CLIENT_LOG(client);
|
||||||
|
|
||||||
/* If the hints were already in this event, use them, if not, request them */
|
/* If the hints were already in this event, use them, if not, request them */
|
||||||
if (reply != NULL)
|
if (reply != NULL)
|
||||||
|
@ -1037,20 +1008,24 @@ int handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_w
|
||||||
xcb_get_wm_normal_hints_reply(conn, xcb_get_wm_normal_hints_unchecked(conn, client->child), &size_hints, NULL);
|
xcb_get_wm_normal_hints_reply(conn, xcb_get_wm_normal_hints_unchecked(conn, client->child), &size_hints, NULL);
|
||||||
|
|
||||||
if ((size_hints.flags & XCB_SIZE_HINT_P_MIN_SIZE)) {
|
if ((size_hints.flags & XCB_SIZE_HINT_P_MIN_SIZE)) {
|
||||||
LOG("min size set\n");
|
// TODO: Minimum size is not yet implemented
|
||||||
LOG("gots min_width = %d, min_height = %d\n", size_hints.min_width, size_hints.min_height);
|
//LOG("Minimum size: %d (width) x %d (height)\n", size_hints.min_width, size_hints.min_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((size_hints.flags & XCB_SIZE_HINT_P_RESIZE_INC)) {
|
||||||
|
if (size_hints.width_inc > 0)
|
||||||
|
client->width_increment = size_hints.width_inc;
|
||||||
|
if (size_hints.height_inc > 0)
|
||||||
|
client->height_increment = size_hints.height_inc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If no aspect ratio was set or if it was invalid, we ignore the hints */
|
/* If no aspect ratio was set or if it was invalid, we ignore the hints */
|
||||||
if (!(size_hints.flags & XCB_SIZE_HINT_P_ASPECT) ||
|
if (!(size_hints.flags & XCB_SIZE_HINT_P_ASPECT) ||
|
||||||
(size_hints.min_aspect_num <= 0) ||
|
(size_hints.min_aspect_num <= 0) ||
|
||||||
(size_hints.min_aspect_den <= 0)) {
|
(size_hints.min_aspect_den <= 0)) {
|
||||||
LOG("No aspect ratio set, ignoring\n");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("window is %08x / %s\n", client->child, client->name);
|
|
||||||
|
|
||||||
int base_width = 0, base_height = 0;
|
int base_width = 0, base_height = 0;
|
||||||
|
|
||||||
/* base_width/height are the desired size of the window.
|
/* base_width/height are the desired size of the window.
|
||||||
|
@ -1070,7 +1045,7 @@ int handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_w
|
||||||
double min_aspect = (double)size_hints.min_aspect_num / size_hints.min_aspect_den;
|
double min_aspect = (double)size_hints.min_aspect_num / size_hints.min_aspect_den;
|
||||||
double max_aspect = (double)size_hints.max_aspect_num / size_hints.min_aspect_den;
|
double max_aspect = (double)size_hints.max_aspect_num / size_hints.min_aspect_den;
|
||||||
|
|
||||||
LOG("min_aspect = %f, max_aspect = %f\n", min_aspect, max_aspect);
|
LOG("Aspect ratio set: minimum %f, maximum %f\n", min_aspect, max_aspect);
|
||||||
LOG("width = %f, height = %f\n", width, height);
|
LOG("width = %f, height = %f\n", width, height);
|
||||||
|
|
||||||
/* Sanity checks, this is user-input, in a way */
|
/* Sanity checks, this is user-input, in a way */
|
||||||
|
@ -1105,7 +1080,6 @@ int handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_w
|
||||||
*/
|
*/
|
||||||
int handle_transient_for(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
|
int handle_transient_for(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
|
||||||
xcb_atom_t name, xcb_get_property_reply_t *reply) {
|
xcb_atom_t name, xcb_get_property_reply_t *reply) {
|
||||||
LOG("Transient hint!\n");
|
|
||||||
Client *client = table_get(&by_child, window);
|
Client *client = table_get(&by_child, window);
|
||||||
if (client == NULL) {
|
if (client == NULL) {
|
||||||
LOG("No such client\n");
|
LOG("No such client\n");
|
||||||
|
@ -1115,17 +1089,13 @@ int handle_transient_for(void *data, xcb_connection_t *conn, uint8_t state, xcb_
|
||||||
xcb_window_t transient_for;
|
xcb_window_t transient_for;
|
||||||
|
|
||||||
if (reply != NULL) {
|
if (reply != NULL) {
|
||||||
if (!xcb_get_wm_transient_for_from_reply(&transient_for, reply)) {
|
if (!xcb_get_wm_transient_for_from_reply(&transient_for, reply))
|
||||||
LOG("Not transient for any window\n");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (!xcb_get_wm_transient_for_reply(conn, xcb_get_wm_transient_for_unchecked(conn, window),
|
if (!xcb_get_wm_transient_for_reply(conn, xcb_get_wm_transient_for_unchecked(conn, window),
|
||||||
&transient_for, NULL)) {
|
&transient_for, NULL))
|
||||||
LOG("Not transient for any window\n");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (client->floating == FLOATING_AUTO_OFF) {
|
if (client->floating == FLOATING_AUTO_OFF) {
|
||||||
LOG("This is a popup window, putting into floating\n");
|
LOG("This is a popup window, putting into floating\n");
|
||||||
|
@ -1142,10 +1112,11 @@ int handle_transient_for(void *data, xcb_connection_t *conn, uint8_t state, xcb_
|
||||||
*/
|
*/
|
||||||
int handle_clientleader_change(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
|
int handle_clientleader_change(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
|
||||||
xcb_atom_t name, xcb_get_property_reply_t *prop) {
|
xcb_atom_t name, xcb_get_property_reply_t *prop) {
|
||||||
LOG("client leader changed\n");
|
|
||||||
if (prop == NULL) {
|
if (prop == NULL) {
|
||||||
prop = xcb_get_property_reply(conn, xcb_get_property_unchecked(conn,
|
prop = xcb_get_property_reply(conn, xcb_get_property_unchecked(conn,
|
||||||
false, window, WM_CLIENT_LEADER, WINDOW, 0, 32), NULL);
|
false, window, WM_CLIENT_LEADER, WINDOW, 0, 32), NULL);
|
||||||
|
if (prop == NULL)
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Client *client = table_get(&by_child, window);
|
Client *client = table_get(&by_child, window);
|
||||||
|
@ -1153,10 +1124,10 @@ int handle_clientleader_change(void *data, xcb_connection_t *conn, uint8_t state
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
xcb_window_t *leader = xcb_get_property_value(prop);
|
xcb_window_t *leader = xcb_get_property_value(prop);
|
||||||
if (leader == NULL)
|
if (leader == NULL || *leader == 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
LOG("changed to %08x\n", *leader);
|
LOG("Client leader changed to %08x\n", *leader);
|
||||||
|
|
||||||
client->leader = *leader;
|
client->leader = *leader;
|
||||||
|
|
||||||
|
|
36
src/layout.c
36
src/layout.c
|
@ -109,7 +109,6 @@ void decorate_window(xcb_connection_t *conn, Client *client, xcb_drawable_t draw
|
||||||
if (client->dock)
|
if (client->dock)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LOG("redecorating child %08x\n", client->child);
|
|
||||||
last_focused = SLIST_FIRST(&(client->workspace->focus_stack));
|
last_focused = SLIST_FIRST(&(client->workspace->focus_stack));
|
||||||
if (client_is_floating(client)) {
|
if (client_is_floating(client)) {
|
||||||
if (last_focused == client)
|
if (last_focused == client)
|
||||||
|
@ -209,7 +208,6 @@ void reposition_client(xcb_connection_t *conn, Client *client) {
|
||||||
LOG("Client is on workspace %p with screen %p\n", client->workspace, client->workspace->screen);
|
LOG("Client is on workspace %p with screen %p\n", client->workspace, client->workspace->screen);
|
||||||
LOG("but screen at %d, %d is %p\n", client->rect.x, client->rect.y, screen);
|
LOG("but screen at %d, %d is %p\n", client->rect.x, client->rect.y, screen);
|
||||||
floating_assign_to_workspace(client, &workspaces[screen->current_workspace]);
|
floating_assign_to_workspace(client, &workspaces[screen->current_workspace]);
|
||||||
LOG("fixed that\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -288,6 +286,20 @@ void resize_client(xcb_connection_t *conn, Client *client) {
|
||||||
LOG("new_height = %f, new_width = %d\n", new_height, new_width);
|
LOG("new_height = %f, new_width = %d\n", new_height, new_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (client->height_increment > 1) {
|
||||||
|
int old_height = rect->height;
|
||||||
|
rect->height = ((int)(rect->height / client->height_increment) * client->height_increment) + 1;
|
||||||
|
LOG("Lost %d pixel due to client's height_increment (%d px)\n",
|
||||||
|
old_height - rect->height, client->height_increment);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client->width_increment > 1) {
|
||||||
|
int old_width = rect->width;
|
||||||
|
rect->width = ((int)(rect->width / client->width_increment) * client->width_increment) + 1;
|
||||||
|
LOG("Lost %d pixel due to client's width_increment (%d px)\n",
|
||||||
|
old_width - rect->width, client->width_increment);
|
||||||
|
}
|
||||||
|
|
||||||
LOG("child will be at %dx%d with size %dx%d\n", rect->x, rect->y, rect->width, rect->height);
|
LOG("child will be at %dx%d with size %dx%d\n", rect->x, rect->y, rect->width, rect->height);
|
||||||
|
|
||||||
xcb_configure_window(conn, client->child, mask, &(rect->x));
|
xcb_configure_window(conn, client->child, mask, &(rect->x));
|
||||||
|
@ -311,7 +323,6 @@ void render_container(xcb_connection_t *conn, Container *container) {
|
||||||
num_clients++;
|
num_clients++;
|
||||||
|
|
||||||
if (container->mode == MODE_DEFAULT) {
|
if (container->mode == MODE_DEFAULT) {
|
||||||
LOG("got %d clients in this default container.\n", num_clients);
|
|
||||||
CIRCLEQ_FOREACH(client, &(container->clients), clients) {
|
CIRCLEQ_FOREACH(client, &(container->clients), clients) {
|
||||||
/* If the client is in fullscreen mode, it does not get reconfigured */
|
/* If the client is in fullscreen mode, it does not get reconfigured */
|
||||||
if (container->workspace->fullscreen_client == client) {
|
if (container->workspace->fullscreen_client == client) {
|
||||||
|
@ -434,7 +445,6 @@ static void render_bars(xcb_connection_t *conn, Workspace *r_ws, int width, int
|
||||||
}
|
}
|
||||||
|
|
||||||
static void render_internal_bar(xcb_connection_t *conn, Workspace *r_ws, int width, int height) {
|
static void render_internal_bar(xcb_connection_t *conn, Workspace *r_ws, int width, int height) {
|
||||||
LOG("Rendering internal bar\n");
|
|
||||||
i3Font *font = load_font(conn, config.font);
|
i3Font *font = load_font(conn, config.font);
|
||||||
i3Screen *screen = r_ws->screen;
|
i3Screen *screen = r_ws->screen;
|
||||||
enum { SET_NORMAL = 0, SET_FOCUSED = 1 };
|
enum { SET_NORMAL = 0, SET_FOCUSED = 1 };
|
||||||
|
@ -477,8 +487,6 @@ static void render_internal_bar(xcb_connection_t *conn, Workspace *r_ws, int wid
|
||||||
(xcb_char2b_t*)ws->name);
|
(xcb_char2b_t*)ws->name);
|
||||||
drawn += ws->text_width + 12;
|
drawn += ws->text_width + 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("done rendering internal\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -491,8 +499,6 @@ void ignore_enter_notify_forall(xcb_connection_t *conn, Workspace *workspace, bo
|
||||||
Client *client;
|
Client *client;
|
||||||
uint32_t values[1];
|
uint32_t values[1];
|
||||||
|
|
||||||
LOG("Ignore enter_notify = %d\n", ignore_enter_notify);
|
|
||||||
|
|
||||||
FOR_TABLE(workspace)
|
FOR_TABLE(workspace)
|
||||||
CIRCLEQ_FOREACH(client, &(workspace->table[cols][rows]->clients), clients) {
|
CIRCLEQ_FOREACH(client, &(workspace->table[cols][rows]->clients), clients) {
|
||||||
/* Change event mask for the decorations */
|
/* Change event mask for the decorations */
|
||||||
|
@ -526,8 +532,6 @@ void render_workspace(xcb_connection_t *conn, i3Screen *screen, Workspace *r_ws)
|
||||||
/* Space for the internal bar */
|
/* Space for the internal bar */
|
||||||
height -= (font->height + 6);
|
height -= (font->height + 6);
|
||||||
|
|
||||||
LOG("got %d rows and %d cols\n", r_ws->rows, r_ws->cols);
|
|
||||||
|
|
||||||
int xoffset[r_ws->rows];
|
int xoffset[r_ws->rows];
|
||||||
int yoffset[r_ws->cols];
|
int yoffset[r_ws->cols];
|
||||||
/* Initialize offsets */
|
/* Initialize offsets */
|
||||||
|
@ -536,19 +540,12 @@ void render_workspace(xcb_connection_t *conn, i3Screen *screen, Workspace *r_ws)
|
||||||
for (int rows = 0; rows < r_ws->rows; rows++)
|
for (int rows = 0; rows < r_ws->rows; rows++)
|
||||||
xoffset[rows] = r_ws->rect.x;
|
xoffset[rows] = r_ws->rect.x;
|
||||||
|
|
||||||
dump_table(conn, r_ws);
|
|
||||||
|
|
||||||
ignore_enter_notify_forall(conn, r_ws, true);
|
ignore_enter_notify_forall(conn, r_ws, true);
|
||||||
|
|
||||||
/* Go through the whole table and render what’s necessary */
|
/* Go through the whole table and render what’s necessary */
|
||||||
FOR_TABLE(r_ws) {
|
FOR_TABLE(r_ws) {
|
||||||
Container *container = r_ws->table[cols][rows];
|
Container *container = r_ws->table[cols][rows];
|
||||||
int single_width = -1, single_height;
|
int single_width = -1, single_height;
|
||||||
LOG("\n");
|
|
||||||
LOG("========\n");
|
|
||||||
LOG("container has %d colspan, %d rowspan\n",
|
|
||||||
container->colspan, container->rowspan);
|
|
||||||
LOG("container at %d, %d\n", xoffset[rows], yoffset[cols]);
|
|
||||||
/* Update position of the container */
|
/* Update position of the container */
|
||||||
container->row = rows;
|
container->row = rows;
|
||||||
container->col = cols;
|
container->col = cols;
|
||||||
|
@ -576,7 +573,6 @@ void render_workspace(xcb_connection_t *conn, i3Screen *screen, Workspace *r_ws)
|
||||||
|
|
||||||
xoffset[rows] += single_width;
|
xoffset[rows] += single_width;
|
||||||
yoffset[cols] += single_height;
|
yoffset[cols] += single_height;
|
||||||
LOG("==========\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ignore_enter_notify_forall(conn, r_ws, false);
|
ignore_enter_notify_forall(conn, r_ws, false);
|
||||||
|
@ -596,10 +592,8 @@ void render_workspace(xcb_connection_t *conn, i3Screen *screen, Workspace *r_ws)
|
||||||
void render_layout(xcb_connection_t *conn) {
|
void render_layout(xcb_connection_t *conn) {
|
||||||
i3Screen *screen;
|
i3Screen *screen;
|
||||||
|
|
||||||
TAILQ_FOREACH(screen, virtual_screens, screens) {
|
TAILQ_FOREACH(screen, virtual_screens, screens)
|
||||||
LOG("Rendering screen %d\n", screen->num);
|
|
||||||
render_workspace(conn, screen, &(workspaces[screen->current_workspace]));
|
render_workspace(conn, screen, &(workspaces[screen->current_workspace]));
|
||||||
}
|
|
||||||
|
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
}
|
}
|
||||||
|
|
21
src/manage.c
21
src/manage.c
|
@ -68,7 +68,6 @@ void manage_existing_windows(xcb_connection_t *conn, xcb_property_handlers_t *pr
|
||||||
void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *conn,
|
void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *conn,
|
||||||
xcb_window_t window, xcb_get_window_attributes_cookie_t cookie,
|
xcb_window_t window, xcb_get_window_attributes_cookie_t cookie,
|
||||||
bool needs_to_be_mapped) {
|
bool needs_to_be_mapped) {
|
||||||
LOG("managing window.\n");
|
|
||||||
xcb_drawable_t d = { window };
|
xcb_drawable_t d = { window };
|
||||||
xcb_get_geometry_cookie_t geomc;
|
xcb_get_geometry_cookie_t geomc;
|
||||||
xcb_get_geometry_reply_t *geom;
|
xcb_get_geometry_reply_t *geom;
|
||||||
|
@ -83,16 +82,12 @@ void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *conn,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needs_to_be_mapped && attr->map_state != XCB_MAP_STATE_VIEWABLE) {
|
if (needs_to_be_mapped && attr->map_state != XCB_MAP_STATE_VIEWABLE)
|
||||||
LOG("Window not mapped, not managing\n");
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
|
|
||||||
/* Don’t manage clients with the override_redirect flag */
|
/* Don’t manage clients with the override_redirect flag */
|
||||||
if (attr->override_redirect) {
|
if (attr->override_redirect)
|
||||||
LOG("override_redirect set, not managing\n");
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if the window is already managed */
|
/* Check if the window is already managed */
|
||||||
if (table_get(&by_child, window))
|
if (table_get(&by_child, window))
|
||||||
|
@ -158,7 +153,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
||||||
/* Events for already managed windows should already be filtered in manage_window() */
|
/* Events for already managed windows should already be filtered in manage_window() */
|
||||||
assert(new == NULL);
|
assert(new == NULL);
|
||||||
|
|
||||||
LOG("reparenting new client\n");
|
LOG("Reparenting window 0x%08x\n", child);
|
||||||
LOG("x = %d, y = %d, width = %d, height = %d\n", x, y, width, height);
|
LOG("x = %d, y = %d, width = %d, height = %d\n", x, y, width, height);
|
||||||
new = calloc(sizeof(Client), 1);
|
new = calloc(sizeof(Client), 1);
|
||||||
new->force_reconfigure = true;
|
new->force_reconfigure = true;
|
||||||
|
@ -177,6 +172,8 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
||||||
new->child = child;
|
new->child = child;
|
||||||
new->rect.width = width;
|
new->rect.width = width;
|
||||||
new->rect.height = height;
|
new->rect.height = height;
|
||||||
|
new->width_increment = 1;
|
||||||
|
new->height_increment = 1;
|
||||||
/* Pre-initialize the values for floating */
|
/* Pre-initialize the values for floating */
|
||||||
new->floating_rect.x = -1;
|
new->floating_rect.x = -1;
|
||||||
new->floating_rect.width = width;
|
new->floating_rect.width = width;
|
||||||
|
@ -192,8 +189,6 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
||||||
mask |= XCB_CW_EVENT_MASK;
|
mask |= XCB_CW_EVENT_MASK;
|
||||||
values[1] = FRAME_EVENT_MASK;
|
values[1] = FRAME_EVENT_MASK;
|
||||||
|
|
||||||
LOG("Reparenting 0x%08x under 0x%08x.\n", child, new->frame);
|
|
||||||
|
|
||||||
i3Font *font = load_font(conn, config.font);
|
i3Font *font = load_font(conn, config.font);
|
||||||
width = min(width, c_ws->rect.x + c_ws->rect.width);
|
width = min(width, c_ws->rect.x + c_ws->rect.width);
|
||||||
height = min(height, c_ws->rect.y + c_ws->rect.height);
|
height = min(height, c_ws->rect.y + c_ws->rect.height);
|
||||||
|
@ -313,7 +308,6 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
||||||
preply = xcb_get_property_reply(conn, leader_cookie, NULL);
|
preply = xcb_get_property_reply(conn, leader_cookie, NULL);
|
||||||
handle_clientleader_change(NULL, conn, 0, new->child, atoms[WM_CLIENT_LEADER], preply);
|
handle_clientleader_change(NULL, conn, 0, new->child, atoms[WM_CLIENT_LEADER], preply);
|
||||||
|
|
||||||
LOG("DEBUG: should have all infos now\n");
|
|
||||||
struct Assignment *assign;
|
struct Assignment *assign;
|
||||||
TAILQ_FOREACH(assign, &assignments, assignments) {
|
TAILQ_FOREACH(assign, &assignments, assignments) {
|
||||||
if (get_matching_client(conn, assign->windowclass_title, new) == NULL)
|
if (get_matching_client(conn, assign->windowclass_title, new) == NULL)
|
||||||
|
@ -435,10 +429,9 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
||||||
|
|
||||||
/* Map the window first to avoid flickering */
|
/* Map the window first to avoid flickering */
|
||||||
xcb_map_window(conn, child);
|
xcb_map_window(conn, child);
|
||||||
if (map_frame) {
|
if (map_frame)
|
||||||
LOG("Mapping client\n");
|
|
||||||
client_map(conn, new);
|
client_map(conn, new);
|
||||||
}
|
|
||||||
if (CUR_CELL->workspace->fullscreen_client == NULL && !new->dock) {
|
if (CUR_CELL->workspace->fullscreen_client == NULL && !new->dock) {
|
||||||
/* Focus the new window if we’re not in fullscreen mode and if it is not a dock window */
|
/* Focus the new window if we’re not in fullscreen mode and if it is not a dock window */
|
||||||
if (new->workspace->fullscreen_client == NULL) {
|
if (new->workspace->fullscreen_client == NULL) {
|
||||||
|
|
|
@ -240,10 +240,8 @@ void set_focus(xcb_connection_t *conn, Client *client, bool set_anyways) {
|
||||||
Client *old_client = SLIST_FIRST(&(c_ws->focus_stack));
|
Client *old_client = SLIST_FIRST(&(c_ws->focus_stack));
|
||||||
|
|
||||||
/* Check if the focus needs to be changed at all */
|
/* Check if the focus needs to be changed at all */
|
||||||
if (!set_anyways && (old_client == client)) {
|
if (!set_anyways && (old_client == client))
|
||||||
LOG("old_client == client, not changing focus\n");
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
/* Store current_row/current_col */
|
/* Store current_row/current_col */
|
||||||
c_ws->current_row = current_row;
|
c_ws->current_row = current_row;
|
||||||
|
@ -261,7 +259,7 @@ void set_focus(xcb_connection_t *conn, Client *client, bool set_anyways) {
|
||||||
current_row = client->container->row;
|
current_row = client->container->row;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("set_focus(frame %08x, child %08x, name %s)\n", client->frame, client->child, client->name);
|
CLIENT_LOG(client);
|
||||||
/* Set focus to the entered window, and flush xcb buffer immediately */
|
/* Set focus to the entered window, and flush xcb buffer immediately */
|
||||||
xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, client->child, XCB_CURRENT_TIME);
|
xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, client->child, XCB_CURRENT_TIME);
|
||||||
//xcb_warp_pointer(conn, XCB_NONE, client->child, 0, 0, 0, 0, 10, 10);
|
//xcb_warp_pointer(conn, XCB_NONE, client->child, 0, 0, 0, 0, 10, 10);
|
||||||
|
|
|
@ -181,8 +181,6 @@ void fake_configure_notify(xcb_connection_t *conn, Rect r, xcb_window_t window)
|
||||||
|
|
||||||
xcb_send_event(conn, false, window, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (char*)&generated_event);
|
xcb_send_event(conn, false, window, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (char*)&generated_event);
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
|
|
||||||
LOG("Told the client it is at %dx%d with %dx%d\n", r.x, r.y, r.width, r.height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -92,7 +92,7 @@ i3Screen *get_screen_containing(int x, int y) {
|
||||||
* This function always returns a screen.
|
* This function always returns a screen.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
i3Screen *get_screen_most(direction_t direction) {
|
i3Screen *get_screen_most(direction_t direction, i3Screen *current) {
|
||||||
i3Screen *screen, *candidate = NULL;
|
i3Screen *screen, *candidate = NULL;
|
||||||
int position = 0;
|
int position = 0;
|
||||||
TAILQ_FOREACH(screen, virtual_screens, screens) {
|
TAILQ_FOREACH(screen, virtual_screens, screens) {
|
||||||
|
@ -104,6 +104,14 @@ i3Screen *get_screen_most(direction_t direction) {
|
||||||
} \
|
} \
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (((direction == D_UP) || (direction == D_DOWN)) &&
|
||||||
|
(current->rect.x != screen->rect.x))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (((direction == D_LEFT) || (direction == D_RIGHT)) &&
|
||||||
|
(current->rect.y != screen->rect.y))
|
||||||
|
continue;
|
||||||
|
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case D_UP:
|
case D_UP:
|
||||||
WIN(screen->rect.y, <= position);
|
WIN(screen->rect.y, <= position);
|
||||||
|
|
Loading…
Reference in New Issue