Mercurial > xlib_App
changeset 9:8769ee69bd05
Simple X11App class is done.
author | Eris Caffee <discordia@eldalin.com> |
---|---|
date | Sun, 22 Apr 2012 01:25:33 -0500 |
parents | c5c33bf5f1fb |
children | 60f59a6159ed |
files | include/App.h include/X11App.h include/xlib_App.xbm src/App.cpp src/X11App.cpp src/main.cpp |
diffstat | 6 files changed, 303 insertions(+), 498 deletions(-) [+] |
line diff
1.1 --- a/include/App.h Sat Apr 21 03:40:26 2012 -0500 1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 1.3 @@ -1,94 +0,0 @@ 1.4 -#include <map> 1.5 -#include <string> 1.6 - 1.7 -#include <X11/Xlib.h> 1.8 - 1.9 -//////////////////////////////////////////////////////////////////////////////// 1.10 -class App 1.11 - { 1.12 - public: 1.13 - 1.14 - ///////////////////////////////////// 1.15 - class BitMap 1.16 - { 1.17 - public: 1.18 - BitMap(const std::string & file); 1.19 - ~BitMap(); 1.20 - 1.21 - void make_pixmap(Display * dpy, Drawable d); 1.22 - 1.23 - // Yeah, it's all public here. Keeping it simple. 1.24 - std::string name; 1.25 - unsigned int width; 1.26 - unsigned int height; 1.27 - unsigned char * data; 1.28 - Pixmap pixmap; 1.29 - 1.30 - private: 1.31 - BitMap(const App::BitMap & b); 1.32 - 1.33 - int read_from_file(const std::string & file); 1.34 - }; 1.35 - 1.36 - ///////////////////////////////////// 1.37 - // TODO: Need to be able to support child windows. 1.38 - // Thus, I need a tree and this class should be a node of the tree. 1.39 - // I could use an STL multimap container that maps child nodes onto parent nodes 1.40 - // The root node would need to be a bit special. Perhaps it would map to itself. 1.41 - // Use the equal_range() method to get the children of the specified node. 1.42 - // I would still need to implement my own tree walking methods: get root node, 1.43 - // for each child (get children and recurse). 1.44 - // 1.45 - // It may be more efficient to implement the tree directly instead of using 1.46 - // std::map as an intermediary. 1.47 - 1.48 - class WindowData 1.49 - { 1.50 - public: 1.51 - WindowData(const std::string & n, Window w, App::BitMap * i) : 1.52 - name(n), win(w), icon(i) {}; 1.53 - ~WindowData() 1.54 - { 1.55 - if (icon) { delete icon; icon = NULL; } 1.56 - } 1.57 - 1.58 - 1.59 - std::string name; 1.60 - Window win; 1.61 - App::BitMap * icon; 1.62 - }; 1.63 - 1.64 - ///////////////////////////////////// 1.65 - 1.66 - typedef std::pair<std::string, App::WindowData *> win_pair; 1.67 - typedef std::map<std::string, App::WindowData *> WindowMap; 1.68 - 1.69 - App(const std::string & appname); 1.70 - ~App(); 1.71 - 1.72 - static int x_error_handler(Display * dpy, XErrorEvent *err); 1.73 - 1.74 - void create_window(const std::string& win_name, 1.75 - int x, int y, 1.76 - unsigned int width, unsigned int height, 1.77 - App::BitMap * icon); 1.78 - 1.79 - inline int display_height(void) const 1.80 - { return DisplayHeight(dpy, DefaultScreen(dpy)); }; 1.81 - 1.82 - inline int display_width(void) const 1.83 - { return DisplayWidth(dpy, DefaultScreen(dpy)); }; 1.84 - 1.85 - void run(void); 1.86 - 1.87 - private: 1.88 - App(); 1.89 - App(const App & a); 1.90 - 1.91 - Display * dpy; 1.92 - WindowMap windows; 1.93 - long event_mask; 1.94 - Atom wm_delete_window; // Need this in contructor and run(). 1.95 - 1.96 - std::string button_state_string(unsigned int state) const; 1.97 - };
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/include/X11App.h Sun Apr 22 01:25:33 2012 -0500 2.3 @@ -0,0 +1,43 @@ 2.4 +#ifndef APP_H 2.5 +#define X11APP_H 2.6 + 2.7 +#include <string> 2.8 + 2.9 +#include <X11/Xlib.h> 2.10 + 2.11 +class X11Window 2.12 + { 2.13 + public: 2.14 + X11Window(Display * dpy, 2.15 + const std::string& win_name, 2.16 + int x, int y, 2.17 + unsigned int width, unsigned int height); 2.18 + 2.19 + std::string name; 2.20 + Window win; 2.21 + }; 2.22 + 2.23 +class X11App 2.24 + { 2.25 + public: 2.26 + 2.27 + X11App(const std::string & appname); 2.28 + ~X11App(); 2.29 + 2.30 + void run(void); 2.31 + 2.32 + private: 2.33 + X11App(); 2.34 + X11App(const X11App & a); 2.35 + X11App operator=(const X11App&); 2.36 + 2.37 + std::string button_state_string(unsigned int state); 2.38 + 2.39 + X11Window * main_win; 2.40 + Display * dpy; 2.41 + long event_mask; 2.42 + Atom wm_delete_window; 2.43 + 2.44 + }; 2.45 + 2.46 +#endif
3.1 --- a/include/xlib_App.xbm Sat Apr 21 03:40:26 2012 -0500 3.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 3.3 @@ -1,46 +0,0 @@ 3.4 -#define xlib_App_width 64 3.5 -#define xlib_App_height 64 3.6 -static unsigned char xlib_App_bits[] = { 3.7 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3.8 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3.9 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3.10 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3.11 - 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 3.12 - 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 3.13 - 0x80, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x10, 0x00, 0xc0, 0xff, 0x3f, 0x00, 3.14 - 0x00, 0x00, 0x3c, 0x00, 0xe0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x3e, 0x00, 3.15 - 0xf0, 0xff, 0x7f, 0x00, 0x00, 0x80, 0x1f, 0x00, 0xf0, 0xff, 0x7f, 0x00, 3.16 - 0x00, 0x80, 0x0f, 0x00, 0xf8, 0xff, 0xff, 0x00, 0x00, 0xc0, 0x07, 0x00, 3.17 - 0xfc, 0xff, 0xff, 0x01, 0x00, 0xe0, 0x03, 0x00, 0xfc, 0xf8, 0xff, 0x01, 3.18 - 0x00, 0xf0, 0x01, 0x00, 0x38, 0xf0, 0xff, 0x03, 0x00, 0xf8, 0x01, 0x00, 3.19 - 0x00, 0xe0, 0xff, 0x03, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x07, 3.20 - 0x00, 0x7c, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x3f, 0x00, 0x00, 3.21 - 0x00, 0x80, 0xff, 0x0f, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x80, 0xff, 0x1f, 3.22 - 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, 0xc0, 0x03, 0x00, 0x00, 3.23 - 0x00, 0x00, 0xff, 0x3f, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x3f, 3.24 - 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x7f, 0xf8, 0x00, 0x00, 0x00, 3.25 - 0x00, 0x00, 0xfc, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 3.26 - 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x3f, 0x00, 0x00, 0x00, 3.27 - 0x00, 0x00, 0xf0, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 3.28 - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x07, 0x00, 0x00, 0x00, 3.29 - 0x00, 0x00, 0xe0, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 3.30 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 3.31 - 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 3.32 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x01, 0x00, 0x00, 0x00, 3.33 - 0x00, 0x00, 0xe0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 3.34 - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0x00, 0x00, 3.35 - 0x00, 0x00, 0xfe, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 3.36 - 0x1f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xcf, 0xff, 0x7f, 0x00, 0x00, 0x00, 3.37 - 0x00, 0xe0, 0x87, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xf0, 0x03, 0xff, 3.38 - 0xff, 0x07, 0xe0, 0x00, 0x00, 0xfc, 0x00, 0xfe, 0xff, 0x1f, 0xf0, 0x00, 3.39 - 0x00, 0xfe, 0x00, 0xfc, 0xff, 0xff, 0x7c, 0x00, 0x00, 0x3f, 0x00, 0xf8, 3.40 - 0xff, 0xff, 0x7f, 0x00, 0x80, 0x1f, 0x00, 0xf8, 0xff, 0xff, 0x3f, 0x00, 3.41 - 0xc0, 0x0f, 0x00, 0xf0, 0xff, 0xff, 0x1f, 0x00, 0xe0, 0x03, 0x00, 0xe0, 3.42 - 0xff, 0xff, 0x0f, 0x00, 0xf0, 0x01, 0x00, 0xc0, 0xff, 0xff, 0x07, 0x00, 3.43 - 0xf0, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x03, 0x00, 0x40, 0x00, 0x00, 0xc0, 3.44 - 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, 3.45 - 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3.46 - 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3.47 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3.48 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3.49 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
4.1 --- a/src/App.cpp Sat Apr 21 03:40:26 2012 -0500 4.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 4.3 @@ -1,356 +0,0 @@ 4.4 -#include "App.h" 4.5 - 4.6 -#include <cstdlib> 4.7 -#include <iostream> 4.8 -#include <typeinfo> 4.9 -#include <X11/Xutil.h> 4.10 - 4.11 - 4.12 -//////////////////////////////////////////////////////////////////////////////// 4.13 -App::App(const std::string & appname) 4.14 - { 4.15 - XSetErrorHandler(&App::x_error_handler); 4.16 - 4.17 - if ((dpy = XOpenDisplay(NULL)) == NULL) 4.18 - { 4.19 - std::cerr << "Unable to connect to display " << XDisplayName(NULL) << std::endl; 4.20 - exit(1); 4.21 - } 4.22 - std::cout << "Display name : " << XDisplayName(NULL) << std::endl 4.23 - << "Number of screens: " << ScreenCount(dpy) << std::endl 4.24 - << "Default screen : " << DefaultScreen(dpy) << std::endl 4.25 - << "Protocol Version : " << ProtocolVersion(dpy) << std::endl 4.26 - << "Protocol Revision: " << ProtocolRevision(dpy) << std::endl 4.27 - << "Server Vendor : " << ServerVendor(dpy) << std::endl 4.28 - << "Vendor Release : " << VendorRelease(dpy) << std::endl 4.29 - << std::endl 4.30 - << "Display width : " << this->display_width() << std::endl 4.31 - << "Display height : " << this->display_height() << std::endl 4.32 - ; 4.33 - 4.34 - App::BitMap * icon = new App::BitMap("xlib_App.xbm"); 4.35 - 4.36 - // Create the main window 4.37 - create_window("main", 4.38 - 0, 0 , 4.39 - this->display_width()/2, this->display_height()/2, 4.40 - icon); 4.41 - 4.42 - // Get a reference to our WindowData structure. We need the Window handle from it for a few things. 4.43 - App::WindowData * wd = windows["main"]; 4.44 - 4.45 - 4.46 - 4.47 - 4.48 - // We need to set the window manager hints, size hints, window name, and icon name 4.49 - 4.50 - // Even though we are not passing any actual size_hints, the Xlib programming manual says to pass the flags below anyway. 4.51 - XSizeHints *size_hints; 4.52 - if (!(size_hints = XAllocSizeHints())) 4.53 - { 4.54 - std::cerr << "XAllocSizeHints: memory allocation failure" << std::endl; 4.55 - exit(1); 4.56 - } 4.57 - size_hints->flags = PPosition | PSize; 4.58 - 4.59 - // Get X Properties for the window and icon names. 4.60 - XTextProperty windowName, iconName; 4.61 - const char * ptr = appname.c_str(); 4.62 - if (XStringListToTextProperty(const_cast<char **>(&ptr), 1, &windowName) == 0) 4.63 - { 4.64 - std::cerr << "XStringListToTextProperty: structure allocation for windowName failed." << std::endl;; 4.65 - exit(1); 4.66 - } 4.67 - ptr = icon->name.c_str(); 4.68 - if (XStringListToTextProperty(const_cast<char **>(&ptr), 1, &iconName) == 0) 4.69 - { 4.70 - std::cerr << "XStringListToTextProperty: structure allocation for iconName failed." << std::endl;; 4.71 - exit(1); 4.72 - } 4.73 - 4.74 - XWMHints *wm_hints; 4.75 - if (!(wm_hints = XAllocWMHints())) 4.76 - { 4.77 - std::cerr << "XAllocWMHints: memory allocation failure" << std::endl; 4.78 - exit(0); 4.79 - } 4.80 - wm_hints->initial_state = NormalState; 4.81 - wm_hints->input = True; 4.82 - wm_hints->icon_pixmap = icon->pixmap; 4.83 - wm_hints->flags = StateHint | IconPixmapHint | InputHint; 4.84 - 4.85 - XSetWMProperties(dpy, wd->win, &windowName, &iconName, 4.86 - NULL, 0, size_hints, wm_hints, 4.87 - NULL); 4.88 - 4.89 - 4.90 - 4.91 - // Select the event types we want to receive. 4.92 - //Other interesting events include KeyReleaseMask and ButtonReleaseMask 4.93 - event_mask = 4.94 - ExposureMask | StructureNotifyMask | 4.95 - KeyPressMask | KeyReleaseMask | 4.96 - FocusChangeMask | 4.97 - PointerMotionMask | 4.98 - EnterWindowMask | LeaveWindowMask | 4.99 - ButtonPressMask | ButtonReleaseMask ; 4.100 - XSelectInput(dpy, wd->win, event_mask); 4.101 - 4.102 - 4.103 - 4.104 - // Make sure we get delete events from the window manager. 4.105 - // "wm_delete_window" is the Atom which corresponds to the delete 4.106 - // window message sent by the window manager. 4.107 - 4.108 - wm_delete_window = XInternAtom (dpy, "WM_DELETE_WINDOW", False); 4.109 - XSetWMProtocols(dpy, wd->win, &wm_delete_window, 1); 4.110 - 4.111 - 4.112 - // This give BadMatch and I don't know why. 4.113 - // XSetWindowAttributes setwinattr; 4.114 - // setwinattr.background_pixmap = bg_pixmap->pixmap; 4.115 - // XChangeWindowAttributes(dpy, wd->win, CWBackPixmap, &setwinattr); 4.116 - 4.117 - // Also BadMatch 4.118 - // XSetWindowBackgroundPixmap(dpy, wd->win, icon->pixmap); 4.119 - 4.120 - 4.121 - // XSetWindowBackgroundPixmap(dpy, wd->win, None); 4.122 - 4.123 - 4.124 - // Map the window. Remember: this does not display the window immediately. 4.125 - // The request is queued until events are read, or we call XFlush or XSync. 4.126 - XMapWindow(dpy, wd->win); 4.127 - } 4.128 - 4.129 -//////////////////////////////////////////////////////////////////////////////// 4.130 -App::~App() 4.131 - { 4.132 - // Ugh. I really wish I could figure out why I can't make a map of string 4.133 - // to WindowData instead of having ton use WindowData * 4.134 - // I'd like to eliminate this next loop. 4.135 - for( WindowMap::iterator i = windows.begin(); i != windows.end(); ++i) 4.136 - { 4.137 - App::WindowData * wp = (*i).second; 4.138 - windows.erase(i); 4.139 - delete wp; 4.140 - } 4.141 - 4.142 - if (dpy) 4.143 - { 4.144 - XCloseDisplay(dpy); 4.145 - } 4.146 - } 4.147 - 4.148 -//////////////////////////////////////////////////////////////////////////////// 4.149 -int App::x_error_handler(Display * dpy, XErrorEvent *err) 4.150 - { 4.151 - char err_msg[1024]; 4.152 - err_msg[0] = 0; 4.153 - XGetErrorText(dpy, err->error_code, err_msg, 1024); 4.154 - std::cerr << "X11 Error"<< std::endl 4.155 - << " display : " << DisplayString(dpy) << std::endl 4.156 - << " serial : " << err->serial << std::endl 4.157 - << " error_code : " << (int) err->error_code << std::endl 4.158 - << " request_code: " << (int) err->request_code << std::endl 4.159 - << " minor_code : " << (int) err->minor_code << std::endl 4.160 - << err_msg << std::endl; 4.161 - return 0; 4.162 - } 4.163 - 4.164 -//////////////////////////////////////////////////////////////////////////////// 4.165 -void App::create_window(const std::string & win_name, 4.166 - int x, int y, 4.167 - unsigned int width, unsigned int height, 4.168 - App::BitMap * icon) 4.169 - { 4.170 - Window win; 4.171 - int border_width = 4; /* Border four pixels wide */ 4.172 - 4.173 - int screen_num = DefaultScreen(dpy); 4.174 - 4.175 - /* Create opaque window */ 4.176 - win = XCreateSimpleWindow(dpy, 4.177 - RootWindow(dpy, screen_num), 4.178 - x, y, 4.179 - width, height, 4.180 - border_width, 4.181 - None, None); 4.182 - // BlackPixel(dpy, screen_num), 4.183 - // WhitePixel(dpy, screen_num)); 4.184 - 4.185 - icon->make_pixmap(dpy, win); 4.186 - 4.187 - // Add it to the window list 4.188 - App::WindowData * win_data = new App::WindowData(win_name, win, icon); 4.189 - windows.insert(win_pair(win_name, win_data)); 4.190 - } 4.191 - 4.192 -//////////////////////////////////////////////////////////////////////////////// 4.193 -void App::run(void) 4.194 - { 4.195 - XEvent e; 4.196 - KeySym k; 4.197 - char key_buffer[8]; 4.198 - key_buffer[7] = 0; 4.199 - XComposeStatus compose_status; 4.200 - 4.201 - int done = 0; 4.202 - 4.203 - while (!done) 4.204 - { 4.205 - while (XCheckIfEvent(dpy, &e, 4.206 - // *sniff* My very first lambda function in C++ 4.207 - [&](Display * d, XEvent * e, XPointer a)->Bool { return True; }, 4.208 - NULL)) 4.209 - { 4.210 - switch (e.type) 4.211 - { 4.212 - 4.213 - //////////////////////// 4.214 - // General window events 4.215 - case Expose: 4.216 - // We'll only redraw the entire window at a time, so unless this is 4.217 - // the last contiguous expose, don't draw the window. 4.218 - if (e.xexpose.count != 0) 4.219 - break; 4.220 - // Draw the window contents here 4.221 - break; 4.222 - case ClientMessage: 4.223 - if ((Atom)e.xclient.data.l[0] == wm_delete_window) 4.224 - done = 1; 4.225 - break; 4.226 - 4.227 - /////////////////////// 4.228 - // Mouse events 4.229 - case MotionNotify: 4.230 - std::cout << "Mouse at (" << e.xmotion.x << "," << e.xmotion.y << ")" << std::endl; 4.231 - break; 4.232 - case ButtonPress: 4.233 - std::cout << "You pressed button " << e.xbutton.button << 4.234 - " at (" << e.xbutton.x << "," << e.xbutton.y << ")" << 4.235 - " state " << button_state_string(e.xbutton.state ) << std::endl; 4.236 - break; 4.237 - case ButtonRelease: 4.238 - std::cout << "You released button " << e.xbutton.button << 4.239 - " at (" << e.xbutton.x << "," << e.xbutton.y << ")" << 4.240 - " state " << button_state_string(e.xbutton.state ) << std::endl; 4.241 - break; 4.242 - case EnterNotify: 4.243 - std::cout << "Mouse has entered the window" << 4.244 - " at (" << e.xbutton.x << "," << e.xbutton.y << ")" << 4.245 - " state " << button_state_string(e.xbutton.state ) << std::endl; 4.246 - break; 4.247 - case LeaveNotify: 4.248 - std::cout << "Mouse has left the window" << 4.249 - " at (" << e.xbutton.x << "," << e.xbutton.y << ")" << 4.250 - " state " << button_state_string(e.xbutton.state ) << std::endl; 4.251 - break; 4.252 - 4.253 - ////////////////// 4.254 - // Keyboard Events 4.255 - case FocusIn: 4.256 - // Interesting note: When we regain focus due to a mouse click in the window, 4.257 - // we first get a LeaveNotify, then the FocusIn, then an EnterNotify, and then 4.258 - // the ButtonPress and ButtonRelease. So in a real app we might want to have 4.259 - // the FocusIn handler read ahead and handle (discard) the next ButtonPress, 4.260 - // and ButtonRelease so that the click does not have a real effect on the application. 4.261 - std::cout << "Got keyboard focus" << std::endl; 4.262 - break; 4.263 - case FocusOut: 4.264 - std::cout << "Lost keyboard focus" << std::endl; 4.265 - break; 4.266 - case KeyPress: 4.267 - // Doing the lookup like this, using XLookupString, means I get the modified 4.268 - // character back. Thus type shift+a gives me XK_A instead of XK_a 4.269 - // If I used XKeySym I'd instead get a sequence such as this: 4.270 - // XK_Shift_L followed by XK_a 4.271 - // 4.272 - // In the end, that might be a more useful way to go, but for now I'll keep 4.273 - // things simple. 4.274 - XLookupString(&(e.xkey), key_buffer, 7, &k, &compose_status); 4.275 - switch (k) 4.276 - { 4.277 - case XK_Escape: 4.278 - case XK_q: 4.279 - std::cout << "Goodbye!" << std::endl; 4.280 - done = 1; 4.281 - break; 4.282 - default: 4.283 - std::cout << "You typed " << key_buffer << std::endl; 4.284 - break; 4.285 - } 4.286 - case MappingNotify: 4.287 - // While it is uncommon for the user to change the keyboard mapping while 4.288 - // a program is running, handling this case is so trivial that there is 4.289 - // simply no excuse to leave it out. 4.290 - XRefreshKeyboardMapping((XMappingEvent *)&e); 4.291 - break; 4.292 - 4.293 - default: 4.294 - break; 4.295 - } 4.296 - } 4.297 - 4.298 - // Do idle time things here 4.299 - 4.300 - } 4.301 - } 4.302 - 4.303 -//////////////////////////////////////////////////////////////////////////////// 4.304 -std::string App::button_state_string(unsigned int state) const 4.305 - { 4.306 - std::string str = ""; 4.307 - if (state & Button1Mask) { str.append("Button1 "); } 4.308 - if (state & Button2Mask) { str.append("Button2 "); } 4.309 - if (state & Button3Mask) { str.append("Button3 "); } 4.310 - if (state & Button4Mask) { str.append("Button4 "); } 4.311 - if (state & Button5Mask) { str.append("Button5 "); } 4.312 - if (state & ShiftMask) { str.append("Shift "); } 4.313 - if (state & LockMask) { str.append("Lock "); } 4.314 - if (state & ControlMask) { str.append("Control "); } 4.315 - if (state & Mod1Mask) { str.append("Mod1 "); } 4.316 - if (state & Mod2Mask) { str.append("Mod2 "); } 4.317 - if (state & Mod3Mask) { str.append("Mod3 "); } 4.318 - if (state & Mod4Mask) { str.append("Mod4 "); } 4.319 - if (state & Mod5Mask) { str.append("Mod5 "); } 4.320 - return str; 4.321 - } 4.322 - 4.323 -//////////////////////////////////////////////////////////////////////////////// 4.324 -// App::BitMap 4.325 -//////////////////////////////////////////////////////////////////////////////// 4.326 -App::BitMap::BitMap(const std::string & file) 4.327 - { 4.328 - read_from_file(file); 4.329 - } 4.330 - 4.331 -//////////////////////////////////////////////////////////////////////////////// 4.332 -App::BitMap::~BitMap() 4.333 - { 4.334 - if (data) { XFree(data); data = NULL; } 4.335 - } 4.336 - 4.337 -//////////////////////////////////////////////////////////////////////////////// 4.338 -void App::BitMap::make_pixmap(Display * dpy, Drawable d) 4.339 - { 4.340 - pixmap = XCreateBitmapFromData(dpy, d, (char *) data, width, height); 4.341 - } 4.342 - 4.343 -//////////////////////////////////////////////////////////////////////////////// 4.344 -int App::BitMap::read_from_file(const std::string & file) 4.345 - { 4.346 - if (BitmapSuccess != XReadBitmapFileData(file.c_str(), &width, &height, &data, NULL, NULL)) 4.347 - { 4.348 - return 0; 4.349 - } 4.350 - 4.351 - name = file; 4.352 - size_t p = name.rfind("/"); 4.353 - if (p != std::string::npos) 4.354 - { 4.355 - name.replace(0, p+1, ""); 4.356 - } 4.357 - return 1; 4.358 - } 4.359 -
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/X11App.cpp Sun Apr 22 01:25:33 2012 -0500 5.3 @@ -0,0 +1,258 @@ 5.4 +#include "X11App.h" 5.5 + 5.6 +#include <cstdlib> 5.7 +#include <iostream> 5.8 +#include <typeinfo> 5.9 +#include <X11/Xutil.h> 5.10 + 5.11 +//////////////////////////////////////////////////////////////////////////////// 5.12 +// X11Window 5.13 +//////////////////////////////////////////////////////////////////////////////// 5.14 +X11Window::X11Window(Display * dpy, 5.15 + const std::string & win_name, 5.16 + int x, int y, 5.17 + unsigned int width, unsigned int height) : 5.18 + name (win_name), 5.19 + win (0) 5.20 + { 5.21 + int screen_num = DefaultScreen(dpy); 5.22 + 5.23 + win = XCreateSimpleWindow(dpy, 5.24 + RootWindow(dpy, screen_num), 5.25 + x, y, 5.26 + width, height, 5.27 + 1, 5.28 + None, None); 5.29 + 5.30 + } 5.31 + 5.32 +//////////////////////////////////////////////////////////////////////////////// 5.33 +// X11App 5.34 +//////////////////////////////////////////////////////////////////////////////// 5.35 +X11App::X11App(const std::string & appname) : 5.36 + main_win (NULL), dpy (NULL), event_mask (0), wm_delete_window (0) 5.37 + { 5.38 + 5.39 + if ((dpy = XOpenDisplay(NULL)) == NULL) 5.40 + { 5.41 + std::cerr << "Unable to connect to display " << XDisplayName(NULL) << std::endl; 5.42 + exit(1); 5.43 + } 5.44 + std::cout << "Display name : " << XDisplayName(NULL) << std::endl 5.45 + << "Number of screens: " << ScreenCount(dpy) << std::endl 5.46 + << "Default screen : " << DefaultScreen(dpy) << std::endl 5.47 + << "Protocol Version : " << ProtocolVersion(dpy) << std::endl 5.48 + << "Protocol Revision: " << ProtocolRevision(dpy) << std::endl 5.49 + << "Server Vendor : " << ServerVendor(dpy) << std::endl 5.50 + << "Vendor Release : " << VendorRelease(dpy) << std::endl 5.51 + << std::endl 5.52 + << "Display width : " << DisplayWidth(dpy, DefaultScreen(dpy)) << std::endl 5.53 + << "Display height : " << DisplayHeight(dpy, DefaultScreen(dpy)) << std::endl 5.54 + ; 5.55 + 5.56 + // Create the main window 5.57 + main_win = new X11Window(dpy, "main", 0, 0, 5.58 + DisplayWidth(dpy, DefaultScreen(dpy)) / 2, 5.59 + DisplayHeight(dpy, DefaultScreen(dpy)) / 2); 5.60 + 5.61 + 5.62 + // We need to set the window manager hints, size hints, and window name. 5.63 + 5.64 + // Even though we are not passing any actual size_hints, the Xlib programming manual says to pass the flags below anyway. 5.65 + XSizeHints *size_hints; 5.66 + if (!(size_hints = XAllocSizeHints())) 5.67 + { 5.68 + std::cerr << "XAllocSizeHints: memory allocation failure" << std::endl; 5.69 + exit(1); 5.70 + } 5.71 + size_hints->flags = PPosition | PSize; 5.72 + 5.73 + 5.74 + // Get X Properties for the window name. 5.75 + XTextProperty windowName; 5.76 + const char * ptr = appname.c_str(); 5.77 + if (XStringListToTextProperty(const_cast<char **>(&ptr), 1, &windowName) == 0) 5.78 + { 5.79 + std::cerr << "XStringListToTextProperty: structure allocation for windowName failed." << std::endl;; 5.80 + exit(1); 5.81 + } 5.82 + 5.83 + XWMHints *wm_hints; 5.84 + if (!(wm_hints = XAllocWMHints())) 5.85 + { 5.86 + std::cerr << "XAllocWMHints: memory allocation failure" << std::endl; 5.87 + exit(0); 5.88 + } 5.89 + wm_hints->initial_state = NormalState; 5.90 + wm_hints->input = True; 5.91 + wm_hints->flags = StateHint | InputHint; 5.92 + 5.93 + XSetWMProperties(dpy, main_win->win, &windowName, NULL, 5.94 + NULL, 0, size_hints, wm_hints, 5.95 + NULL); 5.96 + 5.97 + 5.98 + // Select the event types we want to receive. 5.99 + event_mask = 5.100 + ExposureMask | StructureNotifyMask | 5.101 + KeyPressMask | KeyReleaseMask | 5.102 + FocusChangeMask | 5.103 + PointerMotionMask | 5.104 + EnterWindowMask | LeaveWindowMask | 5.105 + ButtonPressMask | ButtonReleaseMask ; 5.106 + XSelectInput(dpy, main_win->win, event_mask); 5.107 + 5.108 + 5.109 + // Make sure we get delete events from the window manager. 5.110 + // "wm_delete_window" is the Atom which corresponds to the delete 5.111 + // window message sent by the window manager. 5.112 + 5.113 + wm_delete_window = XInternAtom (dpy, "WM_DELETE_WINDOW", False); 5.114 + XSetWMProtocols(dpy, main_win->win, &wm_delete_window, 1); 5.115 + 5.116 + 5.117 + // Map the window. Remember: this does not display the window immediately. 5.118 + // The request is queued until events are read, or we call XFlush or XSync. 5.119 + XMapWindow(dpy, main_win->win); 5.120 + } 5.121 + 5.122 +//////////////////////////////////////////////////////////////////////////////// 5.123 +X11App::~X11App() 5.124 + { 5.125 + if (main_win) { delete main_win; } 5.126 + if (dpy) { XCloseDisplay(dpy); } 5.127 + } 5.128 + 5.129 +//////////////////////////////////////////////////////////////////////////////// 5.130 +void X11App::run(void) 5.131 + { 5.132 + XEvent e; 5.133 + KeySym k; 5.134 + char key_buffer[8]; 5.135 + key_buffer[7] = 0; 5.136 + XComposeStatus compose_status; 5.137 + 5.138 + int done = 0; 5.139 + 5.140 + while (!done) 5.141 + { 5.142 + while (XCheckIfEvent(dpy, &e, 5.143 + // *sniff* My very first lambda function in C++ 5.144 + [&](Display * d, XEvent * e, XPointer a)->Bool { return True; }, 5.145 + NULL)) 5.146 + { 5.147 + switch (e.type) 5.148 + { 5.149 + 5.150 + //////////////////////// 5.151 + // General window events 5.152 + case Expose: 5.153 + // We'll only redraw the entire window at a time, so unless this is 5.154 + // the last contiguous expose, don't draw the window. 5.155 + if (e.xexpose.count != 0) 5.156 + break; 5.157 + // Draw the window contents here 5.158 + break; 5.159 + case ClientMessage: 5.160 + if ((Atom)e.xclient.data.l[0] == wm_delete_window) 5.161 + done = 1; 5.162 + break; 5.163 + 5.164 + /////////////////////// 5.165 + // Mouse events 5.166 + case MotionNotify: 5.167 + std::cout << "Mouse at (" << e.xmotion.x << "," << e.xmotion.y << ")" << std::endl; 5.168 + break; 5.169 + case ButtonPress: 5.170 + std::cout << "You pressed button " << e.xbutton.button << 5.171 + " at (" << e.xbutton.x << "," << e.xbutton.y << ")" << 5.172 + " state " << button_state_string(e.xbutton.state ) << std::endl; 5.173 + break; 5.174 + case ButtonRelease: 5.175 + std::cout << "You released button " << e.xbutton.button << 5.176 + " at (" << e.xbutton.x << "," << e.xbutton.y << ")" << 5.177 + " state " << button_state_string(e.xbutton.state ) << std::endl; 5.178 + break; 5.179 + case EnterNotify: 5.180 + std::cout << "Mouse has entered the window" << 5.181 + " at (" << e.xbutton.x << "," << e.xbutton.y << ")" << 5.182 + " state " << button_state_string(e.xbutton.state ) << std::endl; 5.183 + break; 5.184 + case LeaveNotify: 5.185 + std::cout << "Mouse has left the window" << 5.186 + " at (" << e.xbutton.x << "," << e.xbutton.y << ")" << 5.187 + " state " << button_state_string(e.xbutton.state ) << std::endl; 5.188 + break; 5.189 + 5.190 + ////////////////// 5.191 + // Keyboard Events 5.192 + case FocusIn: 5.193 + // Interesting note: When we regain focus due to a mouse click in the window, 5.194 + // we first get a LeaveNotify, then the FocusIn, then an EnterNotify, and then 5.195 + // the ButtonPress and ButtonRelease. So in a real app we might want to have 5.196 + // the FocusIn handler read ahead and handle (discard) the next ButtonPress, 5.197 + // and ButtonRelease so that the click does not have a real effect on the application. 5.198 + std::cout << "Got keyboard focus" << std::endl; 5.199 + break; 5.200 + case FocusOut: 5.201 + std::cout << "Lost keyboard focus" << std::endl; 5.202 + break; 5.203 + case KeyPress: 5.204 + // Doing the lookup like this, using XLookupString, means I get the modified 5.205 + // character back. Thus type shift+a gives me XK_A instead of XK_a 5.206 + // If I used XKeySym I'd instead get a sequence such as this: 5.207 + // XK_Shift_L followed by XK_a 5.208 + // 5.209 + // In the end, that might be a more useful way to go, but for now I'll keep 5.210 + // things simple. 5.211 + XLookupString(&(e.xkey), key_buffer, 7, &k, &compose_status); 5.212 + switch (k) 5.213 + { 5.214 + case XK_Escape: 5.215 + case XK_q: 5.216 + std::cout << "Goodbye!" << std::endl; 5.217 + done = 1; 5.218 + break; 5.219 + default: 5.220 + std::cout << "You typed " << key_buffer << std::endl; 5.221 + break; 5.222 + } 5.223 + case MappingNotify: 5.224 + // While it is uncommon for the user to change the keyboard mapping while 5.225 + // a program is running, handling this case is so trivial that there is 5.226 + // simply no excuse to leave it out. 5.227 + XRefreshKeyboardMapping((XMappingEvent *)&e); 5.228 + break; 5.229 + 5.230 + default: 5.231 + break; 5.232 + } 5.233 + } 5.234 + 5.235 + // Do idle time things here 5.236 + 5.237 + } 5.238 + } 5.239 + 5.240 +//////////////////////////////////////////////////////////////////////////////// 5.241 +std::string X11App::button_state_string(unsigned int state) 5.242 + { 5.243 + std::string str = ""; 5.244 + if (state & Button1Mask) { str.append("Button1 "); } 5.245 + if (state & Button2Mask) { str.append("Button2 "); } 5.246 + if (state & Button3Mask) { str.append("Button3 "); } 5.247 + if (state & Button4Mask) { str.append("Button4 "); } 5.248 + if (state & Button5Mask) { str.append("Button5 "); } 5.249 + if (state & ShiftMask) { str.append("Shift "); } 5.250 + if (state & LockMask) { str.append("Lock "); } 5.251 + if (state & ControlMask) { str.append("Control "); } 5.252 + if (state & Mod1Mask) { str.append("Mod1 "); } 5.253 + if (state & Mod2Mask) { str.append("Mod2 "); } 5.254 + if (state & Mod3Mask) { str.append("Mod3 "); } 5.255 + if (state & Mod4Mask) { str.append("Mod4 "); } 5.256 + if (state & Mod5Mask) { str.append("Mod5 "); } 5.257 + size_t i = str.rfind(' '); 5.258 + if (i != str.npos) { str.erase(i, 1); } 5.259 + return str; 5.260 + } 5.261 +
6.1 --- a/src/main.cpp Sat Apr 21 03:40:26 2012 -0500 6.2 +++ b/src/main.cpp Sun Apr 22 01:25:33 2012 -0500 6.3 @@ -2,11 +2,11 @@ 6.4 6.5 #include <unistd.h> 6.6 6.7 -#include "App.h" 6.8 +#include "X11App.h" 6.9 6.10 int main(void) 6.11 { 6.12 - App * app = new App("xlib_App"); 6.13 + X11App * app = new X11App("xlib_App"); 6.14 app->run(); 6.15 exit(0); 6.16 }