/* -*- c++ -*- * Copyright ©2005,2008 Hugo Mills * * This software is distributed under the terms of the GNU GPL v3 * For more information on the GPL, see the file COPYING or * visit http://www.gnu.org/ * * This software is distributed without warranty */ #include "output_xroot.h" #include #include extern "C" PluginInfo* getmodules(int i) { if(i==0) { PluginInfo_Output* pi = new PluginInfo_Output(); pi->name = "Output to X Root Window"; pi->author = "Hugo Mills"; pi->copyright = "©2005,2008 Hugo Mills"; pi->version = 0x10000; pi->parser = Output_XRoot::parser; return pi; } else return NULL; } Output* Output_XRoot::parser( ConfigLexer* lex, const std::string& type, const std::string& subtype ) { if(type != "X-root") return NULL; int update = -1; while(!lex->eos()) { if(readkeyedvalue(lex, "update-time", &update)) ; else throw(UnknownConfigToken(lex)); } return new Output_XRoot(update); } Output_XRoot::Output_XRoot(int u) : Output(0, 0), update(u) { display = XOpenDisplay(":0"); if (!display) { std::cerr << "Can't open X display '" << XDisplayName(":0") << "'" << std::endl; exit (2); } screen = DefaultScreen(display); root = RootWindow(display, screen); colourmap = DefaultColormap(display, screen); ymax = DisplayHeight(display, screen); xmax = DisplayWidth(display, screen); depth = (unsigned int)DefaultDepth(display, screen); Visual* visual = DefaultVisual(display, screen); pixmap = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, xmax, ymax, 32, 0); pixmap->data = new char[pixmap->bytes_per_line * ymax]; XGCValues gc_init; gc_init.foreground = WhitePixel(display, screen); gc_init.background = BlackPixel(display, screen); maingc = XCreateGC(display, root, GCForeground|GCBackground, &gc_init); if(pixmap->bits_per_pixel < 16) { std::cerr << "Can't cope with depths less than 16 bpp" << std::endl; exit(1); } red_shift = get_minbit(visual->red_mask); red_length = get_minbit((visual->red_mask >> red_shift) + 1); green_shift = get_minbit(visual->green_mask); green_length = get_minbit((visual->green_mask >> green_shift) + 1); blue_shift = get_minbit(visual->blue_mask); blue_length = get_minbit((visual->blue_mask >> blue_shift) + 1); } Output_XRoot::~Output_XRoot() { XFreeGC(display, maingc); delete[] pixmap->data; pixmap->data = NULL; // Prevent XDestroyImage from attempting a double-free XDestroyImage(pixmap); XCloseDisplay(display); } void Output_XRoot::commit(void) { #ifdef HAVE_BOOST_THREAD boost::mutex::scoped_lock _l(lock); #endif Pixmap pm = XCreatePixmap(display, root, xmax, ymax, depth); XPutImage(display, pm, maingc, pixmap, 0, 0, 0, 0, xmax, ymax); XSetWindowBackgroundPixmap(display, root, pm); XClearWindow(display, root); XSync(display, true); XFreePixmap(display, pm); } void Output_XRoot::setpixel(const ivec2& pos, int r, int g, int b) { if(pos[0] < 0 || pos[0] >= xmax || pos[1] < 0 || pos[1] >= ymax) return; unsigned long colour = (((r << red_length+red_shift) >> 8) & pixmap->red_mask) | (((g << green_length+green_shift) >> 8) & pixmap->green_mask) | (((b << blue_length+blue_shift) >> 8) & pixmap->blue_mask); #ifdef HAVE_BOOST_THREAD boost::mutex::scoped_lock _l(lock); #endif XPutPixel(pixmap, pos[0], ymax - pos[1] - 1, colour); } int Output_XRoot::get_minbit(unsigned long x) const { int r = 0; while((x & 0x1) == 0x0) { r++; x >>= 1; } return r; }