diff --git a/bin/dwn b/bin/dwn index 9f55182..538af44 100755 Binary files a/bin/dwn and b/bin/dwn differ diff --git a/build/ai.o b/build/ai.o index e1eb3b9..b4913ff 100644 Binary files a/build/ai.o and b/build/ai.o differ diff --git a/build/atoms.o b/build/atoms.o index b600c15..de9a0fa 100644 Binary files a/build/atoms.o and b/build/atoms.o differ diff --git a/build/client.d b/build/client.d index 5c1a493..1e7328b 100644 --- a/build/client.d +++ b/build/client.d @@ -18,7 +18,8 @@ build/client.o: src/client.c include/client.h include/dwn.h \ /usr/include/dbus-1.0/dbus/dbus-server.h \ /usr/include/dbus-1.0/dbus/dbus-signature.h \ /usr/include/dbus-1.0/dbus/dbus-syntax.h \ - /usr/include/dbus-1.0/dbus/dbus-threads.h include/layout.h + /usr/include/dbus-1.0/dbus/dbus-threads.h include/layout.h \ + include/panel.h include/client.h: include/dwn.h: include/atoms.h: @@ -46,3 +47,4 @@ include/notifications.h: /usr/include/dbus-1.0/dbus/dbus-syntax.h: /usr/include/dbus-1.0/dbus/dbus-threads.h: include/layout.h: +include/panel.h: diff --git a/build/client.o b/build/client.o index a1527ff..ecedce5 100644 Binary files a/build/client.o and b/build/client.o differ diff --git a/build/keys.d b/build/keys.d index 94fa0ec..34e8dd7 100644 --- a/build/keys.d +++ b/build/keys.d @@ -18,7 +18,8 @@ build/keys.o: src/keys.c include/keys.h include/dwn.h include/client.h \ /usr/include/dbus-1.0/dbus/dbus-signature.h \ /usr/include/dbus-1.0/dbus/dbus-syntax.h \ /usr/include/dbus-1.0/dbus/dbus-threads.h include/news.h \ - include/applauncher.h include/decorations.h include/demo.h + include/applauncher.h include/decorations.h include/demo.h \ + include/layout.h include/keys.h: include/dwn.h: include/client.h: @@ -49,3 +50,4 @@ include/news.h: include/applauncher.h: include/decorations.h: include/demo.h: +include/layout.h: diff --git a/build/keys.o b/build/keys.o index 2b7143a..8f1481e 100644 Binary files a/build/keys.o and b/build/keys.o differ diff --git a/build/layout.o b/build/layout.o index b04a777..66377f5 100644 Binary files a/build/layout.o and b/build/layout.o differ diff --git a/build/panel.o b/build/panel.o index dcd7b5c..3dfc344 100644 Binary files a/build/panel.o and b/build/panel.o differ diff --git a/build/workspace.o b/build/workspace.o index b69a31a..f850750 100644 Binary files a/build/workspace.o and b/build/workspace.o differ diff --git a/include/dwn.h b/include/dwn.h index df7983e..f170eb7 100644 --- a/include/dwn.h +++ b/include/dwn.h @@ -62,6 +62,26 @@ typedef enum { CLIENT_MAXIMIZED = (1 << 5) } ClientFlags; +typedef enum { + SNAP_H_NONE = 0, + SNAP_H_LEFT, + SNAP_H_RIGHT, + SNAP_H_FULL +} SnapHorizontal; + +typedef enum { + SNAP_V_NONE = 0, + SNAP_V_TOP, + SNAP_V_BOTTOM, + SNAP_V_FULL +} SnapVertical; + +typedef struct { + SnapHorizontal horizontal; + SnapVertical vertical; + long timestamp; +} SnapConstraint; + typedef struct Client Client; typedef struct Workspace Workspace; typedef struct Monitor Monitor; @@ -80,6 +100,7 @@ struct Client { unsigned int workspace; char title[256]; char class[64]; + SnapConstraint snap; Client *next; Client *prev; Client *mru_next; diff --git a/include/keys.h b/include/keys.h index cba08ee..ec507f2 100644 --- a/include/keys.h +++ b/include/keys.h @@ -83,6 +83,8 @@ void key_show_shortcuts(void); void key_start_tutorial(void); void key_snap_left(void); void key_snap_right(void); +void key_snap_up(void); +void key_snap_down(void); void key_start_demo(void); void tutorial_start(void); diff --git a/include/layout.h b/include/layout.h index ca807c1..a83c881 100644 --- a/include/layout.h +++ b/include/layout.h @@ -17,6 +17,9 @@ void layout_arrange_monocle(int workspace); int layout_get_usable_area(int *x, int *y, int *width, int *height); int layout_count_tiled_clients(int workspace); +void layout_apply_snap_constraint(Client *c, int area_x, int area_y, + int area_w, int area_h, int gap); + const char *layout_get_name(LayoutType layout); const char *layout_get_symbol(LayoutType layout); diff --git a/site/shortcuts.html b/site/shortcuts.html index 73a11a9..5845e9e 100644 --- a/site/shortcuts.html +++ b/site/shortcuts.html @@ -250,13 +250,37 @@ Super + D Decrease master window count + + + +

Window Snapping (Composable)

+

+ Snapping shortcuts are composable: press Super+Left then Super+Up for top-left quarter. Press the same key twice to expand to full in that axis. +

+
+ + + + + + + + - + - + + + + + + + + +
ShortcutAction
Super + LeftSnap window to left half (50% width)Snap left 50% (press twice for full width)
Super + RightSnap window to right half (50% width)Snap right 50% (press twice for full width)
Super + UpSnap top 50% (press twice for full height)
Super + DownSnap bottom 50% (press twice for full height)
@@ -291,7 +315,7 @@

News Ticker

- Navigate the scrolling news ticker displayed in the bottom panel. + The scrolling news ticker is displayed in the bottom panel.

@@ -302,14 +326,6 @@ - - - - - - - - @@ -380,7 +396,7 @@ Super+H/L Resize master
  • - Super+Left/Right Snap 50% + Super+Arrows Composable snap
  • Shift+F1-9 Move to workspace diff --git a/src/client.c b/src/client.c index fde5c0d..d9a6088 100644 --- a/src/client.c +++ b/src/client.c @@ -12,6 +12,7 @@ #include "decorations.h" #include "notifications.h" #include "layout.h" +#include "panel.h" #include #include @@ -46,6 +47,9 @@ Client *client_create(Window window) client->prev = NULL; client->mru_next = NULL; client->mru_prev = NULL; + client->snap.horizontal = SNAP_H_NONE; + client->snap.vertical = SNAP_V_NONE; + client->snap.timestamp = 0; XWindowAttributes wa; int orig_width = 640, orig_height = 480; @@ -396,6 +400,7 @@ void client_raise(Client *client) XRaiseWindow(dwn->display, win); notifications_raise_all(); + panel_raise_all(); } void client_lower(Client *client) @@ -443,6 +448,13 @@ void client_move(Client *client, int x, int y) return; } + int area_x, area_y, area_w, area_h; + layout_get_usable_area(&area_x, &area_y, &area_w, &area_h); + + if (y < area_y) { + y = area_y; + } + client->x = x; client->y = y; client_configure(client); diff --git a/src/keys.c b/src/keys.c index 6fcd568..0d39f7b 100644 --- a/src/keys.c +++ b/src/keys.c @@ -15,6 +15,7 @@ #include "applauncher.h" #include "decorations.h" #include "demo.h" +#include "layout.h" #include #include @@ -530,9 +531,9 @@ void keys_setup_defaults(void) keys_bind(MOD_SUPER, XK_t, key_start_tutorial, "Start tutorial"); - keys_bind(MOD_SUPER, XK_Down, key_news_next, "Next news article"); + keys_bind(MOD_SUPER, XK_Down, key_snap_down, "Snap window bottom/full"); - keys_bind(MOD_SUPER, XK_Up, key_news_prev, "Previous news article"); + keys_bind(MOD_SUPER, XK_Up, key_snap_up, "Snap window top/full"); keys_bind(MOD_SUPER, XK_Return, key_news_open, "Open news article"); @@ -802,8 +803,12 @@ void key_show_shortcuts(void) "Super+L Expand master area\n" "Super+I Add to master\n" "Super+D Remove from master\n" - "Super+Left Snap window left (50%)\n" - "Super+Right Snap window right (50%)\n" + "\n" + "=== Window Snapping (composable) ===\n" + "Super+Left Left 50% (2x=full width)\n" + "Super+Right Right 50% (2x=full width)\n" + "Super+Up Top 50% (2x=full height)\n" + "Super+Down Bottom 50% (2x=full height)\n" "\n" "=== AI Features ===\n" "Super+A Show AI context\n" @@ -851,10 +856,6 @@ void key_screenshot(void) void key_snap_left(void) { - if (dwn == NULL) { - return; - } - Workspace *ws = workspace_get_current(); if (ws == NULL || ws->focused == NULL) { return; @@ -862,42 +863,30 @@ void key_snap_left(void) Client *c = ws->focused; - int work_x = 0; - int work_y = 0; - int work_width = dwn->screen_width; - int work_height = dwn->screen_height; - - if (dwn->config != NULL) { - if (dwn->config->top_panel_enabled) { - work_y += config_get_panel_height(); - work_height -= config_get_panel_height(); - } - if (dwn->config->bottom_panel_enabled) { - work_height -= config_get_panel_height(); - } - } - - int gap = config_get_gap(); - if (!client_is_floating(c)) { client_set_floating(c, true); } - c->x = work_x + gap; - c->y = work_y + gap; - c->width = (work_width / 2) - (gap * 2); - c->height = work_height - (gap * 2); + if (c->snap.horizontal == SNAP_H_LEFT) { + c->snap.horizontal = SNAP_H_FULL; + } else { + c->snap.horizontal = SNAP_H_LEFT; + } + if (c->snap.vertical == SNAP_V_NONE) { + c->snap.vertical = SNAP_V_FULL; + } + int area_x, area_y, area_w, area_h; + layout_get_usable_area(&area_x, &area_y, &area_w, &area_h); + int gap = config_get_gap(); + + layout_apply_snap_constraint(c, area_x, area_y, area_w, area_h, gap); client_configure(c); decorations_render(c, true); } void key_snap_right(void) { - if (dwn == NULL) { - return; - } - Workspace *ws = workspace_get_current(); if (ws == NULL || ws->focused == NULL) { return; @@ -905,32 +894,86 @@ void key_snap_right(void) Client *c = ws->focused; - int work_x = 0; - int work_y = 0; - int work_width = dwn->screen_width; - int work_height = dwn->screen_height; - - if (dwn->config != NULL) { - if (dwn->config->top_panel_enabled) { - work_y += config_get_panel_height(); - work_height -= config_get_panel_height(); - } - if (dwn->config->bottom_panel_enabled) { - work_height -= config_get_panel_height(); - } + if (!client_is_floating(c)) { + client_set_floating(c, true); } + if (c->snap.horizontal == SNAP_H_RIGHT) { + c->snap.horizontal = SNAP_H_FULL; + } else { + c->snap.horizontal = SNAP_H_RIGHT; + } + if (c->snap.vertical == SNAP_V_NONE) { + c->snap.vertical = SNAP_V_FULL; + } + + int area_x, area_y, area_w, area_h; + layout_get_usable_area(&area_x, &area_y, &area_w, &area_h); int gap = config_get_gap(); + layout_apply_snap_constraint(c, area_x, area_y, area_w, area_h, gap); + client_configure(c); + decorations_render(c, true); +} + +void key_snap_up(void) +{ + Workspace *ws = workspace_get_current(); + if (ws == NULL || ws->focused == NULL) { + return; + } + + Client *c = ws->focused; + if (!client_is_floating(c)) { client_set_floating(c, true); } - c->x = work_x + (work_width / 2) + gap; - c->y = work_y + gap; - c->width = (work_width / 2) - (gap * 2); - c->height = work_height - (gap * 2); + if (c->snap.vertical == SNAP_V_TOP) { + c->snap.vertical = SNAP_V_FULL; + } else { + c->snap.vertical = SNAP_V_TOP; + } + if (c->snap.horizontal == SNAP_H_NONE) { + c->snap.horizontal = SNAP_H_FULL; + } + int area_x, area_y, area_w, area_h; + layout_get_usable_area(&area_x, &area_y, &area_w, &area_h); + int gap = config_get_gap(); + + layout_apply_snap_constraint(c, area_x, area_y, area_w, area_h, gap); + client_configure(c); + decorations_render(c, true); +} + +void key_snap_down(void) +{ + Workspace *ws = workspace_get_current(); + if (ws == NULL || ws->focused == NULL) { + return; + } + + Client *c = ws->focused; + + if (!client_is_floating(c)) { + client_set_floating(c, true); + } + + if (c->snap.vertical == SNAP_V_BOTTOM) { + c->snap.vertical = SNAP_V_FULL; + } else { + c->snap.vertical = SNAP_V_BOTTOM; + } + if (c->snap.horizontal == SNAP_H_NONE) { + c->snap.horizontal = SNAP_H_FULL; + } + + int area_x, area_y, area_w, area_h; + layout_get_usable_area(&area_x, &area_y, &area_w, &area_h); + int gap = config_get_gap(); + + layout_apply_snap_constraint(c, area_x, area_y, area_w, area_h, gap); client_configure(c); decorations_render(c, true); } diff --git a/src/layout.c b/src/layout.c index ff486db..5233cf3 100644 --- a/src/layout.c +++ b/src/layout.c @@ -229,6 +229,51 @@ int layout_count_tiled_clients(int workspace) 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) {
  • Super + DownNext news article
    Super + UpPrevious news article
    Super + Return Open current article in browser