324 lines
7.9 KiB
C
Raw Normal View History

/*
* DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Layout algorithms implementation
*/
#include "layout.h"
#include "client.h"
#include "workspace.h"
#include "config.h"
#include "util.h"
#include "panel.h"
#include "notifications.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;
}
panel_raise_all();
notifications_raise_all();
}
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)
{
int area_x, area_y, area_width, area_height;
layout_get_usable_area(&area_x, &area_y, &area_width, &area_height);
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 title_h = (dwn->config && dwn->config->show_decorations) ?
config_get_title_height() : 0;
int border = c->border_width;
/* Constrain top */
if (c->y - title_h - border < area_y) {
c->y = area_y + title_h + border;
}
/* Constrain left */
if (c->x - border < area_x) {
c->x = area_x + border;
}
/* Constrain bottom */
if (c->y + c->height + border > area_y + area_height) {
c->y = area_y + area_height - c->height - border;
/* If it still violates top after moving up, we must resize */
if (c->y - title_h - border < area_y) {
c->y = area_y + title_h + border;
c->height = area_y + area_height - c->y - border;
}
}
/* Constrain right */
if (c->x + c->width + border > area_x + area_width) {
c->x = area_x + area_width - c->width - border;
/* If it still violates left after moving left, we must resize */
if (c->x - border < area_x) {
c->x = area_x + border;
c->width = area_x + area_width - c->x - border;
}
}
if (c->width < 50) c->width = 50;
if (c->height < 50) c->height = 50;
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;
}
}
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 "???";
}