ultimatepp/uppsrc/Draw/DrawX11.cpp
mdelfede 263ff5f895 changed svn layout
git-svn-id: svn://ultimatepp.org/upp/trunk@281 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2008-06-07 22:31:27 +00:00

459 lines
10 KiB
C++

#include "Draw.h"
#ifdef PLATFORM_X11
#define Time XTime
#define Font XFont
#define Display XDisplay
#define Picture XPicture
#ifndef flagNOGTK
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <gdk/gdkprivate.h>
#endif
#undef Picture
#undef Time
#undef Font
#undef Display
NAMESPACE_UPP
#define LLOG(x) //LOG(x)
#define LTIMING(x) //TIMING(x)
XDisplay *Xdisplay;
int Xscreenno;
Visual *Xvisual;
Window Xroot;
Screen *Xscreen;
Colormap Xcolormap;
int Xheight;
int Xwidth;
int XheightMM;
int XwidthMM;
int Xdepth;
dword Xblack;
dword Xwhite;
int Xconnection;
byte *Xmapcolor;
byte *Xunmapcolor;
dword (*Xgetpixel)(int r, int g, int b);
void StaticExitDraw_()
{
Draw::FreeFonts();
}
EXITBLOCK
{
if(Xdisplay) {
StaticExitDraw_();
// No CloseDisplay for now...
XCloseDisplay(Xdisplay);
LLOG("Xdisplay closed");
Xdisplay = NULL;
}
if(Xmapcolor)
delete[] Xmapcolor;
if(Xunmapcolor)
delete[] Xunmapcolor;
}
void XError()
{
Panic("X11 error !");
}
void XError(const char *s)
{
Panic(String("X11 error:") + s + " !");
}
static int sAcs;
bool sAllocColor(int xr, int xg, int xb)
{
XColor ce;
ce.red = xr;
ce.green = xg;
ce.blue = xb;
ce.flags = DoRed | DoGreen | DoBlue;
if(!XAllocColor(Xdisplay, Xcolormap, &ce)) return false;
sAcs++;
return sAcs < 257;
}
void sAllocColors()
{
int r, g, b;
for(r = 0; r < 2; r++)
for(g = 0; g < 2; g++)
for(b = 0; b < 2; b++)
if(!sAllocColor(65535 * r, 65535 * g, 65535 * b)) return;
for(r = 0; r < 3; r++)
for(g = 0; g < 3; g++)
for(b = 0; b < 3; b++)
if((r == 1 || g == 1 || b == 1) &&
!sAllocColor((65535 * r) / 2, (65535 * g) / 2, (65535 * b) / 2)) return;
for(r = 5; r >= 0; r--)
for(g = 5; g >= 0; g--)
for(b = 5; b >= 0; b--)
if((r != 0 && r != 5 || g != 0 && g != 5 || b != 0 && b != 5) &&
!sAllocColor((65535 * r) / 5, (65535 * g) / 5, (65535 * b) / 5)) return;
for(r = 1; r <= 11; r += 2)
if(!sAllocColor((65535 * r) / 11, (65535 * r) / 11, (65535 * r) / 11)) return;
for(int r = 255; r >= 0; r--)
if(!sAllocColor(r << 8, r << 8, r << 8)) return;
}
dword GetPseudoColorPixel(int r, int g, int b)
{
return Xmapcolor[r * 11 / 255 * (24 * 12) + g * 23 / 255 * 12 + b * 11 / 255];
}
static
struct Xshift {
dword mask;
int bits;
int shift;
dword Do(int c) { return (c >> bits << shift) & mask; }
}
Xred, Xgreen, Xblue;
Xshift CalcXShift(dword mask)
{
Xshift f;
f.mask = mask;
f.shift = 0;
f.bits = 0;
while((mask & 1) == 0) {
mask >>= 1;
f.shift++;
}
while((mask & 1) == 1) {
mask >>= 1;
f.bits++;
}
f.bits = 8 - f.bits;
if(f.bits < 0) {
f.shift += f.bits;
f.bits = 0;
}
LLOG("xshift(" << FormatIntHex(mask) << "): mask = "
<< FormatIntHex(f.mask) << ", bits = " << f.bits << ", shift = " << f.shift);
return f;
}
dword GetTrueColorPixel(int r, int g, int b)
{
return Xred.Do(r) | Xgreen.Do(g) | Xblue.Do(b);
}
inline int ssq(int x) { return x * x; }
void InitX11Draw(XDisplay *display)
{
Xdisplay = display;
if(!Xdisplay) {
puts(NFormat("No X11 display, errno = %d, %s", errno, strerror(errno)));
fflush(stdout);
XError();
}
int Xscreenno = DefaultScreen(Xdisplay);
Xroot = RootWindow(Xdisplay, Xscreenno);
Xscreen = ScreenOfDisplay(Xdisplay, Xscreenno);
Xcolormap = DefaultColormap(Xdisplay, Xscreenno);
// Xcolormap = (Colormap)GDK().gdk_x11_colormap_get_xcolormap(GDK().gdk_rgb_get_colormap());
Xheight = DisplayHeight(Xdisplay, Xscreenno);
Xwidth = DisplayWidth(Xdisplay, Xscreenno);
XheightMM = DisplayHeightMM(Xdisplay, Xscreenno);
XwidthMM = DisplayWidthMM(Xdisplay, Xscreenno);
LLOG("Xwidth = " << Xwidth << ", XwidthMM = " << XwidthMM);
LLOG("Xheight = " << Xheight << ", XheightMM = " << XheightMM);
Xdepth = DefaultDepth(Xdisplay, Xscreenno);
Xblack = BlackPixel(Xdisplay, 0);
Xwhite = WhitePixel(Xdisplay, 0);
Xconnection = XConnectionNumber(Xdisplay);
Xvisual = DefaultVisual(Xdisplay, Xscreenno);
Visual *v = Xvisual;
if(v->c_class == TrueColor) {
Xred = CalcXShift(v->red_mask);
Xgreen = CalcXShift(v->green_mask);
Xblue = CalcXShift(v->blue_mask);
Xgetpixel = GetTrueColorPixel;
}
else {
sAllocColors();
int colorcount = max(1 << Xdepth, 256);
Buffer<XColor> cs(colorcount);
int i;
for(i = 0; i < colorcount; i++)
cs[i].pixel = i;
XQueryColors(Xdisplay, Xcolormap, cs, colorcount);
Xunmapcolor = new byte[3 * colorcount];
for(i = 0; i < colorcount; i++)
{
Xunmapcolor[3 * i + 0] = cs[i].blue;
Xunmapcolor[3 * i + 1] = cs[i].green;
Xunmapcolor[3 * i + 2] = cs[i].red;
}
byte *cm = Xmapcolor = new byte[12 * 24 * 12];
for(int r = 0; r < 12; r++)
for(int g = 0; g < 24; g++)
for(int b = 0; b < 12; b++) {
int mind = INT_MAX;
int mini;
for(int i = 0; i < colorcount; i++) {
int d = ssq(r * 255 / 11 - (cs[i].red >> 8)) +
ssq(g * 255 / 23 - (cs[i].green >> 8)) +
ssq(b * 255 / 11 - (cs[i].blue >> 8));
if(d < mind) {
mini = i;
mind = d;
}
}
*cm++ = mini;
}
Xgetpixel = GetPseudoColorPixel;
}
// XFree(v);
Draw::SetStdFont(ScreenSans(12));
}
void InitX11Draw(const char *dispname)
{
#ifdef flagNOGTK
if(!dispname || !*dispname) {
int f = Environment().Find("DISPLAY");
dispname = (f >= 0 ? ~Environment()[f] : ":0.0");
}
InitX11Draw(XOpenDisplay(dispname));
#else
MemoryIgnoreLeaksBlock __;
const Vector<String>& cmd = CommandLine();
char **argv = (char**) MemoryAllocPermanent(sizeof(char *) * cmd.GetCount());
for(int i = 0; i < cmd.GetCount(); i++)
argv[i] = PermanentCopy(cmd[i]);
int argc = cmd.GetCount();
gtk_init (&argc, &argv);
GtkWidget *w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
GdkDisplay *d = gtk_widget_get_display(w);
gdk_x11_display_get_xdisplay(d);
InitX11Draw(gdk_x11_display_get_xdisplay(d));
gtk_widget_destroy(w);
#endif
}
#ifdef PLATFORM_XFT
void SetClip(GC gc, XftDraw *xftdraw, const Vector<Rect>& cl)
#else
void SetClip(GC gc, const Vector<Rect>& cl)
#endif
{
DrawLock __;
LTIMING("SetClip");
Buffer<XRectangle> xr(cl.GetCount());
LLOG("SetClip");
for(int i = 0; i < cl.GetCount(); i++) {
XRectangle& r = xr[i];
const Rect& cr = cl[i];
LLOG("[" << i << "] = " << cr);
r.x = cr.left;
r.y = cr.top;
r.width = cr.Width();
r.height = cr.Height();
}
XSetClipRectangles(Xdisplay, gc, 0, 0, xr, cl.GetCount(), Unsorted);
#ifdef PLATFORM_XFT
LLOG("XftDrawSetClipRectangles, # = " << cl.GetCount() << ", xftdraw = " << FormatIntHex(xftdraw));
XftDrawSetClipRectangles(xftdraw, 0, 0, xr, cl.GetCount());
LLOG("//XftDrawSetClipRectangles");
#endif
}
void Draw::CloneClip()
{
if(cloff.GetCount() > 1 && cloff.Top().clipi == cloff[cloff.GetCount() - 2].clipi) {
cloff.Top().clipi = clip.GetCount();
Vector<Rect>& c = clip.Add();
c <<= clip[clip.GetCount() - 2];
}
}
void Draw::SetForeground(Color color)
{
DrawLock __;
LTIMING("SetForeground");
if(IsDrawing()) return;
int p = GetXPixel(color.GetR(), color.GetG(), color.GetB());
if(p == foreground) return;
LTIMING("XSetForeground");
LLOG("XSetForeground " << color);
foreground = p;
XSetForeground(Xdisplay, gc, foreground);
}
void Draw::SetClip() {
DrawLock __;
if(IsDrawing() || dw == Xroot) return;
LTIMING("SetClip");
#ifdef PLATFORM_XFT
UPP::SetClip(gc, xftdraw, clip.Top());
#else
UPP::SetClip(gc, clip.Top());
#endif
}
void Draw::SetLineStyle(int width)
{
DrawLock __;
if(IsDrawing()) return;
if(width == linewidth) return;
linewidth = width;
if(IsNull(width))
width = 1;
if(width < PEN_SOLID) {
static const char dash[] = { 18, 6 };
static const char dot[] = { 3, 3 };
static const char dashdot[] = { 9, 6, 3, 6 };
static const char dashdotdot[] = { 9, 3, 3, 3, 3, 3 };
static struct {
const char *dash;
int len;
} ds[] = {
{ dash, __countof(dash) },
{ dot, __countof(dot) },
{ dashdot, __countof(dashdot) },
{ dashdotdot, __countof(dashdotdot) }
};
int i = -(width - PEN_DASH);
ASSERT(i >= 0 && i < 4);
XSetDashes(Xdisplay, gc, 0, ds[i].dash, ds[i].len);
}
XSetLineAttributes(Xdisplay, gc, max(width, 1),
width < PEN_SOLID ? LineOnOffDash : LineSolid, CapRound, JoinRound);
}
void Draw::Init()
{
DrawLock __;
pagePixels = Size(Xwidth, Xheight);
pageMMs = Size(XwidthMM, XheightMM);
inchPixels = 254 * pagePixels / pageMMs / 10;
sheetPixels = pagePixels;
pageOffset = Point(0, 0);
InitFonts();
cloff.Clear();
clip.Clear();
foreground = linewidth = Null;
device = 0;
device = 0;
pixels = true;
printer = aborted = backdraw = is_mono = false;
}
void Draw::Init(const Vector<Rect>& _clip, Point _offset)
{
DrawLock __;
Init();
clip.Add() <<= _clip;
offset.Add(_offset);
actual_offset = _offset;
Cloff& f = cloff.Add();
f.offseti = 0;
f.clipi = 0;
SetClip();
}
Draw::Draw()
{
DrawLock __;
dw = None;
gc = None;
actual_offset = Point(0, 0);
Init();
}
#ifdef PLATFORM_XFT
Draw::Draw(Drawable _dw, GC _gc, XftDraw *_xftdraw, const Vector<Rect>& _clip)
#else
Draw::Draw(Drawable _dw, GC _gc, const Vector<Rect>& _clip)
#endif
{
LLOG("Draw");
dw = _dw;
gc = _gc;
#ifdef PLATFORM_XFT
xftdraw = _xftdraw;
#endif
Init(_clip);
}
Draw::~Draw()
{
}
void BackDraw::Create(Draw& w, int cx, int cy)
{
DrawLock __;
LLOG("Creating BackDraw " << cx << "x" << cy);
Destroy();
size.cx = cx;
size.cy = cy;
dw = XCreatePixmap(Xdisplay, w.GetDrawable(), max(cx, 1), max(cy, 1), Xdepth);
gc = XCreateGC(Xdisplay, dw, 0, 0);
#ifdef PLATFORM_XFT
xftdraw = XftDrawCreate(Xdisplay, (Drawable) dw,
DefaultVisual(Xdisplay, Xscreenno), Xcolormap);
#endif
Vector<Rect> clip;
clip.Add(RectC(0, 0, cx, cy));
Init(clip, Point(0, 0));
backdraw = true;
}
void BackDraw::Put(Draw& w, int x, int y)
{
DrawLock __;
LLOG("Putting BackDraw");
ASSERT(dw != None);
XCopyArea(Xdisplay, dw, w.GetDrawable(), w.GetGC(), 0, 0, size.cx, size.cy,
x + w.GetOffset().x, y + w.GetOffset().y);
}
void BackDraw::Destroy()
{
DrawLock __;
if(dw != None) {
#ifdef PLATFORM_XFT
XftDrawDestroy(xftdraw);
#endif
XFreePixmap(Xdisplay, dw);
XFreeGC(Xdisplay, gc);
}
}
NilDraw::NilDraw()
{
DrawLock __;
dw = Xroot;
gc = XCreateGC(Xdisplay, Xroot, 0, 0);
pixels = false;
Init(Vector<Rect>());
}
NilDraw::~NilDraw()
{
DrawLock __;
XFreeGC(Xdisplay, gc);
}
Draw& ScreenInfo() { return Single<NilDraw>(); }
END_UPP_NAMESPACE
#endif