aboutsummaryrefslogtreecommitdiffstats
path: root/vncviewer
diff options
context:
space:
mode:
Diffstat (limited to 'vncviewer')
-rw-r--r--vncviewer/DesktopWindow.cxx54
-rw-r--r--vncviewer/DesktopWindow.h2
-rw-r--r--vncviewer/Surface.h1
-rw-r--r--vncviewer/Surface_OSX.cxx67
-rw-r--r--vncviewer/Surface_Win32.cxx19
-rw-r--r--vncviewer/Surface_X11.cxx6
-rw-r--r--vncviewer/Viewport.cxx13
-rw-r--r--vncviewer/Viewport.h3
8 files changed, 133 insertions, 32 deletions
diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
index 707628ee..3da25054 100644
--- a/vncviewer/DesktopWindow.cxx
+++ b/vncviewer/DesktopWindow.cxx
@@ -34,6 +34,7 @@
#include "parameters.h"
#include "vncviewer.h"
#include "CConn.h"
+#include "Surface.h"
#include "Viewport.h"
#include <FL/Fl.H>
@@ -59,7 +60,7 @@ static rfb::LogWriter vlog("DesktopWindow");
DesktopWindow::DesktopWindow(int w, int h, const char *name,
const rfb::PixelFormat& serverPF,
CConn* cc_)
- : Fl_Window(w, h), cc(cc_), firstUpdate(true),
+ : Fl_Window(w, h), cc(cc_), offscreen(NULL), firstUpdate(true),
delayedFullscreen(false), delayedDesktopSize(false)
{
Fl_Group* group;
@@ -183,6 +184,8 @@ DesktopWindow::~DesktopWindow()
OptionsDialog::removeCallback(handleOptions);
+ delete offscreen;
+
// FLTK automatically deletes all child widgets, so we shouldn't touch
// them ourselves here
}
@@ -263,7 +266,19 @@ void DesktopWindow::draw()
{
bool redraw;
- int W, H;
+ int X, Y, W, H;
+
+ // X11 needs an off screen buffer for compositing to avoid flicker
+#if !defined(WIN32) && !defined(__APPLE__)
+
+ // Adjust offscreen surface dimensions
+ if ((offscreen == NULL) ||
+ (offscreen->width() != w()) || (offscreen->height() != h())) {
+ delete offscreen;
+ offscreen = new Surface(w(), h());
+ }
+
+#endif
// Active area inside scrollbars
W = w() - (vscroll->visible() ? vscroll->w() : 0);
@@ -274,30 +289,33 @@ void DesktopWindow::draw()
// Redraw background only on full redraws
if (redraw) {
- if (viewport->h() < h()) {
- fl_rectf(0, 0, W, viewport->y(), 40, 40, 40);
- fl_rectf(0, viewport->y() + viewport->h(), W,
- h() - (viewport->y() + viewport->h()),
- 40, 40, 40);
- }
- if (viewport->w() < w()) {
- fl_rectf(0, 0, viewport->x(), H, 40, 40, 40);
- fl_rectf(viewport->x() + viewport->w(), 0,
- w() - (viewport->x() + viewport->w()),
- H, 40, 40, 40);
- }
+ if (offscreen)
+ offscreen->clear(40, 40, 40);
+ else
+ fl_rectf(0, 0, W, H, 40, 40, 40);
}
// Make sure the viewport isn't trampling on the scrollbars
fl_push_clip(0, 0, W, H);
- if (redraw)
- draw_child(*viewport);
- else
- update_child(*viewport);
+ if (offscreen) {
+ viewport->draw(offscreen);
+ viewport->clear_damage();
+ } else {
+ if (redraw)
+ draw_child(*viewport);
+ else
+ update_child(*viewport);
+ }
fl_pop_clip();
+ // Flush offscreen surface to screen
+ if (offscreen) {
+ fl_clip_box(0, 0, W, H, X, Y, W, H);
+ offscreen->draw(X, Y, X, Y, W, H);
+ }
+
// Finally the scrollbars
if (redraw) {
diff --git a/vncviewer/DesktopWindow.h b/vncviewer/DesktopWindow.h
index d0e2eae4..073be661 100644
--- a/vncviewer/DesktopWindow.h
+++ b/vncviewer/DesktopWindow.h
@@ -30,6 +30,7 @@
namespace rfb { class ModifiablePixelBuffer; }
class CConn;
+class Surface;
class Viewport;
class Fl_Scrollbar;
@@ -95,6 +96,7 @@ private:
CConn* cc;
Fl_Scrollbar *hscroll, *vscroll;
Viewport *viewport;
+ Surface *offscreen;
bool firstUpdate;
bool delayedFullscreen;
diff --git a/vncviewer/Surface.h b/vncviewer/Surface.h
index 02917e31..9b1788a5 100644
--- a/vncviewer/Surface.h
+++ b/vncviewer/Surface.h
@@ -42,6 +42,7 @@ public:
void clear(unsigned char r, unsigned char g, unsigned char b, unsigned char a=255);
void draw(int src_x, int src_y, int x, int y, int w, int h);
+ void draw(Surface* dst, int src_x, int src_y, int x, int y, int w, int h);
protected:
void alloc();
diff --git a/vncviewer/Surface_OSX.cxx b/vncviewer/Surface_OSX.cxx
index c51e47f5..dbf0c418 100644
--- a/vncviewer/Surface_OSX.cxx
+++ b/vncviewer/Surface_OSX.cxx
@@ -28,6 +28,32 @@
#include "Surface.h"
+static void render(CGContextRef gc, CGImageRef image,
+ int src_x, int src_y, int src_w, int src_h,
+ int x, int y, int w, int h)
+{
+ CGRect rect;
+
+ CGContextSaveGState(gc);
+
+ // We have to use clipping to partially display an image
+ rect.origin.x = x;
+ rect.origin.y = y;
+ rect.size.width = w;
+ rect.size.height = h;
+
+ CGContextClipToRect(gc, rect);
+
+ rect.origin.x = x - src_x;
+ rect.origin.y = y - src_y;
+ rect.size.width = src_w;
+ rect.size.height = src_h;
+
+ CGContextDrawImage(gc, rect, image);
+
+ CGContextRestoreGState(gc);
+}
+
void Surface::clear(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
{
unsigned char* out;
@@ -50,8 +76,6 @@ void Surface::clear(unsigned char r, unsigned char g, unsigned char b, unsigned
void Surface::draw(int src_x, int src_y, int x, int y, int w, int h)
{
- CGRect rect;
-
CGContextSaveGState(fl_gc);
// Reset the transformation matrix back to the default identity
@@ -62,22 +86,37 @@ void Surface::draw(int src_x, int src_y, int x, int y, int w, int h)
src_y = height() - (src_y + h);
y = Fl_Window::current()->h() - (y + h);
- // We have to use clipping to partially display an image
- rect.origin.x = x;
- rect.origin.y = y;
- rect.size.width = w;
- rect.size.height = h;
+ render(fl_gc, image, src_x, src_y, width(), height(), x, y, w, h);
- CGContextClipToRect(fl_gc, rect);
+ CGContextRestoreGState(fl_gc);
+}
- rect.origin.x = x - src_x;
- rect.origin.y = y - src_y;
- rect.size.width = width();
- rect.size.height = height();
+void Surface::draw(Surface* dst, int src_x, int src_y, int x, int y, int w, int h)
+{
+ CGColorSpaceRef lut;
+ CGContextRef bitmap;
- CGContextDrawImage(fl_gc, rect, image);
+ lut = CGDisplayCopyColorSpace(kCGDirectMainDisplay);
+ if (!lut) {
+ lut = CGColorSpaceCreateDeviceRGB();
+ if (!lut)
+ throw rdr::Exception("CGColorSpaceCreateDeviceRGB");
+ }
- CGContextRestoreGState(fl_gc);
+ bitmap = CGBitmapContextCreate(dst->data, dst->width(),
+ dst->height(), 8, dst->width()*4, lut,
+ kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little);
+ CGColorSpaceRelease(lut);
+ if (!bitmap)
+ throw rdr::Exception("CGBitmapContextCreate");
+
+ // macOS Coordinates are from bottom left, not top left
+ src_y = height() - (src_y + h);
+ y = dst->height() - (y + h);
+
+ render(bitmap, image, src_x, src_y, width(), height(), x, y, w, h);
+
+ CGContextRelease(bitmap);
}
void Surface::alloc()
diff --git a/vncviewer/Surface_Win32.cxx b/vncviewer/Surface_Win32.cxx
index 5a9a6546..5eea2d1d 100644
--- a/vncviewer/Surface_Win32.cxx
+++ b/vncviewer/Surface_Win32.cxx
@@ -70,6 +70,25 @@ void Surface::draw(int src_x, int src_y, int x, int y, int w, int h)
DeleteDC(dc);
}
+void Surface::draw(Surface* dst, int src_x, int src_y, int x, int y, int w, int h)
+{
+ HDC origdc, dstdc;
+
+ dstdc = CreateCompatibleDC(NULL);
+ if (!dstdc)
+ throw rdr::SystemException("CreateCompatibleDC", GetLastError());
+
+ if (!SelectObject(dstdc, dst->bitmap))
+ throw rdr::SystemException("SelectObject", GetLastError());
+
+ origdc = fl_gc;
+ fl_gc = dstdc;
+ draw(src_x, src_y, x, y, w, h);
+ fl_gc = origdc;
+
+ DeleteDC(dstdc);
+}
+
void Surface::alloc()
{
BITMAPINFOHEADER bih;
diff --git a/vncviewer/Surface_X11.cxx b/vncviewer/Surface_X11.cxx
index c7e3778e..e7616143 100644
--- a/vncviewer/Surface_X11.cxx
+++ b/vncviewer/Surface_X11.cxx
@@ -48,6 +48,12 @@ void Surface::draw(int src_x, int src_y, int x, int y, int w, int h)
XRenderFreePicture(fl_display, winPict);
}
+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,
+ src_x, src_y, 0, 0, x, y, w, h);
+}
+
void Surface::alloc()
{
XRenderPictFormat* format;
diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx
index 7b3487c4..b5c516fa 100644
--- a/vncviewer/Viewport.cxx
+++ b/vncviewer/Viewport.cxx
@@ -244,6 +244,19 @@ void Viewport::setCursor(int width, int height, const Point& hotspot,
}
+void Viewport::draw(Surface* dst)
+{
+ int X, Y, W, H;
+
+ // Check what actually needs updating
+ fl_clip_box(x(), y(), w(), h(), X, Y, W, H);
+ if ((W == 0) || (H == 0))
+ return;
+
+ frameBuffer->draw(dst, X - x(), Y - y(), X, Y, W, H);
+}
+
+
void Viewport::draw()
{
int X, Y, W, H;
diff --git a/vncviewer/Viewport.h b/vncviewer/Viewport.h
index ac1ec338..0967fcbb 100644
--- a/vncviewer/Viewport.h
+++ b/vncviewer/Viewport.h
@@ -29,6 +29,7 @@ class Fl_RGB_Image;
class CConn;
class PlatformPixelBuffer;
+class Surface;
class Viewport : public Fl_Widget {
public:
@@ -46,6 +47,8 @@ public:
void setCursor(int width, int height, const rfb::Point& hotspot,
void* data, void* mask);
+ void draw(Surface* dst);
+
// Fl_Widget callback methods
void draw();