/* * * Copyright (c) 1999 Alfredo K. Kojima * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include "dockapp.h" #include #include #include #include #include #include static char *progName = NULL; static unsigned d_width, d_height; static DACallbacks d_callbacks = {NULL, NULL, NULL, NULL, NULL, NULL}; static int d_iswmaker = 0; static int d_timeout = 0; Display *DADisplay = NULL; Window DAWindow = None; Window DALeader = None; int DADepth = 0; Visual *DAVisual = NULL; static unsigned char* PropGetCheckProperty(Display *dpy, Window window, Atom hint, Atom type, int format, int count, int *retCount) { Atom type_ret; int fmt_ret; unsigned long nitems_ret; unsigned long bytes_after_ret; unsigned char *data; int tmp; if (count <= 0) tmp = 0xffffff; else tmp = count; if (XGetWindowProperty(dpy, window, hint, 0, tmp, False, type, &type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret, (unsigned char **)&data)!=Success || !data) return NULL; if ((type!=AnyPropertyType && type!=type_ret) || (count > 0 && nitems_ret != count) || (format != 0 && format != fmt_ret)) { XFree(data); return NULL; } if (retCount) *retCount = nitems_ret; return data; } static Bool iswmaker(Display *dpy) { Atom *data; Atom atom; Atom noticeboard; int i, count; atom = XInternAtom(dpy, "_WINDOWMAKER_WM_PROTOCOLS", False); noticeboard = XInternAtom(dpy, "_WINDOWMAKER_NOTICEBOARD", False); data = (Atom*)PropGetCheckProperty(dpy, DefaultRootWindow(dpy), atom, XA_ATOM, 32, -1, &count); if (!data) return False; for (i = 0; i < count; i++) { if (data[i] == noticeboard) { Window *win; void *d; XFree(data); win = (Window*)PropGetCheckProperty(dpy, DefaultRootWindow(dpy), noticeboard, XA_WINDOW, 32, -1, &count); if (!win) { return False; } d = PropGetCheckProperty(dpy, *win, noticeboard, XA_WINDOW, 32, 1, NULL); if (d) { XFree(d); return True; } return False; } } XFree(data); /* not 100% sure */ return True; } void DAInitialize(char *display, char *name, unsigned width, unsigned height, int argc, char **argv) { XClassHint *chint; XWMHints *hints; d_width = width; d_height = height; progName = argv[0]; DADisplay = XOpenDisplay(display); if (!DADisplay) { printf("%s: could not open display %s!\n", progName, XDisplayName(display)); exit(1); } DAWindow = XCreateSimpleWindow(DADisplay, DefaultRootWindow(DADisplay), 0, 0, width, height, 0, 0, 0); DALeader = XCreateSimpleWindow(DADisplay, DefaultRootWindow(DADisplay), 0, 0, 1, 1, 0, 0, 0); chint = XAllocClassHint(); if (!chint) { printf("%s: cant allocate memory for class hints!\n", progName); exit(1); } chint->res_class = name; chint->res_name = strrchr(argv[0], '/'); if (!chint->res_name) chint->res_name = argv[0]; else chint->res_name++; XSetClassHint(DADisplay, DALeader, chint); XFree(chint); hints = XAllocWMHints(); if (!hints) { printf("%s: cant allocate memory for hints!\n", progName); exit(1); } hints->flags = IconWindowHint|WindowGroupHint; d_iswmaker = iswmaker(DADisplay); if (d_iswmaker) { hints->flags |= StateHint; hints->initial_state = WithdrawnState; } hints->window_group = DALeader; hints->icon_window = DAWindow; XSetWMHints(DADisplay, DALeader, hints); XSetCommand(DADisplay, DALeader, argv, argc); DADepth = DefaultDepth(DADisplay, DefaultScreen(DADisplay)); DAVisual = DefaultVisual(DADisplay, DefaultScreen(DADisplay)); XFlush(DADisplay); } void DASetShape(Pixmap shapeMask) { XShapeCombineMask(DADisplay, DAWindow, ShapeBounding, 0, 0, shapeMask, ShapeSet); XFlush(DADisplay); } void DASetPixmap(Pixmap pixmap) { XSetWindowBackgroundPixmap(DADisplay, DAWindow, pixmap); XClearWindow(DADisplay, DAWindow); XFlush(DADisplay); } Pixmap DAMakePixmap() { Pixmap p; p = XCreatePixmap(DADisplay, DAWindow, d_width, d_height, DefaultDepth(DADisplay, DefaultScreen(DADisplay))); return p; } Bool DAMakePixmapFromData(char **data, Pixmap *pixmap, Pixmap *mask, unsigned *width, unsigned *height) { XpmAttributes xpmat; xpmat.valuemask = XpmCloseness; xpmat.closeness = 40000; if (XpmCreatePixmapFromData(DADisplay, DAWindow, data, pixmap, mask, &xpmat)!=0) { return False; } *width = xpmat.width; *height = xpmat.height; return True; } void DAShow() { if (d_iswmaker) { XMapRaised(DADisplay, DALeader); } else { XMapRaised(DADisplay, DAWindow); } XFlush(DADisplay); } void DASetCallbacks(DACallbacks *callbacks) { long mask = 0; d_callbacks = *callbacks; if (callbacks->buttonPress) mask |= ButtonPressMask; if (callbacks->buttonRelease) mask |= ButtonReleaseMask; XSelectInput(DADisplay, DAWindow, mask); XFlush(DADisplay); } Bool DAProcessEvent(XEvent *event) { if (event->xany.window != DAWindow && event->xany.window != DALeader) return False; switch (event->type) { case DestroyNotify: if (d_callbacks.destroy) { (*d_callbacks.destroy)(); } exit(0); break; case ButtonPress: if (d_callbacks.buttonPress) { (*d_callbacks.buttonPress)(event->xbutton.button, event->xbutton.state, event->xbutton.x, event->xbutton.y); } break; case ButtonRelease: if (d_callbacks.buttonRelease) { (*d_callbacks.buttonRelease)(event->xbutton.button, event->xbutton.state, event->xbutton.x, event->xbutton.y); } break; case MotionNotify: if (d_callbacks.motion) { (*d_callbacks.motion)(event->xbutton.x, event->xbutton.y); } break; case EnterNotify: if (d_callbacks.enter) { (*d_callbacks.enter)(); } break; case LeaveNotify: if (d_callbacks.leave) { (*d_callbacks.leave)(); } break; default: return False; break; } return True; } void DAEventLoop() { XEvent ev; for (;;) { if (d_timeout >= 0) { if (!DANextEventOrTimeout(&ev, d_timeout)) { if (d_callbacks.timeout) (*d_callbacks.timeout)(); continue; } } else { XNextEvent(DADisplay, &ev); } DAProcessEvent(&ev); } } static DAProgramOption defaultOptions[]= { {"-h", "--help", "shows this help text and exit", DONone, False, {NULL}}, {"-v", "--version", "shows program version and exit", DONone, False, {NULL}} }; static void printHelp(char *prog, char *description, DAProgramOption *options, int count) { int j; printf("Usage: %s [OPTIONS]\n", prog); if (description) puts(description); for (j = 0; j < count + 2; j++) { char blank[35]; int c; int i; if (j >= count) { options = defaultOptions; i = j - count; } else { i = j; } if (options[i].shortForm && options[i].longForm) c = printf(" %s, %s", options[i].shortForm, options[i].longForm); else if (options[i].shortForm) c = printf(" %s", options[i].shortForm); else if (options[i].longForm) c = printf(" %s", options[i].longForm); else continue; if (options[i].type != DONone) { switch (options[i].type) { case DOInteger: c += printf(" "); break; case DOString: c += printf(" "); break; case DONatural: c+= printf(" "); break; } } memset(blank, ' ', 30); if (c > 29) c = 1; blank[30-c] = 0; printf("%s %s\n", blank, options[i].description); } } void DAParseArguments(int argc, char **argv, DAProgramOption *options, int count, char *programDescription, char *versionDescription) { int i, j; int found = 0; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-h")==0 || strcmp(argv[i], "--help")==0) { printHelp(argv[0], programDescription, options, count); exit(0); } else if (strcmp(argv[i], "--version")==0) { puts(versionDescription); exit(0); } found = 0; for (j = 0; j < count; j++) { if ((options[j].shortForm && strcmp(options[j].shortForm, argv[i])==0) || (options[j].longForm && strcmp(options[j].longForm, argv[i])==0)) { found = 1; options[j].used = True; if (options[j].type == DONone) break; i++; if (i >= argc) { printf("%s: missing argument for option '%s'\n", argv[0], argv[i-1]); exit(1); } switch (options[j].type) { case DOInteger: { int integer; if (sscanf(argv[i], "%i", &integer)!=1) { printf("%s: error parsing argument for option %s\n", argv[0], argv[i-1]); exit(1); } *options[j].value.integer = integer; } break; case DONatural: { int integer; if (sscanf(argv[i], "%i", &integer)!=1) { printf("%s: error parsing argument for option %s\n", argv[0], argv[i-1]); exit(1); } if (integer < 0) { printf("%s: argument %s must be >= 0\n", argv[0], argv[i-1]); exit(1); } *options[j].value.integer = integer; } break; case DOString: *options[j].value.string = argv[i]; break; } break; } } if (!found) { printf("%s: unrecognized option '%s'\n", argv[0], argv[i]); printHelp(argv[0], programDescription, options, count); exit(1); } } } unsigned long DAGetColor(char *colorName) { XColor color; if (!XParseColor(DADisplay, DefaultColormap(DADisplay, DefaultScreen(DADisplay)), colorName, &color)) { printf("%s: could not parse color %s\n", progName, colorName); exit(1); } if (!XAllocColor(DADisplay, DefaultColormap(DADisplay, DefaultScreen(DADisplay)), &color)) { printf("%s: could not allocate color %s. Using black\n", progName, colorName); return BlackPixel(DADisplay, DefaultScreen(DADisplay)); } return color.pixel; } void DASetTimeout(int milliseconds) { d_timeout = milliseconds; } Bool DANextEventOrTimeout(XEvent *event, unsigned long millisec) { struct timeval timeout; fd_set rset; XSync(DADisplay, False); if (XPending(DADisplay)) { XNextEvent(DADisplay, event); return True; } timeout.tv_sec = millisec/1000; timeout.tv_usec = (millisec%1000)*10; FD_ZERO(&rset); FD_SET(ConnectionNumber(DADisplay), &rset); if (select(ConnectionNumber(DADisplay)+1, &rset, NULL, NULL, &timeout) > 0) { XNextEvent(DADisplay, event); return True; } return False; }