#include "CtrlCore.h" #ifdef GUI_X11 #define Time XTime #define Font XFont #define Display XDisplay #define Picture XPicture #ifndef flagNOGTK #include #include #include #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; bool Xpalette; dword (*Xgetpixel)(int r, int g, int b); EXITBLOCK { if(Xdisplay) { 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(); } 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 { Xpalette = true; sAllocColors(); int colorcount = max(1 << Xdepth, 256); Buffer 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 = 0; 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); Font::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& 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 } void SetClip(GC gc, XftDraw *xftdraw, const Vector& cl) { GuiLock __; LTIMING("SetClip"); Buffer 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); LLOG("XftDrawSetClipRectangles, # = " << cl.GetCount() << ", xftdraw = " << FormatIntHex(xftdraw)); XftDrawSetClipRectangles(xftdraw, 0, 0, xr, cl.GetCount()); LLOG("//XftDrawSetClipRectangles"); } void SystemDraw::CloneClip() { if(cloff.GetCount() > 1 && cloff.Top().clipi == cloff[cloff.GetCount() - 2].clipi) { cloff.Top().clipi = clip.GetCount(); Vector& c = clip.Add(); c <<= clip[clip.GetCount() - 2]; } } void SystemDraw::SetForeground(Color color) { GuiLock __; LTIMING("SetForeground"); 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 SystemDraw::SetClip() { GuiLock __; drawingclip = Rect(-(INT_MAX >> 1), -(INT_MAX >> 1), +(INT_MAX >> 1), +(INT_MAX >> 1)); if(!clip.IsEmpty()) { const Vector& topclip = clip.Top(); drawingclip = Rect(0, 0, 0, 0); if(!topclip.IsEmpty()) { drawingclip = topclip[0]; for(int i = 1; i < topclip.GetCount(); i++) drawingclip |= topclip[i]; } drawingclip -= actual_offset; } if(dw == Xroot) return; LTIMING("SetClip"); UPP::SetClip(gc, xftdraw, clip.Top()); } void SystemDraw::SetLineStyle(int width) { GuiLock __; 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 SystemDraw::Init() { GuiLock __; pageSize = Size(Xwidth, Xheight); cloff.Clear(); clip.Clear(); drawingclip = Rect(-(INT_MAX >> 1), -(INT_MAX >> 1), +(INT_MAX >> 1), +(INT_MAX >> 1)); foreground = linewidth = Null; } void SystemDraw::Init(const Vector& _clip, Point _offset) { GuiLock __; Init(); clip.Add() <<= _clip; offset.Add(_offset); actual_offset = _offset; Cloff& f = cloff.Add(); f.offseti = 0; f.clipi = 0; SetClip(); } dword SystemDraw::GetInfo() const { return 0; } Size SystemDraw::GetPageSize() const { return pageSize; } SystemDraw::SystemDraw() { GuiLock __; dw = None; gc = None; actual_offset = Point(0, 0); Init(); } Size SystemDraw::GetNativeDpi() const { return Size(96, 96); } void SystemDraw::BeginNative() {} void SystemDraw::EndNative() {} int SystemDraw::GetCloffLevel() const { return cloff.GetCount(); } Rect SystemDraw::GetClip() const { LLOG("Draw::GetClipOp; #clip = " << clip.GetCount() << ", #cloff = " << cloff.GetCount() << ", clipi = " << cloff.Top().clipi); const Vector& cl = clip[cloff.Top().clipi]; Rect box(0, 0, 0, 0); if(!cl.GetCount()) return box; box = cl[0]; LLOG("cl[0] = " << box); for(int i = 1; i < cl.GetCount(); i++) { LLOG("cl[" << i << "] = " << cl[i]); box |= cl[i]; } LLOG("out box = " << box << ", actual offset = " << actual_offset); return box - actual_offset; } SystemDraw::SystemDraw(Drawable _dw, GC _gc, XftDraw *_xftdraw, const Vector& _clip) { LLOG("SystemDraw"); dw = _dw; gc = _gc; xftdraw = _xftdraw; Init(_clip); } void BackDraw::Create(SystemDraw& w, int cx, int cy) { GuiLock __; 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); xftdraw = XftDrawCreate(Xdisplay, (Drawable) dw, DefaultVisual(Xdisplay, Xscreenno), Xcolormap); Vector clip; clip.Add(RectC(0, 0, cx, cy)); Init(clip, Point(0, 0)); } void BackDraw::Put(SystemDraw& w, int x, int y) { GuiLock __; 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() { GuiLock __; if(dw != None) { XftDrawDestroy(xftdraw); XFreePixmap(Xdisplay, dw); XFreeGC(Xdisplay, gc); } } bool ScreenInPaletteMode() { return Xpalette; } Size GetScreenSize() { return Size(Xwidth, Xheight); } END_UPP_NAMESPACE #endif