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