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