1 /* High Contrast - a cairo based GTK+ engine
2  * Copyright (C) 2003 Sun Microsystems Inc.
3  * Copyright (C) 2006 Andrew Johnson <acjgenius@earthlink.net>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  * Project contact: <gnome-themes-list@gnome.org>
20  *
21  *
22  * This file contains code from GTK+,
23  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, and Josh MacDonald,
24  * which is also available under the GNU LGPL 2.1 and later versions
25  *
26  */
27 
28 
29 #include "hc_gtk2_engine.h"
30 #include "hc_gtk2_support.h"
31 #include "hc_gtk2_drawing.h"
32 
33 #include <gtk/gtk.h>
34 
35 #include <math.h>
36 #include <string.h>
37 
38 /* Standard Border Function */
39 void
hc_draw_shadow(GtkStyle * style,GdkWindow * window,GtkStateType state_type,GtkShadowType shadow_type,GdkRectangle * area,GtkWidget * widget,const gchar * detail,gint x,gint y,gint width,gint height)40 hc_draw_shadow(GtkStyle * style,
41 	       GdkWindow * window,
42 	       GtkStateType state_type,
43 	       GtkShadowType shadow_type,
44 	       GdkRectangle * area,
45 	       GtkWidget * widget,
46 	       const gchar * detail,
47 	       gint x,
48 	       gint y,
49 	       gint width,
50 	       gint height)
51 {
52 	/* Border Uses Foreground Color */
53 	CairoColor foreground = HC_STYLE(style)->color_cube.fg[state_type];
54 
55 	gint line_width;
56 	gint clip_x = x, clip_y = y, clip_width = width, clip_height = height;
57 
58 	cairo_t *canvas;
59 
60 	/***********************************************/
61 	/* GTK Sanity Checks                           */
62 	/***********************************************/
63 	CHECK_ARGS
64 	SANITIZE_SIZE
65 
66 
67 	/***********************************************/
68 	/* GTK Special Cases - adjust Size/Offset      */
69 	/***********************************************/
70 	line_width = HC_STYLE(style)->edge_thickness;
71 
72 	if (CHECK_DETAIL (detail, "menubar") && ge_is_panel_widget_item(widget))
73 	{
74 		return;
75 	}
76 
77 	/* Spin Button */
78 	if ((CHECK_DETAIL(detail, "spinbutton_up")) || (CHECK_DETAIL(detail, "spinbutton_down")))
79 	{
80 		/* Overdraw Height By Half The Line Width -
81 			Prevents Double line Between buttons */
82 		height += floor(line_width / 2);
83 
84 
85 		/* If Down Button Offset By Half Line Width */
86 		if (CHECK_DETAIL(detail, "spinbutton_down"))
87 		{
88 			y -= floor(line_width / 2);
89 		}
90 
91 
92 		/* Overdraw Width By Line Width -
93 			Prevents Double line Between Entry And Buttons */
94 		width += line_width;
95 
96 
97 		/* If LTR Offset X By Line Width */
98 		if (ge_widget_is_ltr (widget))
99 		{
100 			x -= line_width;
101 		}
102 
103 		/* Force Border To Use Foreground Widget State */
104 		if (widget)
105 		{
106 			foreground = HC_STYLE(style)->color_cube.fg[widget->state];
107 		}
108 	}
109 
110 
111 	/* Entry - Force Border To Use Foreground Matching Widget State */
112 	if (CHECK_DETAIL(detail, "entry") && !ge_is_combo(widget))
113 	{
114 		foreground = HC_STYLE(style)->color_cube.fg[widget ? widget->state : GTK_STATE_NORMAL];
115 	}
116 
117 
118 	/* Combo Box Button's */
119 	if (CHECK_DETAIL(detail, "button") && ge_is_in_combo_box(widget))
120 	{
121 		/* Overdraw Width By Line Width -
122 			Prevents Double Line Between Entry and Button. */
123 		width += line_width;
124 
125 
126 		/* If LTR Offset X By Line Width */
127 		if (ge_widget_is_ltr (widget))
128 		{
129 			x -= line_width;
130 		}
131 
132 
133 		/* Force Border To Use Foreground Matching Parent State */
134 		if ((widget) && (widget->parent))
135 		{
136 			gtk_widget_ensure_style(widget->parent);
137 			ge_gdk_color_to_cairo(&widget->parent->style->fg[GTK_WIDGET_STATE(widget)], &foreground);
138 		}
139 	}
140 
141 
142 	/***********************************************/
143 	/* Draw Border                                 */
144 	/***********************************************/
145 	canvas = ge_gdk_drawable_to_cairo (window, area);
146 
147 	/* Clip Border Too Passed Size */
148 	cairo_rectangle(canvas, clip_x, clip_y, clip_width, clip_height);
149 	cairo_clip(canvas);
150 
151 	/* Set Line Style */
152 	ge_cairo_set_color(canvas, &foreground);
153 	cairo_set_line_cap(canvas, CAIRO_LINE_CAP_BUTT);
154 
155 	cairo_set_line_width (canvas, line_width);
156 	ge_cairo_inner_rectangle (canvas, x, y, width, height);
157 
158 	cairo_stroke(canvas);
159 
160 	cairo_destroy(canvas);
161 }
162 
163 
164 /* Border Function For Frame && Notebook,
165 	With Gap For Text and/or Tabs
166  */
167 void
hc_draw_shadow_gap(GtkStyle * style,GdkWindow * window,GtkStateType state_type,GtkShadowType shadow_type,GdkRectangle * area,GtkWidget * widget,const gchar * detail,gint x,gint y,gint width,gint height,GtkPositionType gap_side,gint gap_pos,gint gap_size)168 hc_draw_shadow_gap (GtkStyle       *style,
169 		    GdkWindow      *window,
170 		    GtkStateType    state_type,
171 		    GtkShadowType   shadow_type,
172 		    GdkRectangle   *area,
173 		    GtkWidget      *widget,
174 		    const gchar    *detail,
175 		    gint            x,
176 		    gint            y,
177 		    gint            width,
178 		    gint            height,
179 		    GtkPositionType gap_side,
180 		    gint            gap_pos,
181 		    gint            gap_size)
182 {
183 	/* Border Uses Foreground Color */
184 	CairoColor *foreground = &HC_STYLE(style)->color_cube.fg[state_type];
185 	gint line_width;
186 	cairo_t *canvas;
187 
188 	/***********************************************/
189 	/* GTK Sanity Checks                           */
190 	/***********************************************/
191 	CHECK_ARGS
192 	SANITIZE_SIZE
193 
194 	if (shadow_type == GTK_SHADOW_NONE)
195 		return;
196 
197 	/***********************************************/
198 	/* GTK Special Cases - adjust Size/Offset      */
199 	/***********************************************/
200 	line_width = HC_STYLE(style)->edge_thickness;
201 
202 	if (CHECK_DETAIL (detail, "notebook"))
203 	{
204 		gap_pos += line_width;
205 		gap_size -= 2*line_width;
206 	}
207 
208 	/***********************************************/
209 	/* Draw Border                                 */
210 	/***********************************************/
211 	canvas = ge_gdk_drawable_to_cairo (window, area);
212 
213 	/* Create And Clip Too Path To Ignore Gap */
214 	hc_simple_border_gap_clip(canvas, line_width, x, y, width, height, gap_side, gap_pos, gap_size);
215 
216 
217 	/* Set Line Style */
218 	ge_cairo_set_color(canvas, foreground);
219 	cairo_set_line_cap(canvas, CAIRO_LINE_CAP_BUTT);
220 
221 	cairo_set_line_width (canvas, line_width);
222 	ge_cairo_inner_rectangle (canvas, x, y, width, height);
223 
224 	cairo_stroke(canvas);
225 
226 	cairo_destroy(canvas);
227 }
228 
229 
230 /* Border Function For Notebooks Tabs */
231 void
hc_draw_extension(GtkStyle * style,GdkWindow * window,GtkStateType state_type,GtkShadowType shadow_type,GdkRectangle * area,GtkWidget * widget,const gchar * detail,gint x,gint y,gint width,gint height,GtkPositionType gap_side)232 hc_draw_extension (GtkStyle       *style,
233 		   GdkWindow      *window,
234 		   GtkStateType    state_type,
235 		   GtkShadowType   shadow_type,
236 		   GdkRectangle   *area,
237 		   GtkWidget      *widget,
238 		   const gchar    *detail,
239 		   gint            x,
240 		   gint            y,
241 		   gint            width,
242 		   gint            height,
243 		   GtkPositionType gap_side)
244 {
245 	/* Fill Uses Background Color */
246 	CairoColor *background = &HC_STYLE(style)->color_cube.bg[state_type];
247 
248 	/* Border Uses Foreground Color */
249 	CairoColor *foreground = &HC_STYLE(style)->color_cube.fg[state_type];
250 
251 	gint line_width;
252 
253 	gint widget_x = 0, widget_y = 0, widget_width = 0, widget_height = 0;
254 	gint clip_x = x, clip_y = y, clip_width = width, clip_height = height;
255 
256 	cairo_t *canvas;
257 
258 	/***********************************************/
259 	/* GTK Sanity Checks                           */
260 	/***********************************************/
261 	CHECK_ARGS
262 	SANITIZE_SIZE
263 
264 
265 	/***********************************************/
266 	/* GTK Special Cases - adjust Size/Offset      */
267 	/***********************************************/
268 	line_width = HC_STYLE(style)->edge_thickness;
269 
270 	/* What all this is for -
271 
272 		GTK doesn't overlap Extensions and Notebooks,
273 		but rather a tab is drawn with a "gap" side.
274 
275 		Instead of long draw cases per gap side,
276 		perform a standard draw, but clipped to size,
277 		and overdraw edge thickness + one on gap side.
278 
279 		To fake the apearance of overlap on edge aligned tabs
280 		increase clip by edge thickness on gap side.
281 	 */
282 	if (widget && (GE_IS_NOTEBOOK (widget)))
283 	{
284 		widget_x = (widget->allocation.x + GTK_CONTAINER (widget)->border_width);
285 		widget_y = (widget->allocation.y + GTK_CONTAINER (widget)->border_width);
286 		widget_width = (widget->allocation.width - 2*GTK_CONTAINER (widget)->border_width);
287 		widget_height = (widget->allocation.height - 2*GTK_CONTAINER (widget)->border_width);
288 	}
289 
290 	switch (gap_side)
291 	{
292 		case GTK_POS_TOP:
293 			if (GTK_CHECK_VERSION(2,10,0) ||
294 				((widget && GE_IS_NOTEBOOK (widget)) &&
295 				((x==widget_x) ||
296 				((x + width) == (widget_x + widget_width)))))
297 			{
298 				clip_height += line_width;
299 
300 				if (!GTK_CHECK_VERSION(2,10,0))
301 				{
302 					height -= floor(line_width/2.0);
303 				}
304 			}
305 
306 			y -= (line_width + 1);
307 			height += (line_width + 1);
308 		break;
309 
310 		case GTK_POS_LEFT:
311 			if (GTK_CHECK_VERSION(2,10,0) ||
312 				((widget && GE_IS_NOTEBOOK (widget)) &&
313 				((y==widget_y) ||
314 				((y + height) == (widget_y + widget_height)))))
315 			{
316 				clip_width += line_width;
317 
318 				if (!GTK_CHECK_VERSION(2,10,0))
319 				{
320 					x -= floor(line_width/2.0);
321 				}
322 			}
323 
324 			x -= (line_width + 1);
325 			width += (line_width + 1);
326 		break;
327 
328 		default:
329 		case GTK_POS_BOTTOM:
330 			height += (line_width + 1);
331 		break;
332 
333 		case GTK_POS_RIGHT:
334 			width += (line_width + 1);
335 		break;
336 	}
337 
338 
339 	/***********************************************/
340 	/* Draw Border                                 */
341 	/***********************************************/
342 	canvas = ge_gdk_drawable_to_cairo (window, area);
343 
344 	/* Clip Too Size */
345 	cairo_rectangle(canvas, clip_x, clip_y, clip_width, clip_height);
346 	cairo_clip(canvas);
347 
348 
349 	/* Set Fill Style */
350 	ge_cairo_set_color(canvas, background);
351 
352 	/* Fill Rectangle */
353 	cairo_rectangle (canvas, x, y, width, height);
354 	cairo_fill(canvas);
355 
356 
357 	/* Set Line Style */
358 	ge_cairo_set_color(canvas, foreground);
359 	cairo_set_line_cap(canvas, CAIRO_LINE_CAP_BUTT);
360 
361 	cairo_set_line_width (canvas, line_width);
362 	ge_cairo_inner_rectangle (canvas, x, y, width, height);
363 
364 	cairo_stroke(canvas);
365 
366 	cairo_destroy(canvas);
367 }
368 
369 
370 /* Draw Function For Boxes Traditionally Either Without Borders,
371 		or With A Single Pixel Line */
372 void
hc_draw_flat_box(GtkStyle * style,GdkWindow * window,GtkStateType state_type,GtkShadowType shadow_type,GdkRectangle * area,GtkWidget * widget,const gchar * detail,gint x,gint y,gint width,gint height)373 hc_draw_flat_box (GtkStyle	*style,
374                   GdkWindow	*window,
375                   GtkStateType	 state_type,
376                   GtkShadowType	 shadow_type,
377                   GdkRectangle	*area,
378                   GtkWidget	*widget,
379                   const gchar	*detail,
380                   gint		 x,
381                   gint		 y,
382                   gint		 width,
383                   gint		 height)
384 {
385 	if (detail && !strcmp ("tooltip", detail))
386 	{
387 		hc_draw_box (style, window, state_type, shadow_type, area,
388 				widget, detail, x, y, width, height);
389 	}
390 	else
391 	{
392 		GtkStyleClass *hc_parent_class;
393 		hc_parent_class = GTK_STYLE_CLASS (g_type_class_peek_parent (G_OBJECT_GET_CLASS(style)));
394 		hc_parent_class->draw_flat_box (style, window, state_type, shadow_type, area,
395 							widget, detail, x, y, width, height);
396 	}
397 }
398 
399 
400 /* Draw Function For Standard Boxes (Most Widgets)
401 	Ensures Fill And Border */
402 void
hc_draw_box(GtkStyle * style,GdkWindow * window,GtkStateType state_type,GtkShadowType shadow_type,GdkRectangle * area,GtkWidget * widget,const gchar * detail,gint x,gint y,gint width,gint height)403 hc_draw_box (GtkStyle	*style,
404                   GdkWindow	*window,
405                   GtkStateType	 state_type,
406                   GtkShadowType	 shadow_type,
407                   GdkRectangle	*area,
408                   GtkWidget	*widget,
409                   const gchar	*detail,
410                   gint		 x,
411                   gint		 y,
412                   gint		 width,
413                   gint		 height)
414 {
415 	/***********************************************/
416 	/* GTK Sanity Checks                           */
417 	/***********************************************/
418 	CHECK_ARGS
419 	SANITIZE_SIZE
420 
421 
422 	/***********************************************/
423 	/* GTK Special Cases - adjust Size/Offset      */
424 	/***********************************************/
425 
426 	/* Add Menu Shell Hack For Menu Bar Item Prelight */
427 	if (GE_IS_MENU_SHELL(widget))
428 	{
429 		hc_gtk2_engine_hack_menu_shell_setup_signals(widget);
430 	}
431 
432 
433 	/***********************************************/
434 	/* Draw Fill                                   */
435 	/***********************************************/
436 	gtk_style_apply_default_background (style, window,
437         					widget && !GTK_WIDGET_NO_WINDOW (widget),
438 						state_type, area, x, y, width, height);
439 
440 
441 	/***********************************************/
442 	/* Draw Border                                 */
443 	/***********************************************/
444 	hc_draw_shadow (style, window, state_type, shadow_type, area, widget, detail,
445 					x, y, width, height);
446 }
447 
448 
449 /* Draw Function For Boxes With Gap
450 
451 	Primarily For Frames With Text
452 	And Notebooks With Tabs.
453  */
454 void
hc_draw_box_gap(GtkStyle * style,GdkWindow * window,GtkStateType state_type,GtkShadowType shadow_type,GdkRectangle * area,GtkWidget * widget,const gchar * detail,gint x,gint y,gint width,gint height,GtkPositionType gap_side,gint gap_pos,gint gap_size)455 hc_draw_box_gap (GtkStyle       *style,
456 		 GdkWindow      *window,
457 		 GtkStateType    state_type,
458 		 GtkShadowType   shadow_type,
459 		 GdkRectangle   *area,
460 		 GtkWidget      *widget,
461 		 const gchar    *detail,
462 		 gint            x,
463 		 gint            y,
464 		 gint            width,
465 		 gint            height,
466 		 GtkPositionType gap_side,
467 		 gint            gap_pos,
468 		 gint            gap_size)
469 {
470 	/***********************************************/
471 	/* GTK Sanity Checks                           */
472 	/***********************************************/
473 	CHECK_ARGS
474 	SANITIZE_SIZE
475 
476 
477 	/***********************************************/
478 	/* Draw Fill                                   */
479 	/***********************************************/
480 	gtk_style_apply_default_background (style, window,
481 	                                    widget && !GTK_WIDGET_NO_WINDOW (widget),
482 	                                    state_type, area, x, y, width, height);
483 
484 
485 	/***********************************************/
486 	/* Draw Border                                 */
487 	/***********************************************/
488 	hc_draw_shadow_gap (style, window, state_type, shadow_type, area, widget, detail,
489 					x, y, width, height, gap_side, gap_pos, gap_size);
490 }
491 
492 
493 /* Draw Function For Boxes Commonly Needing Grips
494 
495 	Primarily For -
496 		Paned Handles
497 		Toolbar Handles
498  */
499 void
hc_draw_handle(GtkStyle * style,GdkWindow * window,GtkStateType state_type,GtkShadowType shadow_type,GdkRectangle * area,GtkWidget * widget,const gchar * detail,gint x,gint y,gint width,gint height,GtkOrientation orientation)500 hc_draw_handle (GtkStyle      *style,
501 		GdkWindow     *window,
502 		GtkStateType   state_type,
503 		GtkShadowType  shadow_type,
504 		GdkRectangle  *area,
505 		GtkWidget     *widget,
506 		const gchar   *detail,
507 		gint           x,
508 		gint           y,
509 		gint           width,
510 		gint           height,
511 		GtkOrientation orientation)
512 {
513 	gint clip_x = x, clip_y = y, clip_width = width, clip_height = height;
514 	gint xthick, ythick;
515 
516 	HcStyle *hc_style;
517 	gdouble xx, yy;
518 	CairoColor *light, *dark;
519 	cairo_t *canvas;
520 
521 	/***********************************************/
522 	/* GTK Sanity Checks                           */
523 	/***********************************************/
524 	CHECK_ARGS
525 	SANITIZE_SIZE
526 
527 
528 	/***********************************************/
529 	/* GTK Special Cases - adjust Size/Offset      */
530 	/***********************************************/
531 	xthick = style->xthickness;
532 	ythick = style->ythickness;
533 
534 	if (CHECK_DETAIL(detail, "paned"))
535 	{
536 		/* we want to ignore the shadow border in paned widgets */
537 		xthick = 0;
538 		ythick = 0;
539 	}
540 
541 	clip_x = x + xthick;
542 	clip_y = y + ythick;
543 	clip_width = width - (xthick * 2);
544 	clip_height = height - (ythick * 2);
545 
546 
547 	/***********************************************/
548 	/* Draw Box                                    */
549 	/***********************************************/
550 	hc_draw_box (style, window, state_type, shadow_type, area, widget,
551 			detail, x, y, width, height);
552 
553 
554 	/***********************************************/
555 	/* Draw Grip                                   */
556 	/***********************************************/
557 	hc_style = HC_STYLE (style);
558 
559 	light = &hc_style->color_cube.light[state_type];
560 	dark = &hc_style->color_cube.dark[state_type];
561 
562 	canvas = ge_gdk_drawable_to_cairo (window, area);
563 
564 	/* Clip Too Size */
565 	cairo_rectangle(canvas, clip_x, clip_y, clip_width, clip_height);
566 	cairo_clip(canvas);
567 
568 	if (CHECK_DETAIL (detail, "paned"))
569 	{
570 		if (orientation == GTK_ORIENTATION_HORIZONTAL)
571 		{
572 			for (xx = x + width/2.0 - 15; xx <= x + width/2.0 + 15; xx += 5)
573 				do_hc_draw_dot (canvas, light, dark, xx, y + height/2.0);
574 		}
575 		else
576 		{
577 			for (yy = y + height/2 - 15; yy <= y + height/2.0 + 15; yy += 5)
578 			{
579 				do_hc_draw_dot (canvas, light, dark, x + width/2.0, yy);
580 			}
581 		}
582 	}
583 	else
584 	{
585 		if (orientation == GTK_ORIENTATION_HORIZONTAL)
586 		{
587 			for (xx = x + xthick + (width/2 - xthick) % 5; xx <= x + width - xthick*2; xx += 5)
588 				do_hc_draw_dot (canvas, light, dark, xx + 2, y + height/2);
589 		}
590 		else
591 		{
592 			for (yy = y + ythick + (height/2 - ythick) % 5; yy <= y + height - ythick*2; yy += 5)
593 				do_hc_draw_dot (canvas, light, dark, x + width/2, yy + 2);
594 		}
595 	}
596 
597 	cairo_destroy(canvas);
598 }
599 
600 
601 void
hc_draw_slider(GtkStyle * style,GdkWindow * window,GtkStateType state_type,GtkShadowType shadow_type,GdkRectangle * area,GtkWidget * widget,const gchar * detail,gint x,gint y,gint width,gint height,GtkOrientation orientation)602 hc_draw_slider (GtkStyle * style,
603 	     GdkWindow * window,
604 	     GtkStateType state_type,
605 	     GtkShadowType shadow_type,
606 	     GdkRectangle * area,
607 	     GtkWidget * widget,
608 	     const gchar * detail,
609 	     gint x,
610 	     gint y,
611              gint width,
612              gint height,
613              GtkOrientation orientation)
614 {
615 	cairo_t *canvas;
616 	gint line_width;
617 
618 	CHECK_ARGS
619 	SANITIZE_SIZE
620 
621 	canvas = ge_gdk_drawable_to_cairo (window, area);
622 
623 	/***********************************************/
624 	/* Draw Box                                    */
625 	/***********************************************/
626 	line_width = HC_STYLE(style)->edge_thickness;
627 
628 	hc_draw_box (style, window, state_type, shadow_type, area, widget,
629 			detail, x, y, width, height);
630 
631 	if (GE_IS_SCALE(widget))
632 	{
633 		if (orientation == GTK_ORIENTATION_HORIZONTAL)
634 		{
635 			do_hc_draw_line (canvas, &HC_STYLE(style)->color_cube.fg[state_type],
636 						line_width /2,
637 						x + ceil(width/2.0) + 0.5,
638 						y + line_width,
639 						x + ceil(width/2.0) + 0.5,
640 						y + height - line_width);
641 		}
642 		else
643 		{
644 			do_hc_draw_line (canvas, &HC_STYLE(style)->color_cube.fg[state_type],
645 						line_width /2,
646 						x + line_width,
647 						y + ceil(height/2.0) + 0.5,
648 						x + width - line_width,
649 						y + ceil(height/2.0) + 0.5);
650 		}
651 	}
652 
653 	cairo_destroy(canvas);
654 }
655 
656 /* Draw Check Buttons Check & Border */
657 void
hc_draw_check(GtkStyle * style,GdkWindow * window,GtkStateType state_type,GtkShadowType shadow_type,GdkRectangle * area,GtkWidget * widget,const gchar * detail,gint x,gint y,gint width,gint height)658 hc_draw_check (GtkStyle      *style,
659 	       GdkWindow     *window,
660 	       GtkStateType   state_type,
661 	       GtkShadowType  shadow_type,
662 	       GdkRectangle  *area,
663 	       GtkWidget     *widget,
664 	       const gchar   *detail,
665 	       gint           x,
666 	       gint           y,
667 	       gint           width,
668 	       gint           height)
669 {
670 	HcStyle *hc_style = HC_STYLE (style);
671 	gboolean inconsistent;
672 	gint line_width;
673 	cairo_t *cr;
674 
675 	CHECK_ARGS
676 	SANITIZE_SIZE
677 
678 	/* Bug #351764 */
679 	if ((!GTK_CHECK_VERSION(2,12,0)) &&
680 			CHECK_DETAIL(detail, "cellcheck"))
681 	{
682 		x += (width - HC_STYLE(style)->cell_indicator_size)/2;
683 		y += (height - HC_STYLE(style)->cell_indicator_size)/2;
684 		width = HC_STYLE(style)->cell_indicator_size;
685 		height = HC_STYLE(style)->cell_indicator_size;
686 	}
687 
688 	inconsistent = (shadow_type == GTK_SHADOW_ETCHED_IN);
689 
690 	line_width = ceil(HC_STYLE(style)->edge_thickness/2.0);
691 	cr = ge_gdk_drawable_to_cairo (window, area);
692 
693 	cairo_save(cr);
694 
695 	ge_cairo_set_color(cr, &hc_style->color_cube.base[state_type]);
696 
697 	cairo_rectangle (cr, x, y, width, height);
698 
699 	cairo_fill(cr);
700 
701 	/* Set Line Style */
702 	ge_cairo_set_color(cr, &hc_style->color_cube.fg[state_type]);
703 	cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
704 
705 	cairo_set_line_width (cr, line_width);
706 
707 	/* Stroke Rectangle */
708 	ge_cairo_stroke_rectangle (cr, x + line_width/2.0, y + line_width/2.0, width - line_width, height - line_width);
709 
710 	cairo_restore(cr);
711 
712 	if ((shadow_type == GTK_SHADOW_IN) || inconsistent)
713 	{
714 		cairo_save (cr);
715 		/* Clip to the inner area. */
716 		cairo_rectangle (cr, x + line_width, y + line_width, width - 2*line_width, height - 2*line_width);
717 		cairo_clip (cr);
718 
719 		ge_cairo_set_color(cr, &hc_style->color_cube.fg[state_type]);
720 
721 		line_width = ceil(MIN(width,height)/5.0);
722 
723 		if (inconsistent)
724 		{
725 			cairo_set_line_width (cr, line_width);
726 
727 			cairo_move_to(cr, x, y + floor(height/2.0) + (line_width%2)/2.0);
728 			cairo_line_to(cr, x + width, y + floor(height/2.0) + (line_width%2)/2.0);
729 		}
730 		else
731 		{
732 			cairo_set_line_width (cr, line_width);
733 
734 			/* Backward Diagonal */
735 			cairo_move_to(cr, x, y);
736 			cairo_line_to(cr, x + width, y + height);
737 
738 			/* Forward Diagonal */
739 			cairo_move_to(cr, x, y + height);
740 			cairo_line_to(cr, x + width, y);
741 		}
742 
743 		cairo_stroke (cr);
744 
745 		cairo_restore (cr);
746 	}
747 
748 	cairo_destroy(cr);
749 }
750 
751 /* Draw Radio Button AKA Option Button Check & Border */
752 void
hc_draw_option(GtkStyle * style,GdkWindow * window,GtkStateType state_type,GtkShadowType shadow_type,GdkRectangle * area,GtkWidget * widget,const gchar * detail,gint x,gint y,gint width,gint height)753 hc_draw_option (GtkStyle      *style,
754 		GdkWindow     *window,
755 		GtkStateType   state_type,
756 		GtkShadowType  shadow_type,
757 		GdkRectangle  *area,
758 		GtkWidget     *widget,
759 		const gchar   *detail,
760 		gint           x,
761 		gint           y,
762 		gint           width,
763 		gint           height)
764 {
765 	HcStyle *hc_style = HC_STYLE (style);
766 	cairo_t *cr;
767 
768 	gint centerX;
769 	gint centerY;
770 	gint radius;
771 	gboolean inconsistent;
772 
773 	CHECK_ARGS
774 	SANITIZE_SIZE
775 
776 	/* Bug #351764 */
777 	if ((!GTK_CHECK_VERSION(2,12,0)) &&
778 			CHECK_DETAIL(detail, "cellradio"))
779 	{
780 		x += (width - HC_STYLE(style)->cell_indicator_size)/2;
781 		y += (height - HC_STYLE(style)->cell_indicator_size)/2;
782 		width = HC_STYLE(style)->cell_indicator_size;
783 		height = HC_STYLE(style)->cell_indicator_size;
784 	}
785 
786 	cr = ge_gdk_drawable_to_cairo (window, area);
787 
788 	centerX = x + floor(width/2);
789 	centerY = y + floor(height/2);
790 	radius = floor(MIN(width,height)/2.0);
791 
792 	cairo_set_line_width (cr, radius*0.30);
793 	cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
794 
795 	cairo_arc(cr, centerX, centerY, radius, 0 , 2 * G_PI);
796 	ge_cairo_set_color(cr, &hc_style->color_cube.bg[state_type]);
797 	cairo_fill (cr);
798 
799 	cairo_arc(cr, centerX, centerY, radius, 0 , 2 * G_PI);
800 	ge_cairo_set_color(cr, &hc_style->color_cube.fg[state_type]);
801 	cairo_stroke (cr);
802 
803 	inconsistent = (shadow_type == GTK_SHADOW_ETCHED_IN);
804 
805 	ge_cairo_set_color(cr, &hc_style->color_cube.text[state_type]);
806 
807 	if (shadow_type == GTK_SHADOW_IN)
808 	{
809 		cairo_arc(cr, centerX, centerY, radius*0.38, 0, 2 * G_PI);
810 		cairo_fill(cr);
811 		cairo_arc(cr, centerX, centerY, radius*0.38, 0, 2 * G_PI);
812 		cairo_stroke(cr);
813 	}
814 	else if (inconsistent)
815 	{
816 		int line_width = ceil(radius*0.68);
817 
818 		/* Force Thickness Even */
819 		line_width -= (line_width % 2);
820 
821 		cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
822 		cairo_set_line_width (cr, line_width);
823 
824 		cairo_move_to(cr, centerX - radius*0.38, centerY);
825 		cairo_line_to(cr, centerX + radius*0.38, centerY);
826 
827 		cairo_stroke (cr);
828 	}
829 
830 	cairo_destroy(cr);
831 }
832 
833 void
hc_draw_tab(GtkStyle * style,GdkWindow * window,GtkStateType state_type,GtkShadowType shadow_type,GdkRectangle * area,GtkWidget * widget,const gchar * detail,gint x,gint y,gint width,gint height)834 hc_draw_tab (GtkStyle      *style,
835 	     GdkWindow     *window,
836 	     GtkStateType   state_type,
837 	     GtkShadowType  shadow_type,
838 	     GdkRectangle  *area,
839 	     GtkWidget     *widget,
840 	     const gchar   *detail,
841 	     gint           x,
842 	     gint           y,
843 	     gint           width,
844 	     gint           height)
845 {
846 	GtkRequisition indicator_size;
847 	GtkBorder indicator_spacing;
848 
849 	HcStyle *hc_style = HC_STYLE (style);
850 	cairo_t *cr;
851 
852 	ge_option_menu_get_props (widget, &indicator_size, &indicator_spacing);
853 
854 	indicator_size.width += 2;
855 	indicator_size.height += 2;
856 
857 	if (ge_widget_is_ltr (widget))
858 	{
859 		x += width - indicator_size.width;
860  	}
861 
862 	y += ((height - indicator_size.height) / 2) + 1;
863 
864 	width = indicator_size.width;
865 	height = indicator_size.height;
866 
867 	cr = ge_gdk_drawable_to_cairo(window, area);
868 
869 	do_hc_draw_arrow (cr, &hc_style->color_cube.fg[state_type],
870 				GTK_ARROW_DOWN,TRUE, x, y,
871 				width, height);
872 
873 
874 	cairo_destroy(cr);
875 }
876 
877 void
hc_draw_layout(GtkStyle * style,GdkWindow * window,GtkStateType state_type,gboolean use_text,GdkRectangle * area,GtkWidget * widget,const gchar * detail,gint x,gint y,PangoLayout * layout)878 hc_draw_layout (GtkStyle        *style,
879 		GdkWindow       *window,
880 		GtkStateType     state_type,
881 		gboolean         use_text,
882 		GdkRectangle    *area,
883 		GtkWidget       *widget,
884 		const gchar     *detail,
885 		gint             x,
886 		gint             y,
887 		PangoLayout     *layout)
888 {
889 	GdkGC *gc;
890 
891 	CHECK_ARGS
892 
893 	gc = use_text ? style->text_gc[state_type] : style->fg_gc[state_type];
894 
895 	if (area)
896 		gdk_gc_set_clip_rectangle (gc, area);
897 
898 	gdk_draw_layout (window, gc, x, y, layout);
899 
900 	if (area)
901 		gdk_gc_set_clip_rectangle (gc, NULL);
902 }
903 
904 void
hc_draw_arrow(GtkStyle * style,GdkWindow * window,GtkStateType state,GtkShadowType shadow,GdkRectangle * area,GtkWidget * widget,const gchar * detail,GtkArrowType arrow_type,gboolean fill,gint x,gint y,gint width,gint height)905 hc_draw_arrow (GtkStyle      *style,
906 	       GdkWindow     *window,
907 	       GtkStateType   state,
908 	       GtkShadowType  shadow,
909 	       GdkRectangle  *area,
910 	       GtkWidget     *widget,
911 	       const gchar   *detail,
912 	       GtkArrowType   arrow_type,
913 	       gboolean       fill,
914 	       gint           x,
915 	       gint           y,
916 	       gint           width,
917 	       gint           height)
918 {
919 	gint line_width;
920 	HcStyle *hc_style;
921 	cairo_t *cr;
922 
923 	/***********************************************/
924 	/* GTK Sanity Checks                           */
925 	/***********************************************/
926 	CHECK_ARGS
927 	SANITIZE_SIZE
928 
929 	/***********************************************/
930 	/* GTK Arrow Special Cases - adjust Size/Offset*/
931 	/***********************************************/
932 	line_width = HC_STYLE(style)->edge_thickness;
933 
934 	if (ge_is_combo_box_entry (widget))
935 	{
936 		x -= 1;
937 
938 		if (ge_widget_is_ltr (widget))
939 		{
940 			x -= (line_width/2);
941 		}
942 		else
943 		{
944 			x += (line_width/2);
945 		}
946 	}
947 	else if (ge_is_combo_box(widget, FALSE))
948 	{
949 		if (ge_widget_is_ltr (widget))
950 		{
951 			x -= 2;
952 		}
953 	}
954 
955 
956 	if (ge_is_combo(widget))
957 	{
958 		y += 1;
959 		width -= 2;
960 		height -= 2;
961 
962 		if (ge_widget_is_ltr (widget))
963 		{
964 			x -= ((width%2)?0:1);
965 		}
966 		else
967 		{
968 			x += floor(line_width/2) + ((width%2)?1:0);
969 		}
970 	}
971 
972 	if (CHECK_DETAIL(detail, "menuitem"))
973 	{
974 		x -= 1;
975 	}
976 
977 	if (CHECK_DETAIL (detail, "arrow"))
978 	{
979 		x += (width%2)?0:1;
980 	}
981 
982 	/***********************************************/
983 	/* Draw Arrow                                  */
984 	/***********************************************/
985 	hc_style = HC_STYLE (style);
986 	cr = ge_gdk_drawable_to_cairo(window, area);
987 
988 	do_hc_draw_arrow (cr, &hc_style->color_cube.fg[state], arrow_type, TRUE,
989 				x, y, width+1, height+1);
990 
991 	cairo_destroy(cr);
992 }
993 
994 void
hc_draw_hline(GtkStyle * style,GdkWindow * window,GtkStateType state_type,GdkRectangle * area,GtkWidget * widget,const gchar * detail,gint x1,gint x2,gint y)995 hc_draw_hline (GtkStyle     *style,
996 	       GdkWindow    *window,
997 	       GtkStateType  state_type,
998 	       GdkRectangle  *area,
999 	       GtkWidget     *widget,
1000 	       const gchar   *detail,
1001 	       gint          x1,
1002 	       gint          x2,
1003 	       gint          y)
1004 {
1005 	HcStyle *hc_style = HC_STYLE (style);
1006 	cairo_t *cr;
1007 	gint line_width;
1008 
1009 	CHECK_ARGS
1010 
1011 	cr = ge_gdk_drawable_to_cairo (window, area);
1012 
1013 	line_width = style->ythickness/2;
1014 
1015 	do_hc_draw_line (cr, &hc_style->color_cube.fg[state_type], (CHECK_DETAIL(detail, "label"))?1:2*line_width - 1,
1016 	                 x1 + line_width + 2, y + style->ythickness/2 + 0.5,
1017 	                 x2 - line_width - 1, y + style->ythickness/2 + 0.5);
1018 
1019 	cairo_destroy(cr);
1020 }
1021 
1022 void
hc_draw_vline(GtkStyle * style,GdkWindow * window,GtkStateType state_type,GdkRectangle * area,GtkWidget * widget,const gchar * detail,gint y1,gint y2,gint x)1023 hc_draw_vline (GtkStyle     *style,
1024 	       GdkWindow    *window,
1025 	       GtkStateType  state_type,
1026 	       GdkRectangle  *area,
1027 	       GtkWidget     *widget,
1028 	       const gchar   *detail,
1029 	       gint          y1,
1030 	       gint          y2,
1031 	       gint          x)
1032 {
1033 	HcStyle *hc_style = HC_STYLE (style);
1034 	cairo_t *cr;
1035 	gint line_width;
1036 
1037 	CHECK_ARGS
1038 
1039 	cr = ge_gdk_drawable_to_cairo (window, area);
1040 
1041 	line_width = style->xthickness/2;
1042 
1043 	do_hc_draw_line (cr, &hc_style->color_cube.fg[state_type],  (CHECK_DETAIL(detail, "label"))?1:2*line_width - 1,
1044 	                 x + style->xthickness/2 + 0.5, y1,
1045 	                 x + style->xthickness/2 + 0.5, y2);
1046 
1047 	cairo_destroy(cr);
1048 }
1049 
1050 void
hc_draw_expander(GtkStyle * style,GdkWindow * window,GtkStateType state_type,GdkRectangle * area,GtkWidget * widget,const gchar * detail,gint x,gint y,GtkExpanderStyle expander_style)1051 hc_draw_expander (GtkStyle        *style,
1052                            GdkWindow       *window,
1053                            GtkStateType     state_type,
1054                            GdkRectangle    *area,
1055                            GtkWidget       *widget,
1056                            const gchar     *detail,
1057                            gint             x,
1058                            gint             y,
1059 			   GtkExpanderStyle expander_style)
1060 {
1061 #define DEFAULT_EXPANDER_SIZE 12
1062 
1063   HcStyle *hc_style = HC_STYLE (style);
1064 
1065   gint expander_size;
1066   gint line_width;
1067   double vertical_overshoot;
1068   int diameter;
1069   double radius;
1070   double interp;		/* interpolation factor for center position */
1071   double x_double_horz, y_double_horz;
1072   double x_double_vert, y_double_vert;
1073   double x_double, y_double;
1074   gint degrees = 0;
1075   cairo_t *cr;
1076 
1077   CHECK_ARGS
1078 
1079   cr = ge_gdk_drawable_to_cairo (window, area);
1080 
1081   if (widget &&
1082       gtk_widget_class_find_style_property (GTK_WIDGET_GET_CLASS (widget),
1083 					    "expander-size"))
1084     {
1085       gtk_widget_style_get (widget,
1086 			    "expander-size", &expander_size,
1087 			    NULL);
1088     }
1089   else
1090     expander_size = DEFAULT_EXPANDER_SIZE;
1091 
1092   line_width = MAX (1, expander_size/9);
1093 
1094   switch (expander_style)
1095     {
1096     case GTK_EXPANDER_COLLAPSED:
1097       degrees = (ge_widget_is_ltr(widget)) ? 0 : 180;
1098       interp = 0.0;
1099       break;
1100     case GTK_EXPANDER_SEMI_COLLAPSED:
1101       degrees = (ge_widget_is_ltr(widget)) ? 30 : 150;
1102       interp = 0.25;
1103       break;
1104     case GTK_EXPANDER_SEMI_EXPANDED:
1105       degrees = (ge_widget_is_ltr(widget)) ? 60 : 120;
1106       interp = 0.75;
1107       break;
1108     case GTK_EXPANDER_EXPANDED:
1109       degrees = 90;
1110       interp = 1.0;
1111       break;
1112     default:
1113       g_assert_not_reached ();
1114     }
1115 
1116   /* Compute distance that the stroke extends beyonds the end
1117    * of the triangle we draw.
1118    */
1119   vertical_overshoot = line_width / 2.0 * (1. / tan (G_PI / 8));
1120 
1121   /* For odd line widths, we end the vertical line of the triangle
1122    * at a half pixel, so we round differently.
1123    */
1124   if (line_width % 2 == 1)
1125     vertical_overshoot = ceil (0.5 + vertical_overshoot) - 0.5;
1126   else
1127     vertical_overshoot = ceil (vertical_overshoot);
1128 
1129   /* Adjust the size of the triangle we draw so that the entire stroke fits
1130    */
1131   diameter = MAX (3, expander_size - 2 * vertical_overshoot);
1132 
1133   /* If the line width is odd, we want the diameter to be even,
1134    * and vice versa, so force the sum to be odd. This relationship
1135    * makes the point of the triangle look right.
1136    */
1137   diameter -= (1 - (diameter + line_width) % 2);
1138 
1139   radius = diameter / 2.;
1140 
1141   /* Adjust the center so that the stroke is properly aligned with
1142    * the pixel grid. The center adjustment is different for the
1143    * horizontal and vertical orientations. For intermediate positions
1144    * we interpolate between the two.
1145    */
1146   x_double_vert = floor (x - (radius + line_width) / 2.) + (radius + line_width) / 2.;
1147   y_double_vert = y - 0.5;
1148 
1149   x_double_horz = x - 0.5;
1150   y_double_horz = floor (y - (radius + line_width) / 2.) + (radius + line_width) / 2.;
1151 
1152   x_double = x_double_vert * (1 - interp) + x_double_horz * interp;
1153   y_double = y_double_vert * (1 - interp) + y_double_horz * interp;
1154 
1155   cairo_translate (cr, x_double, y_double);
1156   cairo_rotate (cr, degrees * G_PI / 180);
1157 
1158   cairo_move_to (cr, - radius / 2., - radius);
1159   cairo_line_to (cr,   radius / 2.,   0);
1160   cairo_line_to (cr, - radius / 2.,   radius);
1161   cairo_close_path (cr);
1162 
1163   cairo_set_line_width (cr, line_width);
1164 
1165   ge_cairo_set_color (cr, &hc_style->color_cube.base[state_type]);
1166 
1167   cairo_fill_preserve (cr);
1168 
1169   ge_cairo_set_color (cr, &hc_style->color_cube.text[state_type]);
1170   cairo_stroke (cr);
1171 
1172   cairo_destroy (cr);
1173 }
1174 
1175 void
hc_draw_diamond(GtkStyle * style,GdkWindow * window,GtkStateType state_type,GtkShadowType shadow_type,GdkRectangle * area,GtkWidget * widget,const gchar * detail,gint x,gint y,gint width,gint height)1176 hc_draw_diamond (GtkStyle      *style,
1177 		 GdkWindow     *window,
1178 		 GtkStateType   state_type,
1179 		 GtkShadowType  shadow_type,
1180 		 GdkRectangle  *area,
1181 		 GtkWidget     *widget,
1182 		 const gchar   *detail,
1183 		 gint           x,
1184 		 gint           y,
1185 		 gint           width,
1186 		 gint           height)
1187 {
1188 	HcStyle *hc_style = HC_STYLE (style);
1189 
1190 	int half_width;
1191 	int half_height;
1192 	cairo_t *cr;
1193 
1194 	CHECK_ARGS
1195 	SANITIZE_SIZE
1196 
1197 	half_width = width / 2;
1198 	half_height = height / 2;
1199 
1200 	cr = ge_gdk_drawable_to_cairo (window, area);
1201 
1202 	switch (shadow_type) {
1203 	case GTK_SHADOW_IN:
1204 		ge_cairo_line(cr, &hc_style->color_cube.light[state_type],
1205 			      x + 2, y + half_height,
1206 			      x + half_width, y + height - 2);
1207 		ge_cairo_line(cr, &hc_style->color_cube.light[state_type],
1208 			      x + half_width, y + height - 2,
1209 			      x + width - 2, y + half_height);
1210 		ge_cairo_line(cr, &hc_style->color_cube.light[state_type],
1211 			      x + 1, y + half_height,
1212 			      x + half_width, y + height - 1);
1213 		ge_cairo_line(cr, &hc_style->color_cube.light[state_type],
1214 			      x + half_width, y + height - 1,
1215 			      x + width - 1, y + half_height);
1216 		ge_cairo_line(cr, &hc_style->color_cube.light[state_type],
1217 			      x, y + half_height,
1218 			      x + half_width, y + height);
1219 		ge_cairo_line(cr, &hc_style->color_cube.light[state_type],
1220 			      x + half_width, y + height,
1221 			      x + width, y + half_height);
1222 
1223 		ge_cairo_line(cr, &hc_style->color_cube.dark[state_type],
1224 			      x + 2, y + half_height,
1225 			      x + half_width, y + 2);
1226 		ge_cairo_line(cr, &hc_style->color_cube.dark[state_type],
1227 			      x + half_width, y + 2,
1228 			      x + width - 2, y + half_height);
1229 		ge_cairo_line(cr, &hc_style->color_cube.dark[state_type],
1230 			      x + 1, y + half_height,
1231 			      x + half_width, y + 1);
1232 		ge_cairo_line(cr, &hc_style->color_cube.dark[state_type],
1233 			      x + half_width, y + 1,
1234 			      x + width - 1, y + half_height);
1235 		ge_cairo_line(cr, &hc_style->color_cube.dark[state_type],
1236 			      x, y + half_height,
1237 			      x + half_width, y);
1238 		ge_cairo_line(cr, &hc_style->color_cube.dark[state_type],
1239 			      x + half_width, y,
1240 			      x + width, y + half_height);
1241 		break;
1242 	case GTK_SHADOW_OUT:
1243 		ge_cairo_line(cr, &hc_style->color_cube.dark[state_type],
1244 			      x + 2, y + half_height,
1245 			      x + half_width, y + height - 2);
1246 		ge_cairo_line(cr, &hc_style->color_cube.dark[state_type],
1247 			      x + half_width, y + height - 2,
1248 			      x + width - 2, y + half_height);
1249 		ge_cairo_line(cr, &hc_style->color_cube.dark[state_type],
1250 			      x + 1, y + half_height,
1251 			      x + half_width, y + height - 1);
1252 		ge_cairo_line(cr, &hc_style->color_cube.dark[state_type],
1253 			      x + half_width, y + height - 1,
1254 			      x + width - 1, y + half_height);
1255 		ge_cairo_line(cr, &hc_style->color_cube.dark[state_type],
1256 			      x, y + half_height,
1257 			      x + half_width, y + height);
1258 		ge_cairo_line(cr, &hc_style->color_cube.dark[state_type],
1259 			      x + half_width, y + height,
1260 			      x + width, y + half_height);
1261 
1262 		ge_cairo_line(cr, &hc_style->color_cube.light[state_type],
1263 			      x + 2, y + half_height,
1264 			      x + half_width, y + 2);
1265 		ge_cairo_line(cr, &hc_style->color_cube.light[state_type],
1266 			      x + half_width, y + 2,
1267 			      x + width - 2, y + half_height);
1268 		ge_cairo_line(cr, &hc_style->color_cube.light[state_type],
1269 			      x + 1, y + half_height,
1270 			      x + half_width, y + 1);
1271 		ge_cairo_line(cr, &hc_style->color_cube.light[state_type],
1272 			      x + half_width, y + 1,
1273 			      x + width - 1, y + half_height);
1274 		ge_cairo_line(cr, &hc_style->color_cube.light[state_type],
1275 			      x, y + half_height,
1276 			      x + half_width, y);
1277 		ge_cairo_line(cr, &hc_style->color_cube.light[state_type],
1278 			      x + half_width, y,
1279 			      x + width, y + half_height);
1280 		break;
1281 	default:
1282 		break;
1283 	}
1284 
1285 	cairo_destroy(cr);
1286 }
1287 
1288 void
hc_draw_polygon(GtkStyle * style,GdkWindow * window,GtkStateType state_type,GtkShadowType shadow_type,GdkRectangle * area,GtkWidget * widget,const gchar * detail,GdkPoint * points,gint npoints,gboolean fill)1289 hc_draw_polygon (GtkStyle      *style,
1290 		 GdkWindow     *window,
1291 		 GtkStateType   state_type,
1292 		 GtkShadowType  shadow_type,
1293 		 GdkRectangle  *area,
1294 		 GtkWidget     *widget,
1295 		 const gchar   *detail,
1296 		 GdkPoint      *points,
1297 		 gint           npoints,
1298 		 gboolean       fill)
1299 {
1300 	HcStyle *hc_style = HC_STYLE (style);
1301 
1302 	static const gdouble pi_over_4 = G_PI_4;
1303 	static const gdouble pi_3_over_4 = G_PI_4 * 3;
1304 
1305 	CairoColor           *color1;
1306 	CairoColor           *color2;
1307 	CairoColor           *color3;
1308 	CairoColor           *color4;
1309 	gdouble            angle;
1310 	int                xadjust;
1311 	int                yadjust;
1312 	int                i;
1313 	cairo_t           *cr;
1314 
1315 	g_return_if_fail(style != NULL);
1316 	g_return_if_fail(window != NULL);
1317 	g_return_if_fail(points != NULL);
1318 
1319 	switch (shadow_type) {
1320 	case GTK_SHADOW_IN:
1321 		color1 = &hc_style->color_cube.light[state_type];
1322 		color2 = &hc_style->color_cube.dark[state_type];
1323 		color3 = &hc_style->color_cube.light[state_type];
1324 		color4 = &hc_style->color_cube.dark[state_type];
1325 		break;
1326 	case GTK_SHADOW_ETCHED_IN:
1327 		color1 = &hc_style->color_cube.light[state_type];
1328 		color2 = &hc_style->color_cube.dark[state_type];
1329 		color3 = &hc_style->color_cube.dark[state_type];
1330 		color4 = &hc_style->color_cube.light[state_type];
1331 		break;
1332 	case GTK_SHADOW_OUT:
1333 		color1 = &hc_style->color_cube.dark[state_type];
1334 		color2 = &hc_style->color_cube.light[state_type];
1335 		color3 = &hc_style->color_cube.dark[state_type];
1336 		color4 = &hc_style->color_cube.light[state_type];
1337 		break;
1338 	case GTK_SHADOW_ETCHED_OUT:
1339 		color1 = &hc_style->color_cube.dark[state_type];
1340 		color2 = &hc_style->color_cube.light[state_type];
1341 		color3 = &hc_style->color_cube.light[state_type];
1342 		color4 = &hc_style->color_cube.dark[state_type];
1343 		break;
1344 	default:
1345 		return;
1346 	}
1347 
1348 	cr = ge_gdk_drawable_to_cairo (window, area);
1349 
1350 	if (fill)
1351 		ge_cairo_polygon(cr, &hc_style->color_cube.bg[state_type], points, npoints);
1352 
1353 	npoints--;
1354 
1355 	for (i = 0; i < npoints; i++) {
1356 		if ((points[i].x == points[i + 1].x) &&
1357 		    (points[i].y == points[i + 1].y)) {
1358 			angle = 0;
1359 		} else {
1360 			angle = atan2(points[i + 1].y - points[i].y,
1361 				      points[i + 1].x - points[i].x);
1362 		}
1363 
1364 		if ((angle > -pi_3_over_4) && (angle < pi_over_4)) {
1365 			if (angle > -pi_over_4) {
1366 				xadjust = 0;
1367 				yadjust = 1;
1368 			} else {
1369 				xadjust = 1;
1370 				yadjust = 0;
1371 			}
1372 
1373 			ge_cairo_line(cr, color1,
1374 				      points[i].x - xadjust,
1375 				      points[i].y - yadjust,
1376 				      points[i + 1].x - xadjust,
1377 				      points[i + 1].y - yadjust);
1378 			ge_cairo_line(cr, color3,
1379 				      points[i].x, points[i].y,
1380 				      points[i + 1].x, points[i + 1].y);
1381 		}
1382 		else {
1383 			if ((angle < -pi_3_over_4) || (angle > pi_3_over_4)) {
1384 				xadjust = 0;
1385 				yadjust = 1;
1386 			} else {
1387 				xadjust = 1;
1388 				yadjust = 0;
1389 			}
1390 
1391 			ge_cairo_line(cr, color4,
1392 				      points[i].x + xadjust,
1393 				      points[i].y + yadjust,
1394 				      points[i + 1].x + xadjust,
1395 				      points[i + 1].y + yadjust);
1396 			ge_cairo_line(cr, color2,
1397 				      points[i].x, points[i].y,
1398 				      points[i + 1].x, points[i + 1].y);
1399 		}
1400 	}
1401 
1402 	cairo_destroy(cr);
1403 }
1404