/* * DWN - Desktop Window Manager * retoor * 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; } 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 "???"; }