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