/[pearpc]/src/system/ui/win32/sysdisplay.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /src/system/ui/win32/sysdisplay.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 7 months ago) by dpavlin
File size: 13705 byte(s)
import upstream CVS
1 /*
2 * PearPC
3 * sysdisplay.cc - screen access functions for Win32
4 *
5 * Copyright (C) 1999-2004 Sebastian Biallas (sb@biallas.net)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include <cstdio>
22 #include <cstdlib>
23 #include <cstring>
24
25 #include "system/sysvaccel.h"
26 #include "system/display.h"
27 #include "system/sysexcept.h"
28 #include "tools/snprintf.h"
29 #include "configparser.h"
30
31 #undef FASTCALL
32
33 #define WIN32_LEAN_AND_MEAN
34 #include <windows.h>
35 #include <windowsx.h>
36 #include <commctrl.h>
37 #include <process.h>
38
39 #undef FASTCALL
40 #include "system/types.h"
41 #include "syswin.h"
42
43 static byte *winframebuffer = NULL;
44 static HBITMAP gMemoryBitmap = 0;
45 static BITMAPINFO gBitmapInfo;
46
47 Win32Display::Win32Display(const char *name, const DisplayCharacteristics &chr, int redraw_ms)
48 :SystemDisplay(chr, redraw_ms)
49 {
50 mClientChar = chr;
51 convertCharacteristicsToHost(mWinChar, mClientChar);
52 mTitle = strdup(name);
53 mMenuHeight = 28;
54 gMenuHeight = mMenuHeight;
55
56 gFrameBuffer = (byte*)realloc(gFrameBuffer, mClientChar.width
57 * mClientChar.height * mClientChar.bytesPerPixel);
58 winframebuffer = (byte*)realloc(winframebuffer, mWinChar.width
59 * mWinChar.height * mWinChar.bytesPerPixel);
60 memset(gFrameBuffer, 0, mClientChar.width
61 * mClientChar.height * mClientChar.bytesPerPixel);
62 damageFrameBufferAll();
63
64 mHomeMouseX = mWinChar.width/2;
65 mHomeMouseY = mWinChar.height/2;
66 InitializeCriticalSection(&gDrawCS);
67
68 mInvisibleCursor = NULL;
69 }
70
71 Win32Display::~Win32Display()
72 {
73 if (gMemoryBitmap) DeleteObject(gMemoryBitmap);
74
75 DeleteCriticalSection(&gDrawCS);
76
77 free(gFrameBuffer);
78 free(winframebuffer);
79
80 if (mInvisibleCursor) DestroyCursor(mInvisibleCursor);
81 }
82
83 void Win32Display::getHostCharacteristics(Container &modes)
84 {
85 DEVMODE dm;
86 DWORD num = 0;
87 while (EnumDisplaySettings(NULL, num++, &dm)) {
88 switch (dm.dmBitsPerPel) {
89 case 15:
90 case 16:
91 dm.dmBitsPerPel = 2;
92 break;
93 case 32:
94 dm.dmBitsPerPel = 4;
95 break;
96 default:
97 continue;
98 }
99 DisplayCharacteristics *dc = new DisplayCharacteristics;
100 dc->width = dm.dmPelsWidth;
101 dc->height = dm.dmPelsHeight;
102 dc->bytesPerPixel = dm.dmBitsPerPel;
103 dc->scanLineLength = -1;
104 dc->vsyncFrequency = dm.dmDisplayFrequency;
105 dc->redShift = -1;
106 dc->redSize = -1;
107 dc->greenShift = -1;
108 dc->greenSize = -1;
109 dc->blueShift = -1;
110 dc->blueSize = -1;
111 modes.insert(dc);
112 }
113 }
114
115 void Win32Display::convertCharacteristicsToHost(DisplayCharacteristics &aHostChar, const DisplayCharacteristics &aClientChar)
116 {
117 aHostChar = aClientChar;
118 if (!mFullscreen) {
119 HWND dw = GetDesktopWindow();
120 HDC ddc = GetDC(dw);
121 aHostChar.bytesPerPixel = (GetDeviceCaps(ddc, BITSPIXEL)+7)/8;
122 aHostChar.scanLineLength = aHostChar.bytesPerPixel * aHostChar.width;
123 ReleaseDC(dw, ddc);
124 }
125 switch (aHostChar.bytesPerPixel) {
126 case 2:
127 aHostChar.redShift = 10;
128 aHostChar.redSize = 5;
129 aHostChar.greenShift = 5;
130 aHostChar.greenSize = 5;
131 aHostChar.blueShift = 0;
132 aHostChar.blueSize = 5;
133 break;
134 case 4:
135 aHostChar.redShift = 16;
136 aHostChar.redSize = 8;
137 aHostChar.greenShift = 8;
138 aHostChar.greenSize = 8;
139 aHostChar.blueShift = 0;
140 aHostChar.blueSize = 8;
141 break;
142 }
143 }
144
145 bool Win32Display::changeResolution(const DisplayCharacteristics &aClientChar)
146 {
147 if (mFullscreen) {
148 EnterCriticalSection(&gDrawCS);
149 DisplayCharacteristics oldhost = mWinChar;
150 DisplayCharacteristics oldclient = mClientChar;
151 mClientChar = aClientChar;
152 convertCharacteristicsToHost(mWinChar, mClientChar);
153
154 DEVMODE dm;
155 dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
156 // dm.dmBitsPerPel = (mWinChar.bytesPerPixel == 2) ? 15 : 32; // GRRRR
157 dm.dmBitsPerPel = (mWinChar.bytesPerPixel == 2) ? 16 : 32;
158 dm.dmPelsWidth = mWinChar.width;
159 dm.dmPelsHeight = mWinChar.height;
160 ht_printf("*** %d **\n", mWinChar.vsyncFrequency);
161 dm.dmDisplayFrequency = mWinChar.vsyncFrequency;
162 LONG err = ChangeDisplaySettings(&dm, CDS_TEST);
163 if (err != DISP_CHANGE_SUCCESSFUL) {
164 if (mWinChar.bytesPerPixel == 2) {
165 dm.dmBitsPerPel = 16;
166 err = ChangeDisplaySettings(&dm, CDS_TEST);
167 }
168 }
169
170 if (err != DISP_CHANGE_SUCCESSFUL) {
171 mWinChar = oldhost;
172 mClientChar = oldclient;
173 LeaveCriticalSection(&gDrawCS);
174
175 /*
176 * FIXME: maybe we should switch back to windowed mode
177 * here if running in fullscreen mode.
178 */
179
180 if (mFullscreenChanged) {
181 // do something
182 }
183
184 return false;
185 }
186 ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
187 gMenuHeight = 0;
188 gFrameBuffer = (byte*)realloc(gFrameBuffer, mClientChar.width
189 * mClientChar.height * mClientChar.bytesPerPixel);
190 winframebuffer = (byte*)realloc(winframebuffer, mWinChar.width
191 * mWinChar.height * mWinChar.bytesPerPixel);
192 createBitmap();
193 damageFrameBufferAll();
194 mFullscreenChanged = true;
195 LeaveCriticalSection(&gDrawCS);
196 SetWindowLong(gHWNDMain, GWL_STYLE, WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_SYSMENU | WS_OVERLAPPED);
197 SetWindowPos(gHWNDMain, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
198 SetWindowPos(gHWNDMain, HWND_TOPMOST, 0, 0, mWinChar.width, mWinChar.height, 0);
199 ShowWindow(gHWNDMain, SW_SHOWMAXIMIZED);
200 setMouseGrab(true);
201 return true;
202 } else {
203 EnterCriticalSection(&gDrawCS);
204 if (mFullscreenChanged) {
205 // switch out of fullscreen mode
206 gMenuHeight = 28;
207
208 setMouseGrab(false);
209 ChangeDisplaySettings(NULL, 0);
210 }
211
212 /*
213 * get size of desktop first
214 * (windows doesn't allow windows greater than the desktop)
215 */
216 HWND dw = GetDesktopWindow();
217 RECT desktoprect;
218 GetWindowRect(dw, &desktoprect);
219 if (aClientChar.width > (desktoprect.right-desktoprect.left)
220 || aClientChar.height > (desktoprect.bottom-desktoprect.top)) {
221 /*
222 * protect user from himself
223 * What shall we do if switching out of full-
224 * screen mode does not work?
225 */
226 if (mFullscreenChanged) {
227 // FIXME: insert clever code here
228 } else {
229 return false;
230 }
231 }
232 mFullscreenChanged = false;
233 mClientChar = aClientChar;
234 convertCharacteristicsToHost(mWinChar, mClientChar);
235 gFrameBuffer = (byte*)realloc(gFrameBuffer, mClientChar.width
236 * mClientChar.height * mClientChar.bytesPerPixel);
237 winframebuffer = (byte*)realloc(winframebuffer, mWinChar.width
238 * mWinChar.height * mWinChar.bytesPerPixel);
239
240 mHomeMouseX = mWinChar.width/2;
241 mHomeMouseY = mWinChar.height/2;
242 createBitmap();
243 SetWindowLong(gHWNDMain, GWL_STYLE, WS_VISIBLE | WS_SYSMENU | WS_CAPTION | WS_BORDER | WS_MINIMIZEBOX);
244 SetWindowPos(gHWNDMain, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
245 SetWindowPos(gHWNDMain, HWND_TOP, 0, 0, mWinChar.width + GetSystemMetrics(SM_CXFIXEDFRAME) * 2,
246 mWinChar.height + gMenuHeight + GetSystemMetrics(SM_CYFIXEDFRAME) * 2 + GetSystemMetrics(SM_CYCAPTION), 0);
247 LeaveCriticalSection(&gDrawCS);
248
249 RECT rect;
250 RECT rect2;
251 GetWindowRect(gHWNDMain, &rect);
252 GetWindowRect(gHWNDMain, &rect2);
253 rect.right = rect.left+mWinChar.width;
254 rect.bottom = rect.top+mWinChar.height+gMenuHeight;
255
256 AdjustWindowRect(&rect, WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN
257 | WS_CAPTION | WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX, FALSE);
258
259 MoveWindow(gHWNDMain, rect2.left, rect2.top, rect.right-rect.left, rect.bottom-rect.top, TRUE);
260 ShowWindow(gHWNDMain, SW_SHOWNORMAL);
261 }
262 damageFrameBufferAll();
263 return true;
264 }
265
266 int Win32Display::toString(char *buf, int buflen) const
267 {
268 return snprintf(buf, buflen, "Win32");
269 }
270
271 void Win32Display::finishMenu()
272 {
273 menuData = (byte*)malloc(mWinChar.width *
274 mMenuHeight * mWinChar.bytesPerPixel);
275 gMenuBitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
276 gMenuBitmapInfo.bmiHeader.biWidth = mWinChar.width;
277 gMenuBitmapInfo.bmiHeader.biHeight = -mMenuHeight;
278 gMenuBitmapInfo.bmiHeader.biPlanes = 1;
279 gMenuBitmapInfo.bmiHeader.biBitCount = 8*mWinChar.bytesPerPixel;
280 gMenuBitmapInfo.bmiHeader.biCompression = BI_RGB;
281 gMenuBitmapInfo.bmiHeader.biSizeImage =
282 mWinChar.width * mMenuHeight
283 * mWinChar.bytesPerPixel;
284 gMenuBitmapInfo.bmiHeader.biXPelsPerMeter = 4500;
285 gMenuBitmapInfo.bmiHeader.biYPelsPerMeter = 4500;
286 gMenuBitmapInfo.bmiHeader.biClrUsed = 0;
287 gMenuBitmapInfo.bmiHeader.biClrImportant = 0;
288
289 // Is this ugly? Yes!
290 fillRGB(0, 0, mClientChar.width, mClientChar.height, MK_RGB(0xff, 0xff, 0xff));
291 drawMenu();
292 sys_convert_display(mClientChar, mWinChar, gFrameBuffer, winframebuffer, 0, mClientChar.height-1);
293 memmove(menuData, winframebuffer, mWinChar.width * mMenuHeight
294 * mWinChar.bytesPerPixel);
295 InvalidateRect(gHWNDMain, NULL, FALSE);
296 }
297
298 void Win32Display::updateTitle()
299 {
300 String key;
301 int key_toggle_mouse_grab = gKeyboard->getKeyConfig().key_toggle_mouse_grab;
302 SystemKeyboard::convertKeycodeToString(key, key_toggle_mouse_grab);
303 ht_snprintf(mCurTitle, sizeof mCurTitle, "%s - [%s %s mouse]", mTitle,key.contentChar(), (isMouseGrabbed() ? "disables" : "enables"));
304 SetWindowText(gHWNDMain, mCurTitle);
305 }
306
307 void Win32Display::setMouseGrab(bool enable)
308 {
309 if (mMouseGrabbed == enable) return;
310 SystemDisplay::setMouseGrab(enable);
311 if (enable) {
312 mResetMouseX = mCurMouseX;
313 mResetMouseY = mCurMouseY;
314
315 showCursor(false);
316 if (mFullscreenChanged) {
317 SetCursorPos(mHomeMouseX, mHomeMouseY);
318 } else {
319 RECT wndRect;
320 GetWindowRect(gHWNDMain, &wndRect);
321 SetCursorPos(wndRect.left + mHomeMouseX + GetSystemMetrics(SM_CXFIXEDFRAME),
322 wndRect.top + mHomeMouseY + GetSystemMetrics(SM_CYFIXEDFRAME)
323 + GetSystemMetrics(SM_CYCAPTION));
324 }
325 } else {
326 if (mFullscreenChanged) {
327 SetCursorPos(mResetMouseX, mResetMouseY);
328 } else {
329 RECT wndRect;
330 GetWindowRect(gHWNDMain, &wndRect);
331 SetCursorPos(wndRect.left + mResetMouseX + GetSystemMetrics(SM_CXFIXEDFRAME),
332 wndRect.top + mResetMouseY + GetSystemMetrics(SM_CYFIXEDFRAME)
333 + GetSystemMetrics(SM_CYCAPTION));
334 }
335 showCursor(true);
336 }
337 }
338
339 void Win32Display::displayShow()
340 {
341 if (!isExposed()) return;
342
343 uint firstDamagedLine, lastDamagedLine;
344 // We've got problems with races here because gcard_write1/2/4
345 // might set gDamageAreaFirstAddr, gDamageAreaLastAddr.
346 // We can't use mutexes in gcard for speed reasons. So we'll
347 // try to minimize the probability of loosing the race.
348 if (gDamageAreaFirstAddr > gDamageAreaLastAddr+3) {
349 return;
350 }
351 uint damageAreaFirstAddr = gDamageAreaFirstAddr;
352 uint damageAreaLastAddr = gDamageAreaLastAddr;
353 healFrameBuffer();
354 // end of race
355
356 // we enter the critical section early, so that
357 // changeResolution can't conflict here
358 EnterCriticalSection(&gDrawCS);
359
360 damageAreaLastAddr += 3; // this is a hack. For speed reasons we
361 // inaccurately set gDamageAreaLastAddr
362 // to the first (not last) byte accessed
363 // accesses are up to 4 bytes "long".
364
365 firstDamagedLine = damageAreaFirstAddr / (mClientChar.width * mClientChar.bytesPerPixel);
366 lastDamagedLine = damageAreaLastAddr / (mClientChar.width * mClientChar.bytesPerPixel);
367 // Overflow may happen, because of the hack used above
368 // and others, that set lastAddr = 0xfffffff0
369 if (lastDamagedLine >= (uint)mClientChar.height) {
370 lastDamagedLine = mClientChar.height-1;
371 }
372
373 sys_convert_display(mClientChar, mWinChar, gFrameBuffer, winframebuffer, firstDamagedLine, lastDamagedLine);
374
375 HDC hdc = GetDC(gHWNDMain);
376
377 SetDIBitsToDevice(
378 hdc,
379 0,
380 gMenuHeight+firstDamagedLine,
381 mWinChar.width,
382 lastDamagedLine-firstDamagedLine+1, // number of lines to draw
383 0,
384 mWinChar.height-lastDamagedLine-1, // line src-position (0,0 = lower left)
385 0,
386 mWinChar.height,
387 winframebuffer, &gBitmapInfo, DIB_RGB_COLORS);
388
389 ReleaseDC(gHWNDMain, hdc);
390
391 LeaveCriticalSection(&gDrawCS);
392 }
393
394 void Win32Display::createBitmap()
395 {
396 if (gMemoryBitmap) DeleteObject(gMemoryBitmap);
397 HDC hdc = GetDC(gHWNDMain);
398 gMemoryBitmap = CreateCompatibleBitmap(hdc, mWinChar.width, mWinChar.height);
399 ReleaseDC(gHWNDMain, hdc);
400 gBitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
401 gBitmapInfo.bmiHeader.biWidth = mWinChar.width;
402 // Height is negative for top-down bitmap
403 gBitmapInfo.bmiHeader.biHeight = -mWinChar.height;
404 gBitmapInfo.bmiHeader.biPlanes = 1;
405 gBitmapInfo.bmiHeader.biBitCount = 8*mWinChar.bytesPerPixel;
406 gBitmapInfo.bmiHeader.biCompression = BI_RGB;
407 gBitmapInfo.bmiHeader.biSizeImage =
408 mWinChar.width * mWinChar.height
409 * mWinChar.bytesPerPixel;
410 gBitmapInfo.bmiHeader.biXPelsPerMeter = 4500;
411 gBitmapInfo.bmiHeader.biYPelsPerMeter = 4500;
412 gBitmapInfo.bmiHeader.biClrUsed = 0;
413 gBitmapInfo.bmiHeader.biClrImportant = 0;
414 }
415
416 void Win32Display::initCursor()
417 {
418 mVisibleCursor = GetCursor();
419
420 int cx = GetSystemMetrics(SM_CXCURSOR);
421 int cy = GetSystemMetrics(SM_CYCURSOR);
422
423 BYTE andplane[cx*cy];
424 BYTE xorplane[cx*cy];
425
426 memset(andplane, 0xff, cx*cy);
427 memset(xorplane, 0, cx*cy);
428 mInvisibleCursor = CreateCursor(NULL, 0, 0, cx, cy, andplane, xorplane);
429 }
430
431 void Win32Display::showCursor(bool visible)
432 {
433 SetClassLong(gHWNDMain, GCL_HCURSOR, visible ? (LONG)mVisibleCursor : (LONG)mInvisibleCursor);
434 }
435
436 SystemDisplay *allocSystemDisplay(const char *title, const DisplayCharacteristics &chr, int redraw_ms)
437 {
438 if (gDisplay) return gDisplay;
439 return new Win32Display(title, chr, redraw_ms);
440 }

  ViewVC Help
Powered by ViewVC 1.1.26