diff --git a/ChangeLog b/ChangeLog index 2327e6c..10b52bb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2009-03-07 Johannes E. Schindelin + * client_examples/SDLvncviewer.c: make the viewer resizable + 2009-03-06 Johannes E. Schindelin * client_examples/SDLvncviewer.c: enable key repeat 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); }