#include "phluid.h"
#include "debug.h"
static void render_name(Client *);
void
make_client(Window * w)
{
Client *c;
XWindowAttributes attr;
XSetWindowAttributes pattr;
XGetWindowAttributes(disp, *w, &attr);
/* popup window, don't make a client */
if (attr.override_redirect)
return;
c = malloc(sizeof *c);
XFetchName(disp, *w, &c->name);
c->shaded = 0;
c->window = *w;
c->x = attr.x;
c->y = attr.y;
c->width = attr.width;
c->height = attr.height;
c->ignore_unmap = 0;
c->next = client_list_head;
client_list_head = c;
c->decals = NULL;
c->decals_to_render = NULL;
/* XGrabServer(disp); *//* is this necessary? */
/* set attributes for window decoration window */
pattr.override_redirect = True;
pattr.background_pixel = bg.pixel;
pattr.border_pixel = bd.pixel;
pattr.event_mask =
StructureNotifyMask | SubstructureRedirectMask | SubstructureNotifyMask |
ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask |
EnterWindowMask;
/* make window decoration window */
c->frame =
XCreateWindow(disp, root, c->x, c->y, c->width,
c->height + TITLEBAR_HEIGHT, 1, DefaultDepth(disp,
screen),
CopyFromParent, DefaultVisual(disp, screen),
CWOverrideRedirect | CWBackPixel | CWBorderPixel |
CWEventMask, &pattr);
XAddToSaveSet(disp, c->window);
XSelectInput(disp, c->window, PropertyChangeMask);
XSetWindowBorderWidth(disp, c->window, 0);
XMoveWindow(disp, c->window, c->x, c->y + TITLEBAR_HEIGHT);
/* going to get an UnmapNotify from XReparentWindow() */
if (attr.map_state == IsViewable)
c->ignore_unmap++;
XReparentWindow(disp, c->window, c->frame, 0, TITLEBAR_HEIGHT);
if (attr.map_state == IsViewable) {
XWMHints *wm_hints;
wm_hints = XAllocWMHints();
wm_hints = XGetWMHints(disp, c->window);
if (wm_hints->initial_state == IconicState) {
c->visible = 0;
} else {
CARD32 data[2];
data[0] = NormalState;
data[1] = None;
XMapWindow(disp, c->frame);
c->visible = 1;
XChangeProperty(disp, c->window, XInternAtom(disp, "WM_STATE", False),
XInternAtom(disp, "WM_STATE", False), 32, PropModeReplace,
(unsigned char *) data, 2);
}
XFree(wm_hints);
}
/* XUngrabServer(disp); */
/* start adding nift with Imlib2 */
/* make background image */
c->bg =
imlib_load_image(PACKAGE_DATA_DIR "/themes/default/images/title_bg.png");
/* add decals */
add_new_decal_to_client(c,
PACKAGE_DATA_DIR
"/themes/default/images/close_normal.png", 1, 1,
DecalFnDelete, DecalFnNone, DecalFnDestroy);
c->updates = imlib_updates_init();
render_title_bar(c);
DEBUG_CLIENT_LIST();
}
void
delete_client(Client * c)
{
Client *tmp;
if (!c)
return;
XGrabServer(disp);
/* The upcoming XReparentWindow and XMoveWindow calls might generate
BadWindow errors if the window already got destroyed. I don't know
how to avoid this so I'll set a handler to take care of it(*cough*
ignore it *cough*) gracefully. */
XSetErrorHandler(handle_xerror);
XReparentWindow(disp, c->window, root, c->x, c->y);
XRemoveFromSaveSet(disp, c->window);
XDestroyWindow(disp, c->frame);
XMoveWindow(disp, c->window, c->x, c->y);
XSync(disp, False);
/* set back to the default error handler */
XSetErrorHandler(NULL);
XUngrabServer(disp);
if (client_list_head == c)
client_list_head = c->next;
else
for (tmp = client_list_head; tmp && tmp->next; tmp = tmp->next)
if (tmp->next == c)
tmp->next = c->next;
/* free up memory */
if (c->name)
XFree(c->name);
imlib_context_set_image(c->title_bar);
imlib_free_image();
imlib_context_set_image(c->bg);
imlib_free_image();
free(c);
DEBUG_CLIENT_LIST();
}
Client *
find_client_by_frame(Window w)
{
Client *c;
for (c = client_list_head; c; c = c->next)
if (c->frame == w)
return c;
return NULL;
}
Client *
find_client_by_child(Window w)
{
Client *c;
for (c = client_list_head; c; c = c->next)
if (c->window == w)
return c;
return NULL;
}
void
render_title_bar(Client * c)
{
int i_w, i_h;
imlib_context_set_image(c->bg);
i_w = imlib_image_get_width();
i_h = imlib_image_get_height();
c->title_bar = imlib_create_image(c->width, TITLEBAR_HEIGHT);
if (c->bg) {
imlib_context_set_image(c->title_bar);
imlib_blend_image_onto_image(c->bg, 0, 0, 0, i_w, i_h, 0, 0,
c->width, TITLEBAR_HEIGHT);
}
c->decals_to_render = c->decals;
render_decals(c);
imlib_context_set_image(c->title_bar);
imlib_context_set_blend(0);
imlib_context_set_drawable(c->frame);
imlib_render_image_on_drawable(0, 0);
imlib_context_set_blend(1);
/* render text */
c->name_change = 1;
c->name_width = 0;
c->name_height = 0;
redraw_client(c);
}
static void
render_name(Client * c)
{
Imlib_Font font;
int text_w, text_h;
DEBUG_PRINT("in render_name\n");
text_w = c->name_width;
text_h = c->name_height;
imlib_add_path_to_font_path(PACKAGE_DATA_DIR "/ttfonts");
font = imlib_load_font("tahomabd/10");
if (font) {
int i_w, i_h;
/* cover up old text */
imlib_context_set_image(c->bg);
i_w = imlib_image_get_width();
i_h = imlib_image_get_height();
imlib_context_set_image(c->title_bar);
imlib_blend_image_onto_image(c->bg, 0, 0, 0, i_w, i_h, TEXT_X, 0,
c->name_width, TITLEBAR_HEIGHT);
/* render new text */
imlib_context_set_font(font);
imlib_context_set_color(60, 60, 60, 200);
imlib_get_text_size(c->name, &c->name_width, &c->name_height);
imlib_context_set_blend(1); /* be sure of blending */
imlib_text_draw(TEXT_X, TEXT_Y, c->name);
imlib_free_font();
}
/* update changed portion (the union of the old and new text areas) */
if (c->name_width > text_w)
text_w = c->name_width;
if (c->name_height > text_h)
text_h = c->name_height;
c->updates =
imlib_update_append_rect(c->updates, TEXT_X, TEXT_Y, text_w, text_h);
}
void
redraw_client(Client * c)
{
Imlib_Image buffer;
int i_w, i_h;
Imlib_Updates current_update;
int up_x, up_y, up_w, up_h; /* geometry of updated portions */
if (c->name_change > 0) {
render_name(c); /* update the name text */
c->name_change--;
}
if (!c->updates)
return;
c->updates =
imlib_updates_merge_for_rendering(c->updates, c->width, TITLEBAR_HEIGHT);
for (current_update = c->updates; current_update;
current_update = imlib_updates_get_next(current_update)) {
imlib_updates_get_coordinates(current_update, &up_x, &up_y, &up_w, &up_h);
imlib_context_set_image(c->title_bar);
i_w = imlib_image_get_width();
i_h = imlib_image_get_height();
buffer = imlib_create_image(up_w, up_h);
imlib_context_set_image(buffer);
/* blend image onto buffer */
imlib_blend_image_onto_image(c->title_bar, 0, 0, 0, i_w, i_h, -up_x,
-up_y, c->width, TITLEBAR_HEIGHT);
imlib_context_set_image(buffer);
imlib_context_set_blend(0);
imlib_context_set_drawable(c->frame);
imlib_render_image_on_drawable(up_x, up_y);
imlib_free_image();
imlib_context_set_blend(1);
}
/* clean up old updates and init new */
if (c->updates)
imlib_updates_free(c->updates);
c->updates = imlib_updates_init();
XFlush(disp);
}
syntax highlighted by Code2HTML, v. 0.9.1