xref: /petsc/src/sys/classes/draw/impls/win32/win32draw.c (revision fe998a80077c9ee0917a39496df43fc256e1b478)
1 
2 #include <petscsys.h>
3 #include <petsc-private/drawimpl.h>
4 #include <../src/sys/classes/draw/impls/win32/win32draw.h>
5 
6 #define IDC_FOUR       109
7 #define IDI_FOUR       107
8 #define IDM_EXIT       105
9 #define IDR_POPUP      103
10 #define MAX_LOADSTRING 100
11 
12 #if !defined(SelectPen)
13 #define SelectPen(hdc, hpen)      ((HPEN)SelectObject((hdc), (HGDIOBJ)(HPEN)(hpen)))
14 #endif
15 #if !defined(SelectFont)
16 #define SelectFont(hdc,hfont)    ((HFONT)SelectObject((hdc), (HGDIOBJ)(HFONT)(hfont)))
17 #endif
18 #if !defined(SelectBrush)
19 #define SelectBrush(hdc,hbrush) ((HBRUSH)SelectObject((hdc), (HGDIOBJ)(HBRUSH)(hbrush)))
20 #endif
21 #if !defined(GetStockBrush)
22 #define GetStockBrush(i)      ((HBRUSH)GetStockObject(i))
23 #endif
24 
25 #define XTRANS(draw,win,x) \
26     (int)(((win)->w)*((draw)->port_xl + (((x - (draw)->coor_xl)*         \
27                             ((draw)->port_xr - (draw)->port_xl))/        \
28                             ((draw)->coor_xr - (draw)->coor_xl))))
29 #define YTRANS(draw,win,y) \
30     (int)(((win)->h)*(1.0-(draw)->port_yl - (((y - (draw)->coor_yl)*     \
31                                 ((draw)->port_yr - (draw)->port_yl))/    \
32                                 ((draw)->coor_yr - (draw)->coor_yl))))
33 
34 HINSTANCE  hInst;
35 HANDLE     g_hWindowListMutex = NULL;
36 WindowNode WindowListHead     = NULL;
37 
38 /* Hard coded color hue until hue.c works with this */
39 unsigned char RedMap[]   = {255,0,255,0,0,0,255,127,34,255,238,165,255,255,190,255,255,238,0,255,105,154,135,0,0,244,152,176,220,216,50,255};
40 unsigned char GreenMap[] = {255,0,0,255,255,0,0,255,139,165,130,42,182,127,190,255,215,162,197,246,105,205,206,100,0,164,245,224,17,191,205,240};
41 unsigned char BlueMap[]  = {255,0,0,0,255,255,225,212,34,0,238,42,193,80,190,0,0,173,205,143,105,50,235,0,128,96,255,230,120,216,50,245};
42 
43 /* Foward declarations of functions included in this code module: */
44 LRESULT CALLBACK PetscWndProc(HWND, UINT, WPARAM, LPARAM);
45 static PetscErrorCode TranslateColor_Win32(PetscDraw,int);
46 static PetscErrorCode AverageColorRectangle_Win32(PetscDraw,int,int,int,int);
47 static PetscErrorCode AverageColorTriangle_Win32(PetscDraw,int,int,int);
48 static PetscErrorCode deletemouselist_Win32(WindowNode);
49 static void OnPaint_Win32(HWND);
50 static void OnDestroy_Win32(HWND);
51 static PetscErrorCode MouseRecord_Win32(HWND,PetscDrawButton);
52 static PetscErrorCode PetscDrawGetPopup_Win32(PetscDraw,PetscDraw*);
53 
54 #undef __FUNCT__
55 #define __FUNCT__ "PetscDrawSetDoubleBuffer_Win32"
56 static PetscErrorCode PetscDrawSetDoubleBuffer_Win32(PetscDraw draw)
57 {
58   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
59   HDC             hdc      = GetDC(windraw->hWnd);
60 
61   PetscFunctionBegin;
62   windraw->node->DoubleBuffer    = CreateCompatibleDC(hdc);
63   windraw->node->DoubleBufferBit = CreateCompatibleBitmap(hdc,windraw->w,windraw->h);
64   windraw->node->dbstore         = SelectObject(windraw->node->DoubleBuffer,windraw->node->DoubleBufferBit);
65   /* Fill background of second buffer */
66   ExtFloodFill(windraw->node->DoubleBuffer,0,0,COLOR_WINDOW,FLOODFILLBORDER);
67   /* Copy current buffer into seconf buffer and set window data as double buffered */
68   BitBlt(windraw->node->DoubleBuffer,0,0,windraw->w,windraw->h,
69          windraw->node->Buffer,0,0, SRCCOPY);
70 
71   windraw->node->DoubleBuffered = PETSC_TRUE;
72   ReleaseDC(windraw->hWnd,hdc);
73   PetscFunctionReturn(0);
74 }
75 
76 #undef __FUNCT__
77 #define __FUNCT__ "PetscDrawFlush_Win32"
78 static PetscErrorCode PetscDrawFlush_Win32(PetscDraw draw)
79 {
80   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
81   HDC             hdc      = GetDC(windraw->hWnd);
82 
83   PetscFunctionBegin;
84   /* flush double buffer into primary buffer */
85   BitBlt(windraw->node->Buffer,0,0,windraw->w,windraw->h,
86          windraw->node->DoubleBuffer,0,0,SRCCOPY);
87   /* flush double buffer into window */
88   BitBlt(hdc,0,0,windraw->w,windraw->h,
89          windraw->node->DoubleBuffer, 0,0,SRCCOPY);
90   ReleaseDC(windraw->hWnd,hdc);
91   PetscFunctionReturn(0);
92 }
93 
94 #undef __FUNCT__
95 #define __FUNCT__ "deletemouselist_Win32"
96 static PetscErrorCode deletemouselist_Win32(WindowNode deletelist)
97 {
98   /* Called upon window close. Frees memory of linked list of stored mouse commands */
99   MouseNode node;
100 
101   while (deletelist->MouseListHead != NULL) {
102     node = deletelist->MouseListHead;
103     if (deletelist->MouseListHead->mnext != NULL) deletelist->MouseListHead = deletelist->MouseListHead->mnext;
104     PetscFree(node);
105   }
106   deletelist->MouseListHead = deletelist->MouseListTail = NULL;
107   if (deletelist->wprev != NULL) deletelist->wprev->wnext = deletelist->wnext;
108   if (deletelist->wnext != NULL) deletelist->wnext->wprev = deletelist->wprev;
109   PetscFree(deletelist);
110   return 0;
111 }
112 
113 #undef __FUNCT__
114 #define __FUNCT__ "PetscDrawGetMouseButton_Win32"
115 static PetscErrorCode PetscDrawGetMouseButton_Win32(PetscDraw draw, PetscDrawButton *button,PetscReal *x_user,PetscReal *y_user,PetscReal *x_phys,PetscReal *y_phys)
116 {
117   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
118   WindowNode      current;
119   MouseNode       node=0;
120 
121   PetscFunctionBegin;
122   /* Make sure no other code is using the linked list at this moment */
123   WaitForSingleObject(g_hWindowListMutex, INFINITE);
124   /* Look for the node that matches the window you are using */
125   current = WindowListHead;
126   while (current != NULL) {
127     if (current->hWnd == windraw->hWnd) {
128       current->IsGetMouseOn = TRUE;
129       break;
130     } else current = current->wnext;
131   }
132   /* If no actions have occured, wait for one */
133   node = current->MouseListHead;
134   if (!node) {
135     ReleaseMutex(g_hWindowListMutex);
136     WaitForSingleObject(current->event, INFINITE);
137     WaitForSingleObject(g_hWindowListMutex, INFINITE);
138   }
139   /* once we have the information, assign the pointers to it */
140   *button = current->MouseListHead->Button;
141   *x_user = current->MouseListHead->user.x;
142   *y_user = current->MouseListHead->user.y;
143   /* optional arguments */
144   if (x_phys) *x_phys = current->MouseListHead->phys.x;
145   if (y_phys) *y_phys = current->MouseListHead->phys.y;
146   /* remove set of information from sub linked-list, delete the node */
147   current->MouseListHead = current->MouseListHead->mnext;
148   if (!current->MouseListHead) {
149     ResetEvent(current->event);
150     current->MouseListTail = NULL;
151   }
152   if (node) PetscFree(node);
153 
154   /* Release mutex so that  other code can use
155      the linked list now that we are done with it */
156   ReleaseMutex(g_hWindowListMutex);
157   PetscFunctionReturn(0);
158 }
159 
160 #undef __FUNCT__
161 #define __FUNCT__ "PetscDrawPause_Win32"
162 static PetscErrorCode PetscDrawPause_Win32(PetscDraw draw)
163 {
164   PetscFunctionBegin;
165   PetscSleep(draw->pause);
166   PetscFunctionReturn(0);
167 }
168 
169 #undef __FUNCT__
170 #define __FUNCT__ "TranslateColor_Win32"
171 static PetscErrorCode TranslateColor_Win32(PetscDraw draw,int color)
172 {
173   /* Maps single color value into the RGB colors in our tables */
174   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
175   windraw->currentcolor = RGB(RedMap[color],GreenMap[color],BlueMap[color]);
176   return 0;
177 }
178 
179 #undef __FUNCT__
180 #define __FUNCT__ "AverageColorRectangle_Win32"
181 static PetscErrorCode AverageColorRectangle_Win32(PetscDraw draw,int c1,int c2, int c3, int c4)
182 {
183   /* Averages colors given at points of rectangle and sets color from color table
184     will be changed once the color gradient problem is worked out */
185   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
186   windraw->currentcolor = RGB(((RedMap[c1]+RedMap[c2]+RedMap[c3]+RedMap[c4])/4),
187                               ((GreenMap[c1]+GreenMap[c2]+GreenMap[c3]+GreenMap[c4])/4),
188                               ((BlueMap[c1]+BlueMap[c2]+BlueMap[c3]+BlueMap[c4])/4));
189   return 0;
190 }
191 
192 #undef __FUNCT__
193 #define __FUNCT__ "AverageColorTriangle_Win32"
194 static PetscErrorCode AverageColorTriangle_Win32(PetscDraw draw,int c1,int c2,int c3)
195 {
196   /* Averages colors given at points of rectangle and sets color from color table
197     will be changed once the color gradient problem is worked out */
198   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
199   windraw->currentcolor = RGB((RedMap[c1]+RedMap[c2]+RedMap[c3])/3,
200                               (GreenMap[c1]+GreenMap[c2]+GreenMap[c3])/3,
201                               (BlueMap[c1]+BlueMap[c2]+BlueMap[c3])/3);
202   return 0;
203 }
204 
205 #undef __FUNCT__
206 #define __FUNCT__ "PetscDrawRectangle_Win32"
207 static PetscErrorCode PetscDrawRectangle_Win32(PetscDraw draw,PetscReal xl,PetscReal yl,PetscReal xr,PetscReal yr,int c1,int c2,int c3,int c4)
208 {
209   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
210   HBRUSH          hbrush;
211   RECT            rect;
212   int             x1,yone,x2,y2;
213   HDC             hdc;
214 
215   PetscFunctionBegin;
216   x1   = XTRANS(draw,windraw,xl);
217   x2   = XTRANS(draw,windraw,xr);
218   yone = YTRANS(draw,windraw,yl);
219   y2   = YTRANS(draw,windraw,yr);
220   SetRect(&rect,x1,y2,x2,yone);
221   if (c1==c2 && c2==c3 && c3==c4) TranslateColor_Win32(draw,c1);
222   else AverageColorRectangle_Win32(draw,c1,c2,c3,c4);
223   hbrush = CreateSolidBrush(windraw->currentcolor);
224 
225   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
226   else                               hdc = windraw->node->Buffer;
227 
228   FillRect(hdc,&rect,hbrush);
229   /* Forces a WM_PAINT message and erases background */
230   InvalidateRect(windraw->hWnd,NULL,TRUE);
231   UpdateWindow(windraw->hWnd);
232   PetscFunctionReturn(0);
233 }
234 
235 #undef __FUNCT__
236 #define __FUNCT__ "PetscDrawLine_Win32"
237 static PetscErrorCode PetscDrawLine_Win32(PetscDraw draw,PetscReal xl,PetscReal yl,PetscReal xr,PetscReal yr,int color)
238 {
239   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
240   HPEN            hpen;
241   int             x1,yone,x2,y2;
242   HDC             hdc;
243 
244   PetscFunctionBegin;
245   TranslateColor_Win32(draw,color);
246   x1   = XTRANS(draw,windraw,xl);x2  = XTRANS(draw,windraw,xr);
247   yone = YTRANS(draw,windraw,yl);y2  = YTRANS(draw,windraw,yr);
248   hpen = CreatePen (PS_SOLID, windraw->linewidth, windraw->currentcolor);
249   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
250   else                               hdc = windraw->node->Buffer;
251 
252   SelectPen(hdc,hpen);
253   MoveToEx(hdc,x1,yone,NULL);
254   LineTo(hdc,x2,y2);
255   /* Forces a WM_PAINT message and erases background */
256   InvalidateRect(windraw->hWnd,NULL,TRUE);
257   UpdateWindow(windraw->hWnd);
258   PetscFunctionReturn(0);
259 }
260 
261 #undef __FUNCT__
262 #define __FUNCT__ "PetscDrawLineSetWidth_Win32"
263 static PetscErrorCode PetscDrawLineSetWidth_Win32(PetscDraw draw,PetscReal width)
264 {
265   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
266   int             averagesize,finalwidth;
267   RECT            rect;
268 
269   PetscFunctionBegin;
270   GetClientRect(windraw->hWnd,&rect);
271   averagesize = ((rect.right - rect.left)+(rect.bottom - rect.top))/2;
272   finalwidth  = (int)PetscFloorReal(averagesize*width);
273   if (finalwidth < 1) finalwidth = 1; /* minimum size PetscDrawLine can except */
274 
275   windraw->linewidth = finalwidth;
276   PetscFunctionReturn(0);
277 }
278 
279 #undef __FUNCT__
280 #define __FUNCT__ "PetscDrawLineGetWidth_Win32"
281 static PetscErrorCode PetscDrawLineGetWidth_Win32(PetscDraw draw,PetscReal *width)
282 {
283   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
284 
285   PetscFunctionBegin;
286   *width = (PetscReal)windraw->linewidth;
287   PetscFunctionReturn(0);
288 }
289 
290 #undef __FUNCT__
291 #define __FUNCT__ "PetscDrawPoint_Win32"
292 static PetscErrorCode PetscDrawPoint_Win32(PetscDraw draw,PetscReal x,PetscReal y,int color)
293 {
294   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
295   HBRUSH          hbrush;
296   HRGN            hrgn;
297   int             radius;
298   int             x1,yone;
299   HDC             hdc;
300 
301   PetscFunctionBegin;
302   TranslateColor_Win32(draw,color);
303   x1     = XTRANS(draw,windraw,x);
304   yone   = YTRANS(draw,windraw,y);
305   hbrush = CreateSolidBrush(windraw->currentcolor);
306   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
307   else                               hdc = windraw->node->Buffer;
308 
309   /* desired size is one logical pixel so just turn it on */
310   if (windraw->pointdiameter == 1) SetPixelV(hdc,x1,yone,windraw->currentcolor);
311   else {
312     /* draw point around position determined */
313     radius = windraw->pointdiameter/2; /* integer division */
314     hrgn   = CreateEllipticRgn(x1-radius,yone-radius,x1+radius,yone+radius);
315     FillRgn(hdc,hrgn,hbrush);
316   }
317   /* Forces a WM_PAINT and erases background */
318   InvalidateRect(windraw->hWnd,NULL,TRUE);
319   UpdateWindow(windraw->hWnd);
320   PetscFunctionReturn(0);
321 }
322 
323 #undef __FUNCT__
324 #define __FUNCT__ "PetscDrawPointSetSize_Win32"
325 static PetscErrorCode PetscDrawPointSetSize_Win32(PetscDraw draw,PetscReal width)
326 {
327   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
328   int             averagesize,diameter;
329   RECT            rect;
330 
331   PetscFunctionBegin;
332   GetClientRect(windraw->hWnd,&rect);
333   averagesize = ((rect.right - rect.left)+(rect.bottom - rect.top))/2;
334   diameter    = (int)PetscFloorReal(averagesize*width);
335   if (diameter < 1) diameter = 1;
336   windraw->pointdiameter = diameter;
337   PetscFunctionReturn(0);
338 }
339 
340 #undef __FUNCT__
341 #define __FUNCT__ "PetscDrawString_Win32"
342 static PetscErrorCode PetscDrawString_Win32(PetscDraw draw,PetscReal x,PetscReal y,int color,const char *text)
343 {
344   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
345   RECT            r;
346   HFONT           hfont;
347   LOGFONT         logfont;
348   int             x1,yone;
349   HDC             hdc;
350 
351   PetscFunctionBegin;
352   x1       = XTRANS(draw,windraw,x);
353   yone     = YTRANS(draw,windraw,y);
354   r.bottom = yone;
355   r.left   = x1;
356   r.right  = x1 + 1;
357   r.top    = yone + 1;
358 
359   logfont.lfHeight         = windraw->stringheight;
360   logfont.lfWidth          = windraw->stringwidth;
361   logfont.lfEscapement     = 0;
362   logfont.lfOrientation    = 0;
363   logfont.lfCharSet        = 0;
364   logfont.lfClipPrecision  = 0;
365   logfont.lfItalic         = 0;
366   logfont.lfOutPrecision   = 0;
367   logfont.lfPitchAndFamily = DEFAULT_PITCH;
368   logfont.lfQuality        = DEFAULT_QUALITY;
369   logfont.lfStrikeOut      = 0;
370   logfont.lfUnderline      = 0;
371   logfont.lfWeight         = FW_NORMAL;
372 
373   hfont = CreateFontIndirect(&logfont);
374   TranslateColor_Win32(draw,color);
375   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
376   else                               hdc = windraw->node->Buffer;
377 
378   SelectFont(hdc,hfont);
379   SetTextColor(hdc,windraw->currentcolor);
380   DrawText(hdc,text,lstrlen(text),&r,DT_NOCLIP);
381   DeleteObject(hfont);
382   /* Forces a WM_PAINT message and erases background */
383   InvalidateRect(windraw->hWnd,NULL,TRUE);
384   UpdateWindow(windraw->hWnd);
385   PetscFunctionReturn(0);
386 }
387 
388 #undef __FUNCT__
389 #define __FUNCT__ "PetscDrawStringVertical_Win32"
390 static PetscErrorCode PetscDrawStringVertical_Win32(PetscDraw draw,PetscReal x,PetscReal y,int color,const char *text)
391 {
392   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
393   RECT            r;
394   HFONT           hfont;
395   LOGFONT         logfont;
396   int             x1,yone;
397   HDC             hdc;
398 
399   PetscFunctionBegin;
400   x1       = XTRANS(draw,windraw,x);
401   yone     = YTRANS(draw,windraw,y);
402   r.left   = x1;
403   r.bottom = yone + 30;
404   r.right  = x1 + 1;
405   r.top    = yone - 30;
406 
407   logfont.lfEscapement     = 2700; /* Causes verticle text drawing */
408   logfont.lfHeight         = windraw->stringheight;
409   logfont.lfWidth          = windraw->stringwidth;
410   logfont.lfOrientation    = 0;
411   logfont.lfCharSet        = DEFAULT_CHARSET;
412   logfont.lfClipPrecision  = 0;
413   logfont.lfItalic         = 0;
414   logfont.lfOutPrecision   = 0;
415   logfont.lfPitchAndFamily = DEFAULT_PITCH;
416   logfont.lfQuality        = DEFAULT_QUALITY;
417   logfont.lfStrikeOut      = 0;
418   logfont.lfUnderline      = 0;
419   logfont.lfWeight         = FW_NORMAL;
420 
421   hfont = CreateFontIndirect(&logfont);
422   TranslateColor_Win32(draw,color);
423   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
424   else                               hdc = windraw->node->Buffer;
425 
426   SelectFont(hdc,hfont);
427   SetTextColor(hdc,windraw->currentcolor);
428   DrawText(hdc,text,lstrlen(text),&r,DT_NOCLIP | DT_SINGLELINE);
429   DeleteObject(hfont);
430   /* Forces a WM_PAINT message and erases background */
431   InvalidateRect(windraw->hWnd,NULL,TRUE);
432   UpdateWindow(windraw->hWnd);
433   PetscFunctionReturn(0);
434 }
435 
436 #undef __FUNCT__
437 #define __FUNCT__ "PetscDrawStringSetSize_Win32"
438 static PetscErrorCode PetscDrawStringSetSize_Win32(PetscDraw draw,PetscReal width,PetscReal height)
439 {
440   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
441   int             w,h;
442 
443   PetscFunctionBegin;
444   w = (int)((windraw->w)*width *(draw->port_xr - draw->port_xl)/(draw->coor_xr - draw->coor_xl));
445   h = (int)((windraw->h)*height*(draw->port_yr - draw->port_yl)/(draw->coor_yr - draw->coor_yl));
446   if (h < 1) h = 1;
447   if (w < 1) w = 1;
448   windraw->stringheight = h;
449   windraw->stringwidth  = w;
450   PetscFunctionReturn(0);
451 }
452 #undef __FUNCT__
453 #define __FUNCT__ "PetscDrawStringGetSize_Win32"
454 static PetscErrorCode PetscDrawStringGetSize_Win32(PetscDraw draw,PetscReal *width,PetscReal *height)
455 {
456   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
457   double          scaleX   = (draw->coor_xr - draw->coor_xl)/(draw->w)*(draw->port_xr - draw->port_xl);
458   double          scaleY   = (draw->coor_yr - draw->coor_yl)/(draw->h)*(draw->port_yr - draw->port_yl);
459 
460   PetscFunctionBegin;
461   *height = (double)windraw->stringheight*scaleY;
462   *width  = (double)windraw->stringwidth*scaleX;
463   PetscFunctionReturn(0);
464 }
465 
466 #undef __FUNCT__
467 #define __FUNCT__ "PetscDrawResizeWindow_Win32"
468 static PetscErrorCode PetscDrawResizeWindow_Win32(PetscDraw draw,int w,int h)
469 {
470   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
471   RECT            r;
472 
473   PetscFunctionBegin;
474   GetWindowRect(windraw->hWnd,&r);
475   MoveWindow(windraw->hWnd,r.left,r.top,(int)w,(int)h,TRUE);
476   /* set all variable dealing with window dimensions */
477   windraw->node->bitheight = windraw->h = draw->h = h;
478   windraw->node->bitwidth  = windraw->w = draw->w = w;
479   /* set up graphic buffers with the new size of window */
480   SetBitmapDimensionEx(windraw->node->BufferBit,w,h,NULL);
481   if (windraw->node->DoubleBuffered) SetBitmapDimensionEx(windraw->node->DoubleBufferBit,w,h,NULL);
482   windraw->haveresized = PETSC_TRUE;
483   PetscFunctionReturn(0);
484 }
485 
486 #undef __FUNCT__
487 #define __FUNCT__ "PetscDrawCheckResizeWindow_Win32"
488 static PetscErrorCode PetscDrawCheckResizedWindow_Win32(PetscDraw draw)
489 {
490   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
491 
492   PetscFunctionBegin;
493   if (windraw->haveresized == 1) PetscFunctionReturn(1);
494   else PetscFunctionReturn(0);
495 }
496 
497 #undef __FUNCT__
498 #define __FUNCT__ "PetscDrawSetTitle_Win32"
499 static PetscErrorCode PetscDrawSetTitle_Win32(PetscDraw draw, const char title[])
500 {
501   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
502 
503   PetscFunctionBegin;
504   SetWindowText(windraw->hWnd,title);
505   PetscFunctionReturn(0);
506 }
507 
508 #undef __FUNCT__
509 #define __FUNCT__ "PetscDrawClear_Win32"
510 static PetscErrorCode PetscDrawClear_Win32(PetscDraw draw)
511 {
512   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
513 
514   PetscFunctionBegin;
515   /* clear primary buffer */
516   ExtFloodFill(windraw->node->Buffer,0,0,COLOR_WINDOW,FLOODFILLBORDER);
517   /* if exists clear secondary buffer */
518   if (windraw->node->DoubleBuffered) ExtFloodFill(windraw->node->DoubleBuffer,0,0,COLOR_WINDOW,FLOODFILLBORDER);
519 
520   /* force WM_PAINT message so cleared buffer will show */
521   InvalidateRect(windraw->hWnd,NULL,TRUE);
522   UpdateWindow(windraw->hWnd);
523   PetscFunctionReturn(0);
524 }
525 
526 #undef __FUNCT__
527 #define __FUNCT__ "PetscDrawTriangle_Win32"
528 static PetscErrorCode PetscDrawTriangle_Win32(PetscDraw draw,PetscReal x1,PetscReal yone,PetscReal x2,PetscReal y2,
529                                               PetscReal x3,PetscReal y3,int c1,int c2,int c3)
530 {
531   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
532   HBRUSH          hbrush;
533   HPEN            hpen;
534   int             p1x,p1y,p2x,p2y,p3x,p3y;
535   HDC             bit;
536 
537   PetscFunctionBegin;
538   AverageColorTriangle_Win32(draw,c1,c2,c3);
539   hbrush = CreateSolidBrush(windraw->currentcolor);
540   hpen   = CreatePen(PS_SOLID,0,windraw->currentcolor);
541   p1x    = XTRANS(draw,windraw,x1);
542   p2x    = XTRANS(draw,windraw,x2);
543   p3x    = XTRANS(draw,windraw,x3);
544   p1y    = YTRANS(draw,windraw,yone);
545   p2y    = YTRANS(draw,windraw,y2);
546   p3y    = YTRANS(draw,windraw,y3);
547 
548   if (windraw->node->DoubleBuffered) bit = windraw->node->DoubleBuffer;
549   else                               bit = windraw->node->Buffer;
550 
551   BeginPath(bit);
552   MoveToEx(bit,p1x,p1y,NULL);
553   LineTo(bit,p2x,p2y);
554   LineTo(bit,p3x,p3y);
555   LineTo(bit,p1x,p1y);
556   EndPath(bit);
557   SelectPen(bit,hpen);
558   SelectBrush(bit,hbrush);
559   StrokeAndFillPath(bit);
560   /* Forces a WM_PAINT message and erases background */
561   InvalidateRect(windraw->hWnd,NULL,TRUE);
562   UpdateWindow(windraw->hWnd);
563   PetscFunctionReturn(0);
564 }
565 
566 #undef __FUNCT__
567 #define __FUNCT__ "PopMessageLoopThread_Win32"
568 void PopMessageLoopThread_Win32(PetscDraw popdraw)
569 {
570   PetscDraw_Win32 *pop = (PetscDraw_Win32*)popdraw->data;
571   MSG             msg;
572   HWND            hWnd = NULL;
573   char            PopClassName [MAX_LOADSTRING + 1];
574   RECT            r;
575   int             width,height;
576   WNDCLASSEX      myclass;
577   LPVOID          lpMsgBuf;
578 
579   PetscFunctionBegin;
580   /* initialize window class parameters */
581   myclass.cbSize        = sizeof(WNDCLASSEX);
582   myclass.style         = CS_OWNDC;
583   myclass.lpfnWndProc   = (WNDPROC)PetscWndProc;
584   myclass.cbClsExtra    = 0;
585   myclass.cbWndExtra    = 0;
586   myclass.hInstance     = NULL;
587   myclass.hIcon         = NULL;
588   myclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
589   myclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
590   myclass.lpszMenuName  = NULL;
591   myclass.lpszClassName = PopClassName;
592   myclass.hIconSm       = NULL;
593 
594   RegisterClassEx(&myclass);
595 
596   SetRect(&r,0,0,450,450);
597 
598   width  = (r.right - r.left) / 3;
599   height = (r.bottom - r.top) / 3;
600 
601   hWnd = CreateWindowEx(0,
602                         PopClassName,
603                         NULL,
604                         WS_POPUPWINDOW | WS_CAPTION,
605                         0,0,
606                         width,height,
607                         NULL,
608                         NULL,
609                         hInst,
610                         NULL);
611   pop->x = 0;
612   pop->y = 0;
613   pop->w = width;
614   pop->h = height;
615 
616   if (!hWnd) {
617     lpMsgBuf = (LPVOID)"Window Not Succesfully Created";
618     MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION);
619     LocalFree(lpMsgBuf);
620     exit(0);
621   }
622   pop->hWnd = hWnd;
623   /* display and update new popup window */
624   ShowWindow(pop->hWnd, SW_SHOWNORMAL);
625   UpdateWindow(pop->hWnd);
626   SetEvent(pop->hReadyEvent);
627 
628   while (GetMessage(&msg, pop->hWnd, 0, 0)) {
629     TranslateMessage(&msg);
630     DispatchMessage(&msg);
631   }
632   PetscFunctionReturnVoid();
633 }
634 
635 #undef __FUNCT__
636 #define __FUNCT__ "PetscDrawDestroy_Win32"
637 static PetscErrorCode PetscDrawDestroy_Win32(PetscDraw draw)
638 {
639   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
640 
641   PetscFunctionBegin;
642   SendMessage(windraw->hWnd,WM_DESTROY,0,0);
643   PetscFree(windraw);
644   PetscFunctionReturn(0);
645 }
646 
647 #undef __FUNCT__
648 #define __FUNCT__ "PetscDrawSynchronizedFlush_Win32"
649 static PetscErrorCode PetscDrawSynchronizedFlush_Win32(PetscDraw draw)
650 {
651   /* Multi Processor is not implemeted yet */
652   PetscFunctionBegin;
653   PetscDrawFlush_Win32(draw);
654   PetscFunctionReturn(0);
655 }
656 
657 #undef __FUNCT__
658 #define __FUNCT__ "PetscDrawSynchronizedClear_Win32"
659 static PetscErrorCode PetscDrawSynchronizedClear_Win32(PetscDraw draw)
660 {
661   /* Multi Processor is not implemeted yet */
662   PetscFunctionBegin;
663   PetscDrawClear_Win32(draw);
664   PetscFunctionReturn(0);
665 }
666 
667 #undef __FUNCT__
668 #define __FUNCT__ "MessageLoopThread_Win32"
669 void MessageLoopThread_Win32(PetscDraw draw)
670 {
671   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
672   MSG             msg;
673   HWND            hWnd = NULL;
674   char            classname[MAX_LOADSTRING + 1];
675   WNDCLASSEX      wclass;
676   LPVOID          lpMsgBuf;
677 
678   PetscFunctionBegin;
679   /* initialize window class parameters */
680   wclass.cbSize        = sizeof(WNDCLASSEX);
681   wclass.style         = CS_SAVEBITS | CS_HREDRAW | CS_VREDRAW;
682   wclass.lpfnWndProc   = (WNDPROC)PetscWndProc;
683   wclass.cbClsExtra    = 0;
684   wclass.cbWndExtra    = 0;
685   wclass.hInstance     = NULL;
686   wclass.hIcon         = LoadIcon(NULL,IDI_APPLICATION);
687   wclass.hCursor       = LoadCursor(NULL,IDC_ARROW);
688   wclass.hbrBackground = GetStockBrush(WHITE_BRUSH);
689   wclass.lpszMenuName  = NULL;
690   wclass.lpszClassName = classname;
691   wclass.hIconSm       = NULL;
692 
693   RegisterClassEx(&wclass);
694 
695 
696   hWnd = CreateWindowEx(0,
697                         classname,
698                         NULL,
699                         WS_OVERLAPPEDWINDOW,
700                         draw->x,
701                         draw->y,
702                         draw->w,
703                         draw->h,
704                         NULL,
705                         NULL,
706                         hInst,
707                         NULL);
708 
709   if (!hWnd) {
710     lpMsgBuf = (LPVOID)"Window Not Succesfully Created";
711     MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION);
712     LocalFree(lpMsgBuf);
713     exit(0);
714   }
715   windraw->hWnd = hWnd;
716   /* display and update new window */
717   ShowWindow(hWnd,SW_SHOWNORMAL);
718   UpdateWindow(hWnd);
719   SetEvent(windraw->hReadyEvent);
720 
721   while (GetMessage(&msg,hWnd, 0, 0)) {
722     TranslateMessage(&msg);
723     DispatchMessage(&msg);
724   }
725   PetscFunctionReturnVoid();
726 }
727 
728 
729 static struct _PetscDrawOps DvOps = { PetscDrawSetDoubleBuffer_Win32,
730                                       PetscDrawFlush_Win32,
731                                       PetscDrawLine_Win32,
732                                       PetscDrawLineSetWidth_Win32,
733                                       PetscDrawLineGetWidth_Win32,
734                                       PetscDrawPoint_Win32,
735                                       PetscDrawPointSetSize_Win32,
736                                       PetscDrawString_Win32,
737                                       PetscDrawStringVertical_Win32,
738                                       PetscDrawStringSetSize_Win32,
739                                       PetscDrawStringGetSize_Win32,
740                                       0,
741                                       PetscDrawClear_Win32,
742                                       PetscDrawSynchronizedFlush_Win32,
743                                       PetscDrawRectangle_Win32,
744                                       PetscDrawTriangle_Win32,
745                                       0,
746                                       PetscDrawGetMouseButton_Win32,
747                                       PetscDrawPause_Win32,
748                                       PetscDrawSynchronizedClear_Win32,
749                                       0,
750                                       0,
751                                       PetscDrawGetPopup_Win32,
752                                       PetscDrawSetTitle_Win32,
753                                       PetscDrawCheckResizedWindow_Win32,
754                                       PetscDrawResizeWindow_Win32,
755                                       PetscDrawDestroy_Win32,
756                                       0,
757                                       0,
758                                       0,
759                                       0};
760 
761 #undef __FUNCT__
762 #define __FUNCT__ "PetscDrawGetPopup_Win32"
763 static PetscErrorCode PetscDrawGetPopup_Win32(PetscDraw draw,PetscDraw *popdraw)
764 {
765   PetscDraw_Win32 *pop;
766   HANDLE          hThread = NULL;
767   WindowNode      newnode;
768   PetscErrorCode  ierr;
769 
770   PetscFunctionBegin;
771   ierr = PetscNew(&pop);CHKERRQ(ierr);
772 
773   (*popdraw)->data = pop;
774 
775   /* the following is temporary fix for initializing a global datastructure */
776   if (!g_hWindowListMutex) g_hWindowListMutex = CreateMutex(NULL,FALSE,NULL);
777   ierr = PetscMemcpy((*popdraw)->ops,&DvOps,sizeof(DvOps));CHKERRQ(ierr);
778 
779   pop->hReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
780   CreateThread(NULL, 0,(LPTHREAD_START_ROUTINE)PopMessageLoopThread_Win32,*popdraw,0,(unsigned long*)hThread);
781   CloseHandle(hThread);
782   WaitForSingleObject(pop->hReadyEvent, INFINITE);
783   CloseHandle(pop->hReadyEvent);
784   WaitForSingleObject(g_hWindowListMutex, INFINITE);
785 
786   draw->popup            = (*popdraw);
787   ierr                   = PetscNew(&newnode);CHKERRQ(ierr);
788   newnode->MouseListHead = NULL;
789   newnode->MouseListTail = NULL;
790   newnode->wnext         = WindowListHead;
791   newnode->wprev         = NULL;
792   newnode->hWnd          = pop->hWnd;
793   if (WindowListHead != NULL) WindowListHead->wprev = newnode;
794   WindowListHead         = newnode;
795   pop->hdc               = GetDC(pop->hWnd);
796 
797   pop->stringheight  = 10;
798   pop->stringwidth   = 6;
799   pop->linewidth     = 1;    /* default pixel sizes of graphics until user changes them */
800   pop->pointdiameter = 1;
801   pop->node          = newnode;
802 
803   newnode->bitwidth  = pop->w;
804   newnode->bitheight = pop->h;
805 
806   /* Create and initialize primary graphics buffer */
807   newnode->Buffer    = CreateCompatibleDC(pop->hdc);
808   newnode->BufferBit = CreateCompatibleBitmap(pop->hdc,pop->w,pop->h);
809   newnode->store     = SelectObject(newnode->Buffer,newnode->BufferBit);
810   ExtFloodFill(newnode->Buffer,0,0,COLOR_WINDOW,FLOODFILLBORDER);
811 
812 
813   newnode->event          = CreateEvent(NULL, TRUE, FALSE, NULL);
814   newnode->DoubleBuffered = PETSC_FALSE;
815 
816   ReleaseDC(pop->hWnd,pop->hdc);
817   ReleaseMutex(g_hWindowListMutex);
818   PetscFunctionReturn(0);
819 }
820 
821 #undef __FUNCT__
822 #define __FUNCT__ "PetscDrawCreate_Win32"
823 PETSC_EXTERN PetscErrorCode  PetscDrawCreate_Win32(PetscDraw draw)
824 {
825   PetscDraw_Win32 *windraw;
826   HANDLE          hThread = NULL;
827   PetscErrorCode  ierr;
828   WindowNode      newnode;
829 
830   PetscFunctionBegin;
831   ierr       = PetscNew(&windraw);CHKERRQ(ierr);
832   draw->data = windraw;
833 
834   /* the following is temporary fix for initializing a global datastructure */
835   if (!g_hWindowListMutex) g_hWindowListMutex = CreateMutex(NULL,FALSE,NULL);
836   ierr = PetscMemcpy(draw->ops,&DvOps,sizeof(DvOps));CHKERRQ(ierr);
837 
838   windraw->hReadyEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
839   /* makes call to MessageLoopThread to creat window and attach a thread */
840   CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)MessageLoopThread_Win32,draw,0,(unsigned long*)hThread);
841   CloseHandle(hThread);
842   WaitForSingleObject(windraw->hReadyEvent,INFINITE);
843   CloseHandle(windraw->hReadyEvent);
844   WaitForSingleObject(g_hWindowListMutex,INFINITE);
845 
846   ierr                   = PetscNew(&newnode);CHKERRQ(ierr);
847   newnode->MouseListHead = NULL;
848   newnode->MouseListTail = NULL;
849   newnode->wnext         = WindowListHead;
850   newnode->wprev         = NULL;
851   newnode->hWnd          = windraw->hWnd;
852   if (WindowListHead != NULL) WindowListHead->wprev = newnode;
853   WindowListHead         = newnode;
854   windraw->hdc           = GetDC(windraw->hWnd);
855 
856   windraw->stringheight  = 10;
857   windraw->stringwidth   = 6;
858   windraw->linewidth     = 1;    /* default pixel sizes of graphics until user changes them */
859   windraw->pointdiameter = 1;
860   windraw->node          = newnode;
861 
862   windraw->x = draw->x;
863   windraw->y = draw->y;
864   windraw->w = newnode->bitwidth    = draw->w;
865   windraw->h = newnode->bitheight   = draw->h;
866 
867   /* Create and initialize primary graphics buffer */
868   newnode->Buffer    = CreateCompatibleDC(windraw->hdc);
869   newnode->BufferBit = CreateCompatibleBitmap(windraw->hdc,windraw->w,windraw->h);
870   newnode->store     = SelectObject(newnode->Buffer,newnode->BufferBit);
871   ExtFloodFill(newnode->Buffer,0,0,COLOR_WINDOW,FLOODFILLBORDER);
872 
873   newnode->event          = CreateEvent(NULL,TRUE,FALSE,NULL);
874   newnode->DoubleBuffered = PETSC_FALSE;
875 
876   ReleaseDC(windraw->hWnd,windraw->hdc);
877   ReleaseMutex(g_hWindowListMutex);
878   PetscFunctionReturn(0);
879 }
880 
881 
882 /* FUNCTION: PetscWndProc(HWND, unsigned, WORD, LONG)
883    PURPOSE:  Processes messages for the main window.
884    WM_COMMAND  - process the application menu
885    WM_PAINT    - Paint the main window
886    WM_DESTROY  - post a quit message and return */
887 
888 #undef __FUNCT__
889 #define __FUNCT__ "PetscWndProc"
890 LRESULT CALLBACK PetscWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
891 {
892   int wmId, wmEvent;
893 
894   PetscFunctionBegin;
895   switch (message) {
896     HANDLE_MSG(hWnd,WM_PAINT,OnPaint_Win32);
897     HANDLE_MSG(hWnd,WM_DESTROY,OnDestroy_Win32);
898   case WM_COMMAND:
899     wmId    = LOWORD(wParam);
900     wmEvent = HIWORD(wParam);
901     /* Parse the menu selections:*/
902     switch (wmId) {
903     case IDM_EXIT:
904       DestroyWindow(hWnd);
905       break;
906     default:
907       return DefWindowProc(hWnd, message, wParam, lParam);
908     }
909     break;
910   case WM_LBUTTONUP:
911     MouseRecord_Win32(hWnd,PETSC_BUTTON_LEFT);
912     break;
913   case WM_RBUTTONUP:
914     MouseRecord_Win32(hWnd,PETSC_BUTTON_RIGHT);
915     break;
916   case WM_MBUTTONUP:
917     MouseRecord_Win32(hWnd,PETSC_BUTTON_CENTER);
918     break;
919   default:
920     PetscFunctionReturn(DefWindowProc(hWnd, message, wParam, lParam));
921   }
922   PetscFunctionReturn(0);
923 }
924 
925 #undef __FUNCT__
926 #define __FUNCT__ "OnPaint_Win32"
927 static void OnPaint_Win32(HWND hWnd)
928 {
929   PAINTSTRUCT ps;
930   HDC         hdc;
931   WindowNode  current = NULL;
932 
933   PetscFunctionBegin;
934   InvalidateRect(hWnd,NULL,TRUE);
935   WaitForSingleObject(g_hWindowListMutex, INFINITE);
936   current = WindowListHead;
937   hdc     = BeginPaint(hWnd, &ps);
938 
939   while (current != NULL) {
940     if (current->hWnd == hWnd) {
941       /* flushes primary buffer to window */
942       BitBlt(hdc,0,0,GetDeviceCaps(hdc,HORZRES),GetDeviceCaps(hdc,VERTRES),
943              current->Buffer,0,0,SRCCOPY);
944 
945       /* StretchBlt(hdc,0,0,w,h,
946         current->Buffer,0,0,current->bitwidth,current->bitheight,SRCCOPY); */
947       break;
948     }
949     current = current->wnext;
950   }
951   EndPaint(hWnd, &ps);
952   ReleaseMutex(g_hWindowListMutex);
953   PetscFunctionReturnVoid();
954 }
955 
956 #undef __FUNCT__
957 #define __FUNCT__ "MouseRecord_Win32"
958 static PetscErrorCode MouseRecord_Win32(HWND hWnd,PetscDrawButton button)
959 {
960   /* Called by all three mouse button actions
961     Records needed mouse data in windows data structure */
962   WindowNode     current = NULL;
963   MouseNode      newnode;
964   POINT          mousepos;
965   PetscErrorCode ierr;
966 
967   PetscFunctionBegin;
968   WaitForSingleObject(g_hWindowListMutex, INFINITE);
969   current = WindowListHead;
970   if (current->IsGetMouseOn == TRUE) {
971 
972     SetEvent(current->event);
973     while (current != NULL) {
974       if (current->hWnd == hWnd) {
975 
976         ierr            = PetscNew(&newnode);CHKERRQ(ierr);
977         newnode->Button = button;
978         GetCursorPos(&mousepos);
979         newnode->user.x = mousepos.x;
980         newnode->user.y = mousepos.y;
981         ScreenToClient(hWnd,&mousepos);
982         newnode->phys.x = mousepos.x;
983         newnode->phys.y = mousepos.y;
984         if (!current->MouseListTail) {
985           current->MouseListHead = newnode;
986           current->MouseListTail = newnode;
987         } else {
988           current->MouseListTail->mnext = newnode;
989           current->MouseListTail        = newnode;
990         }
991         newnode->mnext = NULL;
992 
993         break;
994       }
995       current = current->wnext;
996     }
997   }
998   ReleaseMutex(g_hWindowListMutex);
999   PetscFunctionReturn(0);
1000 }
1001 
1002 #undef __FUNCT__
1003 #define __FUNCT__ "OnDestroy_Win32"
1004 static void OnDestroy_Win32(HWND hWnd)
1005 {
1006   /* searches linked list of window data and frees corresponding memory */
1007   WindowNode current;
1008 
1009   PetscFunctionBegin;
1010   WaitForSingleObject(g_hWindowListMutex, INFINITE);
1011   current = WindowListHead;
1012 
1013   SetEvent(current->event);
1014   while (current != NULL) {
1015     if (current->hWnd == hWnd) {
1016       if (current->wprev != NULL) current->wprev->wnext = current->wnext;
1017       else WindowListHead = current->wnext;
1018       if (current->MouseListHead) deletemouselist_Win32(current);
1019       else PetscFree(current);
1020       break;
1021     }
1022     current = current->wnext;
1023   }
1024   ReleaseMutex(g_hWindowListMutex);
1025   PostQuitMessage(0);
1026   PetscFunctionReturnVoid();
1027 }
1028