]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkdrawable-win32.c
Some bug fixes and improvements to the Win32 GDK.
[~andy/gtk] / gdk / win32 / gdkdrawable-win32.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28
29 #include <math.h>
30 #include "gdk.h"
31 #include "gdkprivate.h"
32
33 #ifndef M_TWOPI
34 #define M_TWOPI         (2.0 * 3.14159265358979323846)
35 #endif
36
37 void
38 gdk_draw_point (GdkDrawable *drawable,
39                 GdkGC       *gc,
40                 gint         x,
41                 gint         y)
42 {
43   GdkWindowPrivate *drawable_private;
44   GdkGCPrivate *gc_private;
45   HDC hdc;
46
47   g_return_if_fail (drawable != NULL);
48   g_return_if_fail (gc != NULL);
49
50   drawable_private = (GdkWindowPrivate*) drawable;
51   if (drawable_private->destroyed)
52     return;
53   gc_private = (GdkGCPrivate*) gc;
54
55   hdc = gdk_gc_predraw (drawable_private, gc_private);
56
57   /* We use LineTo because SetPixel wants the COLORREF directly,
58    * and doesn't use the current pen, which is what we want.
59    */
60   if (!MoveToEx (hdc, x, y, NULL))
61     g_warning ("gdk_draw_point: MoveToEx failed");
62   if (!LineTo (hdc, x + 1, y))
63     g_warning ("gdk_draw_point: LineTo failed");
64   
65   gdk_gc_postdraw (drawable_private, gc_private);
66 }
67
68 void
69 gdk_draw_line (GdkDrawable *drawable,
70                GdkGC       *gc,
71                gint         x1,
72                gint         y1,
73                gint         x2,
74                gint         y2)
75 {
76   GdkWindowPrivate *drawable_private;
77   GdkGCPrivate *gc_private;
78   HDC hdc;
79
80   g_return_if_fail (drawable != NULL);
81   g_return_if_fail (gc != NULL);
82
83   drawable_private = (GdkWindowPrivate*) drawable;
84   if (drawable_private->destroyed)
85     return;
86   gc_private = (GdkGCPrivate*) gc;
87
88   hdc = gdk_gc_predraw (drawable_private, gc_private);
89     
90   GDK_NOTE (MISC, g_print ("gdk_draw_line: %#x (%d) +%d+%d..+%d+%d\n",
91                            drawable_private->xwindow, gc_private,
92                            x1, y1, x2, y2));
93   
94   MoveToEx (hdc, x1, y1, NULL);
95   if (!LineTo (hdc, x2, y2))
96     g_warning ("gdk_draw_line: LineTo #1 failed");
97   /* LineTo doesn't draw the last point, so if we have a pen width of 1,
98    * we draw the end pixel separately... With wider pens it hopefully
99    * doesn't matter?
100    */
101   if (gc_private->pen_width == 1)
102     if (!LineTo (hdc, x2 + 1, y2))
103       g_warning ("gdk_draw_line: LineTo #2 failed");
104   gdk_gc_postdraw (drawable_private, gc_private);
105 }
106
107 void
108 gdk_draw_rectangle (GdkDrawable *drawable,
109                     GdkGC       *gc,
110                     gint         filled,
111                     gint         x,
112                     gint         y,
113                     gint         width,
114                     gint         height)
115 {
116   GdkWindowPrivate *drawable_private;
117   GdkGCPrivate *gc_private;
118   HDC hdc;
119   HGDIOBJ oldpen, oldbrush;
120
121   g_return_if_fail (drawable != NULL);
122   g_return_if_fail (gc != NULL);
123
124   drawable_private = (GdkWindowPrivate*) drawable;
125   if (drawable_private->destroyed)
126     return;
127   gc_private = (GdkGCPrivate*) gc;
128
129   if (width == -1)
130     width = drawable_private->width;
131   if (height == -1)
132     height = drawable_private->height;
133
134   hdc = gdk_gc_predraw (drawable_private, gc_private);
135
136   GDK_NOTE (MISC, g_print ("gdk_draw_rectangle: %#x (%d) %s%dx%d@+%d+%d\n",
137                            drawable_private->xwindow,
138                            gc_private,
139                            (filled ? "fill " : ""),
140                            width, height, x, y));
141     
142 #if 0
143   {
144     HBRUSH hbr = GetCurrentObject (hdc, OBJ_BRUSH);
145     HPEN hpen = GetCurrentObject (hdc, OBJ_PEN);
146     LOGBRUSH lbr;
147     LOGPEN lpen;
148     GetObject (hbr, sizeof (lbr), &lbr);
149     GetObject (hpen, sizeof (lpen), &lpen);
150     
151     g_print ("current brush: style = %s, color = 0x%.08x\n",
152              (lbr.lbStyle == BS_SOLID ? "SOLID" : "???"),
153              lbr.lbColor);
154     g_print ("current pen: style = %s, width = %d, color = 0x%.08x\n",
155              (lpen.lopnStyle == PS_SOLID ? "SOLID" : "???"),
156              lpen.lopnWidth,
157              lpen.lopnColor);
158   }
159 #endif
160
161   if (filled)
162     oldpen = SelectObject (hdc, GetStockObject (NULL_PEN));
163   else
164     oldbrush = SelectObject (hdc, GetStockObject (HOLLOW_BRUSH));
165   
166   if (!Rectangle (hdc, x, y, x+width+1, y+height+1))
167     g_warning ("gdk_draw_rectangle: Rectangle failed");
168   
169   if (filled)
170     SelectObject (hdc, oldpen);
171   else
172     SelectObject (hdc, oldbrush);
173
174   gdk_gc_postdraw (drawable_private, gc_private);
175 }
176
177 void
178 gdk_draw_arc (GdkDrawable *drawable,
179               GdkGC       *gc,
180               gint         filled,
181               gint         x,
182               gint         y,
183               gint         width,
184               gint         height,
185               gint         angle1,
186               gint         angle2)
187 {
188   GdkWindowPrivate *drawable_private;
189   GdkGCPrivate *gc_private;
190   HDC hdc;
191   int nXStartArc, nYStartArc, nXEndArc, nYEndArc;
192
193   g_return_if_fail (drawable != NULL);
194   g_return_if_fail (gc != NULL);
195
196   drawable_private = (GdkWindowPrivate*) drawable;
197   if (drawable_private->destroyed)
198     return;
199   gc_private = (GdkGCPrivate*) gc;
200
201   if (width == -1)
202     width = drawable_private->width;
203   if (height == -1)
204     height = drawable_private->height;
205
206   hdc = gdk_gc_predraw (drawable_private, gc_private);
207
208   nXStartArc = x + width/2 + (int) (sin(angle1/64.*M_TWOPI)*width);
209   nYStartArc = y + height/2 + (int) (cos(angle1/64.*M_TWOPI)*height);
210   nXEndArc = x + width/2 + (int) (sin(angle2/64.*M_TWOPI)*width);
211   nYEndArc = y + height/2 + (int) (cos(angle2/64.*M_TWOPI)*height);
212
213   if (filled)
214     {
215       if (!Pie (hdc, x, y, x+width, y+height,
216                 nXStartArc, nYStartArc, nXEndArc, nYEndArc))
217         g_warning ("gdk_draw_arc: Pie failed");
218     }
219   else
220     {
221       if (!Arc (hdc, x, y, x+width, y+height,
222                 nXStartArc, nYStartArc, nXEndArc, nYEndArc))
223         g_warning ("gdk_draw_arc: Arc failed");
224     }
225   gdk_gc_postdraw (drawable_private, gc_private);
226 }
227
228 void
229 gdk_draw_polygon (GdkDrawable *drawable,
230                   GdkGC       *gc,
231                   gint         filled,
232                   GdkPoint    *points,
233                   gint         npoints)
234 {
235   GdkWindowPrivate *drawable_private;
236   GdkGCPrivate *gc_private;
237   HDC hdc;
238   POINT *pts;
239   int i;
240
241   g_return_if_fail (drawable != NULL);
242   g_return_if_fail (gc != NULL);
243
244   drawable_private = (GdkWindowPrivate*) drawable;
245   if (drawable_private->destroyed)
246     return;
247   gc_private = (GdkGCPrivate*) gc;
248
249   hdc = gdk_gc_predraw (drawable_private, gc_private);
250   pts = g_malloc ((npoints+1) * sizeof (POINT));
251
252   GDK_NOTE (MISC, g_print ("gdk_draw_polygon: %#x (%d) %d\n",
253                            drawable_private->xwindow, gc_private,
254                            npoints));
255
256   for (i = 0; i < npoints; i++)
257     {
258       pts[i].x = points[i].x;
259       pts[i].y = points[i].y;
260     }
261   
262   if ((points[0].x != points[npoints-1].x) ||
263       (points[0].y != points[npoints-1].y)) 
264     {
265       pts[npoints].x = points[0].x;
266       pts[npoints].y = points[0].y;
267       npoints++;
268     }
269   if (filled)
270     {
271       if (!Polygon (hdc, pts, npoints))
272         g_warning ("gdk_draw_polygon: Polygon failed");
273     }
274   else
275     {
276       if (!Polyline (hdc, pts, npoints))
277         g_warning ("gdk_draw_polygon: Polyline failed");
278     }
279   g_free (pts);
280   gdk_gc_postdraw (drawable_private, gc_private);
281 }
282
283 /* gdk_draw_string
284  */
285 void
286 gdk_draw_string (GdkDrawable *drawable,
287                  GdkFont     *font,
288                  GdkGC       *gc,
289                  gint         x,
290                  gint         y,
291                  const gchar *string)
292 {
293   gdk_draw_text (drawable, font, gc, x, y, string, strlen (string));
294 }
295
296 /* gdk_draw_text
297  *
298  * Modified by Li-Da Lho to draw 16 bits and Multibyte strings
299  *
300  * Interface changed: add "GdkFont *font" to specify font or fontset explicitely
301  */
302 void
303 gdk_draw_text (GdkDrawable *drawable,
304                GdkFont     *font,
305                GdkGC       *gc,
306                gint         x,
307                gint         y,
308                const gchar *text,
309                gint         text_length)
310 {
311   GdkWindowPrivate *drawable_private;
312   GdkFontPrivate *font_private;
313   GdkGCPrivate *gc_private;
314   HDC hdc;
315   HFONT xfont;
316   HGDIOBJ oldfont;
317
318   g_return_if_fail (drawable != NULL);
319   g_return_if_fail (font != NULL);
320   g_return_if_fail (gc != NULL);
321   g_return_if_fail (text != NULL);
322
323   drawable_private = (GdkWindowPrivate*) drawable;
324   if (drawable_private->destroyed)
325     return;
326   gc_private = (GdkGCPrivate*) gc;
327   font_private = (GdkFontPrivate*) font;
328
329   if (font->type == GDK_FONT_FONT)
330     {
331       hdc = gdk_gc_predraw (drawable_private, gc_private);
332       xfont = (HFONT) font_private->xfont;
333
334       GDK_NOTE (MISC, g_print ("gdk_draw_text: %#x (%d) %#x "
335                                "+%d+%d font: %#x \"%.*s\" length: %d\n",
336                                drawable_private->xwindow,
337                                gc_private, gc_private->xgc,
338                                x, y, xfont,
339                                (text_length > 10 ? 10 : text_length),
340                                text, text_length));
341       
342       if ((oldfont = SelectObject (hdc, xfont)) == NULL)
343         g_warning ("gdk_draw_text: SelectObject failed");
344       if (!TextOutA (hdc, x, y, text, text_length))
345         g_warning ("gdk_draw_text: TextOutA failed");
346       SelectObject (hdc, oldfont);
347       gdk_gc_postdraw (drawable_private, gc_private);
348     }
349   else
350     g_error ("undefined font type");
351 }
352
353 void
354 gdk_draw_text_wc (GdkDrawable    *drawable,
355                   GdkFont        *font,
356                   GdkGC          *gc,
357                   gint            x,
358                   gint            y,
359                   const GdkWChar *text,
360                   gint            text_length)
361 {
362   GdkWindowPrivate *drawable_private;
363   GdkFontPrivate *font_private;
364   GdkGCPrivate *gc_private;
365   gint i;
366   wchar_t *wcstr;
367
368   g_return_if_fail (drawable != NULL);
369   g_return_if_fail (font != NULL);
370   g_return_if_fail (gc != NULL);
371   g_return_if_fail (text != NULL);
372
373   drawable_private = (GdkWindowPrivate*) drawable;
374   if (drawable_private->destroyed)
375     return;
376   gc_private = (GdkGCPrivate*) gc;
377   font_private = (GdkFontPrivate*) font;
378
379   if (font->type == GDK_FONT_FONT)
380     {
381       HDC hdc;
382       HFONT xfont;
383       HGDIOBJ oldfont;
384
385       hdc = gdk_gc_predraw (drawable_private, gc_private);
386       xfont = (HFONT) font_private->xfont;
387
388       GDK_NOTE (MISC, g_print ("gdk_draw_text_wc: %#x (%d) %#x "
389                                "+%d+%d font: %#x length: %d\n",
390                                drawable_private->xwindow,
391                                gc_private, gc_private->xgc,
392                                x, y, xfont,
393                                text_length));
394       
395       if ((oldfont = SelectObject (hdc, xfont)) == NULL)
396         g_warning ("gdk_draw_text: SelectObject failed");
397       wcstr = g_new (wchar_t, text_length);
398       for (i = 0; i < text_length; i++)
399         wcstr[i] = text[i];
400       if (!TextOutW (hdc, x, y, wcstr, text_length))
401         g_warning ("gdk_draw_text: TextOutW failed");
402       g_free (wcstr);
403       SelectObject (hdc, oldfont);
404       gdk_gc_postdraw (drawable_private, gc_private);
405     }
406   else
407     g_error ("undefined font type");
408 }
409
410 void
411 gdk_draw_pixmap (GdkDrawable *drawable,
412                  GdkGC       *gc,
413                  GdkPixmap   *src,
414                  gint         xsrc,
415                  gint         ysrc,
416                  gint         xdest,
417                  gint         ydest,
418                  gint         width,
419                  gint         height)
420 {
421   GdkWindowPrivate *drawable_private;
422   GdkWindowPrivate *src_private;
423   GdkGCPrivate *gc_private;
424   HDC hdc;
425   HDC srcdc;
426   HGDIOBJ hgdiobj;
427
428   g_return_if_fail (drawable != NULL);
429   g_return_if_fail (src != NULL);
430   g_return_if_fail (gc != NULL);
431
432   drawable_private = (GdkWindowPrivate*) drawable;
433   src_private = (GdkWindowPrivate*) src;
434   if (drawable_private->destroyed || src_private->destroyed)
435     return;
436   gc_private = (GdkGCPrivate*) gc;
437
438   if (width == -1)
439     width = src_private->width;
440   if (height == -1)
441     height = src_private->height;
442
443   hdc = gdk_gc_predraw (drawable_private, gc_private);
444
445   GDK_NOTE (MISC, g_print ("gdk_draw_pixmap: dest: %#x destdc: (%d) %#x "
446                            "src: %#x %dx%d@+%d+%d\n",
447                            drawable_private->xwindow, gc_private, hdc,
448                            src_private->xwindow,
449                            width, height, xdest, ydest));
450
451   /* Strangely enough, this function is called also to bitblt
452    * from a window.
453    */
454   if (src_private->window_type == GDK_WINDOW_PIXMAP)
455     {
456       if ((srcdc = CreateCompatibleDC (hdc)) == NULL)
457         g_warning ("gdk_draw_pixmap: CreateCompatibleDC failed");
458       
459       if ((hgdiobj = SelectObject (srcdc, src_private->xwindow)) == NULL)
460         g_warning ("gdk_draw_pixmap: SelectObject #1 failed");
461       
462       if (!BitBlt (hdc, xdest, ydest, width, height,
463                    srcdc, xsrc, ysrc, SRCCOPY))
464         g_warning ("gdk_draw_pixmap: BitBlt failed");
465       
466       if ((SelectObject (srcdc, hgdiobj) == NULL))
467         g_warning ("gdk_draw_pixmap: SelectObject #2 failed");
468       
469       if (!DeleteDC (srcdc))
470         g_warning ("gdk_draw_pixmap: DeleteDC failed");
471     }
472   else
473     {
474       if ((srcdc = GetDC (src_private->xwindow)) == NULL)
475         g_warning ("gdk_draw_pixmap: GetDC failed");
476       
477       if (!BitBlt (hdc, xdest, ydest, width, height,
478                    srcdc, xsrc, ysrc, SRCCOPY))
479         g_warning ("gdk_draw_pixmap: BitBlt failed");
480       
481       ReleaseDC (src_private->xwindow, srcdc);
482     }
483   gdk_gc_postdraw (drawable_private, gc_private);
484 }
485
486 void
487 gdk_draw_image (GdkDrawable *drawable,
488                 GdkGC       *gc,
489                 GdkImage    *image,
490                 gint         xsrc,
491                 gint         ysrc,
492                 gint         xdest,
493                 gint         ydest,
494                 gint         width,
495                 gint         height)
496 {
497   GdkImagePrivate *image_private;
498
499   g_return_if_fail (drawable != NULL);
500   g_return_if_fail (image != NULL);
501   g_return_if_fail (gc != NULL);
502
503   image_private = (GdkImagePrivate*) image;
504
505   g_return_if_fail (image_private->image_put != NULL);
506
507   if (width == -1)
508     width = image->width;
509   if (height == -1)
510     height = image->height;
511
512   (* image_private->image_put) (drawable, gc, image, xsrc, ysrc,
513                                 xdest, ydest, width, height);
514 }
515
516 void
517 gdk_draw_points (GdkDrawable *drawable,
518                  GdkGC       *gc,
519                  GdkPoint    *points,
520                  gint         npoints)
521 {
522   GdkWindowPrivate *drawable_private;
523   GdkGCPrivate *gc_private;
524   HDC hdc;
525   int i;
526
527   g_return_if_fail (drawable != NULL);
528   g_return_if_fail ((points != NULL) && (npoints > 0));
529   g_return_if_fail (gc != NULL);
530
531   drawable_private = (GdkWindowPrivate*) drawable;
532   if (drawable_private->destroyed)
533     return;
534   gc_private = (GdkGCPrivate*) gc;
535
536   hdc = gdk_gc_predraw (drawable_private, gc_private);
537   
538   GDK_NOTE (MISC, g_print ("gdk_draw_points: %#x destdc: (%d) %#x "
539                            "npoints: %d\n",
540                            drawable_private->xwindow, gc_private, hdc,
541                            npoints));
542
543   for (i = 0; i < npoints; i++)
544     {
545       if (!MoveToEx (hdc, points[i].x, points[i].y, NULL))
546         g_warning ("gdk_draw_points: MoveToEx failed");
547       if (!LineTo (hdc, points[i].x + 1, points[i].y))
548         g_warning ("gdk_draw_points: LineTo failed");
549     }
550   gdk_gc_postdraw (drawable_private, gc_private);
551 }
552
553 void
554 gdk_draw_segments (GdkDrawable *drawable,
555                    GdkGC       *gc,
556                    GdkSegment  *segs,
557                    gint         nsegs)
558 {
559   GdkWindowPrivate *drawable_private;
560   GdkGCPrivate *gc_private;
561   HDC hdc;
562   int i;
563
564   if (nsegs <= 0)
565     return;
566
567   g_return_if_fail (drawable != NULL);
568   g_return_if_fail (segs != NULL);
569   g_return_if_fail (gc != NULL);
570
571   drawable_private = (GdkWindowPrivate*) drawable;
572   if (drawable_private->destroyed)
573     return;
574   gc_private = (GdkGCPrivate*) gc;
575
576   hdc = gdk_gc_predraw (drawable_private, gc_private);
577
578   for (i = 0; i < nsegs; i++)
579     {
580       if (!MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL))
581         g_warning ("gdk_draw_segments: MoveToEx failed");
582       if (!LineTo (hdc, segs[i].x2, segs[i].y2))
583         g_warning ("gdk_draw_segments: LineTo #1 failed");
584       
585       /* Draw end pixel */
586       if (gc_private->pen_width == 1)
587         if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
588           g_warning ("gdk_draw_segments: LineTo #2 failed");
589     }
590   gdk_gc_postdraw (drawable_private, gc_private);
591 }
592
593 void
594 gdk_draw_lines (GdkDrawable *drawable,
595                 GdkGC       *gc,
596                 GdkPoint    *points,
597                 gint         npoints)
598 {
599   GdkWindowPrivate *drawable_private;
600   GdkGCPrivate *gc_private;
601   HDC hdc;
602   POINT *pts;
603   int i;
604
605   if (npoints <= 0)
606     return;
607
608   g_return_if_fail (drawable != NULL);
609   g_return_if_fail (points != NULL);
610   g_return_if_fail (gc != NULL);
611
612   drawable_private = (GdkWindowPrivate*) drawable;
613   gc_private = (GdkGCPrivate*) gc;
614
615   hdc = gdk_gc_predraw (drawable_private, gc_private);
616 #if 1
617   pts = g_malloc (npoints * sizeof (POINT));
618
619   for (i = 0; i < npoints; i++)
620     {
621       pts[i].x = points[i].x;
622       pts[i].y = points[i].y;
623     }
624   
625   if (!Polyline (hdc, pts, npoints))
626     g_warning ("gdk_draw_lines: Polyline failed");
627   
628   g_free (pts);
629   
630   /* Draw end pixel */
631   if (gc_private->pen_width == 1)
632     {
633       MoveToEx (hdc, points[npoints-1].x, points[npoints-1].y, NULL);
634       if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
635         g_warning ("gdk_draw_lines: LineTo failed");
636     }
637 #else
638   MoveToEx (hdc, points[0].x, points[0].y, NULL);
639   for (i = 1; i < npoints; i++)
640     if (!LineTo (hdc, points[i].x, points[i].y))
641       g_warning ("gdk_draw_lines: LineTo #1 failed");
642   
643   /* Draw end pixel */
644   if (gc_private->pen_width == 1)
645     if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
646       g_warning ("gdk_draw_lines: LineTo #2 failed");
647 #endif  
648   gdk_gc_postdraw (drawable_private, gc_private);
649 }