#include <stdio.h>
#include <Xlib.h>
#include <Xutil.h>
#include <X11/keysym.h>
#include <unordered_map>
#include <vector>
#include <string>
//
// References:
// http://stackoverflow.com/questions/18246848/get-utf-8-input-with-x11-display
//
//
class XWindow
{
public:
XWindow(Display* a_dpy, Window a_win) : m_dpy(a_dpy), m_win(a_win) {}
~XWindow() { XDestroyWindow(m_dpy, m_win); }
void Show() {
// KeymapStateMask ??
// ButtonReleaseMask ??
XSelectInput(m_dpy, m_win, StructureNotifyMask | ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask);
XMapWindow(m_dpy, m_win);
//GC gc = XCreateGC(display, window, valuemask, 0);
m_im = XOpenIM(m_dpy, NULL, NULL, NULL);
XIMStyles *styles;
XGetIMValues(m_im, XNQueryInputStyle, &styles, NULL);
m_ic = XCreateIC(m_im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, m_win, NULL);
XSetICFocus(m_ic);
}
void HandleKeyEvent(XEvent& a_event) {
KeySym keysym;
char buf[128] = {};
int len = Xutf8LookupString(m_ic, &a_event.xkey, buf, sizeof(buf), &keysym, NULL);
printf("got keys: %i %i %i %s\n", buf[0], buf[1], buf[2], buf);
if (keysym == XK_Escape) {
printf("got ESC event\n");
XCloseDisplay(m_dpy);
}
}
void HandleExposeEvent(XEvent& a_event) {
int screen = DefaultScreen(m_dpy);
XSetForeground(m_dpy, DefaultGC(m_dpy, screen), WhitePixel(m_dpy, screen));
XFillRectangle(m_dpy, m_win, DefaultGC(m_dpy, screen), 0, 0, m_width, m_height);
XSetForeground(m_dpy, DefaultGC(m_dpy, screen), BlackPixel(m_dpy, screen));
int y_off = 20;
XDrawString(m_dpy, m_win, DefaultGC(m_dpy, screen), 10, y_off, "test", 4);
}
void HandleResizeEvent(XEvent& a_event) {
if (m_width != a_event.xconfigure.width || m_height != a_event.xconfigure.height) {
m_width = a_event.xconfigure.width;
m_height = a_event.xconfigure.height;
printf("Size changed to: %d by %d\n", m_width, m_height);
}
}
private:
std::vector<std::string> m_testLinesOfText;
Display* m_dpy;
Window m_win;
XIM m_im;
XIC m_ic;
int m_width;
int m_height;
};
class XApplication
{
public:
XApplication();
~XApplication();
XWindow* CreateWindow(int a_x, int a_y, int a_w, int a_h);
XEvent* NextEvent();
bool ProcessEvents();
private:
Display* m_display;
int m_screen;
Window m_root;
Visual* m_visual;
XEvent m_event;
std::unordered_map<Window,XWindow*> m_windowMap;
};
XApplication::XApplication()
{
m_display = XOpenDisplay(0);
// XXX Should check m_display
m_screen = DefaultScreen(m_display);
m_root = RootWindow(m_display, m_screen);
m_visual = DefaultVisual(m_display, m_screen);
}
XApplication::~XApplication()
{
XCloseDisplay(m_display);
}
XWindow* XApplication::CreateWindow(int a_x, int a_y, int a_w, int a_h)
{
unsigned clss = 0;
unsigned long valuemask = 0;
int screen = DefaultScreen(m_display);
XSetWindowAttributes* attribs = 0;
//Window window = XCreateSimpleWindow(m_display, m_root,
Window window = XCreateWindow(m_display, m_root,
a_x, a_y, a_w, a_h,
//1, BlackPixel(m_display, screen), WhitePixel(m_display, screen));
5, 24, clss, m_visual, valuemask, attribs);
XWindow* win = new XWindow(m_display, window);
m_windowMap.insert(std::make_pair(window, win));
return win;
}
XEvent* XApplication::NextEvent()
{
XNextEvent(m_display, &m_event);
Window win = m_event.xany.window;
while (XFilterEvent(&m_event, win)) {
XNextEvent(m_display, &m_event);
win = m_event.xany.window;
}
XWindow* w = m_windowMap[win];
switch (m_event.type) {
case KeymapNotify:
// XRefreshKeyboardMapping(&ev.xmapping);
break;
case Expose: {
if (w)
w->HandleExposeEvent(m_event);
break;
}
case KeyPress: {
if (w)
w->HandleKeyEvent(m_event);
break;
}
case ClientMessage: {
break;
}
case ConfigureNotify:
if (w)
w->HandleResizeEvent(m_event);
break;
}
return &m_event;
}
bool XApplication::ProcessEvents()
{
while ( NextEvent() )
/* do nothing */;
return true;
}
int main(int argc, char *argv[])
{
XApplication app;
XWindow* win = app.CreateWindow(0, 0, 640, 480);
win->Show();
app.ProcessEvents();
//getchar();
delete win;
return 0;
}