📄 sdl_x11image.c
字号:
/* SDL - Simple DirectMedia Layer Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Sam Lantinga slouken@libsdl.org*/#ifdef SAVE_RCSIDstatic char rcsid = "@(#) $Id: SDL_x11image.c,v 1.7 2002/03/06 11:23:08 slouken Exp $";#endif#include <stdlib.h>#include <unistd.h>#include "SDL_error.h"#include "SDL_endian.h"#include "SDL_events_c.h"#include "SDL_x11image_c.h"#ifndef NO_SHARED_MEMORY/* Shared memory information */extern int XShmQueryExtension(Display *dpy); /* Not in X11 headers *//* Shared memory error handler routine */static int shm_error;static int (*X_handler)(Display *, XErrorEvent *) = NULL;static int shm_errhandler(Display *d, XErrorEvent *e){ if ( e->error_code == BadAccess ) { shm_error = 1; return(0); } else return(X_handler(d,e));}static void try_mitshm(_THIS, SDL_Surface *screen){ if(!use_mitshm) return; shminfo.shmid = shmget(IPC_PRIVATE, screen->h*screen->pitch, IPC_CREAT | 0777); if ( shminfo.shmid >= 0 ) { shminfo.shmaddr = (char *)shmat(shminfo.shmid, 0, 0); shminfo.readOnly = False; if ( shminfo.shmaddr != (char *)-1 ) { shm_error = False; X_handler = XSetErrorHandler(shm_errhandler); XShmAttach(SDL_Display, &shminfo); XSync(SDL_Display, True); XSetErrorHandler(X_handler); if (shm_error) shmdt(shminfo.shmaddr); } else { shm_error = True; } shmctl(shminfo.shmid, IPC_RMID, NULL); } else { shm_error = True; } if ( shm_error ) use_mitshm = 0; if ( use_mitshm ) screen->pixels = shminfo.shmaddr;}#endif /* ! NO_SHARED_MEMORY *//* Various screen update functions available */static void X11_NormalUpdate(_THIS, int numrects, SDL_Rect *rects);static void X11_MITSHMUpdate(_THIS, int numrects, SDL_Rect *rects);int X11_SetupImage(_THIS, SDL_Surface *screen){#ifndef NO_SHARED_MEMORY try_mitshm(this, screen); if(use_mitshm) { SDL_Ximage = XShmCreateImage(SDL_Display, SDL_Visual, this->hidden->depth, ZPixmap, shminfo.shmaddr, &shminfo, screen->w, screen->h); if(!SDL_Ximage) { XShmDetach(SDL_Display, &shminfo); XSync(SDL_Display, False); shmdt(shminfo.shmaddr); screen->pixels = NULL; goto error; } this->UpdateRects = X11_MITSHMUpdate; }#endif /* not NO_SHARED_MEMORY */ if(!use_mitshm) { int bpp; screen->pixels = malloc(screen->h*screen->pitch); if ( screen->pixels == NULL ) { SDL_OutOfMemory(); return -1; } bpp = screen->format->BytesPerPixel; SDL_Ximage = XCreateImage(SDL_Display, SDL_Visual, this->hidden->depth, ZPixmap, 0, (char *)screen->pixels, screen->w, screen->h, 32, 0); if ( SDL_Ximage == NULL ) goto error; /* XPutImage will convert byte sex automatically */ SDL_Ximage->byte_order = (SDL_BYTEORDER == SDL_BIG_ENDIAN) ? MSBFirst : LSBFirst; this->UpdateRects = X11_NormalUpdate; } screen->pitch = SDL_Ximage->bytes_per_line; return(0);error: SDL_SetError("Couldn't create XImage"); return 1;}void X11_DestroyImage(_THIS, SDL_Surface *screen){ if ( SDL_Ximage ) { XDestroyImage(SDL_Ximage);#ifndef NO_SHARED_MEMORY if ( use_mitshm ) { XShmDetach(SDL_Display, &shminfo); XSync(SDL_Display, False); shmdt(shminfo.shmaddr); }#endif /* ! NO_SHARED_MEMORY */ SDL_Ximage = NULL; } if ( screen ) { screen->pixels = NULL; }}/* Determine the number of CPUs in the system */static int num_CPU(void){ static int num_cpus = 0; if(!num_cpus) {#if defined(__linux) char line[BUFSIZ]; FILE *pstat = fopen("/proc/stat", "r"); if ( pstat ) { while ( fgets(line, sizeof(line), pstat) ) { if (memcmp(line, "cpu", 3) == 0 && line[3] != ' ') { ++num_cpus; } } fclose(pstat); }#elif defined(_SC_NPROCESSORS_ONLN) /* number of processors online (SVR4.0MP compliant machines) */ num_cpus = sysconf(_SC_NPROCESSORS_ONLN);#elif defined(_SC_NPROCESSORS_CONF) /* number of processors configured (SVR4.0MP compliant machines) */ num_cpus = sysconf(_SC_NPROCESSORS_CONF);#endif if ( num_cpus <= 0 ) { num_cpus = 1; } } return num_cpus;}int X11_ResizeImage(_THIS, SDL_Surface *screen, Uint32 flags){ int retval; X11_DestroyImage(this, screen); if ( flags & SDL_OPENGL ) { /* No image when using GL */ retval = 0; } else { retval = X11_SetupImage(this, screen); /* We support asynchronous blitting on the display */ if ( flags & SDL_ASYNCBLIT ) { /* This is actually slower on single-CPU systems, probably because of CPU contention between the X server and the application. Note: Is this still true with XFree86 4.0? */ if ( num_CPU() > 1 ) { screen->flags |= SDL_ASYNCBLIT; } } } return(retval);}/* We don't actually allow hardware surfaces other than the main one */int X11_AllocHWSurface(_THIS, SDL_Surface *surface){ return(-1);}void X11_FreeHWSurface(_THIS, SDL_Surface *surface){ return;}int X11_LockHWSurface(_THIS, SDL_Surface *surface){ if ( (surface == SDL_VideoSurface) && blit_queued ) { XSync(GFX_Display, False); blit_queued = 0; } return(0);}void X11_UnlockHWSurface(_THIS, SDL_Surface *surface){ return;}int X11_FlipHWSurface(_THIS, SDL_Surface *surface){ return(0);}static void X11_NormalUpdate(_THIS, int numrects, SDL_Rect *rects){ int i; for (i = 0; i < numrects; ++i) { if ( rects[i].w == 0 || rects[i].h == 0 ) { /* Clipped? */ continue; } XPutImage(GFX_Display, SDL_Window, SDL_GC, SDL_Ximage, rects[i].x, rects[i].y, rects[i].x, rects[i].y, rects[i].w, rects[i].h); } if ( SDL_VideoSurface->flags & SDL_ASYNCBLIT ) { XFlush(GFX_Display); blit_queued = 1; } else { XSync(GFX_Display, False); }}static void X11_MITSHMUpdate(_THIS, int numrects, SDL_Rect *rects){#ifndef NO_SHARED_MEMORY int i; for ( i=0; i<numrects; ++i ) { if ( rects[i].w == 0 || rects[i].h == 0 ) { /* Clipped? */ continue; } XShmPutImage(GFX_Display, SDL_Window, SDL_GC, SDL_Ximage, rects[i].x, rects[i].y, rects[i].x, rects[i].y, rects[i].w, rects[i].h, False); } if ( SDL_VideoSurface->flags & SDL_ASYNCBLIT ) { XFlush(GFX_Display); blit_queued = 1; } else { XSync(GFX_Display, False); }#endif /* ! NO_SHARED_MEMORY */}/* There's a problem with the automatic refreshing of the display. Even though the XVideo code uses the GFX_Display to update the video memory, it appears that updating the window asynchronously from a different thread will cause "blackouts" of the window. This is a sort of a hacked workaround for the problem.*/static int enable_autorefresh = 1;void X11_DisableAutoRefresh(_THIS){ --enable_autorefresh;}void X11_EnableAutoRefresh(_THIS){ ++enable_autorefresh;}void X11_RefreshDisplay(_THIS){ /* Don't refresh a display that doesn't have an image (like GL) Instead, post an expose event so the application can refresh. */ if ( ! SDL_Ximage || (enable_autorefresh <= 0) ) { SDL_PrivateExpose(); return; }#ifndef NO_SHARED_MEMORY if ( this->UpdateRects == X11_MITSHMUpdate ) { XShmPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage, 0, 0, 0, 0, this->screen->w, this->screen->h, False); } else#endif /* ! NO_SHARED_MEMORY */ { XPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage, 0, 0, 0, 0, this->screen->w, this->screen->h); } XSync(SDL_Display, False);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -