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