1 /* Skippy - Seduces Kids Into Perversion
3 * Copyright (C) 2004 Hyriand <hyriand@thegraveyard.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #define INTERSECTS(x1, y1, w1, h1, x2, y2, w2, h2) \
23 (((x1 >= x2 && x1 < (x2 + w2)) || (x2 >= x1 && x2 < (x1 + w1))) && \
24 ((y1 >= y2 && y1 < (y2 + h2)) || (y2 >= y1 && y2 < (y1 + h1))))
27 clientwin_cmp_func(dlist *l, void *data)
29 return ((ClientWin*)l->data)->client.window == (Window)data;
33 clientwin_validate_func(dlist *l, void *data)
35 ClientWin *cw = (ClientWin *)l->data;
36 CARD32 desktop = (*(CARD32*)data),
37 w_desktop = wm_get_window_desktop(cw->mainwin->dpy, cw->client.window);
40 if(cw->mainwin->xin_active && ! INTERSECTS(cw->client.x, cw->client.y, cw->client.width, cw->client.height,
41 cw->mainwin->xin_active->x_org, cw->mainwin->xin_active->y_org,
42 cw->mainwin->xin_active->width, cw->mainwin->xin_active->height))
46 return (w_desktop == (CARD32)-1 || desktop == w_desktop) &&
47 wm_validate_window(cw->mainwin->dpy, cw->client.window);
51 clientwin_check_group_leader_func(dlist *l, void *data)
53 ClientWin *cw = (ClientWin *)l->data;
54 return wm_get_group_leader(cw->mainwin->dpy, cw->client.window) == *((Window*)data);
58 clientwin_sort_func(dlist* a, dlist* b, void* data)
60 unsigned int pa = ((ClientWin*)a->data)->client.x * ((ClientWin*)a->data)->client.y,
61 pb = ((ClientWin*)b->data)->client.x * ((ClientWin*)b->data)->client.y;
62 return (pa < pb) ? -1 : (pa == pb) ? 0 : 1;
66 clientwin_create(MainWin *mw, Window client)
68 ClientWin *cw = (ClientWin *)malloc(sizeof(ClientWin));
69 XSetWindowAttributes sattr;
70 XWindowAttributes attr;
71 XRenderPictureAttributes pa;
76 cw->origin = cw->destination = None;
79 /* cw->repair = None; */
81 sattr.border_pixel = sattr.background_pixel = 0;
82 sattr.colormap = mw->colormap;
84 sattr.event_mask = ButtonPressMask |
93 sattr.override_redirect = mw->lazy_trans;
95 cw->client.window = client;
96 cw->mini.format = mw->format;
97 cw->mini.window = XCreateWindow(mw->dpy, mw->lazy_trans ? mw->root : mw->window, 0, 0, 1, 1, 0,
98 mw->depth, InputOutput, mw->visual,
99 CWColormap | CWBackPixel | CWBorderPixel | CWEventMask | CWOverrideRedirect, &sattr);
101 if(cw->mini.window == None)
107 XGetWindowAttributes(mw->dpy, client, &attr);
108 cw->client.format = XRenderFindVisualFormat(mw->dpy, attr.visual);
110 pa.subwindow_mode = IncludeInferiors;
111 cw->origin = XRenderCreatePicture (cw->mainwin->dpy, cw->client.window, cw->client.format, CPSubwindowMode, &pa);
113 /* XRenderSetPictureFilter(cw->mainwin->dpy, cw->origin, FilterBest, 0, 0); */
114 if(mw->gquality == 0)
115 XRenderSetPictureFilter(cw->mainwin->dpy, cw->origin, FilterFast, NULL, 0);
116 else if (mw->gquality == 1)
117 XRenderSetPictureFilter(cw->mainwin->dpy, cw->origin, FilterGood, NULL, 0);
118 else if (mw->gquality == 2)
119 XRenderSetPictureFilter(cw->mainwin->dpy, cw->origin, FilterBest, NULL, 0);
120 else if (mw->gquality == 3)
121 XRenderSetPictureFilter(cw->mainwin->dpy, cw->origin, FilterNearest, NULL, 0);
122 else if (mw->gquality == 4)
123 XRenderSetPictureFilter(cw->mainwin->dpy, cw->origin, FilterBilinear, NULL, 0);
124 else if (mw->gquality == 5)
125 XRenderSetPictureFilter(cw->mainwin->dpy, cw->origin, FilterConvolution, NULL, 0);
127 XSelectInput(cw->mainwin->dpy, cw->client.window, SubstructureNotifyMask | StructureNotifyMask);
134 clientwin_update(ClientWin *cw)
137 XWindowAttributes wattr;
139 XGetWindowAttributes(cw->mainwin->dpy, cw->client.window, &wattr);
141 cw->client.format = XRenderFindVisualFormat(cw->mainwin->dpy, wattr.visual);
142 XTranslateCoordinates(cw->mainwin->dpy, cw->client.window, wattr.root,
146 &cw->client.x, &cw->client.y, &tmpwin);
148 cw->client.width = wattr.width;
149 cw->client.height = wattr.height;
151 cw->mini.x = cw->mini.y = 0;
152 cw->mini.width = cw->mini.height = 1;
156 clientwin_destroy(ClientWin *cw, Bool parentDestroyed)
158 if(! parentDestroyed)
160 if(cw->origin != None)
161 XRenderFreePicture(cw->mainwin->dpy, cw->origin);
162 if(cw->damage != None)
163 XDamageDestroy(cw->mainwin->dpy, cw->damage);
165 if(cw->destination != None)
166 XRenderFreePicture(cw->mainwin->dpy, cw->destination);
167 if(cw->pixmap != None)
168 XFreePixmap(cw->mainwin->dpy, cw->pixmap);
170 XDestroyWindow(cw->mainwin->dpy, cw->mini.window);
176 clientwin_repaint(ClientWin *cw, XRectangle *rect)
178 XRenderColor *tint = cw->focused ? &cw->mainwin->highlightTint : &cw->mainwin->normalTint;
179 int s_x = (double)rect->x * cw->factor,
180 s_y = (double)rect->y * cw->factor,
181 s_w = (double)rect->width * cw->factor,
182 s_h = (double)rect->height * cw->factor;
185 if(cw->mainwin->lazy_trans)
187 XRenderComposite(cw->mainwin->dpy, PictOpSrc, cw->origin,
188 cw->focused ? cw->mainwin->highlightPicture : cw->mainwin->normalPicture,
189 cw->destination, s_x, s_y, 0, 0, s_x, s_y, s_w, s_h);
193 XRenderComposite(cw->mainwin->dpy, PictOpSrc, cw->mainwin->background, None, cw->destination, cw->mini.x + s_x, cw->mini.y + s_y, 0, 0, s_x, s_y, s_w, s_h);
194 XRenderComposite(cw->mainwin->dpy, PictOpOver, cw->origin,
195 cw->focused ? cw->mainwin->highlightPicture : cw->mainwin->normalPicture,
196 cw->destination, s_x, s_y, 0, 0, s_x, s_y, s_w, s_h);
200 XRenderFillRectangle(cw->mainwin->dpy, PictOpOver, cw->destination, tint, s_x, s_y, s_w, s_h);
202 XClearArea(cw->mainwin->dpy, cw->mini.window, s_x, s_y, s_w, s_h, False);
206 clientwin_render(ClientWin *cw)
210 rect.width = cw->client.width;
211 rect.height = cw->client.height;
212 clientwin_repaint(cw, &rect);
216 clientwin_repair(ClientWin *cw)
220 XserverRegion rgn = XFixesCreateRegion(cw->mainwin->dpy, 0, 0);
222 XDamageSubtract(cw->mainwin->dpy, cw->damage, None, rgn);
224 rects = XFixesFetchRegion(cw->mainwin->dpy, rgn, &nrects);
225 XFixesDestroyRegion(cw->mainwin->dpy, rgn);
227 for(i = 0; i < nrects; i++)
228 clientwin_repaint(cw, &rects[i]);
237 clientwin_schedule_repair(ClientWin *cw, XRectangle *area)
243 clientwin_move(ClientWin *cw, float f, int x, int y)
245 /* int border = MAX(1, (double)DISTANCE(cw->mainwin) * f * 0.25); */
247 XSetWindowBorderWidth(cw->mainwin->dpy, cw->mini.window, border);
250 cw->mini.x = x + (int)cw->x * f;
251 cw->mini.y = y + (int)cw->y * f;
252 if(cw->mainwin->lazy_trans)
254 cw->mini.x += cw->mainwin->x;
255 cw->mini.y += cw->mainwin->y;
257 /*if(cw->client.width < 800)
258 cw->client.height -= 65;*/
259 cw->mini.width = MAX(1, (int)cw->client.width * f );
260 cw->mini.height = MAX(1, (int)cw->client.height * f );
261 XMoveResizeWindow(cw->mainwin->dpy, cw->mini.window, cw->mini.x - border, cw->mini.y - border, cw->mini.width, cw->mini.height);
264 XFreePixmap(cw->mainwin->dpy, cw->pixmap);
267 XRenderFreePicture(cw->mainwin->dpy, cw->destination);
269 cw->pixmap = XCreatePixmap(cw->mainwin->dpy, cw->mini.window, cw->mini.width, cw->mini.height, cw->mainwin->depth);
270 XSetWindowBackgroundPixmap(cw->mainwin->dpy, cw->mini.window, cw->pixmap);
272 cw->destination = XRenderCreatePicture(cw->mainwin->dpy, cw->pixmap, cw->mini.format, 0, 0);
276 clientwin_map(ClientWin *cw)
279 XDamageDestroy(cw->mainwin->dpy, cw->damage);
281 cw->damage = XDamageCreate(cw->mainwin->dpy, cw->client.window, XDamageReportDeltaRectangles);
282 XRenderSetPictureTransform(cw->mainwin->dpy, cw->origin, &cw->mainwin->transform);
284 clientwin_render(cw);
286 XMapWindow(cw->mainwin->dpy, cw->mini.window);
290 clientwin_unmap(ClientWin *cw)
294 XDamageDestroy(cw->mainwin->dpy, cw->damage);
300 XRenderFreePicture(cw->mainwin->dpy, cw->destination);
301 cw->destination = None;
306 XFreePixmap(cw->mainwin->dpy, cw->pixmap);
310 XUnmapWindow(cw->mainwin->dpy, cw->mini.window);
311 XSetWindowBackgroundPixmap(cw->mainwin->dpy, cw->mini.window, None);
316 int client_msg(Display *disp, Window win, char *msg, /* {{{ */
317 unsigned long data0, unsigned long data1,
318 unsigned long data2, unsigned long data3,
319 unsigned long data4) {
321 long mask = SubstructureRedirectMask | SubstructureNotifyMask;
323 event.xclient.type = ClientMessage;
324 event.xclient.serial = 0;
325 event.xclient.send_event = True;
326 event.xclient.message_type = XInternAtom(disp, msg, False);
327 event.xclient.window = win;
328 event.xclient.format = 32;
329 event.xclient.data.l[0] = data0;
330 event.xclient.data.l[1] = data1;
331 event.xclient.data.l[2] = data2;
332 event.xclient.data.l[3] = data3;
333 event.xclient.data.l[4] = data4;
335 if (XSendEvent(disp, DefaultRootWindow(disp), False, mask, &event)) {
339 fprintf(stderr, "Cannot send %s event.\n", msg);
346 childwin_focus(ClientWin *cw)
348 XWarpPointer(cw->mainwin->dpy, None, cw->client.window, 0, 0, 0, 0, cw->client.width / 2, cw->client.height / 2);
350 client_msg(cw->mainwin->dpy, cw->client.window, "_NET_ACTIVE_WINDOW",
352 XMapRaised(cw->mainwin->dpy, cw->client.window);
353 /*XRaiseWindow(cw->mainwin->dpy, cw->client.window);*/
354 XSetInputFocus(cw->mainwin->dpy, cw->client.window, RevertToParent, CurrentTime);
358 clientwin_handle(ClientWin *cw, XEvent *ev)
360 if((ev->type == ButtonRelease && ev->xbutton.button == 1 && cw->mainwin->pressed == cw)) {
361 if((ev->xbutton.x >= 0 && ev->xbutton.y >= 0 && ev->xbutton.x < cw->mini.width && ev->xbutton.y < cw->mini.height))
363 cw->mainwin->pressed = 0;
365 } else if(ev->type == KeyRelease) {
366 if(ev->xkey.keycode == cw->mainwin->key_up)
368 else if(ev->xkey.keycode == cw->mainwin->key_down)
370 else if(ev->xkey.keycode == cw->mainwin->key_left)
372 else if(ev->xkey.keycode == cw->mainwin->key_right)
374 else if(ev->xkey.keycode == cw->mainwin->key_f8)
375 client_msg(cw->mainwin->dpy, cw->client.window, "_NET_CLOSE_WINDOW",
377 else if(ev->xkey.keycode == cw->mainwin->key_enter || ev->xkey.keycode == cw->mainwin->key_space) {
381 } else if(ev->type == ButtonPress && ev->xbutton.button == 1) {
382 cw->mainwin->pressed = cw;
383 } else if(ev->type == FocusIn) {
385 clientwin_render(cw);
386 XFlush(cw->mainwin->dpy);
387 } else if(ev->type == FocusOut) {
389 clientwin_render(cw);
390 XFlush(cw->mainwin->dpy);
391 } else if(ev->type == EnterNotify) {
392 XSetInputFocus(cw->mainwin->dpy, cw->mini.window, RevertToNone, CurrentTime);
393 if(cw->mainwin->tooltip)
395 int win_title_len = 0;
396 FcChar8 *win_title = wm_get_window_title(cw->mainwin->dpy, cw->client.window, &win_title_len);
399 tooltip_map(cw->mainwin->tooltip,
400 ev->xcrossing.x_root + 20, ev->xcrossing.y_root + 20,
401 win_title, win_title_len);
405 } else if(ev->type == LeaveNotify) {
406 if(cw->mainwin->tooltip)
407 tooltip_unmap(cw->mainwin->tooltip);