1 #include "gfxinterface.h"
2 #include "instance.h"
3 #include <cmath>
4 #include <cstdlib>
5 #include <stdexcept>
6 #include <vector>
7 
8 
9 
10 /*
11  *  Coord
12  */
13 
14 // Implementations of conversions from pixels distances to relative distances.
Rel(int dist,int scale)15 inline int Rel(int dist, int scale)
16 	{ return (dist * RCoord::max + scale / 2) / scale; }
17 
UnRel(int r,int scale)18 inline int UnRel(int r, int scale)
19 	{ return (r * scale + RCoord::max / 2) / RCoord::max; }
20 
21 
Coord(RCoord rc)22 Coord::Coord(RCoord rc)
23 {
24 	x = UnRel(rc.x, X11::Inst().WindowWidth());
25 	y = UnRel(rc.y, X11::Inst().WindowHeight());
26 }
27 
ToRCoord() const28 RCoord Coord::ToRCoord() const
29 {
30 	return RCoord(Rel(x, X11::Inst().WindowWidth()),
31 	              Rel(y, X11::Inst().WindowHeight()));
32 }
33 
Length() const34 double Coord::Length() const
35 {
36 	return std::sqrt(static_cast<double>(x * x + y * y));
37 }
38 
operator *=(double rhs)39 Coord & Coord::operator*=(double rhs)
40 {
41 	x = static_cast<short>(std::floor(x * rhs + 0.5));
42 	y = static_cast<short>(std::floor(y * rhs + 0.5));
43 	return *this;
44 }
45 
operator /=(double rhs)46 Coord & Coord::operator/=(double rhs)
47 {
48 	x = static_cast<short>(std::floor(x / rhs + 0.5));
49 	y = static_cast<short>(std::floor(y / rhs + 0.5));
50 	return *this;
51 }
52 
53 
54 
55 /*
56  *  X11
57  */
58 
59 X11 *    X11::singleton_             (0);
60 unsigned X11::default_window_width_  (640);
61 unsigned X11::default_window_height_ (480);
62 
63 
CreateInstance()64 void X11::CreateInstance()
65 {
66 	if (!singleton_) {
67 		singleton_ = new X11;
68 		InstancesManager::Instance().Push(DestroyInstance);
69 	}
70 }
71 
72 
X11()73 X11::X11()
74 : window_width_ (default_window_width_)
75 , window_height_(default_window_height_)
76 {
77 	display_ = XOpenDisplay(0);
78 	if (!display_) throw std::runtime_error ("Cannot open display");
79 	screen_   = DefaultScreen(display_);
80 	visual_   = DefaultVisual(display_, screen_);
81 	colormap_ = DefaultColormap(display_, screen_);
82 	gc_       = DefaultGC(display_, screen_);
83 
84 	const Color black (BlackPixel(display_, screen_));
85 	window_ = XCreateSimpleWindow(display_, DefaultRootWindow(display_),
86 	                              0, 0, window_width_, window_height_,
87 	                              0, black, black);
88 	XSelectInput(display_, window_, StructureNotifyMask);
89 	XMapWindow(display_, window_);
90 	XEvent e;
91 	do XNextEvent(display_, &e); while (e.type != MapNotify);
92 	XSelectInput(display_, window_, KeyPressMask | KeyReleaseMask);
93 }
94 
95 
~X11()96 X11::~X11()
97 {
98 	XDestroyWindow(display_, window_);
99 	XCloseDisplay(display_);
100 }
101 
102 
SetWindowTitle(const std::string & title) const103 void X11::SetWindowTitle(const std::string & title) const
104 {
105 	const char *const list_ptr (title.c_str());
106  	XTextProperty property;
107 	if (XStringListToTextProperty(const_cast<char**>(&list_ptr), 1, &property)) {
108 		XSetWMName(display_, window_, &property);
109 		XFree(property.value);
110 	} // Do nothing if out of memory.
111 }
112 
113 
GetWindowAttributes(XWindowAttributes * attrs)114 Status X11::GetWindowAttributes(XWindowAttributes * attrs)
115 {
116 	XWindowAttributes attrs2;
117 	if (!attrs) attrs = &attrs2;
118 	const Status s (XGetWindowAttributes(display_, window_, attrs));
119 	if (s != 0) {
120 		window_width_  = attrs->width;
121 		window_height_ = attrs->height;
122 	}
123 	return s;
124 }
125 
126 
ResizeWindow(unsigned width,unsigned height)127 void X11::ResizeWindow(unsigned width, unsigned height)
128 {
129 	GetWindowAttributes();
130 	if (width != window_width_ || height != window_height_) {
131 		XEvent e;
132 		XSelectInput(display_, window_, StructureNotifyMask);
133 		XResizeWindow(display_, window_, width, height);
134 		do XNextEvent(display_, &e); while (e.type != ConfigureNotify);
135 		XSelectInput(display_, window_, KeyPressMask | KeyReleaseMask);
136 		window_width_  = width;
137 		window_height_ = height;
138 	}
139 }
140 
ColorDistance(const XColor & c1,const XColor & c2)141 inline unsigned ColorDistance(const XColor & c1, const XColor & c2)
142 {
143 	return std::abs(c1.red   - c2.red  ) +
144 	       std::abs(c1.green - c2.green) +
145 	       std::abs(c1.blue  - c2.blue );
146 }
147 
148 
AllocColorAlways(XColor * color) const149 void X11::AllocColorAlways(XColor * color) const
150 {
151 	if (AllocColor(color)) return;
152 
153 	std::vector<XColor> colors (visual_->map_entries);
154 	for (std::vector<XColor>::size_type i (0); i < colors.size(); ++i) {
155 		colors[i].pixel = i;
156 	}
157 	XQueryColors(display_, colormap_, &colors[0], colors.size());
158 	unsigned min_dist (3*65535 + 1);
159 	std::vector<XColor>::size_type best_index (0);
160 	for (std::vector<XColor>::size_type i (0); i < colors.size(); ++i) {
161 		const unsigned dist (ColorDistance(colors[i], *color));
162 		if (dist < min_dist) {
163 			min_dist = dist;
164 			best_index = i;
165 		}
166 	}
167 	// This allocation may fail because the colormap is not locked (and
168 	// X Window color management is crap).
169 	// But it looks like it is 1) rare enough 2) quite benign 3) hard to
170 	// work around, so let it silently fail.
171 	*color = colors[best_index];
172 	AllocColor(color);
173 }
174 
175 
SetInvisibleCursor(void)176 void X11::SetInvisibleCursor(void) {
177 	Cursor invisibleCursor;
178 	Pixmap bitmap;
179 	XColor black;
180 	static char noData[] = { 0,0,0,0,0,0,0,0 };
181 	black.red = black.green = black.blue = 0;
182 
183 	bitmap = XCreateBitmapFromData(display_, window_, noData, 8, 8);
184 	invisibleCursor = XCreatePixmapCursor(display_, bitmap, bitmap,
185 	                                      &black, &black, 0, 0);
186 	XDefineCursor(display_, window_, invisibleCursor);
187 	XFreeCursor(display_, invisibleCursor);
188 	XFreePixmap(display_, bitmap);
189 }
190