/* * calmwm - the calm window manager * * Copyright (c) 2004 Marius Aamodt Eriksen * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $OpenBSD: screen.c,v 1.95 2020/02/27 14:56:39 okan Exp $ */ #include #include #include #include #include #include #include #include #include #include #include "calmwm.h" static struct geom screen_apply_gap(struct screen_ctx *, struct geom); static void screen_scan(struct screen_ctx *, Window); void screen_init(int which) { struct screen_ctx *sc; Window active = None; XSetWindowAttributes rootattr; sc = xmalloc(sizeof(*sc)); TAILQ_INIT(&sc->clientq); TAILQ_INIT(&sc->regionq); TAILQ_INIT(&sc->groupq); sc->which = which; sc->rootwin = RootWindow(X_Dpy, sc->which); sc->colormap = DefaultColormap(X_Dpy, sc->which); sc->visual = DefaultVisual(X_Dpy, sc->which); sc->cycling = 0; sc->hideall = 0; conf_screen(sc); xu_ewmh_net_supported(sc); xu_ewmh_net_supported_wm_check(sc); conf_group(sc); screen_update_geometry(sc); xu_ewmh_net_desktop_names(sc); xu_ewmh_net_number_of_desktops(sc); xu_ewmh_net_showing_desktop(sc); xu_ewmh_net_virtual_roots(sc); active = xu_ewmh_get_net_active_window(sc); rootattr.cursor = Conf.cursor[CF_NORMAL]; rootattr.event_mask = SubstructureRedirectMask | SubstructureNotifyMask | PropertyChangeMask | EnterWindowMask | LeaveWindowMask | ColormapChangeMask | BUTTONMASK; XChangeWindowAttributes(X_Dpy, sc->rootwin, (CWEventMask | CWCursor), &rootattr); screen_scan(sc, active); screen_updatestackingorder(sc); if (Conf.xrandr) XRRSelectInput(X_Dpy, sc->rootwin, RRScreenChangeNotifyMask); TAILQ_INSERT_TAIL(&Screenq, sc, entry); XSync(X_Dpy, False); } static void screen_scan(struct screen_ctx *sc, Window active) { Window *wins, w0, w1; unsigned int nwins, i; if (XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins)) { for (i = 0; i < nwins; i++) (void)client_init(wins[i], sc, (active == wins[i])); XFree(wins); } } struct screen_ctx * screen_find(Window win) { struct screen_ctx *sc; TAILQ_FOREACH(sc, &Screenq, entry) { if (sc->rootwin == win) return sc; } warnx("%s: failure win 0x%lx", __func__, win); return NULL; } void screen_updatestackingorder(struct screen_ctx *sc) { Window *wins, w0, w1; struct client_ctx *cc; unsigned int nwins, i, s; if (XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins)) { for (s = 0, i = 0; i < nwins; i++) { /* Skip hidden windows */ if ((cc = client_find(wins[i])) == NULL || cc->flags & CLIENT_HIDDEN) continue; cc->stackingorder = s++; } XFree(wins); } } struct region_ctx * region_find(struct screen_ctx *sc, int x, int y) { struct region_ctx *rc; TAILQ_FOREACH(rc, &sc->regionq, entry) { if ((x >= rc->view.x) && (x < (rc->view.x + rc->view.w)) && (y >= rc->view.y) && (y < (rc->view.y + rc->view.h))) { break; } } return rc; } struct geom screen_area(struct screen_ctx *sc, int x, int y, int apply_gap) { struct region_ctx *rc; struct geom area = sc->view; TAILQ_FOREACH(rc, &sc->regionq, entry) { if ((x >= rc->view.x) && (x < (rc->view.x + rc->view.w)) && (y >= rc->view.y) && (y < (rc->view.y + rc->view.h))) { area = rc->view; break; } } if (apply_gap) area = screen_apply_gap(sc, area); return area; } void screen_update_geometry(struct screen_ctx *sc) { struct region_ctx *rc; sc->view.x = 0; sc->view.y = 0; sc->view.w = DisplayWidth(X_Dpy, sc->which); sc->view.h = DisplayHeight(X_Dpy, sc->which); sc->work = screen_apply_gap(sc, sc->view); while ((rc = TAILQ_FIRST(&sc->regionq)) != NULL) { TAILQ_REMOVE(&sc->regionq, rc, entry); free(rc); } if (Conf.xrandr) { XRRScreenResources *sr; XRRCrtcInfo *ci; int i; sr = XRRGetScreenResources(X_Dpy, sc->rootwin); for (i = 0, ci = NULL; i < sr->ncrtc; i++) { ci = XRRGetCrtcInfo(X_Dpy, sr, sr->crtcs[i]); if (ci == NULL) continue; if (ci->noutput == 0) { XRRFreeCrtcInfo(ci); continue; } rc = xmalloc(sizeof(*rc)); rc->num = i; rc->view.x = ci->x; rc->view.y = ci->y; rc->view.w = ci->width; rc->view.h = ci->height; rc->work = screen_apply_gap(sc, rc->view); TAILQ_INSERT_TAIL(&sc->regionq, rc, entry); XRRFreeCrtcInfo(ci); } XRRFreeScreenResources(sr); } else { rc = xmalloc(sizeof(*rc)); rc->num = 0; rc->view.x = 0; rc->view.y = 0; rc->view.w = DisplayWidth(X_Dpy, sc->which); rc->view.h = DisplayHeight(X_Dpy, sc->which); rc->work = screen_apply_gap(sc, rc->view); TAILQ_INSERT_TAIL(&sc->regionq, rc, entry); } xu_ewmh_net_desktop_geometry(sc); xu_ewmh_net_desktop_viewport(sc); xu_ewmh_net_workarea(sc); } static struct geom screen_apply_gap(struct screen_ctx *sc, struct geom geom) { geom.x += sc->gap.left; geom.y += sc->gap.top; geom.w -= (sc->gap.left + sc->gap.right); geom.h -= (sc->gap.top + sc->gap.bottom); return geom; } /* Bring back clients which are beyond the screen. */ void screen_assert_clients_within(struct screen_ctx *sc) { struct client_ctx *cc; int top, left, right, bottom; TAILQ_FOREACH(cc, &sc->clientq, entry) { if (cc->sc != sc) continue; top = cc->geom.y; left = cc->geom.x; right = cc->geom.x + cc->geom.w + (cc->bwidth * 2) - 1; bottom = cc->geom.y + cc->geom.h + (cc->bwidth * 2) - 1; if ((top > sc->view.h || left > sc->view.w) || (bottom < 0 || right < 0)) { cc->geom.x = sc->gap.left; cc->geom.y = sc->gap.top; client_move(cc); } } } void screen_prop_win_create(struct screen_ctx *sc, Window win) { sc->prop.win = XCreateSimpleWindow(X_Dpy, win, 0, 0, 1, 1, 0, sc->xftcolor[CWM_COLOR_MENU_BG].pixel, sc->xftcolor[CWM_COLOR_MENU_BG].pixel); sc->prop.xftdraw = XftDrawCreate(X_Dpy, sc->prop.win, sc->visual, sc->colormap); XMapWindow(X_Dpy, sc->prop.win); } void screen_prop_win_destroy(struct screen_ctx *sc) { XftDrawDestroy(sc->prop.xftdraw); XDestroyWindow(X_Dpy, sc->prop.win); } void screen_prop_win_draw(struct screen_ctx *sc, const char *fmt, ...) { va_list ap; char *text; XGlyphInfo extents; va_start(ap, fmt); xvasprintf(&text, fmt, ap); va_end(ap); XftTextExtentsUtf8(X_Dpy, sc->xftfont, (const FcChar8*)text, strlen(text), &extents); XResizeWindow(X_Dpy, sc->prop.win, extents.xOff, sc->xftfont->height); XClearWindow(X_Dpy, sc->prop.win); XftDrawStringUtf8(sc->prop.xftdraw, &sc->xftcolor[CWM_COLOR_MENU_FONT], sc->xftfont, 0, sc->xftfont->ascent + 1, (const FcChar8*)text, strlen(text)); free(text); }