203 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			203 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| static Systray *systray = NULL;
 | |
| static unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ;
 | |
| 
 | |
| int
 | |
| width_systray(Bar *bar, BarArg *a)
 | |
| {
 | |
| 	unsigned int w = 0;
 | |
| 	Client *i;
 | |
| 	if (!systray)
 | |
| 		return 1;
 | |
| 	if (showsystray) {
 | |
| 		for (i = systray->icons; i; w += i->w + systrayspacing, i = i->next);
 | |
| 		if (!w)
 | |
| 			XMoveWindow(dpy, systray->win, -systray->h, bar->by);
 | |
| 	}
 | |
| 	return w ? w + lrpad - systrayspacing : 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| draw_systray(Bar *bar, BarArg *a)
 | |
| {
 | |
| 	if (!showsystray)
 | |
| 		return 0;
 | |
| 
 | |
| 	XSetWindowAttributes wa;
 | |
| 	XWindowChanges wc;
 | |
| 	Client *i;
 | |
| 	unsigned int w;
 | |
| 
 | |
| 	if (!systray) {
 | |
| 		/* init systray */
 | |
| 		if (!(systray = (Systray *)calloc(1, sizeof(Systray))))
 | |
| 			die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
 | |
| 
 | |
| 		wa.override_redirect = True;
 | |
| 		wa.event_mask = ButtonPressMask|ExposureMask;
 | |
| 		wa.border_pixel = 0;
 | |
| 		systray->h = MIN(a->h, drw->fonts->h);
 | |
| 		#if BAR_ALPHA_PATCH
 | |
| 		wa.background_pixel = 0;
 | |
| 		wa.colormap = cmap;
 | |
| 		systray->win = XCreateWindow(dpy, root, bar->bx + a->x + lrpad / 2, -systray->h, MAX(a->w + 40, 1), systray->h, 0, depth,
 | |
| 						InputOutput, visual,
 | |
| 						CWOverrideRedirect|CWBorderPixel|CWBackPixel|CWColormap|CWEventMask, &wa); // CWBackPixmap
 | |
| 		#else
 | |
| 		wa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
 | |
| 		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);
 | |
| 		XChangeWindowAttributes(dpy, systray->win, CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWEventMask, &wa);
 | |
| 		#endif // BAR_ALPHA_PATCH
 | |
| 
 | |
| 		XSelectInput(dpy, systray->win, SubstructureNotifyMask);
 | |
| 		XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
 | |
| 				PropModeReplace, (unsigned char *)&systrayorientation, 1);
 | |
| 		#if BAR_ALPHA_PATCH
 | |
| 		XChangeProperty(dpy, systray->win, netatom[NetSystemTrayVisual], XA_VISUALID, 32,
 | |
| 				PropModeReplace, (unsigned char *)&visual->visualid, 1);
 | |
| 		#endif // BAR_ALPHA_PATCH
 | |
| 		XChangeProperty(dpy, systray->win, netatom[NetWMWindowType], XA_ATOM, 32,
 | |
| 				PropModeReplace, (unsigned char *)&netatom[NetWMWindowTypeDock], 1);
 | |
| 		XMapRaised(dpy, systray->win);
 | |
| 		XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime);
 | |
| 		if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) {
 | |
| 			sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0);
 | |
| 			XSync(dpy, False);
 | |
| 		} else {
 | |
| 			fprintf(stderr, "dwm: unable to obtain system tray.\n");
 | |
| 			free(systray);
 | |
| 			systray = NULL;
 | |
| 			return 0;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	systray->bar = bar;
 | |
| 
 | |
| 	wc.stack_mode = Above;
 | |
| 	wc.sibling = bar->win;
 | |
| 	XConfigureWindow(dpy, systray->win, CWSibling|CWStackMode, &wc);
 | |
| 
 | |
| 	drw_setscheme(drw, scheme[SchemeNorm]);
 | |
| 	for (w = 0, i = systray->icons; i; i = i->next) {
 | |
| 		#if BAR_ALPHA_PATCH
 | |
| 		wa.background_pixel = 0;
 | |
| 		#else
 | |
| 		wa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
 | |
| 		#endif // BAR_ALPHA_PATCH
 | |
| 		XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa);
 | |
| 		XMapRaised(dpy, i->win);
 | |
| 		i->x = w;
 | |
| 		XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h);
 | |
| 		w += i->w;
 | |
| 		if (i->next)
 | |
| 			w += systrayspacing;
 | |
| 		if (i->mon != bar->mon)
 | |
| 			i->mon = bar->mon;
 | |
| 	}
 | |
| 
 | |
| 	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);
 | |
| 	return w;
 | |
| }
 | |
| 
 | |
| int
 | |
| click_systray(Bar *bar, Arg *arg, BarArg *a)
 | |
| {
 | |
| 	return -1;
 | |
| }
 | |
| 
 | |
| void
 | |
| removesystrayicon(Client *i)
 | |
| {
 | |
| 	Client **ii;
 | |
| 
 | |
| 	if (!showsystray || !i)
 | |
| 		return;
 | |
| 	for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next);
 | |
| 	if (ii)
 | |
| 		*ii = i->next;
 | |
| 	XReparentWindow(dpy, i->win, root, 0, 0);
 | |
| 	free(i);
 | |
| 	drawbarwin(systray->bar);
 | |
| }
 | |
| 
 | |
| void
 | |
| resizerequest(XEvent *e)
 | |
| {
 | |
| 	XResizeRequestEvent *ev = &e->xresizerequest;
 | |
| 	Client *i;
 | |
| 
 | |
| 	if ((i = wintosystrayicon(ev->window))) {
 | |
| 		updatesystrayicongeom(i, ev->width, ev->height);
 | |
| 		drawbarwin(systray->bar);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void
 | |
| updatesystrayicongeom(Client *i, int w, int h)
 | |
| {
 | |
| 	if (!systray)
 | |
| 		return;
 | |
| 
 | |
| 	int icon_height = systray->h;
 | |
| 	if (i) {
 | |
| 		i->h = icon_height;
 | |
| 		if (w == h)
 | |
| 			i->w = icon_height;
 | |
| 		else if (h == icon_height)
 | |
| 			i->w = w;
 | |
| 		else
 | |
| 			i->w = (int) ((float)icon_height * ((float)w / (float)h));
 | |
| 		applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
 | |
| 		/* force icons into the systray dimensions if they don't want to */
 | |
| 		if (i->h > icon_height) {
 | |
| 			if (i->w == i->h)
 | |
| 				i->w = icon_height;
 | |
| 			else
 | |
| 				i->w = (int) ((float)icon_height * ((float)i->w / (float)i->h));
 | |
| 			i->h = icon_height;
 | |
| 		}
 | |
| 		if (i->w > 2 * icon_height)
 | |
| 			i->w = icon_height;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void
 | |
| updatesystrayiconstate(Client *i, XPropertyEvent *ev)
 | |
| {
 | |
| 	long flags;
 | |
| 	int code = 0;
 | |
| 
 | |
| 	if (!showsystray || !systray || !i || ev->atom != xatom[XembedInfo] ||
 | |
| 			!(flags = getatomprop(i, xatom[XembedInfo], xatom[XembedInfo])))
 | |
| 		return;
 | |
| 
 | |
| 	if (flags & XEMBED_MAPPED && !i->tags) {
 | |
| 		i->tags = 1;
 | |
| 		code = XEMBED_WINDOW_ACTIVATE;
 | |
| 		XMapRaised(dpy, i->win);
 | |
| 		setclientstate(i, NormalState);
 | |
| 	}
 | |
| 	else if (!(flags & XEMBED_MAPPED) && i->tags) {
 | |
| 		i->tags = 0;
 | |
| 		code = XEMBED_WINDOW_DEACTIVATE;
 | |
| 		XUnmapWindow(dpy, i->win);
 | |
| 		setclientstate(i, WithdrawnState);
 | |
| 	}
 | |
| 	else
 | |
| 		return;
 | |
| 	sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
 | |
| 			systray->win, XEMBED_EMBEDDED_VERSION);
 | |
| }
 | |
| 
 | |
| Client *
 | |
| wintosystrayicon(Window w)
 | |
| {
 | |
| 	if (!systray)
 | |
| 		return NULL;
 | |
| 	Client *i = NULL;
 | |
| 	if (!showsystray || !w)
 | |
| 		return i;
 | |
| 	for (i = systray->icons; i && i->win != w; i = i->next);
 | |
| 	return i;
 | |
| }
 | |
| 
 |