X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=vid_glx.c;h=165dcc7919cfbba8dfacc5ad56bc359a9cbb483a;hb=55a5d72bf63b2d0a47059e0d2504bfd03a67d3a7;hp=a960a009850936321d3558210ddffb076d51cee7;hpb=6d9278cdfd9243e42404a8132a4665bd1bf837a8;p=xonotic%2Fdarkplaces.git diff --git a/vid_glx.c b/vid_glx.c index a960a009..165dcc79 100644 --- a/vid_glx.c +++ b/vid_glx.c @@ -76,10 +76,13 @@ static dllfunction_t swapcontrolfuncs[] = static Display *vidx11_display = NULL; static int vidx11_screen; -static Window win; +static Window win, root; static GLXContext ctx = NULL; Atom wm_delete_window_atom; +Atom net_wm_state_atom; +Atom net_wm_state_hidden_atom; +Atom net_wm_state_fullscreen_atom; #define KEY_MASK (KeyPressMask | KeyReleaseMask) #define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \ @@ -109,8 +112,11 @@ qboolean vidmode_ext = false; static int win_x, win_y; -static XF86VidModeModeInfo init_vidmode; +static XF86VidModeModeInfo init_vidmode, game_vidmode; static qboolean vid_isfullscreen = false; +static qboolean vid_isvidmodefullscreen = false; +static qboolean vid_isnetwmfullscreen = false; +static qboolean vid_isoverrideredirect = false; static Visual *vidx11_visual; static Colormap vidx11_colormap; @@ -287,7 +293,7 @@ void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecurso if (fullscreengrab) { XGrabPointer(vidx11_display, win, True, 0, GrabModeAsync, GrabModeAsync, win, None, CurrentTime); - if (vid_grabkeyboard.integer || (vid_isfullscreen && !vid_netwmfullscreen.integer)) + if (vid_grabkeyboard.integer || vid_isoverrideredirect) XGrabKeyboard(vidx11_display, win, False, GrabModeAsync, GrabModeAsync, CurrentTime); } else @@ -469,10 +475,14 @@ static void HandleEvents(void) // window changed size/location win_x = event.xconfigure.x; win_y = event.xconfigure.y; - if(vid_resizable.integer < 2) + if(vid_resizable.integer < 2 || vid_isnetwmfullscreen) { vid.width = event.xconfigure.width; vid.height = event.xconfigure.height; + if(vid_isnetwmfullscreen) + Con_Printf("NetWM fullscreen: actually using resolution %dx%d\n", vid.width, vid.height); + else + Con_DPrintf("Updating to ConfigureNotify resolution %dx%d\n", vid.width, vid.height); } break; case DestroyNotify: @@ -485,31 +495,86 @@ static void HandleEvents(void) Sys_Quit(0); break; case MapNotify: - if (vid.fullscreen) + if (vid_isoverrideredirect) break; // window restored vid_hidden = false; VID_RestoreSystemGamma(); + + if(vid_isvidmodefullscreen) + { + // set our video mode + XF86VidModeSwitchToMode(vidx11_display, vidx11_screen, &game_vidmode); + + // Move the viewport to top left + XF86VidModeSetViewPort(vidx11_display, vidx11_screen, 0, 0); + } + + if(vid_isnetwmfullscreen) + { + // make sure it's fullscreen + XEvent event; + event.type = ClientMessage; + event.xclient.serial = 0; + event.xclient.send_event = True; + event.xclient.message_type = net_wm_state_atom; + event.xclient.window = win; + event.xclient.format = 32; + event.xclient.data.l[0] = 1; + event.xclient.data.l[1] = net_wm_state_fullscreen_atom; + event.xclient.data.l[2] = 0; + event.xclient.data.l[3] = 1; + event.xclient.data.l[4] = 0; + XSendEvent(vidx11_display, root, False, SubstructureRedirectMask | SubstructureNotifyMask, &event); + } + + dowarp = true; + break; case UnmapNotify: - if (vid.fullscreen) + if (vid_isoverrideredirect) break; // window iconified/rolledup/whatever vid_hidden = true; VID_RestoreSystemGamma(); + + if(vid_isvidmodefullscreen) + XF86VidModeSwitchToMode(vidx11_display, vidx11_screen, &init_vidmode); + break; case FocusIn: - if (vid.fullscreen) + if (vid_isoverrideredirect) break; // window is now the input focus vid_activewindow = true; break; case FocusOut: - if (vid.fullscreen) + if (vid_isoverrideredirect) break; + + if(vid_isnetwmfullscreen && event.xfocus.mode == NotifyNormal) + { + // iconify netwm fullscreen window when it loses focus + // when the user selects it in the taskbar, the window manager will map it again and send MapNotify + XEvent event; + event.type = ClientMessage; + event.xclient.serial = 0; + event.xclient.send_event = True; + event.xclient.message_type = net_wm_state_atom; + event.xclient.window = win; + event.xclient.format = 32; + event.xclient.data.l[0] = 1; + event.xclient.data.l[1] = net_wm_state_hidden_atom; + event.xclient.data.l[2] = 0; + event.xclient.data.l[3] = 1; + event.xclient.data.l[4] = 0; + XSendEvent(vidx11_display, root, False, SubstructureRedirectMask | SubstructureNotifyMask, &event); + } + // window is no longer the input focus vid_activewindow = false; VID_RestoreSystemGamma(); + break; case EnterNotify: // mouse entered window @@ -582,7 +647,7 @@ void VID_Shutdown(void) VID_RestoreSystemGamma(); // FIXME: glXDestroyContext here? - if (vid_isfullscreen) + if (vid_isvidmodefullscreen) XF86VidModeSwitchToMode(vidx11_display, vidx11_screen, &init_vidmode); if (win) XDestroyWindow(vidx11_display, win); @@ -590,6 +655,9 @@ void VID_Shutdown(void) vid_hidden = true; vid_isfullscreen = false; + vid_isnetwmfullscreen = false; + vid_isvidmodefullscreen = false; + vid_isoverrideredirect = false; vidx11_display = NULL; win = 0; ctx = NULL; @@ -632,7 +700,7 @@ void VID_Finish (void) if (r_render.integer) { CHECKGLERROR - if (r_speeds.integer || gl_finish.integer) + if (r_speeds.integer == 2 || gl_finish.integer) { qglFinish();CHECKGLERROR } @@ -691,7 +759,7 @@ void VID_BuildGLXAttrib(int *attrib, qboolean stencil, qboolean stereobuffer, in *attrib++ = None; } -int VID_InitMode(int fullscreen, int width, int height, int bpp, int refreshrate, int stereobuffer, int samples) +int VID_InitMode(int fullscreen, int *width, int *height, int bpp, int refreshrate, int stereobuffer, int samples) { int i; int attrib[32]; @@ -700,11 +768,15 @@ int VID_InitMode(int fullscreen, int width, int height, int bpp, int refreshrate XWMHints *wmhints; XSizeHints *szhints; unsigned long mask; - Window root; XVisualInfo *visinfo; int MajorVersion, MinorVersion; const char *drivername; + vid_isfullscreen = false; + vid_isnetwmfullscreen = false; + vid_isvidmodefullscreen = false; + vid_isoverrideredirect = false; + #if defined(__APPLE__) && defined(__MACH__) drivername = "/usr/X11R6/lib/libGL.1.dylib"; #else @@ -728,6 +800,13 @@ int VID_InitMode(int fullscreen, int width, int height, int bpp, int refreshrate return false; } + // LordHavoc: making the close button on a window do the right thing + // seems to involve this mess, sigh... + wm_delete_window_atom = XInternAtom(vidx11_display, "WM_DELETE_WINDOW", false); + net_wm_state_atom = XInternAtom(vidx11_display, "_NET_WM_STATE", false); + net_wm_state_fullscreen_atom = XInternAtom(vidx11_display, "_NET_WM_STATE_FULLSCREEN", false); + net_wm_state_hidden_atom = XInternAtom(vidx11_display, "_NET_WM_STATE_HIDDEN", false); + // make autorepeat send keypress/keypress/.../keyrelease instead of intervening keyrelease XkbSetDetectableAutoRepeat(vidx11_display, true, NULL); @@ -763,13 +842,22 @@ int VID_InitMode(int fullscreen, int width, int height, int bpp, int refreshrate return false; } - if (vidmode_ext) + if (fullscreen) { - int best_fit, best_dist, dist, x, y; + if(vid_netwmfullscreen.integer) + { + // TODO detect WM support + vid_isnetwmfullscreen = true; + vid_isfullscreen = true; + // width and height will be filled in later + Con_DPrintf("Using NetWM fullscreen mode\n"); + } - // Are we going fullscreen? If so, let's change video mode - if (fullscreen) + if(!vid_isfullscreen && vidmode_ext) { + int best_fit, best_dist, dist, x, y; + + // Are we going fullscreen? If so, let's change video mode XF86VidModeModeLine *current_vidmode; XF86VidModeModeInfo **vidmodes; int num_vidmodes; @@ -779,18 +867,18 @@ int VID_InitMode(int fullscreen, int width, int height, int bpp, int refreshrate XF86VidModeGetModeLine(vidx11_display, vidx11_screen, (int*)&init_vidmode.dotclock, current_vidmode); XF86VidModeGetAllModeLines(vidx11_display, vidx11_screen, &num_vidmodes, &vidmodes); - best_dist = 9999999; + best_dist = 0; best_fit = -1; for (i = 0; i < num_vidmodes; i++) { - if (width > vidmodes[i]->hdisplay || height > vidmodes[i]->vdisplay) + if (*width > vidmodes[i]->hdisplay || *height > vidmodes[i]->vdisplay) continue; - x = width - vidmodes[i]->hdisplay; - y = height - vidmodes[i]->vdisplay; + x = *width - vidmodes[i]->hdisplay; + y = *height - vidmodes[i]->vdisplay; dist = (x * x) + (y * y); - if (dist < best_dist) + if (best_fit == -1 || dist < best_dist) { best_dist = dist; best_fit = i; @@ -802,21 +890,33 @@ int VID_InitMode(int fullscreen, int width, int height, int bpp, int refreshrate // LordHavoc: changed from ActualWidth/ActualHeight =, // to width/height =, so the window will take the full area of // the mode chosen - width = vidmodes[best_fit]->hdisplay; - height = vidmodes[best_fit]->vdisplay; + *width = vidmodes[best_fit]->hdisplay; + *height = vidmodes[best_fit]->vdisplay; // change to the mode XF86VidModeSwitchToMode(vidx11_display, vidx11_screen, vidmodes[best_fit]); + memcpy(&game_vidmode, vidmodes[best_fit], sizeof(game_vidmode)); + vid_isvidmodefullscreen = true; vid_isfullscreen = true; // Move the viewport to top left XF86VidModeSetViewPort(vidx11_display, vidx11_screen, 0, 0); + Con_DPrintf("Using XVidMode fullscreen mode at %dx%d\n", *width, *height); } - else - fullscreen = 0; free(vidmodes); } + + if(!vid_isfullscreen) + { + // sorry, no FS available + // use the full desktop resolution + vid_isfullscreen = true; + // width and height will be filled in later + *width = DisplayWidth(vidx11_display, vidx11_screen); + *height = DisplayHeight(vidx11_display, vidx11_screen); + Con_DPrintf("Using X11 fullscreen mode at %dx%d\n", *width, *height); + } } // LordHavoc: save the visual for use in gamma ramp settings later @@ -828,26 +928,30 @@ int VID_InitMode(int fullscreen, int width, int height, int bpp, int refreshrate // LordHavoc: save the colormap for later, too vidx11_colormap = attr.colormap = XCreateColormap(vidx11_display, root, visinfo->visual, AllocNone); attr.event_mask = X_MASK; - if (vid_isfullscreen) + + if (fullscreen) { - if(vid_netwmfullscreen.integer) + if(vid_isnetwmfullscreen) { - mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore | CWEventMask | CWOverrideRedirect; - attr.override_redirect = True; + mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore | CWEventMask; attr.backing_store = NotUseful; attr.save_under = False; } else { - mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore | CWEventMask; + mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore | CWEventMask | CWOverrideRedirect; + attr.override_redirect = True; attr.backing_store = NotUseful; attr.save_under = False; + vid_isoverrideredirect = true; // so it knows to grab } } else + { mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; + } - win = XCreateWindow(vidx11_display, root, 0, 0, width, height, 0, visinfo->depth, InputOutput, visinfo->visual, mask, &attr); + win = XCreateWindow(vidx11_display, root, 0, 0, *width, *height, 0, visinfo->depth, InputOutput, visinfo->visual, mask, &attr); wmhints = XAllocWMHints(); if(XpmCreatePixmapFromData(vidx11_display, win, @@ -860,10 +964,10 @@ int VID_InitMode(int fullscreen, int width, int height, int bpp, int refreshrate clshints->res_class = strdup("DarkPlaces"); szhints = XAllocSizeHints(); - if(vid_resizable.integer == 0) + if(vid_resizable.integer == 0 && !vid_isnetwmfullscreen) { - szhints->min_width = szhints->max_width = width; - szhints->min_height = szhints->max_height = height; + szhints->min_width = szhints->max_width = *width; + szhints->min_height = szhints->max_height = *height; szhints->flags |= PMinSize | PMaxSize; } @@ -872,27 +976,21 @@ int VID_InitMode(int fullscreen, int width, int height, int bpp, int refreshrate XFree(wmhints); XFree(szhints); - if(vid_isfullscreen && vid_netwmfullscreen.integer) - { - Atom net_wm_state_atom = XInternAtom(vidx11_display, "_NET_WM_STATE", false); - Atom net_wm_state_fullscreen_atom = XInternAtom(vidx11_display, "_NET_WM_STATE_FULLSCREEN", false); - XChangeProperty(vidx11_display, win, net_wm_state_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *) &net_wm_state_fullscreen_atom, 1); - } - //XStoreName(vidx11_display, win, gamename); XMapWindow(vidx11_display, win); - // LordHavoc: making the close button on a window do the right thing - // seems to involve this mess, sigh... - wm_delete_window_atom = XInternAtom(vidx11_display, "WM_DELETE_WINDOW", false); XSetWMProtocols(vidx11_display, win, &wm_delete_window_atom, 1); - if (vid_isfullscreen) + if (vid_isoverrideredirect) { XMoveWindow(vidx11_display, win, 0, 0); XRaiseWindow(vidx11_display, win); XWarpPointer(vidx11_display, None, win, 0, 0, 0, 0, 0, 0); XFlush(vidx11_display); + } + + if(vid_isvidmodefullscreen) + { // Move the viewport to top left XF86VidModeSetViewPort(vidx11_display, vidx11_screen, 0, 0); } @@ -947,6 +1045,7 @@ int VID_InitMode(int fullscreen, int width, int height, int bpp, int refreshrate if (!vid_x11_dgasupported) Con_Print( "Failed to detect XF86DGA Mouse extension\n" ); #endif + GL_Init(); return true; } @@ -956,7 +1055,7 @@ void Sys_SendKeyEvents(void) static qboolean sound_active = true; // enable/disable sound on focus gain/loss - if (!vid_hidden && (vid_activewindow || !snd_mutewhenidle.integer)) + if ((!vid_hidden && vid_activewindow) || !snd_mutewhenidle.integer) { if (!sound_active) { @@ -979,3 +1078,37 @@ void Sys_SendKeyEvents(void) void IN_Move (void) { } + +size_t VID_ListModes(vid_mode_t *modes, size_t maxcount) +{ + if(vidmode_ext) + { + int i, bpp; + size_t k; + XF86VidModeModeInfo **vidmodes; + int num_vidmodes; + + XF86VidModeGetAllModeLines(vidx11_display, vidx11_screen, &num_vidmodes, &vidmodes); + k = 0; + for (i = 0; i < num_vidmodes; i++) + { + if(k >= maxcount) + break; + // we don't get bpp info, so let's just assume all of 8, 15, 16, 24, 32 work + for(bpp = 8; bpp <= 32; bpp = ((bpp == 8) ? 15 : (bpp & 0xF8) + 8)) + { + if(k >= maxcount) + break; + modes[k].width = vidmodes[i]->hdisplay; + modes[k].height = vidmodes[i]->vdisplay; + modes[k].bpp = 8; + modes[k].refreshrate = vidmodes[i]->dotclock / vidmodes[i]->htotal / vidmodes[i]->vtotal; + modes[k].pixelheight_num = 1; + modes[k].pixelheight_denom = 1; // xvidmode does not provide this + ++k; + } + } + return k; + } + return 0; // FIXME implement this +}