JWM Source Documentation
tray.c
Go to the documentation of this file.
1 
10 #include "jwm.h"
11 #include "tray.h"
12 #include "color.h"
13 #include "main.h"
14 #include "pager.h"
15 #include "cursor.h"
16 #include "error.h"
17 #include "taskbar.h"
18 #include "menu.h"
19 #include "timing.h"
20 #include "screen.h"
21 #include "settings.h"
22 #include "event.h"
23 #include "client.h"
24 #include "misc.h"
25 #include "hint.h"
26 
27 #define DEFAULT_TRAY_WIDTH 32
28 #define DEFAULT_TRAY_HEIGHT 32
29 
30 #define TRAY_BORDER_SIZE 1
31 
32 static TrayType *trays;
33 static unsigned int trayCount;
34 
35 static void HandleTrayExpose(TrayType *tp, const XExposeEvent *event);
36 static void HandleTrayEnterNotify(TrayType *tp, const XCrossingEvent *event);
37 
38 static TrayComponentType *GetTrayComponent(TrayType *tp, int x, int y);
39 static void HandleTrayButtonPress(TrayType *tp, const XButtonEvent *event);
40 static void HandleTrayButtonRelease(TrayType *tp, const XButtonEvent *event);
41 static void HandleTrayMotionNotify(TrayType *tp, const XMotionEvent *event);
42 
43 static void ComputeTraySize(TrayType *tp);
44 static int ComputeMaxWidth(TrayType *tp);
45 static int ComputeTotalWidth(TrayType *tp);
46 static int ComputeMaxHeight(TrayType *tp);
47 static int ComputeTotalHeight(TrayType *tp);
48 static char CheckHorizontalFill(TrayType *tp);
49 static char CheckVerticalFill(TrayType *tp);
50 static void LayoutTray(TrayType *tp, int *variableSize,
51  int *variableRemainder);
52 
53 static void SignalTray(const TimeType *now, int x, int y, Window w,
54  void *data);
55 
56 
58 void InitializeTray(void)
59 {
60  trays = NULL;
61  trayCount = 0;
62 }
63 
65 void StartupTray(void)
66 {
67  XSetWindowAttributes attr;
68  unsigned long attrMask;
69  TrayType *tp;
71  int variableSize;
72  int variableRemainder;
73  int width, height;
74  int xoffset, yoffset;
75 
76  for(tp = trays; tp; tp = tp->next) {
77 
78  LayoutTray(tp, &variableSize, &variableRemainder);
79 
80  /* Create the tray window. */
81  /* The window is created larger for a border. */
82  attrMask = CWOverrideRedirect;
83  attr.override_redirect = True;
84 
85  /* We can't use PointerMotionHintMask since the exact position
86  * of the mouse on the tray is important for popups. */
87  attrMask |= CWEventMask;
88  attr.event_mask
89  = ButtonPressMask
90  | ButtonReleaseMask
91  | SubstructureNotifyMask
92  | ExposureMask
93  | KeyPressMask
94  | KeyReleaseMask
95  | EnterWindowMask
96  | PointerMotionMask;
97 
98  attrMask |= CWBackPixel;
99  attr.background_pixel = colors[COLOR_TRAY_BG2];
100 
101  Assert(tp->width > 0);
102  Assert(tp->height > 0);
104  tp->x, tp->y, tp->width, tp->height, 0,
105  rootDepth, InputOutput,
106  rootVisual, attrMask, &attr);
109 
110  if(settings.trayOpacity < UINT_MAX) {
113  }
114 
116 
117  /* Create and layout items on the tray. */
118  xoffset = TRAY_BORDER_SIZE;
119  yoffset = TRAY_BORDER_SIZE;
120  for(cp = tp->components; cp; cp = cp->next) {
121 
122  if(cp->Create) {
123  if(tp->layout == LAYOUT_HORIZONTAL) {
124  height = tp->height - TRAY_BORDER_SIZE * 2;
125  width = cp->width;
126  if(width == 0) {
127  width = variableSize;
128  if(variableRemainder) {
129  width += 1;
130  variableRemainder -= 1;
131  }
132  }
133  } else {
134  width = tp->width - TRAY_BORDER_SIZE * 2;
135  height = cp->height;
136  if(height == 0) {
137  height = variableSize;
138  if(variableRemainder) {
139  height += 1;
140  variableRemainder -= 1;
141  }
142  }
143  }
144  cp->width = Max(1, width);
145  cp->height = Max(1, height);
146  (cp->Create)(cp);
147  }
148 
149  cp->x = xoffset;
150  cp->y = yoffset;
151  cp->screenx = tp->x + xoffset;
152  cp->screeny = tp->y + yoffset;
153 
154  if(cp->window != None) {
156  xoffset, yoffset);
157  }
158 
159  if(tp->layout == LAYOUT_HORIZONTAL) {
160  xoffset += cp->width;
161  } else {
162  yoffset += cp->height;
163  }
164  }
165 
166  /* Show the tray. */
167  JXMapWindow(display, tp->window);
168 
169  trayCount += 1;
170 
171  }
172 
175 }
176 
178 void ShutdownTray(void)
179 {
180  TrayType *tp;
181  TrayComponentType *cp;
182 
183  for(tp = trays; tp; tp = tp->next) {
184  for(cp = tp->components; cp; cp = cp->next) {
185  if(cp->Destroy) {
186  (cp->Destroy)(cp);
187  }
188  }
190  }
191 }
192 
194 void DestroyTray(void)
195 {
196  TrayType *tp;
197  TrayComponentType *cp;
198 
199  while(trays) {
200  tp = trays->next;
202  while(trays->components) {
203  cp = trays->components->next;
204  Release(trays->components);
205  trays->components = cp;
206  }
207  Release(trays);
208 
209  trays = tp;
210  }
211 }
212 
215 {
216  TrayType *tp;
217 
218  tp = Allocate(sizeof(TrayType));
219 
220  tp->requestedX = 0;
221  tp->requestedY = -1;
222  tp->x = 0;
223  tp->y = -1;
224  tp->requestedWidth = 0;
225  tp->requestedHeight = 0;
226  tp->width = 0;
227  tp->height = 0;
230  tp->valign = TALIGN_FIXED;
231  tp->halign = TALIGN_FIXED;
232 
233  tp->autoHide = THIDE_OFF;
234  tp->hidden = 0;
235 
236  tp->window = None;
237 
238  tp->components = NULL;
239  tp->componentsTail = NULL;
240 
241  tp->next = trays;
242  trays = tp;
243 
244  RegisterCallback(100, SignalTray, tp);
245 
246  return tp;
247 }
248 
251 {
252  TrayComponentType *cp;
253 
254  cp = Allocate(sizeof(TrayComponentType));
255 
256  cp->tray = NULL;
257  cp->object = NULL;
258 
259  cp->x = 0;
260  cp->y = 0;
261  cp->requestedWidth = 0;
262  cp->requestedHeight = 0;
263  cp->width = 0;
264  cp->height = 0;
265  cp->grabbed = 0;
266 
267  cp->window = None;
268  cp->pixmap = None;
269 
270  cp->Create = NULL;
271  cp->Destroy = NULL;
272 
273  cp->SetSize = NULL;
274  cp->Resize = NULL;
275 
276  cp->ProcessButtonPress = NULL;
277  cp->ProcessButtonRelease = NULL;
278  cp->ProcessMotionEvent = NULL;
279  cp->Redraw = NULL;
280 
281  cp->next = NULL;
282 
283  return cp;
284 }
285 
288 {
289  cp->tray = tp;
290  if(tp->componentsTail) {
291  tp->componentsTail->next = cp;
292  } else {
293  tp->components = cp;
294  }
295  tp->componentsTail = cp;
296  cp->next = NULL;
297 }
298 
301 {
302  TrayComponentType *cp;
303  int result;
304  int temp;
305 
306  result = 0;
307  for(cp = tp->components; cp; cp = cp->next) {
308  temp = cp->width;
309  if(temp > 0) {
310  if(temp > result) {
311  result = temp;
312  }
313  }
314  }
315 
316  return result;
317 }
318 
321 {
322  TrayComponentType *cp;
323  int result;
324 
325  result = 2 * TRAY_BORDER_SIZE;
326  for(cp = tp->components; cp; cp = cp->next) {
327  result += cp->width;
328  }
329 
330  return result;
331 }
332 
335 {
336  TrayComponentType *cp;
337  int result;
338  int temp;
339 
340  result = 0;
341  for(cp = tp->components; cp; cp = cp->next) {
342  temp = cp->height;
343  if(temp > 0) {
344  if(temp > result) {
345  result = temp;
346  }
347  }
348  }
349 
350  return result;
351 }
352 
355 {
356  TrayComponentType *cp;
357  int result;
358 
359  result = 2 * TRAY_BORDER_SIZE;
360  for(cp = tp->components; cp; cp = cp->next) {
361  result += cp->height;
362  }
363 
364  return result;
365 }
366 
369 {
370  TrayComponentType *cp;
371 
372  for(cp = tp->components; cp; cp = cp->next) {
373  if(cp->width == 0) {
374  return 1;
375  }
376  }
377 
378  return 0;
379 }
380 
383 {
384  TrayComponentType *cp;
385 
386  for(cp = tp->components; cp; cp = cp->next) {
387  if(cp->height == 0) {
388  return 1;
389  }
390  }
391 
392  return 0;
393 }
394 
397 {
398  TrayComponentType *cp;
399  const ScreenType *sp;
400  int x, y;
401 
402  /* Determine the first dimension. */
403  if(tp->layout == LAYOUT_HORIZONTAL) {
404 
405  if(tp->height == 0) {
406  tp->height = ComputeMaxHeight(tp) + TRAY_BORDER_SIZE * 2;
407  }
408  if(tp->height == 0) {
410  }
411 
412  } else {
413 
414  if(tp->width == 0) {
415  tp->width = ComputeMaxWidth(tp) + TRAY_BORDER_SIZE * 2;
416  }
417  if(tp->width == 0) {
419  }
420 
421  }
422 
423  /* Now at least one size is known. Inform the components. */
424  for(cp = tp->components; cp; cp = cp->next) {
425  if(cp->SetSize) {
426  if(tp->layout == LAYOUT_HORIZONTAL) {
427  (cp->SetSize)(cp, 0, tp->height - TRAY_BORDER_SIZE * 2);
428  } else {
429  (cp->SetSize)(cp, tp->width - TRAY_BORDER_SIZE * 2, 0);
430  }
431  }
432  }
433 
434  /* Initialize the coordinates. */
435  tp->x = tp->requestedX;
436  tp->y = tp->requestedY;
437 
438  /* Determine on which screen the tray will reside. */
439  switch(tp->valign) {
440  case TALIGN_TOP:
441  y = 0;
442  break;
443  case TALIGN_BOTTOM:
444  y = rootHeight - 1;
445  break;
446  case TALIGN_CENTER:
447  y = 1 + rootHeight / 2;
448  break;
449  default:
450  if(tp->y < 0) {
451  y = rootHeight + tp->y;
452  } else {
453  y = tp->y;
454  }
455  break;
456  }
457  switch(tp->halign) {
458  case TALIGN_LEFT:
459  x = 0;
460  break;
461  case TALIGN_RIGHT:
462  x = rootWidth - 1;
463  break;
464  case TALIGN_CENTER:
465  x = 1 + rootWidth / 2;
466  break;
467  default:
468  if(tp->x < 0) {
469  x = rootWidth + tp->x;
470  } else {
471  x = tp->x;
472  }
473  break;
474  }
475  sp = GetCurrentScreen(x, y);
476 
477  /* Determine the missing dimension. */
478  if(tp->layout == LAYOUT_HORIZONTAL) {
479  if(tp->width == 0) {
480  if(CheckHorizontalFill(tp)) {
481  tp->width = sp->width + sp->x - x;
482  } else {
483  tp->width = ComputeTotalWidth(tp);
484  }
485  if(tp->width == 0) {
487  }
488  }
489  } else {
490  if(tp->height == 0) {
491  if(CheckVerticalFill(tp)) {
492  tp->height = sp->height + sp->y - y;
493  } else {
494  tp->height = ComputeTotalHeight(tp);
495  }
496  if(tp->height == 0) {
498  }
499  }
500  }
501 
502  /* Compute the tray location. */
503  switch(tp->valign) {
504  case TALIGN_TOP:
505  tp->y = sp->y;
506  break;
507  case TALIGN_BOTTOM:
508  tp->y = sp->y + sp->height - tp->height;
509  break;
510  case TALIGN_CENTER:
511  tp->y = sp->y + (sp->height - tp->height) / 2;
512  break;
513  default:
514  if(tp->y < 0) {
515  tp->y = sp->y + sp->height - tp->height + tp->y + 1;
516  }
517  break;
518  }
519 
520  switch(tp->halign) {
521  case TALIGN_LEFT:
522  tp->x = sp->x;
523  break;
524  case TALIGN_RIGHT:
525  tp->x = sp->x + sp->width - tp->width;
526  break;
527  case TALIGN_CENTER:
528  tp->x = sp->x + (sp->width - tp->width) / 2;
529  break;
530  default:
531  if(tp->x < 0) {
532  tp->x = sp->x + sp->width - tp->width + tp->x + 1;
533  }
534  break;
535  }
536 }
537 
540 {
541  Window win1, win2;
542  int winx, winy;
543  unsigned int mask;
544  int mousex, mousey;
545 
546  if(tp->hidden) {
547 
548  tp->hidden = 0;
549  JXMoveWindow(display, tp->window, tp->x, tp->y);
550 
551  JXQueryPointer(display, rootWindow, &win1, &win2,
552  &mousex, &mousey, &winx, &winy, &mask);
553  SetMousePosition(mousex, mousey, win2);
554 
555  }
556 }
557 
559 void ShowAllTrays(void)
560 {
561  TrayType *tp;
562 
563  if(shouldExit) {
564  return;
565  }
566 
567  for(tp = trays; tp; tp = tp->next) {
568  ShowTray(tp);
569  }
570 }
571 
574 {
575  const ScreenType *sp;
576  int x, y;
577 
578  /* Don't hide if the tray is raised. */
579  if(tp->autoHide & THIDE_RAISED) {
580  return;
581  }
582 
583  tp->hidden = 1;
584 
585  /* Determine where to move the tray. */
586  sp = GetCurrentScreen(tp->x, tp->y);
587  switch(tp->autoHide) {
588  case THIDE_LEFT:
589  x = sp->y - tp->width + 1;
590  y = tp->y;
591  break;
592  case THIDE_RIGHT:
593  x = sp->y + sp->width - 1;
594  y = tp->y;
595  break;
596  case THIDE_TOP:
597  x = tp->x;
598  y = sp->y - tp->height + 1;
599  break;
600  case THIDE_BOTTOM:
601  x = tp->x;
602  y = sp->y + sp->height - 1;
603  break;
604  default:
605  Assert(0);
606  return;
607  }
608 
609  /* Move and redraw. */
610  JXMoveWindow(display, tp->window, x, y);
611  DrawSpecificTray(tp);
612 }
613 
615 char ProcessTrayEvent(const XEvent *event)
616 {
617  TrayType *tp;
618 
619  for(tp = trays; tp; tp = tp->next) {
620  if(event->xany.window == tp->window) {
621  switch(event->type) {
622  case Expose:
623  HandleTrayExpose(tp, &event->xexpose);
624  return 1;
625  case EnterNotify:
626  HandleTrayEnterNotify(tp, &event->xcrossing);
627  return 1;
628  case ButtonPress:
629  HandleTrayButtonPress(tp, &event->xbutton);
630  return 1;
631  case ButtonRelease:
632  HandleTrayButtonRelease(tp, &event->xbutton);
633  return 1;
634  case MotionNotify:
635  HandleTrayMotionNotify(tp, &event->xmotion);
636  return 1;
637  default:
638  return 0;
639  }
640  }
641  }
642 
643  return 0;
644 }
645 
647 void SignalTray(const TimeType *now, int x, int y, Window w, void *data)
648 {
649  TrayType *tp = (TrayType*)data;
650  if(tp->autoHide != THIDE_OFF && !tp->hidden && !menuShown) {
651  if(x < tp->x || x >= tp->x + tp->width
652  || y < tp->y || y >= tp->y + tp->height) {
653  HideTray(tp);
654  }
655  }
656 }
657 
659 void HandleTrayExpose(TrayType *tp, const XExposeEvent *event)
660 {
661  DrawSpecificTray(tp);
662 }
663 
665 void HandleTrayEnterNotify(TrayType *tp, const XCrossingEvent *event)
666 {
667  ShowTray(tp);
668 }
669 
672 {
673  TrayComponentType *cp;
674  int xoffset, yoffset;
675 
676  xoffset = 0;
677  yoffset = 0;
678  for(cp = tp->components; cp; cp = cp->next) {
679  const int startx = xoffset;
680  const int starty = yoffset;
681  const int width = cp->width;
682  const int height = cp->height;
683  if(x >= startx && x < startx + width) {
684  if(y >= starty && y < starty + height) {
685  return cp;
686  }
687  }
688  if(tp->layout == LAYOUT_HORIZONTAL) {
689  xoffset += width;
690  } else {
691  yoffset += height;
692  }
693  }
694 
695  return NULL;
696 }
697 
699 void HandleTrayButtonPress(TrayType *tp, const XButtonEvent *event)
700 {
701  TrayComponentType *cp = GetTrayComponent(tp, event->x, event->y);
702  if(cp && cp->ProcessButtonPress) {
703  const int x = event->x - cp->x;
704  const int y = event->y - cp->y;
705  const int mask = event->button;
707  (cp->ProcessButtonPress)(cp, x, y, mask);
708  }
709 }
710 
712 void HandleTrayButtonRelease(TrayType *tp, const XButtonEvent *event)
713 {
714  TrayComponentType *cp;
715 
716  // First inform any components that have a grab.
717  for(cp = tp->components; cp; cp = cp->next) {
718  if(cp->grabbed) {
719  const int x = event->x - cp->x;
720  const int y = event->y - cp->y;
721  const int mask = event->button;
722  (cp->ProcessButtonRelease)(cp, x, y, mask);
723  JXUngrabPointer(display, CurrentTime);
724  cp->grabbed = 0;
725  return;
726  }
727  }
728 
729  cp = GetTrayComponent(tp, event->x, event->y);
730  if(cp && cp->ProcessButtonRelease) {
731  const int x = event->x - cp->x;
732  const int y = event->y - cp->y;
733  const int mask = event->button;
734  (cp->ProcessButtonRelease)(cp, x, y, mask);
735  }
736 }
737 
739 void HandleTrayMotionNotify(TrayType *tp, const XMotionEvent *event)
740 {
741  TrayComponentType *cp = GetTrayComponent(tp, event->x, event->y);
742  if(cp && cp->ProcessMotionEvent) {
743  const int x = event->x - cp->x;
744  const int y = event->y - cp->y;
745  const int mask = event->state;
746  (cp->ProcessMotionEvent)(cp, x, y, mask);
747  }
748 }
749 
751 void DrawTray(void)
752 {
753  TrayType *tp;
754 
755  if(shouldExit) {
756  return;
757  }
758 
759  for(tp = trays; tp; tp = tp->next) {
760  DrawSpecificTray(tp);
761  }
762 }
763 
765 void DrawSpecificTray(const TrayType *tp)
766 {
767  TrayComponentType *cp;
768 
769  for(cp = tp->components; cp; cp = cp->next) {
770  UpdateSpecificTray(tp, cp);
771  }
772 
775  JXDrawLine(display, tp->window, rootGC, 0, 0, tp->width - 1, 0);
776  JXDrawLine(display, tp->window, rootGC, 0, tp->height - 1, 0, 0);
777 
779  JXDrawLine(display, tp->window, rootGC, 0, tp->height - 1,
780  tp->width - 1, tp->height - 1);
781  JXDrawLine(display, tp->window, rootGC, tp->width - 1, 0,
782  tp->width - 1, tp->height - 1);
783  } else {
785  JXDrawRectangle(display, tp->window, rootGC, 0, 0,
786  tp->width - 1, tp->height - 1);
787  }
788 }
789 
791 void RaiseTrays(void)
792 {
793  TrayType *tp;
794  for(tp = trays; tp; tp = tp->next) {
795  tp->autoHide |= THIDE_RAISED;
796  ShowTray(tp);
798  }
799 }
800 
802 void LowerTrays(void)
803 {
804  TrayType *tp;
805  for(tp = trays; tp; tp = tp->next) {
806  tp->autoHide &= ~THIDE_RAISED;
807  }
808  RequireRestack();
809 }
810 
813 {
814  if(JUNLIKELY(shouldExit)) {
815  return;
816  }
817 
818  /* If the tray is hidden, draw only the background. */
819  if(cp->pixmap != None) {
820  JXCopyArea(display, cp->pixmap, tp->window, rootGC, 0, 0,
821  cp->width, cp->height, cp->x, cp->y);
822  }
823 }
824 
826 void LayoutTray(TrayType *tp, int *variableSize, int *variableRemainder)
827 {
828  TrayComponentType *cp;
829  unsigned int variableCount;
830  int width, height;
831  int temp;
832 
833  if(tp->requestedWidth >= 0) {
834  tp->width = tp->requestedWidth;
835  } else {
836  tp->width = rootWidth + tp->requestedWidth - tp->x;
837  }
838  if(tp->requestedHeight >= 0) {
839  tp->height = tp->requestedHeight;
840  } else {
841  tp->height = rootHeight + tp->requestedHeight - tp->y;
842  }
843 
844  for(cp = tp->components; cp; cp = cp->next) {
845  if(cp->requestedWidth != 0) {
846  cp->width = cp->requestedWidth;
847  } else {
848  cp->width = 0;
849  }
850  if(cp->requestedHeight != 0) {
851  cp->height = cp->requestedHeight;
852  } else {
853  cp->height = 0;
854  }
855  }
856 
857  ComputeTraySize(tp);
858 
859  /* Get the remaining size after setting fixed size components. */
860  /* Also, keep track of the number of variable size components. */
861  width = tp->width - TRAY_BORDER_SIZE * 2;
862  height = tp->height - TRAY_BORDER_SIZE * 2;
863  variableCount = 0;
864  for(cp = tp->components; cp; cp = cp->next) {
865  if(tp->layout == LAYOUT_HORIZONTAL) {
866  temp = cp->width;
867  if(temp > 0) {
868  width -= temp;
869  } else {
870  variableCount += 1;
871  }
872  } else {
873  temp = cp->height;
874  if(temp > 0) {
875  height -= temp;
876  } else {
877  variableCount += 1;
878  }
879  }
880  }
881 
882  /* Distribute excess size among variable size components.
883  * If there are no variable size components, shrink the tray.
884  * If we are out of room, just give them a size of one.
885  */
886  *variableSize = 1;
887  *variableRemainder = 0;
888  if(tp->layout == LAYOUT_HORIZONTAL) {
889  if(variableCount) {
890  if(width >= variableCount) {
891  *variableSize = width / variableCount;
892  *variableRemainder = width % variableCount;
893  }
894  } else if(width > 0) {
895  tp->width -= width;
896  }
897  } else {
898  if(variableCount) {
899  if(height >= variableCount) {
900  *variableSize = height / variableCount;
901  *variableRemainder = height % variableCount;
902  }
903  } else if(height > 0) {
904  tp->height -= height;
905  }
906  }
907 
908  tp->width = Max(1, tp->width);
909  tp->height = Max(1, tp->height);
910 }
911 
914 {
915  TrayComponentType *cp;
916  int variableSize;
917  int variableRemainder;
918  int xoffset, yoffset;
919  int width, height;
920 
921  Assert(tp);
922 
923  LayoutTray(tp, &variableSize, &variableRemainder);
924 
925  /* Reposition items on the tray. */
926  xoffset = TRAY_BORDER_SIZE;
927  yoffset = TRAY_BORDER_SIZE;
928  for(cp = tp->components; cp; cp = cp->next) {
929 
930  cp->x = xoffset;
931  cp->y = yoffset;
932  cp->screenx = tp->x + xoffset;
933  cp->screeny = tp->y + yoffset;
934 
935  if(cp->Resize) {
936  if(tp->layout == LAYOUT_HORIZONTAL) {
937  height = tp->height - TRAY_BORDER_SIZE * 2;
938  width = cp->width;
939  if(width == 0) {
940  width = variableSize;
941  if(variableRemainder) {
942  width += 1;
943  variableRemainder -= 1;
944  }
945  }
946  } else {
947  width = tp->width - TRAY_BORDER_SIZE * 2;
948  height = cp->height;
949  if(height == 0) {
950  height = variableSize;
951  if(variableRemainder) {
952  height += 1;
953  variableRemainder -= 1;
954  }
955  }
956  }
957  cp->width = width;
958  cp->height = height;
959  (cp->Resize)(cp);
960  }
961 
962  if(cp->window != None) {
963  JXMoveWindow(display, cp->window, xoffset, yoffset);
964  }
965 
966  if(tp->layout == LAYOUT_HORIZONTAL) {
967  xoffset += cp->width;
968  } else {
969  yoffset += cp->height;
970  }
971  }
972 
973  JXMoveResizeWindow(display, tp->window, tp->x, tp->y,
974  tp->width, tp->height);
975 
977  DrawSpecificTray(tp);
978 
979  if(tp->hidden) {
980  HideTray(tp);
981  }
982 }
983 
986 {
987  const Drawable d = cp->pixmap != None ? cp->pixmap : cp->window;
990  JXFillRectangle(display, d, rootGC, 0, 0, cp->width, cp->height);
991  } else {
993  colors[COLOR_TRAY_BG2], 0, 0,
994  cp->width, cp->height);
995  }
996 }
997 
1000 {
1001  return trays;
1002 }
1003 
1005 unsigned int GetTrayCount(void)
1006 {
1007  return trayCount;
1008 }
1009 
1012 {
1013  Assert(tp);
1014  tp->autoHide = autohide;
1015 }
1016 
1018 void SetTrayX(TrayType *tp, const char *str)
1019 {
1020  Assert(tp);
1021  Assert(str);
1022  tp->requestedX = atoi(str);
1023 }
1024 
1026 void SetTrayY(TrayType *tp, const char *str)
1027 {
1028  Assert(tp);
1029  Assert(str);
1030  tp->requestedY = atoi(str);
1031 }
1032 
1034 void SetTrayWidth(TrayType *tp, const char *str)
1035 {
1036  tp->requestedWidth = atoi(str);
1037 }
1038 
1040 void SetTrayHeight(TrayType *tp, const char *str)
1041 {
1042  tp->requestedHeight = atoi(str);
1043 }
1044 
1045 
1047 void SetTrayLayout(TrayType *tp, const char *str)
1048 {
1049  if(!str) {
1050 
1051  /* Compute based on requested size. */
1052 
1053  } else if(!strcmp(str, "horizontal")) {
1054 
1055  tp->layout = LAYOUT_HORIZONTAL;
1056  return;
1057 
1058  } else if(!strcmp(str, "vertical")) {
1059 
1060  tp->layout = LAYOUT_VERTICAL;
1061  return;
1062 
1063  } else {
1064  Warning(_("invalid tray layout: \"%s\""), str);
1065  }
1066 
1067  /* Prefer horizontal layout, but use vertical if
1068  * width is finite and height is larger than width or infinite.
1069  */
1070  if(tp->requestedWidth > 0
1071  && (tp->requestedHeight == 0
1072  || tp->requestedHeight > tp->requestedWidth)) {
1073  tp->layout = LAYOUT_VERTICAL;
1074  } else {
1075  tp->layout = LAYOUT_HORIZONTAL;
1076  }
1077 }
1078 
1081 {
1082  tp->layer = layer;
1083 }
1084 
1086 void SetTrayHorizontalAlignment(TrayType *tp, const char *str)
1087 {
1088  static const StringMappingType mapping[] = {
1089  { "center", TALIGN_CENTER },
1090  { "fixed", TALIGN_FIXED },
1091  { "left", TALIGN_LEFT },
1092  { "right", TALIGN_RIGHT }
1093  };
1094 
1095  if(!str) {
1096  tp->halign = TALIGN_FIXED;
1097  } else {
1098  const int x = FindValue(mapping, ARRAY_LENGTH(mapping), str);
1099  if(JLIKELY(x >= 0)) {
1100  tp->halign = x;
1101  } else {
1102  Warning(_("invalid tray horizontal alignment: \"%s\""), str);
1103  tp->halign = TALIGN_FIXED;
1104  }
1105  }
1106 }
1107 
1109 void SetTrayVerticalAlignment(TrayType *tp, const char *str)
1110 {
1111  static const StringMappingType mapping[] = {
1112  { "bottom", TALIGN_BOTTOM },
1113  { "center", TALIGN_CENTER },
1114  { "fixed", TALIGN_FIXED },
1115  { "top", TALIGN_TOP }
1116  };
1117 
1118  if(!str) {
1119  tp->valign = TALIGN_FIXED;
1120  } else {
1121  const int x = FindValue(mapping, ARRAY_LENGTH(mapping), str);
1122  if(JLIKELY(x >= 0)) {
1123  tp->valign = x;
1124  } else {
1125  Warning(_("invalid tray vertical alignment: \"%s\""), str);
1126  tp->valign = TALIGN_FIXED;
1127  }
1128  }
1129 }

joewing.net / Projects / JWM