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>
25 /* you can edit these */
26 #define MAX_TASK_WIDTH 500
31 # define WINWIDTH 1280
35 #define FONT_NAME "-*-Technical*-m*-r-*-*-14-*-*"
36 #define XFT_FONT "Arial Unicode MS-12"
37 #define PANGO_FONT_PREF "Utopia"
38 //#define PANGO_FONT_PREF "Technical"
39 #define PANGO_FONT_SIZE 13
40 //#define PAGER /* use a desktop pager? */
41 #define PAGER_DIGIT_WIDTH 6
42 #define PAGER_BUTTON_WIDTH 20
44 /* don't edit these */
46 #define GRILL_WIDTH 10
51 #include <pango/pango.h>
52 #include <pango/pangoxft.h>
55 #include <X11/Xft/Xft.h>
86 unsigned short red, green, blue;
88 {0xd75c, 0xd75c, 0xe75c}, /* 0. light gray */
89 {0xbefb, 0xbaea, 0xcefb}, /* 1. mid gray */
90 {0xaefb, 0xaaea, 0xfefb}, /* 2. dark gray */
91 {0xefbe, 0xefbe, 0xffbe}, /* 3. white */
92 {0x8617, 0x8207, 0x9617}, /* 4. darkest gray */
93 {0x0000, 0x0000, 0x1000}, /* 5. black */
96 #define PALETTE_COUNT (sizeof (cols) / sizeof (cols[0].red) / 3)
98 unsigned long palette[PALETTE_COUNT];
100 char *atom_names[] = {
106 "_NET_WM_STATE_SKIP_TASKBAR",
107 "_NET_WM_STATE_SHADED",
108 "_NET_WM_STATE_BELOW",
109 "_NET_WM_STATE_HIDDEN",
111 "_NET_WM_WINDOW_TYPE",
112 "_NET_WM_WINDOW_TYPE_DOCK",
117 "_NET_CLIENT_LIST_STACKING",
118 "_NET_NUMBER_OF_DESKTOPS",
119 "_NET_CURRENT_DESKTOP",
125 #define ATOM_COUNT (sizeof (atom_names) / sizeof (atom_names[0]))
127 Atom atoms[ATOM_COUNT];
129 #define atom_KWM_WIN_ICON atoms[0]
130 #define atom_WM_STATE atoms[1]
131 #define atom__MOTIF_WM_HINTS atoms[2]
132 #define atom__NET_WM_STATE atoms[3]
133 #define atom__NET_WM_STATE_SKIP_TASKBAR atoms[4]
134 #define atom__NET_WM_STATE_SHADED atoms[5]
135 #define atom__NET_WM_STATE_BELOW atoms[6]
136 #define atom__NET_WM_STATE_HIDDEN atoms[7]
137 #define atom__NET_WM_DESKTOP atoms[8]
138 #define atom__NET_WM_WINDOW_TYPE atoms[9]
139 #define atom__NET_WM_WINDOW_TYPE_DOCK atoms[10]
140 #define atom__NET_WM_STRUT atoms[11]
141 #define atom__WIN_HINTS atoms[12]
142 #define atom__NET_CLIENT_LIST atoms[13]
143 #define atom__NET_CLIENT_LIST_STACKING atoms[14]
144 #define atom__NET_NUMBER_OF_DESKTOPS atoms[15]
145 #define atom__NET_CURRENT_DESKTOP atoms[16]
146 #define atom__OB_WM_ACTION atoms[17]
147 #define atom__NET_WM_NAME atoms[18]
148 #define atom_STRING_UTF8 atoms[19]
151 void *get_prop_data(Window win, Atom prop, Atom type, int *items)
155 unsigned long items_ret;
156 unsigned long after_ret;
157 unsigned char *prop_data;
161 XGetWindowProperty(dd, win, prop, 0, 0x7fffffff, False, type, &type_ret,
162 &format_ret, &items_ret, &after_ret, &prop_data);
169 void set_foreground(int index)
171 XSetForeground(dd, fore_gc, palette[index]);
174 void draw_line(int x, int y, int a, int b)
176 XDrawLine(dd, tb.win, fore_gc, x, y, a, b);
179 void fill_rect(int x, int y, int a, int b)
181 XFillRectangle(dd, tb.win, fore_gc, x, y, a, b);
184 void scale_icon(task * tk)
186 int xx, yy, x, y, w, h, d, bw;
187 Pixmap pix, mk = None;
191 XGetGeometry(dd, tk->icon, &pix, &x, &y, &w, &h, &bw, &d);
192 pix = XCreatePixmap(dd, tk->win, ICONWIDTH, ICONHEIGHT, scr_depth);
194 if (tk->mask != None) {
195 mk = XCreatePixmap(dd, tk->win, ICONWIDTH, ICONHEIGHT, 1);
196 gcv.subwindow_mode = IncludeInferiors;
197 gcv.graphics_exposures = False;
198 mgc = XCreateGC(dd, mk, GCGraphicsExposures | GCSubwindowMode, &gcv);
203 /* this is my simple & dirty scaling routine */
204 for (y = ICONHEIGHT - 1; y >= 0; y--) {
205 yy = (y * h) / ICONHEIGHT;
206 for (x = ICONWIDTH - 1; x >= 0; x--) {
207 xx = (x * w) / ICONWIDTH;
209 XCopyPlane(dd, tk->icon, pix, fore_gc, xx, yy, 1, 1, x, y, 1);
211 XCopyArea(dd, tk->icon, pix, fore_gc, xx, yy, 1, 1, x, y);
213 XCopyArea(dd, tk->mask, mk, mgc, xx, yy, 1, 1, x, y);
225 void get_task_hinticon(task * tk)
229 if (tk->icon != None && tk->icon != generic_icon)
230 if (tk->icon_copied) {
231 XFreePixmap(dd, tk->icon);
232 if (tk->mask != None && tk->mask != generic_mask)
233 XFreePixmap(dd, tk->mask);
239 hin = (XWMHints *)get_prop_data(tk->win, XA_WM_HINTS, XA_WM_HINTS, 0);
241 if ((hin->flags & IconPixmapHint)) {
242 if ((hin->flags & IconMaskHint)) {
243 tk->mask = hin->icon_mask;
246 tk->icon = hin->icon_pixmap;
253 if (tk->icon == None) {
254 tk->icon = generic_icon;
255 if (tk->mask != None)
256 XFreePixmap(dd, tk->mask);
257 tk->mask = generic_mask;
261 void get_task_kdeicon(task * tk)
265 data = get_prop_data(tk->win, atom_KWM_WIN_ICON, atom_KWM_WIN_ICON, 0);
273 int generic_get_int(Window win, Atom at)
278 data = get_prop_data(win, at, XA_CARDINAL, 0);
286 int find_desktop(Window win)
288 return generic_get_int(win, atom__NET_WM_DESKTOP);
291 int is_hidden(Window win)
297 data = get_prop_data(win, atom__NET_WM_STATE, XA_ATOM, &num);
301 if ((data[num]) == atom__NET_WM_STATE_SKIP_TASKBAR)
309 int is_iconified(Window win)
315 data = get_prop_data(win, atom__NET_WM_STATE, XA_ATOM, &num);
319 if ((data[num]) == atom__NET_WM_STATE_HIDDEN)
327 int is_shaded(Window win)
333 data = get_prop_data(win, atom__NET_WM_STATE, XA_ATOM, &num);
337 if ((data[num]) == atom__NET_WM_STATE_SHADED)
345 int get_current_desktop(void)
347 return generic_get_int(root_win, atom__NET_CURRENT_DESKTOP);
350 int get_number_of_desktops(void)
352 return generic_get_int(root_win, atom__NET_NUMBER_OF_DESKTOPS);
355 void add_task(Window win, int focus)
363 /* is this window on a different desktop? */
364 desk = find_desktop(win);
365 if ((desk != 0xffffffff && tb.my_desktop != desk) || is_hidden(win))
368 tk = calloc(1, sizeof(task));
371 tk->name = get_prop_data(tk->win, atom__NET_WM_NAME, atom_STRING_UTF8, 0) ?:
372 get_prop_data(tk->win, XA_WM_NAME, XA_STRING, 0);
373 // tk->name = get_prop_data(win, XA_WM_NAME, XA_STRING, 0);
374 //tk->locale = get_prop_data(win, XA_WM_LOCALE_NAME, XA_STRING, 0);
375 tk->iconified = is_iconified(win);
376 tk->shaded = is_shaded(win);
378 get_task_kdeicon(tk);
379 if (tk->icon == None)
380 get_task_hinticon(tk);
382 XSelectInput(dd, win, PropertyChangeMask | FocusChangeMask
383 | StructureNotifyMask);
385 /* now append it to our linked list */
407 void set_prop(Window win, Atom at, Atom type, long val)
409 XChangeProperty(dd, win, at, type, 32,
410 PropModeReplace, (unsigned char *)&val, 1);
413 Window gui_create_taskbar(void)
417 XSizeHints size_hints;
419 XSetWindowAttributes att;
421 att.background_pixel = palette[0];
422 att.event_mask = ButtonPressMask | ExposureMask;
424 win = rspanelwin = XCreateWindow(/* display */ dd,
425 /* parent */ root_win,
427 /* y */ scr_height - WINHEIGHT,
428 /* width */ WINWIDTH,
429 /* height */ WINHEIGHT,
431 /* depth */ CopyFromParent,
432 /* class */ InputOutput,
433 /* visual */ CopyFromParent,
434 /*value mask*/ CWBackPixel | CWEventMask,
437 /* reside on ALL desktops */
438 set_prop(win, atom__NET_WM_DESKTOP, XA_CARDINAL, 0xFFFFFFFF);
439 set_prop(win, atom__NET_WM_WINDOW_TYPE, XA_ATOM,
440 atom__NET_WM_WINDOW_TYPE_DOCK);
441 set_prop(win, atom__NET_WM_STATE, XA_ATOM, atom__NET_WM_STATE_BELOW);
442 /* use old gnome hint since sawfish doesn't support _NET_WM_STRUT */
443 set_prop(win, atom__WIN_HINTS, XA_CARDINAL,
444 WIN_HINTS_SKIP_FOCUS | WIN_HINTS_SKIP_WINLIST |
445 WIN_HINTS_SKIP_TASKBAR | WIN_HINTS_DO_NOT_COVER);
446 XChangeProperty(dd, win, XA_WM_NAME, XA_STRING, 8, PropModeReplace, "rspanel", 7);
448 /* borderless motif hint */
449 bzero(&mwm, sizeof(mwm));
450 mwm.flags = MWM_HINTS_DECORATIONS;
451 XChangeProperty(dd, win, atom__MOTIF_WM_HINTS, atom__MOTIF_WM_HINTS, 32,
452 PropModeReplace, (unsigned char *)&mwm,
453 sizeof(MWMHints) / 4);
455 /* make sure the WM obays our window position */
456 size_hints.flags = PPosition;
457 /*XSetWMNormalHints (dd, win, &size_hints); */
458 XChangeProperty(dd, win, XA_WM_NORMAL_HINTS, XA_WM_SIZE_HINTS, 32,
459 PropModeReplace, (unsigned char *)&size_hints,
460 sizeof(XSizeHints) / 4);
462 /* make our window unfocusable */
463 wmhints.flags = InputHint;
464 wmhints.input = False;
465 /*XSetWMHints (dd, win, &wmhints); */
466 XChangeProperty(dd, win, XA_WM_HINTS, XA_WM_HINTS, 32, PropModeReplace,
467 (unsigned char *)&wmhints, sizeof(XWMHints) / 4);
472 xftdraw = XftDrawCreate(dd, win, DefaultVisual(dd, scr_screen),
473 DefaultColormap(dd, scr_screen));
489 PangoContext *context;
490 PangoFontDescription *pfd;
493 PangoFontMetrics *metrics;
498 xcl.red = cols[i].red;
499 xcl.green = cols[i].green;
500 xcl.blue = cols[i].blue;
501 XAllocColor(dd, DefaultColormap(dd, scr_screen), &xcl);
502 palette[i] = xcl.pixel;
504 } while (i < PALETTE_COUNT);
508 xfs = XftFontOpenName(dd, scr_screen, XFT_FONT);
510 fontname = FONT_NAME;
512 xfs = XLoadQueryFont(dd, fontname);
517 gcv.graphics_exposures = False;
520 text_y = xfs->ascent + ((WINHEIGHT - (xfs->ascent + xfs->descent)) / 2);
521 fore_gc = XCreateGC(dd, root_win, GCGraphicsExposures, &gcv);
523 text_y = xfs->ascent + ((WINHEIGHT - xfs->ascent) / 2);
525 fore_gc = XCreateGC(dd, root_win, GCFont | GCGraphicsExposures, &gcv);
528 pfd = pango_font_description_new();
529 pango_font_description_set_absolute_size(pfd, PANGO_FONT_SIZE*PANGO_SCALE);
530 pango_font_description_set_family(pfd, PANGO_FONT_PREF);
531 context = pango_xft_get_context(dd, root_win);
532 pango_context_set_font_description(context, pfd);
533 pl = pango_layout_new(context);
534 // pfm = pango_xft_get_font_map(dd, root_win);
535 // pfm = pango_context_get_font_map(context);
537 // pango_layout_set_font_description(pl, pfd);
538 pango_layout_set_single_paragraph_mode(pl, TRUE);
539 pango_layout_set_ellipsize(pl, PANGO_ELLIPSIZE_END);
540 // pango_layout_set_alignment(pl, PANGO_ALIGN_LEFT);
543 // This is actually not all wrong, we use render_line instead and pass the baseline
544 // and don't give a shit about the height.
546 // This is all wrong, we have to check the height of the layout when the text to draw
547 // is known, or pango will just guess at a height or something. woot for smartness.
548 // pfs = pango_font_map_load_fontset(pfm, context, pfd, pango_context_get_language(context));
549 // metrics = pango_fontset_get_metrics(pfs);
550 // metrics = pango_context_get_metrics(context, pfd, NULL);
551 text_y = (WINHEIGHT*PANGO_SCALE// - pango_font_metrics_get_ascent(metrics)
552 //- pango_font_metrics_get_descent(metrics)
553 -7*PANGO_SCALE);//;)/2;
554 pango_font_description_free(pfd);
555 // pango_font_metrics_unref(metrics);
556 g_object_unref(context);
558 fore_gc = XCreateGC(dd, root_win, GCGraphicsExposures, &gcv);
562 XpmCreatePixmapFromData(dd, root_win, icon_xpm, &generic_icon,
563 &generic_mask, NULL);
569 void gui_draw_vline(int x)
572 draw_line(x, 0, x, WINHEIGHT);
574 draw_line(x + 1, 0, x + 1, WINHEIGHT);
577 void draw_box(int x, int width)
579 set_foreground(1); /* mid gray */
580 fill_rect(x + 3, 2, width - 2, WINHEIGHT - 4);
582 set_foreground(3); /* white */
583 draw_line(x + 3, WINHEIGHT - 2, x + width - 1, WINHEIGHT - 2);
584 draw_line(x + width - 1, 1, x + width - 1, WINHEIGHT - 2);
586 set_foreground(4); /* darkest gray */
587 draw_line(x + 3, 1, x + width - 1, 1);
588 draw_line(x + 3, 2, x + 3, WINHEIGHT - 3);
591 void gui_draw_task(task * tk)
595 int taskw = tk->width;
606 set_foreground(0); /* mid gray */
607 fill_rect(x + 2, 0, taskw - 1, WINHEIGHT);
611 int text_x = x + TEXTPAD + TEXTPAD + ICONWIDTH;
612 #define SETCOL(x) col.color.red = cols[x].red;\
613 col.color.green = cols[x].green;\
614 col.color.blue = cols[x].blue;
617 pango_layout_set_width(pl, /*-1);*/(taskw - text_x + x) * PANGO_SCALE);
618 pango_layout_set_text(pl, tk->name, -1);
619 col.color.alpha = 0xffff;
623 pango_xft_render_layout_line(xftdraw, &col, pango_layout_get_line(pl, 0), (text_x+2)*PANGO_SCALE, text_y + 2);
625 } else if (tk->shaded) {
627 pango_xft_render_layout_line(xftdraw, &col, pango_layout_get_line(pl, 0), (text_x-2)*PANGO_SCALE, text_y - 2);
632 pango_xft_render_layout_line(xftdraw, &col, pango_layout_get_line(pl, 0), text_x*PANGO_SCALE, text_y);
636 /* check how many chars can fit */
637 len = strlen(tk->name);
639 XftTextExtentsUtf8(dd, xfs, tk->name, len, &ext);
640 if (ext.width < taskw - (text_x - x) - 2 || len <= 0)
645 col.color.alpha = 0xffff;
648 /* draw task's name dark (iconified) */
650 XftDrawStringUtf8(xftdraw, &col, xfs, text_x, text_y + 1, tk->name,
653 } else if (tk->shaded) {
654 /* draw task's name dark (shaded) */
656 XftDrawStringUtf8(xftdraw, &col, xfs, text_x, text_y - 1, tk->name,
664 /* draw task's name here */
665 XftDrawStringUtf8(xftdraw, &col, xfs, text_x, text_y, tk->name, len);
668 /* check how many chars can fit */
669 len = strlen(tk->name);
671 while (XTextWidth(xfs, tk->name, len) >= taskw - (text_x - x) - 2
676 /* draw task's name dark (iconified) */
678 XDrawString(dd, tb.win, fore_gc, text_x, text_y + 1, tk->name,
681 } else if (tk->shaded) {
682 /* draw task's name dark (shaded) */
684 XDrawString(dd, tb.win, fore_gc, text_x, text_y - 1, tk->name,
691 /* draw task's name here */
692 XDrawString(dd, tb.win, fore_gc, text_x, text_y, tk->name, len);
701 /* draw the task's icon */
702 XSetClipMask(dd, fore_gc, tk->mask);
703 XSetClipOrigin(dd, fore_gc, x + TEXTPAD, (WINHEIGHT - ICONHEIGHT) / 2);
704 XCopyArea(dd, tk->icon, tb.win, fore_gc, 0, 0, ICONWIDTH, ICONHEIGHT,
705 x + TEXTPAD, (WINHEIGHT - ICONHEIGHT) / 2);
706 XSetClipMask(dd, fore_gc, None);
709 void draw_dot(int x, int y)
712 XDrawPoint(dd, tb.win, fore_gc, x, y);
714 XDrawPoint(dd, tb.win, fore_gc, x + 1, y + 1);
717 void draw_grill(int x)
720 while (y < WINHEIGHT - 4) {
727 void ob_action(Window win, char *action)
729 XClientMessageEvent xev;
730 char act_name[14+strlen(action)];
731 sprintf(act_name, "_OB_WM_ACTION_%s", action);
733 xev.type = ClientMessage;
735 xev.message_type = atom__OB_WM_ACTION;
737 /*strncpy(xev.data.b, action, 20);*/
738 xev.data.l[0] = XInternAtom(dd, act_name, False);
739 XSendEvent(dd, root_win, False, SubstructureRedirectMask, (XEvent *)&xev);
744 void switch_desk(int new_desk)
746 XClientMessageEvent xev;
748 if (get_number_of_desktops() <= new_desk)
751 xev.type = ClientMessage;
752 xev.window = root_win;
753 xev.message_type = atom__NET_CURRENT_DESKTOP;
755 xev.data.l[0] = new_desk;
756 XSendEvent(dd, root_win, False, SubstructureRedirectMask, (XEvent *)&xev);
759 void pager_draw_button(int x, int num)
766 if (num == tb.my_desktop) {
767 /* current desktop */
768 draw_box(x, PAGER_BUTTON_WIDTH);
771 fill_rect(x, 1, PAGER_BUTTON_WIDTH + 1, WINHEIGHT - 2);
777 col.color.alpha = 0xffff;
778 col.color.red = cols[5].red;
779 col.color.green = cols[5].green;
780 col.color.blue = cols[5].blue;
781 XftDrawString8(xftdraw, &col, xfs,
782 x + ((PAGER_BUTTON_WIDTH - PAGER_DIGIT_WIDTH) / 2), text_y,
786 XDrawString(dd, tb.win, fore_gc,
787 x + ((PAGER_BUTTON_WIDTH - PAGER_DIGIT_WIDTH) / 2) - 1,
792 void pager_draw(void)
794 int desks, i, x = GRILL_WIDTH;
796 desks = get_number_of_desktops();
798 for (i = 0; i < desks; i++) {
799 pager_draw_button(x, i);
802 x += PAGER_BUTTON_WIDTH;
810 void gui_draw_taskbar(void)
818 pager_size = TEXTPAD;
821 width = WINWIDTH - (pager_size + GRILL_WIDTH + GRILL_WIDTH);
824 if (tb.num_tasks == 0)
827 taskw = width / tb.num_tasks;
828 if (taskw > MAX_TASK_WIDTH)
829 taskw = MAX_TASK_WIDTH;
834 tk->width = taskw - 1;
840 if (x < (width + pager_size + 2)) {
844 fill_rect(x + 2, 0, WINWIDTH, WINHEIGHT);
848 gui_draw_vline(WINWIDTH - 8);
851 draw_grill(WINWIDTH - 6);
854 task *find_task(Window win)
856 task *list = tb.task_list;
858 if (list->win == win)
865 void del_task(Window win)
867 task *next, *prev = 0, *list = tb.task_list;
871 if (list->win == win) {
872 /* unlink and free this task */
874 if (list->icon_copied) {
875 XFreePixmap(dd, list->icon);
876 if (list->mask != None)
877 XFreePixmap(dd, list->mask);
893 void move_taskbar(void)
900 x = TEXTPAD - WINWIDTH;
903 y = scr_height - WINHEIGHT;
905 XMoveWindow(dd, tb.win, x, y);
908 void taskbar_read_clientlist(void)
910 Window *win, focus_win;
911 int num, i, rev, desk, new_desk = 0;
913 desk = get_current_desktop();
920 XResizeWindow(dd, rspanelwin, WINWIDTH, WINHEIGHT);
923 if (desk != tb.my_desktop) {
925 tb.my_desktop = desk;
928 XGetInputFocus(dd, &focus_win, &rev);
930 win = get_prop_data(root_win, atom__NET_CLIENT_LIST, XA_WINDOW, &num);
934 /* remove windows that arn't in the _NET_CLIENT_LIST anymore */
937 //list->focused = (focus_win == list->win);
941 for (i = num - 1; i >= 0; i--)
942 if (list->win == win[i] && !is_hidden(win[i]))
950 /* add any new windows */
951 for (i = 0; i < num; i++) {
952 if (!find_task(win[i]))
953 add_task(win[i], (win[i] == focus_win));
959 void handle_press(int x, int y, int button)
964 if ((y > 2 && y < WINHEIGHT - 2 && x > GRILL_WIDTH) && button == 1)
965 switch_desk((x - GRILL_WIDTH) / PAGER_BUTTON_WIDTH);
968 /* clicked left grill */
971 tb.at_top = 1 - tb.at_top;
973 } else if (button == 4) {
979 /* clicked right grill */
980 else if (x + TEXTPAD > WINWIDTH) {
981 if (tb.hidden && (button == 1 || button == 5)) {
984 } else if (!tb.hidden && (button == 1 || button == 4)) {
991 /* clicked on a task button */
992 if (x > tk->pos_x && x < tk->pos_x + tk->width) {
995 if (tk->iconified && tk->shaded)
996 ob_action(tk->win, "unshade");
997 ob_action(tk->win, "activate");
1001 ob_action(tk->win, "deiconify");
1003 ob_action(tk->win, "iconify");
1006 ob_action(tk->win, "raiselower");
1009 ob_action(tk->win, "shadelower");
1012 ob_action(tk->win, "unshaderaise");
1016 ob_action(tk->win, "deiconify");
1017 ob_action(tk->win, "focus");
1020 ob_action(tk->win, "lower");
1023 ob_action(tk->win, "raise");
1029 } /* clicked on the background */
1032 ob_action(tb.win, "raise");
1035 ob_action(tb.win, "lower");
1038 ob_action(tb.win, "raiselower");
1052 void handle_focusin(Window win)
1059 if (tk->win != win) {
1064 if (tk->win == win) {
1073 void handle_propertynotify(Window win, Atom at)
1077 if (win == root_win) {
1078 if (at == atom__NET_CLIENT_LIST || at == atom__NET_CURRENT_DESKTOP || at == atom__NET_CLIENT_LIST_STACKING) {
1079 taskbar_read_clientlist();
1085 tk = find_task(win);
1089 if (at == XA_WM_NAME || at == atom__NET_WM_NAME) {
1090 /* window's title changed */
1092 if (newname = get_prop_data(tk->win, atom__NET_WM_NAME, atom_STRING_UTF8, 0) ?:
1093 get_prop_data(tk->win, XA_WM_NAME, XA_STRING, 0)) {
1094 if (tk->name && !strcmp(newname, tk->name)) {
1103 } else if (at == atom__NET_WM_STATE) {
1104 /* iconified state changed? */
1105 if (is_iconified(tk->win) != tk->iconified) {
1106 tk->iconified = !tk->iconified;
1109 /* shaded state changed? */
1110 if (is_shaded(tk->win) != tk->shaded) {
1111 tk->shaded = !tk->shaded;
1114 } else if (at == XA_WM_HINTS) {
1115 /* some windows set their WM_HINTS icon after mapping */
1116 //if (tk->icon == generic_icon) {
1117 get_task_hinticon(tk);
1120 } else if (at == atom__NET_WM_DESKTOP) {
1121 if (find_desktop(win) != get_current_desktop())
1126 void handle_error(Display * d, XErrorEvent * ev)
1134 main(int argc, char *argv[])
1141 dd = XOpenDisplay(NULL);
1144 scr_screen = DefaultScreen(dd);
1145 scr_depth = DefaultDepth(dd, scr_screen);
1146 scr_height = DisplayHeight(dd, scr_screen);
1147 scr_width = DisplayWidth(dd, scr_screen);
1148 root_win = RootWindow(dd, scr_screen);
1150 /* helps us catch windows closing/opening */
1151 XSelectInput(dd, root_win, PropertyChangeMask);
1153 XSetErrorHandler((XErrorHandler) handle_error);
1155 XInternAtoms(dd, atom_names, ATOM_COUNT, False, atoms);
1158 bzero(&tb, sizeof(struct taskbar));
1159 tb.win = gui_create_taskbar();
1160 xfd = ConnectionNumber(dd);
1166 select(xfd + 1, &fd, 0, 0, 0);
1168 while (XPending(dd)) {
1169 XNextEvent(dd, &ev);
1172 handle_press(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button);
1175 del_task(ev.xdestroywindow.window);
1180 case PropertyNotify:
1181 handle_propertynotify(ev.xproperty.window, ev.xproperty.atom);
1184 handle_focusin(ev.xfocus.window);
1187 printf ("unknown evt type: %d\n", ev.type); */
1192 /*XCloseDisplay (dd);