diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx index b85485b22c..63ea143f0b 100644 --- a/vncviewer/DesktopWindow.cxx +++ b/vncviewer/DesktopWindow.cxx @@ -368,7 +368,9 @@ void DesktopWindow::resizeFramebuffer(int new_w, int new_h) } } - viewport->size(new_w, new_h); + viewport->resizeFramebuffer(new_w, new_h); + + fitWindow(w(), h()); repositionWidgets(); } @@ -598,6 +600,18 @@ void DesktopWindow::handleClipboardData(const char* data) } +void DesktopWindow::fitWindow(int w, int h) +{ + double viewport_ratio = + static_cast(viewport->frameBufferWidth())/viewport->frameBufferHeight(); + double window_ratio = static_cast(w)/h; + if (window_ratio < viewport_ratio) + viewport->size(w, w/viewport_ratio); + else + viewport->size(h*viewport_ratio, h); +} + + void DesktopWindow::resize(int x, int y, int w, int h) { bool resizing; @@ -660,6 +674,8 @@ void DesktopWindow::resize(int x, int y, int w, int h) Fl_Window::resize(x, y, w, h); + fitWindow(w, h); + if (resizing) { // Try to get the remote size to match our window size, provided // the following conditions are true: diff --git a/vncviewer/DesktopWindow.h b/vncviewer/DesktopWindow.h index fd622c6d17..f1d3e03df7 100644 --- a/vncviewer/DesktopWindow.h +++ b/vncviewer/DesktopWindow.h @@ -108,6 +108,8 @@ class DesktopWindow : public Fl_Window { void repositionWidgets(); + void fitWindow(int w, int h); + static void handleClose(Fl_Widget *wnd, void *data); static void handleOptions(void *data); diff --git a/vncviewer/Surface.h b/vncviewer/Surface.h index 1cb87f502d..6e8ecd9c6f 100644 --- a/vncviewer/Surface.h +++ b/vncviewer/Surface.h @@ -47,6 +47,10 @@ class Surface { void blend(int src_x, int src_y, int x, int y, int w, int h, int a=255); void blend(Surface* dst, int src_x, int src_y, int x, int y, int w, int h, int a=255); + void setScale(double x, double y); + double scaleX() { return scale_x; } + double scaleY() { return scale_y; } + protected: void alloc(); void dealloc(); @@ -54,6 +58,7 @@ class Surface { protected: int w, h; + double scale_x, scale_y; #if defined(WIN32) RGBQUAD* data; diff --git a/vncviewer/Surface_X11.cxx b/vncviewer/Surface_X11.cxx index 7725cb5b8e..3ab468d8f6 100644 --- a/vncviewer/Surface_X11.cxx +++ b/vncviewer/Surface_X11.cxx @@ -53,6 +53,20 @@ void Surface::draw(int src_x, int src_y, int x, int y, int w, int h) XRenderFreePicture(fl_display, winPict); } +void Surface::setScale(double x, double y) +{ + scale_x = x; + scale_y = y; + + XTransform transform_matrix = {{ + {XDoubleToFixed(x), XDoubleToFixed(0), XDoubleToFixed(0)}, + {XDoubleToFixed(0), XDoubleToFixed(y), XDoubleToFixed(0)}, + {XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1)} + }}; + XRenderSetPictureTransform(fl_display, picture, &transform_matrix); + XRenderSetPictureFilter(fl_display, picture, FilterBilinear, 0, 0 ); +} + void Surface::draw(Surface* dst, int src_x, int src_y, int x, int y, int w, int h) { XRenderComposite(fl_display, PictOpSrc, picture, None, dst->picture, diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index d46c0021fe..0499d4bf25 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -232,7 +232,8 @@ void Viewport::updateWindow() Rect r; r = frameBuffer->getDamage(); - damage(FL_DAMAGE_USER1, r.tl.x + x(), r.tl.y + y(), r.width(), r.height()); + damage(FL_DAMAGE_USER1, r.tl.x/frameBuffer->scaleX() + x(), r.tl.y/frameBuffer->scaleY() + y(), + r.width()/frameBuffer->scaleX(), r.height()/frameBuffer->scaleY()); } static const char * dotcursor_xpm[] = { @@ -543,17 +544,45 @@ void Viewport::draw() } -void Viewport::resize(int x, int y, int w, int h) +void Viewport::updateFrameBufferScale(int w, int h) +{ + double new_scale_x = static_cast(frameBuffer->width())/w; + double new_scale_y = static_cast(frameBuffer->height())/h; + frameBuffer->setScale(new_scale_x, new_scale_y); +} + + +void Viewport::resizeFramebuffer(int w, int h) { if ((w != frameBuffer->width()) || (h != frameBuffer->height())) { vlog.debug("Resizing framebuffer from %dx%d to %dx%d", frameBuffer->width(), frameBuffer->height(), w, h); + // XXX: memory leak? frameBuffer = new PlatformPixelBuffer(w, h); assert(frameBuffer); cc->setFramebuffer(frameBuffer); + + updateFrameBufferScale(this->w(), this->h()); } +} + +int Viewport::frameBufferWidth() +{ + return frameBuffer->width(); +} + + +int Viewport::frameBufferHeight() +{ + return frameBuffer->height(); +} + + +void Viewport::resize(int x, int y, int w, int h) +{ + updateFrameBufferScale(w, h); Fl_Widget::resize(x, y, w, h); } @@ -667,9 +696,13 @@ void Viewport::sendPointerEvent(const rfb::Point& pos, int buttonMask) if (viewOnly) return; + rfb::Point scaled_pos; + scaled_pos.x = pos.x * frameBuffer->scaleX(); + scaled_pos.y = pos.y * frameBuffer->scaleY(); + if ((pointerEventInterval == 0) || (buttonMask != lastButtonMask)) { try { - cc->writer()->writePointerEvent(pos, buttonMask); + cc->writer()->writePointerEvent(scaled_pos, buttonMask); } catch (rdr::Exception& e) { vlog.error("%s", e.str()); abort_connection_with_unexpected_error(e); @@ -679,7 +712,7 @@ void Viewport::sendPointerEvent(const rfb::Point& pos, int buttonMask) Fl::add_timeout((double)pointerEventInterval/1000.0, handlePointerTimeout, this); } - lastPointerPos = pos; + lastPointerPos = scaled_pos; lastButtonMask = buttonMask; } diff --git a/vncviewer/Viewport.h b/vncviewer/Viewport.h index c70cca6e5f..81eafaccab 100644 --- a/vncviewer/Viewport.h +++ b/vncviewer/Viewport.h @@ -67,6 +67,10 @@ class Viewport : public Fl_Widget, public EmulateMB { void resize(int x, int y, int w, int h); + void resizeFramebuffer(int w, int h); + int frameBufferWidth(); + int frameBufferHeight(); + int handle(int event); protected: @@ -105,6 +109,8 @@ class Viewport : public Fl_Widget, public EmulateMB { static void handleOptions(void *data); + void updateFrameBufferScale(int w, int h); + private: CConn* cc;