/* Skippy - Seduces Kids Into Perversion
*
* Copyright (C) 2004 Hyriand <hyriand@thegraveyard.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "skippy.h"
#define INTERSECTS(x1, y1, w1, h1, x2, y2, w2, h2) \
(((x1 >= x2 && x1 < (x2 + w2)) || (x2 >= x1 && x2 < (x1 + w1))) && \
((y1 >= y2 && y1 < (y2 + h2)) || (y2 >= y1 && y2 < (y1 + h1))))
int
clientwin_cmp_func(dlist *l, void *data)
{
return ((ClientWin*)l->data)->client.window == (Window)data;
}
int
clientwin_validate_func(dlist *l, void *data)
{
ClientWin *cw = (ClientWin *)l->data;
CARD32 desktop = (*(CARD32*)data),
w_desktop = wm_get_window_desktop(cw->mainwin->dpy, cw->client.window);
#ifdef XINERAMA
if(cw->mainwin->xin_active && ! INTERSECTS(cw->client.x, cw->client.y, cw->client.width, cw->client.height,
cw->mainwin->xin_active->x_org, cw->mainwin->xin_active->y_org,
cw->mainwin->xin_active->width, cw->mainwin->xin_active->height))
return 0;
#endif
return (w_desktop == (CARD32)-1 || desktop == w_desktop) &&
wm_validate_window(cw->mainwin->dpy, cw->client.window);
}
int
clientwin_check_group_leader_func(dlist *l, void *data)
{
ClientWin *cw = (ClientWin *)l->data;
return wm_get_group_leader(cw->mainwin->dpy, cw->client.window) == *((Window*)data);
}
int
clientwin_sort_func(dlist* a, dlist* b, void* data)
{
unsigned int pa = ((ClientWin*)a->data)->client.x * ((ClientWin*)a->data)->client.y,
pb = ((ClientWin*)b->data)->client.x * ((ClientWin*)b->data)->client.y;
return (pa < pb) ? -1 : (pa == pb) ? 0 : 1;
}
ClientWin *
clientwin_create(MainWin *mw, Window client)
{
ClientWin *cw = (ClientWin *)malloc(sizeof(ClientWin));
XSetWindowAttributes sattr;
cw->mainwin = mw;
cw->bg_pixmap = None;
cw->bg_image = 0;
cw->focused = 0;
sattr.border_pixel = BORDER_COLOR(mw);
sattr.background_pixel = BlackPixel(mw->dpy, mw->screen);
sattr.event_mask = ButtonPressMask |
ButtonReleaseMask |
KeyReleaseMask |
EnterWindowMask |
LeaveWindowMask |
PointerMotionMask |
FocusChangeMask;
cw->client.window = client;
cw->mini.window = XCreateWindow(mw->dpy, mw->window, 0, 0, 1, 1, 5,
CopyFromParent, InputOutput, CopyFromParent,
CWBackPixel | CWBorderPixel | CWEventMask, &sattr);
if(cw->mini.window == None)
{
free(cw);
return 0;
}
XSelectInput(cw->mainwin->dpy, cw->client.window, SubstructureNotifyMask | StructureNotifyMask);
return cw;
}
void
clientwin_update(ClientWin *cw)
{
Window tmpwin;
XWindowAttributes wattr;
XGetWindowAttributes(cw->mainwin->dpy, cw->client.window, &wattr);
XTranslateCoordinates(cw->mainwin->dpy, cw->client.window, wattr.root,
-wattr.border_width,
-wattr.border_width,
&cw->client.x, &cw->client.y, &tmpwin);
cw->client.width = wattr.width;
cw->client.height = wattr.height;
cw->mini.x = cw->mini.y = 0;
cw->mini.width = cw->mini.height = 1;
}
void
clientwin_destroy(ClientWin *cw)
{
if(cw->bg_pixmap != None)
XFreePixmap(cw->mainwin->dpy, cw->bg_pixmap);
if(cw->bg_image)
{
imlib_context_set_image(cw->bg_image);
imlib_free_image();
}
XDestroyWindow(cw->mainwin->dpy, cw->mini.window);
free(cw);
}
void
clientwin_snap(ClientWin *cw)
{
struct timespec req, rem;
XRaiseWindow(cw->mainwin->dpy, cw->client.window);
XFlush(cw->mainwin->dpy);
req.tv_sec = 0;
req.tv_nsec = 500000000;
while(nanosleep(&req, &rem))
req = rem;
imlib_context_set_drawable(cw->client.window);
cw->bg_image = imlib_create_image_from_drawable(0, 0, 0, cw->client.width, cw->client.height, 1);
cw->mainwin->stack_touched = True;
}
void
clientwin_render(ClientWin *cw)
{
if(cw->bg_pixmap != None) {
XFreePixmap(cw->mainwin->dpy, cw->bg_pixmap);
cw->bg_pixmap = None;
}
if(cw->bg_image) {
Imlib_Image tmp;
cw->bg_pixmap = XCreatePixmap(cw->mainwin->dpy, cw->mini.window, cw->mini.width, cw->mini.height, cw->mainwin->depth);
imlib_context_set_image(cw->mainwin->background);
tmp = imlib_create_cropped_image(cw->mainwin->x + cw->mini.x, cw->mainwin->y + cw->mini.y, cw->mini.width, cw->mini.height);
imlib_context_set_image(tmp);
imlib_context_set_color_modifier(cw->focused ? cw->mainwin->cm_highlight : cw->mainwin->cm_normal);
imlib_blend_image_onto_image(cw->bg_image, 1, 0, 0, cw->client.width, cw->client.height, 0, 0, cw->mini.width, cw->mini.height);
imlib_context_set_color_modifier(0);
imlib_context_set_drawable(cw->bg_pixmap);
imlib_render_image_on_drawable(0, 0);
imlib_free_image();
XSetWindowBackgroundPixmap(cw->mainwin->dpy, cw->mini.window, cw->bg_pixmap);
} else
XSetWindowBackground(cw->mainwin->dpy, cw->mini.window, BlackPixel(cw->mainwin->dpy, cw->mainwin->depth));
XClearArea(cw->mainwin->dpy, cw->mini.window, 0, 0, 0, 0, True);
}
void
clientwin_move(ClientWin *cw, float f, int x, int y)
{
int border = MAX(1, (double)DISTANCE(cw->mainwin) * f * 0.25);
XSetWindowBorderWidth(cw->mainwin->dpy, cw->mini.window, border);
cw->mini.x = x + (int)cw->x * f;
cw->mini.y = y + (int)cw->y * f;
cw->mini.width = MAX(1, (int)cw->client.width * f);
cw->mini.height = MAX(1, (int)cw->client.height * f);
XMoveResizeWindow(cw->mainwin->dpy, cw->mini.window, cw->mini.x - border, cw->mini.y - border, cw->mini.width, cw->mini.height);
}
void
clientwin_map(ClientWin *cw, int force)
{
if(cw->bg_image)
{
imlib_context_set_image(cw->bg_image);
if(force || imlib_image_get_width() != cw->client.width || imlib_image_get_height() != cw->client.height)
{
imlib_free_image();
cw->bg_image = 0;
clientwin_snap(cw);
}
} else
clientwin_snap(cw);
clientwin_render(cw);
XMapWindow(cw->mainwin->dpy, cw->mini.window);
}
void
clientwin_unmap(ClientWin *cw)
{
XUnmapWindow(cw->mainwin->dpy, cw->mini.window);
XSetWindowBackgroundPixmap(cw->mainwin->dpy, cw->mini.window, None);
XSetWindowBorder(cw->mainwin->dpy, cw->mini.window, BORDER_COLOR(cw->mainwin));
cw->focused = 0;
if(cw->bg_pixmap)
{
XFreePixmap(cw->mainwin->dpy, cw->bg_pixmap);
cw->bg_pixmap = None;
}
}
static void
childwin_focus(ClientWin *cw)
{
XWarpPointer(cw->mainwin->dpy, None, cw->client.window, 0, 0, 0, 0, cw->client.width / 2, cw->client.height / 2);
XRaiseWindow(cw->mainwin->dpy, cw->client.window);
XSetInputFocus(cw->mainwin->dpy, cw->client.window, RevertToParent, CurrentTime);
}
int
clientwin_handle(ClientWin *cw, XEvent *ev)
{
if((ev->type == ButtonRelease && ev->xbutton.button == 1 && cw->mainwin->pressed == cw)) {
if((ev->xbutton.x >= 0 && ev->xbutton.y >= 0 && ev->xbutton.x < cw->mini.width && ev->xbutton.y < cw->mini.height))
childwin_focus(cw);
cw->mainwin->pressed = 0;
return 1;
} else if(ev->type == KeyRelease) {
if(ev->xkey.keycode == cw->mainwin->key_up)
focus_up(cw);
else if(ev->xkey.keycode == cw->mainwin->key_down)
focus_down(cw);
else if(ev->xkey.keycode == cw->mainwin->key_left)
focus_left(cw);
else if(ev->xkey.keycode == cw->mainwin->key_right)
focus_right(cw);
else if(ev->xkey.keycode == cw->mainwin->key_enter || ev->xkey.keycode == cw->mainwin->key_space) {
childwin_focus(cw);
return 1;
}
} else if(ev->type == ButtonPress && ev->xbutton.button == 1) {
cw->mainwin->pressed = cw;
} else if(ev->type == FocusIn) {
cw->focused = 1;
XRaiseWindow(cw->mainwin->dpy, cw->mini.window);
XSetWindowBorder(cw->mainwin->dpy, cw->mini.window, HIGHLIGHT_COLOR(cw->mainwin));
clientwin_render(cw);
XFlush(cw->mainwin->dpy);
} else if(ev->type == FocusOut) {
cw->focused = 0;
XSetWindowBorder(cw->mainwin->dpy, cw->mini.window, BORDER_COLOR(cw->mainwin));
clientwin_render(cw);
XFlush(cw->mainwin->dpy);
} else if(ev->type == EnterNotify) {
XSetInputFocus(cw->mainwin->dpy, cw->mini.window, RevertToNone, CurrentTime);
if(cw->mainwin->tooltip)
{
int win_title_len = 0;
FcChar8 *win_title = wm_get_window_title(cw->mainwin->dpy, cw->client.window, &win_title_len);
if(win_title)
{
tooltip_map(cw->mainwin->tooltip,
ev->xcrossing.x_root + 20, ev->xcrossing.y_root + 20,
win_title, win_title_len);
free(win_title);
}
}
} else if(ev->type == MotionNotify) {
if(cw->mainwin->tooltip)
tooltip_move(cw->mainwin->tooltip, ev->xmotion.x_root + 20, ev->xcrossing.y_root + 20);
} else if(ev->type == LeaveNotify) {
if(cw->mainwin->tooltip)
tooltip_unmap(cw->mainwin->tooltip);
}
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1