]> git.saurik.com Git - wxWidgets.git/blob - src/os2/utilsgui.cpp
fix crash in wxWindowGTK::GTKHandleUnrealize(), closes #14752
[wxWidgets.git] / src / os2 / utilsgui.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/os2/utilsgui.cpp
3 // Purpose: Various utility functions only available in GUI
4 // Author: David Webster
5 // Modified by:
6 // Created: 20.08.2003 (extracted from os2/utils.cpp)
7 // RCS-ID: $Id$
8 // Copyright: (c) David Webster
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #ifndef WX_PRECOMP
28 #include "wx/utils.h"
29 #include "wx/app.h"
30 #include "wx/cursor.h"
31 #include "wx/font.h"
32 #include "wx/timer.h"
33 #endif //WX_PRECOMP
34
35 #include "wx/apptrait.h"
36 #include "wx/os2/private/timer.h"
37 #include "wx/evtloop.h"
38
39 #include "wx/os2/private.h" // includes <windows.h>
40
41 // ============================================================================
42 // implementation
43 // ============================================================================
44
45 // Emit a beeeeeep
46 void wxBell()
47 {
48 DosBeep(1000,1000); // 1kHz during 1 sec.
49 }
50
51 // ----------------------------------------------------------------------------
52 // functions to work with .INI files
53 // ----------------------------------------------------------------------------
54
55 // Sleep for nSecs seconds. Attempt a Windows implementation using timers.
56 static bool inTimer = false;
57
58 class wxSleepTimer: public wxTimer
59 {
60 public:
61 inline void Notify()
62 {
63 inTimer = false;
64 Stop();
65 }
66 };
67
68 // ---------------------------------------------------------------------------
69 // helper functions for showing a "busy" cursor
70 // ---------------------------------------------------------------------------
71
72 HCURSOR gs_wxBusyCursor = 0; // new, busy cursor
73 HCURSOR gs_wxBusyCursorOld = 0; // old cursor
74 static int gs_wxBusyCursorCount = 0;
75
76 // Set the cursor to the busy cursor for all windows
77 void wxBeginBusyCursor(const wxCursor* pCursor)
78 {
79 if ( gs_wxBusyCursorCount++ == 0 )
80 {
81 gs_wxBusyCursor = (HCURSOR)pCursor->GetHCURSOR();
82 ::WinSetPointer(HWND_DESKTOP, (HPOINTER)gs_wxBusyCursor);
83 }
84 //else: nothing to do, already set
85 }
86
87 // Restore cursor to normal
88 void wxEndBusyCursor()
89 {
90 wxCHECK_RET( gs_wxBusyCursorCount > 0
91 ,wxT("no matching wxBeginBusyCursor() for wxEndBusyCursor()")
92 );
93
94 if (--gs_wxBusyCursorCount == 0)
95 {
96 ::WinSetPointer(HWND_DESKTOP, (HPOINTER)gs_wxBusyCursorOld);
97 gs_wxBusyCursorOld = 0;
98 }
99 }
100
101 // true if we're between the above two calls
102 bool wxIsBusy()
103 {
104 return (gs_wxBusyCursorCount > 0);
105 }
106
107 // Check whether this window wants to process messages, e.g. Stop button
108 // in long calculations.
109 bool wxCheckForInterrupt( wxWindow* pWnd )
110 {
111 if(pWnd)
112 {
113 QMSG vMsg;
114 HAB hab = 0;
115 HWND hwndFilter = NULLHANDLE;
116
117 while(::WinPeekMsg(hab, &vMsg, hwndFilter, 0, 0, PM_REMOVE))
118 {
119 ::WinDispatchMsg(hab, &vMsg);
120 }
121 return true;//*** temporary?
122 }
123 else
124 {
125 wxFAIL_MSG(wxT("pWnd==NULL !!!"));
126 return false;//*** temporary?
127 }
128 }
129
130 // ----------------------------------------------------------------------------
131 // get display info
132 // ----------------------------------------------------------------------------
133
134 // See also the wxGetMousePosition in window.cpp
135 // Deprecated: use wxPoint wxGetMousePosition() instead
136 void wxGetMousePosition(
137 int* pX
138 , int* pY
139 )
140 {
141 POINTL vPt;
142
143 ::WinQueryPointerPos(HWND_DESKTOP, &vPt);
144 *pX = vPt.x;
145 *pY = vPt.y;
146 };
147
148 // Return true if we have a colour display
149 bool wxColourDisplay()
150 {
151 #if 0
152 HPS hpsScreen;
153 HDC hdcScreen;
154 LONG lColors;
155
156 hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
157 hdcScreen = ::GpiQueryDevice(hpsScreen);
158 ::DevQueryCaps(hdcScreen, CAPS_COLORS, 1L, &lColors);
159 return(lColors > 1L);
160 #else
161 // I don't see how the PM display could not be color. Besides, this
162 // was leaking DCs and PSs!!! MN
163 return true;
164 #endif
165 }
166
167 // Returns depth of screen
168 int wxDisplayDepth()
169 {
170 HPS hpsScreen;
171 HDC hdcScreen;
172 LONG lPlanes;
173 LONG lBitsPerPixel;
174 static LONG nDepth = 0;
175
176 // The screen colordepth ain't gonna change. No reason to query
177 // it over and over!
178 if (!nDepth) {
179 hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
180 hdcScreen = ::GpiQueryDevice(hpsScreen);
181 ::DevQueryCaps(hdcScreen, CAPS_COLOR_PLANES, 1L, &lPlanes);
182 ::DevQueryCaps(hdcScreen, CAPS_COLOR_BITCOUNT, 1L, &lBitsPerPixel);
183
184 nDepth = (int)(lPlanes * lBitsPerPixel);
185 ::DevCloseDC(hdcScreen);
186 ::WinReleasePS(hpsScreen);
187 }
188 return (nDepth);
189 }
190
191 // Get size of display
192 void wxDisplaySize(
193 int* pWidth
194 , int* pHeight
195 )
196 {
197 HPS hpsScreen;
198 HDC hdcScreen;
199 static LONG lWidth = 0;
200 static LONG lHeight = 0;
201
202 // The screen size ain't gonna change either so just cache the values
203 if (!lWidth) {
204 hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
205 hdcScreen = ::GpiQueryDevice(hpsScreen);
206 ::DevQueryCaps(hdcScreen, CAPS_WIDTH, 1L, &lWidth);
207 ::DevQueryCaps(hdcScreen, CAPS_HEIGHT, 1L, &lHeight);
208 ::DevCloseDC(hdcScreen);
209 ::WinReleasePS(hpsScreen);
210 }
211 if (pWidth)
212 *pWidth = (int)lWidth;
213 if (pHeight)
214 *pHeight = (int)lHeight;
215 }
216
217 void wxDisplaySizeMM(
218 int* pWidth
219 , int* pHeight
220 )
221 {
222 HPS hpsScreen;
223 HDC hdcScreen;
224
225 hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
226 hdcScreen = ::GpiQueryDevice(hpsScreen);
227
228 if (pWidth)
229 ::DevQueryCaps( hdcScreen
230 ,CAPS_HORIZONTAL_RESOLUTION
231 ,1L
232 ,(PLONG)pWidth
233 );
234 if (pHeight)
235 ::DevQueryCaps( hdcScreen
236 ,CAPS_VERTICAL_RESOLUTION
237 ,1L
238 ,(PLONG)pHeight
239 );
240 ::DevCloseDC(hdcScreen);
241 ::WinReleasePS(hpsScreen);
242 }
243
244 void wxClientDisplayRect(int *x, int *y, int *width, int *height)
245 {
246 // This is supposed to return desktop dimensions minus any window
247 // manager panels, menus, taskbars, etc. If there is a way to do that
248 // for this platform please fix this function, otherwise it defaults
249 // to the entire desktop.
250 if (x) *x = 0;
251 if (y) *y = 0;
252 wxDisplaySize(width, height);
253 }
254
255 void wxGUIAppTraits::InitializeGui(unsigned long &ulHab)
256 {
257 ulHab = ::WinInitialize(0);
258 }
259
260 void wxGUIAppTraits::TerminateGui(unsigned long ulHab)
261 {
262 ::WinTerminate(ulHab);
263 }
264
265 wxPortId wxGUIAppTraits::GetToolkitVersion(int *verMaj, int *verMin) const
266 {
267 // How to get version of PM ? I guess, just reusing the OS version is OK.
268 (void) wxGetOsVersion(verMaj, verMin);
269 return wxPORT_OS2;
270 }
271
272 wxTimerImpl* wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
273 {
274 return new wxOS2TimerImpl(timer);
275 }
276
277 wxEventLoopBase* wxGUIAppTraits::CreateEventLoop()
278 {
279 return new wxEventLoop;
280 }
281
282 // ---------------------------------------------------------------------------
283 // window information functions
284 // ---------------------------------------------------------------------------
285
286 wxString WXDLLEXPORT wxGetWindowText( WXHWND hWnd )
287 {
288 wxString vStr;
289
290 if ( hWnd )
291 {
292 long lLen = ::WinQueryWindowTextLength((HWND)hWnd) + 1;
293 ::WinQueryWindowText((HWND)hWnd, lLen, (PSZ)(wxChar*)wxStringBuffer(vStr, lLen));
294 }
295
296 return vStr;
297 }
298
299 wxString WXDLLEXPORT wxGetWindowClass( WXHWND hWnd )
300 {
301 wxString vStr;
302 if ( hWnd )
303 {
304 int nLen = 256; // some starting value
305
306 for ( ;; )
307 {
308 int nCount = ::WinQueryClassName((HWND)hWnd, nLen, (PSZ)(wxChar*)wxStringBuffer(vStr, nLen));
309
310 if (nCount == nLen )
311 {
312 // the class name might have been truncated, retry with larger
313 // buffer
314 nLen *= 2;
315 }
316 else
317 {
318 break;
319 }
320 }
321 }
322 return vStr;
323 }
324
325 WXWORD WXDLLEXPORT wxGetWindowId(
326 WXHWND hWnd
327 )
328 {
329 return ::WinQueryWindowUShort((HWND)hWnd, QWS_ID);
330 }
331
332 void wxDrawBorder(
333 HPS hPS
334 , RECTL& rRect
335 , WXDWORD dwStyle
336 )
337 {
338 POINTL vPoint[2];
339
340 vPoint[0].x = rRect.xLeft;
341 vPoint[0].y = rRect.yBottom;
342 ::GpiMove(hPS, &vPoint[0]);
343 if (dwStyle & wxSIMPLE_BORDER ||
344 dwStyle & wxSTATIC_BORDER)
345 {
346 vPoint[1].x = rRect.xRight - 1;
347 vPoint[1].y = rRect.yTop - 1;
348 ::GpiBox( hPS
349 ,DRO_OUTLINE
350 ,&vPoint[1]
351 ,0L
352 ,0L
353 );
354 }
355 if (dwStyle & wxSUNKEN_BORDER)
356 {
357 LINEBUNDLE vLineBundle;
358
359 vLineBundle.lColor = 0x00FFFFFF; // WHITE
360 vLineBundle.usMixMode = FM_OVERPAINT;
361 vLineBundle.fxWidth = 2;
362 vLineBundle.lGeomWidth = 2;
363 vLineBundle.usType = LINETYPE_SOLID;
364 vLineBundle.usEnd = 0;
365 vLineBundle.usJoin = 0;
366 ::GpiSetAttrs( hPS
367 ,PRIM_LINE
368 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
369 ,0L
370 ,&vLineBundle
371 );
372 vPoint[1].x = rRect.xRight - 1;
373 vPoint[1].y = rRect.yTop - 1;
374 ::GpiBox( hPS
375 ,DRO_OUTLINE
376 ,&vPoint[1]
377 ,0L
378 ,0L
379 );
380 vPoint[0].x = rRect.xLeft + 1;
381 vPoint[0].y = rRect.yBottom + 1;
382 ::GpiMove(hPS, &vPoint[0]);
383 vPoint[1].x = rRect.xRight - 2;
384 vPoint[1].y = rRect.yTop - 2;
385 ::GpiBox( hPS
386 ,DRO_OUTLINE
387 ,&vPoint[1]
388 ,0L
389 ,0L
390 );
391
392 vLineBundle.lColor = 0x00000000; // BLACK
393 vLineBundle.usMixMode = FM_OVERPAINT;
394 vLineBundle.fxWidth = 2;
395 vLineBundle.lGeomWidth = 2;
396 vLineBundle.usType = LINETYPE_SOLID;
397 vLineBundle.usEnd = 0;
398 vLineBundle.usJoin = 0;
399 ::GpiSetAttrs( hPS
400 ,PRIM_LINE
401 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
402 ,0L
403 ,&vLineBundle
404 );
405 vPoint[0].x = rRect.xLeft + 2;
406 vPoint[0].y = rRect.yBottom + 2;
407 ::GpiMove(hPS, &vPoint[0]);
408 vPoint[1].x = rRect.xLeft + 2;
409 vPoint[1].y = rRect.yTop - 3;
410 ::GpiLine(hPS, &vPoint[1]);
411 vPoint[1].x = rRect.xRight - 3;
412 vPoint[1].y = rRect.yTop - 3;
413 ::GpiLine(hPS, &vPoint[1]);
414
415 vPoint[0].x = rRect.xLeft + 3;
416 vPoint[0].y = rRect.yBottom + 3;
417 ::GpiMove(hPS, &vPoint[0]);
418 vPoint[1].x = rRect.xLeft + 3;
419 vPoint[1].y = rRect.yTop - 4;
420 ::GpiLine(hPS, &vPoint[1]);
421 vPoint[1].x = rRect.xRight - 4;
422 vPoint[1].y = rRect.yTop - 4;
423 ::GpiLine(hPS, &vPoint[1]);
424 }
425 if (dwStyle & wxDOUBLE_BORDER)
426 {
427 LINEBUNDLE vLineBundle;
428
429 vLineBundle.lColor = 0x00FFFFFF; // WHITE
430 vLineBundle.usMixMode = FM_OVERPAINT;
431 vLineBundle.fxWidth = 2;
432 vLineBundle.lGeomWidth = 2;
433 vLineBundle.usType = LINETYPE_SOLID;
434 vLineBundle.usEnd = 0;
435 vLineBundle.usJoin = 0;
436 ::GpiSetAttrs( hPS
437 ,PRIM_LINE
438 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
439 ,0L
440 ,&vLineBundle
441 );
442 vPoint[1].x = rRect.xRight - 1;
443 vPoint[1].y = rRect.yTop - 1;
444 ::GpiBox( hPS
445 ,DRO_OUTLINE
446 ,&vPoint[1]
447 ,0L
448 ,0L
449 );
450 vLineBundle.lColor = 0x00000000; // WHITE
451 vLineBundle.usMixMode = FM_OVERPAINT;
452 vLineBundle.fxWidth = 2;
453 vLineBundle.lGeomWidth = 2;
454 vLineBundle.usType = LINETYPE_SOLID;
455 vLineBundle.usEnd = 0;
456 vLineBundle.usJoin = 0;
457 ::GpiSetAttrs( hPS
458 ,PRIM_LINE
459 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
460 ,0L
461 ,&vLineBundle
462 );
463 vPoint[0].x = rRect.xLeft + 2;
464 vPoint[0].y = rRect.yBottom + 2;
465 ::GpiMove(hPS, &vPoint[0]);
466 vPoint[1].x = rRect.xRight - 2;
467 vPoint[1].y = rRect.yTop - 2;
468 ::GpiBox( hPS
469 ,DRO_OUTLINE
470 ,&vPoint[1]
471 ,0L
472 ,0L
473 );
474 vLineBundle.lColor = 0x00FFFFFF; // BLACK
475 vLineBundle.usMixMode = FM_OVERPAINT;
476 vLineBundle.fxWidth = 2;
477 vLineBundle.lGeomWidth = 2;
478 vLineBundle.usType = LINETYPE_SOLID;
479 vLineBundle.usEnd = 0;
480 vLineBundle.usJoin = 0;
481 ::GpiSetAttrs( hPS
482 ,PRIM_LINE
483 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
484 ,0L
485 ,&vLineBundle
486 );
487 vPoint[0].x = rRect.xLeft + 3;
488 vPoint[0].y = rRect.yBottom + 3;
489 ::GpiMove(hPS, &vPoint[0]);
490 vPoint[1].x = rRect.xRight - 3;
491 vPoint[1].y = rRect.yTop - 3;
492 ::GpiBox( hPS
493 ,DRO_OUTLINE
494 ,&vPoint[1]
495 ,0L
496 ,0L
497 );
498 }
499 if (dwStyle & wxRAISED_BORDER)
500 {
501 LINEBUNDLE vLineBundle;
502
503 vLineBundle.lColor = 0x00000000; // BLACK
504 vLineBundle.usMixMode = FM_OVERPAINT;
505 vLineBundle.fxWidth = 2;
506 vLineBundle.lGeomWidth = 2;
507 vLineBundle.usType = LINETYPE_SOLID;
508 vLineBundle.usEnd = 0;
509 vLineBundle.usJoin = 0;
510 ::GpiSetAttrs( hPS
511 ,PRIM_LINE
512 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
513 ,0L
514 ,&vLineBundle
515 );
516 vPoint[1].x = rRect.xRight - 1;
517 vPoint[1].y = rRect.yTop - 1;
518 ::GpiBox( hPS
519 ,DRO_OUTLINE
520 ,&vPoint[1]
521 ,0L
522 ,0L
523 );
524 vPoint[0].x = rRect.xLeft + 1;
525 vPoint[0].y = rRect.yBottom + 1;
526 ::GpiMove(hPS, &vPoint[0]);
527 vPoint[1].x = rRect.xRight - 2;
528 vPoint[1].y = rRect.yTop - 2;
529 ::GpiBox( hPS
530 ,DRO_OUTLINE
531 ,&vPoint[1]
532 ,0L
533 ,0L
534 );
535
536 vLineBundle.lColor = 0x00FFFFFF; // WHITE
537 vLineBundle.usMixMode = FM_OVERPAINT;
538 vLineBundle.fxWidth = 2;
539 vLineBundle.lGeomWidth = 2;
540 vLineBundle.usType = LINETYPE_SOLID;
541 vLineBundle.usEnd = 0;
542 vLineBundle.usJoin = 0;
543 ::GpiSetAttrs( hPS
544 ,PRIM_LINE
545 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
546 ,0L
547 ,&vLineBundle
548 );
549 vPoint[0].x = rRect.xLeft + 2;
550 vPoint[0].y = rRect.yBottom + 2;
551 ::GpiMove(hPS, &vPoint[0]);
552 vPoint[1].x = rRect.xLeft + 2;
553 vPoint[1].y = rRect.yTop - 3;
554 ::GpiLine(hPS, &vPoint[1]);
555 vPoint[1].x = rRect.xRight - 3;
556 vPoint[1].y = rRect.yTop - 3;
557 ::GpiLine(hPS, &vPoint[1]);
558
559 vPoint[0].x = rRect.xLeft + 3;
560 vPoint[0].y = rRect.yBottom + 3;
561 ::GpiMove(hPS, &vPoint[0]);
562 vPoint[1].x = rRect.xLeft + 3;
563 vPoint[1].y = rRect.yTop - 4;
564 ::GpiLine(hPS, &vPoint[1]);
565 vPoint[1].x = rRect.xRight - 4;
566 vPoint[1].y = rRect.yTop - 4;
567 ::GpiLine(hPS, &vPoint[1]);
568 }
569 } // end of wxDrawBorder
570
571 void wxOS2SetFont(
572 HWND hWnd
573 , const wxFont& rFont
574 )
575 {
576 char zFont[128];
577 char zFacename[30];
578 char zWeight[30];
579 char zStyle[30];
580
581 if (hWnd == NULLHANDLE)
582 return;
583
584 //
585 // The fonts available for Presentation Params are just a few
586 // outline fonts, the rest are available to the GPI, so we must
587 // map the families to one of these three
588 //
589 switch(rFont.GetFamily())
590 {
591 case wxSCRIPT:
592 strcpy(zFacename, "Script");
593 break;
594
595 case wxDECORATIVE:
596 strcpy(zFacename, "WarpSans");
597 break;
598
599 case wxROMAN:
600 strcpy(zFacename,"Times New Roman");
601 break;
602
603 case wxTELETYPE:
604 strcpy(zFacename, "Courier New");
605 break;
606
607 case wxMODERN:
608 strcpy(zFacename, "Courier New");
609 break;
610
611 case wxDEFAULT:
612 default:
613 case wxSWISS:
614 strcpy(zFacename, "Helvetica");
615 break;
616 }
617
618 switch(rFont.GetWeight())
619 {
620 default:
621 case wxNORMAL:
622 case wxLIGHT:
623 zWeight[0] = '\0';
624 break;
625
626 case wxBOLD:
627 case wxFONTWEIGHT_MAX:
628 strcpy(zWeight, "Bold");
629 break;
630 }
631
632 switch(rFont.GetStyle())
633 {
634 case wxITALIC:
635 case wxSLANT:
636 strcpy(zStyle, "Italic");
637 break;
638
639 default:
640 zStyle[0] = '\0';
641 break;
642 }
643 sprintf(zFont, "%d.%s", rFont.GetPointSize(), zFacename);
644 if (zWeight[0] != '\0')
645 {
646 strcat(zFont, " ");
647 strcat(zFont, zWeight);
648 }
649 if (zStyle[0] != '\0')
650 {
651 strcat(zFont, " ");
652 strcat(zFont, zStyle);
653 }
654 ::WinSetPresParam(hWnd, PP_FONTNAMESIZE, strlen(zFont) + 1, (PVOID)zFont);
655 } // end of wxOS2SetFont
656
657 // ---------------------------------------------------------------------------
658 // Helper for taking a regular bitmap and giving it a disabled look
659 // ---------------------------------------------------------------------------
660 wxBitmap wxDisableBitmap(
661 const wxBitmap& rBmp
662 , long lColor
663 )
664 {
665 wxMask* pMask = rBmp.GetMask();
666
667 if (!pMask)
668 return(wxNullBitmap);
669
670 DEVOPENSTRUC vDop = {0L, "DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
671 SIZEL vSize = {0, 0};
672 HDC hDC = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDop, NULLHANDLE);
673 HPS hPS = ::GpiCreatePS(vHabmain, hDC, &vSize, PU_PELS | GPIA_ASSOC);
674 BITMAPINFOHEADER2 vHeader;
675 BITMAPINFO2 vInfo;
676 ERRORID vError;
677 wxString sError;
678 HBITMAP hBitmap = (HBITMAP)rBmp.GetHBITMAP();
679 HBITMAP hOldBitmap = NULLHANDLE;
680 HBITMAP hOldMask = NULLHANDLE;
681 HBITMAP hMask = (HBITMAP)rBmp.GetMask()->GetMaskBitmap();
682 unsigned char* pucBits; // buffer that will contain the bitmap data
683 unsigned char* pucData; // pointer to use to traverse bitmap data
684 unsigned char* pucBitsMask; // buffer that will contain the mask data
685 unsigned char* pucDataMask; // pointer to use to traverse mask data
686 LONG lScans = 0L;
687 LONG lScansSet = 0L;
688 bool bpp16 = (wxDisplayDepth() == 16);
689
690 memset(&vHeader, '\0', 16);
691 vHeader.cbFix = 16;
692
693 memset(&vInfo, '\0', 16);
694 vInfo.cbFix = 16;
695 vInfo.cx = (ULONG)rBmp.GetWidth();
696 vInfo.cy = (ULONG)rBmp.GetHeight();
697 vInfo.cPlanes = 1;
698 vInfo.cBitCount = 24; // Set to desired count going in
699
700 //
701 // Create the buffers for data....all wxBitmaps are 24 bit internally
702 //
703 int nBytesPerLine = rBmp.GetWidth() * 3;
704 int nSizeDWORD = sizeof(DWORD);
705 int nLineBoundary = nBytesPerLine % nSizeDWORD;
706 int nPadding = 0;
707 int i;
708 int j;
709
710 //
711 // Bitmap must be in a double-word aligned address so we may
712 // have some padding to worry about
713 //
714 if (nLineBoundary > 0)
715 {
716 nPadding = nSizeDWORD - nLineBoundary;
717 nBytesPerLine += nPadding;
718 }
719 pucBits = (unsigned char *)malloc(nBytesPerLine * rBmp.GetHeight());
720 memset(pucBits, '\0', (nBytesPerLine * rBmp.GetHeight()));
721 pucBitsMask = (unsigned char *)malloc(nBytesPerLine * rBmp.GetHeight());
722 memset(pucBitsMask, '\0', (nBytesPerLine * rBmp.GetHeight()));
723
724 //
725 // Extract the bitmap and mask data
726 //
727 if ((hOldBitmap = ::GpiSetBitmap(hPS, hBitmap)) == HBM_ERROR)
728 {
729 vError = ::WinGetLastError(vHabmain);
730 sError = wxPMErrorToStr(vError);
731 }
732 ::GpiQueryBitmapInfoHeader(hBitmap, &vHeader);
733 vInfo.cBitCount = 24;
734 if ((lScans = ::GpiQueryBitmapBits( hPS
735 ,0L
736 ,(LONG)rBmp.GetHeight()
737 ,(PBYTE)pucBits
738 ,&vInfo
739 )) == GPI_ALTERROR)
740 {
741 vError = ::WinGetLastError(vHabmain);
742 sError = wxPMErrorToStr(vError);
743 }
744 if ((hOldMask = ::GpiSetBitmap(hPS, hMask)) == HBM_ERROR)
745 {
746 vError = ::WinGetLastError(vHabmain);
747 sError = wxPMErrorToStr(vError);
748 }
749 ::GpiQueryBitmapInfoHeader(hMask, &vHeader);
750 vInfo.cBitCount = 24;
751 if ((lScans = ::GpiQueryBitmapBits( hPS
752 ,0L
753 ,(LONG)rBmp.GetHeight()
754 ,(PBYTE)pucBitsMask
755 ,&vInfo
756 )) == GPI_ALTERROR)
757 {
758 vError = ::WinGetLastError(vHabmain);
759 sError = wxPMErrorToStr(vError);
760 }
761 if (( hMask = ::GpiSetBitmap(hPS, hOldMask)) == HBM_ERROR)
762 {
763 vError = ::WinGetLastError(vHabmain);
764 sError = wxPMErrorToStr(vError);
765 }
766 pucData = pucBits;
767 pucDataMask = pucBitsMask;
768
769 //
770 // Get the mask value
771 //
772 for (i = 0; i < rBmp.GetHeight(); i++)
773 {
774 for (j = 0; j < rBmp.GetWidth(); j++)
775 {
776 // Byte 1
777 if (bpp16 && *pucDataMask == 0xF8) // 16 bit display gobblygook
778 {
779 *pucData = 0x7F;
780 pucData++;
781 }
782 else if (*pucDataMask == 0xFF) // set to grey
783 {
784 *pucData = 0x7F;
785 pucData++;
786 }
787 else
788 {
789 *pucData = ((unsigned char)(lColor >> 16));
790 pucData++;
791 }
792
793 // Byte 2
794 if (bpp16 && *(pucDataMask + 1) == 0xFC) // 16 bit display gobblygook
795 {
796 *pucData = 0x7F;
797 pucData++;
798 }
799 else if (*(pucDataMask + 1) == 0xFF) // set to grey
800 {
801 *pucData = 0x7F;
802 pucData++;
803 }
804 else
805 {
806 *pucData = ((unsigned char)(lColor >> 8));
807 pucData++;
808 }
809
810 // Byte 3
811 if (bpp16 && *(pucDataMask + 2) == 0xF8) // 16 bit display gobblygook
812 {
813 *pucData = 0x7F;
814 pucData++;
815 }
816 else if (*(pucDataMask + 2) == 0xFF) // set to grey
817 {
818 *pucData = 0x7F;
819 pucData++;
820 }
821 else
822 {
823 *pucData = ((unsigned char)lColor);
824 pucData++;
825 }
826 pucDataMask += 3;
827 }
828 for (j = 0; j < nPadding; j++)
829 {
830 pucData++;
831 pucDataMask++;
832 }
833 }
834
835 //
836 // Create a new bitmap and set the modified bits
837 //
838 wxBitmap vNewBmp( rBmp.GetWidth()
839 ,rBmp.GetHeight()
840 ,24
841 );
842 HBITMAP hNewBmp = (HBITMAP)vNewBmp.GetHBITMAP();
843
844 if ((hOldBitmap = ::GpiSetBitmap(hPS, hNewBmp)) == HBM_ERROR)
845 {
846 vError = ::WinGetLastError(vHabmain);
847 sError = wxPMErrorToStr(vError);
848 }
849 if ((lScansSet = ::GpiSetBitmapBits( hPS
850 ,0L
851 ,(LONG)rBmp.GetHeight()
852 ,(PBYTE)pucBits
853 ,&vInfo
854 )) == GPI_ALTERROR)
855
856 {
857 vError = ::WinGetLastError(vHabmain);
858 sError = wxPMErrorToStr(vError);
859 }
860 wxMask* pNewMask;
861
862 pNewMask = new wxMask(pMask->GetMaskBitmap());
863 vNewBmp.SetMask(pNewMask);
864 free(pucBits);
865 ::GpiSetBitmap(hPS, NULLHANDLE);
866 ::GpiDestroyPS(hPS);
867 ::DevCloseDC(hDC);
868 if (vNewBmp.IsOk())
869 return(vNewBmp);
870 return(wxNullBitmap);
871 } // end of wxDisableBitmap
872
873 COLORREF wxColourToRGB(
874 const wxColour& rColor
875 )
876 {
877 return(OS2RGB(rColor.Red(), rColor.Green(), rColor.Blue()));
878 } // end of wxColourToRGB