JWM Source Documentation
taskbar.c
Go to the documentation of this file.
1 
10 #include "jwm.h"
11 #include "taskbar.h"
12 #include "tray.h"
13 #include "timing.h"
14 #include "main.h"
15 #include "client.h"
16 #include "clientlist.h"
17 #include "color.h"
18 #include "popup.h"
19 #include "button.h"
20 #include "cursor.h"
21 #include "icon.h"
22 #include "error.h"
23 #include "winmenu.h"
24 #include "screen.h"
25 #include "settings.h"
26 #include "event.h"
27 #include "misc.h"
28 #include "desktop.h"
29 
30 typedef struct TaskBarType {
31 
33  struct TaskBarType *next;
34 
38  int itemWidth;
40  char labeled;
41 
42  Pixmap buffer;
43 
45  int mousex, mousey;
46 
47 } TaskBarType;
48 
49 typedef struct ClientEntry {
51  struct ClientEntry *next;
52  struct ClientEntry *prev;
53 } ClientEntry;
54 
55 typedef struct TaskEntry {
57  struct TaskEntry *next;
58  struct TaskEntry *prev;
59 } TaskEntry;
60 
61 static TaskBarType *bars;
64 
65 static void ComputeItemSize(TaskBarType *tp);
66 static char ShouldShowEntry(const TaskEntry *tp);
67 static char ShouldFocusEntry(const TaskEntry *tp);
68 static TaskEntry *GetEntry(TaskBarType *bar, int x, int y);
69 static void Render(const TaskBarType *bp);
70 static void ShowClientList(TaskBarType *bar, TaskEntry *tp);
71 static void RunTaskBarCommand(MenuAction *action, unsigned button);
72 
73 static void SetSize(TrayComponentType *cp, int width, int height);
74 static void Create(TrayComponentType *cp);
75 static void Resize(TrayComponentType *cp);
77  int x, int y, int mask);
78 static void MinimizeGroup(const TaskEntry *tp);
79 static void FocusGroup(const TaskEntry *tp);
81  int x, int y, int mask);
82 static void SignalTaskbar(const TimeType *now, int x, int y, Window w,
83  void *data);
84 
87 {
88  bars = NULL;
89  taskEntries = NULL;
90  taskEntriesTail = NULL;
91 }
92 
94 void ShutdownTaskBar(void)
95 {
96  TaskBarType *bp;
97  for(bp = bars; bp; bp = bp->next) {
99  }
100 }
101 
103 void DestroyTaskBar(void)
104 {
105  TaskBarType *bp;
106  while(bars) {
107  bp = bars->next;
109  Release(bars);
110  bars = bp;
111  }
112 }
113 
116 {
117 
118  TrayComponentType *cp;
119  TaskBarType *tp;
120 
121  tp = Allocate(sizeof(TaskBarType));
122  tp->next = bars;
123  bars = tp;
124  tp->itemHeight = 0;
125  tp->itemWidth = 0;
126  tp->userHeight = 0;
127  tp->maxItemWidth = 0;
129  tp->labeled = 1;
132  tp->mouseTime.seconds = 0;
133  tp->mouseTime.ms = 0;
134 
135  cp = CreateTrayComponent();
136  cp->object = tp;
137  tp->cp = cp;
138 
139  cp->SetSize = SetSize;
140  cp->Create = Create;
141  cp->Resize = Resize;
144 
146 
147  return cp;
148 
149 }
150 
152 void SetSize(TrayComponentType *cp, int width, int height)
153 {
154  TaskBarType *tp = (TaskBarType*)cp->object;
155  if(width == 0) {
157  } else if(height == 0) {
158  tp->layout = LAYOUT_VERTICAL;
159  } else if(width > height) {
161  } else {
162  tp->layout = LAYOUT_VERTICAL;
163  }
164 }
165 
168 {
169  TaskBarType *tp = (TaskBarType*)cp->object;
171  rootDepth);
172  tp->buffer = cp->pixmap;
173  ClearTrayDrawable(cp);
174 }
175 
178 {
179  TaskBarType *tp = (TaskBarType*)cp->object;
180  if(tp->buffer != None) {
182  }
184  rootDepth);
185  tp->buffer = cp->pixmap;
186  ClearTrayDrawable(cp);
187 }
188 
191 {
192  TrayComponentType *cp = tp->cp;
193  if(tp->layout == LAYOUT_VERTICAL) {
194 
195  if(tp->userHeight > 0) {
196  tp->itemHeight = tp->userHeight;
197  } else {
199  }
200  tp->itemWidth = cp->width;
201 
202  } else {
203 
204  TaskEntry *ep;
205  unsigned itemCount = 0;
206 
207  tp->itemHeight = cp->height;
208  for(ep = taskEntries; ep; ep = ep->next) {
209  if(ShouldShowEntry(ep)) {
210  itemCount += 1;
211  }
212  }
213  if(itemCount == 0) {
214  return;
215  }
216 
217  tp->itemWidth = Max(1, cp->width / itemCount);
218  if(!tp->labeled) {
219  tp->itemWidth = Min(tp->itemHeight, tp->itemWidth);
220  }
221  if(tp->maxItemWidth > 0) {
222  tp->itemWidth = Min(tp->maxItemWidth, tp->itemWidth);
223  }
224  }
225 }
226 
228 void ProcessTaskButtonEvent(TrayComponentType *cp, int x, int y, int mask)
229 {
230 
231  TaskBarType *bar = (TaskBarType*)cp->object;
232  TaskEntry *entry = GetEntry(bar, x, y);
233 
234  if(entry) {
235  ClientEntry *cp;
236  ClientNode *focused = NULL;
237  char onTop = 0;
238  char hasActive = 0;
239 
240  switch(mask) {
241  case Button1: /* Raise or minimize items in this group. */
242  for(cp = entry->clients; cp; cp = cp->next) {
243  int layer;
244  char foundTop = 0;
245  if(cp->client->state.status & STAT_MINIMIZED) {
246  continue;
247  } else if(!ShouldFocus(cp->client, 0)) {
248  continue;
249  }
250  for(layer = LAST_LAYER; layer >= FIRST_LAYER; layer--) {
251  ClientNode *np;
252  for(np = nodes[layer]; np; np = np->next) {
253  if(np->state.status & STAT_MINIMIZED) {
254  continue;
255  } else if(!ShouldFocus(np, 0)) {
256  continue;
257  }
258  if(np == cp->client) {
259  const char isActive = (np->state.status & STAT_ACTIVE)
261  onTop = onTop || !foundTop;
262  if(isActive) {
263  focused = np;
264  }
265  if(!(cp->client->state.status
267  || isActive) {
268  hasActive = 1;
269  }
270  }
271  if(hasActive && onTop) {
272  goto FoundActiveAndTop;
273  }
274  foundTop = 1;
275  }
276  }
277  }
278 FoundActiveAndTop:
279  if(hasActive && onTop) {
280  ClientNode *nextClient = NULL;
281  int i;
282 
283  /* Try to find a client on a different desktop. */
284  for(i = 0; i < settings.desktopCount - 1; i++) {
285  const int target = (currentDesktop + i + 1)
287  for(cp = entry->clients; cp; cp = cp->next) {
288  ClientNode *np = cp->client;
289  if(!ShouldFocus(np, 0)) {
290  continue;
291  } else if(np->state.status & STAT_STICKY) {
292  continue;
293  } else if(np->state.desktop == target) {
294  if(!nextClient || np->state.status & STAT_ACTIVE) {
295  nextClient = np;
296  }
297  }
298  }
299  if(nextClient) {
300  break;
301  }
302  }
303  /* Focus the next client or minimize the current group. */
304  if(nextClient) {
305  ChangeDesktop(nextClient->state.desktop);
306  RestoreClient(nextClient, 1);
307  } else {
308  MinimizeGroup(entry);
309  }
310  } else {
311  FocusGroup(entry);
312  if(focused) {
313  FocusClient(focused);
314  }
315  }
316  break;
317  case Button3:
318  ShowClientList(bar, entry);
319  break;
320  case Button4:
321  FocusPrevious();
322  break;
323  case Button5:
324  FocusNext();
325  break;
326  default:
327  break;
328  }
329  }
330 
331 }
332 
334 void MinimizeGroup(const TaskEntry *tp)
335 {
336  ClientEntry *cp;
337  for(cp = tp->clients; cp; cp = cp->next) {
338  if(ShouldFocus(cp->client, 1)) {
339  MinimizeClient(cp->client, 0);
340  }
341  }
342 }
343 
345 void FocusGroup(const TaskEntry *tp)
346 {
347  const char *className = tp->clients->client->className;
348  ClientNode **toRestore;
349  const ClientEntry *cp;
350  unsigned restoreCount;
351  int i;
352  char shouldSwitch;
353 
354  /* If there is no class name, then there will only be one client. */
355  if(!className || !settings.groupTasks) {
356  if(!(tp->clients->client->state.status & STAT_STICKY)) {
358  }
359  RestoreClient(tp->clients->client, 1);
360  FocusClient(tp->clients->client);
361  return;
362  }
363 
364  /* If there is a client in the group on this desktop,
365  * then we remain on the same desktop. */
366  shouldSwitch = 1;
367  for(cp = tp->clients; cp; cp = cp->next) {
369  shouldSwitch = 0;
370  break;
371  }
372  }
373 
374  /* Switch to the desktop of the top-most client in the group. */
375  if(shouldSwitch) {
376  for(i = 0; i < LAYER_COUNT; i++) {
377  ClientNode *np;
378  for(np = nodes[i]; np; np = np->next) {
379  if(np->className && !strcmp(np->className, className)) {
380  if(ShouldFocus(np, 0)) {
381  if(!(np->state.status & STAT_STICKY)) {
383  }
384  break;
385  }
386  }
387  }
388  }
389  }
390 
391  /* Build up the list of clients to restore in correct order. */
392  toRestore = AllocateStack(sizeof(ClientNode*) * clientCount);
393  restoreCount = 0;
394  for(i = 0; i < LAYER_COUNT; i++) {
395  ClientNode *np;
396  for(np = nodes[i]; np; np = np->next) {
397  if(!ShouldFocus(np, 1)) {
398  continue;
399  }
400  if(np->className && !strcmp(np->className, className)) {
401  toRestore[restoreCount] = np;
402  restoreCount += 1;
403  }
404  }
405  }
406  Assert(restoreCount <= clientCount);
407  for(i = restoreCount - 1; i >= 0; i--) {
408  RestoreClient(toRestore[i], 1);
409  }
410  for(i = 0; i < restoreCount; i++) {
411  if(toRestore[i]->state.status & (STAT_CANFOCUS | STAT_TAKEFOCUS)) {
412  FocusClient(toRestore[i]);
413  break;
414  }
415  }
416  ReleaseStack(toRestore);
417 }
418 
420 void ProcessTaskMotionEvent(TrayComponentType *cp, int x, int y, int mask)
421 {
422  TaskBarType *bp = (TaskBarType*)cp->object;
423  bp->mousex = cp->screenx + x;
424  bp->mousey = cp->screeny + y;
426 }
427 
430 {
431  Menu *menu;
432  MenuItem *item;
433  ClientEntry *cp;
434 
435  const ScreenType *sp;
436  int x, y;
437  Window w;
438 
439  if(settings.groupTasks) {
440 
441  menu = CreateMenu();
442 
444  item->name = CopyString(_("Close"));
445  item->action.type = MA_CLOSE | MA_GROUP_MASK;
446  item->action.context = tp;
447  item->next = menu->items;
448  menu->items = item;
449 
451  item->name = CopyString(_("Minimize"));
453  item->action.context = tp;
454  item->next = menu->items;
455  menu->items = item;
456 
458  item->name = CopyString(_("Restore"));
460  item->action.context = tp;
461  item->next = menu->items;
462  menu->items = item;
463 
465  item->name = CopyString(_("Send To"));
467  item->action.context = tp;
468  item->next = menu->items;
469  menu->items = item;
470 
471  /* Load the separator and group actions. */
473  item->next = menu->items;
474  menu->items = item;
475 
476  /* Load the clients into the menu. */
477  for(cp = tp->clients; cp; cp = cp->next) {
478  if(!ShouldFocus(cp->client, 0)) {
479  continue;
480  }
482  if(cp->client->state.status & STAT_MINIMIZED) {
483  size_t len = 0;
484  if(cp->client->name) {
485  len = strlen(cp->client->name);
486  }
487  item->name = Allocate(len + 3);
488  item->name[0] = '[';
489  memcpy(&item->name[1], cp->client->name, len);
490  item->name[len + 1] = ']';
491  item->name[len + 2] = 0;
492  } else {
493  item->name = CopyString(cp->client->name);
494  }
495  item->icon = cp->client->icon ? cp->client->icon : GetDefaultIcon();
496  item->action.type = MA_EXECUTE;
497  item->action.context = cp->client;
498  item->next = menu->items;
499  menu->items = item;
500  }
501  } else {
502  /* Not grouping clients. */
503  menu = CreateWindowMenu(tp->clients->client);
504  }
505 
506  /* Initialize and position the menu. */
507  InitializeMenu(menu);
508  sp = GetCurrentScreen(bar->cp->screenx, bar->cp->screeny);
509  GetMousePosition(&x, &y, &w);
510  if(bar->layout == LAYOUT_HORIZONTAL) {
511  if(bar->cp->screeny + bar->cp->height / 2 < sp->y + sp->height / 2) {
512  /* Bottom of the screen: menus go up. */
513  y = bar->cp->screeny + bar->cp->height;
514  } else {
515  /* Top of the screen: menus go down. */
516  y = bar->cp->screeny - menu->height;
517  }
518  x -= menu->width / 2;
519  x = Max(x, sp->x);
520  } else {
521  if(bar->cp->screenx + bar->cp->width / 2 < sp->x + sp->width / 2) {
522  /* Left side: menus go right. */
523  x = bar->cp->screenx + bar->cp->width;
524  } else {
525  /* Right side: menus go left. */
526  x = bar->cp->screenx - menu->width;
527  }
528  y -= menu->height / 2;
529  y = Max(y, sp->y);
530  }
531 
532  ShowMenu(menu, RunTaskBarCommand, x, y, 0);
533 
534  DestroyMenu(menu);
535 
536 }
537 
539 void RunTaskBarCommand(MenuAction *action, unsigned button)
540 {
541  ClientEntry *cp;
542 
543  if(action->type & MA_GROUP_MASK) {
544  TaskEntry *tp = action->context;
545  for(cp = tp->clients; cp; cp = cp->next) {
546  if(!ShouldFocus(cp->client, 0)) {
547  continue;
548  }
549  switch(action->type & ~MA_GROUP_MASK) {
550  case MA_SENDTO:
551  SetClientDesktop(cp->client, action->value);
552  break;
553  case MA_CLOSE:
554  DeleteClient(cp->client);
555  break;
556  case MA_RESTORE:
557  RestoreClient(cp->client, 0);
558  break;
559  case MA_MINIMIZE:
560  MinimizeClient(cp->client, 0);
561  break;
562  default:
563  break;
564  }
565  }
566  } else if(action->type == MA_EXECUTE) {
567  if(button == Button3) {
568  Window w;
569  int x, y;
570  GetMousePosition(&x, &y, &w);
571  ShowWindowMenu(action->context, x, y, 0);
572  } else {
573  ClientNode *np = action->context;
574  RestoreClient(np, 1);
575  FocusClient(np);
576  MoveMouse(np->window, np->width / 2, np->height / 2);
577  }
578  } else {
579  RunWindowCommand(action, button);
580  }
581 }
582 
585 {
586  TaskEntry *tp = NULL;
587  ClientEntry *cp = Allocate(sizeof(ClientEntry));
588  cp->client = np;
589 
590  if(np->className && settings.groupTasks) {
591  for(tp = taskEntries; tp; tp = tp->next) {
592  const char *className = tp->clients->client->className;
593  if(className && !strcmp(np->className, className)) {
594  break;
595  }
596  }
597  }
598  if(tp == NULL) {
599  tp = Allocate(sizeof(TaskEntry));
600  tp->clients = NULL;
601  tp->next = NULL;
602  tp->prev = taskEntriesTail;
603  if(taskEntriesTail) {
604  taskEntriesTail->next = tp;
605  } else {
606  taskEntries = tp;
607  }
608  taskEntriesTail = tp;
609  }
610 
611  cp->next = tp->clients;
612  if(tp->clients) {
613  tp->clients->prev = cp;
614  }
615  cp->prev = NULL;
616  tp->clients = cp;
617 
620 
621 }
622 
625 {
626  TaskEntry *tp;
627  for(tp = taskEntries; tp; tp = tp->next) {
628  ClientEntry *cp;
629  for(cp = tp->clients; cp; cp = cp->next) {
630  if(cp->client == np) {
631  if(cp->prev) {
632  cp->prev->next = cp->next;
633  } else {
634  tp->clients = cp->next;
635  }
636  if(cp->next) {
637  cp->next->prev = cp->prev;
638  }
639  Release(cp);
640  if(!tp->clients) {
641  if(tp->prev) {
642  tp->prev->next = tp->next;
643  } else {
644  taskEntries = tp->next;
645  }
646  if(tp->next) {
647  tp->next->prev = tp->prev;
648  } else {
649  taskEntriesTail = tp->prev;
650  }
651  Release(tp);
652  }
655  return;
656  }
657  }
658  }
659 }
660 
662 void UpdateTaskBar(void)
663 {
664  TaskBarType *bp;
665  int lastHeight = -1;
666 
667  if(JUNLIKELY(shouldExit)) {
668  return;
669  }
670 
671  for(bp = bars; bp; bp = bp->next) {
672  if(bp->layout == LAYOUT_VERTICAL) {
673  TaskEntry *tp;
674  lastHeight = bp->cp->requestedHeight;
675  if(bp->userHeight > 0) {
676  bp->itemHeight = bp->userHeight;
677  } else {
679  }
680  bp->cp->requestedHeight = 0;
681  for(tp = taskEntries; tp; tp = tp->next) {
682  if(ShouldShowEntry(tp)) {
683  bp->cp->requestedHeight += bp->itemHeight;
684  }
685  }
686  bp->cp->requestedHeight = Max(1, bp->cp->requestedHeight);
687  if(lastHeight != bp->cp->requestedHeight) {
688  ResizeTray(bp->cp->tray);
689  }
690  }
691  ComputeItemSize(bp);
692  Render(bp);
693  }
694 }
695 
697 void SignalTaskbar(const TimeType *now, int x, int y, Window w, void *data)
698 {
699 
700  TaskBarType *bp = (TaskBarType*)data;
701  TaskEntry *ep;
702 
703  if(w == bp->cp->tray->window &&
704  abs(bp->mousex - x) < settings.doubleClickDelta &&
705  abs(bp->mousey - y) < settings.doubleClickDelta) {
706  if(GetTimeDifference(now, &bp->mouseTime) >= settings.popupDelay) {
707  ep = GetEntry(bp, x - bp->cp->screenx, y - bp->cp->screeny);
708  if(settings.groupTasks) {
709  if(ep && ep->clients->client->className) {
711  }
712  } else {
713  if(ep && ep->clients->client->name) {
714  ShowPopup(x, y, ep->clients->client->name, POPUP_TASK);
715  }
716  }
717  }
718  }
719 
720 }
721 
723 void Render(const TaskBarType *bp)
724 {
725  TaskEntry *tp;
726  char *displayName;
727  ButtonNode button;
728  int x, y;
729 
730  if(JUNLIKELY(shouldExit)) {
731  return;
732  }
733 
734  ClearTrayDrawable(bp->cp);
735  if(!taskEntries) {
736  UpdateSpecificTray(bp->cp->tray, bp->cp);
737  return;
738  }
739 
740  ResetButton(&button, bp->cp->pixmap);
742  button.font = FONT_TASKLIST;
743  button.height = bp->itemHeight;
744  button.width = bp->itemWidth;
745  button.text = NULL;
746 
747  x = 0;
748  y = 0;
749  for(tp = taskEntries; tp; tp = tp->next) {
750 
751  if(!ShouldShowEntry(tp)) {
752  continue;
753  }
754 
755  /* Check for an active or urgent window and count clients. */
756  ClientEntry *cp;
757  unsigned clientCount = 0;
758  button.type = BUTTON_TASK;
759  for(cp = tp->clients; cp; cp = cp->next) {
760  if(ShouldFocus(cp->client, 0)) {
761  const char flash = (cp->client->state.status & STAT_FLASH) != 0;
762  const char active = (cp->client->state.status & STAT_ACTIVE)
764  if(flash || active) {
765  if(button.type == BUTTON_TASK) {
766  button.type = BUTTON_TASK_ACTIVE;
767  } else {
768  button.type = BUTTON_TASK;
769  }
770  }
771  clientCount += 1;
772  }
773  }
774  button.x = x;
775  button.y = y;
776  if(!tp->clients->client->icon) {
777  button.icon = GetDefaultIcon();
778  } else {
779  button.icon = tp->clients->client->icon;
780  }
781  displayName = NULL;
782  if(bp->labeled) {
784  if(clientCount != 1) {
785  const size_t len = strlen(tp->clients->client->className) + 16;
786  displayName = Allocate(len);
787  snprintf(displayName, len, "%s (%u)",
788  tp->clients->client->className, clientCount);
789  button.text = displayName;
790  } else {
791  button.text = tp->clients->client->className;
792  }
793  } else {
794  button.text = tp->clients->client->name;
795  }
796  }
797  DrawButton(&button);
798  if(displayName) {
799  Release(displayName);
800  }
801 
802  if(bp->layout == LAYOUT_HORIZONTAL) {
803  x += bp->itemWidth;
804  } else {
805  y += bp->itemHeight;
806  }
807  }
808 
809  UpdateSpecificTray(bp->cp->tray, bp->cp);
810 
811 }
812 
814 void FocusNext(void)
815 {
816  TaskEntry *tp;
817 
818  /* Find the current entry. */
819  for(tp = taskEntries; tp; tp = tp->next) {
820  ClientEntry *cp;
821  for(cp = tp->clients; cp; cp = cp->next) {
823  if(ShouldFocus(cp->client, 1)) {
824  if(cp->client->state.status & STAT_ACTIVE) {
825  cp = cp->next;
826  goto ClientFound;
827  }
828  }
829  }
830  }
831  }
832 ClientFound:
833 
834  /* Move to the next group. */
835  if(tp) {
836  do {
837  tp = tp->next;
838  } while(tp && !ShouldFocusEntry(tp));
839  }
840  if(!tp) {
841  /* Wrap around; start at the beginning. */
842  for(tp = taskEntries; tp; tp = tp->next) {
843  if(ShouldFocusEntry(tp)) {
844  break;
845  }
846  }
847  }
848 
849  /* Focus the group if one exists. */
850  if(tp) {
851  FocusGroup(tp);
852  }
853 }
854 
856 void FocusPrevious(void)
857 {
858  TaskEntry *tp;
859 
860  /* Find the current entry. */
861  for(tp = taskEntries; tp; tp = tp->next) {
862  ClientEntry *cp;
863  for(cp = tp->clients; cp; cp = cp->next) {
865  if(ShouldFocus(cp->client, 1)) {
866  if(cp->client->state.status & STAT_ACTIVE) {
867  cp = cp->next;
868  goto ClientFound;
869  }
870  }
871  }
872  }
873  }
874 ClientFound:
875 
876  /* Move to the previous group. */
877  if(tp) {
878  do {
879  tp = tp->prev;
880  } while(tp && !ShouldFocusEntry(tp));
881  }
882  if(!tp) {
883  /* Wrap around; start at the end. */
884  for(tp = taskEntriesTail; tp; tp = tp->prev) {
885  if(ShouldFocusEntry(tp)) {
886  break;
887  }
888  }
889  }
890 
891  /* Focus the group if one exists. */
892  if(tp) {
893  FocusGroup(tp);
894  }
895 }
896 
898 char ShouldShowEntry(const TaskEntry *tp)
899 {
900  const ClientEntry *cp;
901  for(cp = tp->clients; cp; cp = cp->next) {
902  if(ShouldFocus(cp->client, 0)) {
903  return 1;
904  }
905  }
906  return 0;
907 }
908 
911 {
912  const ClientEntry *cp;
913  for(cp = tp->clients; cp; cp = cp->next) {
915  if(ShouldFocus(cp->client, 1)) {
916  return 1;
917  }
918  }
919  }
920  return 0;
921 }
922 
924 TaskEntry *GetEntry(TaskBarType *bar, int x, int y)
925 {
926  TaskEntry *tp;
927  int offset;
928 
929  offset = 0;
930  for(tp = taskEntries; tp; tp = tp->next) {
931  if(!ShouldShowEntry(tp)) {
932  continue;
933  }
934  if(bar->layout == LAYOUT_HORIZONTAL) {
935  offset += bar->itemWidth;
936  if(x < offset) {
937  return tp;
938  }
939  } else {
940  offset += bar->itemHeight;
941  if(y < offset) {
942  return tp;
943  }
944  }
945  }
946 
947  return NULL;
948 }
949 
951 void SetMaxTaskBarItemWidth(TrayComponentType *cp, const char *value)
952 {
953  TaskBarType *bp = (TaskBarType*)cp->object;
954  int temp;
955 
956  Assert(cp);
957  Assert(value);
958 
959  temp = atoi(value);
960  if(JUNLIKELY(temp < 0)) {
961  Warning(_("invalid maxwidth for TaskList: %s"), value);
962  return;
963  }
964  bp->maxItemWidth = temp;
965 }
966 
968 void SetTaskBarHeight(TrayComponentType *cp, const char *value)
969 {
970  TaskBarType *bp = (TaskBarType*)cp->object;
971  int temp;
972 
973  temp = atoi(value);
974  if(JUNLIKELY(temp < 0)) {
975  Warning(_("invalid height for TaskList: %s"), value);
976  return;
977  }
978  bp->userHeight = temp;
979 }
980 
982 void SetTaskBarLabeled(TrayComponentType *cp, char labeled)
983 {
984  TaskBarType *bp = (TaskBarType*)cp->object;
985  bp->labeled = labeled;
986 }
987 
990 {
991  TaskEntry *tp;
992  ClientNode *client;
993  Window *windows;
994  unsigned int count;
995  int layer;
996 
997  /* Determine how much we need to allocate. */
998  if(clientCount == 0) {
999  windows = NULL;
1000  } else {
1001  windows = AllocateStack(clientCount * sizeof(Window));
1002  }
1003 
1004  /* Set _NET_CLIENT_LIST */
1005  count = 0;
1006  for(tp = taskEntries; tp; tp = tp->next) {
1007  ClientEntry *cp;
1008  for(cp = tp->clients; cp; cp = cp->next) {
1009  windows[count] = cp->client->window;
1010  count += 1;
1011  }
1012  }
1013  Assert(count <= clientCount);
1015  XA_WINDOW, 32, PropModeReplace,
1016  (unsigned char*)windows, count);
1017 
1018  /* Set _NET_CLIENT_LIST_STACKING */
1019  count = 0;
1020  for(layer = FIRST_LAYER; layer <= LAST_LAYER; layer++) {
1021  for(client = nodes[layer]; client; client = client->next) {
1022  windows[count] = client->window;
1023  count += 1;
1024  }
1025  }
1027  XA_WINDOW, 32, PropModeReplace,
1028  (unsigned char*)windows, count);
1029 
1030  if(windows != NULL) {
1031  ReleaseStack(windows);
1032  }
1033 
1034 }

joewing.net / Projects / JWM