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