dwm-workspaces-20260411-23a25b2.diff (17315B)
1 From 23a25b2918e083e7c9ecad934db7841004aa4629 Mon Sep 17 00:00:00 2001 2 From: 8dcc <8dcc.git@gmail.com> 3 Date: Sat, 11 Apr 2026 17:38:52 +0200 4 Subject: [PATCH] Add support for multiple workspaces 5 6 Each monitor now has N independently-named workspaces (defined via the 7 new 'workspaces' array in 'config.h', like 'tags'). Every client belongs 8 to exactly one workspace; switching workspaces hides all clients from 9 the previous workspace and shows only those from the new one. 10 11 Each workspace maintains its own tag view, layout, and layout history 12 independently of all others. Switching workspaces carries the current 13 tag selection over so the viewed tag does not change. 14 15 Default keybinds (where 'F<n>' represents function keys): 16 17 * Mod+F<n>: Switch to workspace N. 18 * Mod+Shift+F<n>: Move focused window to workspace N. 19 20 The bar shows workspace buttons leftmost, styled identically to tag 21 buttons ('SchemeSel' for active, 'SchemeNorm' for others). Clicking a 22 workspace button switches to it. 23 --- 24 config.def.h | 8 +++ 25 dwm.c | 181 ++++++++++++++++++++++++++++++++++++--------------- 26 2 files changed, 135 insertions(+), 54 deletions(-) 27 28 diff --git a/config.def.h b/config.def.h 29 index 1c0b587..db6ce40 100644 30 --- a/config.def.h 31 +++ b/config.def.h 32 @@ -20,6 +20,7 @@ static const char *colors[][3] = { 33 34 /* tagging */ 35 static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; 36 +static const char *workspaces[] = { "A", "B", "C" }; 37 38 static const Rule rules[] = { 39 /* xprop(1): 40 @@ -50,6 +51,9 @@ static const Layout layouts[] = { 41 { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ 42 { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ 43 { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, 44 +#define WSKEYS(KEY,WS) \ 45 + { MODKEY, KEY, viewws, {.i = (WS)} }, \ 46 + { MODKEY|ShiftMask, KEY, tagws, {.i = (WS)} }, 47 48 /* helper for spawning shell commands in the pre dwm-5.0 fashion */ 49 #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } 50 @@ -93,6 +97,9 @@ static Key keys[] = { 51 TAGKEYS( XK_7, 6) 52 TAGKEYS( XK_8, 7) 53 TAGKEYS( XK_9, 8) 54 + WSKEYS( XK_F1, 0) 55 + WSKEYS( XK_F2, 1) 56 + WSKEYS( XK_F3, 2) 57 { MODKEY|ShiftMask, XK_q, quit, {0} }, 58 }; 59 60 @@ -100,6 +107,7 @@ static Key keys[] = { 61 /* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ 62 static Button buttons[] = { 63 /* click event mask button function argument */ 64 + { ClkWsBar, 0, Button1, viewws, {0} }, 65 { ClkLtSymbol, 0, Button1, setlayout, {0} }, 66 { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, 67 { ClkWinTitle, 0, Button2, zoom, {0} }, 68 diff --git a/dwm.c b/dwm.c 69 index 4465af1..7534363 100644 70 --- a/dwm.c 71 +++ b/dwm.c 72 @@ -49,7 +49,10 @@ 73 #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) 74 #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ 75 * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) 76 -#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) 77 +#define MWS(m) ((m)->ws[(m)->selws]) 78 +#define MTAGSET(m) (MWS(m).tagset[MWS(m).seltags]) 79 +#define ISVISIBLE(C) ((C)->tags & MTAGSET((C)->mon) \ 80 + && (C)->ws == (C)->mon->selws) 81 #define LENGTH(X) (sizeof X / sizeof X[0]) 82 #define MOUSEMASK (BUTTONMASK|PointerMotionMask) 83 #define WIDTH(X) ((X)->w + 2 * (X)->bw) 84 @@ -64,7 +67,7 @@ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, 85 NetWMFullscreen, NetActiveWindow, NetWMWindowType, 86 NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ 87 enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ 88 -enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, 89 +enum { ClkWsBar, ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, 90 ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ 91 92 typedef union { 93 @@ -92,6 +95,7 @@ struct Client { 94 int basew, baseh, incw, inch, maxw, maxh, minw, minh; 95 int bw, oldbw; 96 unsigned int tags; 97 + int ws; 98 int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; 99 Client *next; 100 Client *snext; 101 @@ -111,17 +115,23 @@ typedef struct { 102 void (*arrange)(Monitor *); 103 } Layout; 104 105 -struct Monitor { 106 +typedef struct { 107 + unsigned int tagset[2]; 108 + unsigned int seltags; 109 + unsigned int sellt; 110 + const Layout *lt[2]; 111 char ltsymbol[16]; 112 +} WsState; 113 + 114 +struct Monitor { 115 float mfact; 116 int nmaster; 117 int num; 118 int by; /* bar geometry */ 119 int mx, my, mw, mh; /* screen size */ 120 int wx, wy, ww, wh; /* window area */ 121 - unsigned int seltags; 122 - unsigned int sellt; 123 - unsigned int tagset[2]; 124 + int selws; 125 + WsState *ws; 126 int showbar; 127 int topbar; 128 Client *clients; 129 @@ -129,7 +139,6 @@ struct Monitor { 130 Client *stack; 131 Monitor *next; 132 Window barwin; 133 - const Layout *lt[2]; 134 }; 135 136 typedef struct { 137 @@ -208,7 +217,9 @@ static void sigchld(int unused); 138 static void spawn(const Arg *arg); 139 static void tag(const Arg *arg); 140 static void tagmon(const Arg *arg); 141 +static void tagws(const Arg *arg); 142 static void tile(Monitor *); 143 +static void viewws(const Arg *arg); 144 static void togglebar(const Arg *arg); 145 static void togglefloating(const Arg *arg); 146 static void toggletag(const Arg *arg); 147 @@ -308,7 +319,7 @@ applyrules(Client *c) 148 XFree(ch.res_class); 149 if (ch.res_name) 150 XFree(ch.res_name); 151 - c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; 152 + c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : MTAGSET(c->mon); 153 } 154 155 int 156 @@ -343,7 +354,7 @@ applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) 157 *h = bh; 158 if (*w < bh) 159 *w = bh; 160 - if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { 161 + if (resizehints || c->isfloating || !MWS(c->mon).lt[MWS(c->mon).sellt]->arrange) { 162 /* see last two sentences in ICCCM 4.1.2.3 */ 163 baseismin = c->basew == c->minw && c->baseh == c->minh; 164 if (!baseismin) { /* temporarily remove base dimensions */ 165 @@ -394,9 +405,10 @@ arrange(Monitor *m) 166 void 167 arrangemon(Monitor *m) 168 { 169 - strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); 170 - if (m->lt[m->sellt]->arrange) 171 - m->lt[m->sellt]->arrange(m); 172 + strncpy(MWS(m).ltsymbol, MWS(m).lt[MWS(m).sellt]->symbol, 173 + sizeof MWS(m).ltsymbol); 174 + if (MWS(m).lt[MWS(m).sellt]->arrange) 175 + MWS(m).lt[MWS(m).sellt]->arrange(m); 176 } 177 178 void 179 @@ -432,17 +444,26 @@ buttonpress(XEvent *e) 180 if (ev->window == selmon->barwin) { 181 i = x = 0; 182 do 183 - x += TEXTW(tags[i]); 184 - while (ev->x >= x && ++i < LENGTH(tags)); 185 - if (i < LENGTH(tags)) { 186 - click = ClkTagBar; 187 - arg.ui = 1 << i; 188 - } else if (ev->x < x + blw) 189 - click = ClkLtSymbol; 190 - else if (ev->x > selmon->ww - TEXTW(stext)) 191 - click = ClkStatusText; 192 - else 193 - click = ClkWinTitle; 194 + x += TEXTW(workspaces[i]); 195 + while (ev->x >= x && ++i < LENGTH(workspaces)); 196 + if (i < LENGTH(workspaces)) { 197 + click = ClkWsBar; 198 + arg.i = i; 199 + } else { 200 + i = 0; 201 + do 202 + x += TEXTW(tags[i]); 203 + while (ev->x >= x && ++i < LENGTH(tags)); 204 + if (i < LENGTH(tags)) { 205 + click = ClkTagBar; 206 + arg.ui = 1 << i; 207 + } else if (ev->x < x + blw) 208 + click = ClkLtSymbol; 209 + else if (ev->x > selmon->ww - TEXTW(stext)) 210 + click = ClkStatusText; 211 + else 212 + click = ClkWinTitle; 213 + } 214 } else if ((c = wintoclient(ev->window))) { 215 focus(c); 216 restack(selmon); 217 @@ -452,7 +473,8 @@ buttonpress(XEvent *e) 218 for (i = 0; i < LENGTH(buttons); i++) 219 if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button 220 && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) 221 - buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); 222 + buttons[i].func((click == ClkTagBar || click == ClkWsBar) 223 + && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); 224 } 225 226 void 227 @@ -475,7 +497,7 @@ cleanup(void) 228 size_t i; 229 230 view(&a); 231 - selmon->lt[selmon->sellt] = &foo; 232 + MWS(selmon).lt[MWS(selmon).sellt] = &foo; 233 for (m = mons; m; m = m->next) 234 while (m->stack) 235 unmanage(m->stack, 0); 236 @@ -506,6 +528,7 @@ cleanupmon(Monitor *mon) 237 } 238 XUnmapWindow(dpy, mon->barwin); 239 XDestroyWindow(dpy, mon->barwin); 240 + free(mon->ws); 241 free(mon); 242 } 243 244 @@ -586,7 +609,7 @@ configurerequest(XEvent *e) 245 if ((c = wintoclient(ev->window))) { 246 if (ev->value_mask & CWBorderWidth) 247 c->bw = ev->border_width; 248 - else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) { 249 + else if (c->isfloating || !MWS(selmon).lt[MWS(selmon).sellt]->arrange) { 250 m = c->mon; 251 if (ev->value_mask & CWX) { 252 c->oldx = c->x; 253 @@ -631,16 +654,22 @@ Monitor * 254 createmon(void) 255 { 256 Monitor *m; 257 + unsigned int i; 258 259 m = ecalloc(1, sizeof(Monitor)); 260 - m->tagset[0] = m->tagset[1] = 1; 261 m->mfact = mfact; 262 m->nmaster = nmaster; 263 m->showbar = showbar; 264 m->topbar = topbar; 265 - m->lt[0] = &layouts[0]; 266 - m->lt[1] = &layouts[1 % LENGTH(layouts)]; 267 - strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); 268 + m->selws = 0; 269 + m->ws = ecalloc(LENGTH(workspaces), sizeof(WsState)); 270 + for (i = 0; i < LENGTH(workspaces); i++) { 271 + m->ws[i].tagset[0] = m->ws[i].tagset[1] = 1; 272 + m->ws[i].lt[0] = &layouts[0]; 273 + m->ws[i].lt[1] = &layouts[1 % LENGTH(layouts)]; 274 + strncpy(m->ws[i].ltsymbol, layouts[0].symbol, 275 + sizeof m->ws[i].ltsymbol); 276 + } 277 return m; 278 } 279 280 @@ -709,14 +738,22 @@ drawbar(Monitor *m) 281 } 282 283 for (c = m->clients; c; c = c->next) { 284 - occ |= c->tags; 285 + if (c->ws == m->selws) /* only count occupied tags for current workspace */ 286 + occ |= c->tags; 287 if (c->isurgent) 288 urg |= c->tags; 289 } 290 x = 0; 291 + for (i = 0; i < LENGTH(workspaces); i++) { 292 + w = TEXTW(workspaces[i]); 293 + drw_setscheme(drw, scheme[i == (unsigned int)m->selws 294 + ? SchemeSel : SchemeNorm]); 295 + drw_text(drw, x, 0, w, bh, lrpad / 2, workspaces[i], 0); 296 + x += w; 297 + } 298 for (i = 0; i < LENGTH(tags); i++) { 299 w = TEXTW(tags[i]); 300 - drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); 301 + drw_setscheme(drw, scheme[MWS(m).tagset[MWS(m).seltags] & 1 << i ? SchemeSel : SchemeNorm]); 302 drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); 303 if (occ & 1 << i) 304 drw_rect(drw, x + boxs, boxs, boxw, boxw, 305 @@ -724,9 +761,9 @@ drawbar(Monitor *m) 306 urg & 1 << i); 307 x += w; 308 } 309 - w = blw = TEXTW(m->ltsymbol); 310 + w = blw = TEXTW(MWS(m).ltsymbol); 311 drw_setscheme(drw, scheme[SchemeNorm]); 312 - x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); 313 + x = drw_text(drw, x, 0, w, bh, lrpad / 2, MWS(m).ltsymbol, 0); 314 315 if ((w = m->ww - sw - x) > bh) { 316 if (m->sel) { 317 @@ -1034,9 +1071,11 @@ manage(Window w, XWindowAttributes *wa) 318 if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { 319 c->mon = t->mon; 320 c->tags = t->tags; 321 + c->ws = t->ws; 322 } else { 323 c->mon = selmon; 324 applyrules(c); 325 + c->ws = c->mon->selws; /* set after applyrules, which may change c->mon */ 326 } 327 328 if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw) 329 @@ -1110,7 +1149,7 @@ monocle(Monitor *m) 330 if (ISVISIBLE(c)) 331 n++; 332 if (n > 0) /* override layout symbol */ 333 - snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n); 334 + snprintf(MWS(m).ltsymbol, sizeof MWS(m).ltsymbol, "[%d]", n); 335 for (c = nexttiled(m->clients); c; c = nexttiled(c->next)) 336 resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0); 337 } 338 @@ -1176,10 +1215,10 @@ movemouse(const Arg *arg) 339 ny = selmon->wy; 340 else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap) 341 ny = selmon->wy + selmon->wh - HEIGHT(c); 342 - if (!c->isfloating && selmon->lt[selmon->sellt]->arrange 343 + if (!c->isfloating && MWS(selmon).lt[MWS(selmon).sellt]->arrange 344 && (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) 345 togglefloating(NULL); 346 - if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) 347 + if (!MWS(selmon).lt[MWS(selmon).sellt]->arrange || c->isfloating) 348 resize(c, nx, ny, c->w, c->h, 1); 349 break; 350 } 351 @@ -1325,11 +1364,11 @@ resizemouse(const Arg *arg) 352 if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww 353 && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh) 354 { 355 - if (!c->isfloating && selmon->lt[selmon->sellt]->arrange 356 + if (!c->isfloating && MWS(selmon).lt[MWS(selmon).sellt]->arrange 357 && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) 358 togglefloating(NULL); 359 } 360 - if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) 361 + if (!MWS(selmon).lt[MWS(selmon).sellt]->arrange || c->isfloating) 362 resize(c, c->x, c->y, nw, nh, 1); 363 break; 364 } 365 @@ -1354,9 +1393,9 @@ restack(Monitor *m) 366 drawbar(m); 367 if (!m->sel) 368 return; 369 - if (m->sel->isfloating || !m->lt[m->sellt]->arrange) 370 + if (m->sel->isfloating || !MWS(m).lt[MWS(m).sellt]->arrange) 371 XRaiseWindow(dpy, m->sel->win); 372 - if (m->lt[m->sellt]->arrange) { 373 + if (MWS(m).lt[MWS(m).sellt]->arrange) { 374 wc.stack_mode = Below; 375 wc.sibling = m->barwin; 376 for (c = m->stack; c; c = c->snext) 377 @@ -1416,7 +1455,8 @@ sendmon(Client *c, Monitor *m) 378 detach(c); 379 detachstack(c); 380 c->mon = m; 381 - c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ 382 + c->tags = MTAGSET(m); /* assign tags of target monitor */ 383 + c->ws = m->selws; 384 attach(c); 385 attachstack(c); 386 focus(NULL); 387 @@ -1500,11 +1540,12 @@ setfullscreen(Client *c, int fullscreen) 388 void 389 setlayout(const Arg *arg) 390 { 391 - if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) 392 - selmon->sellt ^= 1; 393 + if (!arg || !arg->v || arg->v != MWS(selmon).lt[MWS(selmon).sellt]) 394 + MWS(selmon).sellt ^= 1; 395 if (arg && arg->v) 396 - selmon->lt[selmon->sellt] = (Layout *)arg->v; 397 - strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); 398 + MWS(selmon).lt[MWS(selmon).sellt] = (Layout *)arg->v; 399 + strncpy(MWS(selmon).ltsymbol, MWS(selmon).lt[MWS(selmon).sellt]->symbol, 400 + sizeof MWS(selmon).ltsymbol); 401 if (selmon->sel) 402 arrange(selmon); 403 else 404 @@ -1517,7 +1558,7 @@ setmfact(const Arg *arg) 405 { 406 float f; 407 408 - if (!arg || !selmon->lt[selmon->sellt]->arrange) 409 + if (!arg || !MWS(selmon).lt[MWS(selmon).sellt]->arrange) 410 return; 411 f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; 412 if (f < 0.1 || f > 0.9) 413 @@ -1618,7 +1659,7 @@ showhide(Client *c) 414 if (ISVISIBLE(c)) { 415 /* show clients top down */ 416 XMoveWindow(dpy, c->win, c->x, c->y); 417 - if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen) 418 + if ((!MWS(c->mon).lt[MWS(c->mon).sellt]->arrange || c->isfloating) && !c->isfullscreen) 419 resize(c, c->x, c->y, c->w, c->h, 0); 420 showhide(c->snext); 421 } else { 422 @@ -1670,6 +1711,38 @@ tagmon(const Arg *arg) 423 sendmon(selmon->sel, dirtomon(arg->i)); 424 } 425 426 +/* Move the focused client to the workspace given by arg->i */ 427 +void 428 +tagws(const Arg *arg) 429 +{ 430 + if (!selmon->sel) 431 + return; 432 + if (arg->i < 0 || arg->i >= (int)LENGTH(workspaces)) 433 + return; 434 + selmon->sel->ws = arg->i; 435 + focus(NULL); 436 + arrange(selmon); 437 +} 438 + 439 +/* Switch the active workspace on selmon to arg->i */ 440 +void 441 +viewws(const Arg *arg) 442 +{ 443 + if (arg->i < 0 || arg->i >= (int)LENGTH(workspaces)) 444 + return; 445 + if (arg->i == selmon->selws) 446 + return; 447 + 448 + /* carry tag selection so the viewed tag does not change */ 449 + selmon->ws[arg->i].tagset[0] = MWS(selmon).tagset[0]; 450 + selmon->ws[arg->i].tagset[1] = MWS(selmon).tagset[1]; 451 + selmon->ws[arg->i].seltags = MWS(selmon).seltags; 452 + 453 + selmon->selws = arg->i; 454 + focus(NULL); 455 + arrange(selmon); 456 +} 457 + 458 void 459 tile(Monitor *m) 460 { 461 @@ -1737,10 +1810,10 @@ toggletag(const Arg *arg) 462 void 463 toggleview(const Arg *arg) 464 { 465 - unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); 466 + unsigned int newtagset = MTAGSET(selmon) ^ (arg->ui & TAGMASK); 467 468 if (newtagset) { 469 - selmon->tagset[selmon->seltags] = newtagset; 470 + MWS(selmon).tagset[MWS(selmon).seltags] = newtagset; 471 focus(NULL); 472 arrange(selmon); 473 } 474 @@ -2035,11 +2108,11 @@ updatewmhints(Client *c) 475 void 476 view(const Arg *arg) 477 { 478 - if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) 479 + if ((arg->ui & TAGMASK) == MTAGSET(selmon)) 480 return; 481 - selmon->seltags ^= 1; /* toggle sel tagset */ 482 + MWS(selmon).seltags ^= 1; /* toggle sel tagset */ 483 if (arg->ui & TAGMASK) 484 - selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; 485 + MWS(selmon).tagset[MWS(selmon).seltags] = arg->ui & TAGMASK; 486 focus(NULL); 487 arrange(selmon); 488 } 489 @@ -2115,7 +2188,7 @@ zoom(const Arg *arg) 490 { 491 Client *c = selmon->sel; 492 493 - if (!selmon->lt[selmon->sellt]->arrange 494 + if (!MWS(selmon).lt[MWS(selmon).sellt]->arrange 495 || (selmon->sel && selmon->sel->isfloating)) 496 return; 497 if (c == nexttiled(selmon->clients)) 498 -- 499 2.53.0 500