JWM Source Documentation
place.c
Go to the documentation of this file.
1 
10 #include "jwm.h"
11 #include "place.h"
12 #include "client.h"
13 #include "border.h"
14 #include "screen.h"
15 #include "tray.h"
16 #include "settings.h"
17 #include "clientlist.h"
18 #include "misc.h"
19 
20 typedef struct Strut {
23  struct Strut *next;
24 } Strut;
25 
26 static Strut *struts = NULL;
27 
28 /* desktopCount x screenCount */
29 /* Note that we assume x and y are 0 based for all screens here. */
30 static int *cascadeOffsets = NULL;
31 
32 static char DoRemoveClientStrut(ClientNode *np);
33 static void InsertStrut(const BoundingBox *box, ClientNode *np);
34 static void CenterClient(const BoundingBox *box, ClientNode *np);
35 static int IntComparator(const void *a, const void *b);
36 static int TryTileClient(const BoundingBox *box, ClientNode *np,
37  int x, int y);
38 static char TileClient(const BoundingBox *box, ClientNode *np);
39 static void CascadeClient(const BoundingBox *box, ClientNode *np);
40 
41 static void SubtractStrutBounds(BoundingBox *box, const ClientNode *np);
42 static void SubtractBounds(const BoundingBox *src, BoundingBox *dest);
43 static void SubtractTrayBounds(BoundingBox *box, unsigned int layer);
44 static void SetWorkarea(void);
45 
47 void StartupPlacement(void)
48 {
49  const unsigned titleHeight = GetTitleHeight();
50  int count;
51  int x;
52 
54  cascadeOffsets = Allocate(count * sizeof(int));
55 
56  for(x = 0; x < count; x++) {
57  cascadeOffsets[x] = settings.borderWidth + titleHeight;
58  }
59 
60  SetWorkarea();
61 }
62 
65 {
66 
67  Strut *sp;
68 
70 
71  while(struts) {
72  sp = struts->next;
73  Release(struts);
74  struts = sp;
75  }
76 
77 }
78 
81 {
82  if(DoRemoveClientStrut(np)) {
83  SetWorkarea();
84  }
85 }
86 
89 {
90  char updated = 0;
91  Strut **spp = &struts;
92  while(*spp) {
93  Strut *sp = *spp;
94  if(sp->client == np) {
95  *spp = sp->next;
96  Release(sp);
97  updated = 1;
98  } else {
99  spp = &sp->next;
100  }
101  }
102  return updated;
103 }
104 
105 
108 {
109  if(JLIKELY(box->width > 0 && box->height > 0)) {
110  Strut *sp = Allocate(sizeof(Strut));
111  sp->client = np;
112  sp->box = *box;
113  sp->next = struts;
114  struts = sp;
115  }
116 }
117 
120 {
121 
123  int status;
124  Atom actualType;
125  int actualFormat;
126  unsigned long count;
127  unsigned long bytesLeft;
128  unsigned char *value;
129  long *lvalue;
130  long leftWidth, rightWidth, topHeight, bottomHeight;
131  char updated;
132 
133  updated = DoRemoveClientStrut(np);
134 
135  box.x = 0;
136  box.y = 0;
137  box.width = 0;
138  box.height = 0;
139 
140  /* First try to read _NET_WM_STRUT_PARTIAL */
141  /* Format is:
142  * left_width, right_width, top_width, bottom_width,
143  * left_start_y, left_end_y, right_start_y, right_end_y,
144  * top_start_x, top_end_x, bottom_start_x, bottom_end_x
145  */
146  count = 0;
147  status = JXGetWindowProperty(display, np->window,
149  0, 12, False, XA_CARDINAL, &actualType,
150  &actualFormat, &count, &bytesLeft, &value);
151  if(status == Success && actualFormat != 0) {
152  if(JLIKELY(count == 12)) {
153 
154  long leftStart, leftStop;
155  long rightStart, rightStop;
156  long topStart, topStop;
157  long bottomStart, bottomStop;
158 
159  lvalue = (long*)value;
160  leftWidth = lvalue[0];
161  rightWidth = lvalue[1];
162  topHeight = lvalue[2];
163  bottomHeight = lvalue[3];
164  leftStart = lvalue[4];
165  leftStop = lvalue[5];
166  rightStart = lvalue[6];
167  rightStop = lvalue[7];
168  topStart = lvalue[8];
169  topStop = lvalue[9];
170  bottomStart = lvalue[10];
171  bottomStop = lvalue[11];
172 
173  if(leftWidth > 0) {
174  box.x = 0;
175  box.y = leftStart;
176  box.height = leftStop - leftStart;
177  box.width = leftWidth;
178  InsertStrut(&box, np);
179  }
180 
181  if(rightWidth > 0) {
182  box.x = rootWidth - rightWidth;
183  box.y = rightStart;
184  box.height = rightStop - rightStart;
185  box.width = rightWidth;
186  InsertStrut(&box, np);
187  }
188 
189  if(topHeight > 0) {
190  box.x = topStart;
191  box.y = 0;
192  box.height = topHeight;
193  box.width = topStop - topStart;
194  InsertStrut(&box, np);
195  }
196 
197  if(bottomHeight > 0) {
198  box.x = bottomStart;
199  box.y = rootHeight - bottomHeight;
200  box.width = bottomStop - bottomStart;
201  box.height = bottomHeight;
202  InsertStrut(&box, np);
203  }
204 
205  }
206  JXFree(value);
207  SetWorkarea();
208  return;
209  }
210 
211  /* Next try to read _NET_WM_STRUT */
212  /* Format is: left_width, right_width, top_width, bottom_width */
213  count = 0;
215  0, 4, False, XA_CARDINAL, &actualType,
216  &actualFormat, &count, &bytesLeft, &value);
217  if(status == Success && actualFormat != 0) {
218  if(JLIKELY(count == 4)) {
219  lvalue = (long*)value;
220  leftWidth = lvalue[0];
221  rightWidth = lvalue[1];
222  topHeight = lvalue[2];
223  bottomHeight = lvalue[3];
224 
225  if(leftWidth > 0) {
226  box.x = 0;
227  box.y = 0;
228  box.width = leftWidth;
229  box.height = rootHeight;
230  InsertStrut(&box, np);
231  }
232 
233  if(rightWidth > 0) {
234  box.x = rootWidth - rightWidth;
235  box.y = 0;
236  box.width = rightWidth;
237  box.height = rootHeight;
238  InsertStrut(&box, np);
239  }
240 
241  if(topHeight > 0) {
242  box.x = 0;
243  box.y = 0;
244  box.width = rootWidth;
245  box.height = topHeight;
246  InsertStrut(&box, np);
247  }
248 
249  if(bottomHeight > 0) {
250  box.x = 0;
251  box.y = rootHeight - bottomHeight;
252  box.width = rootWidth;
253  box.height = bottomHeight;
254  InsertStrut(&box, np);
255  }
256 
257  }
258  JXFree(value);
259  SetWorkarea();
260  return;
261  }
262 
263  /* Struts were removed. */
264  if(updated) {
265  SetWorkarea();
266  }
267 
268 }
269 
272 {
273  box->x = sp->x;
274  box->y = sp->y;
275  box->width = sp->width;
276  box->height = sp->height;
277 }
278 
281 {
282 
283  BoundingBox boxes[4];
284 
285  if(src->x + src->width <= dest->x) {
286  return;
287  }
288  if(src->y + src->height <= dest->y) {
289  return;
290  }
291  if(dest->x + dest->width <= src->x) {
292  return;
293  }
294  if(dest->y + dest->height <= src->y) {
295  return;
296  }
297 
298  /* There are four ways to do this:
299  * 0. Increase the x-coordinate and decrease the width of dest.
300  * 1. Increase the y-coordinate and decrease the height of dest.
301  * 2. Decrease the width of dest.
302  * 3. Decrease the height of dest.
303  * We will chose the option which leaves the greatest area.
304  * Note that negative areas are possible.
305  */
306 
307  /* 0 */
308  boxes[0] = *dest;
309  boxes[0].x = src->x + src->width;
310  boxes[0].width = dest->x + dest->width - boxes[0].x;
311 
312  /* 1 */
313  boxes[1] = *dest;
314  boxes[1].y = src->y + src->height;
315  boxes[1].height = dest->y + dest->height - boxes[1].y;
316 
317  /* 2 */
318  boxes[2] = *dest;
319  boxes[2].width = src->x - dest->x;
320 
321  /* 3 */
322  boxes[3] = *dest;
323  boxes[3].height = src->y - dest->y;
324 
325  /* 0 and 1, winner in 0. */
326  if(boxes[0].width * boxes[0].height < boxes[1].width * boxes[1].height) {
327  boxes[0] = boxes[1];
328  }
329 
330  /* 2 and 3, winner in 2. */
331  if(boxes[2].width * boxes[2].height < boxes[3].width * boxes[3].height) {
332  boxes[2] = boxes[3];
333  }
334 
335  /* 0 and 2, winner in dest. */
336  if(boxes[0].width * boxes[0].height < boxes[2].width * boxes[2].height) {
337  *dest = boxes[2];
338  } else {
339  *dest = boxes[0];
340  }
341 
342 }
343 
345 void SubtractTrayBounds(BoundingBox *box, unsigned int layer)
346 {
347  const TrayType *tp;
349  BoundingBox last;
350  for(tp = GetTrays(); tp; tp = tp->next) {
351 
352  if(tp->layer > layer && tp->autoHide == THIDE_OFF) {
353 
354  src.x = tp->x;
355  src.y = tp->y;
356  src.width = tp->width;
357  src.height = tp->height;
358  if(src.x < 0) {
359  src.width += src.x;
360  src.x = 0;
361  }
362  if(src.y < 0) {
363  src.height += src.y;
364  src.y = 0;
365  }
366 
367  last = *box;
368  SubtractBounds(&src, box);
369  if(box->width * box->height <= 0) {
370  *box = last;
371  break;
372  }
373 
374  }
375 
376  }
377 }
378 
381 {
382 
383  Strut *sp;
384  BoundingBox last;
385 
386  for(sp = struts; sp; sp = sp->next) {
387  if(np != NULL && sp->client == np) {
388  continue;
389  }
391  last = *box;
392  SubtractBounds(&sp->box, box);
393  if(box->width * box->height <= 0) {
394  *box = last;
395  break;
396  }
397  }
398  }
399 
400 }
401 
404 {
405  np->x = box->x + (box->width / 2) - (np->width / 2);
406  np->y = box->y + (box->height / 2) - (np->height / 2);
407  ConstrainSize(np);
408  ConstrainPosition(np);
409 }
410 
412 int IntComparator(const void *a, const void *b)
413 {
414  const int ia = *(const int*)a;
415  const int ib = *(const int*)b;
416  return ia - ib;
417 }
418 
420 int TryTileClient(const BoundingBox *box, ClientNode *np, int x, int y)
421 {
422  const ClientNode *tp;
423  int layer;
424  int north, south, east, west;
425  int x1, x2, y1, y2;
426  int ox1, ox2, oy1, oy2;
427  int overlap;
428 
429  /* Set the client position. */
430  GetBorderSize(&np->state, &north, &south, &east, &west);
431  np->x = x + west;
432  np->y = y + north;
433  ConstrainSize(np);
434  ConstrainPosition(np);
435 
436  /* Get the client boundaries. */
437  x1 = np->x - west;
438  x2 = np->x + np->width + east;
439  y1 = np->y - north;
440  y2 = np->y + np->height + south;
441 
442  overlap = 0;
443 
444  /* Return maximum cost for window outside bounding box. */
445  if ( x1 < box->x ||
446  x2 > box->x + box->width ||
447  y1 < box->y ||
448  y2 > box->y + box->height) {
449  return INT_MAX;
450  }
451 
452  /* Loop over each client. */
453  for(layer = np->state.layer; layer < LAYER_COUNT; layer++) {
454  for(tp = nodes[layer]; tp; tp = tp->next) {
455 
456  /* Skip clients that aren't visible. */
457  if(!IsClientOnCurrentDesktop(tp)) {
458  continue;
459  }
460  if(!(tp->state.status & STAT_MAPPED)) {
461  continue;
462  }
463  if(tp == np) {
464  continue;
465  }
466 
467  /* Get the boundaries of the other client. */
468  GetBorderSize(&tp->state, &north, &south, &east, &west);
469  ox1 = tp->x - west;
470  ox2 = tp->x + tp->width + east;
471  oy1 = tp->y - north;
472  oy2 = tp->y + tp->height + south;
473 
474  /* Check for an overlap. */
475  if(x2 <= ox1 || x1 >= ox2) {
476  continue;
477  }
478  if(y2 <= oy1 || y1 >= oy2) {
479  continue;
480  }
481  overlap += (Min(ox2, x2) - Max(ox1, x1))
482  * (Min(oy2, y2) - Max(oy1, y1));
483  }
484  }
485 
486  return overlap;
487 }
488 
491 {
492 
493  const ClientNode *tp;
494  int layer;
495  int north, south, east, west;
496  int i, j;
497  int count;
498  int *xs;
499  int *ys;
500  int leastOverlap;
501  int bestx, besty;
502 
503  /* Count insertion points, including bounding box edges. */
504  count = 2;
505  for(layer = np->state.layer; layer < LAYER_COUNT; layer++) {
506  for(tp = nodes[layer]; tp; tp = tp->next) {
507  if(!IsClientOnCurrentDesktop(tp)) {
508  continue;
509  }
510  if(!(tp->state.status & STAT_MAPPED)) {
511  continue;
512  }
513  if(tp == np) {
514  continue;
515  }
516  count += 2;
517  }
518  }
519 
520  /* Allocate space for the points. */
521  xs = AllocateStack(sizeof(int) * count);
522  ys = AllocateStack(sizeof(int) * count);
523 
524  /* Insert points. */
525  xs[0] = box->x;
526  ys[0] = box->y;
527  count = 1;
528  for(layer = np->state.layer; layer < LAYER_COUNT; layer++) {
529  for(tp = nodes[layer]; tp; tp = tp->next) {
530  if(!IsClientOnCurrentDesktop(tp)) {
531  continue;
532  }
533  if(!(tp->state.status & STAT_MAPPED)) {
534  continue;
535  }
536  if(tp == np) {
537  continue;
538  }
539  GetBorderSize(&tp->state, &north, &south, &east, &west);
540  xs[count + 0] = tp->x - west;
541  xs[count + 1] = tp->x + tp->width + east;
542  ys[count + 0] = tp->y - north;
543  ys[count + 1] = tp->y + tp->height + south;
544  count += 2;
545  }
546  }
547 
548  /* Try placing at lower right edge of box, too. */
549  GetBorderSize(&np->state, &north, &south, &east, &west);
550  xs[count] = box->x + box->width - np->width - east - west;
551  ys[count] = box->y + box->height - np->height - north - south;
552  count += 1;
553 
554  /* Sort the points. */
555  qsort(xs, count, sizeof(int), IntComparator);
556  qsort(ys, count, sizeof(int), IntComparator);
557 
558  /* Try all possible positions. */
559  leastOverlap = INT_MAX;
560  bestx = xs[0];
561  besty = ys[0];
562  for(i = 0; i < count; i++) {
563  for(j = 0; j < count; j++) {
564  const int overlap = TryTileClient(box, np, xs[i], ys[j]);
565  if(overlap < leastOverlap) {
566  leastOverlap = overlap;
567  bestx = xs[i];
568  besty = ys[j];
569  if(overlap == 0) {
570  break;
571  }
572  }
573  }
574  }
575 
576  ReleaseStack(xs);
577  ReleaseStack(ys);
578 
579  if(leastOverlap < INT_MAX) {
580  /* Set the client position. */
581  GetBorderSize(&np->state, &north, &south, &east, &west);
582  np->x = bestx + west;
583  np->y = besty + north;
584  ConstrainSize(np);
585  ConstrainPosition(np);
586  return 1;
587  } else {
588  /* Tiled placement failed. */
589  return 0;
590  }
591 }
592 
595 {
596  const ScreenType *sp;
597  const unsigned titleHeight = GetTitleHeight();
598  int north, south, east, west;
599  int cascadeIndex;
600  char overflow;
601 
602  GetBorderSize(&np->state, &north, &south, &east, &west);
603  sp = GetMouseScreen();
604  cascadeIndex = sp->index * settings.desktopCount + currentDesktop;
605 
606  /* Set the cascaded location. */
607  np->x = box->x + west + cascadeOffsets[cascadeIndex];
608  np->y = box->y + north + cascadeOffsets[cascadeIndex];
609  cascadeOffsets[cascadeIndex] += settings.borderWidth + titleHeight;
610 
611  /* Check for cascade overflow. */
612  overflow = 0;
613  if(np->x + np->width - box->x > box->width) {
614  overflow = 1;
615  } else if(np->y + np->height - box->y > box->height) {
616  overflow = 1;
617  }
618 
619  if(overflow) {
620  cascadeOffsets[cascadeIndex] = settings.borderWidth + titleHeight;
621  np->x = box->x + west + cascadeOffsets[cascadeIndex];
622  np->y = box->y + north + cascadeOffsets[cascadeIndex];
623 
624  /* Check for client overflow and update cascade position. */
625  if(np->x + np->width - box->x > box->width) {
626  np->x = box->x + west;
627  } else if(np->y + np->height - box->y > box->height) {
628  np->y = box->y + north;
629  } else {
630  cascadeOffsets[cascadeIndex] += settings.borderWidth + titleHeight;
631  }
632  }
633 
634  ConstrainSize(np);
635  ConstrainPosition(np);
636 
637 }
638 
640 void PlaceClient(ClientNode *np, char alreadyMapped)
641 {
642 
644  const ScreenType *sp;
645 
646  Assert(np);
647 
648  if(alreadyMapped || (!(np->state.status & STAT_PIGNORE)
649  && (np->sizeFlags & (PPosition | USPosition)))) {
650 
651  GravitateClient(np, 0);
652  if(!alreadyMapped) {
653  ConstrainSize(np);
654  ConstrainPosition(np);
655  }
656 
657  } else {
658 
659  sp = GetMouseScreen();
660  GetScreenBounds(sp, &box);
661  SubtractTrayBounds(&box, np->state.layer);
662  SubtractStrutBounds(&box, np);
663 
664  /* If tiled is specified, first attempt to use tiled placement. */
665  if(np->state.status & STAT_TILED) {
666  if(TileClient(&box, np)) {
667  return;
668  }
669  }
670 
671  /* Either tiled placement failed or was not specified. */
672  if(np->state.status & STAT_CENTERED) {
673  CenterClient(&box, np);
674  } else {
675  CascadeClient(&box, np);
676  }
677 
678  }
679 
680 }
681 
684 {
685 
687  const ScreenType *sp;
688  int north, south, east, west;
689  const int oldWidth = np->width;
690  const int oldHeight = np->height;
691 
692  /* First we make sure the window isn't larger than the program allows.
693  * We do this here to avoid moving the window below.
694  */
695  np->width = Min(np->width, np->maxWidth);
696  np->height = Min(np->height, np->maxHeight);
697 
698  /* Constrain the width if necessary. */
699  sp = GetCurrentScreen(np->x, np->y);
700  GetScreenBounds(sp, &box);
701  SubtractTrayBounds(&box, np->state.layer);
702  SubtractStrutBounds(&box, np);
703  GetBorderSize(&np->state, &north, &south, &east, &west);
704  if(np->width + east + west > sp->width) {
705  box.x += west;
706  box.width -= east + west;
707  if(box.width > np->maxWidth) {
708  box.width = np->maxWidth;
709  }
710  if(box.width > np->width) {
711  box.width = np->width;
712  }
713  np->x = box.x;
714  np->width = box.width - (box.width % np->xinc);
715  }
716 
717  /* Constrain the height if necessary. */
718  if(np->height + north + south > sp->height) {
719  box.y += north;
720  box.height -= north + south;
721  if(box.height > np->maxHeight) {
722  box.height = np->maxHeight;
723  }
724  if(box.height > np->height) {
725  box.height = np->height;
726  }
727  np->y = box.y;
728  np->height = box.height - (box.height % np->yinc);
729  }
730 
731  /* If the program has a minimum constraint, we apply that here.
732  * Note that this could cause the window to overlap something. */
733  np->width = Max(np->width, np->minWidth);
734  np->height = Max(np->height, np->minHeight);
735 
736  /* Fix the aspect ratio. */
737  if(np->sizeFlags & PAspect) {
738  if(np->width * np->aspect.miny < np->height * np->aspect.minx) {
739  np->height = (np->width * np->aspect.miny) / np->aspect.minx;
740  }
741  if(np->width * np->aspect.maxy > np->height * np->aspect.maxx) {
742  np->width = (np->height * np->aspect.maxx) / np->aspect.maxy;
743  }
744  }
745 
746  if(np->width != oldWidth || np->height != oldHeight) {
747  return 1;
748  } else {
749  return 0;
750  }
751 
752 }
753 
756 {
757 
759  int north, south, east, west;
760 
761  /* Get the bounds for placement. */
762  box.x = 0;
763  box.y = 0;
764  box.width = rootWidth;
765  box.height = rootHeight;
766  SubtractTrayBounds(&box, np->state.layer);
767  SubtractStrutBounds(&box, np);
768 
769  /* Fix the position. */
770  GetBorderSize(&np->state, &north, &south, &east, &west);
771  if(np->x + np->width + east + west > box.x + box.width) {
772  np->x = box.x + box.width - np->width - east;
773  }
774  if(np->y + np->height + north + south > box.y + box.height) {
775  np->y = box.y + box.height - np->height - south;
776  }
777  if(np->x < box.x + west) {
778  np->x = box.x + west;
779  }
780  if(np->y < box.y + north) {
781  np->y = box.y + north;
782  }
783 
784 }
785 
788 {
790  const ScreenType *sp;
791  int north, south, east, west;
792 
793  np->oldx = np->x;
794  np->oldy = np->y;
795  np->oldWidth = np->width;
796  np->oldHeight = np->height;
797  np->state.maxFlags = flags;
798 
799  GetBorderSize(&np->state, &north, &south, &east, &west);
800 
801  sp = GetCurrentScreen(np->x + (east + west + np->width) / 2,
802  np->y + (north + south + np->height) / 2);
803  GetScreenBounds(sp, &box);
804  if(!(flags & (MAX_HORIZ | MAX_LEFT | MAX_RIGHT))) {
805  box.x = np->x - west;
806  box.width = np->width + east + west;
807  }
808  if(!(flags & (MAX_VERT | MAX_TOP | MAX_BOTTOM))) {
809  box.y = np->y - north;
810  box.height = np->height + north + south;
811  }
812  SubtractTrayBounds(&box, np->state.layer);
813  SubtractStrutBounds(&box, np);
814 
815  if(box.width > np->maxWidth) {
816  box.width = np->maxWidth;
817  }
818  if(box.height > np->maxHeight) {
819  box.height = np->maxHeight;
820  }
821 
822  if(np->sizeFlags & PAspect) {
823  if(box.width * np->aspect.miny < box.height * np->aspect.minx) {
824  box.height = (box.width * np->aspect.miny) / np->aspect.minx;
825  }
826  if(box.width * np->aspect.maxy > box.height * np->aspect.maxx) {
827  box.width = (box.height * np->aspect.maxx) / np->aspect.maxy;
828  }
829  }
830 
831  /* If maximizing horizontally, update width. */
832  if(flags & MAX_HORIZ) {
833  np->x = box.x;
834  np->width = box.width;
835  if(!(np->state.status & STAT_IIGNORE)) {
836  np->width -= ((np->width - np->baseWidth) % np->xinc);
837  }
838  } else if(flags & MAX_LEFT) {
839  np->x = box.x;
840  np->width = box.width / 2 - west;
841  if(!(np->state.status & STAT_IIGNORE)) {
842  np->width -= ((np->width - np->baseWidth) % np->xinc);
843  }
844  } else if(flags & MAX_RIGHT) {
845  np->x = box.x + box.width / 2 + west;
846  np->width = box.width / 2 - east;
847  if(!(np->state.status & STAT_IIGNORE)) {
848  np->width -= ((np->width - np->baseWidth) % np->xinc);
849  }
850  }
851 
852  /* If maximizing vertically, update height. */
853  if(flags & MAX_VERT) {
854  np->y = box.y + north;
855  np->height = box.height - north;
856  if(!(np->state.status & STAT_IIGNORE)) {
857  np->height -= ((np->height - np->baseHeight) % np->yinc);
858  }
859  } else if(flags & MAX_TOP) {
860  np->y = box.y + north;
861  np->height = box.height / 2 - north - south;
862  if(!(np->state.status & STAT_IIGNORE)) {
863  np->height -= ((np->height - np->baseHeight) % np->yinc);
864  }
865  } else if(flags & MAX_BOTTOM) {
866  np->y = box.y + box.height / 2 + north;
867  np->height = box.height / 2 - north - south;
868  if(!(np->state.status & STAT_IIGNORE)) {
869  np->height -= ((np->height - np->baseHeight) % np->yinc);
870  }
871  }
872 
873 }
874 
876 void GetGravityDelta(const ClientNode *np, int gravity, int *x, int *y)
877 {
878  int north, south, east, west;
879  GetBorderSize(&np->state, &north, &south, &east, &west);
880  switch(gravity) {
881  case NorthWestGravity:
882  *y = -north;
883  *x = -west;
884  break;
885  case NorthGravity:
886  *y = -north;
887  *x = (west - east) / 2;
888  break;
889  case NorthEastGravity:
890  *y = -north;
891  *x = west;
892  break;
893  case WestGravity:
894  *x = -west;
895  *y = (north - south) / 2;
896  break;
897  case CenterGravity:
898  *y = (north - south) / 2;
899  *x = (west - east) / 2;
900  break;
901  case EastGravity:
902  *x = west;
903  *y = (north - south) / 2;
904  break;
905  case SouthWestGravity:
906  *y = south;
907  *x = -west;
908  break;
909  case SouthGravity:
910  *x = (west - east) / 2;
911  *y = south;
912  break;
913  case SouthEastGravity:
914  *y = south;
915  *x = west;
916  break;
917  default: /* Static */
918  *x = 0;
919  *y = 0;
920  break;
921  }
922 }
923 
925 void GravitateClient(ClientNode *np, char negate)
926 {
927  int deltax, deltay;
928  GetGravityDelta(np, np->gravity, &deltax, &deltay);
929  if(negate) {
930  np->x += deltax;
931  np->y += deltay;
932  } else {
933  np->x -= deltax;
934  np->y -= deltay;
935  }
936 }
937 
939 void SetWorkarea(void)
940 {
942  unsigned long *array;
943  unsigned int count;
944  int x;
945 
946  count = 4 * settings.desktopCount * sizeof(unsigned long);
947  array = (unsigned long*)AllocateStack(count);
948 
949  box.x = 0;
950  box.y = 0;
951  box.width = rootWidth;
952  box.height = rootHeight;
953 
955  SubtractStrutBounds(&box, NULL);
956 
957  for(x = 0; x < settings.desktopCount; x++) {
958  array[x * 4 + 0] = box.x;
959  array[x * 4 + 1] = box.y;
960  array[x * 4 + 2] = box.width;
961  array[x * 4 + 3] = box.height;
962  }
964  XA_CARDINAL, 32, PropModeReplace,
965  (unsigned char*)array, settings.desktopCount * 4);
966 
967  ReleaseStack(array);
968 }

joewing.net / Projects / JWM