#include <cstdio>
#include <cstdlib>
#include <sstream>
using namespace std;
#include "config.h"
#include "keywords.h"
#include "Options.h"
#include "PlanetProperties.h"
#include "xpUtil.h"
#include "DisplayX11.h"
#include "TimerX11.h"
#include "vroot.h"
// The window is static because it needs to stay open between
// renderings.
Window DisplayX11::window;
DisplayX11::DisplayX11(const int tr) : DisplayBase(tr)
{
Options *options = Options::getInstance();
if (options->DisplayMode() == WINDOW)
display = TimerX11::DisplayID();
else
display = XOpenDisplay(NULL);
if (display == NULL)
xpExit("Can't open X display\n", __FILE__, __LINE__);
const int screen_num = DefaultScreen(display);
if (options->VirtualRoot())
root = VirtualRootWindowOfScreen(ScreenOfDisplay(display, screen_num));
else
root = ScreenOfDisplay(display, screen_num)->root;
XWindowAttributes xgwa;
XGetWindowAttributes(display, root, &xgwa);
fullWidth_ = xgwa.width;
fullHeight_ = xgwa.height;
switch (options->DisplayMode())
{
case WINDOW:
{
if (options->XID())
{
window = static_cast<Window> (options->XID());
}
else
{
width_ = options->getWidth();
height_ = options->getHeight();
if (times_run == 0)
{
int x = options->getWindowX();
int y = options->getWindowY();
if (options->GeometryMask() & XNegative)
x += (fullWidth_ - width_);
if (options->GeometryMask() & YNegative)
y += (fullHeight_ - height_);
window = XCreateSimpleWindow(display, root, x, y,
width_, height_, 4,
WhitePixel(display, screen_num),
BlackPixel(display, screen_num));
if (options->GeometryMask() != NoValue)
{
XSizeHints *hints = XAllocSizeHints();
hints->flags = USPosition;
XSetWMNormalHints(display, window, hints);
}
string title;
if (options->WindowTitle().empty())
{
title.assign("Xplanet ");
title += VERSION;
}
else
{
title.assign(options->WindowTitle());
}
XTextProperty windowName;
char *titlec = (char *) title.c_str();
XStringListToTextProperty(&titlec, 1, &windowName);
XSetWMName(display, window, &windowName);
}
}
XGetWindowAttributes(display, window, &xgwa);
width_ = xgwa.width;
height_ = xgwa.height;
}
break;
case ROOT:
if (options->GeometrySelected())
{
width_ = options->getWidth();
height_ = options->getHeight();
}
else
{
width_ = fullWidth_;
height_ = fullHeight_;
}
window = root;
break;
default:
xpExit("DisplayX11: Unknown display mode?\n", __FILE__, __LINE__);
}
if (!options->CenterSelected())
{
if (width_ % 2 == 0)
options->CenterX(width_/2 - 0.5);
else
options->CenterX(width_/2);
if (height_ % 2 == 0)
options->CenterY(height_/2 - 0.5);
else
options->CenterY(height_/2);
}
allocateRGBData();
}
DisplayX11::~DisplayX11()
{
}
void
DisplayX11::renderImage(PlanetProperties *planetProperties[])
{
drawLabel(planetProperties);
Options *options = Options::getInstance();
Pixmap pixmap;
switch (options->DisplayMode())
{
case WINDOW:
pixmap = createPixmap(rgb_data, width_, height_);
XMapWindow(display, window);
break;
case ROOT:
if (options->GeometrySelected()) PlaceImageOnRoot();
pixmap = createPixmap(rgb_data, fullWidth_, fullHeight_);
if (options->Transparency())
{
// Set the background pixmap for Eterms and aterms. This
// code is taken from the Esetroot source.
Atom prop_root, prop_esetroot, type;
int format;
unsigned long length, after;
unsigned char *data_root, *data_esetroot;
prop_root = XInternAtom(display, "_XROOTPMAP_ID", True);
prop_esetroot = XInternAtom(display, "ESETROOT_PMAP_ID", True);
if (prop_root != None && prop_esetroot != None)
{
XGetWindowProperty(display, root, prop_root,
0L, 1L, False, AnyPropertyType,
&type, &format, &length,
&after, &data_root);
if (type == XA_PIXMAP)
{
XGetWindowProperty(display, root, prop_esetroot,
0L, 1L, False, AnyPropertyType,
&type, &format, &length,
&after, &data_esetroot);
if (data_root && data_esetroot)
{
if (type == XA_PIXMAP
&& *((Pixmap *) data_root) == *((Pixmap *) data_esetroot))
{
XKillClient(display, *((Pixmap *) data_root));
}
}
}
}
/* This will locate the property, creating it if it
* doesn't exist */
prop_root = XInternAtom(display, "_XROOTPMAP_ID", False);
prop_esetroot = XInternAtom(display, "ESETROOT_PMAP_ID", False);
/* The call above should have created it. If that failed,
* we can't continue. */
if (prop_root == None || prop_esetroot == None)
{
xpWarn("Can't set pixmap for transparency\n",
__FILE__, __LINE__);
}
else
{
XChangeProperty(display, root, prop_root, XA_PIXMAP,
32, PropModeReplace,
(unsigned char *) &pixmap, 1);
XChangeProperty(display, root, prop_esetroot, XA_PIXMAP,
32, PropModeReplace,
(unsigned char *) &pixmap, 1);
XSetCloseDownMode(display, RetainPermanent);
XFlush(display);
}
}
break;
default:
xpExit("Unknown X11 display mode?\n", __FILE__, __LINE__);
}
XSetWindowBackgroundPixmap(display, window, pixmap);
if (!options->Transparency()) XFreePixmap(display, pixmap);
XClearWindow(display, window);
XFlush(display);
if (options->DisplayMode() == ROOT) XCloseDisplay(display);
}
void
DisplayX11::computeShift(unsigned long mask,
unsigned char &left_shift,
unsigned char &right_shift)
{
left_shift = 0;
right_shift = 8;
if (mask != 0)
{
while ((mask & 0x01) == 0)
{
left_shift++;
mask >>= 1;
}
while ((mask & 0x01) == 1)
{
right_shift--;
mask >>= 1;
}
}
}
Pixmap
DisplayX11::createPixmap(const unsigned char *rgb,
const int pixmap_width, const int pixmap_height)
{
int i, j; // loop variables
const int screen_num = DefaultScreen(display);
const int depth = DefaultDepth(display, screen_num);
Visual *visual = DefaultVisual(display, screen_num);
Colormap colormap = DefaultColormap(display, screen_num);
Pixmap tmp = XCreatePixmap(display, window, pixmap_width, pixmap_height,
depth);
char *pixmap_data = NULL;
switch (depth)
{
case 32:
case 24:
pixmap_data = new char[4 * pixmap_width * pixmap_height];
break;
case 16:
case 15:
pixmap_data = new char[2 * pixmap_width * pixmap_height];
break;
case 8:
pixmap_data = new char[pixmap_width * pixmap_height];
break;
default:
break;
}
XImage *ximage = XCreateImage(display, visual, depth, ZPixmap, 0,
pixmap_data, pixmap_width, pixmap_height,
8, 0);
int entries;
XVisualInfo v_template;
v_template.visualid = XVisualIDFromVisual(visual);
XVisualInfo *visual_info = XGetVisualInfo(display, VisualIDMask,
&v_template, &entries);
unsigned long ipos = 0;
switch (visual_info->c_class)
{
case PseudoColor:
{
XColor xc;
xc.flags = DoRed | DoGreen | DoBlue;
int num_colors = 256;
XColor *colors = new XColor[num_colors];
for (i = 0; i < num_colors; i++) colors[i].pixel = (unsigned long) i;
XQueryColors(display, colormap, colors, num_colors);
int *closest_color = new int[num_colors];
for (i = 0; i < num_colors; i++)
{
xc.red = (i & 0xe0) << 8; // highest 3 bits
xc.green = (i & 0x1c) << 11; // middle 3 bits
xc.blue = (i & 0x03) << 14; // lowest 2 bits
// find the closest color in the colormap
double distance, distance_squared, min_distance = 0;
for (int ii = 0; ii < num_colors; ii++)
{
distance = colors[ii].red - xc.red;
distance_squared = distance * distance;
distance = colors[ii].green - xc.green;
distance_squared += distance * distance;
distance = colors[ii].blue - xc.blue;
distance_squared += distance * distance;
if ((ii == 0) || (distance_squared <= min_distance))
{
min_distance = distance_squared;
closest_color[i] = ii;
}
}
}
for (j = 0; j < pixmap_height; j++)
{
for (i = 0; i < pixmap_width; i++)
{
xc.red = (unsigned short) (rgb[ipos++] & 0xe0);
xc.green = (unsigned short) (rgb[ipos++] & 0xe0);
xc.blue = (unsigned short) (rgb[ipos++] & 0xc0);
xc.pixel = xc.red | (xc.green >> 3) | (xc.blue >> 6);
XPutPixel(ximage, i, j,
colors[closest_color[xc.pixel]].pixel);
}
}
delete [] colors;
delete [] closest_color;
}
break;
case TrueColor:
{
unsigned char red_left_shift;
unsigned char red_right_shift;
unsigned char green_left_shift;
unsigned char green_right_shift;
unsigned char blue_left_shift;
unsigned char blue_right_shift;
computeShift(visual_info->red_mask, red_left_shift,
red_right_shift);
computeShift(visual_info->green_mask, green_left_shift,
green_right_shift);
computeShift(visual_info->blue_mask, blue_left_shift,
blue_right_shift);
unsigned long pixel;
unsigned long red, green, blue;
for (j = 0; j < pixmap_height; j++)
{
for (i = 0; i < pixmap_width; i++)
{
red = (unsigned long)
rgb[ipos++] >> red_right_shift;
green = (unsigned long)
rgb[ipos++] >> green_right_shift;
blue = (unsigned long)
rgb[ipos++] >> blue_right_shift;
pixel = (((red << red_left_shift) & visual_info->red_mask)
| ((green << green_left_shift)
& visual_info->green_mask)
| ((blue << blue_left_shift)
& visual_info->blue_mask));
XPutPixel(ximage, i, j, pixel);
}
}
}
break;
default:
{
ostringstream errStr;
errStr << "createPixmap: visual = " << visual_info->c_class << endl
<< "Visual should be either PseudoColor or TrueColor\n";
xpWarn(errStr.str(), __FILE__, __LINE__);
return(tmp);
}
}
GC gc = XCreateGC(display, window, 0, NULL);
XPutImage(display, tmp, gc, ximage, 0, 0, 0, 0, pixmap_width,
pixmap_height);
XFreeGC(display, gc);
XFree(visual_info);
delete [] pixmap_data;
// Set ximage data to NULL since pixmap data was deallocated above
ximage->data = NULL;
XDestroyImage(ximage);
return(tmp);
}
void
DisplayX11::decomposePixmap(const Pixmap p, unsigned char *rgb)
{
int i, j;
unsigned long ipos = 0;
const int screen_num = DefaultScreen(display);
Visual *visual = DefaultVisual(display, screen_num);
int entries;
XVisualInfo v_template;
v_template.visualid = XVisualIDFromVisual(visual);
XVisualInfo *visual_info = XGetVisualInfo(display, VisualIDMask,
&v_template, &entries);
Colormap colormap = DefaultColormap(display, screen_num);
XImage *ximage = XGetImage(display, p, 0, 0, width_,
height_, AllPlanes, ZPixmap);
switch (visual_info->c_class)
{
case PseudoColor:
{
XColor *xc = new XColor[width_];
for (j = 0; j < height_; j++)
{
for (i = 0; i < width_; i++)
xc[i].pixel = XGetPixel(ximage, i, j);
XQueryColors(display, colormap, xc, width_);
for (i = 0; i < width_; i++)
{
rgb[ipos++] = (unsigned char) (xc[i].red >> 8);
rgb[ipos++] = (unsigned char) (xc[i].green >> 8);
rgb[ipos++] = (unsigned char) (xc[i].blue >> 8);
}
}
delete [] xc;
}
break;
case TrueColor:
{
unsigned char red_left_shift;
unsigned char red_right_shift;
unsigned char green_left_shift;
unsigned char green_right_shift;
unsigned char blue_left_shift;
unsigned char blue_right_shift;
computeShift(visual_info->red_mask, red_left_shift,
red_right_shift);
computeShift(visual_info->green_mask, green_left_shift,
green_right_shift);
computeShift(visual_info->blue_mask, blue_left_shift,
blue_right_shift);
unsigned long pixel;
for (j = 0; j < height_; j++)
{
for (i = 0; i < width_; i++)
{
pixel = XGetPixel(ximage, i, j);
rgb[ipos++] = ((unsigned char)
(((pixel & visual_info->red_mask)
>> red_left_shift)
<< red_right_shift));
rgb[ipos++] = ((unsigned char)
(((pixel & visual_info->green_mask)
>> green_left_shift)
<< green_right_shift));
rgb[ipos++] = ((unsigned char)
(((pixel & visual_info->blue_mask)
>> blue_left_shift)
<< blue_right_shift));
}
}
}
break;
default:
{
ostringstream errStr;
errStr << "decomposePixmap: visual = " << visual_info->c_class << endl
<< "Visual should be either PseudoColor or TrueColor\n";
xpWarn(errStr.str(), __FILE__, __LINE__);
}
}
XFree(visual_info);
XDestroyImage(ximage);
}
syntax highlighted by Code2HTML, v. 0.9.1