swallow.c (5215B)
1 #include <X11/Xlib-xcb.h> 2 #include <xcb/res.h> 3 #ifdef __OpenBSD__ 4 #include <sys/sysctl.h> 5 #include <kvm.h> 6 #endif /* __OpenBSD__ */ 7 8 static int scanner; 9 static xcb_connection_t *xcon; 10 11 int 12 swallow(Client *p, Client *c) 13 { 14 Client *s; 15 XWindowChanges wc; 16 #if NOBORDER_PATCH 17 int border_padding = 0; 18 #endif // NOBORDER_PATCH 19 20 if (c->noswallow > 0 || c->isterminal) 21 return 0; 22 if (c->noswallow < 0 && !swallowfloating && c->isfloating) 23 return 0; 24 25 XMapWindow(dpy, c->win); 26 27 detach(c); 28 detachstack(c); 29 30 setclientstate(c, WithdrawnState); 31 XUnmapWindow(dpy, p->win); 32 33 p->swallowing = c; 34 c->mon = p->mon; 35 36 Window w = p->win; 37 p->win = c->win; 38 c->win = w; 39 40 XChangeProperty(dpy, c->win, netatom[NetClientList], XA_WINDOW, 32, PropModeReplace, 41 (unsigned char *) &(p->win), 1); 42 43 #if BAR_WINICON_PATCH 44 updateicon(p); 45 #endif 46 updatetitle(p); 47 s = scanner ? c : p; 48 #if BAR_EWMHTAGS_PATCH 49 setfloatinghint(s); 50 #endif // BAR_EWMHTAGS_PATCH 51 52 #if NOBORDER_PATCH 53 wc.border_width = p->bw; 54 if (noborder(p)) { 55 wc.border_width = 0; 56 border_padding = p->bw * 2; 57 } 58 59 XConfigureWindow(dpy, p->win, CWBorderWidth, &wc); 60 XMoveResizeWindow(dpy, p->win, s->x, s->y, s->w + border_padding, s->h + border_padding); 61 #else 62 wc.border_width = p->bw; 63 XConfigureWindow(dpy, p->win, CWBorderWidth, &wc); 64 XMoveResizeWindow(dpy, p->win, s->x, s->y, s->w, s->h); 65 #endif // NOBORDER_PATCH 66 67 #if !BAR_FLEXWINTITLE_PATCH 68 XSetWindowBorder(dpy, p->win, scheme[SchemeNorm][ColBorder].pixel); 69 #endif // BAR_FLEXWINTITLE_PATCH 70 71 arrange(p->mon); 72 configure(p); 73 updateclientlist(); 74 75 return 1; 76 } 77 78 void 79 unswallow(Client *c) 80 { 81 XWindowChanges wc; 82 c->win = c->swallowing->win; 83 #if NOBORDER_PATCH 84 int border_padding = 0; 85 #endif // NOBORDER_PATCH 86 87 free(c->swallowing); 88 c->swallowing = NULL; 89 90 XDeleteProperty(dpy, c->win, netatom[NetClientList]); 91 92 /* unfullscreen the client */ 93 setfullscreen(c, 0); 94 #if BAR_WINICON_PATCH 95 updateicon(c); 96 #endif 97 updatetitle(c); 98 arrange(c->mon); 99 XMapWindow(dpy, c->win); 100 101 #if NOBORDER_PATCH 102 wc.border_width = c->bw; 103 if (noborder(c)) { 104 wc.border_width = 0; 105 border_padding = c->bw * 2; 106 } 107 108 XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); 109 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w + border_padding, c->h + border_padding); 110 #else 111 wc.border_width = c->bw; 112 XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); 113 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); 114 #endif // NOBORDER_PATCH 115 #if !BAR_FLEXWINTITLE_PATCH 116 XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); 117 #endif // BAR_FLEXWINTITLE_PATCH 118 119 #if BAR_EWMHTAGS_PATCH 120 setfloatinghint(c); 121 #endif // BAR_EWMHTAGS_PATCH 122 setclientstate(c, NormalState); 123 arrange(c->mon); 124 focus(NULL); 125 } 126 127 pid_t 128 winpid(Window w) 129 { 130 pid_t result = 0; 131 132 #ifdef __linux__ 133 xcb_res_client_id_spec_t spec = {0}; 134 spec.client = w; 135 spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID; 136 137 xcb_generic_error_t *e = NULL; 138 xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec); 139 xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e); 140 141 if (!r) 142 return (pid_t)0; 143 144 xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r); 145 for (; i.rem; xcb_res_client_id_value_next(&i)) { 146 spec = i.data->spec; 147 if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) { 148 uint32_t *t = xcb_res_client_id_value_value(i.data); 149 result = *t; 150 break; 151 } 152 } 153 154 free(r); 155 156 if (result == (pid_t)-1) 157 result = 0; 158 159 #endif /* __linux__ */ 160 #ifdef __OpenBSD__ 161 Atom type; 162 int format; 163 unsigned long len, bytes; 164 unsigned char *prop; 165 pid_t ret; 166 167 if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 1), 0, 1, False, AnyPropertyType, &type, &format, &len, &bytes, &prop) != Success || !prop) 168 return 0; 169 170 ret = *(pid_t*)prop; 171 XFree(prop); 172 result = ret; 173 #endif /* __OpenBSD__ */ 174 175 return result; 176 } 177 178 pid_t 179 getparentprocess(pid_t p) 180 { 181 unsigned int v = 0; 182 183 #ifdef __linux__ 184 FILE *f; 185 char buf[256]; 186 snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); 187 188 if (!(f = fopen(buf, "r"))) 189 return (pid_t)0; 190 191 if (fscanf(f, "%*u %*s %*c %u", (unsigned *)&v) != 1) 192 v = (pid_t)0; 193 fclose(f); 194 #endif /* __linux__ */ 195 #ifdef __OpenBSD__ 196 int n; 197 kvm_t *kd; 198 struct kinfo_proc *kp; 199 200 kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL); 201 if (!kd) 202 return 0; 203 204 kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n); 205 v = kp->p_ppid; 206 #endif /* __OpenBSD__ */ 207 return (pid_t)v; 208 } 209 210 int 211 isdescprocess(pid_t p, pid_t c) 212 { 213 while (p != c && c != 0) 214 c = getparentprocess(c); 215 216 return (int)c; 217 } 218 219 Client * 220 termforwin(const Client *w) 221 { 222 Client *c; 223 Monitor *m; 224 225 if (!w->pid || w->isterminal) 226 return NULL; 227 228 c = selmon->sel; 229 if (c && c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) 230 return c; 231 232 for (m = mons; m; m = m->next) { 233 for (c = m->clients; c; c = c->next) { 234 if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) 235 return c; 236 } 237 } 238 239 return NULL; 240 } 241 242 Client * 243 swallowingclient(Window w) 244 { 245 Client *c; 246 Monitor *m; 247 248 for (m = mons; m; m = m->next) { 249 for (c = m->clients; c; c = c->next) { 250 if (c->swallowing && c->swallowing->win == w) 251 return c; 252 } 253 } 254 255 return NULL; 256 } 257