bar_systray.c (5654B)
1 static Systray *systray = NULL; 2 static unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ; 3 4 int 5 width_systray(Bar *bar, BarArg *a) 6 { 7 unsigned int w = 0; 8 Client *i; 9 if (!systray) 10 return 1; 11 if (showsystray) { 12 for (i = systray->icons; i; w += i->w + systrayspacing, i = i->next); 13 if (!w) 14 XMoveWindow(dpy, systray->win, -systray->h, bar->by); 15 } 16 return w ? w + lrpad - systrayspacing : 0; 17 } 18 19 int 20 draw_systray(Bar *bar, BarArg *a) 21 { 22 if (!showsystray) 23 return 0; 24 25 XSetWindowAttributes wa; 26 XWindowChanges wc; 27 Client *i; 28 unsigned int w; 29 30 if (!systray) { 31 /* init systray */ 32 if (!(systray = (Systray *)calloc(1, sizeof(Systray)))) 33 die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); 34 35 wa.override_redirect = True; 36 wa.event_mask = ButtonPressMask|ExposureMask; 37 wa.border_pixel = 0; 38 systray->h = MIN(a->h, drw->fonts->h); 39 #if BAR_ALPHA_PATCH 40 wa.background_pixel = 0; 41 wa.colormap = cmap; 42 systray->win = XCreateWindow(dpy, root, bar->bx + a->x + lrpad / 2, -systray->h, MAX(a->w + 40, 1), systray->h, 0, depth, 43 InputOutput, visual, 44 CWOverrideRedirect|CWBorderPixel|CWBackPixel|CWColormap|CWEventMask, &wa); // CWBackPixmap 45 #else 46 wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; 47 systray->win = XCreateSimpleWindow(dpy, root, bar->bx + a->x + lrpad / 2, -systray->h, MIN(a->w, 1), systray->h, 0, 0, scheme[SchemeNorm][ColBg].pixel); 48 XChangeWindowAttributes(dpy, systray->win, CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWEventMask, &wa); 49 #endif // BAR_ALPHA_PATCH 50 51 XSelectInput(dpy, systray->win, SubstructureNotifyMask); 52 XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, 53 PropModeReplace, (unsigned char *)&systrayorientation, 1); 54 #if BAR_ALPHA_PATCH 55 XChangeProperty(dpy, systray->win, netatom[NetSystemTrayVisual], XA_VISUALID, 32, 56 PropModeReplace, (unsigned char *)&visual->visualid, 1); 57 #endif // BAR_ALPHA_PATCH 58 XChangeProperty(dpy, systray->win, netatom[NetWMWindowType], XA_ATOM, 32, 59 PropModeReplace, (unsigned char *)&netatom[NetWMWindowTypeDock], 1); 60 XMapRaised(dpy, systray->win); 61 XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); 62 if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { 63 sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0); 64 XSync(dpy, False); 65 } else { 66 fprintf(stderr, "dwm: unable to obtain system tray.\n"); 67 free(systray); 68 systray = NULL; 69 return 0; 70 } 71 } 72 73 systray->bar = bar; 74 75 wc.stack_mode = Above; 76 wc.sibling = bar->win; 77 XConfigureWindow(dpy, systray->win, CWSibling|CWStackMode, &wc); 78 79 drw_setscheme(drw, scheme[SchemeNorm]); 80 for (w = 0, i = systray->icons; i; i = i->next) { 81 #if BAR_ALPHA_PATCH 82 wa.background_pixel = 0; 83 #else 84 wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; 85 #endif // BAR_ALPHA_PATCH 86 XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); 87 XMapRaised(dpy, i->win); 88 i->x = w; 89 XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); 90 w += i->w; 91 if (i->next) 92 w += systrayspacing; 93 if (i->mon != bar->mon) 94 i->mon = bar->mon; 95 } 96 97 #if !BAR_ALPHA_PATCH 98 wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; 99 XChangeWindowAttributes(dpy, systray->win, CWBackPixel, &wa); 100 XClearWindow(dpy, systray->win); 101 #endif // BAR_ALPHA_PATCH 102 103 XMoveResizeWindow(dpy, systray->win, bar->bx + a->x + lrpad / 2, (w ? bar->by + a->y + (a->h - systray->h) / 2: -systray->h), MAX(w, 1), systray->h); 104 return w; 105 } 106 107 int 108 click_systray(Bar *bar, Arg *arg, BarArg *a) 109 { 110 return -1; 111 } 112 113 void 114 removesystrayicon(Client *i) 115 { 116 Client **ii; 117 118 if (!showsystray || !i) 119 return; 120 for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); 121 if (ii) 122 *ii = i->next; 123 XReparentWindow(dpy, i->win, root, 0, 0); 124 free(i); 125 drawbarwin(systray->bar); 126 } 127 128 void 129 resizerequest(XEvent *e) 130 { 131 XResizeRequestEvent *ev = &e->xresizerequest; 132 Client *i; 133 134 if ((i = wintosystrayicon(ev->window))) { 135 updatesystrayicongeom(i, ev->width, ev->height); 136 drawbarwin(systray->bar); 137 } 138 } 139 140 void 141 updatesystrayicongeom(Client *i, int w, int h) 142 { 143 if (!systray) 144 return; 145 146 int icon_height = systray->h; 147 if (i) { 148 i->h = icon_height; 149 if (w == h) 150 i->w = icon_height; 151 else if (h == icon_height) 152 i->w = w; 153 else 154 i->w = (int) ((float)icon_height * ((float)w / (float)h)); 155 applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); 156 /* force icons into the systray dimensions if they don't want to */ 157 if (i->h > icon_height) { 158 if (i->w == i->h) 159 i->w = icon_height; 160 else 161 i->w = (int) ((float)icon_height * ((float)i->w / (float)i->h)); 162 i->h = icon_height; 163 } 164 if (i->w > 2 * icon_height) 165 i->w = icon_height; 166 } 167 } 168 169 void 170 updatesystrayiconstate(Client *i, XPropertyEvent *ev) 171 { 172 long flags; 173 int code = 0; 174 175 if (!showsystray || !systray || !i || ev->atom != xatom[XembedInfo] || 176 !(flags = getatomprop(i, xatom[XembedInfo], xatom[XembedInfo]))) 177 return; 178 179 if (flags & XEMBED_MAPPED && !i->tags) { 180 i->tags = 1; 181 code = XEMBED_WINDOW_ACTIVATE; 182 XMapRaised(dpy, i->win); 183 setclientstate(i, NormalState); 184 } 185 else if (!(flags & XEMBED_MAPPED) && i->tags) { 186 i->tags = 0; 187 code = XEMBED_WINDOW_DEACTIVATE; 188 XUnmapWindow(dpy, i->win); 189 setclientstate(i, WithdrawnState); 190 } 191 else 192 return; 193 sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0, 194 systray->win, XEMBED_EMBEDDED_VERSION); 195 } 196 197 Client * 198 wintosystrayicon(Window w) 199 { 200 if (!systray) 201 return NULL; 202 Client *i = NULL; 203 if (!showsystray || !w) 204 return i; 205 for (i = systray->icons; i && i->win != w; i = i->next); 206 return i; 207 } 208