1 /* Patched Version - all changes to this code have been done by
2 * Frank Hale with exception of the virtual desktop buttons. Somebody
3 * sent me a patch for that.
4 *
5 * frankhale@yahoo.com
6 * Date - 17 Nov 2001
7 */
8
9 /********************************************************
10 ** F***ing Small Panel 0.7 Copyright (c) 2000-2001 By **
11 ** Peter Zelezny <zed@linuxpower.org> **
12 ** See file COPYING for license details. **
13 ********************************************************/
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <time.h>
18 #include <sys/time.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21
22 #include <X11/Xlib.h>
23 #include <X11/Xproto.h>
24 #include <X11/Xutil.h>
25 #include <X11/Xatom.h>
26
27 #ifdef HAVE_XPM
28 #include <X11/xpm.h>
29 #include "icon.xpm"
30 #endif
31
32 #include "fspanel.h"
33
34 /* you can edit these */
35 #define MAX_TASK_WIDTH 145
36 #define PAGER_BOX_WIDTH 24
37 #define ICONWIDTH 16
38 #define ICONHEIGHT 16
39 #define WINHEIGHT 24
40 #define WINWIDTH (scr_width)
41 #define FONT_NAME "-*-lucida*-m*-r-*-*-12-*-*"
42
43 /* don't edit these */
44 #define TEXTPAD 6
45 #define left_arrow_x 18
46 #define right_arrow_x 30
47
48 Display *dd;
49 Window root_win;
50 Pixmap generic_icon;
51 Pixmap generic_mask;
52 GC fore_gc;
53 XFontStruct *xfs;
54 int scr_screen;
55 int scr_depth;
56 int scr_width;
57 int scr_height;
58 int text_y;
59 int pager_width;
60 /*int time_width;*/
61 Window win;
62
63 unsigned short cols[] = {
64 0xd75c, 0xd75c, 0xd75c, /* 0. light gray */
65 0xbefb, 0xbaea, 0xbefb, /* 1. mid gray */
66 0xaefb, 0xaaea, 0xaefb, /* 2. dark gray */
67 0xefbe, 0xefbe, 0xefbe, /* 3. white */
68 0x8617, 0x8207, 0x8617, /* 4. darkest gray */
69 0x0000, 0x0000, 0x0000 /* 5. black */
70 };
71
72 #define PALETTE_COUNT (sizeof (cols) / sizeof (cols[0]) / 3)
73
74 unsigned long palette[PALETTE_COUNT];
75
76 char *atom_names[] = {
77 "KWM_WIN_ICON",
78 "_MOTIF_WM_HINTS",
79 "_NET_CURRENT_DESKTOP",
80 "_WIN_WORKSPACE",
81 "_NET_WM_STATE_SKIP_TASKBAR",
82 "_NET_WM_STATE_SKIP_PAGER",
83 "_WIN_HINTS",
84 /*"_NET_WM_STRUT",*/
85 "_WIN_LAYER",
86 "_NET_CLIENT_LIST",
87 "_WIN_CLIENT_LIST",
88 "_NET_NUMBER_OF_DESKTOPS",
89 "_WIN_WORKSPACE_COUNT",
90 "_NET_WM_STATE_STICKY",
91 "_WIN_STATE",
92 "WM_STATE"
93 };
94
95 #define ATOM_COUNT (sizeof (atom_names) / sizeof (atom_names[0]))
96
97 Atom net_wm_strut;
98
99 Atom atoms[ATOM_COUNT];
100
101 #define atom_KWM_WIN_ICON atoms[0]
102 #define atom__MOTIF_WM_HINTS atoms[1]
103 #define atom__NET_CURRENT_DESKTOP atoms[2]
104 #define atom__WIN_WORKSPACE atoms[3]
105 #define atom__NET_WM_STATE_SKIP_TASKBAR atoms[4]
106 #define atom__NET_WM_STATE_SKIP_PAGER atoms[5]
107 #define atom__WIN_HINTS atoms[6]
108 /*#define atom__NET_WM_STRUT atoms[ ]*/
109 #define atom__WIN_LAYER atoms[7]
110 #define atom__NET_CLIENT_LIST atoms[8]
111 #define atom__WIN_CLIENT_LIST atoms[9]
112 #define atom__NET_NUMBER_OF_DESKTOPS atoms[10]
113 #define atom__WIN_WORKSPACE_COUNT atoms[11]
114 #define atom__NET_WM_STATE_STICKY atoms[12]
115 #define atom__WIN_STATE atoms[13]
116 #define atom_WM_STATE atoms[14]
117
118
119 /*************************************/
120 /* CODE BELOW GETS/SETS X PROPERTIES */
121 /*************************************/
122
switch_desk(taskbar * tb,int rel)123 void switch_desk (taskbar * tb, int rel)
124 {
125 XClientMessageEvent xev;
126 unsigned long *data;
127 int want = tb->my_desktop + rel, protocol;
128
129 if (want < 0)
130 return;
131
132 /* try unified window spec first (protocol 0) */
133 protocol = 0;
134 data = get_prop_data (root_win, atom__NET_NUMBER_OF_DESKTOPS, XA_CARDINAL, 0);
135
136 /* failed, let's try gnome (protocol 1) */
137 if (!data)
138 {
139 protocol = 1;
140 data = get_prop_data (root_win, atom__WIN_WORKSPACE_COUNT, XA_CARDINAL, 0);
141 }
142
143 if (data)
144 {
145 register unsigned long max_desks = *data;
146 XFree (data);
147 if (max_desks <= want)
148 return;
149 }
150
151 xev.type = ClientMessage;
152 xev.window = root_win;
153
154 /* send it with the right protocol */
155 if (protocol == 0)
156 xev.message_type = atom__NET_CURRENT_DESKTOP;
157 else if (protocol == 1)
158 xev.message_type = atom__WIN_WORKSPACE;
159
160 xev.format = 32;
161 xev.data.l[0] = want;
162 XSendEvent (dd, root_win, False, SubstructureNotifyMask, (XEvent *) &xev);
163 }
164
set_bottom_strut()165 void set_bottom_strut()
166 {
167 CARD32 strut[] = { 0,0,0,WINHEIGHT+3 };
168 XChangeProperty (dd, win, net_wm_strut, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &strut, 4);
169 }
170
set_top_strut()171 void set_top_strut()
172 {
173 CARD32 strut[] = { 0,0,WINHEIGHT+1,0 };
174 XChangeProperty (dd, win, net_wm_strut, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &strut, 4);
175 }
176
turn_off_strut()177 void turn_off_strut()
178 {
179 XDeleteProperty(dd, win, net_wm_strut);
180 }
181
get_prop_data(Window win,Atom prop,Atom type,int * items)182 unsigned long*get_prop_data (Window win, Atom prop, Atom type, int *items)
183 {
184 Atom type_ret;
185 int format_ret;
186 unsigned long items_ret;
187 unsigned long after_ret;
188 unsigned char *prop_data;
189
190 prop_data = 0;
191
192 XGetWindowProperty (dd, win, prop, 0, 0x7fffffff, False,
193 type, &type_ret, &format_ret, &items_ret,
194 &after_ret, &prop_data);
195 if (items)
196 *items = items_ret;
197
198 return (unsigned long *)prop_data;
199 }
200
get_task_hinticon(task * tk)201 void get_task_hinticon (task *tk)
202 {
203 XWMHints *hin;
204
205 tk->icon = None;
206 tk->mask = None;
207
208 hin = (XWMHints *) get_prop_data (tk->win, XA_WM_HINTS, XA_WM_HINTS, 0);
209 if (hin)
210 {
211 if ((hin->flags & IconPixmapHint))
212 {
213 if ((hin->flags & IconMaskHint))
214 {
215 tk->mask = hin->icon_mask;
216 }
217
218 tk->icon = hin->icon_pixmap;
219 tk->icon_copied = 1;
220 scale_icon (tk);
221 }
222 XFree (hin);
223 }
224
225 if (tk->icon == None)
226 {
227 tk->icon = generic_icon;
228 tk->mask = generic_mask;
229 }
230 }
231
get_task_kdeicon(task * tk)232 void get_task_kdeicon (task *tk)
233 {
234 unsigned long *data;
235
236 data = get_prop_data (tk->win, atom_KWM_WIN_ICON, atom_KWM_WIN_ICON, 0);
237 if (data)
238 {
239 tk->icon = data[0];
240 tk->mask = data[1];
241 XFree (data);
242 }
243 }
244
find_desktop(Window win)245 int find_desktop (Window win)
246 {
247 int desk = 0;
248 unsigned long *data;
249
250 /* try unified window spec first */
251 data = get_prop_data (win, atom__NET_CURRENT_DESKTOP, XA_CARDINAL, 0);
252
253 if (!data)
254 /* failed, let's try gnome */
255 data = get_prop_data (win, atom__WIN_WORKSPACE, XA_CARDINAL, 0);
256
257 if (data)
258 {
259 desk = *data;
260 XFree (data);
261 }
262 return desk;
263 }
264
is_hidden(Window win)265 int is_hidden (Window win)
266 {
267 unsigned long *data;
268 int ret = 0;
269
270 /* try unified window spec first (two hints) */
271 data = get_prop_data (win, atom__NET_WM_STATE_SKIP_TASKBAR, XA_CARDINAL, 0);
272
273 if (!data)
274 data = get_prop_data (win, atom__NET_WM_STATE_SKIP_PAGER, XA_CARDINAL, 0);
275
276 if (data)
277 /* if we got one, we're done */
278 {
279 ret = 1;
280 XFree (data);
281 }
282
283 else
284 /* failed, let's try gnome (one hint, three bits) */
285 {
286 data = get_prop_data (win, atom__WIN_HINTS, XA_CARDINAL, 0);
287 if (data)
288 {
289 if (((*data) & WIN_HINTS_SKIP_FOCUS) || ((*data) & WIN_HINTS_SKIP_WINLIST) || ((*data) & WIN_HINTS_SKIP_TASKBAR))
290 /* if we got one, we're done */
291 ret = 1;
292 XFree (data);
293 }
294 }
295 return ret;
296 }
297
is_iconified(Window win)298 int is_iconified (Window win)
299 {
300 unsigned long *data;
301 int ret = 0;
302
303 data = get_prop_data (win, atom_WM_STATE, atom_WM_STATE, 0);
304 if (data)
305 {
306 if (data[0] == IconicState)
307 ret = 1;
308 XFree (data);
309 }
310 return ret;
311 }
312
set_prop(Window win,Atom at,long val)313 void set_prop (Window win, Atom at, long val)
314 {
315 XChangeProperty (dd, win, at, XA_CARDINAL, 32,
316 PropModeReplace, (unsigned char *) &val, 1);
317 }
318
319 /*************************************/
320 /* CODE ABOVE GETS/SETS X PROPERTIES */
321 /*************************************/
322
323
324
325
326
327
328
329 /**************************************/
330 /* CODE BELOW DOES GRAPHICS OPERATIONS*/
331 /**************************************/
332
gui_init(void)333 void gui_init (void)
334 {
335 XGCValues gcv;
336 XColor xcl;
337 int i, j;
338 char *fontname;
339
340 i = j = 0;
341 do
342 {
343 xcl.red = cols[i];
344 i++;
345 xcl.green = cols[i];
346 i++;
347 xcl.blue = cols[i];
348 i++;
349 XAllocColor (dd, DefaultColormap (dd, scr_screen), &xcl);
350 palette[j] = xcl.pixel;
351 j++;
352 }
353 while (j < PALETTE_COUNT);
354
355 fontname = FONT_NAME;
356 do
357 {
358 xfs = XLoadQueryFont (dd, fontname);
359 fontname = "fixed";
360 }
361 while (!xfs);
362
363 /*time_width = XTextWidth (xfs, "88:88", 5); */
364 #define time_width (35)
365 text_y = xfs->ascent + ((WINHEIGHT - xfs->ascent) / 2);
366
367 gcv.font = xfs->fid;
368 gcv.graphics_exposures = False;
369 fore_gc = XCreateGC (dd, root_win, GCFont | GCGraphicsExposures, &gcv);
370
371 #ifdef HAVE_XPM
372 XpmCreatePixmapFromData (dd, root_win, icon_xpm, &generic_icon,
373 &generic_mask, NULL);
374 #else
375 generic_icon = 0;
376 #endif
377 }
378
set_foreground(int index)379 void set_foreground (int index)
380 {
381 XSetForeground (dd, fore_gc, palette[index]);
382 }
383
draw_line(taskbar * tb,int x,int y,int a,int b)384 void draw_line (taskbar *tb, int x, int y, int a, int b)
385 {
386 XDrawLine (dd, tb->win, fore_gc, x, y, a, b);
387 }
388
fill_rect(taskbar * tb,int x,int y,int a,int b)389 void fill_rect (taskbar *tb, int x, int y, int a, int b)
390 {
391 XFillRectangle (dd, tb->win, fore_gc, x, y, a, b);
392 }
393
scale_icon(task * tk)394 void scale_icon (task *tk)
395 {
396 int xx, yy, x, y;
397 unsigned int w, h, d, bw;
398 Pixmap pix, mk = None;
399 XGCValues gcv;
400 GC mgc=None;
401
402 XGetGeometry (dd, tk->icon, &pix, &x, &y, &w, &h, &bw, &d);
403 pix = XCreatePixmap (dd, tk->win, ICONWIDTH, ICONHEIGHT, scr_depth);
404
405 if (tk->mask != None)
406 {
407 mk = XCreatePixmap (dd, tk->win, ICONWIDTH, ICONHEIGHT, 1);
408 gcv.subwindow_mode = IncludeInferiors;
409 gcv.graphics_exposures = False;
410 mgc = XCreateGC (dd, mk, GCGraphicsExposures | GCSubwindowMode, &gcv);
411 }
412
413 set_foreground (3);
414
415 /* this is my simple & dirty scaling routine */
416 for (y = ICONHEIGHT - 1; y >= 0; y--)
417 {
418 yy = (y * h) / ICONHEIGHT;
419 for (x = ICONWIDTH - 1; x >= 0; x--)
420 {
421 xx = (x * w) / ICONWIDTH;
422 if (d != scr_depth)
423 XCopyPlane (dd, tk->icon, pix, fore_gc, xx, yy, 1, 1, x, y, 1);
424 else
425 XCopyArea (dd, tk->icon, pix, fore_gc, xx, yy, 1, 1, x, y);
426 if (mk != None)
427 XCopyArea (dd, tk->mask, mk, mgc, xx, yy, 1, 1, x, y);
428 }
429 }
430
431 if (mk != None)
432 {
433 XFreeGC (dd, mgc);
434 tk->mask = mk;
435 }
436
437 tk->icon = pix;
438 }
439
gui_draw_vline(taskbar * tb,int x)440 void gui_draw_vline (taskbar * tb, int x)
441 {
442 set_foreground (4);
443 draw_line (tb, x, 0, x, WINHEIGHT);
444 set_foreground (3);
445 draw_line (tb, x + 1, 0, x + 1, WINHEIGHT);
446 }
447
gui_draw_task(taskbar * tb,task * tk)448 void gui_draw_task (taskbar * tb, task * tk)
449 {
450 int len;
451 int x = tk->pos_x;
452 int taskw = tk->width;
453
454 if (!tk->name)
455 return;
456
457 gui_draw_vline (tb, x);
458
459 /*set_foreground (3); *//* it's already 3 from gui_draw_vline() */
460 draw_line (tb, x + 1, 0, x + taskw, 0);
461
462 set_foreground (1);
463 draw_line (tb, x + 1, WINHEIGHT - 1, x + taskw, WINHEIGHT - 1);
464
465 if (tk->focused)
466 {
467 x++;
468 /*set_foreground (1);*/ /* mid gray */
469 fill_rect (tb, x + 3, 3, taskw - 5, WINHEIGHT - 6);
470 set_foreground (3); /* white */
471 draw_line (tb, x + 2, WINHEIGHT - 2, x + taskw - 2, WINHEIGHT - 2);
472 draw_line (tb, x + taskw - 2, 2, x + taskw - 2, WINHEIGHT - 2);
473 set_foreground (0);
474 draw_line (tb, x + 1, 2, x + 1, WINHEIGHT - 2);
475 set_foreground (4); /* darkest gray */
476 draw_line (tb, x + 2, 2, x + taskw - 2, 2);
477 draw_line (tb, x + 2, 2, x + 2, WINHEIGHT - 3);
478 } else
479 {
480 set_foreground (0); /* mid gray */
481 fill_rect (tb, x + 2, 1, taskw - 1, WINHEIGHT - 2);
482 }
483
484 {
485 register int text_x = x + TEXTPAD + TEXTPAD + ICONWIDTH;
486
487 /* check how many chars can fit */
488 len = strlen (tk->name);
489 while (XTextWidth (xfs, tk->name, len) >= taskw - (text_x - x) - 2
490 && len > 0)
491 len--;
492
493 if (tk->iconified)
494 {
495 /* draw task's name dark (iconified) */
496 set_foreground (3);
497 XDrawString (dd, tb->win, fore_gc, text_x, text_y + 1, tk->name,
498 len);
499 set_foreground (4);
500 } else
501 {
502 set_foreground (5);
503 }
504
505 /* draw task's name here */
506 XDrawString (dd, tb->win, fore_gc, text_x, text_y, tk->name, len);
507 }
508
509 #ifndef HAVE_XPM
510 if (!tk->icon)
511 return;
512 #endif
513
514 /* draw the task's icon */
515 XSetClipMask (dd, fore_gc, tk->mask);
516 XSetClipOrigin (dd, fore_gc, x + TEXTPAD, (WINHEIGHT - ICONHEIGHT) / 2);
517 XCopyArea (dd, tk->icon, tb->win, fore_gc, 0, 0, ICONWIDTH, ICONHEIGHT,
518 x + TEXTPAD, (WINHEIGHT - ICONHEIGHT) / 2);
519 XSetClipMask (dd, fore_gc, None);
520 }
521
gui_draw_clock(taskbar * tb)522 void gui_draw_clock (taskbar * tb)
523 {
524 char *time_str;
525 time_t now;
526 int width, old_x, x = WINWIDTH - time_width - (TEXTPAD * 4);
527
528 old_x = x;
529
530 width = WINWIDTH - x - 2;
531
532 now = time (0);
533 time_str = ctime (&now) + 11;
534
535 gui_draw_vline (tb, x);
536 x += TEXTPAD;
537
538 /*set_foreground (3); *//* white *//* it's already 3 from gui_draw_vline() */
539 draw_line (tb, x + 1, WINHEIGHT - 2, old_x + width - TEXTPAD,
540 WINHEIGHT - 2);
541 draw_line (tb, old_x + width - TEXTPAD, 2, old_x + width - TEXTPAD,
542 WINHEIGHT - 2);
543
544 set_foreground (1); /* mid gray */
545 fill_rect (tb, x + 1, 2, width - (TEXTPAD * 2) - 1, WINHEIGHT - 4);
546
547 set_foreground (4); /* darkest gray */
548 draw_line (tb, x, 2, x + width - (TEXTPAD * 2) - 1, 2);
549 draw_line (tb, x, 2, x, WINHEIGHT - 2);
550
551 set_foreground (5);
552 XDrawString (dd, tb->win, fore_gc, x + TEXTPAD - 1, text_y,
553 time_str, 5);
554 }
555
draw_dot(Window win,int x,int y)556 void draw_dot (Window win, int x, int y)
557 {
558 set_foreground (4);
559 XDrawPoint (dd, win, fore_gc, x, y);
560 set_foreground (3);
561 XDrawPoint (dd, win, fore_gc, x + 1, y + 1);
562 }
563
draw_grill(Window win,int x)564 void draw_grill (Window win, int x)
565 {
566 int y = 0;
567 while (y < WINHEIGHT - 4)
568 {
569 y += 3;
570 draw_dot (win, x + 3, y);
571 draw_dot (win, x, y);
572 }
573 }
574
gui_draw_pager(taskbar * tb)575 void gui_draw_pager (taskbar * tb)
576 {
577 int i, loc, text_x;
578 unsigned long *data;
579 char label[2];
580
581 /* try unified window spec first */
582 data= get_prop_data(root_win, atom__NET_NUMBER_OF_DESKTOPS, XA_CARDINAL, 0);
583
584 if (!data)
585 /* failed, let's try gnome */
586 data= get_prop_data(root_win, atom__WIN_WORKSPACE_COUNT, XA_CARDINAL, 0);
587
588 if (data)
589 {
590 register unsigned long max_desks = *data;
591 XFree(data);
592 pager_width = PAGER_BOX_WIDTH * max_desks;
593 for (i=0; i < max_desks; i++)
594 {
595 loc = 8 + (i * PAGER_BOX_WIDTH);
596 label[0] = i + '0';
597 text_x = loc + (PAGER_BOX_WIDTH / 2) - (XTextWidth(xfs,label,1)/2);
598 if (i == tb->my_desktop)
599 {
600 set_foreground(1);
601 fill_rect (tb, loc + 3, 2, PAGER_BOX_WIDTH - 5, WINHEIGHT - 3 );
602 set_foreground (4);
603 draw_line (tb, loc + 2, 1, loc + 2, WINHEIGHT - 2 );
604 draw_line (tb, loc + 3, 1, loc + PAGER_BOX_WIDTH - 2, 1 );
605 set_foreground (3);
606 draw_line (tb, loc + 3, WINHEIGHT - 2 , loc + PAGER_BOX_WIDTH - 2, WINHEIGHT - 2 );
607 draw_line (tb, loc + PAGER_BOX_WIDTH - 2, WINHEIGHT - 3, loc + PAGER_BOX_WIDTH - 2, 2 );
608 set_foreground(5);
609 XDrawString(dd, tb->win, fore_gc, text_x, text_y, label, 1);
610 }
611 else
612 {
613 set_foreground(0);
614 fill_rect (tb, loc + 2, 1, PAGER_BOX_WIDTH - 3, WINHEIGHT - 2 );
615 set_foreground(5);
616 XDrawString(dd, tb->win, fore_gc, text_x, text_y, label, 1);
617 }
618 gui_draw_vline(tb, loc + PAGER_BOX_WIDTH);
619 }
620 }
621 else
622 {
623 pager_width = 0;
624 }
625 }
626
gui_draw_taskbar(taskbar * tb)627 void gui_draw_taskbar (taskbar * tb)
628 {
629 task *tk;
630 int x, width, taskw;
631 int under = 0;
632
633 set_foreground (5); /* black */
634 gui_draw_pager(tb);
635
636 width = WINWIDTH - pager_width - 8 - time_width - (TEXTPAD * 4);
637 x = pager_width + 12;
638
639 if (tb->num_tasks == 0)
640 goto clear;
641
642 taskw = width / tb->num_tasks;
643 if (taskw > MAX_TASK_WIDTH)
644 {
645 taskw = MAX_TASK_WIDTH;
646 under = 1;
647 }
648
649 tk = tb->task_list;
650 while (tk)
651 {
652 tk->pos_x = x;
653 tk->width = taskw - 1;
654 gui_draw_task (tb, tk);
655 x += taskw;
656 tk = tk->next;
657 }
658
659 if (under)
660 {
661 clear:
662 gui_draw_vline (tb, x);
663 set_foreground (0);
664 fill_rect (tb, x + 2, 0, WINWIDTH, WINHEIGHT);
665 }
666
667 gui_draw_clock (tb);
668
669 /*gui_draw_vline (tb, 8);
670 gui_draw_vline (tb, 74);*/
671
672 gui_draw_vline (tb, 8);
673 gui_draw_vline (tb, pager_width + 12);
674
675 draw_grill (tb->win, 2);
676 draw_grill (tb->win, WINWIDTH - 6);
677 }
678
679 /**************************************/
680 /* CODE ABOVE DOES GRAPHICS OPERATIONS*/
681 /**************************************/
682
gui_create_taskbar(void)683 taskbar *gui_create_taskbar (void)
684 {
685 taskbar *tb;
686 MWMHints mwm;
687 XSizeHints size_hints;
688 XWMHints wmhints;
689 XSetWindowAttributes att;
690
691 att.background_pixel = palette[0];
692 att.event_mask = ButtonPressMask | ExposureMask;
693
694 win = XCreateWindow (
695 /* display */ dd,
696 /* parent */ root_win,
697 /* x */ 0,
698 /* y */ scr_height - WINHEIGHT,
699 /* width */ WINWIDTH,
700 /* height */ WINHEIGHT,
701 /* border */ 0,
702 /* depth */ CopyFromParent,
703 /* class */ InputOutput,
704 /* visual */ CopyFromParent,
705 /*value mask*/ CWBackPixel | CWEventMask,
706 /* attribs */ &att);
707
708
709 set_bottom_strut();
710
711 /* don't let any windows cover fspanel */
712 set_prop (win, atom__WIN_LAYER, 10); /* WIN_LAYER_ABOVE_DOCK */
713
714 set_prop (win, atom__WIN_STATE, WIN_STATE_STICKY |
715 WIN_STATE_FIXED_POSITION);
716
717 set_prop (win, atom__NET_WM_STATE_STICKY, 0);
718
719 set_prop (win, atom__WIN_HINTS, WIN_HINTS_SKIP_FOCUS |
720 WIN_HINTS_SKIP_WINLIST |
721 WIN_HINTS_SKIP_TASKBAR | WIN_HINTS_DO_NOT_COVER);
722
723 set_prop (win, atom__NET_WM_STATE_SKIP_TASKBAR, 0);
724 set_prop (win, atom__NET_WM_STATE_SKIP_PAGER, 0);
725
726 /* borderless motif hint */
727 memset (&mwm, 0, sizeof (mwm));
728 mwm.flags = MWM_HINTS_DECORATIONS;
729 XChangeProperty (dd, win, atom__MOTIF_WM_HINTS,
730 atom__MOTIF_WM_HINTS, 32, PropModeReplace,
731 (unsigned char *) &mwm, sizeof (MWMHints) / 4);
732
733 /* make sure the WM obeys our window position */
734 size_hints.flags = PPosition;
735 /*XSetWMNormalHints (dd, win, &size_hints);*/
736 XChangeProperty (dd, win, XA_WM_NORMAL_HINTS,
737 XA_WM_SIZE_HINTS, 32, PropModeReplace,
738 (unsigned char *) &size_hints, sizeof (XSizeHints) / 4);
739
740 /* make our window unfocusable */
741 wmhints.flags = InputHint;
742 wmhints.input = 0;
743 /*XSetWMHints (dd, win, &wmhints);*/
744 XChangeProperty (dd, win, XA_WM_HINTS,
745 XA_WM_HINTS, 32, PropModeReplace,
746 (unsigned char *) &wmhints, sizeof (XWMHints) / 4);
747
748 XMapWindow (dd, win);
749
750 tb = (taskbar *)calloc (1, sizeof (taskbar));
751 tb->win = win;
752
753 return tb;
754 }
755
add_task(taskbar * tb,Window win,int focus)756 void add_task (taskbar * tb, Window win, int focus)
757 {
758 task *tk, *list;
759
760 /* is this window on a different desktop? */
761 if (tb->my_desktop != find_desktop (win) || is_hidden (win))
762 return;
763
764 tk = (task *)calloc (1, sizeof (task));
765 tk->win = win;
766 tk->focused = focus;
767 tk->name = (char *)(void *)get_prop_data (win, XA_WM_NAME, XA_STRING, 0);
768 tk->iconified = is_iconified (win);
769
770 get_task_kdeicon (tk);
771 if (tk->icon == None)
772 get_task_hinticon (tk);
773
774 XSelectInput (dd, win, PropertyChangeMask | FocusChangeMask |
775 StructureNotifyMask);
776
777 /* now append it to our linked list */
778 tb->num_tasks++;
779
780 list = tb->task_list;
781 if (!list)
782 {
783 tb->task_list = tk;
784 return;
785 }
786 while (1)
787 {
788 if (!list->next)
789 {
790 list->next = tk;
791 return;
792 }
793 list = list->next;
794 }
795 }
796
797
move_taskbar(taskbar * tb)798 void move_taskbar (taskbar * tb)
799 {
800 int x, y;
801
802 x = y = 0;
803
804 if (tb->hidden)
805 x = WINWIDTH - TEXTPAD;
806
807 if (!tb->at_top)
808 y = scr_height - WINHEIGHT;
809
810 XMoveWindow (dd, tb->win, x, y);
811 }
812
toggle_placement(taskbar * tb)813 void toggle_placement(taskbar * tb)
814 {
815 if (tb->hidden)
816 tb->hidden = 0;
817 else
818 {
819 if(tb->at_top)
820 set_bottom_strut();
821 else
822 set_top_strut();
823
824 tb->at_top = !tb->at_top;
825 }
826
827 move_taskbar (tb);
828 }
829
find_task(taskbar * tb,Window win)830 task * find_task (taskbar * tb, Window win)
831 {
832 task *list = tb->task_list;
833 while (list)
834 {
835 if (list->win == win)
836 return list;
837 list = list->next;
838 }
839 return 0;
840 }
841
del_task(taskbar * tb,Window win)842 void del_task (taskbar * tb, Window win)
843 {
844 task *next, *prev = 0, *list = tb->task_list;
845
846 while (list)
847 {
848 next = list->next;
849 if (list->win == win)
850 {
851 /* unlink and free this task */
852 tb->num_tasks--;
853 if (list->icon_copied)
854 {
855 XFreePixmap (dd, list->icon);
856 if (list->mask != None)
857 XFreePixmap (dd, list->mask);
858 }
859 if (list->name)
860 XFree (list->name);
861 free (list);
862 if (prev == 0)
863 tb->task_list = next;
864 else
865 prev->next = next;
866 return;
867 }
868 prev = list;
869 list = next;
870 }
871 }
872
taskbar_read_clientlist(taskbar * tb)873 void taskbar_read_clientlist (taskbar * tb)
874 {
875 Window *win, focus_win;
876 int num, i, rev, desk, new_desk = 0;
877 task *list, *next;
878
879 desk = find_desktop (root_win);
880 if (desk != tb->my_desktop)
881 {
882 new_desk = 1;
883 tb->my_desktop = desk;
884 }
885
886 XGetInputFocus (dd, &focus_win, &rev);
887
888 /* try unified window spec first */
889 win = get_prop_data (root_win, atom__NET_CLIENT_LIST, XA_WINDOW, &num);
890 if (!win)
891 {
892 /* failed, let's try gnome */
893 win = get_prop_data (root_win, atom__WIN_CLIENT_LIST, XA_CARDINAL, &num);
894 if (!win)
895 return;
896 }
897
898 /* remove windows that aren't in the _WIN_CLIENT_LIST anymore */
899 list = tb->task_list;
900 while (list)
901 {
902 list->focused = (focus_win == list->win);
903 next = list->next;
904
905 /*
906 if (!new_desk)
907 for (i = num - 1; i >= 0; i--)
908 if (list->win == win[i])
909 goto dontdel;
910 del_task (tb, list->win);
911 dontdel:
912 */
913
914 if (!new_desk)
915 for (i = num - 1; i >= 0; i--)
916 if (list->win == win[i])
917 goto second_check;
918 del_task (tb, list->win);
919 second_check:
920 /* Frank Hale <frankhale@yahoo.com>
921 * --------------------------------
922 * 29 July 2001
923 *
924 * Well what if the window was changed to another desktop? We need to get rid of it.
925 * Otherwise our window manager needs to switch to that desktop in order to get fspanel
926 * to update its task list properly.
927 *
928 */
929 if (tb->my_desktop != find_desktop (list->win) || is_hidden (list->win))
930 del_task(tb, list->win);
931
932 list = next;
933 }
934
935 /* add any new windows */
936 for (i = 0; i < num; i++)
937 {
938 if (!find_task (tb, win[i]))
939 add_task (tb, win[i], (win[i] == focus_win));
940 }
941
942 XFree (win);
943 }
944
handle_press(taskbar * tb,int x,int y)945 void handle_press (taskbar * tb, int x, int y)
946 {
947 task *tk;
948
949 /* clicked on pager */
950 if (x > 8 && x < pager_width + 8)
951 {
952 switch_desk (tb, ((x-8) /PAGER_BOX_WIDTH) - tb->my_desktop);
953 }
954
955 /* clicked left grill */
956 if (x < 6)
957 {
958 toggle_placement(tb);
959
960 return;
961 }
962
963 /* clicked right grill */
964 if (x + TEXTPAD > WINWIDTH)
965 {
966 tb->hidden = !tb->hidden;
967 move_taskbar (tb);
968 return;
969 }
970
971 tk = tb->task_list;
972 while (tk)
973 {
974 if (x > tk->pos_x && x < tk->pos_x + tk->width)
975 {
976 if (tk->iconified)
977 {
978 tk->iconified = 0;
979 tk->focused = 1;
980 XMapWindow (dd, tk->win);
981 } else
982 {
983 if (tk->focused)
984 {
985 tk->iconified = 1;
986 tk->focused = 0;
987 XIconifyWindow (dd, tk->win, scr_screen);
988 } else
989 {
990 tk->focused = 1;
991 XRaiseWindow (dd, tk->win);
992 XSetInputFocus (dd, tk->win, RevertToNone, CurrentTime);
993 }
994 }
995
996 XSync (dd, False);
997
998 gui_draw_task (tb, tk);
999 } else
1000 {
1001 if (tk->focused)
1002 {
1003 tk->focused = 0;
1004 gui_draw_task (tb, tk);
1005 }
1006 }
1007
1008 tk = tk->next;
1009 }
1010 }
1011
handle_focusin(taskbar * tb,Window win)1012 void handle_focusin (taskbar * tb, Window win)
1013 {
1014 task *tk;
1015
1016 tk = tb->task_list;
1017 while (tk)
1018 {
1019 if (tk->focused)
1020 {
1021 if (tk->win != win)
1022 {
1023 tk->focused = 0;
1024 gui_draw_task (tb, tk);
1025 }
1026 } else
1027 {
1028 if (tk->win == win)
1029 {
1030 tk->focused = 1;
1031 gui_draw_task (tb, tk);
1032 }
1033 }
1034 tk = tk->next;
1035 }
1036 }
1037
handle_propertynotify(taskbar * tb,Window win,Atom at)1038 void handle_propertynotify (taskbar * tb, Window win, Atom at)
1039 {
1040 task *tk;
1041
1042 /*
1043 * Hmm, the next if statement doesn't correctly
1044 * Update the taskbar when a window changes desktops.
1045 * The next 2 lines simply by pass whatever it was
1046 * the author was intending so that the taskbar gets
1047 * updated no matter what. Its a hack, probably not
1048 * optimal but I don't give a shit.
1049 *
1050 * Frank Hale
1051 */
1052 taskbar_read_clientlist (tb);
1053 gui_draw_taskbar (tb);
1054
1055 /*
1056 if (win == root_win)
1057 {
1058 if (at == atom__NET_CLIENT_LIST ||
1059 at == atom__WIN_CLIENT_LIST ||
1060 at == atom__NET_CURRENT_DESKTOP ||
1061 at == atom__WIN_WORKSPACE)
1062 {
1063 taskbar_read_clientlist (tb);
1064 gui_draw_taskbar (tb);
1065 }
1066 return;
1067 }
1068 */
1069
1070 tk = find_task (tb, win);
1071 if (!tk)
1072 return;
1073
1074 if (at == XA_WM_NAME)
1075 {
1076 /* window's title changed */
1077 if (tk->name)
1078 XFree (tk->name);
1079 tk->name = (char *)(void *)get_prop_data (tk->win, XA_WM_NAME, XA_STRING, 0);
1080 gui_draw_task (tb, tk);
1081 } else if (at == atom_WM_STATE)
1082 {
1083 /* iconified state changed? */
1084 if (is_iconified (tk->win) != tk->iconified)
1085 {
1086 tk->iconified = !tk->iconified;
1087 gui_draw_task (tb, tk);
1088 }
1089 } else if (at == XA_WM_HINTS)
1090 {
1091 /* some windows set their WM_HINTS icon after mapping */
1092 if (tk->icon == generic_icon)
1093 {
1094 get_task_hinticon (tk);
1095 gui_draw_task (tb, tk);
1096 }
1097 }
1098 }
1099
handle_error(Display * d,XErrorEvent * ev)1100 void handle_error (Display * d, XErrorEvent * ev)
1101 {
1102 }
1103
main(int argc,char * argv[])1104 int main (int argc, char *argv[])
1105 {
1106 taskbar *tb;
1107 XEvent ev;
1108 fd_set fd;
1109 struct timeval tv;
1110 int xfd;
1111 time_t now;
1112 struct tm *lt;
1113 int i;
1114 char *placement_str="";
1115 int placement=0;
1116
1117 /* Macro borrowed from aewm's code. */
1118 #define OPT_STR(name, variable) \
1119 if (strcmp(argv[i], name) == 0 && i+1<argc) { \
1120 variable = argv[++i]; \
1121 continue; \
1122 }
1123
1124 for (i = 1; i < argc; i++)
1125 {
1126 OPT_STR("-placement", placement_str)
1127
1128 if(strcmp(argv[i], "-usage")==0) {
1129 fprintf(stderr, "usage: fspanel [options]\n");
1130 fprintf(stderr, " options are: -placement (top|bottom), -usage\n");
1131 return 0;
1132 }
1133 }
1134
1135 // either top or bottom (default: bottom)
1136 if (strcmp(placement_str, "top")==0)
1137 placement = 1;
1138
1139 dd = XOpenDisplay (NULL);
1140 if (!dd)
1141 return 0;
1142
1143 scr_screen = DefaultScreen (dd);
1144 scr_depth = DefaultDepth (dd, scr_screen);
1145 scr_height = DisplayHeight (dd, scr_screen);
1146 scr_width = DisplayWidth (dd, scr_screen);
1147 root_win = RootWindow (dd, scr_screen);
1148
1149 /* helps us catch windows closing/opening */
1150 XSelectInput (dd, root_win, PropertyChangeMask);
1151
1152 XSetErrorHandler ((XErrorHandler) handle_error);
1153
1154 XInternAtoms (dd, atom_names, ATOM_COUNT, False, atoms);
1155
1156 net_wm_strut = XInternAtom (dd, "_NET_WM_STRUT", False);
1157
1158 gui_init ();
1159 tb = gui_create_taskbar ();
1160 xfd = ConnectionNumber (dd);
1161
1162 XSync (dd, False);
1163
1164 // if not top or bottom, the placement is off. virtual ducttape.
1165 toggle_placement(tb);
1166 toggle_placement(tb);
1167
1168 if(placement)
1169 {
1170 toggle_placement(tb);
1171 }
1172
1173 while (1)
1174 {
1175 now = time (0);
1176 lt = gmtime (&now);
1177 tv.tv_usec = 0;
1178 tv.tv_sec = 60 - lt->tm_sec;
1179 FD_ZERO (&fd);
1180 FD_SET (xfd, &fd);
1181 if (select (xfd + 1, &fd, 0, 0, &tv) == 0)
1182 gui_draw_clock (tb);
1183
1184 while (XPending (dd))
1185 {
1186 XNextEvent (dd, &ev);
1187
1188 switch (ev.type)
1189 {
1190 case ButtonPress:
1191 if (ev.xbutton.button == 1)
1192 handle_press (tb, ev.xbutton.x, ev.xbutton.y);
1193 break;
1194 case DestroyNotify:
1195 del_task (tb, ev.xdestroywindow.window);
1196 /* fall through */
1197 case Expose:
1198 gui_draw_taskbar (tb);
1199 break;
1200 case PropertyNotify:
1201 handle_propertynotify (tb, ev.xproperty.window, ev.xproperty.atom);
1202 break;
1203 case FocusIn:
1204 handle_focusin (tb, ev.xfocus.window);
1205 break;
1206
1207 }
1208 }
1209 }
1210
1211 /*XCloseDisplay (dd);
1212
1213 return 0;*/
1214 }
1215