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