/* * Copyright 2010 Johan Veenhuizen */ #include #include #include #include "wind.h" struct button { struct listener listener; void (*function)(void *, Time); void *arg; struct bitmap *bitmap; Pixmap pixmap; 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 event(void *, XEvent *); static void update(struct button *b) { Bool invert = b->pressed && b->entered; GC fg = invert ? background : foreground; GC bg = invert ? foreground : background; XFillRectangle(dpy, b->pixmap, bg, 0, 0, b->width, b->height); drawbitmap(b->pixmap, fg, b->bitmap, (b->width - b->bitmap->width) / 2, (b->height - b->bitmap->height) / 2); if (!invert) { XSetLineAttributes(dpy, fg, b->entered ? 1 + 2 * halfleading : 0, LineSolid, CapButt, JoinMiter); XDrawRectangle(dpy, b->pixmap, fg, 0, 0, b->width - 1, b->height - 1); XSetLineAttributes(dpy, fg, 0, LineSolid, CapButt, JoinMiter); } XCopyArea(dpy, b->pixmap, b->window, fg, 0, 0, b->width, b->height, 0, 0); } static void buttonpress(struct button *b, XButtonEvent *e) { 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->arg, 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) { if (b->entered) { b->entered = False; update(b); } } static void unmapnotify(struct button *b, XUnmapEvent *e) { if (b->pressed) { b->pressed = False; update(b); } } 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 event(void *self, XEvent *e) { switch (e->type) { case Expose: expose(self, &e->xexpose); break; case EnterNotify: enternotify(self, &e->xcrossing); break; case LeaveNotify: leavenotify(self, &e->xcrossing); break; case ButtonPress: buttonpress(self, &e->xbutton); break; case ButtonRelease: buttonrelease(self, &e->xbutton); break; case UnmapNotify: unmapnotify(self, &e->xunmap); break; } } struct button *bcreate(void (*function)(void *, Time), void *arg, 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->arg = arg; b->bitmap = bitmap; 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, x, y, width, height, 0, CopyFromParent, InputOutput, CopyFromParent, CWWinGravity, &(XSetWindowAttributes){ .win_gravity = gravity }); b->listener.function = event; b->listener.pointer = b; setlistener(b->window, &b->listener); XGrabButton(dpy, Button1, AnyModifier, b->window, False, EnterWindowMask | LeaveWindowMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None); XSelectInput(dpy, b->window, EnterWindowMask | LeaveWindowMask | StructureNotifyMask | ExposureMask); update(b); XMapWindow(dpy, b->window); return b; } void bdestroy(struct button *b) { setlistener(b->window, NULL); XFreePixmap(dpy, b->pixmap); XDestroyWindow(dpy, b->window); free(b); }