2025-12-28 03:14:31 +01:00
|
|
|
/*
|
|
|
|
|
* DWN - Desktop Window Manager
|
2025-12-28 04:30:10 +01:00
|
|
|
* retoor <retoor@molodetz.nl>
|
2025-12-28 03:14:31 +01:00
|
|
|
* Layout algorithms implementation
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "layout.h"
|
|
|
|
|
#include "client.h"
|
|
|
|
|
#include "workspace.h"
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#include "util.h"
|
|
|
|
|
|
|
|
|
|
static const char *layout_names[] = {
|
|
|
|
|
"Tiling",
|
|
|
|
|
"Floating",
|
|
|
|
|
"Monocle"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const char *layout_symbols[] = {
|
|
|
|
|
"[]=",
|
|
|
|
|
"><>",
|
|
|
|
|
"[M]"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void layout_arrange(int workspace)
|
|
|
|
|
{
|
|
|
|
|
Workspace *ws = workspace_get(workspace);
|
|
|
|
|
if (ws == NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (ws->layout) {
|
|
|
|
|
case LAYOUT_TILING:
|
|
|
|
|
layout_arrange_tiling(workspace);
|
|
|
|
|
break;
|
|
|
|
|
case LAYOUT_FLOATING:
|
|
|
|
|
layout_arrange_floating(workspace);
|
|
|
|
|
break;
|
|
|
|
|
case LAYOUT_MONOCLE:
|
|
|
|
|
layout_arrange_monocle(workspace);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
layout_arrange_tiling(workspace);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void layout_arrange_tiling(int workspace)
|
|
|
|
|
{
|
|
|
|
|
Workspace *ws = workspace_get(workspace);
|
|
|
|
|
if (ws == NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int area_x, area_y, area_width, area_height;
|
|
|
|
|
layout_get_usable_area(&area_x, &area_y, &area_width, &area_height);
|
|
|
|
|
|
|
|
|
|
int gap = config_get_gap();
|
|
|
|
|
int title_height = config_get_title_height();
|
|
|
|
|
int border = config_get_border_width();
|
|
|
|
|
|
|
|
|
|
int n = layout_count_tiled_clients(workspace);
|
|
|
|
|
if (n == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int master_count = ws->master_count;
|
|
|
|
|
if (master_count > n) {
|
|
|
|
|
master_count = n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int master_width;
|
|
|
|
|
if (n <= master_count) {
|
|
|
|
|
master_width = area_width - 2 * gap;
|
|
|
|
|
} else {
|
|
|
|
|
master_width = (int)((area_width - 3 * gap) * ws->master_ratio);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int stack_width = area_width - master_width - 3 * gap;
|
|
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
int master_y = area_y + gap;
|
|
|
|
|
int stack_y = area_y + gap;
|
|
|
|
|
|
|
|
|
|
for (Client *c = dwn->client_list; c != NULL; c = c->next) {
|
|
|
|
|
if (c->workspace != (unsigned int)workspace) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (client_is_floating(c) || client_is_fullscreen(c) || client_is_minimized(c)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int x, y, w, h;
|
|
|
|
|
|
|
|
|
|
if (i < master_count) {
|
|
|
|
|
int master_h = (area_height - 2 * gap - (master_count - 1) * gap) / master_count;
|
|
|
|
|
|
|
|
|
|
x = area_x + gap;
|
|
|
|
|
y = master_y;
|
|
|
|
|
w = master_width;
|
|
|
|
|
h = master_h;
|
|
|
|
|
|
|
|
|
|
master_y += h + gap;
|
|
|
|
|
} else {
|
|
|
|
|
int stack_count = n - master_count;
|
|
|
|
|
int stack_h = (area_height - 2 * gap - (stack_count - 1) * gap) / stack_count;
|
|
|
|
|
|
|
|
|
|
x = area_x + gap + master_width + gap;
|
|
|
|
|
y = stack_y;
|
|
|
|
|
w = stack_width;
|
|
|
|
|
h = stack_h;
|
|
|
|
|
|
|
|
|
|
stack_y += h + gap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int actual_h = h - title_height - 2 * border;
|
|
|
|
|
int actual_w = w - 2 * border;
|
|
|
|
|
|
|
|
|
|
if (actual_h < 50) actual_h = 50;
|
|
|
|
|
if (actual_w < 50) actual_w = 50;
|
|
|
|
|
|
|
|
|
|
client_move_resize(c, x + border, y + title_height + border,
|
|
|
|
|
actual_w, actual_h);
|
|
|
|
|
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void layout_arrange_floating(int workspace)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
for (Client *c = dwn->client_list; c != NULL; c = c->next) {
|
|
|
|
|
if (c->workspace != (unsigned int)workspace) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (client_is_minimized(c)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int area_x, area_y, area_width, area_height;
|
|
|
|
|
layout_get_usable_area(&area_x, &area_y, &area_width, &area_height);
|
|
|
|
|
|
|
|
|
|
if (c->x < area_x) c->x = area_x;
|
|
|
|
|
if (c->y < area_y) c->y = area_y;
|
|
|
|
|
if (c->x + c->width > area_x + area_width) {
|
|
|
|
|
c->x = area_x + area_width - c->width;
|
|
|
|
|
}
|
|
|
|
|
if (c->y + c->height > area_y + area_height) {
|
|
|
|
|
c->y = area_y + area_height - c->height;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
client_configure(c);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void layout_arrange_monocle(int workspace)
|
|
|
|
|
{
|
|
|
|
|
int area_x, area_y, area_width, area_height;
|
|
|
|
|
layout_get_usable_area(&area_x, &area_y, &area_width, &area_height);
|
|
|
|
|
|
|
|
|
|
int gap = config_get_gap();
|
|
|
|
|
int title_height = config_get_title_height();
|
|
|
|
|
int border = config_get_border_width();
|
|
|
|
|
|
|
|
|
|
for (Client *c = dwn->client_list; c != NULL; c = c->next) {
|
|
|
|
|
if (c->workspace != (unsigned int)workspace) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (client_is_floating(c) || client_is_fullscreen(c) || client_is_minimized(c)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int x = area_x + gap;
|
|
|
|
|
int y = area_y + gap;
|
|
|
|
|
int w = area_width - 2 * gap - 2 * border;
|
|
|
|
|
int h = area_height - 2 * gap - title_height - 2 * border;
|
|
|
|
|
|
|
|
|
|
if (h < 50) h = 50;
|
|
|
|
|
if (w < 50) w = 50;
|
|
|
|
|
|
|
|
|
|
client_move_resize(c, x + border, y + title_height + border, w, h);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int layout_get_usable_area(int *x, int *y, int *width, int *height)
|
|
|
|
|
{
|
|
|
|
|
if (dwn == NULL) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int panel_height = config_get_panel_height();
|
|
|
|
|
bool top_panel = (dwn->config != NULL) ? dwn->config->top_panel_enabled : true;
|
|
|
|
|
bool bottom_panel = (dwn->config != NULL) ? dwn->config->bottom_panel_enabled : true;
|
|
|
|
|
|
|
|
|
|
*x = 0;
|
|
|
|
|
*y = top_panel ? panel_height : 0;
|
|
|
|
|
*width = dwn->screen_width;
|
|
|
|
|
*height = dwn->screen_height;
|
|
|
|
|
|
|
|
|
|
if (top_panel) {
|
|
|
|
|
*height -= panel_height;
|
|
|
|
|
}
|
|
|
|
|
if (bottom_panel) {
|
|
|
|
|
*height -= panel_height;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int layout_count_tiled_clients(int workspace)
|
|
|
|
|
{
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
|
|
for (Client *c = dwn->client_list; c != NULL; c = c->next) {
|
|
|
|
|
if (c->workspace != (unsigned int)workspace) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (client_is_floating(c) || client_is_fullscreen(c) || client_is_minimized(c)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-28 11:21:03 +01:00
|
|
|
void layout_apply_snap_constraint(Client *c, int area_x, int area_y,
|
|
|
|
|
int area_w, int area_h, int gap)
|
|
|
|
|
{
|
|
|
|
|
if (c == NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int half_w = area_w / 2;
|
|
|
|
|
int half_h = area_h / 2;
|
|
|
|
|
|
|
|
|
|
switch (c->snap.horizontal) {
|
|
|
|
|
case SNAP_H_LEFT:
|
|
|
|
|
c->x = area_x + gap;
|
|
|
|
|
c->width = half_w - gap * 2;
|
|
|
|
|
break;
|
|
|
|
|
case SNAP_H_RIGHT:
|
|
|
|
|
c->x = area_x + half_w + gap;
|
|
|
|
|
c->width = half_w - gap * 2;
|
|
|
|
|
break;
|
|
|
|
|
case SNAP_H_FULL:
|
|
|
|
|
c->x = area_x + gap;
|
|
|
|
|
c->width = area_w - gap * 2;
|
|
|
|
|
break;
|
|
|
|
|
case SNAP_H_NONE:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (c->snap.vertical) {
|
|
|
|
|
case SNAP_V_TOP:
|
|
|
|
|
c->y = area_y + gap;
|
|
|
|
|
c->height = half_h - gap * 2;
|
|
|
|
|
break;
|
|
|
|
|
case SNAP_V_BOTTOM:
|
|
|
|
|
c->y = area_y + half_h + gap;
|
|
|
|
|
c->height = half_h - gap * 2;
|
|
|
|
|
break;
|
|
|
|
|
case SNAP_V_FULL:
|
|
|
|
|
c->y = area_y + gap;
|
|
|
|
|
c->height = area_h - gap * 2;
|
|
|
|
|
break;
|
|
|
|
|
case SNAP_V_NONE:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-28 03:14:31 +01:00
|
|
|
const char *layout_get_name(LayoutType layout)
|
|
|
|
|
{
|
|
|
|
|
if (layout >= 0 && layout < LAYOUT_COUNT) {
|
|
|
|
|
return layout_names[layout];
|
|
|
|
|
}
|
|
|
|
|
return "Unknown";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *layout_get_symbol(LayoutType layout)
|
|
|
|
|
{
|
|
|
|
|
if (layout >= 0 && layout < LAYOUT_COUNT) {
|
|
|
|
|
return layout_symbols[layout];
|
|
|
|
|
}
|
|
|
|
|
return "???";
|
|
|
|
|
}
|