/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide 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 dpavlin 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