3ab3c81f3925ea40754cf3799a9066f6839cc325
[universe.git] / simple_window.cc
1
2 // Written and (C) by Francois Fleuret
3 // Contact <francois.fleuret@idiap.ch> for comments & bug reports
4
5 #include "simple_window.h"
6
7 SimpleEvent::SimpleEvent() : type(UNDEFINED) {}
8
9 SimpleWindow::SimpleWindow(const char *name, int x, int y, int w, int h) {
10
11   _width = w; _height = h;
12
13   _display = XOpenDisplay(0);
14
15   if (_display) {
16
17       Visual *v = XDefaultVisual(_display, DefaultScreen(_display));
18
19       _blue_mask = v->blue_mask;
20       _green_mask = v->green_mask;
21       _red_mask = v->red_mask;
22
23       if(_blue_mask == 0 || _green_mask == 0 || _red_mask == 0) {
24         cerr << "Can not deal with the colors on that display.\n";
25       }
26
27       _red_shift = 1;
28       while(!(_red_mask & 1)) {
29         _red_mask = _red_mask >> 1;
30         _red_shift = _red_shift << 1;
31       }
32
33       _green_shift = 1;
34       while(!(_green_mask & 1)) {
35         _green_mask = _green_mask >> 1;
36         _green_shift = _green_shift << 1;
37       }
38
39       _blue_shift = 1;
40       while(!(_blue_mask & 1)) {
41         _blue_mask = _blue_mask >> 1;
42         _blue_shift = _blue_shift << 1;
43       }
44
45       _gc = DefaultGC(_display, DefaultScreen(_display));
46
47       XSetWindowAttributes xswa;
48
49       _pixmap = XCreatePixmap(_display, DefaultRootWindow(_display),
50                               _width, _height, DisplayPlanes(_display, DefaultScreen(_display)));
51
52       xswa.background_pixmap = _pixmap;
53       xswa.event_mask = ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | KeyPressMask | KeyReleaseMask;
54       xswa.backing_store = Always;
55
56       _window = XCreateWindow(_display, DefaultRootWindow(_display), x, y, _width, _height,
57                               0, 0, InputOutput, CopyFromParent,
58                               CWBackPixmap | CWEventMask | CWBackingStore,
59                               &xswa);
60
61       XSizeHints size_hints;
62       size_hints.flags = PMinSize | PMaxSize | USPosition;
63       size_hints.x = x; // These two lines do not seem to be required
64       size_hints.y = y; // ...
65       size_hints.min_width = _width;
66       size_hints.min_height = _height;
67       size_hints.max_width = _width;
68       size_hints.max_height = _height;
69       XSetNormalHints(_display, _window, &size_hints);
70
71       XStoreName(_display, _window, name);
72
73       XSetState(_display, _gc, 0, 0, GXcopy, AllPlanes);
74       XFillRectangle(_display, _pixmap, _gc, 0, 0, _width, _height);
75       XFlush(_display);
76     } else abort();
77 }
78
79
80 SimpleWindow::~SimpleWindow() {
81   XUnmapWindow(_display, _window);
82   XDestroyWindow(_display, _window);
83   XCloseDisplay(_display);
84 }
85
86 int SimpleWindow::width() {
87   return _width;
88 }
89
90 int SimpleWindow::height() {
91   return _height;
92 }
93
94 void SimpleWindow::map() {
95   XMapWindow(_display, _window);
96   XFlush(_display);
97 }
98
99 void SimpleWindow::unmap() {
100   XUnmapWindow(_display, _window);
101   XFlush(_display);
102 }
103
104 void SimpleWindow::color(float red, float green, float blue) {
105   XSetState(_display, _gc,
106               ((unsigned int) (  red *   _red_mask)) *   _red_shift
107             + ((unsigned int) (green * _green_mask)) * _green_shift
108             + ((unsigned int) ( blue *  _blue_mask)) *  _blue_shift,
109             0, GXcopy, AllPlanes);
110 }
111
112 void SimpleWindow::draw_point(int x, int y) {
113   XDrawPoint(_display, _pixmap, _gc, x, y);
114 }
115
116 void SimpleWindow::draw_line(int x1, int y1, int x2, int y2) {
117   XDrawLine(_display, _pixmap, _gc, x1, y1, x2, y2);
118 }
119
120 void SimpleWindow::draw_circle(int x, int y, int r) {
121   XDrawArc(_display, _pixmap, _gc, x-r, y-r, 2*r, 2*r, 0, 360*64);
122 }
123
124 void SimpleWindow::draw_text(const char *s, int x, int y) {
125   XDrawString(_display, _pixmap, _gc, x, y, s, strlen(s));
126 }
127
128 void SimpleWindow::fill_rectangle(int x, int y, int w, int h) {
129   XFillRectangle(_display, _pixmap, _gc, x, y, w, h);
130 }
131
132 void SimpleWindow::fill_polygon(int nb, int *x, int *y) {
133   XPoint points[nb];
134   for(int n = 0; n < nb; n++) {
135     points[n].x = x[n];
136     points[n].y = y[n];
137   }
138   XFillPolygon(_display, _pixmap, _gc, points, nb, Nonconvex, CoordModeOrigin);
139 }
140
141 void SimpleWindow::show() {
142   XCopyArea(_display, _pixmap, _window, _gc, 0, 0, _width, _height, 0, 0);
143   XFlush(_display);
144 }
145
146 void SimpleWindow::fill() {
147   XFillRectangle(_display, _pixmap, _gc, 0, 0, _width, _height);
148 }
149
150 int  SimpleWindow::file_descriptor() {
151   return XConnectionNumber(_display);
152 }
153
154 SimpleEvent SimpleWindow::event() {
155   SimpleEvent se;
156
157   if(XPending(_display) > 0) {
158
159     XEvent event;
160     XNextEvent(_display, &event);
161
162     switch (event.type) {
163
164     case ButtonPress:
165       se.type = SimpleEvent::MOUSE_CLICK_PRESS;
166       se.button = event.xbutton.button;
167       se.x = event.xbutton.x;
168       se.y = event.xbutton.y;
169       break;
170
171     case ButtonRelease:
172       se.type = SimpleEvent::MOUSE_CLICK_RELEASE;
173       se.button = event.xbutton.button;
174       se.x = event.xbutton.x;
175       se.y = event.xbutton.y;
176       break;
177
178     case MotionNotify:
179       se.type = SimpleEvent::MOUSE_MOTION;
180       se.button = event.xbutton.button;
181       se.x = event.xbutton.x;
182       se.y = event.xbutton.y;
183       break;
184
185     case KeyPress:
186       se.type = SimpleEvent::KEY_PRESS;
187       strncpy(se.key,
188               XKeysymToString(XKeycodeToKeysym(_display, event.xkey.keycode, 0)),
189               (sizeof(se.key)/sizeof(char) - 1));
190       break;
191
192     case KeyRelease:
193       se.type = SimpleEvent::KEY_RELEASE;
194       strncpy(se.key,
195               XKeysymToString(XKeycodeToKeysym(_display, event.xkey.keycode, 0)),
196               (sizeof(se.key)/sizeof(char) - 1));
197       break;
198
199     default:
200       se.type = SimpleEvent::UNDEFINED;
201       break;
202     }
203   } else se.type = SimpleEvent::NO_EVENT;
204   return se;
205 }