Implement floating (please test and find bugs)

Details which are missing: A command to hide/show all floating clients,
moving/resizing clients with your mouse holding Mod1 (click anywhere
in the client, not just on its borders), resize/move by keyboard, select
next/previous client by keyboard
This commit is contained in:
Michael Stapelberg
2009-05-23 16:34:03 +02:00
parent 6bb0c82588
commit 5b8e2ecb18
12 changed files with 525 additions and 60 deletions

View File

@ -24,6 +24,7 @@
#include "i3.h"
#include "xinerama.h"
#include "client.h"
#include "floating.h"
bool focus_window_in_container(xcb_connection_t *conn, Container *container, direction_t direction) {
/* If this container is empty, were done */
@ -418,6 +419,49 @@ static void snap_current_container(xcb_connection_t *conn, direction_t direction
render_layout(conn);
}
static void move_floating_window_to_workspace(xcb_connection_t *conn, Client *client, int workspace) {
/* t_ws (to workspace) is just a container pointer to the workspace were switching to */
Workspace *t_ws = &(workspaces[workspace-1]);
LOG("moving floating\n");
if (t_ws->screen == NULL) {
LOG("initializing new workspace, setting num to %d\n", workspace-1);
t_ws->screen = c_ws->screen;
/* Copy the dimensions from the virtual screen */
memcpy(&(t_ws->rect), &(t_ws->screen->rect), sizeof(Rect));
} else {
/* Check if there is already a fullscreen client on the destination workspace and
* stop moving if so. */
if (client->fullscreen && (t_ws->fullscreen_client != NULL)) {
LOG("Not moving: Fullscreen client already existing on destination workspace.\n");
return;
}
}
/* Remove from focus stack */
SLIST_REMOVE(&(client->workspace->focus_stack), client, Client, focus_clients);
if (client->workspace->fullscreen_client == client)
client->workspace->fullscreen_client = NULL;
/* Insert into destination focus stack */
client->workspace = t_ws;
SLIST_INSERT_HEAD(&(t_ws->focus_stack), client, focus_clients);
if (client->fullscreen)
t_ws->fullscreen_client = client;
/* If were moving it to an invisible screen, we need to unmap it */
if (t_ws->screen->current_workspace != t_ws->num) {
LOG("This workspace is not visible, unmapping\n");
xcb_unmap_window(conn, client->frame);
}
LOG("done\n");
render_layout(conn);
}
/*
* Moves the currently selected window to the given workspace
*
@ -463,7 +507,9 @@ static void move_current_window_to_workspace(xcb_connection_t *conn, int workspa
if (container->workspace->fullscreen_client == current_client)
container->workspace->fullscreen_client = NULL;
/* TODO: insert it to the correct position */
CIRCLEQ_INSERT_TAIL(&(to_container->clients), current_client, clients);
SLIST_INSERT_HEAD(&(to_container->workspace->focus_stack), current_client, focus_clients);
if (current_client->fullscreen)
t_ws->fullscreen_client = current_client;
@ -564,6 +610,14 @@ void show_workspace(xcb_connection_t *conn, int workspace) {
CIRCLEQ_FOREACH(client, &(c_ws->table[cols][rows]->clients), clients)
xcb_map_window(conn, client->frame);
/* Map all floating clients */
SLIST_FOREACH(client, &(c_ws->focus_stack), focus_clients) {
if (!client->floating)
continue;
xcb_map_window(conn, client->frame);
}
/* Map all stack windows, if any */
struct Stack_Window *stack_win;
SLIST_FOREACH(stack_win, &stack_wins, stack_windows)
@ -683,6 +737,12 @@ static void travel_focus_stack(xcb_connection_t *conn, const char *arguments) {
*/
void parse_command(xcb_connection_t *conn, const char *command) {
LOG("--- parsing command \"%s\" ---\n", command);
/* Get the first client from focus stack because floating clients are not
* in any container, therefore CUR_CELL is not appropriate. */
Client *last_focused = SLIST_FIRST(&(c_ws->focus_stack));
if (last_focused == SLIST_END(&(c_ws->focus_stack)))
last_focused = NULL;
/* Hmm, just to be sure */
if (command[0] == '\0')
return;
@ -708,17 +768,17 @@ void parse_command(xcb_connection_t *conn, const char *command) {
}
if (STARTS_WITH(command, "kill")) {
if (CUR_CELL->currently_focused == NULL) {
if (last_focused == NULL) {
LOG("There is no window to kill\n");
return;
}
LOG("Killing current window\n");
client_kill(conn, CUR_CELL->currently_focused);
client_kill(conn, last_focused);
return;
}
/* Is it a jump to a specified workspae, row, col? */
/* Is it a jump to a specified workspace, row, col? */
if (STARTS_WITH(command, "jump ")) {
const char *arguments = command + strlen("jump ");
if (arguments[0] == '"')
@ -736,19 +796,34 @@ void parse_command(xcb_connection_t *conn, const char *command) {
/* Is it 'f' for fullscreen? */
if (command[0] == 'f') {
if (CUR_CELL->currently_focused == NULL)
if (last_focused == NULL)
return;
toggle_fullscreen(conn, CUR_CELL->currently_focused);
toggle_fullscreen(conn, last_focused);
return;
}
/* Is it just 's' for stacking or 'd' for default? */
if ((command[0] == 's' || command[0] == 'd') && (command[1] == '\0')) {
if (last_focused->floating) {
LOG("not switching, this is a floating client\n");
return;
}
LOG("Switching mode for current container\n");
switch_layout_mode(conn, CUR_CELL, (command[0] == 's' ? MODE_STACK : MODE_DEFAULT));
return;
}
/* Is it 't' for toggle tiling/floating? */
if (command[0] == 't') {
if (last_focused == NULL) {
LOG("Cannot toggle tiling/floating: workspace empty\n");
return;
}
toggle_floating_mode(conn, last_focused);
return;
}
enum { WITH_WINDOW, WITH_CONTAINER } with = WITH_WINDOW;
/* Is it a <with>? */
@ -764,7 +839,7 @@ void parse_command(xcb_connection_t *conn, const char *command) {
}
}
/* It's a normal <cmd> */
/* Its a normal <cmd> */
char *rest = NULL;
enum { ACTION_FOCUS, ACTION_MOVE, ACTION_SNAP } action = ACTION_FOCUS;
direction_t direction;
@ -793,7 +868,14 @@ void parse_command(xcb_connection_t *conn, const char *command) {
}
if (*rest == '\0') {
move_current_window_to_workspace(conn, workspace);
if (last_focused->floating)
move_floating_window_to_workspace(conn, last_focused, workspace);
else move_current_window_to_workspace(conn, workspace);
return;
}
if (last_focused->floating) {
LOG("Not performing because this is a floating window\n");
return;
}