aboutsummaryrefslogtreecommitdiffstats
path: root/vncviewer/Surface_Win32.cxx
diff options
context:
space:
mode:
authorPierre Ossman <ossman@cendio.se>2017-01-02 17:00:41 +0100
committerPierre Ossman <ossman@cendio.se>2017-02-10 17:02:13 +0100
commit403ac27d2377df4fed8bf5039125f6d89aaa6955 (patch)
tree00e740d165f0aedff234e50b2303581efe6805d5 /vncviewer/Surface_Win32.cxx
parent13548819fa30b58f8d007a367d48934c7f064914 (diff)
downloadtigervnc-403ac27d2377df4fed8bf5039125f6d89aaa6955.tar.gz
tigervnc-403ac27d2377df4fed8bf5039125f6d89aaa6955.zip
Abstract platform rendering to "surfaces"
This will allow us to render more things than just the framebuffer.
Diffstat (limited to 'vncviewer/Surface_Win32.cxx')
-rw-r--r--vncviewer/Surface_Win32.cxx146
1 files changed, 146 insertions, 0 deletions
diff --git a/vncviewer/Surface_Win32.cxx b/vncviewer/Surface_Win32.cxx
new file mode 100644
index 00000000..5a9a6546
--- /dev/null
+++ b/vncviewer/Surface_Win32.cxx
@@ -0,0 +1,146 @@
+/* Copyright 2016 Pierre Ossman for Cendio AB
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <assert.h>
+
+#include <FL/Fl_RGB_Image.H>
+#include <FL/x.H>
+
+#include <rdr/Exception.h>
+
+#include "Surface.h"
+
+void Surface::clear(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
+{
+ RGBQUAD* out;
+ int x, y;
+
+ r = (unsigned)r * a / 255;
+ g = (unsigned)g * a / 255;
+ b = (unsigned)b * a / 255;
+
+ out = data;
+ for (y = 0;y < width();y++) {
+ for (x = 0;x < height();x++) {
+ out->rgbRed = r;
+ out->rgbGreen = g;
+ out->rgbBlue = b;
+ out->rgbReserved = a;
+ out++;
+ }
+ }
+}
+
+void Surface::draw(int src_x, int src_y, int x, int y, int w, int h)
+{
+ HDC dc;
+
+ dc = CreateCompatibleDC(fl_gc);
+ if (!dc)
+ throw rdr::SystemException("CreateCompatibleDC", GetLastError());
+
+ if (!SelectObject(dc, bitmap))
+ throw rdr::SystemException("SelectObject", GetLastError());
+
+ if (!BitBlt(fl_gc, x, y, w, h, dc, src_x, src_y, SRCCOPY)) {
+ // If the desktop we're rendering to is inactive (like when the screen
+ // is locked or the UAC is active), then GDI calls will randomly fail.
+ // This is completely undocumented so we have no idea how best to deal
+ // with it. For now, we've only seen this error and for this function
+ // so only ignore this combination.
+ if (GetLastError() != ERROR_INVALID_HANDLE)
+ throw rdr::SystemException("BitBlt", GetLastError());
+ }
+
+ DeleteDC(dc);
+}
+
+void Surface::alloc()
+{
+ BITMAPINFOHEADER bih;
+
+ data = new RGBQUAD[width() * height()];
+
+ memset(&bih, 0, sizeof(bih));
+
+ bih.biSize = sizeof(BITMAPINFOHEADER);
+ bih.biBitCount = 32;
+ bih.biPlanes = 1;
+ bih.biWidth = width();
+ bih.biHeight = -height(); // Negative to get top-down
+ bih.biCompression = BI_RGB;
+
+ bitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bih,
+ DIB_RGB_COLORS, (void**)&data, NULL, 0);
+ if (!bitmap)
+ throw rdr::SystemException("CreateDIBSection", GetLastError());
+}
+
+void Surface::dealloc()
+{
+ DeleteObject(bitmap);
+}
+
+void Surface::update(const Fl_RGB_Image* image)
+{
+ const unsigned char* in;
+ RGBQUAD* out;
+ int x, y;
+
+ assert(image->w() == width());
+ assert(image->h() == height());
+
+ // Convert data and pre-multiply alpha
+ in = (const unsigned char*)image->data()[0];
+ out = data;
+ for (y = 0;y < image->w();y++) {
+ for (x = 0;x < image->h();x++) {
+ switch (image->d()) {
+ case 1:
+ out->rgbBlue = in[0];
+ out->rgbGreen = in[0];
+ out->rgbRed = in[0];
+ out->rgbReserved = 0xff;
+ break;
+ case 2:
+ out->rgbBlue = (unsigned)in[0] * in[1] / 255;
+ out->rgbGreen = (unsigned)in[0] * in[1] / 255;
+ out->rgbRed = (unsigned)in[0] * in[1] / 255;
+ out->rgbReserved = in[1];
+ break;
+ case 3:
+ out->rgbBlue = in[2];
+ out->rgbGreen = in[1];
+ out->rgbRed = in[0];
+ out->rgbReserved = 0xff;
+ break;
+ case 4:
+ out->rgbBlue = (unsigned)in[2] * in[3] / 255;
+ out->rgbGreen = (unsigned)in[1] * in[3] / 255;
+ out->rgbRed = (unsigned)in[0] * in[3] / 255;
+ out->rgbReserved = in[3];
+ break;
+ }
+ in += image->d();
+ out++;
+ }
+ if (image->ld() != 0)
+ in += image->ld() - image->w() * image->d();
+ }
+}
+