view src/App.cpp @ 6:1b73e60d53b4

Now with keyboard support
author Eris Caffee <discordia@eldalin.com>
date Tue, 17 Apr 2012 01:56:49 -0500
parents 008e28de2870
children 713e3c5db1e1
line source
1 #include "App.h"
3 #include <cstdlib>
4 #include <iostream>
5 #include <typeinfo>
6 #include <X11/Xutil.h>
9 ////////////////////////////////////////////////////////////////////////////////
10 App::App(const std::string & appname)
11 {
12 XSetErrorHandler(&App::x_error_handler);
14 if ((dpy = XOpenDisplay(NULL)) == NULL)
15 {
16 std::cerr << "Unable to connect to display " << XDisplayName(NULL) << std::endl;
17 exit(1);
18 }
19 std::cout << "Display name : " << XDisplayName(NULL) << std::endl
20 << "Number of screens: " << ScreenCount(dpy) << std::endl
21 << "Default screen : " << DefaultScreen(dpy) << std::endl
22 << "Protocol Version : " << ProtocolVersion(dpy) << std::endl
23 << "Protocol Revision: " << ProtocolRevision(dpy) << std::endl
24 << "Server Vendor : " << ServerVendor(dpy) << std::endl
25 << "Vendor Release : " << VendorRelease(dpy) << std::endl
26 << std::endl
27 << "Display width : " << this->display_width() << std::endl
28 << "Display height : " << this->display_height() << std::endl
29 ;
31 App::BitMap * icon = new App::BitMap("xlib_App.xbm");
33 // Create the main window
34 create_window("main",
35 0, 0 ,
36 this->display_width()/2, this->display_height()/2,
37 icon);
39 // Get a reference to our WindowData structure. We need the Window handle from it for a few things.
40 App::WindowData * wd = windows["main"];
45 // We need to set the window manager hints, size hints, window name, and icon name
47 // Even though we are not passing any actual size_hints, the Xlib programming manual says to pass the flags below anyway.
48 XSizeHints *size_hints;
49 if (!(size_hints = XAllocSizeHints()))
50 {
51 std::cerr << "XAllocSizeHints: memory allocation failure" << std::endl;
52 exit(1);
53 }
54 size_hints->flags = PPosition | PSize;
56 // Get X Properties for the window and icon names.
57 XTextProperty windowName, iconName;
58 const char * ptr = appname.c_str();
59 if (XStringListToTextProperty(const_cast<char **>(&ptr), 1, &windowName) == 0)
60 {
61 std::cerr << "XStringListToTextProperty: structure allocation for windowName failed." << std::endl;;
62 exit(1);
63 }
64 ptr = icon->name.c_str();
65 if (XStringListToTextProperty(const_cast<char **>(&ptr), 1, &iconName) == 0)
66 {
67 std::cerr << "XStringListToTextProperty: structure allocation for iconName failed." << std::endl;;
68 exit(1);
69 }
71 XWMHints *wm_hints;
72 if (!(wm_hints = XAllocWMHints()))
73 {
74 std::cerr << "XAllocWMHints: memory allocation failure" << std::endl;
75 exit(0);
76 }
77 wm_hints->initial_state = NormalState;
78 wm_hints->input = True;
79 wm_hints->icon_pixmap = icon->pixmap;
80 wm_hints->flags = StateHint | IconPixmapHint | InputHint;
82 XSetWMProperties(dpy, wd->win, &windowName, &iconName,
83 NULL, 0, size_hints, wm_hints,
84 NULL);
88 // Select the event types we want to receive.
89 //Other interesting events include KeyReleaseMask and ButtonReleaseMask
90 event_mask = ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask ;
91 XSelectInput(dpy, wd->win, event_mask);
95 // Make sure we get delete events from the window manager.
96 // "wm_delete_window" is the Atom which corresponds to the delete
97 // window message sent by the window manager.
99 wm_delete_window = XInternAtom (dpy, "WM_DELETE_WINDOW", False);
100 XSetWMProtocols(dpy, wd->win, &wm_delete_window, 1);
103 // This give BadMatch and I don't know why.
104 // XSetWindowAttributes setwinattr;
105 // setwinattr.background_pixmap = bg_pixmap->pixmap;
106 // XChangeWindowAttributes(dpy, wd->win, CWBackPixmap, &setwinattr);
108 // Also BadMatch
109 // XSetWindowBackgroundPixmap(dpy, wd->win, icon->pixmap);
112 // XSetWindowBackgroundPixmap(dpy, wd->win, None);
115 // Map the window. Remember: this does not display the window immediately.
116 // The request is queued until events are read, or we call XFlush or XSync.
117 XMapWindow(dpy, wd->win);
118 }
120 ////////////////////////////////////////////////////////////////////////////////
121 App::~App()
122 {
123 // Ugh. I really wish I could figure out why I can't make a map of string
124 // to WindowData instead of having ton use WindowData *
125 // I'd like to eliminate this next loop.
126 for( WindowMap::iterator i = windows.begin(); i != windows.end(); ++i)
127 {
128 App::WindowData * wp = (*i).second;
129 windows.erase(i);
130 delete wp;
131 }
133 if (dpy)
134 {
135 XCloseDisplay(dpy);
136 }
137 }
139 ////////////////////////////////////////////////////////////////////////////////
140 int App::x_error_handler(Display * dpy, XErrorEvent *err)
141 {
142 char err_msg[1024];
143 err_msg[0] = 0;
144 XGetErrorText(dpy, err->error_code, err_msg, 1024);
145 std::cerr << "X11 Error"<< std::endl
146 << " display : " << DisplayString(dpy) << std::endl
147 << " serial : " << err->serial << std::endl
148 << " error_code : " << (int) err->error_code << std::endl
149 << " request_code: " << (int) err->request_code << std::endl
150 << " minor_code : " << (int) err->minor_code << std::endl
151 << err_msg << std::endl;
152 return 0;
153 }
155 ////////////////////////////////////////////////////////////////////////////////
156 void App::create_window(const std::string & win_name,
157 int x, int y,
158 unsigned int width, unsigned int height,
159 App::BitMap * icon)
160 {
161 Window win;
162 int border_width = 4; /* Border four pixels wide */
164 int screen_num = DefaultScreen(dpy);
166 /* Create opaque window */
167 win = XCreateSimpleWindow(dpy,
168 RootWindow(dpy, screen_num),
169 x, y,
170 width, height,
171 border_width,
172 None, None);
173 // BlackPixel(dpy, screen_num),
174 // WhitePixel(dpy, screen_num));
176 icon->make_pixmap(dpy, win);
178 // Add it to the window list
179 App::WindowData * win_data = new App::WindowData(win_name, win, icon);
180 windows.insert(win_pair(win_name, win_data));
181 }
183 ////////////////////////////////////////////////////////////////////////////////
184 void App::run(void)
185 {
186 XEvent e;
187 KeySym k;
188 char key_buffer[8];
189 key_buffer[7] = 0;
190 XComposeStatus compose_status;
192 int done = 0;
194 while (!done)
195 {
196 while (XCheckIfEvent(dpy, &e,
197 // *sniff* My very first lambda function in C++
198 [&](Display * d, XEvent * e, XPointer a)->Bool { return True; },
199 NULL))
200 {
201 switch (e.type)
202 {
203 case Expose:
204 // We'll only redraw the entire window at a time, so unless this is
205 // the last contiguous expose, don't draw the window.
206 if (e.xexpose.count != 0)
207 break;
208 // Draw the window contents here
209 break;
210 case ClientMessage:
211 if ((Atom)e.xclient.data.l[0] == wm_delete_window)
212 done = 1;
213 break;
214 case ButtonPress:
215 case KeyPress:
216 XLookupString(&(e.xkey), key_buffer, 7, &k, &compose_status);
217 switch (k)
218 {
219 case XK_Escape:
220 case XK_q:
221 std::cout << "Goodbye!" << std::endl;
222 done = 1;
223 break;
224 default:
225 std::cout << "You typed " << key_buffer << std::endl;
226 break;
227 }
228 default:
229 break;
230 }
231 }
233 // Do idle time things here
235 }
236 }
238 ////////////////////////////////////////////////////////////////////////////////
239 // App::BitMap
240 ////////////////////////////////////////////////////////////////////////////////
241 App::BitMap::BitMap(const std::string & file)
242 {
243 read_from_file(file);
244 }
246 ////////////////////////////////////////////////////////////////////////////////
247 App::BitMap::~BitMap()
248 {
249 if (data) { XFree(data); data = NULL; }
250 }
252 ////////////////////////////////////////////////////////////////////////////////
253 void App::BitMap::make_pixmap(Display * dpy, Drawable d)
254 {
255 pixmap = XCreateBitmapFromData(dpy, d, (char *) data, width, height);
256 }
258 ////////////////////////////////////////////////////////////////////////////////
259 int App::BitMap::read_from_file(const std::string & file)
260 {
261 if (BitmapSuccess != XReadBitmapFileData(file.c_str(), &width, &height, &data, NULL, NULL))
262 {
263 return 0;
264 }
266 name = file;
267 size_t p = name.rfind("/");
268 if (p != std::string::npos)
269 {
270 name.replace(0, p+1, "");
271 }
272 return 1;
273 }