Better debug message
[gtk-oxygen-engine:gtk-oxygen-engine.git] / src / qt_theme_draw.c
1 /***************************************************************************
2  *   Copyright (C) 2008 by David Sansome                                   *
3  *   me@davidsansome.com                                                   *
4  *                                                                         *
5  *   Copyright (C) 2010 by C├ędric Bellegarde                               *
6  *   gnumdk@gmail.com                                                      *
7  *                                                                         *
8  *   This program is free software; you can redistribute it and/or modify  *
9  *   it under the terms of the GNU General Public License as published by  *
10  *   the Free Software Foundation; either version 2 of the License, or     *
11  *   (at your option) any later version.                                   *
12  *                                                                         *
13  *   This program is distributed in the hope that it will be useful,       *
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
16  *   GNU General Public License for more details.                          *
17  *                                                                         *
18  *   You should have received a copy of the GNU General Public License     *
19  *   along with this program; if not, write to the                         *
20  *   Free Software Foundation, Inc.,                                       *
21  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
22  ***************************************************************************/
23
24 #include <math.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <gtk/gtkprogressbar.h>
28 #include <gdk/gdk.h>
29 #include <gdk/gdkx.h>
30 #include <gtk/gtk.h>
31 #include <glib/glist.h>
32
33 #include <gdk-pixbuf/gdk-pixbuf.h>
34
35 #include "qt_style.h"
36 #include "qt_rc_style.h"
37 #include "wrapper.h"
38 #include "wmmove.c" /* Code from qtcurve engine */
39
40 /* Special fix for Qt oxygen drawing extension when drawing tabs */
41 #define QT_GTK_TAB_DIFF 6
42 #define GTK_ACTIVE_TAB_FIX 2
43
44 #define DETAIL(xx)    ((detail) && (!strcmp(xx, detail)))
45 #define DETAILHAS(xx) ((detail) && (strstr(detail, xx)))
46 #define PARENT(xx)    ((parent) && (!strcmp(xx, gtk_widget_get_name(parent))))
47 #define WIDGET(xx)    (GTK_IS_WIDGET(widget) && (!strcmp(xx, gtk_widget_get_name(widget))))
48
49 #define GTK_QT_STANDARD_ARGS window, toplevel->window, style, stateType, x, y, w, h, GTK_IS_WIDGET(widget) && gtk_widget_is_focus(widget)
50
51 #ifndef max
52 #define max(x,y) ((x)>=(y)?(x):(y))
53 #endif
54 #ifndef min
55 #define min(x,y) ((x)<=(y)?(x):(y))
56 #endif
57
58 #define IS_MENU_WINDOW(Window) (GTK_WINDOW(Window)->default_widget && GTK_IS_MENU(GTK_WINDOW(Window)->default_widget))
59
60 static void oxygenengine_style_init(OxygenEngineStyle      *style);
61 static void oxygenengine_style_class_init(OxygenEngineStyleClass *klass);
62
63 static GtkStyleClass *parent_class = NULL;
64
65 static void windowCleanup(GtkWidget *widget)
66 {
67     if(widget) {
68         g_signal_handler_disconnect(G_OBJECT(widget),
69                                     (unsigned long)g_object_steal_data(G_OBJECT(widget), "WINDOW_SIZE_REQUEST_ID"));
70         g_signal_handler_disconnect(G_OBJECT(widget),
71                                     (unsigned long)g_object_steal_data(G_OBJECT(widget), "WINDOW_DESTROY_ID"));
72         g_signal_handler_disconnect(G_OBJECT(widget),
73                                     (unsigned long)g_object_steal_data(G_OBJECT(widget), "WINDOW_STYLE_SET_ID"));
74         g_object_steal_data(G_OBJECT(widget), "WINDOW_HACK_SET");
75     }
76 }
77
78 static gboolean windowSizeRequest(GtkWidget *widget, GdkEvent *event, gpointer user_data)
79 {
80     (void) event;
81     (void) user_data;
82     /* Need to invalidate the whole of the window on a resize, as gradient needs to be redone.*/
83     if(widget) {
84         int width, height;
85         /* Need to check size really change, some apps are stupid */
86         sizeFromMap(GDK_DRAWABLE_XID(widget->window), &width, &height);
87         if((width != -1 && width != widget->allocation.width) || (height != -1 && height != widget->allocation.height)) {
88             GdkRectangle rect;
89             rect.x = 0, rect.y = 0, rect.width = widget->allocation.width, rect.height = widget->allocation.height;
90             gdk_window_invalidate_rect(widget->window, &rect, FALSE);
91             addSize2Map(GDK_DRAWABLE_XID(widget->window), widget->allocation.width, widget->allocation.height);
92             return TRUE;
93         }
94     }
95     return FALSE;
96 }
97
98 static gboolean windowStyleSet(GtkWidget *widget, GtkStyle *previous_style, gpointer user_data)
99 {
100     (void) previous_style;
101     (void) user_data;
102     windowCleanup(widget);
103     return FALSE;
104 }
105
106 static gboolean windowDestroy(GtkWidget *widget, GdkEvent *event, gpointer user_data)
107 {
108     (void) event;
109     (void) user_data;
110     int width = 0;
111     int height = 0;
112     if(GDK_IS_DRAWABLE(widget->window))
113         gdk_drawable_get_size(widget->window, &width, &height);
114     destroyImage(GDK_WINDOW_XID(widget->window), width, height);
115     windowCleanup(widget);
116     return FALSE;
117 }
118
119 static gboolean windowSetup(GtkWidget *widget)
120 {
121     if(widget && !g_object_get_data(G_OBJECT(widget), "WINDOW_HACK_SET")) {
122         g_object_set_data(G_OBJECT(widget), "WINDOW_HACK_SET", (gpointer)1);
123
124         g_object_set_data(G_OBJECT(widget), "WINDOW_SIZE_REQUEST_ID",
125                           (gpointer)g_signal_connect(G_OBJECT(widget), "size-allocate",
126                                   (GtkSignalFunc)windowSizeRequest, NULL));
127         g_object_set_data(G_OBJECT(widget), "WINDOW_DESTROY_ID",
128                           (gpointer)g_signal_connect(G_OBJECT(widget), "hide",
129                                   (GtkSignalFunc)windowDestroy, NULL));
130         g_object_set_data(G_OBJECT(widget), "WINDOW_STYLE_SET_ID",
131                           (gpointer)g_signal_connect(G_OBJECT(widget), "style-set",
132                                   (GtkSignalFunc)windowStyleSet, NULL));
133         return TRUE;
134     }
135
136     return FALSE;
137 }
138
139 static void sanitize_size(GdkWindow* window, int* w, int* h)
140 {
141     if((*w == -1) && (*h == -1))
142         gdk_window_get_size(window, w, h);
143     else if(*w == -1)
144         gdk_window_get_size(window, w, NULL);
145     else if(*h == -1)
146         gdk_window_get_size(window, NULL, h);
147 }
148
149 static void
150 draw_hline(GtkStyle* style,
151            GdkWindow* window,
152            GtkStateType stateType,
153            GdkRectangle* area,
154            GtkWidget* widget,
155            const gchar* detail,
156            int x1,
157            int x2,
158            int y)
159 {
160     (void) area;
161     GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
162     int x = min(x1, x2);
163     int w = abs(x2 - x1);
164     int h = 2;
165
166     if(gtkQtDebug())
167         printf("HLINE (%d,%d,%d) Widget: %s  Detail: %s\n", x1, x2, y, gtk_widget_get_name(widget), detail);
168
169     if(DETAIL("menuitem") || ! DETAIL("vscale"))
170         drawToolMenuItem(GTK_QT_STANDARD_ARGS, 2, FALSE);
171 }
172
173
174 static void
175 draw_vline(GtkStyle* style,
176            GdkWindow* window,
177            GtkStateType stateType,
178            GdkRectangle* area,
179            GtkWidget* widget,
180            const gchar* detail,
181            int y1,
182            int y2,
183            int x)
184 {
185     (void) area;
186     GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
187     int y = min(y1, y2) - 5;
188     int h = abs(y2 - y1) + 10;
189     int w = 2;
190
191     if(gtkQtDebug())
192         printf("VLINE (%d,%d,%d) Widget: %s  Detail: %s\n", y1, y2, x, gtk_widget_get_name(widget), detail);
193
194     if(DETAIL("toolbar") || !DETAIL("hscale")) {
195         drawToolMenuItem(GTK_QT_STANDARD_ARGS, 2, TRUE);
196     }
197 }
198
199 static void
200 draw_shadow(GtkStyle     *style,
201             GdkWindow    *window,
202             GtkStateType  stateType,
203             GtkShadowType shadowType,
204             GdkRectangle *area,
205             GtkWidget    *widget,
206             const gchar  *detail,
207             int          x,
208             int          y,
209             int          w,
210             int          h)
211 {
212     (void) area;
213     GtkWidget *toplevel = NULL;
214     int tx, ty;
215
216     sanitize_size(window, &w, &h);
217
218     if(gtkQtDebug())
219         printf("Shadow (%d,%d,%d,%d) Widget: %s Detail: %s\n", x, y, w, h, gtk_widget_get_name(widget), detail);
220
221     if(!widget)  /* stupid gftp */
222         return;
223
224     toplevel = gtk_widget_get_toplevel(widget);
225
226     if(DETAIL("menuitem"))
227         return;
228     if(DETAIL("menu"))
229         return;
230     if(DETAIL("scrolled_window")) {
231         int tx, ty;
232         if(gtk_widget_translate_coordinates(widget, toplevel, x, y, &tx, &ty)) {
233             x -= 1;
234             y -= 0;
235             w += 2;
236             h += 2;
237             drawRectFrame(GTK_QT_STANDARD_ARGS, tx, ty);
238         } else
239             drawMenuFrame(GTK_QT_STANDARD_ARGS);
240         return;
241     }
242     if(DETAIL("entry")) {
243         if(gtk_widget_has_focus(widget))
244             stateType = GTK_STATE_SELECTED;
245         if(gtk_widget_translate_coordinates(widget, toplevel, x, y, &tx, &ty)) {
246             GtkWidget *parent = gtk_widget_get_parent(widget);
247             /* Here we check if current window is a mozilla (GtkFixed) window,
248              * we already have this information with noGradients() but we need
249              * to handle gtk open/save dialogs
250              */
251             drawLineEditFrame(GTK_QT_STANDARD_ARGS, tx, ty, !strcmp(gtk_widget_get_name(parent), "GtkFixed"));
252         }
253         return;
254     }
255     if(DETAIL("frame") || DETAIL("trough") || DETAIL("viewport")) {
256         return;
257     }
258
259     if(shadowType == GTK_SHADOW_NONE)
260         return;
261
262     if(WIDGET("GimpFgBgEditor"))
263         return;
264     /*
265     if (gtk_widget_translate_coordinates (widget, toplevel, x, y, &tx, &ty))
266     {
267         drawFrame(GTK_QT_STANDARD_ARGS, 1, tx, ty, GTK_POS_TOP);
268     }*/
269 }
270
271 static void
272 draw_polygon(GtkStyle* style,
273              GdkWindow* window,
274              GtkStateType stateType,
275              GtkShadowType shadowType,
276              GdkRectangle* area,
277              GtkWidget* widget,
278              const gchar* detail,
279              GdkPoint* points,
280              int npoints,
281              int fill)
282 {
283 #ifndef M_PI
284 #define M_PI    3.14159265358979323846
285 #endif /* M_PI */
286 #ifndef M_PI_4
287 #define M_PI_4  0.78539816339744830962
288 #endif /* M_PI_4 */
289     (void) widget;
290     (void) detail;
291     (void) shadowType;
292     static const gdouble pi_over_4 = M_PI_4;
293     static const gdouble pi_3_over_4 = M_PI_4 * 3;
294
295     GdkGC              *gc1;
296     GdkGC              *gc2;
297     GdkGC              *gc3;
298     GdkGC              *gc4;
299     gdouble             angle;
300     int                xadjust;
301     int                yadjust;
302     int                i;
303
304     g_return_if_fail(style != NULL);
305     g_return_if_fail(window != NULL);
306     g_return_if_fail(points != NULL);
307
308     switch(shadowType) {
309     case GTK_SHADOW_IN:
310         gc1 = style->light_gc[stateType];
311         gc2 = style->dark_gc[stateType];
312         gc3 = style->light_gc[stateType];
313         gc4 = style->dark_gc[stateType];
314         break;
315     case GTK_SHADOW_ETCHED_IN:
316         gc1 = style->light_gc[stateType];
317         gc2 = style->dark_gc[stateType];
318         gc3 = style->dark_gc[stateType];
319         gc4 = style->light_gc[stateType];
320         break;
321     case GTK_SHADOW_OUT:
322         gc1 = style->dark_gc[stateType];
323         gc2 = style->light_gc[stateType];
324         gc3 = style->dark_gc[stateType];
325         gc4 = style->light_gc[stateType];
326         break;
327     case GTK_SHADOW_ETCHED_OUT:
328         gc1 = style->dark_gc[stateType];
329         gc2 = style->light_gc[stateType];
330         gc3 = style->light_gc[stateType];
331         gc4 = style->dark_gc[stateType];
332         break;
333     default:
334         return;
335     }
336
337     if(area) {
338         gdk_gc_set_clip_rectangle(gc1, area);
339         gdk_gc_set_clip_rectangle(gc2, area);
340         gdk_gc_set_clip_rectangle(gc3, area);
341         gdk_gc_set_clip_rectangle(gc4, area);
342     }
343
344     if(fill)
345         gdk_draw_polygon(window, style->bg_gc[stateType], TRUE, points, npoints);
346
347     npoints--;
348
349     for(i = 0; i < npoints; i++) {
350         if((points[i].x == points[i + 1].x) &&
351                 (points[i].y == points[i + 1].y)) {
352             angle = 0;
353         } else {
354             angle = atan2(points[i + 1].y - points[i].y,
355                           points[i + 1].x - points[i].x);
356         }
357
358         if((angle > -pi_3_over_4) && (angle < pi_over_4)) {
359             if(angle > -pi_over_4) {
360                 xadjust = 0;
361                 yadjust = 1;
362             } else {
363                 xadjust = 1;
364                 yadjust = 0;
365             }
366
367             gdk_draw_line(window, gc1,
368                           points[i].x - xadjust, points[i].y - yadjust,
369                           points[i + 1].x - xadjust, points[i + 1].y - yadjust);
370             gdk_draw_line(window, gc3,
371                           points[i].x, points[i].y,
372                           points[i + 1].x, points[i + 1].y);
373         } else {
374             if((angle < -pi_3_over_4) || (angle > pi_3_over_4)) {
375                 xadjust = 0;
376                 yadjust = 1;
377             } else {
378                 xadjust = 1;
379                 yadjust = 0;
380             }
381
382             gdk_draw_line(window, gc4,
383                           points[i].x + xadjust, points[i].y + yadjust,
384                           points[i + 1].x + xadjust, points[i + 1].y + yadjust);
385             gdk_draw_line(window, gc2,
386                           points[i].x, points[i].y,
387                           points[i + 1].x, points[i + 1].y);
388         }
389     }
390     if(area) {
391         gdk_gc_set_clip_rectangle(gc1, NULL);
392         gdk_gc_set_clip_rectangle(gc2, NULL);
393         gdk_gc_set_clip_rectangle(gc3, NULL);
394         gdk_gc_set_clip_rectangle(gc4, NULL);
395     }
396 }
397
398 static void
399 draw_arrow(GtkStyle* style,
400            GdkWindow* window,
401            GtkStateType stateType,
402            GtkShadowType shadowType,
403            GdkRectangle* area,
404            GtkWidget* widget,
405            const gchar *detail,
406            GtkArrowType arrowType,
407            int fill, int x, int y, int w, int h)
408 {
409     (void) area;
410     (void) shadowType;
411     (void) fill;
412     GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
413     sanitize_size(window, &w, &h);
414
415     if(gtkQtDebug())
416         printf("Arrow (%d,%d,%d,%d) Widget: %s  Detail: %s\n", x, y, w, h, gtk_widget_get_name(widget), detail);
417
418     if(DETAIL("menuitem") && !noGradients()) {
419         if(stateType == GTK_STATE_PRELIGHT) {/* arraw already drawn by Qt */ 
420             return;
421         }
422         else {
423             switch(arrowType) {
424                 case GTK_ARROW_LEFT:
425                     x -= 2;
426                     break;
427                 case GTK_ARROW_RIGHT:
428                     x += 2;
429                     break;
430                 default:
431                     break;
432             }
433         }
434     }
435     
436     if(DETAIL("hscrollbar") || DETAIL("vscrollbar"))
437         return;
438     if(DETAIL("spinbutton"))
439         return;
440     if(DETAIL("notebook")) {
441         drawArrow(GTK_QT_STANDARD_ARGS, arrowType);
442         return;
443     }
444     if(DETAIL("arrow")) {
445         GtkWidget* parent = gtk_widget_get_parent(widget);
446         if(parent) {
447             drawArrow(GTK_QT_STANDARD_ARGS, arrowType);
448         }
449         return;
450     } else {
451         drawArrow(GTK_QT_STANDARD_ARGS, arrowType);
452         return;
453     }
454 }
455
456
457
458 static void
459 draw_diamond(GtkStyle * style,
460              GdkWindow * window,
461              GtkStateType stateType,
462              GtkShadowType shadowType,
463              GdkRectangle * area,
464              GtkWidget * widget,
465              const gchar *detail,
466              int x,
467              int y,
468              int w,
469              int h)
470 {
471     (void) style;
472     (void) window;
473     (void) stateType;
474     (void) shadowType;
475     (void) area;
476     (void) widget;
477     (void) detail;
478     (void) x;
479     (void) y;
480     (void) w;
481     (void) h;
482 }
483
484
485
486 static void
487 draw_box(GtkStyle * style,
488          GdkWindow * window,
489          GtkStateType stateType,
490          GtkShadowType shadowType,
491          GdkRectangle * area,
492          GtkWidget * widget,
493          const gchar *detail,
494          int x,
495          int y,
496          int w,
497          int h)
498 {
499     (void) shadowType;
500     (void) area;
501     int tx, ty;
502     GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
503
504     sanitize_size(window, &w, &h);
505
506     if(gtkQtDebug())
507         printf("Box (%d,%d,%d,%d) Widget: %s  Detail: %s\n", x, y, w, h, gtk_widget_get_name(widget), detail);
508
509     if(GTK_IS_SCROLLBAR(widget)) {
510         if(DETAIL("trough")) {
511             GtkOrientation orientation = ((w > h) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL);
512
513             drawScrollBar(GTK_QT_STANDARD_ARGS, orientation);
514         }
515         return;
516     }
517     if(DETAIL("menuitem")) {
518         /* Crude way of checking if it's a menu item, or a menubar item */
519         if(x != 0)
520             drawMenuBarItem(GTK_QT_STANDARD_ARGS);
521         else {
522             int type = 0;
523             if(GTK_IS_TEAROFF_MENU_ITEM(widget))
524                 return;
525             else if (gtk_menu_item_get_submenu(GTK_MENU_ITEM(widget)))
526                 type = 3;
527                /* BUG: Can't be used because qt give no way to draw it without an arrow*/
528             drawToolMenuItem(GTK_QT_STANDARD_ARGS, type, FALSE);
529         }
530         return;
531     }
532     if(DETAIL("menubar")) {
533         if(!noGradients()) {
534             int tx, ty;
535             if(gtk_widget_translate_coordinates(widget, toplevel, x, y, &tx, &ty)) {
536                 addSize2Map(GDK_DRAWABLE_XID(widget->window), widget->allocation.width, widget->allocation.height);
537                 windowSetup(widget);
538                 qtcWMMoveSetup(widget);
539                 drawWidgetBackground(GTK_QT_STANDARD_ARGS, tx, ty);
540             }
541         }
542         return;
543     }
544     if(DETAIL("menu")) {
545         x -= 1;
546         y -= 1;
547         w += 2;
548         h += 3;
549         drawMenuFrame(GTK_QT_STANDARD_ARGS);
550         return;
551     }
552     if(GTK_IS_PROGRESS(widget) && DETAIL("trough")) {
553         double fraction = gtk_progress_bar_get_fraction(GTK_PROGRESS_BAR(widget));
554         GtkProgressBarOrientation orientation = gtk_progress_bar_get_orientation(GTK_PROGRESS_BAR(widget));
555         drawProgressBar(GTK_QT_STANDARD_ARGS, orientation, fraction);
556         return;
557     }
558     if(DETAIL("bar")) {
559         if((GTK_IS_PROGRESS(widget) && !gtk_progress_bar_get_fraction(GTK_PROGRESS_BAR(widget))) || noGradients()) {
560             x = area->x; y = area->y; w = area->width; h = area->height;
561             drawProgressChunk(GTK_QT_STANDARD_ARGS);
562         }
563         return;
564     }
565     if(GTK_IS_SCALE(widget) && DETAIL("trough")) {
566         GtkAdjustment* adj;
567         int inverted;
568         GValue *val = (GValue*)g_malloc(sizeof(GValue));
569
570         memset(val, 0, sizeof(GValue));
571         g_value_init(val, G_TYPE_BOOLEAN);
572         g_object_get_property((GObject*)widget, "inverted", val);
573         inverted = g_value_get_boolean(val);
574         g_value_unset(val);
575         g_free(val);
576
577         adj = gtk_range_get_adjustment((GtkRange *) widget);
578         drawSlider(GTK_QT_STANDARD_ARGS, adj, (GTK_RANGE(widget))->orientation, inverted);
579         return;
580     }
581     if(DETAIL("button")) {
582         GtkWidget *parent;
583         GtkReliefStyle relief;
584         parent = gtk_widget_get_parent(widget);
585
586         if(parent) {
587             if(GTK_IS_CLIST(parent) || GTK_IS_LIST(parent) || GTK_IS_TREE_VIEW(parent)) {
588                 drawListHeader(GTK_QT_STANDARD_ARGS);
589                 return;
590             }
591         }
592         if(GTK_IS_BUTTON(widget)) {
593             relief = gtk_button_get_relief(GTK_BUTTON(widget));
594         }
595         else {
596             stateType = GTK_STATE_NORMAL;
597             drawMenuFrame(GTK_QT_STANDARD_ARGS);
598             return;
599         }
600         
601         if(relief == GTK_RELIEF_NONE || relief == GTK_RELIEF_HALF) {
602             drawToolButton(GTK_QT_STANDARD_ARGS);
603         } else { /* normal button */
604             int defaultButton = GTK_WIDGET_HAS_FOCUS(widget);
605             GtkWindow *top_window = GTK_WINDOW(toplevel);
606
607             if(top_window && top_window->default_widget == widget)
608                 defaultButton = 1;
609
610             drawButton(GTK_QT_STANDARD_ARGS, defaultButton);
611         }
612         return;
613     }
614     if(DETAIL("tab")) {
615         GtkWidget *toplevel = gtk_widget_get_toplevel(widget);
616         /* Gtk doesn't draw tab at same qt position,
617         */
618         h += QT_GTK_TAB_DIFF;
619         drawTab(GTK_QT_STANDARD_ARGS, GTK_POS_TOP);
620
621         return;
622     }
623     if(DETAIL("optionmenu")) {
624         drawComboBox(GTK_QT_STANDARD_ARGS);
625         return;
626     }
627     if(DETAIL("toolbar")) { /* Nothing to draw for now*/
628         return;
629     }
630     if(DETAIL("spinbutton_up")) {
631         if(noGradients())
632             drawSpinButton(GTK_QT_STANDARD_ARGS, 0);
633         else {
634             x -= 2;
635             y += 2;
636             drawArrow(GTK_QT_STANDARD_ARGS, GTK_ARROW_UP);
637         }
638         return;
639     }
640     if(DETAIL("spinbutton_down")) {
641         if(noGradients())
642             drawSpinButton(GTK_QT_STANDARD_ARGS, 1);
643         else {
644             x -= 2;
645             drawArrow(GTK_QT_STANDARD_ARGS, GTK_ARROW_DOWN);
646         }
647         return;
648     }
649     if(DETAIL("spinbutton")) {
650         if(!noGradients()) {
651             if(gtk_widget_translate_coordinates(widget, toplevel, x, y, &tx, &ty)) {
652                 drawSpinFrame(GTK_QT_STANDARD_ARGS, tx, ty);
653             }
654         }
655         return;
656     }
657
658     if(DETAIL("optionmenutab") || DETAIL("buttondefault") || DETAIL("trough-fill-level"))
659         return;
660     
661     if(DETAIL("entry-progress")) {
662         drawProgressChunk(GTK_QT_STANDARD_ARGS);
663         return;
664     }
665     
666     if(!detail) {
667         parent_class->draw_box(style, window, stateType, shadowType, area, widget, detail, x, y, w, h);
668         return;
669     }
670     
671     if(gtk_widget_translate_coordinates(widget, toplevel, x, y, &tx, &ty)) {
672         drawFrame(GTK_QT_STANDARD_ARGS, 0, tx, ty, GTK_POS_TOP);
673     }
674 }
675
676 /* From qtcurve, see at end of draw_flat_box() */
677 static void qtcLogHandler(const gchar *domain, GLogLevelFlags level, const gchar *msg, gpointer data)
678 {
679     (void) domain;
680     (void) level;
681     (void) msg;
682     (void) data;
683 }
684
685 static void
686 draw_flat_box(GtkStyle * style,
687               GdkWindow * window,
688               GtkStateType stateType,
689               GtkShadowType shadowType,
690               GdkRectangle * area,
691               GtkWidget * widget,
692               const gchar *detail,
693               int x,
694               int y,
695               int w,
696               int h)
697 {
698     (void) shadowType;
699     (void) area;
700     GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
701     sanitize_size(window, &w, &h);
702
703     if(gtkQtDebug())
704         printf("Flat Box (%d,%d,%d,%d) Widget: %s  Detail: %s %d %d\n", x, y, w, h, gtk_widget_get_name(widget), detail, stateType, GTK_STATE_SELECTED);
705
706     if((DETAILHAS("cell_odd_ruled")|| DETAIL("treeview")) && stateType != GTK_STATE_SELECTED) {
707         cairo_t *t = gdk_cairo_create(window);
708         GdkColor color = alternateBackground(style, stateType != GTK_STATE_INSENSITIVE);
709         cairo_set_source_rgb(t, (float)color.red/65535, (float)color.green/65535, (float)color.blue/65535);
710         cairo_rectangle(t, x, y, w, h);
711         cairo_fill(t);
712         cairo_destroy(t);
713     } else if((DETAILHAS("cell_odd") || DETAILHAS("cell_even") || DETAIL("listitem")) && (stateType == GTK_STATE_SELECTED)) {
714         unsigned int round;
715         if(strstr(detail, "_start") != 0)
716             round = 0;
717         else if(strstr(detail, "_middle") != 0)
718             round = 1;
719         else if(strstr(detail, "_end") != 0)
720             round = 2;
721         else
722             round = 3;
723         drawItemViewItem(GTK_QT_STANDARD_ARGS, round);
724     } else if(DETAIL("tooltip")) {
725         gtk_window_set_opacity(GTK_WINDOW(widget), 0.8);
726         drawTooltip(GTK_QT_STANDARD_ARGS);
727     } else if(DETAIL("entry_bg")) {
728         gboolean editable = TRUE;
729         if(!noGradients() && GTK_IS_ENTRY(widget)) {
730             if(!gtk_widget_is_sensitive(widget))
731                 editable = FALSE;
732             drawLineEdit(GTK_QT_STANDARD_ARGS);
733         }
734     } else if(DETAIL("trough")) {
735         int tx, ty;
736         if(gtk_widget_translate_coordinates(widget, toplevel, x, y, &tx, &ty)) {
737             int topWidth = 0;
738             int topHeight =0;
739             if(GDK_IS_DRAWABLE(toplevel->window))
740                 gdk_drawable_get_size(toplevel->window, &topWidth, &topHeight);
741             if(topWidth >= tx + w && topHeight >= ty + h)
742                 drawWidgetBackground(GTK_QT_STANDARD_ARGS, tx, ty);
743             else
744                 drawRect(GTK_QT_STANDARD_ARGS, TRUE);
745         }
746     } else if(DETAIL("viewportbin")) {
747         int tx, ty;
748         if(gtk_widget_translate_coordinates(widget, toplevel, x, y, &tx, &ty)) {
749             drawViewportBackground(GTK_QT_STANDARD_ARGS, tx, ty);
750         }
751     } else if(DETAIL("eventbox")) {
752         int tx, ty;
753         if(gtk_widget_translate_coordinates(widget, toplevel, x, y, &tx, &ty)) {
754             drawWidgetBackground(GTK_QT_STANDARD_ARGS, tx, ty);
755         }
756     } else if(DETAIL("icon_view_item")) {
757         drawItemViewItem(GTK_QT_STANDARD_ARGS, 3);
758     } else if(DETAIL("base")) {
759         if(GTK_IS_WINDOW(widget) &&
760                 gtk_widget_is_toplevel(widget) &&
761                 ! IS_MENU_WINDOW(widget) &&
762                 ! noGradients()) {
763             addSize2Map(GDK_DRAWABLE_XID(widget->window), widget->allocation.width, widget->allocation.height);
764             windowSetup(widget);
765             drawOxygenBackground(GTK_QT_STANDARD_ARGS);
766         }
767         /* Code from qtcurve */
768         if(GTK_IS_DIALOG(toplevel) && !g_object_get_data(G_OBJECT(toplevel), "QTC_BUTTON_ORDER_HACK_SET")) {
769             /* gtk_dialog_set_alternative_button_order will cause errors to be logged, but dont want these
770                so register ur own error handler, and then unregister afterwards...*/
771             guint id=g_log_set_handler("Gtk", G_LOG_LEVEL_CRITICAL, qtcLogHandler, NULL);
772             g_object_set_data(G_OBJECT(toplevel), "QTC_BUTTON_ORDER_HACK_SET", (gpointer)1);
773
774             gtk_dialog_set_alternative_button_order(GTK_DIALOG(toplevel), GTK_RESPONSE_HELP,
775                                                     GTK_RESPONSE_OK, GTK_RESPONSE_YES, GTK_RESPONSE_ACCEPT, GTK_RESPONSE_APPLY,
776                                                     GTK_RESPONSE_REJECT, GTK_RESPONSE_CLOSE, GTK_RESPONSE_NO, GTK_RESPONSE_CANCEL, -1);
777             g_log_remove_handler("Gtk", id);
778             g_log_set_handler("Gtk", G_LOG_LEVEL_CRITICAL, g_log_default_handler, NULL);
779         }
780     }
781 }
782
783
784 static void
785 draw_check(GtkStyle * style,
786            GdkWindow * window,
787            GtkStateType stateType,
788            GtkShadowType shadowType,
789            GdkRectangle * area,
790            GtkWidget * widget,
791            const gchar *detail,
792            int x,
793            int y,
794            int w,
795            int h)
796 {
797     (void) area;
798     GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
799     if(gtkQtDebug())
800         printf("Check (%d,%d,%d,%d) Widget: %s  Detail: %s\n", x, y, w, h, gtk_widget_get_name(widget), detail);
801
802     if(GTK_IS_MENU_ITEM(widget)) {
803         if(shadowType == GTK_SHADOW_IN) {
804             drawMenuCheck(GTK_QT_STANDARD_ARGS);
805         }
806         return;
807     }
808     drawCheckBox(GTK_QT_STANDARD_ARGS, shadowType == GTK_SHADOW_IN);
809 }
810
811 static void
812 draw_option(GtkStyle * style,
813             GdkWindow * window,
814             GtkStateType stateType,
815             GtkShadowType shadowType,
816             GdkRectangle * area,
817             GtkWidget * widget,
818             const gchar *detail,
819             int x,
820             int y,
821             int w,
822             int h)
823 {
824     (void) area;
825     GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
826     if(gtkQtDebug())
827         printf("Option (%d,%d,%d,%d) Widget: %s  Detail: %s\n", x, y, w, h, gtk_widget_get_name(widget), detail);
828
829     if(GTK_IS_MENU_ITEM(widget)) {
830         if(shadowType == GTK_SHADOW_IN) {
831             drawMenuCheck(GTK_QT_STANDARD_ARGS);
832         }
833         return;
834     }
835     drawRadioButton(GTK_QT_STANDARD_ARGS, shadowType == GTK_SHADOW_IN);
836 }
837
838
839 static void
840 draw_tab(GtkStyle * style,
841          GdkWindow * window,
842          GtkStateType stateType,
843          GtkShadowType shadowType,
844          GdkRectangle * area,
845          GtkWidget * widget,
846          const gchar *detail,
847          int x,
848          int y,
849          int w,
850          int h)
851 {
852     (void) shadowType;
853     (void) area;
854     GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
855     if(gtkQtDebug())
856         printf("Tab (%d,%d,%d,%d) Widget: %s  Detail: %s\n", x, y, w, h, gtk_widget_get_name(widget), detail);
857
858     drawArrow(GTK_QT_STANDARD_ARGS, GTK_ARROW_DOWN);
859 }
860
861 static void
862 draw_box_gap(GtkStyle* style,
863              GdkWindow* window,
864              GtkStateType stateType,
865              GtkShadowType shadowType,
866              GdkRectangle* area,
867              GtkWidget* widget,
868              const gchar* detail,
869              int x,
870              int y,
871              int w,
872              int h,
873              GtkPositionType gap_side,
874              int gap_x,
875              int gap_w)
876 {
877     (void) shadowType;
878     (void) area;
879     (void) gap_side;
880     int tx, ty;
881     GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
882
883     sanitize_size(window, &w, &h);
884
885     if(w < 0 || h < 10) return; /* Eclipse/Firefox really can be this stupid! */
886
887     if(gtkQtDebug())
888         printf("Box_gap (%d,%d,%d,%d,%d, %d) Widget: %s  Detail: %s\n", x, y, w, h, gap_x, gap_w, gtk_widget_get_name(widget), detail);
889
890     if(DETAIL("notebook")) {
891         GtkPositionType position = gtk_notebook_get_tab_pos(GTK_NOTEBOOK(widget));
892         if(position == GTK_POS_BOTTOM || position == GTK_POS_TOP) {
893             x -= 2;
894             w += 4;
895         }
896         else {
897             y -= 2;
898             h += 4;
899         }
900         if(gtk_widget_translate_coordinates(widget, toplevel, x, y, &tx, &ty)) {
901             drawFrame(GTK_QT_STANDARD_ARGS, 0, tx, ty, position);
902         }
903     }
904 }
905
906 static void
907 draw_shadow_gap(GtkStyle * style,
908                 GdkWindow * window,
909                 GtkStateType stateType,
910                 GtkShadowType shadowType,
911                 GdkRectangle * area,
912                 GtkWidget * widget,
913                 const gchar *detail,
914                 int x,
915                 int y,
916                 int w,
917                 int h,
918                 GtkPositionType gap_side,
919                 int gap_x,
920                 int gap_w)
921 {
922     (void) style;
923     (void) window;
924     (void) stateType;
925     (void) shadowType;
926     (void) area;
927     (void) widget;
928     (void) detail;
929     (void) x;
930     (void) y;
931     (void) w;
932     (void) h;
933     (void) gap_side;
934     (void) gap_x;
935     (void) gap_w;
936 }
937
938 static void
939 draw_extension(GtkStyle * style,
940                GdkWindow * window,
941                GtkStateType stateType,
942                GtkShadowType shadowType,
943                GdkRectangle * area,
944                GtkWidget * widget,
945                const gchar *detail,
946                int x,
947                int y,
948                int w,
949                int h,
950                GtkPositionType gap_side)
951 {
952     (void) gap_side;
953     (void) shadowType;
954     (void) area;
955     GtkWidget *toplevel;
956     GtkPositionType position;
957
958     g_return_if_fail(style != NULL);
959     g_return_if_fail(window != NULL);
960
961     sanitize_size(window, &w, &h);
962
963     if(gtkQtDebug())
964         printf("Extension (%d,%d,%d,%d) Widget: %s  Detail: %s\n", x, y, w, h, gtk_widget_get_name(widget), detail);
965
966     toplevel = gtk_widget_get_toplevel(widget);
967     position = gtk_notebook_get_tab_pos(GTK_NOTEBOOK(widget));
968     
969     /* Gtk doesn't draw tab at same qt position,
970      * This try to handle the problem
971      */
972     switch(position) {
973     case GTK_POS_LEFT:
974         break;
975     case GTK_POS_RIGHT:
976         break;
977     default:
978         h += QT_GTK_TAB_DIFF;
979         if(stateType == GTK_STATE_ACTIVE) {
980             y -= GTK_ACTIVE_TAB_FIX;
981             h += GTK_ACTIVE_TAB_FIX;
982         }
983         break;
984     }
985
986     drawTab(GTK_QT_STANDARD_ARGS, position);
987 }
988
989
990 static void
991 draw_focus(GtkStyle     *style,
992            GdkWindow    *window,
993            GtkStateType  stateType,
994            GdkRectangle *area,
995            GtkWidget    *widget,
996            const gchar  *detail,
997            int          x,
998            int          y,
999            int          w,
1000            int          h)
1001 {
1002     (void) style;
1003     (void) window;
1004     (void) stateType;
1005     (void) area;
1006     (void) widget;
1007     (void) detail;
1008     (void) x;
1009     (void) y;
1010     (void) w;
1011     (void) h;
1012 }
1013
1014 static void
1015 draw_slider(GtkStyle * style,
1016             GdkWindow * window,
1017             GtkStateType stateType,
1018             GtkShadowType shadowType,
1019             GdkRectangle * area,
1020             GtkWidget * widget,
1021             const gchar *detail,
1022             int x,
1023             int y,
1024             int w,
1025             int h,
1026             GtkOrientation orientation)
1027 {
1028     (void) shadowType;
1029     (void) area;
1030     GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
1031
1032     if(gtkQtDebug())
1033         printf("Slider (%d,%d,%d,%d) Widget: %s  Detail: %s\n", x, y, w, h, gtk_widget_get_name(widget), detail);
1034
1035     if(DETAIL("slider")) {
1036         drawScrollBarSlider(GTK_QT_STANDARD_ARGS, orientation);
1037         return;
1038     }
1039 }
1040
1041 static void
1042 draw_handle(GtkStyle * style,
1043             GdkWindow * window,
1044             GtkStateType stateType,
1045             GtkShadowType shadowType,
1046             GdkRectangle * area,
1047             GtkWidget * widget,
1048             const gchar *detail,
1049             int x,
1050             int y,
1051             int w,
1052             int h,
1053             GtkOrientation orientation)
1054 {
1055     (void) shadowType;
1056     (void) area;
1057     GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
1058
1059     g_return_if_fail(style != NULL);
1060     g_return_if_fail(window != NULL);
1061
1062     sanitize_size(window, &w, &h);
1063
1064     if(gtkQtDebug())
1065         printf("Handle (%d,%d,%d,%d) Widget: %s  Detail: %s \n", x, y, w, h, gtk_widget_get_name(widget), detail);
1066
1067     drawSplitter(GTK_QT_STANDARD_ARGS, orientation);
1068     return;
1069 }
1070
1071 static
1072 void  draw_layout(GtkStyle *style,
1073                   GdkWindow *window,
1074                   GtkStateType stateType,
1075                   gboolean use_text,
1076                   GdkRectangle *area,
1077                   GtkWidget *widget,
1078                   const gchar *detail,
1079                   int x,
1080                   int y,
1081                   PangoLayout *layout)
1082 {
1083     (void) use_text;
1084     cairo_t *t = gdk_cairo_create(window);
1085     GdkColor color;
1086     float opacity = 1.0;
1087     
1088     if(gtkQtDebug())
1089         printf("Layout (%d,%d) Widget: %s, Layout: %s,  Detail: %s %d \n", x, y, gtk_widget_get_name(widget), pango_layout_get_text(layout), detail, stateType);
1090
1091     g_return_if_fail(window != NULL);
1092     
1093     if(area) {
1094         gdk_cairo_rectangle(t, area);
1095         cairo_clip(t);
1096     }
1097     
1098     if(stateType == GTK_STATE_INSENSITIVE)
1099         opacity = 0.45;
1100     
1101     switch(stateType) {
1102         case GTK_STATE_PRELIGHT: /* Not Kde style */
1103             color = style->text[GTK_STATE_NORMAL];
1104             break;
1105         case GTK_STATE_ACTIVE:
1106             if(DETAIL("cellrenderertext")) /* Only in item list */
1107                 color = style->text[stateType];
1108             else
1109                 color = style->text[GTK_STATE_NORMAL];
1110             break;
1111         case GTK_STATE_INSENSITIVE: /* For a strange reason, GTK_STATE_INSENSITIVE color is bad */
1112             color = style->text[GTK_STATE_NORMAL];
1113             opacity = 0.45;
1114             break;
1115         default:
1116             color = style->text[stateType];
1117             break;
1118     }
1119  
1120     cairo_set_source_rgba(t, (float)color.red/65535, (float)color.green/65535, (float)color.blue/65535, opacity);
1121     cairo_move_to(t, x, y);
1122     pango_cairo_show_layout(t, layout);
1123     cairo_destroy(t);
1124
1125 }
1126
1127 GType oxygenengine_type_style = 0;
1128
1129 void
1130 oxygenengine_style_register_type(GTypeModule *module)
1131 {
1132     static const GTypeInfo object_info = {
1133         sizeof(OxygenEngineStyleClass),
1134         (GBaseInitFunc) NULL,
1135         (GBaseFinalizeFunc) NULL,
1136         (GClassInitFunc) oxygenengine_style_class_init,
1137         NULL,           /* class_finalize */
1138         NULL,           /* class_data */
1139         sizeof(OxygenEngineStyle),
1140         0,              /* n_preallocs */
1141         (GInstanceInitFunc) oxygenengine_style_init,
1142         NULL
1143     };
1144
1145     oxygenengine_type_style = g_type_module_register_type(module,
1146                               GTK_TYPE_STYLE,
1147                               "OxygenEngineStyle",
1148                               &object_info, 0);
1149 }
1150
1151 static void
1152 oxygenengine_style_init(OxygenEngineStyle *style)
1153 {
1154     (void) style;
1155 }
1156
1157 static GdkPixbuf *
1158 set_transparency(const GdkPixbuf *pixbuf, gdouble alpha_percent)
1159 {
1160     GdkPixbuf *target;
1161     guchar *data, *current;
1162     unsigned int x, y, rowstride, height, width;
1163
1164     g_return_val_if_fail(pixbuf != NULL, NULL);
1165     g_return_val_if_fail(GDK_IS_PIXBUF(pixbuf), NULL);
1166
1167     /* Returns a copy of pixbuf with it's non-completely-transparent pixels to
1168        have an alpha level "alpha_percent" of their original value. */
1169
1170     target = gdk_pixbuf_add_alpha(pixbuf, FALSE, 0, 0, 0);
1171
1172     if(alpha_percent == 1.0)
1173         return target;
1174     width = gdk_pixbuf_get_width(target);
1175     height = gdk_pixbuf_get_height(target);
1176     rowstride = gdk_pixbuf_get_rowstride(target);
1177     data = gdk_pixbuf_get_pixels(target);
1178
1179     for(y = 0; y < height; y++) {
1180         for(x = 0; x < width; x++) {
1181             /* The "4" is the number of chars per pixel, in this case, RGBA,
1182                the 3 means "skip to the alpha" */
1183             current = data + (y * rowstride) + (x * 4) + 3;
1184             *(current) = (guchar)(*(current) * alpha_percent);
1185         }
1186     }
1187
1188     return target;
1189 }
1190
1191
1192 static GdkPixbuf*
1193 scale_or_ref(GdkPixbuf *src,
1194              int width,
1195              int height)
1196 {
1197     if(width == gdk_pixbuf_get_width(src) &&
1198             height == gdk_pixbuf_get_height(src)) {
1199         return g_object_ref(src);
1200     } else {
1201         return gdk_pixbuf_scale_simple(src, width, height, GDK_INTERP_BILINEAR);
1202     }
1203 }
1204
1205
1206 static GdkPixbuf *
1207 render_icon(GtkStyle            *style,
1208             const GtkIconSource *source,
1209             GtkTextDirection     direction,
1210             GtkStateType         state,
1211             GtkIconSize          size,
1212             GtkWidget           *widget,
1213             const char          *detail)
1214 {
1215     (void) direction;
1216     (void) detail;
1217     int width = 1;
1218     int height = 1;
1219     GdkPixbuf *scaled;
1220     GdkPixbuf *stated;
1221     GdkPixbuf *base_pixbuf;
1222     GdkScreen *screen;
1223     GtkSettings *settings;
1224
1225     /* Oddly, style can be NULL in this function, because
1226      * GtkIconSet can be used without a style and if so
1227      * it uses this function.
1228      */
1229
1230     base_pixbuf = gtk_icon_source_get_pixbuf(source);
1231
1232     g_return_val_if_fail(base_pixbuf != NULL, NULL);
1233
1234     if(widget && gtk_widget_has_screen(widget)) {
1235         screen = gtk_widget_get_screen(widget);
1236         settings = gtk_settings_get_for_screen(screen);
1237     } else if(style->colormap) {
1238         screen = gdk_colormap_get_screen(style->colormap);
1239         settings = gtk_settings_get_for_screen(screen);
1240     } else {
1241         settings = gtk_settings_get_default();
1242         GTK_NOTE(MULTIHEAD,
1243                  g_warning("Using the default screen for gtk_default_render_icon()"));
1244     }
1245
1246     if(size != (GtkIconSize) - 1 && !gtk_icon_size_lookup_for_settings(settings, size, &width, &height)) {
1247         g_warning(G_STRLOC ": invalid icon size '%d'", size);
1248         return NULL;
1249     }
1250
1251     /* If the size was wildcarded, and we're allowed to scale, then scale; otherwise,
1252      * leave it alone.
1253      */
1254     if(size != (GtkIconSize) - 1 && gtk_icon_source_get_size_wildcarded(source))
1255         scaled = scale_or_ref(base_pixbuf, width, height);
1256     else
1257         scaled = g_object_ref(base_pixbuf);
1258
1259     /* If the state was wildcarded, then generate a state. */
1260     if(gtk_icon_source_get_state_wildcarded(source)) {
1261         if(state == GTK_STATE_INSENSITIVE) {
1262             stated = set_transparency(scaled, 0.3);
1263             gdk_pixbuf_saturate_and_pixelate(stated, stated, 0.1, FALSE);
1264
1265             g_object_unref(scaled);
1266         } else if(state == GTK_STATE_PRELIGHT) {
1267             stated = gdk_pixbuf_copy(scaled);
1268
1269             gdk_pixbuf_saturate_and_pixelate(scaled, stated, 1.2, FALSE);
1270
1271             g_object_unref(scaled);
1272         } else {
1273             stated = scaled;
1274         }
1275     } else
1276         stated = scaled;
1277
1278     return stated;
1279 }
1280
1281 static void
1282 oxygenengine_style_class_init(OxygenEngineStyleClass *klass)
1283 {
1284     GtkStyleClass *style_class = GTK_STYLE_CLASS(klass);
1285
1286     parent_class = g_type_class_peek_parent(klass);
1287
1288     style_class->draw_hline = draw_hline;
1289     style_class->draw_vline = draw_vline;
1290     style_class->draw_shadow = draw_shadow;
1291     style_class->draw_polygon = draw_polygon;
1292     style_class->draw_arrow = draw_arrow;
1293     style_class->draw_diamond = draw_diamond;
1294     /*style_class->draw_string = draw_string;*/
1295     style_class->draw_box = draw_box;
1296     style_class->draw_flat_box = draw_flat_box;
1297     style_class->draw_check = draw_check;
1298     style_class->draw_option = draw_option;
1299     style_class->draw_tab = draw_tab;
1300     style_class->draw_shadow_gap = draw_shadow_gap;
1301
1302     /* box around notebooks */
1303     style_class->draw_box_gap = draw_box_gap;
1304     /* the tab */
1305     style_class->draw_extension = draw_extension;
1306
1307     style_class->render_icon = render_icon;
1308
1309     style_class->draw_focus = draw_focus;
1310     style_class->draw_handle = draw_handle;
1311     style_class->draw_layout = draw_layout;
1312
1313     style_class->draw_slider = draw_slider;
1314
1315 }