blob: ad5e6b1cf4908ce58f4a9a8e15b9db9a54e00b80 [file] [log] [blame]
Constantin Kaplinsky729598c2006-05-25 05:12:25 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
Pierre Ossman4d0bc6e2014-02-12 13:12:31 +01002 * Copyright 2014 Pierre Ossman for Cendio AB
Constantin Kaplinsky729598c2006-05-25 05:12:25 +00003 *
4 * This is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This software is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this software; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 * USA.
18 */
19
20#include <rfb_win32/DeviceContext.h>
21#include <rfb_win32/CompatibleBitmap.h>
22#include <rfb_win32/BitmapInfo.h>
23#include <rdr/Exception.h>
24#include <rfb/LogWriter.h>
25
26using namespace rfb;
27using namespace win32;
28
29
30static LogWriter vlog("DeviceContext");
31
32PixelFormat DeviceContext::getPF() const {
33 return getPF(dc);
34}
35
36PixelFormat DeviceContext::getPF(HDC dc) {
Pierre Ossman4d0bc6e2014-02-12 13:12:31 +010037 bool trueColour, bigEndian;
38 int bpp, depth;
39 int redMax, greenMax, blueMax;
40 int redShift, greenShift, blueShift;
41
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000042 CompatibleBitmap bitmap(dc, 1, 1);
43
44 // -=- Get the bitmap format information
45 BitmapInfo bi;
46 memset(&bi, 0, sizeof(bi));
47 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
48 bi.bmiHeader.biBitCount = 0;
49 if (!::GetDIBits(dc, bitmap, 0, 1, NULL, (BITMAPINFO*)&bi, DIB_RGB_COLORS)) {
50 throw rdr::SystemException("unable to determine device pixel format", GetLastError());
51 }
52 if (!::GetDIBits(dc, bitmap, 0, 1, NULL, (BITMAPINFO*)&bi, DIB_RGB_COLORS)) {
53 throw rdr::SystemException("unable to determine pixel shifts/palette", GetLastError());
54 }
55
56 // Set the initial format information
Pierre Ossman4d0bc6e2014-02-12 13:12:31 +010057 trueColour = bi.bmiHeader.biBitCount > 8;
58 bigEndian = 0;
59 bpp = bi.bmiHeader.biBitCount;
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000060
Pierre Ossman4d0bc6e2014-02-12 13:12:31 +010061 if (trueColour) {
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000062 DWORD rMask=0, gMask=0, bMask=0;
63
64 // Which true colour format is the DIB section using?
65 switch (bi.bmiHeader.biCompression) {
66 case BI_RGB:
67 // Default RGB layout
68 switch (bi.bmiHeader.biBitCount) {
69 case 16:
70 // RGB 555 - High Colour
71 vlog.info("16-bit High Colour");
72 rMask = 0x7c00;
73 bMask = 0x001f;
74 gMask = 0x03e0;
75 break;
76 case 24:
77 case 32:
78 // RGB 888 - True Colour
79 vlog.info("24/32-bit High Colour");
80 rMask = 0xff0000;
81 gMask = 0x00ff00;
82 bMask = 0x0000ff;
83 break;
84 default:
85 vlog.error("bits per pixel %u not supported", bi.bmiHeader.biBitCount);
86 throw rdr::Exception("unknown bits per pixel specified");
87 };
88 break;
89 case BI_BITFIELDS:
90 // Custom RGB layout
91 rMask = bi.mask.red;
92 gMask = bi.mask.green;
93 bMask = bi.mask.blue;
Pierre Ossmanfb450fb2015-03-03 16:34:56 +010094 vlog.info("%d-bit BitFields: (%lx, %lx, %lx)",
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000095 bi.bmiHeader.biBitCount, rMask, gMask, bMask);
96 break;
97 };
98
99 // Convert the data we just retrieved
Pierre Ossman4d0bc6e2014-02-12 13:12:31 +0100100 initMaxAndShift(rMask, &redMax, &redShift);
101 initMaxAndShift(gMask, &greenMax, &greenShift);
102 initMaxAndShift(bMask, &blueMax, &blueShift);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000103
104 // Calculate the depth from the colour shifts
Pierre Ossman4d0bc6e2014-02-12 13:12:31 +0100105 depth = 0;
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000106 Pixel bits = rMask | gMask | bMask;
107 while (bits) {
Pierre Ossman4d0bc6e2014-02-12 13:12:31 +0100108 depth++;
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000109 bits = bits >> 1;
110 }
111
112 // Check that the depth & bpp are valid
Pierre Ossman4d0bc6e2014-02-12 13:12:31 +0100113 if (depth > bpp) {
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000114 vlog.error("depth exceeds bits per pixel!");
Pierre Ossman4d0bc6e2014-02-12 13:12:31 +0100115 bpp = depth;
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000116 }
117
118 // Correct the bits-per-pixel to something we're happy with
Pierre Ossman4d0bc6e2014-02-12 13:12:31 +0100119 if (bpp <= 16)
120 bpp = 16;
121 else if (bpp <= 32)
122 bpp = 32;
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000123 } else {
124 // Palettised format - depth reflects number of colours,
125 // but bits-per-pixel is ALWAYS 8
Pierre Ossman4d0bc6e2014-02-12 13:12:31 +0100126 depth = bpp;
127 if (bpp < 8)
128 bpp = 8;
129 vlog.info("%d-colour palettised", 1<<depth);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000130 }
131
Adam Tkac9c8076b2011-02-21 12:40:30 +0000132
Pierre Ossman4d0bc6e2014-02-12 13:12:31 +0100133 return PixelFormat(bpp, depth, bigEndian, trueColour,
134 redMax, greenMax, blueMax,
135 redShift, greenShift, blueShift);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000136}
137
138Rect DeviceContext::getClipBox() const {
139 return getClipBox(dc);
140}
141
142Rect DeviceContext::getClipBox(HDC dc) {
143 // Get the display dimensions
144 RECT cr;
145 if (!GetClipBox(dc, &cr))
146 throw rdr::SystemException("GetClipBox", GetLastError());
147 return Rect(cr.left, cr.top, cr.right, cr.bottom);
148}
149
150
151DeviceDC::DeviceDC(const TCHAR* deviceName) {
152 dc = ::CreateDC(_T("DISPLAY"), deviceName, NULL, NULL);
153 if (!dc)
154 throw rdr::SystemException("failed to create DeviceDC", GetLastError());
155}
156
157DeviceDC::~DeviceDC() {
158 if (dc)
159 DeleteDC(dc);
160}
161
162
163WindowDC::WindowDC(HWND wnd) : hwnd(wnd) {
164 dc = GetDC(wnd);
165 if (!dc)
166 throw rdr::SystemException("GetDC failed", GetLastError());
167}
168
169WindowDC::~WindowDC() {
170 if (dc)
171 ReleaseDC(hwnd, dc);
172}
173
174
175CompatibleDC::CompatibleDC(HDC existing) {
176 dc = CreateCompatibleDC(existing);
177 if (!dc)
178 throw rdr::SystemException("CreateCompatibleDC failed", GetLastError());
179}
180
181CompatibleDC::~CompatibleDC() {
182 if (dc)
183 DeleteDC(dc);
184}
185
186
187BitmapDC::BitmapDC(HDC hdc, HBITMAP hbitmap) : CompatibleDC(hdc){
188 oldBitmap = (HBITMAP)SelectObject(dc, hbitmap);
189 if (!oldBitmap)
190 throw rdr::SystemException("SelectObject to CompatibleDC failed",
191 GetLastError());
192}
193
194BitmapDC::~BitmapDC() {
195 SelectObject(dc, oldBitmap);
196}