Added XInput event registration to XCB

This commit is contained in:
Jack Andersen 2015-05-11 23:38:37 -10:00
parent a66469b991
commit d0db7b080f
6 changed files with 194 additions and 47 deletions

View File

@ -77,7 +77,7 @@ public:
{(void)coord;(void)button;(void)mods;} {(void)coord;(void)button;(void)mods;}
virtual void mouseMove(const SWindowCoord& coord) virtual void mouseMove(const SWindowCoord& coord)
{(void)coord;} {(void)coord;}
virtual void scroll(const SScrollDelta& scroll) virtual void scroll(const SWindowCoord& coord, const SScrollDelta& scroll)
{(void)scroll;} {(void)scroll;}
virtual void touchDown(const SWindowCoord& coord, uintptr_t tid) virtual void touchDown(const SWindowCoord& coord, uintptr_t tid)

View File

@ -1,9 +1,13 @@
CONFIG -= Qt CONFIG -= Qt
CONFIG += console QT =
LIBS -= -lQtGui -lQtCore
#CONFIG += console
#QMAKE_CXXFLAGS -= -std=c++0x #QMAKE_CXXFLAGS -= -std=c++0x
#CONFIG += c++11 #CONFIG += c++11
unix:QMAKE_CXXFLAGS += -std=c++11 -stdlib=libc++ unix:QMAKE_CXXFLAGS += -std=c++11 -stdlib=libc++
unix:LIBS += -std=c++11 -stdlib=libc++ -lc++abi -lxcb -lxcb-glx -lxcb-xkb -lxcb-keysyms -lxkbcommon -lxkbcommon-x11 unix:LIBS += -std=c++11 -stdlib=libc++ -lc++abi -lxcb \
-lxcb-glx -lxcb-xkb -lxcb-xinput -lxcb-keysyms \
-lxkbcommon -lxkbcommon-x11
win32:LIBS += Setupapi.lib winusb.lib User32.lib /SUBSYSTEM:Windows win32:LIBS += Setupapi.lib winusb.lib User32.lib /SUBSYSTEM:Windows

View File

@ -9,15 +9,25 @@
#include <xcb/xcb_event.h> #include <xcb/xcb_event.h>
#include <xkbcommon/xkbcommon-x11.h> #include <xkbcommon/xkbcommon-x11.h>
#include <xcb/xkb.h> #include <xcb/xkb.h>
#include <xcb/xinput.h>
#undef explicit #undef explicit
namespace boo namespace boo
{ {
int XINPUT_OPCODE = 0;
static xcb_window_t getWindowOfEvent(xcb_generic_event_t* event, bool& windowEvent) static xcb_window_t getWindowOfEvent(xcb_generic_event_t* event, bool& windowEvent)
{ {
switch (XCB_EVENT_RESPONSE_TYPE(event)) switch (XCB_EVENT_RESPONSE_TYPE(event))
{ {
case XCB_CLIENT_MESSAGE:
{
xcb_client_message_event_t* ev = (xcb_client_message_event_t*)event;
windowEvent = true;
return ev->window;
}
case XCB_EXPOSE: case XCB_EXPOSE:
{ {
xcb_expose_event_t* ev = (xcb_expose_event_t*)event; xcb_expose_event_t* ev = (xcb_expose_event_t*)event;
@ -34,31 +44,56 @@ static xcb_window_t getWindowOfEvent(xcb_generic_event_t* event, bool& windowEve
{ {
xcb_key_press_event_t* ev = (xcb_key_press_event_t*)event; xcb_key_press_event_t* ev = (xcb_key_press_event_t*)event;
windowEvent = true; windowEvent = true;
return ev->root; return ev->event;
} }
case XCB_KEY_RELEASE: case XCB_KEY_RELEASE:
{ {
xcb_key_release_event_t* ev = (xcb_key_release_event_t*)event; xcb_key_release_event_t* ev = (xcb_key_release_event_t*)event;
windowEvent = true; windowEvent = true;
return ev->root; return ev->event;
} }
case XCB_BUTTON_PRESS: case XCB_BUTTON_PRESS:
{ {
xcb_button_press_event_t* ev = (xcb_button_press_event_t*)event; xcb_button_press_event_t* ev = (xcb_button_press_event_t*)event;
windowEvent = true; windowEvent = true;
return ev->root; return ev->event;
} }
case XCB_BUTTON_RELEASE: case XCB_BUTTON_RELEASE:
{ {
xcb_button_release_event_t* ev = (xcb_button_release_event_t*)event; xcb_button_release_event_t* ev = (xcb_button_release_event_t*)event;
windowEvent = true; windowEvent = true;
return ev->root; return ev->event;
} }
case XCB_MOTION_NOTIFY: case XCB_MOTION_NOTIFY:
{ {
xcb_motion_notify_event_t* ev = (xcb_motion_notify_event_t*)event; xcb_motion_notify_event_t* ev = (xcb_motion_notify_event_t*)event;
windowEvent = true; windowEvent = true;
return ev->root; return ev->event;
}
case XCB_GE_GENERIC:
{
xcb_ge_event_t* gev = (xcb_ge_event_t*)event;
if (gev->pad0 == XINPUT_OPCODE)
{
fprintf(stderr, "INPUTEVENT\n");
return 0;
switch (XCB_EVENT_RESPONSE_TYPE(gev))
{
case XCB_INPUT_DEVICE_CHANGED:
{
xcb_input_device_changed_event_t* ev = (xcb_input_device_changed_event_t*)event;
return 0;
}
case XCB_INPUT_DEVICE_MOTION_NOTIFY:
{
xcb_input_device_motion_notify_event_t* ev = (xcb_input_device_motion_notify_event_t*)event;
windowEvent = true;
return ev->event;
}
default:
return 0;
}
}
} }
default: default:
windowEvent = false; windowEvent = false;
@ -108,6 +143,10 @@ public:
xcb_xkb_per_client_flags(m_xcbConn, XCB_XKB_ID_USE_CORE_KBD, xcb_xkb_per_client_flags(m_xcbConn, XCB_XKB_ID_USE_CORE_KBD,
XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT, XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT, 0, 0, 0); XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT, 0, 0, 0);
} }
~CApplicationXCB() ~CApplicationXCB()
@ -125,6 +164,7 @@ public:
xcb_generic_event_t* event; xcb_generic_event_t* event;
m_running = true; m_running = true;
m_callback.appLaunched(this); m_callback.appLaunched(this);
xcb_flush(m_xcbConn);
while (m_running && (event = xcb_wait_for_event(m_xcbConn))) while (m_running && (event = xcb_wait_for_event(m_xcbConn)))
{ {
bool windowEvent; bool windowEvent;
@ -132,9 +172,9 @@ public:
fprintf(stderr, "EVENT %d\n", XCB_EVENT_RESPONSE_TYPE(event)); fprintf(stderr, "EVENT %d\n", XCB_EVENT_RESPONSE_TYPE(event));
if (windowEvent) if (windowEvent)
{ {
IWindow* window = m_windows[evWindow]; auto window = m_windows.find(evWindow);
if (window) if (window != m_windows.end())
window->_incomingEvent(event); window->second->_incomingEvent(event);
} }
free(event); free(event);
} }

View File

@ -2,6 +2,7 @@
#include "inputdev/CDeviceFinder.hpp" #include "inputdev/CDeviceFinder.hpp"
#include <libudev.h> #include <libudev.h>
#include <string.h> #include <string.h>
#include <signal.h>
#include <thread> #include <thread>
namespace boo namespace boo
@ -165,6 +166,8 @@ public:
~CHIDListenerUdev() ~CHIDListenerUdev()
{ {
m_udevRunning = false; m_udevRunning = false;
//raise(SIGINT);
pthread_kill(m_udevThread->native_handle(), SIGINT);
m_udevThread->join(); m_udevThread->join();
delete m_udevThread; delete m_udevThread;
udev_monitor_unref(m_udevMon); udev_monitor_unref(m_udevMon);

View File

@ -7,8 +7,10 @@
#include <xcb/xproto.h> #include <xcb/xproto.h>
#include <xcb/xcb_keysyms.h> #include <xcb/xcb_keysyms.h>
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#include <xcb/xinput.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
#include <string.h> #include <string.h>
#define XK_MISCELLANY #define XK_MISCELLANY
@ -77,46 +79,50 @@ static int translateModifiers(unsigned state)
return retval; return retval;
} }
static int translateButton(unsigned state) static int translateButton(unsigned detail)
{ {
int retval = 0; int retval = 0;
if (state & XCB_BUTTON_MASK_1) if (detail == 1)
retval = IWindowCallback::BUTTON_PRIMARY; retval = IWindowCallback::BUTTON_PRIMARY;
else if (state & XCB_BUTTON_MASK_2) else if (detail == 3)
retval = IWindowCallback::BUTTON_SECONDARY; retval = IWindowCallback::BUTTON_SECONDARY;
else if (state & XCB_BUTTON_MASK_3) else if (detail == 2)
retval = IWindowCallback::BUTTON_MIDDLE; retval = IWindowCallback::BUTTON_MIDDLE;
else if (state & XCB_BUTTON_MASK_4) else if (detail == 8)
retval = IWindowCallback::BUTTON_AUX1; retval = IWindowCallback::BUTTON_AUX1;
else if (state & XCB_BUTTON_MASK_5) else if (detail == 9)
retval = IWindowCallback::BUTTON_AUX2; retval =
IWindowCallback::BUTTON_AUX2;
return retval; return retval;
} }
#define INTERN_ATOM(var, conn, name) \ #define INTERN_ATOM(var, conn, name, if_exists) \
do {\ do {\
xcb_intern_atom_cookie_t cookie = \ xcb_intern_atom_cookie_t cookie = \
xcb_intern_atom(conn, 0, sizeof(#name), #name); \ xcb_intern_atom(conn, if_exists, sizeof(#name), #name); \
xcb_intern_atom_reply_t* reply = \ xcb_intern_atom_reply_t* reply = \
xcb_intern_atom_reply(conn, cookie, NULL); \ xcb_intern_atom_reply(conn, cookie, NULL); \
var = reply->atom; \ var = reply->atom; \
free(reply); \ /*free(reply);*/ \
} while(0) } while(0)
struct SXCBAtoms struct SXCBAtoms
{ {
xcb_atom_t m_wmProtocols = 0;
xcb_atom_t m_wmDeleteWindow = 0;
xcb_atom_t m_netwmState = 0; xcb_atom_t m_netwmState = 0;
xcb_atom_t m_netwmStateFullscreen = 0; xcb_atom_t m_netwmStateFullscreen = 0;
xcb_atom_t m_netwmStateAdd = 0; xcb_atom_t m_netwmStateAdd = 0;
xcb_atom_t m_netwmStateRemove = 0; xcb_atom_t m_netwmStateRemove = 0;
xcb_atom_t m_
xcb_key_symbols_t* m_keySyms = NULL; xcb_key_symbols_t* m_keySyms = NULL;
SXCBAtoms(xcb_connection_t* conn) SXCBAtoms(xcb_connection_t* conn)
{ {
INTERN_ATOM(m_netwmState, conn, _NET_WM_STATE); INTERN_ATOM(m_wmProtocols, conn, WM_PROTOCOLS, 1);
INTERN_ATOM(m_netwmStateFullscreen, conn, _NET_WM_STATE_FULLSCREEN); INTERN_ATOM(m_wmDeleteWindow, conn, WM_DELETE_WINDOW, 1);
INTERN_ATOM(m_netwmStateAdd, conn, _NET_WM_STATE_ADD); INTERN_ATOM(m_netwmState, conn, _NET_WM_STATE, 0);
INTERN_ATOM(m_netwmStateRemove, conn, _NET_WM_STATE_REMOVE); INTERN_ATOM(m_netwmStateFullscreen, conn, _NET_WM_STATE_FULLSCREEN, 0);
INTERN_ATOM(m_netwmStateAdd, conn, _NET_WM_STATE_ADD, 0);
INTERN_ATOM(m_netwmStateRemove, conn, _NET_WM_STATE_REMOVE, 0);
m_keySyms = xcb_key_symbols_alloc(conn); m_keySyms = xcb_key_symbols_alloc(conn);
} }
}; };
@ -138,7 +144,6 @@ IGraphicsContext* _CGraphicsContextXCBNew(IGraphicsContext::EGraphicsAPI api,
class CWindowXCB final : public IWindow class CWindowXCB final : public IWindow
{ {
xcb_connection_t* m_xcbConn; xcb_connection_t* m_xcbConn;
xcb_window_t m_windowId; xcb_window_t m_windowId;
IGraphicsContext* m_gfxCtx; IGraphicsContext* m_gfxCtx;
@ -164,7 +169,6 @@ public:
uint32_t visualId; uint32_t visualId;
m_gfxCtx = _CGraphicsContextXCBNew(IGraphicsContext::API_OPENGL_3_3, this, m_xcbConn, visualId); m_gfxCtx = _CGraphicsContextXCBNew(IGraphicsContext::API_OPENGL_3_3, this, m_xcbConn, visualId);
/* Create colormap */ /* Create colormap */
xcb_colormap_t colormap = xcb_generate_id(m_xcbConn); xcb_colormap_t colormap = xcb_generate_id(m_xcbConn);
xcb_create_colormap(m_xcbConn, XCB_COLORMAP_ALLOC_NONE, xcb_create_colormap(m_xcbConn, XCB_COLORMAP_ALLOC_NONE,
@ -179,7 +183,7 @@ public:
XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE |
XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE |
XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_EXPOSURE |
XCB_EVENT_MASK_STRUCTURE_NOTIFY | 0xFFFFFF, XCB_EVENT_MASK_STRUCTURE_NOTIFY,
colormap, colormap,
XCB_NONE XCB_NONE
}; };
@ -190,6 +194,27 @@ public:
XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP, XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP,
valueMasks); valueMasks);
/* The XInput extension enables per-pixel smooth scrolling trackpads */
struct
{
xcb_input_event_mask_t mask;
uint32_t maskVal;
} masks =
{
{XCB_INPUT_DEVICE_ALL_MASTER, 1},
XCB_INPUT_XI_EVENT_MASK_MOTION
};
xcb_input_xi_select_events(m_xcbConn, m_windowId, 1, &masks.mask);
xcb_change_property(m_xcbConn, XCB_PROP_MODE_REPLACE, m_windowId, S_ATOMS->m_wmProtocols,
XCB_ATOM_ATOM, 32, 1, &S_ATOMS->m_wmDeleteWindow);
const xcb_atom_t wm_protocols[1] = {
S_ATOMS->m_wmDeleteWindow,
};
xcb_change_property(m_xcbConn, XCB_PROP_MODE_REPLACE, m_windowId,
S_ATOMS->m_wmProtocols, 4,
32, 1, wm_protocols);
/* Set the title of the window */ /* Set the title of the window */
const char* c_title = title.c_str(); const char* c_title = title.c_str();
xcb_change_property(m_xcbConn, XCB_PROP_MODE_REPLACE, m_windowId, xcb_change_property(m_xcbConn, XCB_PROP_MODE_REPLACE, m_windowId,
@ -203,8 +228,9 @@ public:
/* Initialize context */ /* Initialize context */
xcb_map_window(m_xcbConn, m_windowId); xcb_map_window(m_xcbConn, m_windowId);
m_gfxCtx->initializeContext(); xcb_flush(m_xcbConn);
m_gfxCtx->initializeContext();
} }
~CWindowXCB() ~CWindowXCB()
@ -323,7 +349,6 @@ public:
XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_STRUCTURE_NOTIFY |
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
(const char*)&fsEvent); (const char*)&fsEvent);
} }
uintptr_t getPlatformHandle() const uintptr_t getPlatformHandle() const
@ -336,6 +361,14 @@ public:
xcb_generic_event_t* event = (xcb_generic_event_t*)e; xcb_generic_event_t* event = (xcb_generic_event_t*)e;
switch (XCB_EVENT_RESPONSE_TYPE(event)) switch (XCB_EVENT_RESPONSE_TYPE(event))
{ {
case XCB_CLIENT_MESSAGE:
{
xcb_client_message_event_t* ev = (xcb_client_message_event_t*)event;
if (ev->data.data32[0] == S_ATOMS->m_wmDeleteWindow)
{
fprintf(stderr, "CLOSED\n");
}
}
case XCB_EXPOSE: case XCB_EXPOSE:
{ {
xcb_expose_event_t* ev = (xcb_expose_event_t*)event; xcb_expose_event_t* ev = (xcb_expose_event_t*)event;
@ -347,11 +380,14 @@ public:
case XCB_CONFIGURE_NOTIFY: case XCB_CONFIGURE_NOTIFY:
{ {
xcb_configure_notify_event_t* ev = (xcb_configure_notify_event_t*)event; xcb_configure_notify_event_t* ev = (xcb_configure_notify_event_t*)event;
if (ev->width && ev->height)
{
m_wx = ev->x; m_wx = ev->x;
m_wy = ev->y; m_wy = ev->y;
m_ww = ev->width; m_ww = ev->width;
m_wh = ev->height; m_wh = ev->height;
} }
}
case XCB_KEY_PRESS: case XCB_KEY_PRESS:
{ {
xcb_key_press_event_t* ev = (xcb_key_press_event_t*)event; xcb_key_press_event_t* ev = (xcb_key_press_event_t*)event;
@ -395,15 +431,15 @@ public:
case XCB_BUTTON_PRESS: case XCB_BUTTON_PRESS:
{ {
xcb_button_press_event_t* ev = (xcb_button_press_event_t*)event; xcb_button_press_event_t* ev = (xcb_button_press_event_t*)event;
int button = translateButton(ev->state); int button = translateButton(ev->detail);
if (m_callback && button) if (m_callback && button)
{ {
int modifierMask = translateModifiers(ev->state); int modifierMask = translateModifiers(ev->state);
IWindowCallback::SWindowCoord coord = IWindowCallback::SWindowCoord coord =
{ {
{(unsigned)ev->root_x, (unsigned)ev->root_y}, {(unsigned)ev->event_x, (unsigned)ev->event_y},
{(unsigned)(ev->root_x / m_pixelFactor), (unsigned)(ev->root_y / m_pixelFactor)}, {(unsigned)(ev->event_x / m_pixelFactor), (unsigned)(ev->event_y / m_pixelFactor)},
{ev->root_x / (float)m_ww, ev->root_y / (float)m_wh} {ev->event_x / (float)m_ww, ev->event_y / (float)m_wh}
}; };
m_callback->mouseDown(coord, (IWindowCallback::EMouseButton)button, m_callback->mouseDown(coord, (IWindowCallback::EMouseButton)button,
(IWindowCallback::EModifierKey)modifierMask); (IWindowCallback::EModifierKey)modifierMask);
@ -412,15 +448,15 @@ public:
case XCB_BUTTON_RELEASE: case XCB_BUTTON_RELEASE:
{ {
xcb_button_release_event_t* ev = (xcb_button_release_event_t*)event; xcb_button_release_event_t* ev = (xcb_button_release_event_t*)event;
int button = translateButton(ev->state); int button = translateButton(ev->detail);
if (m_callback && button) if (m_callback && button)
{ {
int modifierMask = translateModifiers(ev->state); int modifierMask = translateModifiers(ev->state);
IWindowCallback::SWindowCoord coord = IWindowCallback::SWindowCoord coord =
{ {
{(unsigned)ev->root_x, (unsigned)ev->root_y}, {(unsigned)ev->event_x, (unsigned)ev->event_y},
{(unsigned)(ev->root_x / m_pixelFactor), (unsigned)(ev->root_y / m_pixelFactor)}, {(unsigned)(ev->event_x / m_pixelFactor), (unsigned)(ev->event_y / m_pixelFactor)},
{ev->root_x / (float)m_ww, ev->root_y / (float)m_wh} {ev->event_x / (float)m_ww, ev->event_y / (float)m_wh}
}; };
m_callback->mouseUp(coord, (IWindowCallback::EMouseButton)button, m_callback->mouseUp(coord, (IWindowCallback::EMouseButton)button,
(IWindowCallback::EModifierKey)modifierMask); (IWindowCallback::EModifierKey)modifierMask);
@ -433,9 +469,9 @@ public:
{ {
IWindowCallback::SWindowCoord coord = IWindowCallback::SWindowCoord coord =
{ {
{(unsigned)ev->root_x, (unsigned)ev->root_y}, {(unsigned)ev->event_x, (unsigned)ev->event_y},
{(unsigned)(ev->root_x / m_pixelFactor), (unsigned)(ev->root_y / m_pixelFactor)}, {(unsigned)(ev->event_x / m_pixelFactor), (unsigned)(ev->event_y / m_pixelFactor)},
{ev->root_x / (float)m_ww, ev->root_y / (float)m_wh} {ev->event_x / (float)m_ww, ev->event_y / (float)m_wh}
}; };
m_callback->mouseMove(coord); m_callback->mouseMove(coord);
} }

View File

@ -46,13 +46,76 @@ public:
}; };
struct CTestWindowCallback : public IWindowCallback
{
void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods)
{
fprintf(stderr, "Mouse Down %d (%f,%f)\n", button, coord.norm[0], coord.norm[1]);
}
void mouseUp(const SWindowCoord& coord, EMouseButton button, EModifierKey mods)
{
fprintf(stderr, "Mouse Up %d (%f,%f)\n", button, coord.norm[0], coord.norm[1]);
}
void mouseMove(const SWindowCoord& coord)
{
//fprintf(stderr, "Mouse Move (%f,%f)\n", coord.norm[0], coord.norm[1]);
}
void scroll(const SWindowCoord& coord, const SScrollDelta& scroll)
{
fprintf(stderr, "Mouse Move (%f,%f)\n", coord.norm[0], coord.norm[1]);
}
void touchDown(const SWindowCoord& coord, uintptr_t tid)
{
}
void touchUp(const SWindowCoord& coord, uintptr_t tid)
{
}
void touchMove(const SWindowCoord& coord, uintptr_t tid)
{
}
void charKeyDown(unsigned long charCode, EModifierKey mods, bool isRepeat)
{
}
void charKeyUp(unsigned long charCode, EModifierKey mods)
{
}
void specialKeyDown(ESpecialKey key, EModifierKey mods, bool isRepeat)
{
}
void specialKeyUp(ESpecialKey key, EModifierKey mods)
{
}
void modKeyDown(EModifierKey mod, bool isRepeat)
{
}
void modKeyUp(EModifierKey mod)
{
}
};
struct CTestApplicationCallback : public IApplicationCallback struct CTestApplicationCallback : public IApplicationCallback
{ {
IWindow* mainWindow = NULL; IWindow* mainWindow = NULL;
boo::CTestDeviceFinder devFinder; boo::CTestDeviceFinder devFinder;
CTestWindowCallback windowCallback;
void appLaunched(IApplication* app) void appLaunched(IApplication* app)
{ {
mainWindow = app->newWindow("YAY!"); mainWindow = app->newWindow("YAY!");
mainWindow->setCallback(&windowCallback);
mainWindow->showWindow(); mainWindow->showWindow();
devFinder.startScanning(); devFinder.startScanning();
} }
@ -75,6 +138,7 @@ int main(int argc, char** argv)
boo::IApplication* app = IApplicationBootstrap(boo::IApplication::PLAT_AUTO, appCb, "RWK", argc, argv); boo::IApplication* app = IApplicationBootstrap(boo::IApplication::PLAT_AUTO, appCb, "RWK", argc, argv);
app->run(); app->run();
delete app; delete app;
printf("IM DYING!!\n");
return 0; return 0;
} }