From 455566e8b5b2ea5bd78350769eb2d62279cc0dc6 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 10 Feb 2017 16:37:52 +0100 Subject: [PATCH] Fade overlay in and out --- vncviewer/DesktopWindow.cxx | 36 +++++++++++++++++++++-------- vncviewer/DesktopWindow.h | 4 +++- vncviewer/Surface.h | 4 ++-- vncviewer/Surface_OSX.cxx | 16 +++++++------ vncviewer/Surface_Win32.cxx | 6 ++--- vncviewer/Surface_X11.cxx | 46 +++++++++++++++++++++++++++++++++---- 6 files changed, 84 insertions(+), 28 deletions(-) diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx index 0dc03c41..190b39cc 100644 --- a/vncviewer/DesktopWindow.cxx +++ b/vncviewer/DesktopWindow.cxx @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -187,7 +188,7 @@ DesktopWindow::~DesktopWindow() Fl::remove_timeout(handleFullscreenTimeout, this); Fl::remove_timeout(handleEdgeScroll, this); Fl::remove_timeout(menuOverlay, this); - Fl::remove_timeout(clearOverlay, this); + Fl::remove_timeout(updateOverlay, this); OptionsDialog::removeCallback(handleOptions); @@ -336,9 +337,9 @@ void DesktopWindow::draw() fl_clip_box(ox, oy, ow, oh, ox, oy, ow, oh); if (offscreen) - overlay->blend(offscreen, ox - X, oy - Y, ox, oy, ow, oh); + overlay->blend(offscreen, ox - X, oy - Y, ox, oy, ow, oh, overlayAlpha); else - overlay->blend(ox - X, oy - Y, ox, oy, ow, oh); + overlay->blend(ox - X, oy - Y, ox, oy, ow, oh, overlayAlpha); } // Flush offscreen surface to screen @@ -469,7 +470,7 @@ void DesktopWindow::setOverlay(const char* text, ...) const unsigned char* b; delete overlay; - Fl::remove_timeout(clearOverlay, this); + Fl::remove_timeout(updateOverlay, this); va_start(ap, text); vsnprintf(textbuf, sizeof(textbuf), text, ap); @@ -538,21 +539,36 @@ void DesktopWindow::setOverlay(const char* text, ...) h = image->h(); overlay = new Surface(image); + overlayAlpha = 0; + gettimeofday(&overlayStart, NULL); delete image; - damage(FL_DAMAGE_USER1); - - Fl::add_timeout(3.0, clearOverlay, this); + Fl::add_timeout(1.0/60, updateOverlay, this); } -void DesktopWindow::clearOverlay(void *data) +void DesktopWindow::updateOverlay(void *data) { DesktopWindow *self; + unsigned elapsed; self = (DesktopWindow*)data; - delete self->overlay; - self->overlay = NULL; + + elapsed = msSince(&self->overlayStart); + + if (elapsed < 500) { + self->overlayAlpha = (unsigned)255 * elapsed / 500; + Fl::add_timeout(1.0/60, updateOverlay, self); + } else if (elapsed < 3500) { + self->overlayAlpha = 255; + Fl::add_timeout(3.0, updateOverlay, self); + } else if (elapsed < 4000) { + self->overlayAlpha = (unsigned)255 * (4000 - elapsed) / 500; + Fl::add_timeout(1.0/60, updateOverlay, self); + } else { + delete self->overlay; + self->overlay = NULL; + } self->damage(FL_DAMAGE_USER1); } diff --git a/vncviewer/DesktopWindow.h b/vncviewer/DesktopWindow.h index 1390e4f4..3dfaaea8 100644 --- a/vncviewer/DesktopWindow.h +++ b/vncviewer/DesktopWindow.h @@ -76,7 +76,7 @@ private: static void menuOverlay(void *data); void setOverlay(const char *text, ...) __printf_attr(2, 3); - static void clearOverlay(void *data); + static void updateOverlay(void *data); static int fltkHandle(int event, Fl_Window *win); @@ -109,6 +109,8 @@ private: Viewport *viewport; Surface *offscreen; Surface *overlay; + unsigned char overlayAlpha; + struct timeval overlayStart; bool firstUpdate; bool delayedFullscreen; diff --git a/vncviewer/Surface.h b/vncviewer/Surface.h index 7d164681..032889b4 100644 --- a/vncviewer/Surface.h +++ b/vncviewer/Surface.h @@ -44,8 +44,8 @@ public: 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); - void blend(int src_x, int src_y, int x, int y, int w, int h); - void blend(Surface* dst, int src_x, int src_y, int x, int y, int w, int h); + 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); protected: void alloc(); diff --git a/vncviewer/Surface_OSX.cxx b/vncviewer/Surface_OSX.cxx index 73c10f46..2dfaa477 100644 --- a/vncviewer/Surface_OSX.cxx +++ b/vncviewer/Surface_OSX.cxx @@ -28,7 +28,8 @@ #include "Surface.h" -static void render(CGContextRef gc, CGImageRef image, CGBlendMode mode, +static void render(CGContextRef gc, CGImageRef image, + CGBlendMode mode, CGFloat alpha, int src_x, int src_y, int src_w, int src_h, int x, int y, int w, int h) { @@ -37,6 +38,7 @@ static void render(CGContextRef gc, CGImageRef image, CGBlendMode mode, CGContextSaveGState(gc); CGContextSetBlendMode(gc, mode); + CGContextSetAlpha(gc, alpha); // We have to use clipping to partially display an image rect.origin.x = x; @@ -109,7 +111,7 @@ 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); - render(fl_gc, image, kCGBlendModeCopy, + render(fl_gc, image, kCGBlendModeCopy, 1.0, src_x, src_y, width(), height(), x, y, w, h); CGContextRestoreGState(fl_gc); @@ -125,13 +127,13 @@ void Surface::draw(Surface* dst, int src_x, int src_y, int x, int y, int w, int src_y = height() - (src_y + h); y = dst->height() - (y + h); - render(bitmap, image, kCGBlendModeCopy, + render(bitmap, image, kCGBlendModeCopy, 1.0, src_x, src_y, width(), height(), x, y, w, h); CGContextRelease(bitmap); } -void Surface::blend(int src_x, int src_y, int x, int y, int w, int h) +void Surface::blend(int src_x, int src_y, int x, int y, int w, int h, int a) { CGContextSaveGState(fl_gc); @@ -143,13 +145,13 @@ void Surface::blend(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); - render(fl_gc, image, kCGBlendModeNormal, + render(fl_gc, image, kCGBlendModeNormal, (CGFloat)a/255.0, src_x, src_y, width(), height(), x, y, w, h); CGContextRestoreGState(fl_gc); } -void Surface::blend(Surface* dst, int src_x, int src_y, int x, int y, int w, int h) +void Surface::blend(Surface* dst, int src_x, int src_y, int x, int y, int w, int h, int a) { CGContextRef bitmap; @@ -159,7 +161,7 @@ void Surface::blend(Surface* dst, int src_x, int src_y, int x, int y, int w, int src_y = height() - (src_y + h); y = dst->height() - (y + h); - render(bitmap, image, kCGBlendModeNormal, + render(bitmap, image, kCGBlendModeNormal, (CGFloat)a/255.0, src_x, src_y, width(), height(), x, y, w, h); CGContextRelease(bitmap); diff --git a/vncviewer/Surface_Win32.cxx b/vncviewer/Surface_Win32.cxx index 87b0cb2f..9400f536 100644 --- a/vncviewer/Surface_Win32.cxx +++ b/vncviewer/Surface_Win32.cxx @@ -89,13 +89,13 @@ void Surface::draw(Surface* dst, int src_x, int src_y, int x, int y, int w, int DeleteDC(dstdc); } -void Surface::blend(int src_x, int src_y, int x, int y, int w, int h) +void Surface::blend(int src_x, int src_y, int x, int y, int w, int h, int a) { // Compositing doesn't work properly for window DC:s assert(false); } -void Surface::blend(Surface* dst, int src_x, int src_y, int x, int y, int w, int h) +void Surface::blend(Surface* dst, int src_x, int src_y, int x, int y, int w, int h, int a) { HDC dstdc, srcdc; BLENDFUNCTION blend; @@ -114,7 +114,7 @@ void Surface::blend(Surface* dst, int src_x, int src_y, int x, int y, int w, int blend.BlendOp = AC_SRC_OVER; blend.BlendFlags = 0; - blend.SourceConstantAlpha = 255; + blend.SourceConstantAlpha = a; blend.AlphaFormat = AC_SRC_ALPHA; if (!AlphaBlend(dstdc, x, y, w, h, srcdc, src_x, src_y, w, h, blend)) { diff --git a/vncviewer/Surface_X11.cxx b/vncviewer/Surface_X11.cxx index f36976fa..3523da3d 100644 --- a/vncviewer/Surface_X11.cxx +++ b/vncviewer/Surface_X11.cxx @@ -54,20 +54,56 @@ void Surface::draw(Surface* dst, int src_x, int src_y, int x, int y, int w, int src_x, src_y, 0, 0, x, y, w, h); } -void Surface::blend(int src_x, int src_y, int x, int y, int w, int h) +static Picture alpha_mask(int a) { - Picture winPict; + Pixmap pixmap; + XRenderPictFormat* format; + XRenderPictureAttributes rep; + Picture pict; + XRenderColor color; + + if (a == 255) + return None; + + pixmap = XCreatePixmap(fl_display, XDefaultRootWindow(fl_display), + 1, 1, 8); + + format = XRenderFindStandardFormat(fl_display, PictStandardA8); + rep.repeat = RepeatNormal; + pict = XRenderCreatePicture(fl_display, pixmap, format, CPRepeat, &rep); + XFreePixmap(fl_display, pixmap); + + color.alpha = (unsigned)a * 65535 / 255; + + XRenderFillRectangle(fl_display, PictOpSrc, pict, &color, + 0, 0, 1, 1); + + return pict; +} + +void Surface::blend(int src_x, int src_y, int x, int y, int w, int h, int a) +{ + Picture winPict, alpha; winPict = XRenderCreatePicture(fl_display, fl_window, visFormat, 0, NULL); - XRenderComposite(fl_display, PictOpOver, picture, None, winPict, + alpha = alpha_mask(a); + XRenderComposite(fl_display, PictOpOver, picture, alpha, winPict, src_x, src_y, 0, 0, x, y, w, h); XRenderFreePicture(fl_display, winPict); + + if (alpha != None) + XRenderFreePicture(fl_display, alpha); } -void Surface::blend(Surface* dst, int src_x, int src_y, int x, int y, int w, int h) +void Surface::blend(Surface* dst, int src_x, int src_y, int x, int y, int w, int h, int a) { - XRenderComposite(fl_display, PictOpOver, picture, None, dst->picture, + Picture alpha; + + alpha = alpha_mask(a); + XRenderComposite(fl_display, PictOpOver, picture, alpha, dst->picture, src_x, src_y, 0, 0, x, y, w, h); + if (alpha != None) + XRenderFreePicture(fl_display, alpha); } -- 2.39.5