| 
									
										
										
										
											2008-12-17 23:49:35 +00:00
										 |  |  | #include "X11Window.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | X11Window::X11Window(int _iwidth, int _iheight) { | 
					
						
							|  |  |  |     int _twidth,  _theight; | 
					
						
							|  |  |  |     if(g_Config.bFullscreen) { | 
					
						
							|  |  |  | 	if(strlen(g_Config.iFSResolution) > 1) { | 
					
						
							|  |  |  | 	    sscanf(g_Config.iFSResolution, "%dx%d", &_twidth, &_theight); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { // No full screen reso set, fall back to default {
 | 
					
						
							|  |  |  |             _twidth = _iwidth; | 
					
						
							|  |  |  |             _theight = _iheight; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else  {// Going Windowed
 | 
					
						
							|  |  |  |         if(strlen(g_Config.iWindowedRes) > 1) { | 
					
						
							|  |  |  | 	    sscanf(g_Config.iWindowedRes, "%dx%d", &_twidth, &_theight); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { // No Window reso set, fall back to default
 | 
					
						
							|  |  |  |             _twidth = _iwidth; | 
					
						
							|  |  |  |             _theight = _iheight; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     SetSize(_twidth, _theight); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-20 22:18:52 +00:00
										 |  |  |     float FactorW  = 640.0f / (float)_twidth; | 
					
						
							|  |  |  |     float FactorH  = 480.0f / (float)_theight; | 
					
						
							| 
									
										
										
										
											2008-12-17 23:49:35 +00:00
										 |  |  |     float Max = (FactorW < FactorH) ? FactorH : FactorW; | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     if(g_Config.bStretchToFit) { | 
					
						
							| 
									
										
										
										
											2008-12-21 21:02:43 +00:00
										 |  |  | 	SetMax(1.0f / FactorW, 1.0f / FactorH); | 
					
						
							| 
									
										
										
										
											2008-12-20 22:18:52 +00:00
										 |  |  | 	SetOffset(0,0); | 
					
						
							| 
									
										
										
										
											2008-12-17 23:49:35 +00:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2008-12-21 21:02:43 +00:00
										 |  |  | 	SetMax(1.0f / Max, 1.0f / Max); | 
					
						
							|  |  |  | 	SetOffset((int)((_twidth - (640 * GetXmax())) / 2), | 
					
						
							|  |  |  | 		  (int)((_theight - (480 * GetYmax())) / 2)); | 
					
						
							| 
									
										
										
										
											2008-12-17 23:49:35 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-12-20 22:18:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-17 23:49:35 +00:00
										 |  |  |     XVisualInfo *vi; | 
					
						
							|  |  |  |     Colormap cmap; | 
					
						
							|  |  |  |     int dpyWidth, dpyHeight; | 
					
						
							|  |  |  |     int glxMajorVersion, glxMinorVersion; | 
					
						
							|  |  |  |     int vidModeMajorVersion, vidModeMinorVersion; | 
					
						
							|  |  |  |     Atom wmDelete; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // attributes for a single buffered visual in RGBA format with at least
 | 
					
						
							|  |  |  |     // 8 bits per color and a 24 bit depth buffer
 | 
					
						
							|  |  |  |     int attrListSgl[] = {GLX_RGBA, GLX_RED_SIZE, 8,  | 
					
						
							|  |  |  |                          GLX_GREEN_SIZE, 8,  | 
					
						
							|  |  |  |                          GLX_BLUE_SIZE, 8,  | 
					
						
							|  |  |  |                          GLX_DEPTH_SIZE, 24, | 
					
						
							|  |  |  |                          None}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // attributes for a double buffered visual in RGBA format with at least 
 | 
					
						
							|  |  |  |     // 8 bits per color and a 24 bit depth buffer
 | 
					
						
							|  |  |  |     int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER,  | 
					
						
							|  |  |  |                           GLX_RED_SIZE, 8,  | 
					
						
							|  |  |  |                           GLX_GREEN_SIZE, 8,  | 
					
						
							|  |  |  |                           GLX_BLUE_SIZE, 8,  | 
					
						
							|  |  |  |                           GLX_DEPTH_SIZE, 24, | 
					
						
							| 
									
										
										
										
											2008-12-22 10:47:37 +00:00
										 |  |  |                           GLX_SAMPLE_BUFFERS_ARB,  | 
					
						
							|  |  |  | 			  g_Config.iMultisampleMode,  | 
					
						
							|  |  |  | 			  GLX_SAMPLES_ARB, 1, None }; | 
					
						
							| 
									
										
										
										
											2008-12-17 23:49:35 +00:00
										 |  |  |     dpy = XOpenDisplay(0); | 
					
						
							|  |  |  |     g_VideoInitialize.pWindowHandle = (HWND)dpy; | 
					
						
							|  |  |  |     screen = DefaultScreen(dpy); | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     fs = g_Config.bFullscreen; //Set to setting in Options
 | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     /* get an appropriate visual */ | 
					
						
							|  |  |  |     vi = glXChooseVisual(dpy, screen, attrListDbl); | 
					
						
							|  |  |  |     if (vi == NULL) { | 
					
						
							|  |  |  |         vi = glXChooseVisual(dpy, screen, attrListSgl); | 
					
						
							|  |  |  |         doubleBuffered = False; | 
					
						
							|  |  |  |         ERROR_LOG("Only Singlebuffered Visual!\n"); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         doubleBuffered = True; | 
					
						
							|  |  |  |         ERROR_LOG("Got Doublebuffered Visual!\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     glXQueryVersion(dpy, &glxMajorVersion, &glxMinorVersion); | 
					
						
							|  |  |  |     ERROR_LOG("glX-Version %d.%d\n", glxMajorVersion, glxMinorVersion); | 
					
						
							|  |  |  |     /* create a GLX context */ | 
					
						
							|  |  |  |     ctx = glXCreateContext(dpy, vi, 0, GL_TRUE); | 
					
						
							|  |  |  |     if(!ctx) { | 
					
						
							|  |  |  |         ERROR_LOG("Couldn't Create GLX context.Quit"); | 
					
						
							|  |  |  |         exit(0); // TODO: Don't bring down entire Emu
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* create a color map */ | 
					
						
							|  |  |  |     cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), | 
					
						
							|  |  |  |                            vi->visual, AllocNone); | 
					
						
							|  |  |  |     attr.colormap = cmap; | 
					
						
							|  |  |  |     attr.border_pixel = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // get a connection
 | 
					
						
							|  |  |  |     XF86VidModeQueryVersion(dpy, &vidModeMajorVersion, &vidModeMinorVersion); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (fs) { | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         XF86VidModeModeInfo **modes = NULL; | 
					
						
							|  |  |  |         int modeNum = 0; | 
					
						
							|  |  |  |         int bestMode = 0; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  |         // set best mode to current
 | 
					
						
							|  |  |  |         bestMode = 0; | 
					
						
							|  |  |  |         ERROR_LOG("XF86VidModeExtension-Version %d.%d\n", vidModeMajorVersion, vidModeMinorVersion); | 
					
						
							|  |  |  |         XF86VidModeGetAllModeLines(dpy, screen, &modeNum, &modes); | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         if (modeNum > 0 && modes != NULL) { | 
					
						
							|  |  |  |             /* save desktop-resolution before switching modes */ | 
					
						
							|  |  |  |             deskMode = *modes[0]; | 
					
						
							|  |  |  |             /* look for mode with requested resolution */ | 
					
						
							|  |  |  |             for (int i = 0; i < modeNum; i++) { | 
					
						
							|  |  |  |                 if ((modes[i]->hdisplay == _twidth) &&  | 
					
						
							|  |  |  | 		    (modes[i]->vdisplay == _theight)) { | 
					
						
							|  |  |  |                     bestMode = i; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }     | 
					
						
							|  |  |  | 	     | 
					
						
							|  |  |  |             XF86VidModeSwitchToMode(dpy, screen, modes[bestMode]); | 
					
						
							|  |  |  |             XF86VidModeSetViewPort(dpy, screen, 0, 0); | 
					
						
							|  |  |  |             dpyWidth = modes[bestMode]->hdisplay; | 
					
						
							|  |  |  |             dpyHeight = modes[bestMode]->vdisplay; | 
					
						
							|  |  |  |             ERROR_LOG("Resolution %dx%d\n", dpyWidth, dpyHeight); | 
					
						
							|  |  |  |             XFree(modes); | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             /* create a fullscreen window */ | 
					
						
							|  |  |  |             attr.override_redirect = True; | 
					
						
							|  |  |  |             attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask |  | 
					
						
							|  |  |  | 		KeyReleaseMask | ButtonReleaseMask | StructureNotifyMask; | 
					
						
							|  |  |  |             win = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 0, 0,  | 
					
						
							|  |  |  | 				dpyWidth, dpyHeight, 0, vi->depth, InputOutput, | 
					
						
							|  |  |  | 				vi->visual, CWBorderPixel | CWColormap |  | 
					
						
							|  |  |  | 				CWEventMask | CWOverrideRedirect, &attr); | 
					
						
							|  |  |  |             XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0); | 
					
						
							|  |  |  |             XMapRaised(dpy, win); | 
					
						
							|  |  |  |             XGrabKeyboard(dpy, win, True, GrabModeAsync,  | 
					
						
							|  |  |  | 			  GrabModeAsync, CurrentTime); | 
					
						
							|  |  |  |             XGrabPointer(dpy, win, True, ButtonPressMask, | 
					
						
							|  |  |  |                          GrabModeAsync, GrabModeAsync, win, None, CurrentTime); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             ERROR_LOG("Failed to start fullscreen. If you received the \n" | 
					
						
							|  |  |  |                       "\"XFree86-VidModeExtension\" extension is missing, add\n" | 
					
						
							|  |  |  |                       "Load \"extmod\"\n" | 
					
						
							|  |  |  |                       "to your X configuration file (under the Module Section)\n"); | 
					
						
							|  |  |  |             fs = 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     if (!fs) { | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  |         // create a window in window mode
 | 
					
						
							|  |  |  |         attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask |  | 
					
						
							|  |  |  | 	    KeyReleaseMask | ButtonReleaseMask | | 
					
						
							|  |  |  |             StructureNotifyMask  | ResizeRedirectMask; | 
					
						
							|  |  |  |         win = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 0, 0, _twidth,  | 
					
						
							|  |  |  | 			    _theight, 0, vi->depth, InputOutput, vi->visual, | 
					
						
							|  |  |  | 			    CWBorderPixel | CWColormap | CWEventMask, &attr); | 
					
						
							|  |  |  |         // only set window title and handle wm_delete_events if in windowed mode
 | 
					
						
							|  |  |  |         wmDelete = XInternAtom(dpy, "WM_DELETE_WINDOW", True); | 
					
						
							|  |  |  |         XSetWMProtocols(dpy, win, &wmDelete, 1); | 
					
						
							|  |  |  |         XSetStandardProperties(dpy, win, "GPU", | 
					
						
							|  |  |  | 			       "GPU", None, NULL, 0, NULL); | 
					
						
							|  |  |  |         XMapRaised(dpy, win); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | X11Window::~X11Window() { | 
					
						
							|  |  |  |     if (ctx) { | 
					
						
							|  |  |  |         if (!glXMakeCurrent(dpy, None, NULL)) { | 
					
						
							|  |  |  |             ERROR_LOG("Could not release drawing context.\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         XUnmapWindow(dpy, win); | 
					
						
							|  |  |  |         glXDestroyContext(dpy, ctx); | 
					
						
							|  |  |  |         XCloseDisplay(dpy); | 
					
						
							|  |  |  |         ctx = NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     /* switch back to original desktop resolution if we were in fs */ | 
					
						
							|  |  |  |     if (dpy != NULL) { | 
					
						
							|  |  |  |         if (fs) { | 
					
						
							|  |  |  | 	    XF86VidModeSwitchToMode(dpy, screen, &deskMode); | 
					
						
							|  |  |  | 	    XF86VidModeSetViewPort(dpy, screen, 0, 0); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void X11Window::SwapBuffers() { | 
					
						
							|  |  |  |     glXSwapBuffers(dpy, win); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void X11Window::SetWindowText(const char *text) { | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Tell X to ask the window manager to set the window title. (X | 
					
						
							|  |  |  |      * itself doesn't provide window title functionality.) | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     XStoreName(dpy, win, text);    | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool X11Window::PeekMessages() { | 
					
						
							|  |  |  |     // TODO: implement
 | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | void X11Window::Update() { | 
					
						
							|  |  |  |     // We just check all of our events here
 | 
					
						
							|  |  |  |     XEvent event; | 
					
						
							|  |  |  |     KeySym key; | 
					
						
							|  |  |  |     static bool ShiftPressed = false; | 
					
						
							|  |  |  |     static bool ControlPressed = false; | 
					
						
							|  |  |  |     static int FKeyPressed = -1; | 
					
						
							|  |  |  |     int x,y; | 
					
						
							|  |  |  |     u32 w,h,depth; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int num_events; | 
					
						
							|  |  |  |     for (num_events = XPending(dpy);num_events > 0;num_events--) { | 
					
						
							|  |  |  |         XNextEvent(dpy, &event); | 
					
						
							|  |  |  |         switch(event.type) { | 
					
						
							|  |  |  | 	case KeyRelease: | 
					
						
							|  |  |  | 	    key = XLookupKeysym((XKeyEvent*)&event, 0); | 
					
						
							|  |  |  | 	    if(key >= XK_F1 && key <= XK_F9) { | 
					
						
							|  |  |  | 		g_VideoInitialize.pKeyPress(FKeyPressed, ShiftPressed, ControlPressed); | 
					
						
							|  |  |  | 		FKeyPressed = -1; | 
					
						
							|  |  |  | 	    } else { | 
					
						
							|  |  |  | 		if(key == XK_Shift_L || key == XK_Shift_R) | 
					
						
							|  |  |  | 		    ShiftPressed = false; | 
					
						
							|  |  |  | 		else if(key == XK_Control_L || key == XK_Control_R) | 
					
						
							|  |  |  | 		    ControlPressed = false; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 		    XPutBackEvent(dpy, &event); | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	case KeyPress: | 
					
						
							|  |  |  | 	    key = XLookupKeysym((XKeyEvent*)&event, 0); | 
					
						
							|  |  |  | 	    if(key >= XK_F1 && key <= XK_F9)  | 
					
						
							|  |  |  | 		FKeyPressed = key - 0xff4e; | 
					
						
							|  |  |  | 	    else { | 
					
						
							|  |  |  | 		if(key == XK_Shift_L || key == XK_Shift_R)  | 
					
						
							|  |  |  | 		    ShiftPressed = true; | 
					
						
							|  |  |  | 		else if(key == XK_Control_L || key == XK_Control_R) | 
					
						
							|  |  |  | 		    ControlPressed = true; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 		    XPutBackEvent(dpy, &event); | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	case ButtonPress: | 
					
						
							|  |  |  | 	case ButtonRelease: | 
					
						
							|  |  |  | 	    XPutBackEvent(dpy, &event); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	case ConfigureNotify: | 
					
						
							|  |  |  | 	    Window winDummy; | 
					
						
							|  |  |  | 	    unsigned int borderDummy; | 
					
						
							|  |  |  | 	    XGetGeometry(dpy, win, &winDummy, &x, &y, | 
					
						
							|  |  |  | 			 &w, &h, &borderDummy, &depth); | 
					
						
							|  |  |  | 	    SetSize(w, h); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	case ClientMessage: //TODO: We aren't reading this correctly, It could be anything, highest chance is that it's a close event though
 | 
					
						
							|  |  |  | 	    Video_Shutdown(); // Calling from here since returning false does nothing
 | 
					
						
							|  |  |  | 	    return;  | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 	    //TODO: Should we put the event back if we don't handle it?
 | 
					
						
							|  |  |  | 	    // I think we handle all the needed ones, the rest shouldn't matter
 | 
					
						
							|  |  |  | 	    // But to be safe, let's but them back anyway
 | 
					
						
							|  |  |  | 	    //XPutBackEvent(dpy, &event);
 | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-12-22 22:24:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     float FactorW  = 640.0f / (float)GetWidth(); | 
					
						
							|  |  |  |     float FactorH  = 480.0f / (float)GetHeight(); | 
					
						
							|  |  |  |     float Max = (FactorW < FactorH) ? FactorH : FactorW; | 
					
						
							|  |  |  |     //    AR = (float)surface->w / (float)surface->h;;
 | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     if (g_Config.bStretchToFit) { | 
					
						
							|  |  |  | 	SetMax(1,1); | 
					
						
							|  |  |  | 	SetOffset(0,0); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  | 	SetMax(1.0f / Max, 1.0f / Max); | 
					
						
							|  |  |  | 	SetOffset((int)((GetWidth() - (640 * GetXmax())) / 2), | 
					
						
							|  |  |  | 		  (int)((GetHeight() - (480 * GetYmax())) / 2)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2008-12-17 23:49:35 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool X11Window::MakeCurrent() { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Window winDummy; | 
					
						
							|  |  |  |     unsigned int borderDummy; | 
					
						
							|  |  |  |     int x,y; | 
					
						
							|  |  |  |     u32 w,h,depth; | 
					
						
							|  |  |  |     // connect the glx-context to the window
 | 
					
						
							|  |  |  |     glXMakeCurrent(dpy, win, ctx); | 
					
						
							|  |  |  |     XGetGeometry(dpy, win, &winDummy, &x, &y, | 
					
						
							|  |  |  |                  &w, &h, &borderDummy, &depth); | 
					
						
							|  |  |  |     SetSize(w, h); | 
					
						
							|  |  |  |     ERROR_LOG("GLWin Depth %d", depth); | 
					
						
							|  |  |  |     if (glXIsDirect(dpy, ctx))  | 
					
						
							|  |  |  |         ERROR_LOG("you have Direct Rendering!"); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         ERROR_LOG("no Direct Rendering possible!"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // better for pad plugin key input (thc)
 | 
					
						
							|  |  |  |     XSelectInput(dpy, win, ExposureMask | KeyPressMask | ButtonPressMask |  | 
					
						
							|  |  |  | 		 KeyReleaseMask | ButtonReleaseMask | StructureNotifyMask |  | 
					
						
							|  |  |  | 		 EnterWindowMask | LeaveWindowMask | FocusChangeMask); | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } |