diff options
Diffstat (limited to 'abs/mv-core/ghosd/ghosd-0.0.1/ghosd/ghosd.c')
-rw-r--r-- | abs/mv-core/ghosd/ghosd-0.0.1/ghosd/ghosd.c | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/abs/mv-core/ghosd/ghosd-0.0.1/ghosd/ghosd.c b/abs/mv-core/ghosd/ghosd-0.0.1/ghosd/ghosd.c new file mode 100644 index 0000000..d830a1b --- /dev/null +++ b/abs/mv-core/ghosd/ghosd-0.0.1/ghosd/ghosd.c @@ -0,0 +1,226 @@ +/* ghosd -- OSD with fake transparency, cairo, and pango. + * Copyright (C) 2006 Evan Martin <martine@danga.com> + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <cairo/cairo-xlib-xrender.h> +#include <X11/Xatom.h> + +#include "ghosd.h" +#include "ghosd-internal.h" + +static Pixmap +take_snapshot(Ghosd *ghosd) { + Pixmap pixmap; + GC gc; + + /* create a pixmap to hold the screenshot. */ + pixmap = XCreatePixmap(ghosd->dpy, ghosd->win, + ghosd->width, ghosd->height, + DefaultDepth(ghosd->dpy, DefaultScreen(ghosd->dpy))); + + /* then copy the screen into the pixmap. */ + gc = XCreateGC(ghosd->dpy, pixmap, 0, NULL); + XSetSubwindowMode(ghosd->dpy, gc, IncludeInferiors); + XCopyArea(ghosd->dpy, DefaultRootWindow(ghosd->dpy), pixmap, gc, + ghosd->x, ghosd->y, ghosd->width, ghosd->height, + 0, 0); + XSetSubwindowMode(ghosd->dpy, gc, ClipByChildren); + XFreeGC(ghosd->dpy, gc); + + return pixmap; +} + +void +ghosd_render(Ghosd *ghosd) { + Pixmap pixmap; + GC gc; + + /* make our own copy of the background pixmap as the initial surface. */ + pixmap = XCreatePixmap(ghosd->dpy, ghosd->win, ghosd->width, ghosd->height, + DefaultDepth(ghosd->dpy, DefaultScreen(ghosd->dpy))); + + gc = XCreateGC(ghosd->dpy, pixmap, 0, NULL); + if (ghosd->transparent) { + XCopyArea(ghosd->dpy, ghosd->background, pixmap, gc, + 0, 0, ghosd->width, ghosd->height, 0, 0); + } else { + XFillRectangle(ghosd->dpy, pixmap, gc, + 0, 0, ghosd->width, ghosd->height); + } + XFreeGC(ghosd->dpy, gc); + + /* render with cairo. */ + if (ghosd->render_func) { + /* create cairo surface using the pixmap. */ + XRenderPictFormat *xrformat = + XRenderFindVisualFormat(ghosd->dpy, + DefaultVisual(ghosd->dpy, + DefaultScreen(ghosd->dpy))); + cairo_surface_t *surf = + cairo_xlib_surface_create_with_xrender_format( + ghosd->dpy, pixmap, + ScreenOfDisplay(ghosd->dpy, DefaultScreen(ghosd->dpy)), + xrformat, + ghosd->width, ghosd->height); + + /* draw some stuff. */ + cairo_t *cr = cairo_create(surf); + ghosd->render_func(ghosd, cr, ghosd->render_data); + cairo_destroy(cr); + } + + /* point window at its new backing pixmap. */ + XSetWindowBackgroundPixmap(ghosd->dpy, ghosd->win, pixmap); + XFreePixmap(ghosd->dpy, pixmap); + + /* and tell the window to redraw with this pixmap. */ + XClearWindow(ghosd->dpy, ghosd->win); +} + +static void +set_hints(Display *dpy, Window win) { + /* we're almost a _NET_WM_WINDOW_TYPE_SPLASH, but we don't want + * to be centered on the screen. instead, manually request the + * behavior we want. */ + + /* turn off window decorations. + * we could pull this in from a motif header, but it's easier to + * use this snippet i found on a mailing list. */ + Atom mwm_hints = XInternAtom(dpy, "_MOTIF_WM_HINTS", False); +#define MWM_HINTS_DECORATIONS (1<<1) + struct { + long flags, functions, decorations, input_mode; + } mwm_hints_setting = { + MWM_HINTS_DECORATIONS, 0, 0, 0 + }; + XChangeProperty(dpy, win, + mwm_hints, mwm_hints, 32, PropModeReplace, + (unsigned char *)&mwm_hints_setting, 4); + + /* always on top, not in taskbar or pager. */ + Atom win_state = XInternAtom(dpy, "_NET_WM_STATE", False); + Atom win_state_setting[] = { + XInternAtom(dpy, "_NET_WM_STATE_ABOVE", False), + XInternAtom(dpy, "_NET_WM_STATE_SKIP_TASKBAR", False), + XInternAtom(dpy, "_NET_WM_STATE_SKIP_PAGER", False) + }; + XChangeProperty(dpy, win, win_state, XA_ATOM, 32, + PropModeReplace, (unsigned char*)&win_state_setting, 3); +} + +static Window +make_window(Display *dpy) { + Window win; + XSetWindowAttributes att; + + /* XXX I don't understand X well enough to know if these are the correct + * settings. */ + att.backing_store = WhenMapped; + att.background_pixel = None; + att.border_pixel = 0; + att.background_pixmap = None; + att.save_under = True; + att.event_mask = ExposureMask | StructureNotifyMask; + att.override_redirect = True; + + win = XCreateWindow(dpy, DefaultRootWindow(dpy), + -1, -1, 1, 1, 0, + CopyFromParent, InputOutput, CopyFromParent, + CWBackingStore | CWBackPixel | CWBackPixmap | + CWEventMask | CWSaveUnder | CWOverrideRedirect, + &att); + + set_hints(dpy, win); + + /* XXX: XSetClassHint? */ + + return win; +} + +void +ghosd_show(Ghosd *ghosd) { + XMapWindow(ghosd->dpy, ghosd->win); +} + +void +ghosd_set_transparent(Ghosd *ghosd, int transparent) { + ghosd->transparent = (transparent != 0); +} + +void +ghosd_set_render(Ghosd *ghosd, GhosdRenderFunc render_func, void *render_data) { + ghosd->render_func = render_func; + ghosd->render_data = render_data; +} + +void +ghosd_set_position(Ghosd *ghosd, int x, int y, int width, int height) { + const int dpy_width = DisplayWidth(ghosd->dpy, DefaultScreen(ghosd->dpy)); + const int dpy_height = DisplayHeight(ghosd->dpy, DefaultScreen(ghosd->dpy)); + + if (x == GHOSD_COORD_CENTER) { + x = (dpy_width - width) / 2; + } else if (x < 0) { + x = dpy_width - width + x; + } + + if (y == GHOSD_COORD_CENTER) { + y = (dpy_height - height) / 2; + } else if (y < 0) { + y = dpy_height - height + y; + } + + ghosd->x = x; + ghosd->y = y; + ghosd->width = width; + ghosd->height = height; + + if (ghosd->transparent) + ghosd->background = take_snapshot(ghosd); + + XMoveResizeWindow(ghosd->dpy, ghosd->win, + ghosd->x, ghosd->y, ghosd->width, ghosd->height); +} + +#if 0 +static int +x_error_handler(Display *dpy, XErrorEvent* evt) { + /* segfault so we can get a backtrace. */ + char *x = NULL; + *x = 0; + return 0; +} +#endif + +Ghosd * +ghosd_new(void) { + Ghosd *ghosd; + Display *dpy; + Window win; + + dpy = XOpenDisplay(NULL); + if (dpy == NULL) { + fprintf(stderr, "Couldn't open display: (XXX FIXME)\n"); + return NULL; + } + + win = make_window(dpy); + + ghosd = calloc(1, sizeof(Ghosd)); + ghosd->dpy = dpy; + ghosd->win = win; + ghosd->transparent = 1; + + return ghosd; +} + +int +ghosd_get_socket(Ghosd *ghosd) { + return ConnectionNumber(ghosd->dpy); +} + +/* vim: set ts=2 sw=2 et cino=(0 : */ |