/******************************************************** ** F***ing Small Panel 0.7 Copyright (c) 2000-2001 By ** ** Peter Zelezny ** ** See file COPYING for license details. ** ********************************************************/ #include #include #include #include #include #include #include #include #include #ifdef HAVE_XPM #include #include "icon.xpm" #endif #include "fspanel.h" /* you can edit these */ #define MAX_TASK_WIDTH 145 #define ICONWIDTH 16 #define ICONHEIGHT 16 #define WINHEIGHT 24 #define WINWIDTH (scr_width) #define FONT_NAME "-*-lucida*-m*-r-*-*-12-*-*" /* don't edit these */ #define TEXTPAD 6 #define left_arrow_x 25 #define right_arrow_x 50 Display *dd; Window root_win; /* WM supports EWMH This flag is set if the window manager supports the EWMH protocol for e.g. switching workspaces. The fallback if this is not supported is to use the Gnome variant. This is determined by looking for the presence of the _NET_SUPPORTED property of the root window. Note that this is only used for communication with the WM, whether each client supports this protocol is up to the individual client. */ int wm_use_ewmh; int always_on_top = 1; Pixmap generic_icon; Pixmap generic_mask; GC fore_gc; XFontStruct *xfs; int scr_screen; int scr_depth; int scr_width; int scr_height; int text_y; /*int time_width;*/ unsigned short cols[] = { 0xd75c, 0xd75c, 0xd75c, /* 0. light gray */ 0xbefb, 0xbaea, 0xbefb, /* 1. mid gray */ 0xaefb, 0xaaea, 0xaefb, /* 2. dark gray */ 0xefbe, 0xefbe, 0xefbe, /* 3. white */ 0x8617, 0x8207, 0x8617, /* 4. darkest gray */ 0x0000, 0x0000, 0x0000 /* 5. black */ }; #define PALETTE_COUNT (sizeof (cols) / sizeof (cols[0]) / 3) unsigned long palette[PALETTE_COUNT]; char *atom_names[] = { "KWM_WIN_ICON", "_MOTIF_WM_HINTS", "_WIN_WORKSPACE", "_WIN_HINTS", "_WIN_LAYER", "_NET_CLIENT_LIST", "_WIN_CLIENT_LIST", "_WIN_WORKSPACE_COUNT", "_WIN_STATE", "WM_STATE", "_NET_NUMBER_OF_DESKTOPS", "_NET_CURRENT_DESKTOP", "_NET_WM_STATE", "_NET_WM_STATE_ABOVE", "_NET_SUPPORTED", "_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_DESKTOP", "_NET_WM_DESKTOP", "_NET_WM_NAME", "UTF8_STRING", }; #define ATOM_COUNT (sizeof (atom_names) / sizeof (atom_names[0])) Atom atoms[ATOM_COUNT]; #define atom_KWM_WIN_ICON atoms[0] #define atom__MOTIF_WM_HINTS atoms[1] #define atom__WIN_WORKSPACE atoms[2] #define atom__WIN_HINTS atoms[3] #define atom__WIN_LAYER atoms[4] #define atom__NET_CLIENT_LIST atoms[5] #define atom__WIN_CLIENT_LIST atoms[6] #define atom__WIN_WORKSPACE_COUNT atoms[7] #define atom__WIN_STATE atoms[8] #define atom_WM_STATE atoms[9] #define atom__NET_NUMBER_OF_DESKTOPS atoms[10] #define atom__NET_CURRENT_DESKTOP atoms[11] #define atom__NET_WM_STATE atoms[12] #define atom__NET_WM_STATE_ABOVE atoms[13] #define atom__NET_SUPPORTED atoms[14] #define atom__NET_WM_WINDOW_TYPE atoms[15] #define atom__NET_WM_WINDOW_TYPE_DESKTOP atoms[16] #define atom__NET_WM_DESKTOP atoms[17] #define atom__NET_WM_NAME atoms[18] #define atom_UTF8_STRING atoms[19] void * get_prop_data (Window win, Atom prop, Atom type, int *items) { Atom type_ret; int format_ret; unsigned long items_ret; unsigned long after_ret; unsigned char *prop_data; prop_data = 0; XGetWindowProperty (dd, win, prop, 0, 0x7fffffff, False, type, &type_ret, &format_ret, &items_ret, &after_ret, &prop_data); if (items) *items = items_ret; return prop_data; } void set_foreground (int index) { XSetForeground (dd, fore_gc, palette[index]); } void draw_line (taskbar *tb, int x, int y, int a, int b) { XDrawLine (dd, tb->win, fore_gc, x, y, a, b); } void fill_rect (taskbar *tb, int x, int y, int a, int b) { XFillRectangle (dd, tb->win, fore_gc, x, y, a, b); } void scale_icon (task *tk) { int xx, yy, x, y; unsigned int w, h, d, bw; Pixmap pix, mk = None; XGCValues gcv; GC mgc = None; Window unused; XGetGeometry (dd, tk->icon, &unused, &x, &y, &w, &h, &bw, &d); pix = XCreatePixmap (dd, tk->win, ICONWIDTH, ICONHEIGHT, scr_depth); if (tk->mask != None) { mk = XCreatePixmap (dd, tk->win, ICONWIDTH, ICONHEIGHT, 1); gcv.subwindow_mode = IncludeInferiors; gcv.graphics_exposures = False; mgc = XCreateGC (dd, mk, GCGraphicsExposures | GCSubwindowMode, &gcv); } set_foreground (3); /* this is my simple & dirty scaling routine */ for (y = ICONHEIGHT - 1; y >= 0; y--) { yy = (y * h) / ICONHEIGHT; for (x = ICONWIDTH - 1; x >= 0; x--) { xx = (x * w) / ICONWIDTH; if (d != scr_depth) XCopyPlane (dd, tk->icon, pix, fore_gc, xx, yy, 1, 1, x, y, 1); else XCopyArea (dd, tk->icon, pix, fore_gc, xx, yy, 1, 1, x, y); if (mk != None) XCopyArea (dd, tk->mask, mk, mgc, xx, yy, 1, 1, x, y); } } if (mk != None) { XFreeGC (dd, mgc); tk->mask = mk; } tk->icon = pix; } void get_task_hinticon (task *tk) { XWMHints *hin; tk->icon = None; tk->mask = None; hin = (XWMHints *) get_prop_data (tk->win, XA_WM_HINTS, XA_WM_HINTS, 0); if (hin) { if ((hin->flags & IconPixmapHint)) { if ((hin->flags & IconMaskHint)) { tk->mask = hin->icon_mask; } tk->icon = hin->icon_pixmap; tk->icon_copied = 1; scale_icon (tk); } XFree (hin); } if (tk->icon == None) { tk->icon = generic_icon; tk->mask = generic_mask; } } void get_task_kdeicon (task *tk) { unsigned long *data; data = get_prop_data (tk->win, atom_KWM_WIN_ICON, atom_KWM_WIN_ICON, 0); if (data) { tk->icon = data[0]; tk->mask = data[1]; XFree (data); } } /* returns whether the window is visible on the desktop */ int is_visible_on_desktop (Window win, int desk) { int client_desk = -1; unsigned long *data; if (wm_use_ewmh) data = get_prop_data (win, atom__NET_WM_DESKTOP, XA_CARDINAL, 0); else data = get_prop_data (win, atom__WIN_WORKSPACE, XA_CARDINAL, 0); if (data) { client_desk = *data; XFree (data); } /* If the client_desk is -1, it is visible on all desktops */ return (client_desk == -1) || (client_desk == desk); } /* index of the currently displayed desktop */ int get_current_desktop () { int desk = 0; unsigned long *data; if (wm_use_ewmh) data = get_prop_data (root_win, atom__NET_CURRENT_DESKTOP, XA_CARDINAL, 0); else data = get_prop_data (root_win, atom__WIN_WORKSPACE, XA_CARDINAL, 0); if (data) { desk = *data; XFree (data); } return desk; } int is_hidden (Window win) { unsigned long *data; int ret = 0; data = get_prop_data (win, atom__WIN_HINTS, XA_CARDINAL, 0); if (data) { if ((*data) & WIN_HINTS_SKIP_TASKBAR) ret = 1; XFree (data); } return ret; } int is_iconified (Window win) { unsigned long *data; int ret = 0; data = get_prop_data (win, atom_WM_STATE, atom_WM_STATE, 0); if (data) { if (data[0] == IconicState) ret = 1; XFree (data); } return ret; } /* window name The returned pointer must be freed using XFree() after use. TODO: The encoding for WM_NAME can be STRING or COMPOUND_TEXT. In any case this encoding should be normalized before returning from this function. */ char* get_window_name (Window win) { char* res = NULL; /* try EWMH's _NET_WM_NAME first */ res = get_prop_data (win, atom__NET_WM_NAME, atom_UTF8_STRING, 0); if (!res) /* fallback to WM_NAME */ res = get_prop_data (win, XA_WM_NAME, XA_STRING, 0); return res; } void add_task (taskbar * tb, Window win, int focus) { task *tk, *list; /* is this window on a different desktop or hidden? */ if (!is_visible_on_desktop (win, tb->my_desktop) || is_hidden (win)) return; tk = calloc (1, sizeof (task)); tk->win = win; tk->focused = focus; tk->name = get_window_name (win); tk->iconified = is_iconified (win); get_task_kdeicon (tk); if (tk->icon == None) get_task_hinticon (tk); XSelectInput (dd, win, PropertyChangeMask | FocusChangeMask | StructureNotifyMask); /* now append it to our linked list */ tb->num_tasks++; list = tb->task_list; if (!list) { tb->task_list = tk; return; } while (1) { if (!list->next) { list->next = tk; return; } list = list->next; } } void gui_sync (void) { XSync (dd, False); } void set_prop (Window win, Atom at, long val) { XChangeProperty (dd, win, at, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &val, 1); } taskbar * gui_create_taskbar (void) { taskbar *tb; Window win; XClassHint wm_class; MWMHints mwm; XSizeHints size_hints; XWMHints wmhints; XSetWindowAttributes att; att.background_pixel = palette[0]; att.event_mask = ButtonPressMask | ExposureMask; win = XCreateWindow ( /* display */ dd, /* parent */ root_win, /* x */ 0, /* y */ scr_height - WINHEIGHT, /* width */ WINWIDTH, /* height */ WINHEIGHT, /* border */ 0, /* depth */ CopyFromParent, /* class */ InputOutput, /* visual */ CopyFromParent, /*value mask*/ CWBackPixel | CWEventMask, /* attribs */ &att); /* set name and class */ wm_class.res_name = "fspanel"; wm_class.res_class = "fspanel"; XSetClassHint (dd, win, &wm_class); /* don't let any windows cover fspanel */ if (wm_use_ewmh) { if (always_on_top) { XChangeProperty (dd, win, atom__NET_WM_STATE, XA_ATOM, 32, PropModeReplace, (unsigned char *) &atom__NET_WM_STATE_ABOVE, 1); } XChangeProperty (dd, win, atom__NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (unsigned char *) &atom__NET_WM_WINDOW_TYPE_DESKTOP, 1); } else { set_prop (win, atom__WIN_LAYER, 10); /* WIN_LAYER_ABOVE_DOCK */ set_prop (win, atom__WIN_STATE, WIN_STATE_STICKY | WIN_STATE_FIXED_POSITION); } set_prop (win, atom__WIN_HINTS, WIN_HINTS_SKIP_FOCUS | WIN_HINTS_SKIP_WINLIST | WIN_HINTS_SKIP_TASKBAR | WIN_HINTS_DO_NOT_COVER); /* borderless motif hint */ memset (&mwm, 0, sizeof (mwm)); mwm.flags = MWM_HINTS_DECORATIONS; XChangeProperty (dd, win, atom__MOTIF_WM_HINTS, atom__MOTIF_WM_HINTS, 32, PropModeReplace, (unsigned char *) &mwm, sizeof (MWMHints) / 4); /* make sure the WM obeys our window position */ size_hints.flags = PPosition; /*XSetWMNormalHints (dd, win, &size_hints);*/ XChangeProperty (dd, win, XA_WM_NORMAL_HINTS, XA_WM_SIZE_HINTS, 32, PropModeReplace, (unsigned char *) &size_hints, sizeof (XSizeHints) / 4); /* make our window unfocusable */ wmhints.flags = InputHint; wmhints.input = 0; /*XSetWMHints (dd, win, &wmhints);*/ XChangeProperty (dd, win, XA_WM_HINTS, XA_WM_HINTS, 32, PropModeReplace, (unsigned char *) &wmhints, sizeof (XWMHints) / 4); XMapWindow (dd, win); tb = calloc (1, sizeof (taskbar)); tb->win = win; return tb; } void gui_init (void) { XGCValues gcv; XColor xcl; int i, j; char *fontname; i = j = 0; do { xcl.red = cols[i]; i++; xcl.green = cols[i]; i++; xcl.blue = cols[i]; i++; XAllocColor (dd, DefaultColormap (dd, scr_screen), &xcl); palette[j] = xcl.pixel; j++; } while (j < PALETTE_COUNT); fontname = FONT_NAME; do { xfs = XLoadQueryFont (dd, fontname); fontname = "fixed"; } while (!xfs); /*time_width = XTextWidth (xfs, "88:88", 5); */ #define time_width (35) text_y = xfs->ascent + ((WINHEIGHT - xfs->ascent) / 2); gcv.font = xfs->fid; gcv.graphics_exposures = False; fore_gc = XCreateGC (dd, root_win, GCFont | GCGraphicsExposures, &gcv); #ifdef HAVE_XPM XpmCreatePixmapFromData (dd, root_win, icon_xpm, &generic_icon, &generic_mask, NULL); #else generic_icon = 0; #endif } void gui_draw_vline (taskbar * tb, int x) { set_foreground (4); draw_line (tb, x, 0, x, WINHEIGHT); set_foreground (3); draw_line (tb, x + 1, 0, x + 1, WINHEIGHT); } void gui_draw_task (taskbar * tb, task * tk) { int len; int x = tk->pos_x; int taskw = tk->width; if (!tk->name) return; gui_draw_vline (tb, x); /*set_foreground (3); *//* it's already 3 from gui_draw_vline() */ draw_line (tb, x + 1, 0, x + taskw, 0); set_foreground (1); draw_line (tb, x + 1, WINHEIGHT - 1, x + taskw, WINHEIGHT - 1); if (tk->focused) { x++; /*set_foreground (1);*/ /* mid gray */ fill_rect (tb, x + 3, 3, taskw - 5, WINHEIGHT - 6); set_foreground (3); /* white */ draw_line (tb, x + 2, WINHEIGHT - 2, x + taskw - 2, WINHEIGHT - 2); draw_line (tb, x + taskw - 2, 2, x + taskw - 2, WINHEIGHT - 2); set_foreground (0); draw_line (tb, x + 1, 2, x + 1, WINHEIGHT - 2); set_foreground (4); /* darkest gray */ draw_line (tb, x + 2, 2, x + taskw - 2, 2); draw_line (tb, x + 2, 2, x + 2, WINHEIGHT - 3); } else { set_foreground (0); /* mid gray */ fill_rect (tb, x + 2, 1, taskw - 1, WINHEIGHT - 2); } { register int text_x = x + TEXTPAD + TEXTPAD + ICONWIDTH; /* check how many chars can fit */ len = strlen (tk->name); while (XTextWidth (xfs, tk->name, len) >= taskw - (text_x - x) - 2 && len > 0) len--; if (tk->iconified) { /* draw task's name dark (iconified) */ set_foreground (3); XDrawString (dd, tb->win, fore_gc, text_x, text_y + 1, tk->name, len); set_foreground (4); } else { set_foreground (5); } /* draw task's name here */ XDrawString (dd, tb->win, fore_gc, text_x, text_y, tk->name, len); } #ifndef HAVE_XPM if (!tk->icon) return; #endif /* draw the task's icon */ XSetClipMask (dd, fore_gc, tk->mask); XSetClipOrigin (dd, fore_gc, x + TEXTPAD, (WINHEIGHT - ICONHEIGHT) / 2); XCopyArea (dd, tk->icon, tb->win, fore_gc, 0, 0, ICONWIDTH, ICONHEIGHT, x + TEXTPAD, (WINHEIGHT - ICONHEIGHT) / 2); XSetClipMask (dd, fore_gc, None); } void gui_draw_clock (taskbar * tb) { char *time_str; time_t now; int width, old_x, x = WINWIDTH - time_width - (TEXTPAD * 4); old_x = x; width = WINWIDTH - x - 2; now = time (0); time_str = ctime (&now) + 11; gui_draw_vline (tb, x); x += TEXTPAD; /*set_foreground (3); *//* white *//* it's already 3 from gui_draw_vline() */ draw_line (tb, x + 1, WINHEIGHT - 2, old_x + width - TEXTPAD, WINHEIGHT - 2); draw_line (tb, old_x + width - TEXTPAD, 2, old_x + width - TEXTPAD, WINHEIGHT - 2); set_foreground (1); /* mid gray */ fill_rect (tb, x + 1, 2, width - (TEXTPAD * 2) - 1, WINHEIGHT - 4); set_foreground (4); /* darkest gray */ draw_line (tb, x, 2, x + width - (TEXTPAD * 2) - 1, 2); draw_line (tb, x, 2, x, WINHEIGHT - 2); set_foreground (5); XDrawString (dd, tb->win, fore_gc, x + TEXTPAD - 1, text_y, time_str, 5); } void draw_dot (Window win, int x, int y) { set_foreground (4); XDrawPoint (dd, win, fore_gc, x, y); set_foreground (3); XDrawPoint (dd, win, fore_gc, x + 1, y + 1); } void draw_grill (Window win, int x) { int y = 0; while (y < WINHEIGHT - 4) { y += 3; draw_dot (win, x + 3, y); draw_dot (win, x, y); } } void draw_up_triangle (taskbar *tb) { fill_rect (tb, left_arrow_x + 2, (WINHEIGHT - 4) / 2 + 1, 3, 3); draw_line (tb, left_arrow_x, (WINHEIGHT - 4) / 2 + 3, left_arrow_x + 3, (WINHEIGHT - 4) / 2); draw_line (tb, left_arrow_x + 3, (WINHEIGHT - 4) / 2, left_arrow_x + 6, (WINHEIGHT - 4) / 2 + 3); draw_line (tb, left_arrow_x + 1, (WINHEIGHT - 4) / 2 + 3, left_arrow_x + 5, (WINHEIGHT - 4) / 2 + 3); } void draw_down_triangle (taskbar *tb) { draw_line (tb, right_arrow_x, (WINHEIGHT - 4) / 2, right_arrow_x + 3, (WINHEIGHT - 4) / 2 + 3); draw_line (tb, right_arrow_x, (WINHEIGHT - 4) / 2, right_arrow_x + 4, (WINHEIGHT - 4) / 2 + 2); draw_line (tb, right_arrow_x, (WINHEIGHT - 4) / 2, right_arrow_x + 5, (WINHEIGHT - 4) / 2 + 1); draw_line (tb, right_arrow_x, (WINHEIGHT - 4) / 2, right_arrow_x + 6, (WINHEIGHT - 4) / 2); } void gui_draw_taskbar (taskbar * tb) { task *tk; int x, width, taskw; int under = 0; set_foreground (5); /* black */ draw_up_triangle (tb); draw_down_triangle (tb); width = WINWIDTH - 80 - time_width - (TEXTPAD * 4); x = 80; if (tb->num_tasks == 0) goto clear; taskw = width / tb->num_tasks; if (taskw > MAX_TASK_WIDTH) { taskw = MAX_TASK_WIDTH; under = 1; } tk = tb->task_list; while (tk) { tk->pos_x = x; tk->width = taskw - 1; gui_draw_task (tb, tk); x += taskw; tk = tk->next; } if (under) { clear: gui_draw_vline (tb, x); set_foreground (0); fill_rect (tb, x + 2, 0, WINWIDTH, WINHEIGHT); } gui_draw_clock (tb); gui_draw_vline (tb, 8); gui_draw_vline (tb, 74); draw_grill (tb->win, 2); draw_grill (tb->win, WINWIDTH - 6); } task * find_task (taskbar * tb, Window win) { task *list = tb->task_list; while (list) { if (list->win == win) return list; list = list->next; } return 0; } void del_task (taskbar * tb, Window win) { task *next, *prev = 0, *list = tb->task_list; while (list) { next = list->next; if (list->win == win) { /* unlink and free this task */ tb->num_tasks--; if (list->icon_copied) { XFreePixmap (dd, list->icon); if (list->mask != None) XFreePixmap (dd, list->mask); } if (list->name) XFree (list->name); free (list); if (prev == 0) tb->task_list = next; else prev->next = next; return; } prev = list; list = next; } } void taskbar_read_clientlist (taskbar * tb) { Window *win, focus_win; int num, i, rev, desk, new_desk = 0; task *list, *next; desk = get_current_desktop (); if (desk != tb->my_desktop) { new_desk = 1; tb->my_desktop = desk; } XGetInputFocus (dd, &focus_win, &rev); /* try unified window spec first */ win = get_prop_data (root_win, atom__NET_CLIENT_LIST, XA_WINDOW, &num); if (!win) { /* failed, let's try gnome */ win = get_prop_data (root_win, atom__WIN_CLIENT_LIST, XA_CARDINAL, &num); if (!win) return; } /* remove windows that aren't in the _WIN_CLIENT_LIST anymore */ list = tb->task_list; while (list) { list->focused = (focus_win == list->win); next = list->next; if (!new_desk) for (i = num - 1; i >= 0; i--) if (list->win == win[i]) goto dontdel; del_task (tb, list->win); dontdel: list = next; } /* add any new windows */ for (i = 0; i < num; i++) { if (!find_task (tb, win[i])) add_task (tb, win[i], (win[i] == focus_win)); } XFree (win); } void move_taskbar (taskbar * tb) { int x, y; x = y = 0; if (tb->hidden) x = WINWIDTH - TEXTPAD; if (!tb->at_top) y = scr_height - WINHEIGHT; XMoveWindow (dd, tb->win, x, y); } void switch_desk (taskbar * tb, int rel) { XClientMessageEvent xev; unsigned long *data, max_desks; int want = tb->my_desktop + rel; if (want < 0) return; if (wm_use_ewmh) data = get_prop_data (root_win, atom__NET_NUMBER_OF_DESKTOPS, XA_CARDINAL, 0); else data = get_prop_data (root_win, atom__WIN_WORKSPACE_COUNT, XA_CARDINAL, 0); if (!data) /* number of workspaces not available */ return; max_desks = *data; XFree (data); if (max_desks <= want) return; xev.type = ClientMessage; xev.window = root_win; if (wm_use_ewmh) xev.message_type = atom__NET_CURRENT_DESKTOP; else xev.message_type = atom__WIN_WORKSPACE; xev.format = 32; xev.data.l[0] = want; XSendEvent (dd, root_win, False, SubstructureNotifyMask, (XEvent *) &xev); } void handle_press (taskbar * tb, int x, int y) { task *tk; if (y > 3 && y < WINHEIGHT - 3) { if (x >= right_arrow_x && x < right_arrow_x + 9) { switch_desk (tb, +1); return; } if (x >= left_arrow_x && x < left_arrow_x + 9) { switch_desk (tb, -1); return; } } /* clicked left grill */ if (x < 6) { if (tb->hidden) tb->hidden = 0; else tb->at_top = !tb->at_top; move_taskbar (tb); return; } /* clicked right grill */ if (x + TEXTPAD > WINWIDTH) { tb->hidden = !tb->hidden; move_taskbar (tb); return; } tk = tb->task_list; while (tk) { if (x > tk->pos_x && x < tk->pos_x + tk->width) { if (tk->iconified) { tk->iconified = 0; tk->focused = 1; XMapWindow (dd, tk->win); } else { if (tk->focused) { tk->iconified = 1; tk->focused = 0; XIconifyWindow (dd, tk->win, scr_screen); } else { tk->focused = 1; XRaiseWindow (dd, tk->win); XSetInputFocus (dd, tk->win, RevertToNone, CurrentTime); } } gui_sync (); gui_draw_task (tb, tk); } else { if (tk->focused) { tk->focused = 0; gui_draw_task (tb, tk); } } tk = tk->next; } } void handle_focusin (taskbar * tb, Window win) { task *tk; tk = tb->task_list; while (tk) { if (tk->focused) { if (tk->win != win) { tk->focused = 0; gui_draw_task (tb, tk); } } else { if (tk->win == win) { tk->focused = 1; gui_draw_task (tb, tk); } } tk = tk->next; } } void handle_propertynotify (taskbar * tb, Window win, Atom at) { task *tk; if (win == root_win) { if (wm_use_ewmh) { if (at == atom__NET_CLIENT_LIST || at == atom__NET_CURRENT_DESKTOP) { taskbar_read_clientlist (tb); gui_draw_taskbar (tb); } } else { if (at == atom__WIN_CLIENT_LIST || at == atom__WIN_WORKSPACE) { taskbar_read_clientlist (tb); gui_draw_taskbar (tb); } } return; } tk = find_task (tb, win); if (!tk) return; if (at == XA_WM_NAME || at == atom__NET_WM_NAME) { /* window's title changed */ if (tk->name) XFree (tk->name); tk->name = get_window_name (tk->win); gui_draw_task (tb, tk); } else if (at == atom_WM_STATE) { /* iconified state changed? */ if (is_iconified (tk->win) != tk->iconified) { tk->iconified = !tk->iconified; gui_draw_task (tb, tk); } } else if (at == XA_WM_HINTS) { /* some windows set their WM_HINTS icon after mapping */ if (tk->icon == generic_icon) { get_task_hinticon (tk); gui_draw_task (tb, tk); } } } void handle_error (Display * d, XErrorEvent * ev) { } int #ifdef NOSTDLIB _start (void) #else main (int argc, char *argv[]) #endif { taskbar *tb; XEvent ev; fd_set fd; struct timeval tv; int xfd; int i; time_t now; struct tm *lt; void *prop; dd = XOpenDisplay (NULL); if (!dd) return 0; scr_screen = DefaultScreen (dd); scr_depth = DefaultDepth (dd, scr_screen); scr_height = DisplayHeight (dd, scr_screen); scr_width = DisplayWidth (dd, scr_screen); root_win = RootWindow (dd, scr_screen); for (i = 1; i < argc; ++i) { if (strcmp("--background", argv[i]) == 0) { always_on_top = 0; } } /* helps us catch windows closing/opening */ XSelectInput (dd, root_win, PropertyChangeMask); XSetErrorHandler ((XErrorHandler) handle_error); XInternAtoms (dd, atom_names, ATOM_COUNT, False, atoms); /* check if the WM supports EWMH Note that this is not reliable. When switching to a EWMH-unaware WM, it will not delete this property. Also, we can't react to changes in this without a restart. */ prop = get_prop_data (root_win, atom__NET_SUPPORTED, XA_ATOM, NULL); if (prop) { wm_use_ewmh = 1; XFree (prop); } gui_init (); tb = gui_create_taskbar (); xfd = ConnectionNumber (dd); gui_sync (); while (1) { now = time (0); lt = gmtime (&now); tv.tv_usec = 0; tv.tv_sec = 60 - lt->tm_sec; FD_ZERO (&fd); FD_SET (xfd, &fd); if (select (xfd + 1, &fd, 0, 0, &tv) == 0) gui_draw_clock (tb); while (XPending (dd)) { XNextEvent (dd, &ev); switch (ev.type) { case ButtonPress: if (ev.xbutton.button == 1) handle_press (tb, ev.xbutton.x, ev.xbutton.y); break; case DestroyNotify: del_task (tb, ev.xdestroywindow.window); /* fall through */ case Expose: gui_draw_taskbar (tb); break; case PropertyNotify: handle_propertynotify (tb, ev.xproperty.window, ev.xproperty.atom); break; case FocusIn: handle_focusin (tb, ev.xfocus.window); break; /*default: printf ("unknown evt type: %d\n", ev.type);*/ } } } /*XCloseDisplay (dd); return 0;*/ }