/*
* Copyright 2010 Johan Veenhuizen
*/
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include "wind.h"
struct button {
struct eventlistener listener;
void (*function)(struct client *, Time);
struct client *client;
struct bitmap *bitmap;
Pixmap pixmap;
int x;
int y;
int width;
int height;
Window window;
Bool pressed;
Bool entered;
};
static void update(struct button *);
static void buttonpress(struct button *, XButtonEvent *);
static void buttonrelease(struct button *, XButtonEvent *);
static void enternotify(struct button *, XCrossingEvent *);
static void leavenotify(struct button *, XCrossingEvent *);
static void expose(struct button *, XExposeEvent *);
static void unmapnotify(struct button *, XUnmapEvent *);
static void eventlistener(void *, XEvent *);
static void update(struct button *b)
{
Bool invert = b->pressed && b->entered;
XFillRectangle(dpy, b->pixmap, invert ? foreground : background,
0, 0, b->width, b->height);
if (!invert)
XDrawRectangle(dpy, b->pixmap, foreground,
0, 0, b->width - 1, b->height - 1);
if (!b->pressed && b->entered)
XDrawRectangle(dpy, b->pixmap, foreground,
1, 1, b->width - 3, b->height - 3);
drawbitmap(b->pixmap, invert ? background : foreground, b->bitmap,
(b->width - b->bitmap->width) / 2,
(b->height - b->bitmap->height) / 2);
XCopyArea(dpy, b->pixmap, b->window, foreground,
0, 0, b->width, b->height, 0, 0);
}
static void buttonpress(struct button *b, XButtonEvent *e)
{
if (e->button == Button1) {
b->pressed = True;
update(b);
}
}
static void buttonrelease(struct button *b, XButtonEvent *e)
{
if (e->button == Button1) {
if (b->pressed && b->entered)
b->function(b->client, e->time);
b->pressed = False;
update(b);
}
}
static void enternotify(struct button *b, XCrossingEvent *e)
{
b->entered = True;
update(b);
}
static void leavenotify(struct button *b, XCrossingEvent *e)
{
b->entered = False;
update(b);
}
static void mapnotify(struct button *b, XMapEvent *e)
{
update(b);
}
static void unmapnotify(struct button *b, XUnmapEvent *e)
{
b->pressed = False;
}
static void expose(struct button *b, XExposeEvent *e)
{
XCopyArea(dpy, b->pixmap, b->window, foreground,
e->x, e->y, e->width, e->height, e->x, e->y);
}
static void eventlistener(void *self, XEvent *e)
{
struct button *b = self;
switch (e->type) {
case Expose:
expose(b, &e->xexpose);
break;
case MapNotify:
mapnotify(b, &e->xmap);
break;
case EnterNotify:
enternotify(b, &e->xcrossing);
break;
case LeaveNotify:
leavenotify(b, &e->xcrossing);
break;
case ButtonPress:
buttonpress(b, &e->xbutton);
break;
case ButtonRelease:
buttonrelease(b, &e->xbutton);
break;
case UnmapNotify:
unmapnotify(b, &e->xunmap);
break;
}
}
struct button *bcreate(void (*function)(struct client *, Time),
struct client *client, struct bitmap *bitmap,
Window parent, int x, int y, int width,
int height, int gravity)
{
struct button *b = xmalloc(sizeof *b);
b->function = function;
b->client = client;
b->bitmap = bitmap;
b->x = x;
b->y = y;
b->width = width;
b->height = height;
b->pixmap = XCreatePixmap(dpy, root, width, height,
DefaultDepth(dpy, scr));
b->pressed = False;
b->entered = False;
b->window = XCreateWindow(dpy, parent, b->x, b->y, b->width, b->height,
0, CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWBackPixel | CWWinGravity,
&(XSetWindowAttributes){
.override_redirect = True,
.background_pixel = backgroundpixel,
.win_gravity = gravity });
b->listener.function = eventlistener;
b->listener.pointer = b;
seteventlistener(b->window, &b->listener);
XSelectInput(dpy, b->window,
ButtonPressMask | ButtonReleaseMask |
EnterWindowMask | LeaveWindowMask |
StructureNotifyMask | ExposureMask);
XMapWindow(dpy, b->window);
return b;
}
void bdestroy(struct button *b)
{
seteventlistener(b->window, NULL);
XFreePixmap(dpy, b->pixmap);
XDestroyWindow(dpy, b->window);
free(b);
}