2 /**********************************************************
3 ** Rather Small Panel 0.8beta1 Copyright (c) 2006 **
4 ** By Mikael Magnusson **
5 ** See file COPYING for license details. **
6 **********************************************************/
12 #include <sys/types.h>
16 #include <X11/Xutil.h>
17 #include <X11/Xatom.h>
26 /* you can edit these */
27 #define MAX_TASK_WIDTH 500
32 # define WINWIDTH 1280
36 #define FONT_NAME "-*-Technical*-m*-r-*-*-14-*-*"
37 #define XFT_FONT "Arial Unicode MS-12"
38 #define PANGO_FONT_PREF "Utopia"
39 //#define PANGO_FONT_PREF "Technical"
40 #define PANGO_FONT_SIZE 13
41 //#define PAGER /* use a desktop pager? */
42 #define PAGER_DIGIT_WIDTH 6
43 #define PAGER_BUTTON_WIDTH 20
48 /* don't edit these */
50 #define GRILL_WIDTH 10
55 #include <pango/pango.h>
56 #include <pango/pangoxft.h>
59 #include <X11/Xft/Xft.h>
90 unsigned short red, green, blue;
92 {0xd75c, 0xd75c, 0xe75c}, /* 0. light gray */
93 {0xbefb, 0xbaea, 0xcefb}, /* 1. mid gray */
94 {0xaefb, 0xaaea, 0xfefb}, /* 2. dark gray */
95 {0xefbe, 0xefbe, 0xffbe}, /* 3. white */
96 {0x8617, 0x8207, 0x9617}, /* 4. darkest gray */
97 {0x0000, 0x0000, 0x1000}, /* 5. black */
100 #define PALETTE_COUNT (sizeof (cols) / sizeof (cols[0].red) / 3)
102 unsigned long palette[PALETTE_COUNT];
104 char *atom_names[] = {
110 "_NET_WM_STATE_SKIP_TASKBAR",
111 "_NET_WM_STATE_SHADED",
112 "_NET_WM_STATE_BELOW",
113 "_NET_WM_STATE_HIDDEN",
115 "_NET_WM_WINDOW_TYPE",
116 "_NET_WM_WINDOW_TYPE_DOCK",
121 "_NET_CLIENT_LIST_STACKING",
122 "_NET_NUMBER_OF_DESKTOPS",
123 "_NET_CURRENT_DESKTOP",
127 "_NET_ACTIVE_WINDOW",
128 "_NET_RESTACK_WINDOW",
131 #define ATOM_COUNT (sizeof (atom_names) / sizeof (atom_names[0]))
133 Atom atoms[ATOM_COUNT];
140 _NET_WM_STATE_SKIP_TASKBAR,
141 _NET_WM_STATE_SHADED,
143 _NET_WM_STATE_HIDDEN,
146 _NET_WM_WINDOW_TYPE_DOCK,
150 _NET_CLIENT_LIST_STACKING,
151 _NET_NUMBER_OF_DESKTOPS,
152 _NET_CURRENT_DESKTOP,
166 #define atom_KWM_WIN_ICON atoms[0]
167 #define atom_WM_STATE atoms[1]
168 #define atom__MOTIF_WM_HINTS atoms[2]
169 #define atom__NET_WM_STATE atoms[3]
170 #define atom__NET_WM_STATE_SKIP_TASKBAR atoms[4]
171 #define atom__NET_WM_STATE_SHADED atoms[5]
172 #define atom__NET_WM_STATE_BELOW atoms[6]
173 #define atom__NET_WM_STATE_HIDDEN atoms[7]
174 #define atom__NET_WM_DESKTOP atoms[8]
175 #define atom__NET_WM_WINDOW_TYPE atoms[9]
176 #define atom__NET_WM_WINDOW_TYPE_DOCK atoms[10]
177 #define atom__NET_WM_STRUT atoms[11]
178 #define atom__WIN_HINTS atoms[12]
179 #define atom__NET_CLIENT_LIST atoms[13]
180 #define atom__NET_CLIENT_LIST_STACKING atoms[14]
181 #define atom__NET_NUMBER_OF_DESKTOPS atoms[15]
182 #define atom__NET_CURRENT_DESKTOP atoms[16]
183 #define atom__OB_WM_ACTION atoms[17]
184 #define atom__NET_WM_NAME atoms[18]
185 #define atom_STRING_UTF8 atoms[19]
186 #define atom__NET_ACTIVE_WINDOW atoms[20]
188 void *get_prop_data(Window win, Atom prop, Atom type, int *items)
192 unsigned long items_ret;
193 unsigned long after_ret;
194 unsigned char *prop_data;
198 XGetWindowProperty(dd, win, prop, 0, 0x7fffffff, False, type, &type_ret,
199 &format_ret, &items_ret, &after_ret, &prop_data);
206 void set_foreground(int index)
208 XSetForeground(dd, fore_gc, palette[index]);
211 void draw_line(int x, int y, int a, int b)
213 XDrawLine(dd, tb.win, fore_gc, x, y, a, b);
216 void fill_rect(int x, int y, int a, int b)
218 XFillRectangle(dd, tb.win, fore_gc, x, y, a, b);
221 void scale_icon(task * tk)
224 unsigned int w, h, d, bw;
225 Pixmap pix, mk = None;
229 XGetGeometry(dd, tk->icon, &pix, &x, &y, &w, &h, &bw, &d);
230 pix = XCreatePixmap(dd, tk->win, ICONWIDTH, ICONHEIGHT, scr_depth);
232 if (tk->mask != None) {
233 mk = XCreatePixmap(dd, tk->win, ICONWIDTH, ICONHEIGHT, 1);
234 gcv.subwindow_mode = IncludeInferiors;
235 gcv.graphics_exposures = False;
236 mgc = XCreateGC(dd, mk, GCGraphicsExposures | GCSubwindowMode, &gcv);
241 /* this is my simple & dirty scaling routine */
242 for (y = ICONHEIGHT - 1; y >= 0; y--) {
243 yy = (y * h) / ICONHEIGHT;
244 for (x = ICONWIDTH - 1; x >= 0; x--) {
245 xx = (x * w) / ICONWIDTH;
247 XCopyPlane(dd, tk->icon, pix, fore_gc, xx, yy, 1, 1, x, y, 1);
249 XCopyArea(dd, tk->icon, pix, fore_gc, xx, yy, 1, 1, x, y);
251 XCopyArea(dd, tk->mask, mk, mgc, xx, yy, 1, 1, x, y);
263 void get_task_hinticon(task * tk)
267 if (tk->icon != None && tk->icon != generic_icon)
268 if (tk->icon_copied) {
269 XFreePixmap(dd, tk->icon);
270 if (tk->mask != None && tk->mask != generic_mask)
271 XFreePixmap(dd, tk->mask);
277 hin = (XWMHints *)get_prop_data(tk->win, XA_WM_HINTS, XA_WM_HINTS, 0);
279 if ((hin->flags & IconPixmapHint)) {
280 if ((hin->flags & IconMaskHint)) {
281 tk->mask = hin->icon_mask;
284 tk->icon = hin->icon_pixmap;
291 if (tk->icon == None) {
292 tk->icon = generic_icon;
293 if (tk->mask != None)
294 XFreePixmap(dd, tk->mask);
295 tk->mask = generic_mask;
299 void get_task_kdeicon(task * tk)
303 data = get_prop_data(tk->win, atoms[KWM_WIN_ICON], atoms[KWM_WIN_ICON], 0);
311 int generic_get_int(Window win, Atom at)
316 data = get_prop_data(win, at, XA_CARDINAL, 0);
324 int find_desktop(Window win)
326 return generic_get_int(win, atoms[_NET_WM_DESKTOP]);
329 int is_hidden(Window win)
335 data = get_prop_data(win, atoms[_NET_WM_STATE], XA_ATOM, &num);
339 if ((data[num]) == atoms[_NET_WM_STATE_SKIP_TASKBAR])
347 int is_iconified(Window win)
353 data = get_prop_data(win, atoms[_NET_WM_STATE], XA_ATOM, &num);
357 if ((data[num]) == atoms[_NET_WM_STATE_HIDDEN])
365 int is_shaded(Window win)
371 data = get_prop_data(win, atoms[_NET_WM_STATE], XA_ATOM, &num);
375 if ((data[num]) == atoms[_NET_WM_STATE_SHADED])
383 int get_current_desktop(void)
385 return generic_get_int(root_win, atoms[_NET_CURRENT_DESKTOP]);
388 int get_number_of_desktops(void)
390 return generic_get_int(root_win, atoms[_NET_NUMBER_OF_DESKTOPS]);
393 void add_task(Window win, int focus)
401 /* is this window on a different desktop? */
402 desk = find_desktop(win);
403 if ((desk != 0xffffffff && tb.my_desktop != desk) || is_hidden(win))
406 tk = calloc(1, sizeof(task));
409 tk->name = get_prop_data(tk->win, atoms[_NET_WM_NAME], atoms[STRING_UTF8], 0) ?:
410 get_prop_data(tk->win, XA_WM_NAME, XA_STRING, 0);
411 // tk->name = get_prop_data(win, XA_WM_NAME, XA_STRING, 0);
412 //tk->locale = get_prop_data(win, XA_WM_LOCALE_NAME, XA_STRING, 0);
413 tk->iconified = is_iconified(win);
414 tk->shaded = is_shaded(win);
416 get_task_kdeicon(tk);
417 if (tk->icon == None)
418 get_task_hinticon(tk);
420 XSelectInput(dd, win, PropertyChangeMask | FocusChangeMask
421 | StructureNotifyMask);
423 /* now append it to our linked list */
445 void set_prop(Window win, Atom at, Atom type, long val)
447 XChangeProperty(dd, win, at, type, 32,
448 PropModeReplace, (unsigned char *)&val, 1);
451 Window gui_create_taskbar(void)
455 XSizeHints size_hints;
457 XSetWindowAttributes att;
460 att.background_pixel = palette[0];
461 att.event_mask = ButtonPressMask | ExposureMask;
463 win = rspanelwin = XCreateWindow(/* display */ dd,
464 /* parent */ root_win,
466 /* y */ scr_height - WINHEIGHT,
467 /* width */ WINWIDTH,
468 /* height */ WINHEIGHT,
470 /* depth */ CopyFromParent,
471 /* class */ InputOutput,
472 /* visual */ CopyFromParent,
473 /*value mask*/ CWBackPixel | CWEventMask,
476 /* reside on ALL desktops */
477 set_prop(win, atoms[_NET_WM_DESKTOP], XA_CARDINAL, 0xFFFFFFFF);
478 set_prop(win, atoms[_NET_WM_WINDOW_TYPE], XA_ATOM,
479 atoms[_NET_WM_WINDOW_TYPE_DOCK]);
480 set_prop(win, atoms[_NET_WM_STATE], XA_ATOM, atoms[_NET_WM_STATE_BELOW]);
481 /* use old gnome hint since sawfish doesn't support _NET_WM_STRUT */
482 set_prop(win, atoms[_WIN_HINTS], XA_CARDINAL,
483 WIN_HINTS_SKIP_FOCUS | WIN_HINTS_SKIP_WINLIST |
484 WIN_HINTS_SKIP_TASKBAR | WIN_HINTS_DO_NOT_COVER);
485 XChangeProperty(dd, win, XA_WM_NAME, XA_STRING, 8, PropModeReplace,
486 (unsigned char *)"rspanel", 7);
488 /* borderless motif hint */
489 bzero(&mwm, sizeof(mwm));
490 mwm.flags = MWM_HINTS_DECORATIONS;
491 XChangeProperty(dd, win, atoms[_MOTIF_WM_HINTS], atoms[_MOTIF_WM_HINTS], 32,
492 PropModeReplace, (unsigned char *)&mwm,
493 sizeof(MWMHints) / 4);
495 /* make sure the WM obays our window position */
496 size_hints.flags = PPosition;
497 /*XSetWMNormalHints (dd, win, &size_hints); */
498 XChangeProperty(dd, win, XA_WM_NORMAL_HINTS, XA_WM_SIZE_HINTS, 32,
499 PropModeReplace, (unsigned char *)&size_hints,
500 sizeof(XSizeHints) / 4);
502 /* make our window unfocusable */
503 wmhints.flags = InputHint;
504 wmhints.input = False;
505 /*XSetWMHints (dd, win, &wmhints); */
506 XChangeProperty(dd, win, XA_WM_HINTS, XA_WM_HINTS, 32, PropModeReplace,
507 (unsigned char *)&wmhints, sizeof(XWMHints) / 4);
509 xclhints.res_name = "rspanel";
510 xclhints.res_class = "RSPanel";
511 XSetClassHint(dd, win, &xclhints);
516 xftdraw = XftDrawCreate(dd, win, DefaultVisual(dd, scr_screen),
517 DefaultColormap(dd, scr_screen));
533 PangoContext *context;
534 PangoFontDescription *pfd;
539 xcl.red = cols[i].red;
540 xcl.green = cols[i].green;
541 xcl.blue = cols[i].blue;
542 XAllocColor(dd, DefaultColormap(dd, scr_screen), &xcl);
543 palette[i] = xcl.pixel;
545 } while (i < PALETTE_COUNT);
549 xfs = XftFontOpenName(dd, scr_screen, XFT_FONT);
551 fontname = FONT_NAME;
553 xfs = XLoadQueryFont(dd, fontname);
558 gcv.graphics_exposures = False;
561 text_y = xfs->ascent + ((WINHEIGHT - (xfs->ascent + xfs->descent)) / 2);
562 fore_gc = XCreateGC(dd, root_win, GCGraphicsExposures, &gcv);
564 text_y = xfs->ascent + ((WINHEIGHT - xfs->ascent) / 2);
566 fore_gc = XCreateGC(dd, root_win, GCFont | GCGraphicsExposures, &gcv);
569 pfd = pango_font_description_new();
570 pango_font_description_set_absolute_size(pfd, PANGO_FONT_SIZE*PANGO_SCALE);
571 pango_font_description_set_family(pfd, PANGO_FONT_PREF);
572 context = pango_xft_get_context(dd, root_win);
573 pango_context_set_font_description(context, pfd);
574 pl = pango_layout_new(context);
576 pango_layout_set_single_paragraph_mode(pl, TRUE);
577 pango_layout_set_ellipsize(pl, PANGO_ELLIPSIZE_END);
579 text_y = (WINHEIGHT*PANGO_SCALE-7*PANGO_SCALE);
580 pango_font_description_free(pfd);
581 g_object_unref(context);
583 fore_gc = XCreateGC(dd, root_win, GCGraphicsExposures, &gcv);
587 XpmCreatePixmapFromData(dd, root_win, icon_xpm, &generic_icon,
588 &generic_mask, NULL);
594 void gui_draw_vline(int x)
597 draw_line(x, 0, x, WINHEIGHT);
599 draw_line(x + 1, 0, x + 1, WINHEIGHT);
602 void draw_box(int x, int width)
604 set_foreground(1); /* mid gray */
605 fill_rect(x + 3, 2, width - 2, WINHEIGHT - 4);
607 set_foreground(3); /* white */
608 draw_line(x + 3, WINHEIGHT - 2, x + width - 1, WINHEIGHT - 2);
609 draw_line(x + width - 1, 1, x + width - 1, WINHEIGHT - 2);
611 set_foreground(4); /* darkest gray */
612 draw_line(x + 3, 1, x + width - 1, 1);
613 draw_line(x + 3, 2, x + 3, WINHEIGHT - 3);
616 void gui_draw_task(task * tk)
619 int taskw = tk->width;
633 set_foreground(0); /* mid gray */
634 fill_rect(x + 2, 0, taskw - 1, WINHEIGHT);
638 int text_x = x + TEXTPAD + TEXTPAD + (tk->icon ? ICONWIDTH : -1*ICONWIDTH/4);
639 #define SETCOL(x) col.color.red = cols[x].red;\
640 col.color.green = cols[x].green;\
641 col.color.blue = cols[x].blue;
644 pango_layout_set_width(pl, /*-1);*/(taskw - text_x + x) * PANGO_SCALE);
645 pango_layout_set_text(pl, tk->name, -1);
646 col.color.alpha = 0xffff;
650 pango_xft_render_layout_line(xftdraw, &col, pango_layout_get_line(pl, 0), (text_x+2)*PANGO_SCALE, text_y + 2);
652 } else if (tk->shaded) {
654 pango_xft_render_layout_line(xftdraw, &col, pango_layout_get_line(pl, 0), (text_x-2)*PANGO_SCALE, text_y - 2);
659 pango_xft_render_layout_line(xftdraw, &col, pango_layout_get_line(pl, 0), text_x*PANGO_SCALE, text_y);
663 /* check how many chars can fit */
664 len = strlen(tk->name);
666 XftTextExtentsUtf8(dd, xfs, tk->name, len, &ext);
667 if (ext.width < taskw - (text_x - x) - 2 || len <= 0)
672 col.color.alpha = 0xffff;
675 /* draw task's name dark (iconified) */
677 XftDrawStringUtf8(xftdraw, &col, xfs, text_x, text_y + 1, tk->name,
680 } else if (tk->shaded) {
681 /* draw task's name dark (shaded) */
683 XftDrawStringUtf8(xftdraw, &col, xfs, text_x, text_y - 1, tk->name,
691 /* draw task's name here */
692 XftDrawStringUtf8(xftdraw, &col, xfs, text_x, text_y, tk->name, len);
695 /* check how many chars can fit */
696 len = strlen(tk->name);
698 while (XTextWidth(xfs, tk->name, len) >= taskw - (text_x - x) - 2
703 /* draw task's name dark (iconified) */
705 XDrawString(dd, tb.win, fore_gc, text_x, text_y + 1, tk->name,
708 } else if (tk->shaded) {
709 /* draw task's name dark (shaded) */
711 XDrawString(dd, tb.win, fore_gc, text_x, text_y - 1, tk->name,
718 /* draw task's name here */
719 XDrawString(dd, tb.win, fore_gc, text_x, text_y, tk->name, len);
728 /* draw the task's icon */
729 XSetClipMask(dd, fore_gc, tk->mask);
730 XSetClipOrigin(dd, fore_gc, x + TEXTPAD, (WINHEIGHT - ICONHEIGHT) / 2);
731 XCopyArea(dd, tk->icon, tb.win, fore_gc, 0, 0, ICONWIDTH, ICONHEIGHT,
732 x + TEXTPAD, (WINHEIGHT - ICONHEIGHT) / 2);
733 XSetClipMask(dd, fore_gc, None);
736 void draw_dot(int x, int y)
739 XDrawPoint(dd, tb.win, fore_gc, x, y);
741 XDrawPoint(dd, tb.win, fore_gc, x + 1, y + 1);
744 void draw_grill(int x)
747 while (y < WINHEIGHT - 4) {
754 void ob_action(Window win, char *action)
756 XClientMessageEvent xev;
757 char act_name[14+strlen(action)];
758 sprintf(act_name, "_OB_WM_ACTION_%s", action);
760 xev.type = ClientMessage;
762 xev.message_type = atoms[_OB_WM_ACTION];
764 /*strncpy(xev.data.b, action, 20);*/
765 xev.data.l[0] = XInternAtom(dd, act_name, False);
766 XSendEvent(dd, root_win, False, SubstructureRedirectMask, (XEvent *)&xev);
769 void netwm_action(Window win, atom_t atom, Time time, long l)
771 XClientMessageEvent xev = {
772 .type = ClientMessage,
776 .message_type = atoms[atom]
779 if (atom == _NET_ACTIVE_WINDOW) {
781 xev.data.l[1] = time;
783 } else if (atom == _NET_CURRENT_DESKTOP) {
785 xev.data.l[1] = time;
786 } else if (atom == _NET_RESTACK_WINDOW) {
790 xev.message_type = atoms[_NET_WM_STATE];
792 xev.data.l[1] = atoms[atom];
796 XSendEvent(dd, root_win, False, SubstructureNotifyMask|SubstructureRedirectMask, (XEvent *)&xev);
801 void switch_desk(int new_desk, Time time)
803 if (get_number_of_desktops() <= new_desk)
806 netwm_action(None, _NET_CURRENT_DESKTOP, time, new_desk);
809 void pager_draw_button(int x, int num)
816 if (num == tb.my_desktop) {
817 /* current desktop */
818 draw_box(x, PAGER_BUTTON_WIDTH);
821 fill_rect(x, 1, PAGER_BUTTON_WIDTH + 1, WINHEIGHT - 2);
827 col.color.alpha = 0xffff;
828 col.color.red = cols[5].red;
829 col.color.green = cols[5].green;
830 col.color.blue = cols[5].blue;
831 XftDrawString8(xftdraw, &col, xfs,
832 x + ((PAGER_BUTTON_WIDTH - PAGER_DIGIT_WIDTH) / 2), text_y,
836 XDrawString(dd, tb.win, fore_gc,
837 x + ((PAGER_BUTTON_WIDTH - PAGER_DIGIT_WIDTH) / 2) - 1,
842 void pager_draw(void)
844 int desks, i, x = GRILL_WIDTH;
846 desks = get_number_of_desktops();
848 for (i = 0; i < desks; i++) {
849 pager_draw_button(x, i);
852 x += PAGER_BUTTON_WIDTH;
860 void gui_draw_taskbar(void)
868 pager_size = TEXTPAD;
871 width = WINWIDTH - (pager_size + GRILL_WIDTH + GRILL_WIDTH);
874 if (tb.num_tasks == 0)
877 taskw = width / tb.num_tasks;
878 if (taskw > MAX_TASK_WIDTH)
879 taskw = MAX_TASK_WIDTH;
884 tk->width = taskw - 1;
890 if (x < (width + pager_size + 2)) {
894 fill_rect(x + 2, 0, WINWIDTH, WINHEIGHT);
898 gui_draw_vline(WINWIDTH - 8);
901 draw_grill(WINWIDTH - 6);
904 task *find_task(Window win)
906 task *list = tb.task_list;
908 if (list->win == win)
915 void del_task(Window win)
917 task *next, *prev = 0, *list = tb.task_list;
921 if (list->win == win) {
922 /* unlink and free this task */
924 if (list->icon_copied) {
925 XFreePixmap(dd, list->icon);
926 if (list->mask != None)
927 XFreePixmap(dd, list->mask);
943 void move_taskbar(void)
950 x = TEXTPAD - WINWIDTH;
953 y = scr_height - WINHEIGHT;
955 XMoveWindow(dd, tb.win, x, y);
958 void taskbar_read_clientlist(void)
960 Window *win, focus_win = 0;
961 int num, i, desk, new_desk = 0;
963 desk = get_current_desktop();
970 XResizeWindow(dd, rspanelwin, WINWIDTH, WINHEIGHT);
973 if (desk != tb.my_desktop) {
975 tb.my_desktop = desk;
978 win = get_prop_data(root_win, atoms[_NET_ACTIVE_WINDOW], XA_WINDOW, &num);
982 win = get_prop_data(root_win, atoms[_NET_CLIENT_LIST], XA_WINDOW, &num);
986 /* remove windows that arn't in the _NET_CLIENT_LIST anymore */
989 list->focused = (focus_win == list->win);
993 for (i = num - 1; i >= 0; i--)
994 if (list->win == win[i] && !is_hidden(win[i]))
1002 /* add any new windows */
1003 for (i = 0; i < num; i++) {
1004 if (!find_task(win[i]))
1005 add_task(win[i], (win[i] == focus_win));
1011 void handle_press(int x, int y, int button, Time time)
1016 if ((y > 2 && y < WINHEIGHT - 2 && x > GRILL_WIDTH) && button == 1)
1017 switch_desk((x - GRILL_WIDTH) / PAGER_BUTTON_WIDTH, time);
1020 /* clicked left grill */
1023 tb.at_top = 1 - tb.at_top;
1025 } else if (button == 4) {
1031 /* clicked right grill */
1032 else if (x + TEXTPAD > WINWIDTH) {
1033 if (tb.hidden && (button == 1 || button == 5)) {
1036 } else if (!tb.hidden && (button == 1 || button == 4)) {
1043 /* clicked on a task button */
1044 if (x > tk->pos_x && x < tk->pos_x + tk->width) {
1047 if (tk->iconified && tk->shaded)
1048 ob_action(tk->win, "unshade");
1049 //ob_action(tk->win, "activate");
1050 netwm_action(tk->win, _NET_ACTIVE_WINDOW, time, 0);
1054 //ob_action(tk->win, "deiconify");
1055 netwm_action(tk->win, _NET_WM_STATE_HIDDEN, time, REMOVE);
1057 netwm_action(tk->win, _NET_WM_STATE_HIDDEN, time, ADD);
1058 //ob_action(tk->win, "iconify");
1061 ob_action(tk->win, "raiselower");
1064 if (is_shaded(tk->win))
1065 netwm_action(tk->win, _NET_RESTACK_WINDOW, time, Below);
1067 netwm_action(tk->win, _NET_WM_STATE_SHADED, time, ADD);
1070 if (is_shaded(tk->win))
1071 netwm_action(tk->win, _NET_WM_STATE_SHADED, time, REMOVE);
1073 netwm_action(tk->win, _NET_RESTACK_WINDOW, time, Above);
1077 netwm_action(tk->win, _NET_WM_STATE_SHADED, time, REMOVE);
1078 //ob_action(tk->win, "deiconify");
1080 ob_action(tk->win, "focus");
1083 // ob_action(tk->win, "lower");
1084 netwm_action(tk->win, _NET_RESTACK_WINDOW, time, Below);
1087 // ob_action(tk->win, "raise");
1088 netwm_action(tk->win, _NET_RESTACK_WINDOW, time, Above);
1094 } /* clicked on the background */
1097 ob_action(tb.win, "raise");
1100 ob_action(tb.win, "lower");
1103 ob_action(tb.win, "raiselower");
1117 void handle_focusin(Window win)
1124 if (tk->win != win) {
1129 if (tk->win == win) {
1138 void handle_propertynotify(Window win, Atom at)
1142 if (win == root_win) {
1143 if (at == atoms[_NET_CLIENT_LIST] || at == atoms[_NET_CURRENT_DESKTOP] || at == atoms[_NET_CLIENT_LIST_STACKING]) {
1144 taskbar_read_clientlist();
1150 tk = find_task(win);
1154 if (at == XA_WM_NAME || at == atoms[_NET_WM_NAME]) {
1155 /* window's title changed */
1157 newname = get_prop_data(tk->win, atoms[_NET_WM_NAME], atoms[STRING_UTF8], 0) ?:
1158 get_prop_data(tk->win, XA_WM_NAME, XA_STRING, 0);
1160 if (tk->name && !strcmp(newname, tk->name)) {
1169 } else if (at == atoms[_NET_WM_STATE]) {
1170 /* iconified state changed? */
1171 if (is_iconified(tk->win) != tk->iconified) {
1172 tk->iconified = !tk->iconified;
1175 /* shaded state changed? */
1176 if (is_shaded(tk->win) != tk->shaded) {
1177 tk->shaded = !tk->shaded;
1180 } else if (at == XA_WM_HINTS) {
1181 /* some windows set their WM_HINTS icon after mapping */
1182 //if (tk->icon == generic_icon) {
1183 get_task_hinticon(tk);
1186 } else if (at == atoms[_NET_WM_DESKTOP]) {
1187 if (find_desktop(win) != get_current_desktop())
1192 void handle_error(Display * d, XErrorEvent * ev)
1200 main(int argc, char *argv[])
1207 dd = XOpenDisplay(NULL);
1210 scr_screen = DefaultScreen(dd);
1211 scr_depth = DefaultDepth(dd, scr_screen);
1212 scr_height = DisplayHeight(dd, scr_screen);
1213 scr_width = DisplayWidth(dd, scr_screen);
1214 root_win = RootWindow(dd, scr_screen);
1216 /* helps us catch windows closing/opening */
1217 XSelectInput(dd, root_win, PropertyChangeMask);
1219 XSetErrorHandler((XErrorHandler) handle_error);
1221 XInternAtoms(dd, atom_names, ATOM_COUNT, False, atoms);
1224 bzero(&tb, sizeof(struct taskbar));
1225 tb.win = gui_create_taskbar();
1226 xfd = ConnectionNumber(dd);
1232 select(xfd + 1, &fd, 0, 0, 0);
1234 while (XPending(dd)) {
1235 XNextEvent(dd, &ev);
1238 handle_press(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.time);
1241 del_task(ev.xdestroywindow.window);
1246 case PropertyNotify:
1247 handle_propertynotify(ev.xproperty.window, ev.xproperty.atom);
1250 if (ev.xfocus.mode != NotifyGrab)
1251 handle_focusin(ev.xfocus.window);
1254 printf ("unknown evt type: %d\n", ev.type); */
1259 /*XCloseDisplay (dd);