From a02607fe352eca4ba8efff8df52c9e5ab1d04e6c Mon Sep 17 00:00:00 2001 From: dscho Date: Sat, 7 Mar 2009 19:18:26 +0000 Subject: Teach SDLvncviewer to be resizable Using "SDLvncviewer -resizable", you make the window resizable. This means that you can shrink the window (e.g. when you are trying to access an x11vnc from your little netbook), or you can enlarge it. Signed-off-by: Johannes Schindelin --- client_examples/SDLvncviewer.c | 153 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 145 insertions(+), 8 deletions(-) (limited to 'client_examples/SDLvncviewer.c') diff --git a/client_examples/SDLvncviewer.c b/client_examples/SDLvncviewer.c index 791c308..2f011ee 100644 --- a/client_examples/SDLvncviewer.c +++ b/client_examples/SDLvncviewer.c @@ -8,25 +8,37 @@ struct { int sdl; int rfb; } buttonMapping[]={ {0,0} }; -static rfbBool resize(rfbClient* client) { - static char first=TRUE; +static int enableResizable; #ifdef SDL_ASYNCBLIT - int flags=SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL; + int sdlFlags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL; #else - int flags=SDL_HWSURFACE|SDL_HWACCEL; + int sdlFlags = SDL_HWSURFACE | SDL_HWACCEL; #endif +static int realWidth, realHeight, bytesPerPixel, rowStride; +static char *sdlPixels; + +static rfbBool resize(rfbClient* client) { + static char first=TRUE; int width=client->width,height=client->height, depth=client->format.bitsPerPixel; + + if (enableResizable) + sdlFlags |= SDL_RESIZABLE; + client->updateRect.x = client->updateRect.y = 0; client->updateRect.w = width; client->updateRect.h = height; - rfbBool okay=SDL_VideoModeOK(width,height,depth,flags); + rfbBool okay=SDL_VideoModeOK(width,height,depth,sdlFlags); if(!okay) for(depth=24;!okay && depth>4;depth/=2) - okay=SDL_VideoModeOK(width,height,depth,flags); + okay=SDL_VideoModeOK(width,height,depth,sdlFlags); if(okay) { - SDL_Surface* sdl=SDL_SetVideoMode(width,height,depth,flags); + SDL_Surface* sdl=SDL_SetVideoMode(width,height,depth,sdlFlags); rfbClientSetClientData(client, SDL_Init, sdl); client->width = sdl->pitch / (depth / 8); + if (sdlPixels) { + free(client->frameBuffer); + sdlPixels = NULL; + } client->frameBuffer=sdl->pixels; if(first || depth!=client->format.bitsPerPixel) { first=FALSE; @@ -147,10 +159,124 @@ static rfbKeySym SDL_key2rfbKeySym(SDL_KeyboardEvent* e) { return k; } +static uint32_t get(rfbClient *cl, int x, int y) +{ + switch (bytesPerPixel) { + case 1: return ((uint8_t *)cl->frameBuffer)[x + y * cl->width]; + case 2: return ((uint16_t *)cl->frameBuffer)[x + y * cl->width]; + case 4: return ((uint32_t *)cl->frameBuffer)[x + y * cl->width]; + default: + rfbClientErr("Unknown bytes/pixel: %d", bytesPerPixel); + exit(1); + } +} + +static void put(int x, int y, uint32_t v) +{ + switch (bytesPerPixel) { + case 1: ((uint8_t *)sdlPixels)[x + y * rowStride] = v; break; + case 2: ((uint16_t *)sdlPixels)[x + y * rowStride] = v; break; + case 4: ((uint32_t *)sdlPixels)[x + y * rowStride] = v; break; + default: + rfbClientErr("Unknown bytes/pixel: %d", bytesPerPixel); + exit(1); + } +} + +static void resizeRectangleToReal(rfbClient *cl, int x, int y, int w, int h) +{ + int i0 = x * realWidth / cl->width; + int i1 = ((x + w) * realWidth - 1) / cl->width + 1; + int j0 = y * realHeight / cl->height; + int j1 = ((y + h) * realHeight - 1) / cl->height + 1; + int i, j; + + for (j = j0; j < j1; j++) + for (i = i0; i < i1; i++) { + int x0 = i * cl->width / realWidth; + int x1 = ((i + 1) * cl->width - 1) / realWidth + 1; + int y0 = j * cl->height / realHeight; + int y1 = ((j + 1) * cl->height - 1) / realHeight + 1; + uint32_t r = 0, g = 0, b = 0; + + for (y = y0; y < y1; y++) + for (x = x0; x < x1; x++) { + uint32_t v = get(cl, x, y); +#define REDSHIFT cl->format.redShift +#define REDMAX cl->format.redMax +#define GREENSHIFT cl->format.greenShift +#define GREENMAX cl->format.greenMax +#define BLUESHIFT cl->format.blueShift +#define BLUEMAX cl->format.blueMax + r += (v >> REDSHIFT) & REDMAX; + g += (v >> GREENSHIFT) & GREENMAX; + b += (v >> BLUESHIFT) & BLUEMAX; + } + r /= (x1 - x0) * (y1 - y0); + g /= (x1 - x0) * (y1 - y0); + b /= (x1 - x0) * (y1 - y0); + + put(i, j, (r << REDSHIFT) | (g << GREENSHIFT) | + (b << BLUESHIFT)); + } +} + static void update(rfbClient* cl,int x,int y,int w,int h) { + if (sdlPixels) { + resizeRectangleToReal(cl, x, y, w, h); + w = ((x + w) * realWidth - 1) / cl->width + 1; + h = ((y + h) * realHeight - 1) / cl->height + 1; + x = x * realWidth / cl->width; + y = y * realHeight / cl->height; + w -= x; + h -= y; + } SDL_UpdateRect(rfbClientGetClientData(cl, SDL_Init), x, y, w, h); } +static void setRealDimension(rfbClient *client, int w, int h) +{ + SDL_Surface* sdl; + + if (w < 0) { + const SDL_VideoInfo *info = SDL_GetVideoInfo(); + w = info->current_h; + h = info->current_w; + } + + if (w == realWidth && h == realHeight) + return; + + if (!sdlPixels) { + int size; + + sdlPixels = (char *)client->frameBuffer; + rowStride = client->width; + + bytesPerPixel = client->format.bitsPerPixel / 8; + size = client->width * bytesPerPixel * client->height; + client->frameBuffer = malloc(size); + if (!client->frameBuffer) { + rfbClientErr("Could not allocate %d bytes", size); + exit(1); + } + memcpy(client->frameBuffer, sdlPixels, size); + } + + sdl = rfbClientGetClientData(client, SDL_Init); + if (sdl->w != w || sdl->h != h) { + int depth = sdl->format->BitsPerPixel; + sdl = SDL_SetVideoMode(w, h, depth, sdlFlags); + rfbClientSetClientData(client, SDL_Init, sdl); + sdlPixels = sdl->pixels; + rowStride = sdl->pitch / (depth / 8); + } + + realWidth = w; + realHeight = h; + update(client, 0, 0, client->width, client->height); +} + static void kbd_leds(rfbClient* cl, int value, int pad) { /* note: pad is for future expansion 0=unused */ fprintf(stderr,"Led State= 0x%02X\n", value); @@ -231,8 +357,10 @@ int main(int argc,char** argv) { #endif for (i = 1, j = 1; i < argc; i++) - if (!strcmp(argv[1], "-viewonly")) + if (!strcmp(argv[i], "-viewonly")) viewOnly = 1; + else if (!strcmp(argv[i], "-resizable")) + enableResizable = 1; else { if (i != j) argv[j] = argv[i]; @@ -270,6 +398,11 @@ int main(int argc,char** argv) { break; int state=SDL_GetMouseState(&x,&y); int i; + + if (sdlPixels) { + x = x * cl->width / realWidth; + y = y * cl->height / realHeight; + } for(buttonMask=0,i=0;buttonMapping[i].sdl;i++) if(state&SDL_BUTTON(buttonMapping[i].sdl)) buttonMask|=buttonMapping[i].rfb; @@ -286,6 +419,10 @@ int main(int argc,char** argv) { return 0; case SDL_ACTIVEEVENT: break; + case SDL_VIDEORESIZE: + setRealDimension(cl, + e.resize.w, e.resize.h); + break; default: rfbClientLog("ignore SDL event: 0x%x\n",e.type); } -- cgit v1.2.3