view src/X11App.cpp @ 10:60f59a6159ed

Dropped an unneeded header
author Eris Caffee <discordia@eldalin.com>
date Sun, 22 Apr 2012 01:32:14 -0500
parents 8769ee69bd05
children
line source
1 #include "X11App.h"
3 #include <cstdlib>
4 #include <iostream>
5 #include <X11/Xutil.h>
7 ////////////////////////////////////////////////////////////////////////////////
8 // X11Window
9 ////////////////////////////////////////////////////////////////////////////////
10 X11Window::X11Window(Display * dpy,
11 const std::string & win_name,
12 int x, int y,
13 unsigned int width, unsigned int height) :
14 name (win_name),
15 win (0)
16 {
17 int screen_num = DefaultScreen(dpy);
19 win = XCreateSimpleWindow(dpy,
20 RootWindow(dpy, screen_num),
21 x, y,
22 width, height,
23 1,
24 None, None);
26 }
28 ////////////////////////////////////////////////////////////////////////////////
29 // X11App
30 ////////////////////////////////////////////////////////////////////////////////
31 X11App::X11App(const std::string & appname) :
32 main_win (NULL), dpy (NULL), event_mask (0), wm_delete_window (0)
33 {
35 if ((dpy = XOpenDisplay(NULL)) == NULL)
36 {
37 std::cerr << "Unable to connect to display " << XDisplayName(NULL) << std::endl;
38 exit(1);
39 }
40 std::cout << "Display name : " << XDisplayName(NULL) << std::endl
41 << "Number of screens: " << ScreenCount(dpy) << std::endl
42 << "Default screen : " << DefaultScreen(dpy) << std::endl
43 << "Protocol Version : " << ProtocolVersion(dpy) << std::endl
44 << "Protocol Revision: " << ProtocolRevision(dpy) << std::endl
45 << "Server Vendor : " << ServerVendor(dpy) << std::endl
46 << "Vendor Release : " << VendorRelease(dpy) << std::endl
47 << std::endl
48 << "Display width : " << DisplayWidth(dpy, DefaultScreen(dpy)) << std::endl
49 << "Display height : " << DisplayHeight(dpy, DefaultScreen(dpy)) << std::endl
50 ;
52 // Create the main window
53 main_win = new X11Window(dpy, "main", 0, 0,
54 DisplayWidth(dpy, DefaultScreen(dpy)) / 2,
55 DisplayHeight(dpy, DefaultScreen(dpy)) / 2);
58 // We need to set the window manager hints, size hints, and window name.
60 // Even though we are not passing any actual size_hints, the Xlib programming manual says to pass the flags below anyway.
61 XSizeHints *size_hints;
62 if (!(size_hints = XAllocSizeHints()))
63 {
64 std::cerr << "XAllocSizeHints: memory allocation failure" << std::endl;
65 exit(1);
66 }
67 size_hints->flags = PPosition | PSize;
70 // Get X Properties for the window name.
71 XTextProperty windowName;
72 const char * ptr = appname.c_str();
73 if (XStringListToTextProperty(const_cast<char **>(&ptr), 1, &windowName) == 0)
74 {
75 std::cerr << "XStringListToTextProperty: structure allocation for windowName failed." << std::endl;;
76 exit(1);
77 }
79 XWMHints *wm_hints;
80 if (!(wm_hints = XAllocWMHints()))
81 {
82 std::cerr << "XAllocWMHints: memory allocation failure" << std::endl;
83 exit(0);
84 }
85 wm_hints->initial_state = NormalState;
86 wm_hints->input = True;
87 wm_hints->flags = StateHint | InputHint;
89 XSetWMProperties(dpy, main_win->win, &windowName, NULL,
90 NULL, 0, size_hints, wm_hints,
91 NULL);
94 // Select the event types we want to receive.
95 event_mask =
96 ExposureMask | StructureNotifyMask |
97 KeyPressMask | KeyReleaseMask |
98 FocusChangeMask |
99 PointerMotionMask |
100 EnterWindowMask | LeaveWindowMask |
101 ButtonPressMask | ButtonReleaseMask ;
102 XSelectInput(dpy, main_win->win, event_mask);
105 // Make sure we get delete events from the window manager.
106 // "wm_delete_window" is the Atom which corresponds to the delete
107 // window message sent by the window manager.
109 wm_delete_window = XInternAtom (dpy, "WM_DELETE_WINDOW", False);
110 XSetWMProtocols(dpy, main_win->win, &wm_delete_window, 1);
113 // Map the window. Remember: this does not display the window immediately.
114 // The request is queued until events are read, or we call XFlush or XSync.
115 XMapWindow(dpy, main_win->win);
116 }
118 ////////////////////////////////////////////////////////////////////////////////
119 X11App::~X11App()
120 {
121 if (main_win) { delete main_win; }
122 if (dpy) { XCloseDisplay(dpy); }
123 }
125 ////////////////////////////////////////////////////////////////////////////////
126 void X11App::run(void)
127 {
128 XEvent e;
129 KeySym k;
130 char key_buffer[8];
131 key_buffer[7] = 0;
132 XComposeStatus compose_status;
134 int done = 0;
136 while (!done)
137 {
138 while (XCheckIfEvent(dpy, &e,
139 // *sniff* My very first lambda function in C++
140 [&](Display * d, XEvent * e, XPointer a)->Bool { return True; },
141 NULL))
142 {
143 switch (e.type)
144 {
146 ////////////////////////
147 // General window events
148 case Expose:
149 // We'll only redraw the entire window at a time, so unless this is
150 // the last contiguous expose, don't draw the window.
151 if (e.xexpose.count != 0)
152 break;
153 // Draw the window contents here
154 break;
155 case ClientMessage:
156 if ((Atom)e.xclient.data.l[0] == wm_delete_window)
157 done = 1;
158 break;
160 ///////////////////////
161 // Mouse events
162 case MotionNotify:
163 std::cout << "Mouse at (" << e.xmotion.x << "," << e.xmotion.y << ")" << std::endl;
164 break;
165 case ButtonPress:
166 std::cout << "You pressed button " << e.xbutton.button <<
167 " at (" << e.xbutton.x << "," << e.xbutton.y << ")" <<
168 " state " << button_state_string(e.xbutton.state ) << std::endl;
169 break;
170 case ButtonRelease:
171 std::cout << "You released button " << e.xbutton.button <<
172 " at (" << e.xbutton.x << "," << e.xbutton.y << ")" <<
173 " state " << button_state_string(e.xbutton.state ) << std::endl;
174 break;
175 case EnterNotify:
176 std::cout << "Mouse has entered the window" <<
177 " at (" << e.xbutton.x << "," << e.xbutton.y << ")" <<
178 " state " << button_state_string(e.xbutton.state ) << std::endl;
179 break;
180 case LeaveNotify:
181 std::cout << "Mouse has left the window" <<
182 " at (" << e.xbutton.x << "," << e.xbutton.y << ")" <<
183 " state " << button_state_string(e.xbutton.state ) << std::endl;
184 break;
186 //////////////////
187 // Keyboard Events
188 case FocusIn:
189 // Interesting note: When we regain focus due to a mouse click in the window,
190 // we first get a LeaveNotify, then the FocusIn, then an EnterNotify, and then
191 // the ButtonPress and ButtonRelease. So in a real app we might want to have
192 // the FocusIn handler read ahead and handle (discard) the next ButtonPress,
193 // and ButtonRelease so that the click does not have a real effect on the application.
194 std::cout << "Got keyboard focus" << std::endl;
195 break;
196 case FocusOut:
197 std::cout << "Lost keyboard focus" << std::endl;
198 break;
199 case KeyPress:
200 // Doing the lookup like this, using XLookupString, means I get the modified
201 // character back. Thus type shift+a gives me XK_A instead of XK_a
202 // If I used XKeySym I'd instead get a sequence such as this:
203 // XK_Shift_L followed by XK_a
204 //
205 // In the end, that might be a more useful way to go, but for now I'll keep
206 // things simple.
207 XLookupString(&(e.xkey), key_buffer, 7, &k, &compose_status);
208 switch (k)
209 {
210 case XK_Escape:
211 case XK_q:
212 std::cout << "Goodbye!" << std::endl;
213 done = 1;
214 break;
215 default:
216 std::cout << "You typed " << key_buffer << std::endl;
217 break;
218 }
219 case MappingNotify:
220 // While it is uncommon for the user to change the keyboard mapping while
221 // a program is running, handling this case is so trivial that there is
222 // simply no excuse to leave it out.
223 XRefreshKeyboardMapping((XMappingEvent *)&e);
224 break;
226 default:
227 break;
228 }
229 }
231 // Do idle time things here
233 }
234 }
236 ////////////////////////////////////////////////////////////////////////////////
237 std::string X11App::button_state_string(unsigned int state)
238 {
239 std::string str = "";
240 if (state & Button1Mask) { str.append("Button1 "); }
241 if (state & Button2Mask) { str.append("Button2 "); }
242 if (state & Button3Mask) { str.append("Button3 "); }
243 if (state & Button4Mask) { str.append("Button4 "); }
244 if (state & Button5Mask) { str.append("Button5 "); }
245 if (state & ShiftMask) { str.append("Shift "); }
246 if (state & LockMask) { str.append("Lock "); }
247 if (state & ControlMask) { str.append("Control "); }
248 if (state & Mod1Mask) { str.append("Mod1 "); }
249 if (state & Mod2Mask) { str.append("Mod2 "); }
250 if (state & Mod3Mask) { str.append("Mod3 "); }
251 if (state & Mod4Mask) { str.append("Mod4 "); }
252 if (state & Mod5Mask) { str.append("Mod5 "); }
253 size_t i = str.rfind(' ');
254 if (i != str.npos) { str.erase(i, 1); }
255 return str;
256 }