source: trunk/src/helpers/shapewin.c@ 14

Last change on this file since 14 was 14, checked in by umoeller, 25 years ago

Major updates; timers, LVM, miscellaneous.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 53.5 KB
Line 
1
2/*
3 *@@sourcefile shapewin.c:
4 * contains helper functions for "shaped" PM windows which
5 * can be non-rectangular in shape and have transparency.
6 *
7 * This file is new with V0.85.
8 *
9 * Usage: All PM programs.
10 *
11 * Function prefixes:
12 * -- shp* shape window functions
13 *
14 * This file consists of two parts:
15 *
16 * *** Part 1 ***
17 *
18 * The code in Part 1 implements the "Shape" window. This is used
19 * to display a bitmap on the screen with transparency.
20 *
21 * Really, it is not the "Shape" window which displays the bitmap.
22 * Since PM can only handle rectangular windows, as many subwindows
23 * as required are created, which are only managed by the (invisible)
24 * "Shape" window.
25 *
26 * See shp_fnwpShapeMgr for a window hierarchy.
27 *
28 * If you are not using the frame window functions in Part 2, the
29 * shape window class must be registered like this (the declarations
30 * are in shapewin.h):
31 *
32 + WinRegisterClass(
33 + hab, // anchor block handle
34 + SHAPE_WINDOW_CLASS, // class name (shapewin.h)
35 + shp_fnwpShapeMgr, // window procedure (in this file)
36 + 0L, // default window style
37 + sizeof(PVOID)) ; // class data size
38 *
39 * You can then create shape windows using WinCreateWindow():
40 + hwndShape = WinCreateWindow(
41 + hwndParent, // see remark (2)
42 + SHAPE_WINDOW_CLASS, // class name (shapewin.h)
43 + pszName, // doesn't matter
44 + flStyle, // can be 0
45 + x, y, cx, cy, // can all be 0; shape window
46 + // size depends on bitmap
47 + hwndOwner, // see remark (2)
48 + hwndInsertBehind, // should be HWND_TOP
49 + id,
50 + pCtlData, // *SHPCTLDATA, see remark (1)
51 + pPresParams); // NULL
52 *
53 * Remarks:
54 *
55 * 1) Shape windows _require_ a SHPCTLDATA structure for input with
56 * the pCtlData parameter of WinCreateWindow. This structure
57 * must contain the following:
58 + SHORT cx, cy ; // bitmap size
59 + HPS hpsMask; // HPS with bitmap selected into
60 + HPS hpsDraw; // HPS used for drawing the bitmap
61 *
62 * Note that the bitmap in hpsMask determines the drawing mask
63 * of the bitmap, while the bitmap in hpsDraw determines the
64 * bitmap to be drawn. You can use the same HPS (and thus
65 * the same bitmap) for both, but you can also use different
66 * ones.
67 *
68 * You _must_ select the bitmap(s) to be displayed into the HPS's,
69 * using GpiSetBitmap, or nothing will work. shpLoadBitmap
70 * in Part 2 of this file offers you a one-shot function for
71 * loading a bitmap either from resources or a PM 1.3 *.BMP
72 * file.
73 *
74 * Transparency is determined according to the most lower-left
75 * pixel of the bitmap in hpsMask. That is, all hpsDraw bitmap
76 * pixels which have the same color as hpsMask pixel (0, 0)
77 * will be made transparent.
78 *
79 * During window creation, the shape window analyzes the bitmap
80 * which was selected into hpsMask and creates lots of rectangular
81 * PM windows as neccessary. This is dependent of the
82 * "transparency" pixels of the bitmap.
83 *
84 * There is no limit for the size of the bitmap (in the HPS's).
85 * But you should be very careful with large bitmaps, because
86 * this can block the system forever. Shape windows are real
87 * CPU hogs. The number of PM subwindows created depends on the
88 * size of the bitmap and on the transparency. The calculations
89 * are line-based:
90 * -- each line is examined, and a PM window is created for
91 * each line of the input bitmap;
92 * -- if this line contains "transparency" pixels, more PM
93 * windows are created accordingly for that line.
94 * -- However, if several vertically adjacent subwindows have
95 * the same left and right coordinates, they are combined
96 * into one window.
97 *
98 * As a result, the more single transparent pixels you have,
99 * the more windows need to be created. The more rectangular
100 * transparent areas you have, the less windows need to be
101 * created.
102 *
103 * 2) The "Shape" window requires both a parent and an owner window.
104 * As always, the parent window determines the visibility, while
105 * the owner window requires a more abstract relationship. With
106 * shape windows, the owner window is important because all the
107 * input messages (for mouse and keyboard input) are forwarded
108 * to the owner.
109 *
110 * So it's best to set the parent to HWND_DESKTOP and specify
111 * a frame window for the owner. If you don't already have a
112 * frame window in your application, you can create an invisible
113 * frame window just for message handling. That's what the shp*
114 * functions in Part 2 of this file do (Akira Hatakeyama calls
115 * this the "Voodoo" feature).
116 *
117 * Never use the shape window itself as a top-level window,
118 * but one of your own windows instead, which own the shape
119 * window.
120 *
121 * Note that the keyboard and mouse input messages which are
122 * forwarded to the owner contain mouse coordinates relative
123 * to the rectangular shape subwindow which actually received
124 * the message, not relative to the frame window. So you better
125 * determine the real mouse position using WinQueryPointerPos().
126 *
127 * Note that the size of the shape window is defined once upon
128 * creation and cannot be changed later because this would conflict
129 * with all the subwindows which were created. For the same reason,
130 * you cannot alter the bitmap of the shape window after creation.
131 * You must create a second shape bitmap for that.
132 * Thus all the size parameters in WinSetWindowPos are swallowed and
133 * ignored.
134 *
135 * *** Part 2 ***
136 *
137 * This implements a proper invisible frame window for displaying
138 * shaped bitmap windows directly on the desktop.
139 * See shpCreateWindows for a working example.
140 *
141 * Note: Version numbering in this file relates to XWorkplace version
142 * numbering.
143 *
144 *@@header "helpers\shapewin.h"
145 */
146
147/*
148 * Credits:
149 * 1) Functions for shaped windows.
150 * This is based on the ShapeWin library 1.01 (SHAPEWIN.ZIP at
151 * Hobbes), (C) 1998, 1999 Software Research Associates, Inc.
152 * This has been written by Akira Hatakeyama (akira@sra.co.jp).
153 * Updated by Takayuki Suwa (jjsuwa@ibm.net).
154 * The original was placed under the GPL.
155 *
156 * Changes made by Ulrich M”ller (February 1999):
157 * -- some speedup (marked with *UM)
158 * -- renamed and commented out almost all of the functions
159 * and structures to make their use more lucid.
160 *
161 * 2) Functions for easily creating shape frame windows from a
162 * given HBITMAP. This has been written by me, after getting
163 * some inspiration from the sample programs in SHAPEWIN.ZIP.
164 *
165 * Copyright (C) 1998-2000
166 * Ulrich M”ller,
167 * Akira Hatakeyama,
168 * Takayuki Suwa.
169 * This file is part of the "XWorkplace helpers" source package.
170 * This is free software; you can redistribute it and/or modify
171 * it under the terms of the GNU General Public License as published
172 * by the Free Software Foundation, in version 2 as it comes in the
173 * "COPYING" file of the XWorkplace main distribution.
174 * This program is distributed in the hope that it will be useful,
175 * but WITHOUT ANY WARRANTY; without even the implied warranty of
176 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
177 * GNU General Public License for more details.
178 *
179 */
180
181#define OS2EMX_PLAIN_CHAR
182 // this is needed for "os2emx.h"; if this is defined,
183 // emx will define PSZ as _signed_ char, otherwise
184 // as unsigned char
185
186#define INCL_DOSERRORS
187
188#define INCL_WINWINDOWMGR
189#define INCL_WINFRAMEMGR
190#define INCL_WINDIALOGS
191#define INCL_WININPUT
192#define INCL_WINPOINTERS
193#define INCL_WINSYS
194#define INCL_WINRECTANGLES
195#define INCL_WINTRACKRECT
196
197#define INCL_GPILOGCOLORTABLE
198#define INCL_GPIPRIMITIVES
199#define INCL_GPIBITMAPS
200#include <os2.h>
201
202#include <stdlib.h>
203#include <stdio.h>
204#include <string.h>
205
206#include "setup.h" // code generation and debugging options
207
208#include "helpers\gpih.h"
209#include "helpers\shapewin.h"
210
211#pragma hdrstop
212
213/*
214 *@@category: Helpers\PM helpers\Window classes\Shaped windows (transparency)
215 */
216
217/* ******************************************************************
218 *
219 * Global variables
220 *
221 ********************************************************************/
222
223BOOL G_ShapeRegisteredRegion = FALSE;
224
225/* ******************************************************************
226 *
227 * Part 1: Shape window functions
228 *
229 ********************************************************************/
230
231// forward declarations for structures, because
232// the structures are referenced from each other
233typedef struct _SHPWINCTLDATA *PSHPWINCTLDATA;
234typedef struct _SHPREGION *PSHPREGION;
235
236/*
237 * SHPWINCTLDATA:
238 * internal shape window control data.
239 * This is the shape-window-internal structure
240 * to allow the shape window to manage itself.
241 * This is created in WM_CREATE with the data
242 * passed in the mp1 and mp2 parameters
243 * (CREATESTRUCT and SHPCTLDATA).
244 * This is stored in a shape window's window words.
245 */
246
247typedef struct _SHPWINCTLDATA
248{
249 // common window parameters
250 // (copied from CREATESTRUCT in WM_CREATE)
251 HWND hwndShape ; // main shape window handle
252 HWND hwndParent; // shape window's parent (should be HWND_DESKTOP)
253 HWND hwndOwner ; // shape window's owner, to whom we'll forward all
254 // all the input messages
255 USHORT id ; // window ID
256 SHORT x ; // x - horz. position
257 SHORT y ; // y - vert. position
258 SHORT cx ; // horz. size
259 SHORT cy ; // vert. size
260 PSZ pszText ; // window text
261
262 // additional window parameters
263 HPS hpsDraw; // the input HPS with the bitmap
264 ULONG nRegion; // number of "regions"
265 PSHPREGION aRegion; // array of "regions"
266
267} SHPWINCTLDATA;
268
269/*
270 * SHPREGION:
271 * this is the structure for shape window
272 * "regions". Note that has nothing to do
273 * with GPI regions, but is simply a structure
274 * for each rectangular area in the shape
275 * window's bitmap which can be displayed
276 * as a rectangular PM window.
277 */
278
279typedef struct _SHPREGION
280{
281 PSHPWINCTLDATA pCtrl; // link to parent
282 HWND hwnd ; // drawing window
283 RECTL rect ; // rectangle of sub-bitmap
284} SHPREGION;
285
286/*
287 * SHPSPAN:
288 * this is a temporary structure used during
289 * the creation of SHPREGION's from the
290 * input bitmap.
291 */
292
293typedef struct _SHPSPAN {
294 ULONG nSize ;
295 ULONG nUsed ;
296 RECTL aSpan[1];
297} SHPSPAN, *PSHPSPAN;
298
299// the following defines how many SHPSPAN structures
300// will be initially created and afterwards for span
301// expansions by spanExpand
302#define SPAN_ALLOC_STEP 1024
303
304/*
305 * spanFree:
306 *
307 */
308
309void spanFree(PSHPSPAN pSpan)
310{
311 if (pSpan != NULL)
312 free(pSpan);
313}
314
315/*
316 * spanCreate:
317 * this creates SPAN_ALLOC_STEP SHPSPAN structures.
318 */
319
320PSHPSPAN spanCreate(void)
321{
322 PSHPSPAN pSpan;
323 int len ;
324
325 len = sizeof(SHPSPAN) + sizeof(RECTL) * SPAN_ALLOC_STEP;
326
327 if ((pSpan = (PSHPSPAN)malloc(len)) == NULL)
328 return NULL;
329
330 memset(pSpan, 0, len);
331 pSpan->nSize = SPAN_ALLOC_STEP;
332 pSpan->nUsed = 0 ;
333 return pSpan;
334}
335
336/*
337 * spanExpand:
338 * this expands the memory used for the SHPSPAN
339 * structures if more spans need to be appended.
340 * Another SPAN_ALLOC_STEP SHPSPAN structures are created.
341 */
342
343PSHPSPAN spanExpand(PSHPSPAN pOld)
344{
345 PSHPSPAN pNew;
346 int len ;
347
348 // TRACE("spanExpand\n");
349
350 len = sizeof(SHPSPAN) + sizeof(RECTL) * (pOld->nSize + SPAN_ALLOC_STEP);
351
352 if ((pNew = (PSHPSPAN)malloc(len)) == NULL)
353 return NULL;
354
355 memset(pNew, 0, len);
356 pNew->nSize = pOld->nSize + SPAN_ALLOC_STEP;
357 pNew->nUsed = pOld->nUsed;
358 memcpy(pNew->aSpan, pOld->aSpan, sizeof(RECTL) * pOld->nUsed);
359 spanFree(pOld);
360
361 return pNew;
362}
363
364/*
365 * spanAppend:
366 * this adds a new SHPSPAN to the list of spans.
367 *
368 */
369
370PSHPSPAN spanAppend(PSHPSPAN pSpan,
371 int y, // bottom y; top y = y+1
372 int x1, // left x
373 int x2) // right x
374{
375 int i;
376 PRECTL p;
377 PSHPSPAN pNew;
378
379 // TRACE("spanAppend %d (%d %d)\n", y, x1, x2);
380
381 /*
382 * check if continuous one
383 */
384
385 for (i = 0; i < pSpan->nUsed; i++) {
386 p = &pSpan->aSpan[i];
387 if (p->yTop == y && p->xLeft == x1 && p->xRight == x2)
388 {
389 p->yTop += 1;
390 return pSpan; // merged
391 }
392 }
393
394 /*
395 * if not enough space, expand
396 */
397
398 if ((pSpan->nUsed + 1) >= pSpan->nSize)
399 {
400 if ((pNew = spanExpand(pSpan)) == NULL)
401 return NULL;
402
403 pSpan = pNew;
404 }
405
406 /*
407 * append a rectangle
408 */
409
410 pSpan->aSpan[pSpan->nUsed].yTop = y + 1;
411 pSpan->aSpan[pSpan->nUsed].yBottom = y ;
412 pSpan->aSpan[pSpan->nUsed].xLeft = x1;
413 pSpan->aSpan[pSpan->nUsed].xRight = x2;
414 pSpan->nUsed += 1;
415
416 return pSpan;
417}
418
419#ifdef SHPDEBUG
420
421 /*
422 * ptisin:
423 *
424 */
425
426 BOOL ptisin(PSHPSPAN pSpan, int x, int y)
427 {
428 int i;
429
430 for (i = 0; i < pSpan->nUsed; i++)
431 {
432 if (y >= pSpan->aSpan[i].yTop) {
433 continue;
434 }
435 if (y < pSpan->aSpan[i].yBottom) {
436 continue;
437 }
438 if (x < pSpan->aSpan[i].xLeft) {
439 continue;
440 }
441 if (x >= pSpan->aSpan[i].xRight) {
442 continue;
443 }
444 return TRUE;
445 }
446 return FALSE;
447 }
448
449 /*
450 * dumpSpan:
451 *
452 */
453
454 void dumpSpan(PSHPSPAN pSpan)
455 {
456 int i, maxx, maxy, x, y;
457
458 TRACE("dumpSpan %d\n", pSpan->nUsed);
459
460 maxx = maxy = 0;
461
462 for (i = 0; i < pSpan->nUsed; i++)
463 {
464 if (pSpan->aSpan[i].yTop > maxy)
465 {
466 maxy = pSpan->aSpan[i].yTop;
467 }
468 if (pSpan->aSpan[i].xRight > maxx)
469 {
470 maxx = pSpan->aSpan[i].xRight;
471 }
472 }
473
474 for (y = maxy - 1; y >= 0; y--)
475 {
476 printf("%03d : ", y);
477 for (x = 0; x < maxx; x++)
478 {
479 if (ptisin(pSpan, x, y))
480 printf("#");
481 else
482 printf("_");
483 }
484 printf("\n");
485 }
486 }
487
488#endif // SHPDEBUG
489
490/*
491 * shprgnDraw:
492 * this gets called upon receiving WM_PAINT in
493 * shp_fnwpShapeRegion. We simply draw the
494 * subrectangle from the shape window's bitmap
495 * which corresponds to our region rectangle.
496 */
497
498void shprgnDraw(HPS hps, PSHPREGION pRgn)
499{
500 POINTL apt[3];
501
502 apt[0].x = 0;
503 apt[0].y = 0;
504 apt[1].x = (pRgn->rect.xRight - pRgn->rect.xLeft);
505 apt[1].y = (pRgn->rect.yTop - pRgn->rect.yBottom);
506 apt[2].x = pRgn->rect.xLeft ;
507 apt[2].y = pRgn->rect.yBottom;
508 GpiBitBlt(hps, pRgn->pCtrl->hpsDraw, 3, apt, ROP_SRCCOPY, 0);
509}
510
511/*
512 *@@ shp_fnwpShapeRegion:
513 * this is the window procedure for each of the
514 * shape window's rectangular subwindows.
515 *
516 * See shp_fnwpShapeMgr for a window hierarchy.
517 */
518
519MRESULT EXPENTRY shp_fnwpShapeRegion(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
520{
521 PSHPREGION pRgn;
522 HPS hps ;
523
524 pRgn = (PSHPREGION)WinQueryWindowPtr(hwnd, 0);
525
526 switch (msg)
527 {
528 /*
529 * WM_CREATE:
530 * store the SHPREGION pointer in our
531 * window words.
532 */
533
534 case WM_CREATE:
535 // TRACE("WM_CREATE\n");
536 pRgn = (PSHPREGION)PVOIDFROMMP(mp1);
537 WinSetWindowPtr(hwnd, 0, (PVOID) pRgn);
538 return (MRESULT) FALSE;
539
540 /*
541 * WM_PAINT:
542 * draw our subrectangle of the main bitmap.
543 */
544
545 case WM_PAINT:
546 // TRACE("WM_PAINT (%d %d) (%d %d)\n", pRgn->rect.yBottom, pRgn->rect.xLeft, pRgn->rect.yTop, pRgn->rect.xRight);
547 hps = WinBeginPaint(hwnd, NULLHANDLE, NULL);
548 shprgnDraw(hps, pRgn);
549 WinEndPaint(hps) ;
550 return (MRESULT) 0;
551
552 case WM_MOUSEMOVE :
553 case WM_BUTTON1DOWN :
554 case WM_BUTTON1UP :
555 case WM_BUTTON1CLICK :
556 case WM_BUTTON1DBLCLK:
557 case WM_BUTTON2DOWN :
558 case WM_BUTTON2UP :
559 case WM_BUTTON2CLICK :
560 case WM_BUTTON2DBLCLK:
561 case WM_BUTTON3DOWN :
562 case WM_BUTTON3UP :
563 case WM_BUTTON3CLICK :
564 case WM_BUTTON3DBLCLK:
565 case WM_CHAR :
566 case WM_VIOCHAR :
567 case WM_BEGINDRAG :
568 case WM_ENDDRAG :
569 case WM_SINGLESELECT :
570 case WM_OPEN :
571 case WM_CONTEXTMENU :
572 case WM_CONTEXTHELP :
573 case WM_TEXTEDIT :
574 case WM_BEGINSELECT :
575 case WM_ENDSELECT :
576 // forward all these to the shape window
577 return WinSendMsg(pRgn->pCtrl->hwndShape, msg, mp1, mp2);
578 }
579 return WinDefWindowProc(hwnd, msg, mp1, mp2);
580}
581
582/*
583 * shpmgrWMAdjustWindowPos:
584 * adjust the region windows' positions, visibility etc.
585 * by going thru the whole region windows list and
586 * repositioning all the windows.
587 * This gets called upon receiving WM_ADJUSTWINDOWPOS
588 * in shp_fnwpShapeMgr.
589 */
590
591int shpmgrWMAdjustWindowPos(PSHPWINCTLDATA pCtrl, PSWP pSwp)
592{
593 int i ;
594 PSHPREGION pRgn;
595 ULONG fl ;
596 // HPS hps ;
597
598 PSWP pswpArray;
599
600 // TRACE("shpmgrWMAdjustWindowPos - %d, %08x\n", pCtrl->nRegion, pSwp->fl);
601
602 if (pCtrl->nRegion == 0 || pCtrl->aRegion == NULL)
603 {
604 // TRACE("ShpDrawRegion - no region to open\n");
605 return -1;
606 }
607
608 if ((fl = pSwp->fl) & SWP_MOVE)
609 {
610 pCtrl->x = pSwp->x;
611 pCtrl->y = pSwp->y;
612 }
613
614 pswpArray = (PSWP) malloc(sizeof(SWP) * pCtrl->nRegion);
615
616 // go thru all the "regions" and adjust their sizes
617 for (i = 0, pRgn = pCtrl->aRegion;
618 i < pCtrl->nRegion;
619 i++, pRgn++)
620 {
621 pswpArray[i].fl = fl;
622 pswpArray[i].cy = (pRgn->rect.yTop - pRgn->rect.yBottom);
623 pswpArray[i].cx = (pRgn->rect.xRight - pRgn->rect.xLeft);
624 pswpArray[i].y = (pCtrl->y + pRgn->rect.yBottom);
625 pswpArray[i].x = (pCtrl->x + pRgn->rect.xLeft);
626 pswpArray[i].hwndInsertBehind = pSwp->hwndInsertBehind;
627 pswpArray[i].hwnd = pRgn->hwnd;
628 }
629
630 // set all window positions at once
631 WinSetMultWindowPos(WinQueryAnchorBlock(pCtrl->hwndShape),
632 &pswpArray[0],
633 pCtrl->nRegion);
634 free((void*) pswpArray);
635
636 // calling WinInvalidateRect is not neccessary,
637 // because the windows' update regions are already
638 // properly set by WinSetMultWindowPos (*UM)
639
640 /* for (i = 0, pRgn = pCtrl->aRegion;
641 i < pCtrl->nRegion;
642 i++, pRgn++)
643 {
644 if (fl & (SWP_MOVE | SWP_ZORDER)) {
645 WinInvalidateRect(pRgn->hwnd, NULL, FALSE);
646 }
647 } */
648 return 0;
649}
650
651/*
652 * shpmgrUpdateRegions:
653 * this gets called by shp_fnwpShapeMgr upon receiving
654 * SHAPEWIN_MSG_UPDATE.
655 */
656
657int shpmgrUpdateRegions(PSHPWINCTLDATA pCtrl, PRECTL pRect)
658{
659 RECTL rect, intern;
660 int i ;
661 PSHPREGION pRgn;
662 HAB hab ;
663 // HPS hps ;
664
665 // TRACE("shpmgrUpdateRegions\n");
666
667 hab = WinQueryAnchorBlock(pCtrl->hwndShape);
668
669 if (pRect == NULL) {
670 rect.xLeft = 0 ;
671 rect.yBottom = 0 ;
672 rect.xRight = pCtrl->cx;
673 rect.yTop = pCtrl->cy;
674 pRect = &rect;
675 }
676 for (i = 0, pRgn = pCtrl->aRegion; i < pCtrl->nRegion; i++, pRgn++)
677 {
678 if (WinIntersectRect(hab, &intern, pRect, &pRgn->rect) == FALSE) {
679 continue;
680 } else {
681 WinInvalidateRect(pRgn->hwnd, NULL, FALSE);
682 }
683 }
684 return 0;
685}
686
687/*
688 * shpmgrParseBitmap:
689 * this gets called from shpmgrWMCreate_Bitmap2Regions when the
690 * shape region windows need to be created.
691 * This function does the actual bitmap analysis and
692 * creates a large number of SHPSPAN structures according
693 * to the bitmaps, which can later be turned into
694 * PM windows.
695 * This happens during the processing of WM_CREATE in
696 * shp_fnwpShapeMgr.
697 * CPU usage: relatively low. Maybe 5% of the whole creation
698 * procedure.
699 *
700 *@@changed V0.9.1 (99-12-03): fixed memory leak
701 */
702
703PSHPSPAN shpmgrParseBitmap(HPS hps, PBITMAPINFOHEADER2 bmih2)
704{
705 int blen, hlen;
706 PUCHAR buf;
707 PBITMAPINFO2 pbmi;
708 PSHPSPAN pSpan, pNew;
709 int x, y, k;
710 LONG first, color;
711 BOOL inspan;
712 int left;
713
714 // TRACE("shpmgrParseBitmap\n");
715
716 hlen = sizeof(BITMAPINFO2) + sizeof(RGB) * 256;
717 blen = ((bmih2->cBitCount * bmih2->cx + 31) / 32) * bmih2->cPlanes * 4;
718
719 pbmi = (PBITMAPINFO2)malloc(hlen);
720 buf = (PUCHAR)malloc(blen);
721
722 if (pbmi == NULL || buf == NULL)
723 {
724 // TRACE("shpmgrParseBitmap - failed to alloc %d %d\n", hlen, blen);
725 if (pbmi)
726 free(pbmi);
727 if (buf)
728 free(buf);
729 return NULL;
730 }
731 memcpy(pbmi, bmih2, sizeof(BITMAPINFOHEADER2));
732
733 if ((pSpan = spanCreate()) == NULL)
734 {
735 // TRACE("shpmgrParseBitmap - failed to make\n");
736 free(pbmi);
737 free(buf);
738 return NULL;
739 }
740
741 first = -1;
742
743 for (y = 0; y < bmih2->cy; y++)
744 {
745
746 // TRACE("shpmgrParseBitmap - scan line %d\n", y); fflush(stdout);
747
748 GpiQueryBitmapBits(hps, y, 1, (PBYTE)buf, pbmi);
749
750 for (x = 0, inspan = FALSE; x < bmih2->cx; x++)
751 {
752 k = x * 3;
753 color = ((buf[k] << 16) | (buf[k+1] << 8) | buf[k+2]);
754
755 if (first < 0)
756 {
757 // first iteration: get the very first color (that
758 // is the pixel at (0, 0)), with which we will
759 // compare the others to determine the mask
760 first = color;
761 }
762
763 if (inspan == FALSE && color != first)
764 {
765 inspan = TRUE;
766 left = x;
767 }
768 else if (inspan == TRUE && color == first)
769 {
770 // transparent color found:
771 // create new span
772 inspan = FALSE;
773 if ((pNew = spanAppend(pSpan, y, left, x)) != NULL)
774 {
775 pSpan = pNew;
776 }
777 else
778 {
779 // TRACE("shpmgrParseBitmap - failed to extend\n");
780 break;
781 }
782 }
783 }
784 if (inspan == TRUE)
785 {
786 if ((pNew = spanAppend(pSpan, y, left, x)) != NULL)
787 pSpan = pNew;
788 else
789 // TRACE("shpmgrParseBitmap - failed to extend\n");
790 break;
791 }
792 }
793
794#ifdef SHPDEBUG
795 dumpSpan(pSpan);
796#endif
797
798 // fixed these memory leaks V0.9.1 (99-12-03)
799 if (pbmi)
800 free(pbmi);
801 if (buf)
802 free(buf);
803
804 return pSpan;
805}
806
807/*
808 * shpmgrWMCreate_Bitmap2Regions:
809 * this gets called from shpmgrWMCreate (WM_CREATE) to have a
810 * drawing region created from the bitmap which has been
811 * selected into the given HPS.
812 *
813 * First step in WM_CREATE.
814 */
815
816int shpmgrWMCreate_Bitmap2Regions(PSHPWINCTLDATA pCtrl, // in: shape control data
817 HPS hpsMask) // in: HPS with selected bitmap
818{
819 HAB hab;
820 HDC hdc;
821 HPS hps;
822 SIZEL siz;
823 HBITMAP hbm,
824 hbmPrevious;
825 BITMAPINFOHEADER2 bmi;
826 POINTL apt[3];
827 PSHPSPAN pSpan;
828 PSHPREGION pRegn;
829 int i;
830
831 // TRACE("shpmgrWMCreate_Bitmap2Regions\n");
832
833 hab = WinQueryAnchorBlock(pCtrl->hwndShape);
834
835 /*
836 * Create Memory DC & HPS
837 */
838
839 hdc = DevOpenDC(hab, OD_MEMORY, "*", 0, NULL, NULLHANDLE);
840 siz.cx = siz.cy = 0;
841 hps = GpiCreatePS(hab, hdc, &siz,
842 PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC);
843
844 /*
845 * Create Bitmap and relate to memory PS
846 */
847
848 memset(&bmi, 0, sizeof(bmi));
849
850 bmi.cbFix = sizeof(BITMAPINFOHEADER2);
851 bmi.cx = pCtrl->cx;
852 bmi.cy = pCtrl->cy;
853 bmi.cPlanes = 1 ;
854 bmi.cBitCount = 24;
855 bmi.ulCompression = 0 ;
856 bmi.cclrUsed = 0 ;
857 bmi.cclrImportant = 0 ;
858
859 hbm = GpiCreateBitmap(hps, &bmi, 0, NULL, NULL);
860
861 hbmPrevious = GpiSetBitmap(hps, hbm);
862
863 /*
864 * Copy in Mask Pattern
865 */
866
867 // TRACE("shpmgrWMCreate_Bitmap2Regions - copyin %d x %d mask pattern\n", bmi.cx, bmi.cy);
868
869 apt[0].x = 0; // Target
870 apt[0].y = 0;
871 apt[1].x = bmi.cx;
872 apt[1].y = bmi.cy;
873 apt[2].x = 0; // Source
874 apt[2].y = 0;
875
876 if (GpiBitBlt(hps, pCtrl->hpsDraw, 3, apt, ROP_SRCCOPY, 0) == GPI_ERROR) {
877 // TRACE("MakeRect - BitBlt Failed %08x, hdc %08x, hps %08x, hbm %08x\n",
878 // WinGetLastError(hab), hdc, hps, hbm);
879 }
880
881 /*
882 * Parse Mask Pattern
883 */
884
885 // call shpmgrParseBitmap; this does the actual creation of the
886 // "spans" by comparing all bitmap pixels to the (0, 0)
887 // pixel
888 if ((pSpan = shpmgrParseBitmap(hps, &bmi)) != NULL)
889 {
890 if ((pRegn = (PSHPREGION) malloc(sizeof(SHPREGION) * pSpan->nUsed)) == NULL)
891 {
892 // TRACE("shpmgrWMCreate_Bitmap2Regions - failed to alloc\n");
893 }
894 else
895 {
896 // mask created successfully:
897 pCtrl->nRegion = pSpan->nUsed;
898 pCtrl->aRegion = pRegn;
899
900 for (i = 0; i < pSpan->nUsed; i++)
901 {
902 pRegn[i].pCtrl = pCtrl;
903 pRegn[i].hwnd = NULLHANDLE;
904 pRegn[i].rect.xLeft = pSpan->aSpan[i].xLeft ;
905 pRegn[i].rect.xRight = pSpan->aSpan[i].xRight ;
906 pRegn[i].rect.yTop = pSpan->aSpan[i].yTop ;
907 pRegn[i].rect.yBottom = pSpan->aSpan[i].yBottom;
908 }
909 }
910 spanFree(pSpan);
911 }
912
913 /*
914 * dispose local resources
915 */
916
917 GpiSetBitmap(hps, hbmPrevious); // (*UM)
918 GpiDeleteBitmap(hbm);
919 GpiDestroyPS(hps);
920 DevCloseDC(hdc);
921
922 return 0;
923}
924
925/*
926 * shpmgrWMCreate_Regions2Windows:
927 * this gets called from shpmgrWMCreate (WM_CREATE) to convert
928 * all the "regions" that have been created by shpmgrWMCreate_Bitmap2Regions
929 * in pCtrl to individual rectangular PM windows.
930 *
931 * CPU usage: extremely high, because all the dull PM functions
932 * take so damn long. Calculating the "regions" isn't really
933 * difficult, but it's the PM windows which cause the CPU hog.
934 *
935 * Second step in WM_CREATE.
936 */
937
938int shpmgrWMCreate_Regions2Windows(PSHPWINCTLDATA pCtrl)
939{
940 int i ;
941 PSHPREGION pRgn;
942 ULONG flStyle;
943
944 // TRACE("shpmgrWMCreate_Regions2Windows %d regions\n", pCtrl->nRegion);
945
946 // check if any "regions" exist at all
947 if (pCtrl->nRegion == 0 || pCtrl->aRegion == NULL)
948 {
949 // TRACE("shpmgrWMCreate_Regions2Windows - no region to open\n");
950 return -1;
951 }
952
953 if (G_ShapeRegisteredRegion == FALSE)
954 {
955 // first call: register "shape region" class
956 WinRegisterClass(WinQueryAnchorBlock(pCtrl->hwndShape),
957 WC_SHAPE_REGION,
958 shp_fnwpShapeRegion,
959 CS_PARENTCLIP
960 // use parent's clipping region instead
961 // of the one of the region window
962 | CS_CLIPSIBLINGS
963 // don't allow the subwindows to paint
964 // over siblings (ie. windows with the
965 // same parent); this is neccessary if
966 // HWND_DESKTOP is the parent
967 | CS_SYNCPAINT,
968 // paint immediately
969 sizeof(PVOID));
970 G_ShapeRegisteredRegion = TRUE;
971 }
972
973 flStyle = 0;
974
975 // now go thru the "regions" list
976 for (i = 0, pRgn = pCtrl->aRegion;
977 i < pCtrl->nRegion;
978 i++, pRgn++)
979 {
980 // and create a window for each "region"
981 pRgn->hwnd = WinCreateWindow(
982 pCtrl->hwndParent, // copy parent window from shape window
983 // changed (*UM)
984 // HWND_DESKTOP, // Parent Window
985 WC_SHAPE_REGION, // window class
986 NULL, // window text
987 flStyle, // window style
988 (pCtrl->x + pRgn->rect.xLeft), // x
989 (pCtrl->y + pRgn->rect.yBottom), // y
990 (pRgn->rect.xRight - pRgn->rect.xLeft), // cx
991 (pRgn->rect.yTop - pRgn->rect.yBottom), // cy
992 pCtrl->hwndOwner, // Owner Window
993 HWND_TOP, // Z-Order
994 i, // Window ID
995 pRgn, // Control Data
996 NULL); // Pres. Param.
997 }
998 return 0;
999}
1000
1001/*
1002 * shpmgrFreeRegion:
1003 * cleanup during WM_DESTROY.
1004 */
1005
1006int shpmgrFreeRegion(PSHPWINCTLDATA pCtrl)
1007{
1008 int i ;
1009 PSHPREGION pRgn;
1010
1011 for (i = 0, pRgn = pCtrl->aRegion;
1012 i < pCtrl->nRegion;
1013 i++, pRgn++)
1014 WinDestroyWindow(pRgn->hwnd);
1015
1016 free(pCtrl->aRegion);
1017
1018 return 0;
1019}
1020
1021/*
1022 * shpmgrWMCreate:
1023 * this initializes the "shape window".
1024 * This gets called upon receiving WM_CREATE in shp_fnwpShapeMgr.
1025 * The procedure is as follows:
1026 * 1) the bitmap in pData->hpsDraw is analyzed pixel by
1027 * pixel to create a number of "regions" from it
1028 * (which are not GPI regions, but an array of SHPREGION
1029 * structures. At least one of these structures is
1030 * created for each line. This is done by calling
1031 * shpmgrWMCreate_Bitmap2Regions.
1032 * 2) We then call shpmgrWMCreate_Regions2Windows to actually create
1033 * PM windows from all these structures.
1034 */
1035
1036PSHPWINCTLDATA shpmgrWMCreate(HWND hwnd, // in: shape window
1037 PCREATESTRUCT pWin, // in: create struct of WM_CREATE
1038 PSHPCTLDATA pData) // in: SHPCTLDATA struct (WM_CREATE mp1)
1039{
1040 PSHPWINCTLDATA pCtrl;
1041
1042 if (pData->hpsDraw == NULLHANDLE || pData->hpsMask == NULLHANDLE) {
1043 return NULL;
1044 }
1045
1046 // create new PSHPWINCTLDATA structure
1047 if ((pCtrl = (PSHPWINCTLDATA) malloc(sizeof(SHPWINCTLDATA))) == NULL) {
1048 return NULL;
1049 }
1050
1051 /*
1052 * Setup Common Window Parameters
1053 */
1054
1055 pCtrl->hwndShape = hwnd;
1056 pCtrl->hwndParent = pWin->hwndParent;
1057 pCtrl->hwndOwner = pWin->hwndOwner ;
1058 pCtrl->id = pWin->id;
1059 pCtrl->x = pWin->x ;
1060 pCtrl->y = pWin->y ;
1061 pCtrl->cx = pWin->cx;
1062 pCtrl->cy = pWin->cy;
1063
1064 /*
1065 * Setup Image Window's Control Data
1066 */
1067
1068 pCtrl->cx = pData->cx;
1069 pCtrl->cy = pData->cy;
1070 pCtrl->hpsDraw = pData->hpsDraw;
1071
1072 // now create "regions" from bitmap;
1073 // this will store the "regions" in pCtrl
1074 shpmgrWMCreate_Bitmap2Regions(pCtrl, pData->hpsMask);
1075
1076 // now create as many rectangular PM
1077 // windows as we have "regions" in pCtrl
1078 shpmgrWMCreate_Regions2Windows(pCtrl);
1079
1080 return pCtrl;
1081}
1082
1083/*
1084 * shpmgrWMDestroy:
1085 * this cleans up the shape's resources.
1086 * Gets called upon receiving WM_DESTROY in
1087 * shp_fnwpShapeMgr.
1088 */
1089
1090void shpmgrWMDestroy(PSHPWINCTLDATA pCtrl)
1091{
1092 if (pCtrl == NULL)
1093 return;
1094
1095 shpmgrFreeRegion(pCtrl);
1096 free(pCtrl);
1097}
1098
1099/*
1100 *@@ shp_fnwpShapeMgr:
1101 * this is the window procedure for the "shape window manager".
1102 * Register this procedure with WinRegisterWindowClass.
1103 *
1104 * This does the transformation of the bitmap into many
1105 * rectangular subwindows upon WM_CREATE, each of which
1106 * will use shp_fnwpShapeRegion as its window proc.
1107 *
1108 * There should be the following window hierarchy (the
1109 * lines signify ownership):
1110 *
1111 + Your owner window
1112 + |
1113 + +-- owns "shape manager" window (this window proc)
1114 + |
1115 + +-- lots of "region" windows (shp_fnwpShapeRegion)
1116 + +-- ...
1117 *
1118 * The "region" windows are owned by the "shape manager" window,
1119 * but have the same parent as the "shape manager" window.
1120 * Normally, this should be set to HWND_DESKTOP when creating the
1121 * "shape" window.
1122 *
1123 * This window procedure forwards the following messages
1124 * to its owner:
1125 * -- WM_MOUSEMOVE
1126 * -- all WM_BUTTONxxx messages
1127 * -- WM_CHAR
1128 * -- WM_VIOCHAR
1129 * -- WM_BEGINDRAG
1130 * -- WM_ENDDRAG
1131 * -- WM_SINGLESELECT
1132 * -- WM_OPEN
1133 * -- WM_CONTEXTMENU
1134 * -- WM_CONTEXTHELP
1135 * -- WM_TEXTEDIT
1136 * -- WM_BEGINSELECT
1137 * -- WM_ENDSELECT
1138 */
1139
1140MRESULT EXPENTRY shp_fnwpShapeMgr(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
1141{
1142 PSHPWINCTLDATA pCtrl;
1143 PSWP pswp ;
1144 // SHORT sx; // , sy;
1145
1146 pCtrl = (PSHPWINCTLDATA) WinQueryWindowPtr(hwnd, 0);
1147
1148 switch (msg)
1149 {
1150
1151 /*
1152 * WM_CREATE:
1153 * shape window is being created.
1154 * Parameters:
1155 * PSHPCTLDATA mp1
1156 * PCREATESTRUCT mp2
1157 * Shaped windows must have a SHPCTLDATA
1158 * structure in mp1.
1159 */
1160
1161 case WM_CREATE:
1162 // TRACE("WM_CREATE\n");
1163 pCtrl = shpmgrWMCreate(hwnd,
1164 (PCREATESTRUCT)PVOIDFROMMP(mp2),
1165 (PSHPCTLDATA)PVOIDFROMMP(mp1));
1166
1167 if (pCtrl == NULL)
1168 return (MRESULT) TRUE;
1169
1170 // store control data in window words
1171 WinSetWindowPtr(hwnd, 0, (PVOID) pCtrl);
1172 return (MRESULT) FALSE;
1173
1174 /*
1175 * WM_DESTROY:
1176 * clean up.
1177 */
1178
1179 case WM_DESTROY:
1180 // TRACE("WM_DESTORY\n");
1181 shpmgrWMDestroy(pCtrl);
1182 return (MRESULT) 0;
1183
1184 /*
1185 * WM_ADJUSTWINDOWPOS:
1186 * this needs to be manipulated to
1187 * adjust the positions of all the
1188 * subwindows instead.
1189 */
1190
1191 case WM_ADJUSTWINDOWPOS:
1192 // TRACE("WM_ADJUSTWINDOWPOS\n");
1193 pswp = (PSWP) PVOIDFROMMP(mp1);
1194 // DUMPSWP(pswp);
1195
1196 // enforce the size which we were given
1197 // in the beginning, because we cannot
1198 // change the size later
1199 pswp->cx = pCtrl->cx;
1200 pswp->cy = pCtrl->cy;
1201
1202 // adjust the sub-windows
1203 shpmgrWMAdjustWindowPos(pCtrl, pswp);
1204
1205 // never show ourselves
1206 pswp->fl &= ~SWP_SHOW;
1207 return (MRESULT) 0;
1208
1209 /*
1210 * SHAPEWIN_MSG_UPDATE:
1211 *
1212 */
1213
1214 case SHAPEWIN_MSG_UPDATE:
1215 shpmgrUpdateRegions(pCtrl, (PRECTL) PVOIDFROMMP(mp1));
1216 return (MRESULT) 0;
1217
1218 /*
1219 * WM_QUERYDLGCODE:
1220 *
1221 */
1222
1223 case WM_QUERYDLGCODE:
1224 // TRACE("WM_QUERYDLGCODE\n");
1225 return (MRESULT)DLGC_STATIC;
1226
1227 /*
1228 * WM_PAINT:
1229 * we just swallow this message because
1230 * there's no "shape window" to be painted;
1231 * instead, all the region windows get
1232 * their own WM_PAINT message
1233 */
1234
1235 case WM_PAINT:
1236 {
1237 // TRACE("WM_PAINT\n");
1238 /* HPS hps = WinBeginPaint(hwnd, NULLHANDLE, NULL);
1239
1240 POINTL apt[3];
1241 RECTL rclWin;
1242 WinQueryWindowRect(hwnd, &rclWin);
1243
1244 // lower left of target
1245 apt[0].x = 0;
1246 apt[0].y = 0;
1247 // upper right of target
1248 apt[1].x = rclWin.xRight;
1249 apt[1].y = rclWin.yTop;
1250 // lower left of source
1251 apt[2].x = 0;
1252 apt[2].y = 0;
1253 GpiBitBlt(hps,
1254 pCtrl->hpsDraw,
1255 3,
1256 apt,
1257 ROP_SRCCOPY,
1258 0); */
1259
1260 // delete update region to stop further
1261 // WM_PAINTs for this window;
1262 // this is faster than WiNBeginPaint
1263 WinValidateRect(hwnd, NULL, FALSE);
1264 // WinEndPaint(hps);
1265 return (MRESULT) 0;
1266 }
1267
1268 /*
1269 * all input-related messages:
1270 * forward these to the owner
1271 */
1272
1273 case WM_MOUSEMOVE :
1274 case WM_BUTTON1DOWN :
1275 case WM_BUTTON1UP :
1276 case WM_BUTTON1CLICK :
1277 case WM_BUTTON1DBLCLK:
1278 case WM_BUTTON2DOWN :
1279 case WM_BUTTON2UP :
1280 case WM_BUTTON2CLICK :
1281 case WM_BUTTON2DBLCLK:
1282 case WM_BUTTON3DOWN :
1283 case WM_BUTTON3UP :
1284 case WM_BUTTON3CLICK :
1285 case WM_BUTTON3DBLCLK:
1286 case WM_CHAR :
1287 case WM_VIOCHAR :
1288 case WM_BEGINDRAG :
1289 case WM_ENDDRAG :
1290 case WM_SINGLESELECT :
1291 case WM_OPEN :
1292 case WM_CONTEXTMENU :
1293 case WM_CONTEXTHELP :
1294 case WM_TEXTEDIT :
1295 case WM_BEGINSELECT :
1296 case WM_ENDSELECT :
1297 return WinSendMsg(pCtrl->hwndOwner, msg, mp1, mp2);
1298
1299 } // end switch (msg)
1300 return WinDefWindowProc(hwnd, msg, mp1, mp2);
1301}
1302
1303/* ******************************************************************
1304 *
1305 * Part 2: Shape frame functions
1306 *
1307 ********************************************************************/
1308
1309MRESULT EXPENTRY fnwpShapeFrame(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
1310
1311/*
1312 *@@ shpLoadBitmap:
1313 * this creates a memory device context/presentation space
1314 * and loads and selects a bitmap into it.
1315 *
1316 * If pszBitmap == NULL, the bitmap is loaded from the
1317 * specified resources, otherwise we attempt to load the
1318 * bitmap file specified in pszBitmap (using gpihLoadBitmapFile).
1319 *
1320 * Output in the given SHAPEFRAME structure:
1321 * -- hab: as passed to this func
1322 * -- hdc: device context handle
1323 * -- hps: presentation space handle
1324 * -- hbm: bitmap handle
1325 * -- bmi: BITMAPINFOHEADER of hbmp
1326 * -- ptlLowerLeft: lower left corner is set so that
1327 * bitmap is centered on screen
1328 *
1329 * All other fields are neither read nor written to.
1330 * Returns TRUE if everything went OK.
1331 *
1332 * You can call this function directly before calling
1333 * shpCreateWindows.
1334 *
1335 * Pass the SHAPEFRAME structure to shpFreeBitmap to clean up.
1336 *
1337 *@@changed V0.9.0 [umoeller]: added default window positioning
1338 *@@changed V0.9.0 [umoeller]: removed GpiSetBitmap here
1339 */
1340
1341BOOL shpLoadBitmap(HAB hab, // in: anchor block
1342 PSZ pszBitmapFile, // in: OS/2 1.3 bmp file or NULL
1343 HMODULE hmodResource, // in: module handle from where the
1344 // resources should be loaded if
1345 // pszBitmapFile == NULL. This can be 0 for
1346 // the current EXE
1347 ULONG idResource, // in: bitmap resource ID in that module
1348 PSHAPEFRAME psb) // out: bitmap info
1349{
1350 SIZEL siz;
1351 BOOL brc;
1352
1353 psb->hab = hab;
1354
1355 psb->hdc = DevOpenDC(hab, OD_MEMORY, "*", 0, NULL, NULLHANDLE);
1356 if (psb->hdc)
1357 {
1358 siz.cx = siz.cy = 0;
1359 psb->hps = GpiCreatePS(hab, psb->hdc, &siz,
1360 PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC);
1361
1362 if (psb->hps)
1363 {
1364 if (pszBitmapFile)
1365 {
1366 // load bitmap file
1367 ULONG ulError;
1368 psb->hbm = gpihLoadBitmapFile(psb->hps,
1369 pszBitmapFile,
1370 &ulError);
1371 } else
1372 // load resource bitmap
1373 psb->hbm = GpiLoadBitmap(psb->hps,
1374 hmodResource,
1375 idResource,
1376 0, 0);
1377 if (psb->hbm)
1378 {
1379 SWP swpScreen;
1380 // store bitmap info in structure
1381 psb->bmi.cbFix = sizeof(psb->bmi);
1382 GpiQueryBitmapInfoHeader(psb->hbm, &psb->bmi);
1383
1384 // set ptlLowerLeft so that the bitmap
1385 // is centered on the screen
1386 WinQueryWindowPos(HWND_DESKTOP, &swpScreen);
1387 psb->ptlLowerLeft.x = (swpScreen.cx - psb->bmi.cx) / 2;
1388 psb->ptlLowerLeft.y = (swpScreen.cy - psb->bmi.cy) / 2;
1389
1390 brc = TRUE;
1391 }
1392 }
1393 }
1394 return (brc);
1395}
1396
1397/*
1398 *@@ shpFreeBitmap:
1399 * this cleans up resources allocated by shpLoadBitmap:
1400 * delete the bitmap, destroy the HPS and HDC.
1401 *
1402 *@@changed V0.9.3 (2000-04-11) [umoeller]: fixed major resource leak; the bitmap was never freed
1403 */
1404
1405VOID shpFreeBitmap(PSHAPEFRAME psb)
1406{
1407 if (psb->hbm != NULLHANDLE)
1408 {
1409 // unset bitmap in HPS; it cannot be deleted otherwise...
1410 GpiSetBitmap(psb->hps, NULLHANDLE); // V0.9.3 (2000-04-11) [umoeller]
1411 GpiDeleteBitmap(psb->hbm);
1412 psb->hbm = NULLHANDLE;
1413 }
1414 if (psb->hps != NULLHANDLE)
1415 {
1416 GpiDestroyPS(psb->hps);
1417 psb->hps = NULLHANDLE;
1418 }
1419 if (psb->hdc != NULLHANDLE)
1420 {
1421 DevCloseDC(psb->hdc);
1422 psb->hdc = NULLHANDLE;
1423 }
1424}
1425
1426/*
1427 *@@ shpCreateWindows:
1428 * this is a one-shot function for creating a
1429 * shaped window from a bitmap.
1430 *
1431 * Required fields in SHAPEFRAME for input (those
1432 * are all properly set by shpLoadBitmap):
1433 * -- hab: anchor block
1434 * -- hps: presentation space handle
1435 * -- hbm: bitmap handle
1436 * -- bmi: BITMAPINFOHEADER of hbmp
1437 * -- ptlLowerLeft: lower left corner of where
1438 * to position the shape window (new with V0.9.0).
1439 *
1440 * All other fields are ignored for input and only
1441 * set for output (and for the shape window later).
1442 *
1443 * You can use shpLoadBitmap to have all the fields
1444 * initialized, which will also set ptlLowerLeft
1445 * so that the shape window gets centered on the
1446 * Desktop.
1447 *
1448 * Otherwise you must initialize the above fields for
1449 * yourself.
1450 *
1451 * Obviously, this function uses the same HPS (and
1452 * thus bitmap) for both transparency and drawing.
1453 * If you wish to use two different bitmaps (one for
1454 * transparency, one for drawing), you cannot use
1455 * this function.
1456 *
1457 * Note that the windows are now (V0.9.0) also positioned
1458 * on the screen.
1459 *
1460 * Output in that structure:
1461 * -- hwndShapeFrame: invisible rectangular frame
1462 * window for the shape window
1463 * (fnwpShapeFrame, created here)
1464 * -- hwndShape: "shape" window
1465 * (shp_fnwpShapeMgr, created here)
1466 * -- pfnFrame: original window procedure of
1467 * WC_FRAME (hwndShapeFrame),
1468 * which is subclassed here
1469 * using fnwpShapeFrame
1470 * -- shpctrl: control data for hwndShape
1471 *
1472 * Returns TRUE if everything went OK.
1473 *
1474 * <B>Example</B> for creating a shaped window and
1475 * centering it on the screen:
1476 + SHAPEFRAME sb;
1477 + if (shpLoadBitmap(hab...,
1478 + szBitmapFile...,
1479 + 0, 0,
1480 + &sb))
1481 + {
1482 + // create shape (transparent) windows
1483 + if (shpCreateWindows(habQuickThread, &sb))
1484 + {
1485 * ...
1486 + }
1487 + }
1488 + ...
1489 + // cleanup
1490 + shpFreeBitmap(&sb);
1491 + WinDestroyWindow(sb.hwndShapeFrame) ;
1492 + WinDestroyWindow(sb.hwndShape);
1493 *
1494 *@@changed V0.9.0 [umoeller]: removed hab from function prototype
1495 *@@changed V0.9.0 [umoeller]: added window positioning
1496 *@@changed V0.9.0 [umoeller]: added GpiSetBitmap here (always forget that)
1497 */
1498
1499BOOL shpCreateWindows(PSHAPEFRAME psb)
1500{
1501 BOOL brc = FALSE;
1502
1503 if (psb->hbm)
1504 {
1505 // bitmap seems to be valid:
1506 FRAMECDATA fcd;
1507
1508 GpiSetBitmap(psb->hps, psb->hbm);
1509
1510 memset(&fcd, 0, sizeof(fcd));
1511 fcd.cb = sizeof(fcd);
1512
1513 // create invisible frame
1514 psb->hwndShapeFrame = WinCreateWindow(
1515 HWND_DESKTOP, // Parent window handle
1516 WC_FRAME, // Frame Window Class
1517 "XWorkplaceLogoShape", // title
1518 0, // Window Style
1519 0, 0, 0, 0, // Position & size
1520 NULLHANDLE, // Owner Window
1521 HWND_TOP, // Z-Order
1522 0, // Window ID
1523 &fcd, // Control Data
1524 NULL); // Presentation Parameter
1525
1526 if (psb->hwndShapeFrame)
1527 {
1528 // store the SHAPEFRAME structure in the frame's window words
1529 // so that the subclassed frame can access the data
1530 WinSetWindowULong(psb->hwndShapeFrame, QWL_USER, (ULONG)psb);
1531
1532 // subclass the frame window; store the original wnd proc in
1533 // the SHAPEFRAME structure
1534 psb->pfnFrame = WinSubclassWindow(psb->hwndShapeFrame, fnwpShapeFrame);
1535
1536 if ((psb->hwndShapeFrame) && (psb->hps))
1537 {
1538 // OK, no errors so far
1539
1540 // register shape window class; if this is already
1541 // registered, this won't hurt
1542 WinRegisterClass(psb->hab,
1543 WC_SHAPE_WINDOW,
1544 shp_fnwpShapeMgr,
1545 0L, // class style flags
1546 sizeof(PVOID));
1547
1548 // create shape manager window
1549 psb->shpctrl.cx = psb->bmi.cx;
1550 psb->shpctrl.cy = psb->bmi.cy;
1551 psb->shpctrl.hpsDraw = psb->hps;
1552 psb->shpctrl.hpsMask = psb->hps;
1553
1554 // create the "shape" window
1555 psb->hwndShape = WinCreateWindow(
1556 HWND_DESKTOP, // Parent Window
1557 WC_SHAPE_WINDOW, // Window Class
1558 NULL, // Window Text
1559 0, // Window Style;
1560 // no clip siblings!
1561 0, 0, 0, 0, // Pos & Size
1562 psb->hwndShapeFrame, // Owner Window
1563 HWND_TOP, // Z-Order
1564 0, // Window ID
1565 &psb->shpctrl, // Control Data
1566 NULL); // Pres. Param.
1567
1568 if (psb->hwndShape)
1569 {
1570 // no error: only then return TRUE
1571 brc = TRUE;
1572
1573 // and position the windows
1574 WinSetWindowPos(psb->hwndShapeFrame, NULLHANDLE,
1575 psb->ptlLowerLeft.x, psb->ptlLowerLeft.y,
1576 psb->bmi.cx, psb->bmi.cy,
1577 (SWP_MOVE | SWP_SIZE | SWP_HIDE));
1578 WinSetWindowPos(psb->hwndShape, NULLHANDLE,
1579 psb->ptlLowerLeft.x, psb->ptlLowerLeft.y,
1580 psb->bmi.cx, psb->bmi.cy,
1581 (SWP_MOVE | SWP_SIZE | SWP_SHOW));
1582 }
1583 }
1584 }
1585 }
1586
1587 return (brc);
1588}
1589
1590/*
1591 *@@ fnwpShapeFrame:
1592 * this is the window proc for subclassing the shape frame window
1593 * (shpCreateWindows above).
1594 * The shaped window proc (shp_fnwpShapeMgr) keeps forwarding messages
1595 * to its owner (which is the frame here), so we better handle
1596 * those messages.
1597 */
1598
1599MRESULT EXPENTRY fnwpShapeFrame(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
1600{
1601 MRESULT mrc;
1602
1603 // get the SHAPEFRAME structure from the window words,
1604 // which has been stored there by shpCreateWindows
1605 PSHAPEFRAME psb = (PSHAPEFRAME)WinQueryWindowULong(hwnd, QWL_USER);
1606
1607 // _Pmpf(("frame %08x %08x %08x", msg, mp1, mp2));
1608
1609 switch (msg)
1610 {
1611
1612 /*
1613 * WM_ADJUSTWINDOWPOS:
1614 * forward the data we get here to the shape
1615 * window (which will in turn reposition all
1616 * the region windows);
1617 * afterwards, always delete SHOW and set HIDE
1618 * for ourselves
1619 */
1620
1621 case WM_ADJUSTWINDOWPOS: {
1622 PSWP pswp = (PSWP) PVOIDFROMMP(mp1);
1623 POINTL ptl;
1624 WinQueryPointerPos(HWND_DESKTOP, &ptl);
1625 WinSetWindowPos(psb->hwndShape,
1626 pswp->hwndInsertBehind,
1627 // use current mouse position instead
1628 // of the original ones
1629 ptl.x,
1630 ptl.y,
1631 // pswp->x,
1632 // pswp->y,
1633 pswp->cx,
1634 pswp->cy,
1635 pswp->fl);
1636 pswp->fl &= ~SWP_SHOW;
1637 pswp->fl |= SWP_HIDE;
1638 mrc = (*psb->pfnFrame)(hwnd, msg, mp1, mp2);
1639 break; }
1640
1641 /* the shape window forwards these messages to us:
1642 WM_MOUSEMOVE
1643 WM_BUTTON1DOWN
1644 WM_BUTTON1UP
1645 WM_BUTTON1CLICK
1646 WM_BUTTON1DBLCLK
1647 WM_BUTTON2DOWN
1648 WM_BUTTON2UP
1649 WM_BUTTON2CLICK
1650 WM_BUTTON2DBLCLK
1651 WM_BUTTON3DOWN
1652 WM_BUTTON3UP
1653 WM_BUTTON3CLICK
1654 WM_BUTTON3DBLCLK
1655 WM_CHAR
1656 WM_VIOCHAR
1657 WM_BEGINDRAG
1658 WM_ENDDRAG
1659 WM_SINGLESELECT
1660 WM_OPEN
1661 WM_CONTEXTMENU
1662 WM_CONTEXTHELP
1663 WM_TEXTEDIT
1664 WM_BEGINSELECT
1665 WM_ENDSELECT */
1666
1667 /*
1668 * WM_SINGLESELECT:
1669 * if we are being clicked upon, bring the
1670 * shape window to top instead
1671 */
1672
1673 case WM_SINGLESELECT:
1674 WinSetWindowPos(psb->hwndShape, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER);
1675 mrc = 0;
1676 break;
1677
1678 /*
1679 * WM_BEGINDRAG:
1680 * if we are being dragged with MB2, forward
1681 * this to the shape window
1682 */
1683
1684 case WM_BEGINDRAG:
1685 WinSendMsg(psb->hwndShapeFrame, WM_TRACKFRAME,
1686 MPFROMSHORT(TF_MOVE /* | TF_SETPOINTERPOS*/ ), NULL);
1687 mrc = 0;
1688 break;
1689
1690 default:
1691 mrc = (*psb->pfnFrame)(hwnd, msg, mp1, mp2);
1692 }
1693
1694 return (mrc);
1695}
1696
1697/*
1698 *@@ shp2RegisterClasses:
1699 *
1700 *@@added V0.9.3 (2000-05-03) [umoeller]
1701 */
1702
1703BOOL shp2RegisterClasses(HAB hab)
1704{
1705 // register shape window class; if this is already
1706 // registered, this won't hurt
1707 return(WinRegisterClass(hab,
1708 WC_SHAPE_WINDOW,
1709 shp_fnwpShapeMgr,
1710 0L, // class style flags
1711 sizeof(PVOID)));
1712}
1713
1714
Note: See TracBrowser for help on using the repository browser.