00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "Kernel/OVR_System.h"
00017 #include "Kernel/OVR_Array.h"
00018 #include "Kernel/OVR_String.h"
00019 #include "Kernel/OVR_Timer.h"
00020
00021 #include "Linux_Platform.h"
00022 #include "Linux_Gamepad.h"
00023
00024
00025 #include "../Render/Render_GL_Device.h"
00026
00027 #include <X11/extensions/Xinerama.h>
00028
00029
00030 namespace OVR { namespace Platform { namespace Linux {
00031
00032 static const char *AtomNames[] = {"WM_PROTOCOLS", "WM_DELETE_WINDOW"};
00033
00034 PlatformCore::PlatformCore(Application* app)
00035 : Platform::PlatformCore(app), Disp(NULL), Win(0), Vis(NULL), Quit(0), MMode(Mouse_Normal)
00036 {
00037 pGamepadManager = *new Linux::GamepadManager();
00038 }
00039 PlatformCore::~PlatformCore()
00040 {
00041 XFreeCursor(Disp, InvisibleCursor);
00042
00043 if (Disp)
00044 XCloseDisplay(Disp);
00045 }
00046
00047
00048 bool PlatformCore::SetupWindow(int w, int h)
00049 {
00050
00051 if (!Disp)
00052 {
00053 XInitThreads();
00054
00055 Disp = XOpenDisplay(NULL);
00056 if (!Disp)
00057 {
00058 OVR_DEBUG_LOG(("XOpenDisplay failed."));
00059 return false;
00060 }
00061
00062 XInternAtoms(Disp, const_cast<char**>(AtomNames), NumAtoms, false, Atoms);
00063 }
00064
00065 XSetWindowAttributes winattr;
00066 unsigned attrmask = CWEventMask | CWBorderPixel;
00067
00068 winattr.event_mask = ButtonPressMask|ButtonReleaseMask|KeyPressMask|KeyReleaseMask|ButtonMotionMask|PointerMotionMask|
00069 StructureNotifyMask;
00070 winattr.border_pixel = 0;
00071
00072 int screenNumber = DefaultScreen(Disp);
00073
00074 if (!Vis)
00075 {
00076 int attr[16];
00077 int nattr = 2;
00078
00079 attr[0] = GLX_RGBA;
00080 attr[1] = GLX_DOUBLEBUFFER;
00081 attr[nattr++] = GLX_DEPTH_SIZE;
00082 attr[nattr++] = 24;
00083 attr[nattr] = 0;
00084
00085 Vis = glXChooseVisual(Disp, screenNumber, attr);
00086
00087 if (!Vis)
00088 {
00089 OVR_DEBUG_LOG(("glXChooseVisual failed."));
00090 return false;
00091 }
00092 }
00093
00094 Window rootWindow = XRootWindow(Disp, Vis->screen);
00095
00096 winattr.colormap = XCreateColormap(Disp, rootWindow, Vis->visual, AllocNone);
00097 attrmask |= CWColormap;
00098
00099
00100 Win = XCreateWindow(Disp, rootWindow, 0, 0, w, h, 0, Vis->depth,
00101 InputOutput, Vis->visual, attrmask, &winattr);
00102
00103 if (!Win)
00104 {
00105 OVR_DEBUG_LOG(("XCreateWindow failed."));
00106 return false;
00107 }
00108
00109
00110 XStoreName(Disp, Win, "OVR App");
00111 XSetWMProtocols(Disp, Win, &Atoms[WM_DELETE_WINDOW], 1);
00112
00113
00114 XColor black;
00115 static char noData[] = { 0,0,0,0,0,0,0,0 };
00116 black.red = black.green = black.blue = 0;
00117
00118 Pixmap bitmapNoData = XCreateBitmapFromData(Disp, Win, noData, 8, 8);
00119 InvisibleCursor = XCreatePixmapCursor(Disp, bitmapNoData, bitmapNoData,
00120 &black, &black, 0, 0);
00121 XDefineCursor(Disp, Win, InvisibleCursor);
00122
00123 Width = w;
00124 Height = h;
00125
00126 return true;
00127 }
00128
00129 void PlatformCore::SetMouseMode(MouseMode mm)
00130 {
00131 if (mm == MMode)
00132 return;
00133
00134 if (Win)
00135 {
00136 if (mm == Mouse_Relative)
00137 {
00138 XWarpPointer(Disp, Win, Win, 0,0,Width,Height, Width/2, Height/2);
00139 }
00140 else
00141 {
00142
00143
00144 }
00145 }
00146 MMode = mm;
00147 }
00148
00149 void PlatformCore::GetWindowSize(int* w, int* h) const
00150 {
00151 *w = Width;
00152 *h = Height;
00153 }
00154
00155 void PlatformCore::SetWindowTitle(const char* title)
00156 {
00157 XStoreName(Disp, Win, title);
00158 }
00159
00160 void PlatformCore::ShowWindow(bool show)
00161 {
00162 if (show)
00163 XRaiseWindow(Disp, Win);
00164 else
00165 XIconifyWindow(Disp, Win, 0);
00166 }
00167
00168 void PlatformCore::DestroyWindow()
00169 {
00170 if (Win)
00171 XDestroyWindow(Disp, Win);
00172 Win = 0;
00173 }
00174
00175
00176 static int KeyMap[][2] =
00177 {
00178 { XK_BackSpace, Key_Backspace },
00179 { XK_Tab, Key_Tab },
00180 { XK_Clear, Key_Clear },
00181 { XK_Return, Key_Return },
00182 { XK_Shift_L, Key_Shift },
00183 { XK_Control_L, Key_Control },
00184 { XK_Alt_L, Key_Alt },
00185 { XK_Shift_R, Key_Shift },
00186 { XK_Control_R, Key_Control },
00187 { XK_Alt_R, Key_Alt },
00188 { XK_Pause, Key_Pause },
00189 { XK_Caps_Lock, Key_CapsLock },
00190 { XK_Escape, Key_Escape },
00191 { XK_space, Key_Space },
00192 { XK_Page_Up, Key_PageUp },
00193 { XK_Page_Down, Key_PageDown },
00194 { XK_Prior, Key_PageUp },
00195 { XK_Next, Key_PageDown },
00196 { XK_End, Key_End },
00197 { XK_Home, Key_Home },
00198 { XK_Left, Key_Left },
00199 { XK_Up, Key_Up },
00200 { XK_Right, Key_Right },
00201 { XK_Down, Key_Down },
00202 { XK_Insert, Key_Insert },
00203 { XK_Delete, Key_Delete },
00204 { XK_Help, Key_Help },
00205 { XK_Num_Lock, Key_NumLock },
00206 { XK_Scroll_Lock, Key_ScrollLock },
00207 };
00208
00209
00210 static KeyCode MapXKToKeyCode(unsigned vk)
00211 {
00212 unsigned key = Key_None;
00213
00214 if ((vk >= 'a') && (vk <= 'z'))
00215 {
00216 key = vk - 'a' + Key_A;
00217 }
00218 else if ((vk >= ' ') && (vk <= '~'))
00219 {
00220 key = vk;
00221 }
00222 else if ((vk >= XK_KP_0) && (vk <= XK_KP_9))
00223 {
00224 key = vk - XK_KP_0 + Key_KP_0;
00225 }
00226 else if ((vk >= XK_F1) && (vk <= XK_F15))
00227 {
00228 key = vk - XK_F1 + Key_F1;
00229 }
00230 else
00231 {
00232 for (unsigned i = 0; i< (sizeof(KeyMap) / sizeof(KeyMap[1])); i++)
00233 {
00234 if (vk == KeyMap[i][0])
00235 {
00236 key = KeyMap[i][1];
00237 break;
00238 }
00239 }
00240 }
00241
00242 return (KeyCode)key;
00243 }
00244
00245 static int MapModifiers(int xmod)
00246 {
00247 int mod = 0;
00248 if (xmod & ShiftMask)
00249 mod |= Mod_Shift;
00250 if (xmod & ControlMask)
00251 mod |= Mod_Control;
00252 if (xmod & Mod1Mask)
00253 mod |= Mod_Alt;
00254 if (xmod & Mod4Mask)
00255 mod |= Mod_Meta;
00256 return mod;
00257 }
00258
00259 void PlatformCore::processEvent(XEvent& event)
00260 {
00261 switch (event.xany.type)
00262 {
00263 case ConfigureNotify:
00264 if (event.xconfigure.width != Width || event.xconfigure.height != Height)
00265 {
00266 Width = event.xconfigure.width;
00267 Height = event.xconfigure.height;
00268 pApp->OnResize(Width, Height);
00269
00270 if (pRender)
00271 pRender->SetWindowSize(Width, Height);
00272 }
00273 break;
00274
00275 case KeyPress:
00276 case KeyRelease:
00277 {
00278 char chars[8] = {0};
00279 KeySym xk;
00280 XComposeStatus comp;
00281 XLookupString(&event.xkey, chars, sizeof(chars), &xk, &comp);
00282 if (xk != XK_VoidSymbol)
00283 pApp->OnKey(MapXKToKeyCode((unsigned)xk), chars[0], event.xany.type == KeyPress, MapModifiers(event.xkey.state));
00284 if (xk == XK_Escape && MMode == Mouse_Relative)
00285 {
00286
00287 MMode = Mouse_RelativeEscaped;
00288 showCursor(true);
00289 }
00290 }
00291 break;
00292
00293 case MotionNotify:
00294 if (MMode == Mouse_Relative)
00295 {
00296 int dx = event.xmotion.x - Width/2;
00297 int dy = event.xmotion.y - Height/2;
00298
00299
00300 if (dx == 0 && dy == 0)
00301 break;
00302
00303 XWarpPointer(Disp, Win, Win, 0,0,Width,Height, Width/2, Height/2);
00304 pApp->OnMouseMove(dx, dy, Mod_MouseRelative|MapModifiers(event.xmotion.state));
00305 }
00306 else
00307 {
00308 pApp->OnMouseMove(event.xmotion.x, event.xmotion.y, MapModifiers(event.xmotion.state));
00309 }
00310 break;
00311
00312 case MapNotify:
00313 if (MMode == Mouse_Relative)
00314 {
00315 XWarpPointer(Disp, Win, Win, 0,0,Width,Height, Width/2, Height/2);
00316 showCursor(false);
00317 }
00318 break;
00319
00320 case ButtonPress:
00321 if (event.xbutton.button == 1)
00322 {
00323
00324
00325 if (MMode == Mouse_RelativeEscaped)
00326 {
00327 XWarpPointer(Disp, Win, Win, 0,0,Width,Height, Width/2, Height/2);
00328 showCursor(false);
00329 MMode = Mouse_Relative;
00330 }
00331 }
00332 break;
00333
00334 case FocusOut:
00335 if (MMode == Mouse_Relative)
00336 {
00337 MMode = Mouse_RelativeEscaped;
00338 showCursor(true);
00339 }
00340 break;
00341
00342 case ClientMessage:
00343 if (event.xclient.message_type == Atoms[WM_PROTOCOLS] &&
00344 Atom(event.xclient.data.l[0]) == Atoms[WM_DELETE_WINDOW])
00345 pApp->OnQuitRequest();
00346 break;
00347 }
00348 }
00349
00350 int PlatformCore::Run()
00351 {
00352 while (!Quit)
00353 {
00354 if (XPending(Disp))
00355 {
00356 XEvent event;
00357 XNextEvent(Disp, &event);
00358
00359 if (pApp && event.xany.window == Win)
00360 processEvent(event);
00361 }
00362 else
00363 {
00364 pApp->OnIdle();
00365 }
00366 }
00367
00368 return ExitCode;
00369 }
00370
00371 bool PlatformCore::determineScreenOffset(int screenId, int* screenOffsetX, int* screenOffsetY)
00372 {
00373 Display* display = XOpenDisplay(NULL);
00374
00375 bool foundScreen = false;
00376
00377 if (display)
00378 {
00379 int numberOfScreens;
00380 XineramaScreenInfo* screens = XineramaQueryScreens(display, &numberOfScreens);
00381
00382 if (screenId < numberOfScreens)
00383 {
00384 XineramaScreenInfo screenInfo = screens[screenId];
00385 *screenOffsetX = screenInfo.x_org;
00386 *screenOffsetY = screenInfo.y_org;
00387
00388 foundScreen = true;
00389 }
00390
00391 XFree(screens);
00392 }
00393
00394 return foundScreen;
00395 }
00396
00397 void PlatformCore::showWindowDecorations(bool show)
00398 {
00399
00400
00401 typedef struct WMHints
00402 {
00403 unsigned long flags;
00404 unsigned long functions;
00405 unsigned long decorations;
00406 long inputMode;
00407 unsigned long status;
00408 } Hints;
00409
00410 #define MWM_DECOR_ALL (1L << 0)
00411 #define MWM_DECOR_BORDER (1L << 1)
00412 #define MWM_DECOR_RESIZEH (1L << 2)
00413 #define MWM_DECOR_TITLE (1L << 3)
00414 #define MWM_DECOR_MENU (1L << 4)
00415 #define MWM_DECOR_MINIMIZE (1L << 5)
00416 #define MWM_DECOR_MAXIMIZE (1L << 6)
00417
00418 Atom property = XInternAtom(Disp, "_MOTIF_WM_HINTS", true);
00419
00420 Hints hints;
00421 hints.flags = 2;
00422
00423 if (show)
00424 {
00425 hints.decorations = MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MENU | MWM_DECOR_MINIMIZE | MWM_DECOR_MAXIMIZE;
00426 }
00427 else
00428 {
00429
00430 hints.decorations = 0;
00431 }
00432
00433 XChangeProperty(Disp,Win,property,property,32,PropModeReplace,(unsigned char *)&hints,5);
00434 }
00435
00436 bool PlatformCore::SetFullscreen(const Render::RendererParams& rp, int fullscreen)
00437 {
00438 if (rp.Fullscreen == Render::Display_Window && fullscreen == Render::Display_FakeFullscreen)
00439 {
00440
00441 int xOffset;
00442 int yOffset;
00443
00444 if (!determineScreenOffset(rp.Display.CgDisplayId, &xOffset, &yOffset))
00445 {
00446 return false;
00447 }
00448
00449 showWindowDecorations(false);
00450
00451 XMoveWindow(Disp, Win, xOffset, yOffset);
00452 XMapRaised(Disp, Win);
00453
00454 Platform::PlatformCore::SetFullscreen(rp, fullscreen);
00455 return true;
00456 }
00457 else if (rp.Fullscreen == Render::Display_FakeFullscreen && fullscreen == Render::Display_Window)
00458 {
00459
00460 showWindowDecorations(true);
00461
00462 XMoveWindow(Disp, Win, 0, 0);
00463 XMapRaised(Disp, Win);
00464
00465 Platform::PlatformCore::SetFullscreen(rp, fullscreen);
00466 return true;
00467 }
00468 else if (fullscreen == Render::Display_Fullscreen)
00469 {
00470 return false;
00471 }
00472 }
00473
00474 RenderDevice* PlatformCore::SetupGraphics(const SetupGraphicsDeviceSet& setupGraphicsDesc,
00475 const char* type, const Render::RendererParams& rp)
00476 {
00477 const SetupGraphicsDeviceSet* setupDesc = setupGraphicsDesc.PickSetupDevice(type);
00478 OVR_ASSERT(setupDesc);
00479
00480 pRender = *setupDesc->pCreateDevice(rp, this);
00481 if (pRender)
00482 pRender->SetWindowSize(Width, Height);
00483
00484 return pRender.GetPtr();
00485 }
00486
00487 void PlatformCore::showCursor(bool show)
00488 {
00489 if (show)
00490 {
00491 XUndefineCursor(Disp, Win);
00492 }
00493 else
00494 {
00495 XDefineCursor(Disp, Win, InvisibleCursor);
00496 }
00497 }
00498
00499 }}
00500
00501
00502 namespace Render { namespace GL { namespace Linux {
00503
00504 Render::RenderDevice* RenderDevice::CreateDevice(const RendererParams& rp, void* oswnd)
00505 {
00506 Platform::Linux::PlatformCore* PC = (Platform::Linux::PlatformCore*)oswnd;
00507
00508 GLXContext context = glXCreateContext(PC->Disp, PC->Vis, 0, GL_TRUE);
00509
00510 if (!context)
00511 return NULL;
00512
00513 if (!glXMakeCurrent(PC->Disp, PC->Win, context))
00514 {
00515 glXDestroyContext(PC->Disp, context);
00516 return NULL;
00517 }
00518
00519 XMapRaised(PC->Disp, PC->Win);
00520
00521 return new Render::GL::Linux::RenderDevice(rp, PC->Disp, PC->Win, context);
00522 }
00523
00524 void RenderDevice::Present()
00525 {
00526 glXSwapBuffers(Disp, Win);
00527 }
00528
00529 void RenderDevice::Shutdown()
00530 {
00531 if (Context)
00532 {
00533 glXMakeCurrent(Disp, 0, NULL);
00534 glXDestroyContext(Disp, Context);
00535 Context = NULL;
00536 Win = 0;
00537 }
00538 }
00539
00540 }}}}
00541
00542
00543 int main(int argc, const char* argv[])
00544 {
00545 using namespace OVR;
00546 using namespace OVR::Platform;
00547
00548
00549 Application* app = Application::CreateApplication();
00550 Linux::PlatformCore* platform = new Linux::PlatformCore(app);
00551
00552 app->SetPlatformCore(platform);
00553
00554 int exitCode = app->OnStartup(argc, argv);
00555 if (!exitCode)
00556 exitCode = platform->Run();
00557
00558
00559 Application::DestroyApplication(app);
00560 app = 0;
00561
00562 return exitCode;
00563 }