* Control.cs: Make use of Theme.DoubleBufferingSupported
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ThemeGtk.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2004-2006 Novell, Inc.
21 //
22 // Authors:
23 //      Jordi Mas i Hernandez, jordi@ximian.com
24 //      Alexander Olk, alex.olk@googlemail.com
25 //
26 //      This is an experimental GTK theme. 
27 //
28 //      Comments:
29 //              - For now we would keep all the themes in the same assembly to have
30 //              handy the internals methods. 
31 //              - We are using Pinovoke for now to access GTK/GDK to avoid adding 
32 //              gtk-sharp as a SWF dependency
33 //              - The ThemeGtk comes from ThemeWin32Classic, we use it as the default
34 //              implementation for the methods that we are not taking care of.
35 //              - When GDK is initialised it opens its own display. There is not way of changing it,
36 //              then we use that display as SWF display
37 //              - You can activate this Theme in Linux doing export MONO_THEME=gtk
38 //              - GTK paints controls into a window no a device context. We should inverstigate if we 
39 //              we can encapsulate a dc in a gtkwindow.
40
41
42 // NOT COMPLETE
43
44 using System;
45 using System.Drawing;
46 using System.Drawing.Drawing2D;
47 using System.Drawing.Imaging;
48 using System.Reflection;
49 using System.Runtime.InteropServices;
50
51 namespace System.Windows.Forms
52 {
53         internal class ThemeGtk : ThemeWin32Classic
54         {               
55                 /* GTK enums */
56                 internal enum StateType 
57                 {
58                         Normal,
59                         Active,
60                         Prelight,
61                         Selected,
62                         Insensitive,
63                 }       
64
65                 internal enum ShadowType 
66                 {
67                         None,
68                         In,
69                         Out,
70                         EtchedIn,
71                         EtchedOut,
72                 }       
73
74                 internal enum ArrowType 
75                 {
76                         Up,
77                         Down,
78                         Left,
79                         Right,
80                 }
81
82                 /* Structs */
83                 [StructLayout(LayoutKind.Sequential)]   
84                 internal struct GdkColorStruct
85                 {
86                         internal int pixel;
87                         internal short red;
88                         internal short green;
89                         internal short blue;
90                 }
91
92                 [StructLayout(LayoutKind.Sequential)]   
93                 internal struct GtkStyleStruct
94                 {
95                         [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=12)]
96                         internal byte[] obj; /* GObject is 12 bytes*/
97                         [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
98                         internal GdkColorStruct[] fg;
99                         [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]               
100                         internal GdkColorStruct[] bg;
101                         [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
102                         internal GdkColorStruct[] light;
103                         [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
104                         internal GdkColorStruct[] dark;
105                         [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
106                         internal GdkColorStruct[] mid;
107                         [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
108                         internal GdkColorStruct[] text;
109                         [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
110                         internal GdkColorStruct[] baseclr;
111                         [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
112                         internal GdkColorStruct[] text_aa;              /* Halfway between text/base */
113   
114                         internal GdkColorStruct black;
115                         internal GdkColorStruct white;
116
117                         /* TODO: There is more stuff that we will add when we need it*/
118                 }
119                 
120                 /* GDK imports */
121                 [DllImport("libgdk-x11-2.0.so")]
122                 internal static extern IntPtr gdk_display_manager_get ();
123
124                 [DllImport("libgdk-x11-2.0.so")]
125                 internal static extern IntPtr gdk_display_manager_get_default_display (IntPtr display_manager);
126
127                 [DllImport("libgdk-x11-2.0.so")]
128                 internal static extern void gdk_display_manager_set_default_display (IntPtr display_manager, IntPtr display);
129
130                 [DllImport("libgdk-x11-2.0.so")]
131                 internal static extern IntPtr gdk_x11_display_get_xdisplay (IntPtr display);
132
133                 [DllImport("libgdk-x11-2.0.so")]
134                 static extern IntPtr gdk_window_foreign_new_for_display (IntPtr display, uint anid);
135
136                 [DllImport("libgdk-x11-2.0.so")]
137                 static extern bool gdk_init_check(out int argc, string argv);   
138
139                 /* GTK imports */               
140                 [DllImport("libgtk-x11-2.0.so")]
141                 static extern bool gtk_init_check (out int argc, string argv);
142
143                 [DllImport("libgtk-x11-2.0.so")]
144                 static extern IntPtr gtk_adjustment_new (double value, double lower, double upper, double step_increment, double page_increment, double page_size);
145
146                 [DllImport("libgtk-x11-2.0.so")]
147                 static extern IntPtr gtk_rc_get_style (IntPtr widget);
148
149                 [DllImport("libgtk-x11-2.0.so")]
150                 static extern IntPtr gtk_vscrollbar_new(IntPtr adjustment);
151                 
152                 [DllImport("libgtk-x11-2.0.so")]
153                 static extern IntPtr gtk_hscrollbar_new(IntPtr adjustment);
154
155                 [DllImport("libgtk-x11-2.0.so")]
156                 static extern IntPtr gtk_style_attach (IntPtr raw, IntPtr window);
157
158                 [DllImport("libgtk-x11-2.0.so")]
159                 static extern IntPtr gtk_rc_style_new ();
160
161                 [DllImport("libgtk-x11-2.0.so")]
162                 static extern IntPtr gtk_invisible_new ();
163
164                 [DllImport("libgtk-x11-2.0.so")]
165                 static extern void gtk_widget_ensure_style (IntPtr raw);
166
167                 [DllImport("libgtk-x11-2.0.so")]
168                 static extern IntPtr gtk_widget_get_style (IntPtr raw);
169
170                 [DllImport("libgtk-x11-2.0.so")]
171                 static extern void gtk_style_detach (IntPtr raw);
172                 
173                 [DllImport("libgtk-x11-2.0.so")]
174                 static extern IntPtr  gtk_button_new ();
175
176                 /* GTK Drawing */
177                 [DllImport("libgtk-x11-2.0.so")]
178                 static extern void gtk_paint_handle (IntPtr style, IntPtr window, int state_type, int shadow_type, IntPtr area, IntPtr widget, string detail, int x, int y, int width, int height, int orientation);
179
180                 [DllImport("libgtk-x11-2.0.so")]
181                 static extern void gtk_paint_arrow (IntPtr style, IntPtr window, int state_type, int shadow_type, 
182                                                     IntPtr area, IntPtr widget, string detail, int arrow_type, bool fill, int x, int y, int width, int height);
183
184                 [DllImport("libgtk-x11-2.0.so")]
185                 static extern void gtk_paint_slider (IntPtr style, IntPtr window, int state_type, int shadow_type, 
186                                                      IntPtr area, IntPtr widget, string detail, int x, int y, int width, int height, int orientation);
187
188                 [DllImport("libgtk-x11-2.0.so")]
189                 static extern void gtk_paint_box (IntPtr style, IntPtr window, int state_type, int shadow_type, 
190                                                   IntPtr area, IntPtr widget, string detail, int x, int y, int width, int height);
191                 
192                 [DllImport("libgtk-x11-2.0.so")]
193                 static extern void gtk_paint_flat_box (IntPtr style, IntPtr window, int state_type, int shadow_type,
194                                                        IntPtr area, IntPtr widget, string detail, int x, int y, int width, int height);
195                 
196                 [DllImport("libgtk-x11-2.0.so")]
197                 static extern void gtk_paint_hline(IntPtr style, IntPtr window, int state_type, IntPtr area, IntPtr widget, string detail, int x1, int x2, int y);
198                 
199                 [DllImport("libgtk-x11-2.0.so")]
200                 static extern void gtk_paint_vline(IntPtr style, IntPtr window, int state_type, IntPtr area, IntPtr widget, string detail, int y1, int y2, int x);
201                 
202                 [DllImport("libgtk-x11-2.0.so")]
203                 static extern void gtk_paint_check(IntPtr style, IntPtr window, int state_type, int shadow_type, IntPtr area, IntPtr widget, string detail, int x, int y, int width, int height);
204                 
205                 [DllImport("libgtk-x11-2.0.so")]
206                 static extern void gtk_paint_focus(IntPtr style, IntPtr window, int state_type, IntPtr area, IntPtr widget, string detail, int x, int y, int width, int height);
207                 
208                 [DllImport("libgtk-x11-2.0.so")]
209                 static extern void gtk_widget_size_allocate (IntPtr widget, ref Rectangle allocation);
210                 
211                 [DllImport("libgtk-x11-2.0.so")]
212                 static extern void gtk_widget_set_size_request (IntPtr widget, int width, int height);
213
214                 /* Data */
215                 static protected IntPtr dispmgr;
216                 static protected IntPtr gdkdisplay;
217                 static protected IntPtr widget;
218                 static protected IntPtr style;
219                 static protected SolidBrush br_buttonface;
220                 static protected SolidBrush br_buttontext;
221                 
222                 IntPtr global_gtk_button = gtk_button_new();
223                 IntPtr global_gtk_vscrollbar = IntPtr.Zero;
224                 IntPtr global_gtk_hscrollbar = IntPtr.Zero;
225                 
226                 IntPtr current_gdk_window = IntPtr.Zero;
227                 IntPtr current_style = IntPtr.Zero;
228
229                 public static void InitGtk ()
230                 {       
231                         Console.WriteLine ("ThemeGtk Init");            
232                         int argc = 0;
233                         string argv = "";
234                         
235                         gdk_init_check (out argc, argv);        
236
237                         dispmgr =  gdk_display_manager_get ();
238                         gdkdisplay =  gdk_display_manager_get_default_display (dispmgr);
239                         gtk_init_check (out argc, argv);
240
241                         widget = gtk_invisible_new ();
242                         gtk_widget_ensure_style (widget);
243                         style = gtk_widget_get_style (widget);                  
244
245                         XplatUIX11.GetInstance().SetDisplay (gdk_x11_display_get_xdisplay (gdkdisplay));
246                 }
247
248                 public void LoadSysDefaultColors ()
249                 {
250                         GtkStyleStruct style_struct;                    
251                         
252                         style_struct = (GtkStyleStruct) Marshal.PtrToStructure (style, typeof (GtkStyleStruct));                        
253                         defaultWindowBackColor = ColorFromGdkColor (style_struct.bg[0]);
254                         defaultWindowForeColor = ColorFromGdkColor (style_struct.fg[0]);
255                 }
256
257                 public ThemeGtk () : base ()
258                 {
259                         Console.WriteLine ("ThemeGtk constructor");
260                         InitGtk ();
261                         default_font =  new Font (FontFamily.GenericSansSerif, 8.25f);
262                         
263                         LoadSysDefaultColors ();        
264
265                         br_buttonface = new SolidBrush (defaultWindowBackColor);                
266                         br_buttontext = new SolidBrush (defaultWindowForeColor);                        
267                         always_draw_hotkeys = true;
268                         
269                         IntPtr adj = gtk_adjustment_new (0, 0, 0, 0, 0, 0);
270                         global_gtk_vscrollbar = gtk_vscrollbar_new (adj);
271                         global_gtk_hscrollbar = gtk_hscrollbar_new (adj);
272                 }       
273
274                 public override bool DoubleBufferingSupported {
275                         get {return false; }
276                 }
277                 
278 //              public override Color ColorControl {
279 //                      get { return Color.Blue;}
280 //              }
281                 
282                 protected override void ButtonBase_DrawButton(ButtonBase button, Graphics dc)
283                 {
284                         Rectangle buttonRectangle = button.ClientRectangle;
285                         
286                         IntPtr gdkwindow = gdk_window_foreign_new_for_display (gdkdisplay, (uint) button.Handle);
287                         
288                         IntPtr style;
289                         
290                         style = gtk_rc_get_style (global_gtk_button);           
291                         style = gtk_style_attach (style, gdkwindow);  // need it
292                         
293                         StateType state_type = StateType.Normal;
294                         ShadowType shadow_type = ShadowType.In;
295                         string detail = "buttondefault";
296                         
297                         if (!button.is_enabled) {
298                                 state_type = StateType.Insensitive;
299                         } else
300                         if (button.is_pressed) {
301                                 state_type = StateType.Active;
302                                 shadow_type = ShadowType.Out;
303                                 detail = "button";
304                         } else
305                         if (button.is_entered) {
306                                 state_type = StateType.Prelight;
307                         }
308                         
309                         if (button.flat_style == FlatStyle.Flat)
310                                 gtk_paint_flat_box (style, gdkwindow,
311                                                     (int) state_type,
312                                                     (int) shadow_type,
313                                                     IntPtr.Zero,
314                                                     IntPtr.Zero,
315                                                     detail,
316                                                     buttonRectangle.X, buttonRectangle.Y,
317                                                     buttonRectangle.Width, buttonRectangle.Height);
318                         else
319                         if (button.flat_style != FlatStyle.Popup || (button.flat_style == FlatStyle.Popup && button.is_entered))
320                                 gtk_paint_box (style, gdkwindow,
321                                                (int) state_type,
322                                                (int) shadow_type,
323                                                IntPtr.Zero,
324                                                IntPtr.Zero,
325                                                detail,
326                                                buttonRectangle.X, buttonRectangle.Y,
327                                                buttonRectangle.Width, buttonRectangle.Height);
328                 }
329                 
330                 protected override void ButtonBase_DrawFocus( ButtonBase button, Graphics dc ) {
331                         
332                         if ( !button.is_enabled)
333                                 return;
334                         
335                         Rectangle focus_rect = new Rectangle( button.ClientRectangle.X + 4, button.ClientRectangle.Y + 4, button.ClientRectangle.Width - 9, button.ClientRectangle.Height - 9 );
336                         
337                         IntPtr gdkwindow = gdk_window_foreign_new_for_display (gdkdisplay, (uint) button.Handle);
338                         
339                         IntPtr style;
340                         
341                         style = gtk_rc_get_style (global_gtk_button);           
342                         style = gtk_style_attach (style, gdkwindow);  // need it
343                         
344                         gtk_paint_focus (style,
345                                          gdkwindow,
346                                          (int) StateType.Active,
347                                          IntPtr.Zero,
348                                          IntPtr.Zero,
349                                          "button",
350                                          focus_rect.X,
351                                          focus_rect.Y,
352                                          focus_rect.Width,
353                                          focus_rect.Height);
354                 }
355                 
356                 #region ScrollBar
357                 public override void DrawScrollBar( Graphics dc, Rectangle clip, ScrollBar bar ) {
358                         int             scrollbutton_width = bar.scrollbutton_width;
359                         int             scrollbutton_height = bar.scrollbutton_height;
360                         Rectangle       first_arrow_area;
361                         Rectangle       second_arrow_area;                      
362                         Rectangle       thumb_pos;
363                         
364                         IntPtr gdkwindow = gdk_window_foreign_new_for_display (gdkdisplay, (uint) bar.Handle);
365                         
366                         IntPtr style;
367                         
368                         Rectangle allocation = new Rectangle (bar.ClientRectangle.X, bar.ClientRectangle.Y, bar.ClientRectangle.Width, bar.ClientRectangle.Height);
369                         
370                         // fix for artefacts
371                         Color fix_color = bar.Parent != null ? bar.Parent.BackColor : ColorControl;
372                         
373                         if (bar.vert) {
374                                 style = gtk_rc_get_style (global_gtk_vscrollbar);
375                                 
376                                 gtk_widget_size_allocate (global_gtk_vscrollbar, ref allocation);
377                                 
378                                 dc.FillRectangle (ResPool.GetSolidBrush (fix_color), 
379                                                   bar.ClientRectangle.X, bar.ClientRectangle.Y, bar.ClientRectangle.Width, 3);
380                                 dc.FillRectangle (ResPool.GetSolidBrush (fix_color), 
381                                                   bar.ClientRectangle.X, bar.ClientRectangle.Bottom - 4, bar.ClientRectangle.Width, 3);
382                         } else {
383                                 style = gtk_rc_get_style (global_gtk_hscrollbar);
384                                 
385                                 gtk_widget_size_allocate (global_gtk_hscrollbar, ref allocation);
386                                 
387                                 dc.FillRectangle (ResPool.GetSolidBrush (fix_color), 
388                                                   bar.ClientRectangle.X, bar.ClientRectangle.Y, 3, bar.ClientRectangle.Height);
389                                 dc.FillRectangle (ResPool.GetSolidBrush (fix_color), 
390                                                   bar.ClientRectangle.Right - 4, bar.ClientRectangle.Y, 3, bar.ClientRectangle.Height);
391                         }
392                         
393                         style = gtk_style_attach (style, gdkwindow);  // need it
394                         
395                         current_gdk_window = gdkwindow;
396                         current_style = style;
397                         
398                         thumb_pos = bar.ThumbPos;
399                         
400                         if ( bar.vert ) {
401                                 first_arrow_area = new Rectangle( 0, 0, bar.Width, scrollbutton_height + 1 );
402                                 bar.FirstArrowArea = first_arrow_area;
403                                 
404                                 second_arrow_area = new Rectangle( 0, bar.ClientRectangle.Height - scrollbutton_height - 1, bar.Width, scrollbutton_height + 1 );
405                                 bar.SecondArrowArea = second_arrow_area;
406                                 
407                                 thumb_pos.Width = bar.Width;
408                                 bar.ThumbPos = thumb_pos;
409                                 
410                                 /* Background */
411                                 switch ( bar.thumb_moving ) {
412                                 case ScrollBar.ThumbMoving.None: {
413                                                 ScrollBar_Vertical_Draw_ThumbMoving_None( scrollbutton_height, bar, clip, dc );
414                                                 break;
415                                         }
416                                 case ScrollBar.ThumbMoving.Forward: {
417                                                 ScrollBar_Vertical_Draw_ThumbMoving_Forward( scrollbutton_height, bar, thumb_pos, clip, dc );
418                                                 break;
419                                         }
420                                         
421                                 case ScrollBar.ThumbMoving.Backwards: {
422                                                 ScrollBar_Vertical_Draw_ThumbMoving_Backwards( scrollbutton_height, bar, thumb_pos, clip, dc );
423                                                 break;
424                                         }
425                                         
426                                 default:
427                                         break;
428                                 }
429                                 
430                                 /* Buttons */
431                                 if ( clip.IntersectsWith( first_arrow_area ) )
432                                         CPDrawScrollButton( dc, first_arrow_area, ScrollButton.Up, bar.firstbutton_state );
433                                 if ( clip.IntersectsWith( second_arrow_area ) )
434                                         CPDrawScrollButton( dc, second_arrow_area, ScrollButton.Down, bar.secondbutton_state );
435                         } else {
436                                 first_arrow_area = new Rectangle( 0, 0, scrollbutton_width + 1, bar.Height );
437                                 bar.FirstArrowArea = first_arrow_area;
438                                 
439                                 second_arrow_area = new Rectangle( bar.ClientRectangle.Width - scrollbutton_width - 1, 0, scrollbutton_width + 1, bar.Height );
440                                 bar.SecondArrowArea = second_arrow_area;
441                                 
442                                 thumb_pos.Height = bar.Height;
443                                 bar.ThumbPos = thumb_pos;
444                                 
445                                 /* Background */                                        
446                                 switch ( bar.thumb_moving ) {
447                                 case ScrollBar.ThumbMoving.None: {
448                                                 ScrollBar_Horizontal_Draw_ThumbMoving_None( scrollbutton_width, bar, clip, dc );
449                                                 break;
450                                         }
451                                         
452                                 case ScrollBar.ThumbMoving.Forward: {
453                                                 ScrollBar_Horizontal_Draw_ThumbMoving_Forward( scrollbutton_width, thumb_pos, bar, clip, dc );
454                                                 break;
455                                         }
456                                         
457                                 case ScrollBar.ThumbMoving.Backwards: {
458                                                 ScrollBar_Horizontal_Draw_ThumbMoving_Backwards( scrollbutton_width, thumb_pos, bar, clip, dc );
459                                                 break;
460                                         }
461                                 }
462                                 
463                                 /* Buttons */
464                                 if ( clip.IntersectsWith( first_arrow_area ) )
465                                         CPDrawScrollButton( dc, first_arrow_area, ScrollButton.Left, bar.firstbutton_state );
466                                 if ( clip.IntersectsWith( second_arrow_area ) )
467                                         CPDrawScrollButton( dc, second_arrow_area, ScrollButton.Right, bar.secondbutton_state );
468                         }
469                         
470                         /* Thumb */
471                         ScrollBar_DrawThumb( bar, thumb_pos, clip, dc );                                
472                 }
473                 
474                 protected override void ScrollBar_DrawThumb( ScrollBar bar, Rectangle thumb_pos, Rectangle clip, Graphics dc ) {
475                         if ( bar.Enabled && thumb_pos.Width > 0 && thumb_pos.Height > 0 && clip.IntersectsWith( thumb_pos ) )
476                                 DrawScrollBarThumb( dc, thumb_pos, bar );
477                 }
478                 
479                 protected override void ScrollBar_Vertical_Draw_ThumbMoving_None (int scrollbutton_height, ScrollBar bar, Rectangle clip, Graphics dc)
480                 {
481                         Rectangle r = new Rectangle (0,
482                                                      scrollbutton_height, bar.ClientRectangle.Width, bar.ClientRectangle.Height - (scrollbutton_height * 2));
483                         Rectangle intersect = Rectangle.Intersect (clip, r);
484                         
485                         if (intersect != Rectangle.Empty) {
486                                 
487                                 gtk_paint_box (style, 
488                                                current_gdk_window, 
489                                                (int) StateType.Active,
490                                                (int) ShadowType.Out,
491                                                IntPtr.Zero,
492                                                global_gtk_vscrollbar,
493                                                "vscrollbar",
494                                                intersect.X, intersect.Y,
495                                                intersect.Width, intersect.Height);
496                         }
497                 }
498                 
499                 protected override void ScrollBar_Vertical_Draw_ThumbMoving_Forward( int scrollbutton_height, ScrollBar bar, Rectangle thumb_pos, Rectangle clip, Graphics dc ) {
500                         Rectangle r = new Rectangle( 0,  scrollbutton_height,
501                                                     bar.ClientRectangle.Width, thumb_pos.Y  - scrollbutton_height );
502                         Rectangle intersect = Rectangle.Intersect( clip, r );
503                         
504                         if ( intersect != Rectangle.Empty ) {
505                                 
506                                 gtk_paint_box (style, 
507                                                current_gdk_window, 
508                                                (int) StateType.Active,
509                                                (int) ShadowType.Out,
510                                                IntPtr.Zero,
511                                                global_gtk_vscrollbar,
512                                                "vscrollbar",
513                                                intersect.X, intersect.Y,
514                                                intersect.Width, intersect.Height);
515                         }
516                         
517                         r.X = 0;
518                         r.Y = thumb_pos.Y + thumb_pos.Height;
519                         r.Width = bar.ClientRectangle.Width;
520                         r.Height = bar.ClientRectangle.Height -  ( thumb_pos.Y + thumb_pos.Height ) - scrollbutton_height;
521                         
522                         intersect = Rectangle.Intersect( clip, r );
523                         if ( intersect != Rectangle.Empty ) {
524                                 
525                                 gtk_paint_box (style, 
526                                                current_gdk_window, 
527                                                (int) StateType.Active,
528                                                (int) ShadowType.Out,
529                                                IntPtr.Zero,
530                                                global_gtk_vscrollbar,
531                                                "vscrollbar",
532                                                intersect.X, intersect.Y,
533                                                intersect.Width, intersect.Height);
534                         }
535                 }
536                 
537                 protected override void ScrollBar_Vertical_Draw_ThumbMoving_Backwards( int scrollbutton_height, ScrollBar bar, Rectangle thumb_pos, Rectangle clip, Graphics dc ) {
538                         Rectangle r = new Rectangle( 0,  scrollbutton_height,
539                                                     bar.ClientRectangle.Width, thumb_pos.Y - scrollbutton_height );
540                         Rectangle intersect = Rectangle.Intersect( clip, r );
541                         
542                         if ( intersect != Rectangle.Empty ) {
543                                 
544                                 gtk_paint_box (style, 
545                                                current_gdk_window, 
546                                                (int) StateType.Active,
547                                                (int) ShadowType.Out,
548                                                IntPtr.Zero,
549                                                global_gtk_vscrollbar,
550                                                "vscrollbar",
551                                                intersect.X, intersect.Y,
552                                                intersect.Width, intersect.Height);
553                         }
554                         
555                         r.X = 0;
556                         r.Y = thumb_pos.Y + thumb_pos.Height;
557                         r.Width = bar.ClientRectangle.Width;
558                         r.Height = bar.ClientRectangle.Height -  ( thumb_pos.Y + thumb_pos.Height ) - scrollbutton_height;
559                         
560                         intersect = Rectangle.Intersect( clip, r );
561                         if ( intersect != Rectangle.Empty ) {
562                                 
563                                 gtk_paint_box (style, 
564                                                current_gdk_window, 
565                                                (int) StateType.Active,
566                                                (int) ShadowType.Out,
567                                                IntPtr.Zero,
568                                                global_gtk_vscrollbar,
569                                                "vscrollbar",
570                                                intersect.X, intersect.Y,
571                                                intersect.Width, intersect.Height);
572                         }
573                 }
574                 
575                 protected override void ScrollBar_Horizontal_Draw_ThumbMoving_None( int scrollbutton_width, ScrollBar bar, Rectangle clip, Graphics dc ) {
576                         Rectangle r = new Rectangle( scrollbutton_width,
577                                                     0, bar.ClientRectangle.Width - ( scrollbutton_width * 2 ), bar.ClientRectangle.Height );
578                         Rectangle intersect = Rectangle.Intersect( clip, r );
579                         
580                         if ( intersect != Rectangle.Empty ) {
581                                 
582                                 gtk_paint_box (style, 
583                                                current_gdk_window, 
584                                                (int) StateType.Active,
585                                                (int) ShadowType.Out,
586                                                IntPtr.Zero,
587                                                global_gtk_hscrollbar,
588                                                "hscrollbar",
589                                                intersect.X, intersect.Y,
590                                                intersect.Width, intersect.Height);
591                         }
592                 }
593                 
594                 protected override void ScrollBar_Horizontal_Draw_ThumbMoving_Forward( int scrollbutton_width, Rectangle thumb_pos, ScrollBar bar, Rectangle clip, Graphics dc ) {
595                         Rectangle r = new Rectangle( scrollbutton_width,  0,
596                                                     thumb_pos.X - scrollbutton_width, bar.ClientRectangle.Height );
597                         Rectangle intersect = Rectangle.Intersect( clip, r );
598                         
599                         if ( intersect != Rectangle.Empty ) {
600                                 
601                                 gtk_paint_box (style, 
602                                                current_gdk_window, 
603                                                (int) StateType.Active,
604                                                (int) ShadowType.Out,
605                                                IntPtr.Zero,
606                                                global_gtk_hscrollbar,
607                                                "hscrollbar",
608                                                intersect.X, intersect.Y,
609                                                intersect.Width, intersect.Height);
610                         }
611                         
612                         r.X = thumb_pos.X + thumb_pos.Width;
613                         r.Y = 0;
614                         r.Width = bar.ClientRectangle.Width -  ( thumb_pos.X + thumb_pos.Width ) - scrollbutton_width;
615                         r.Height = bar.ClientRectangle.Height;
616                         
617                         intersect = Rectangle.Intersect( clip, r );
618                         if ( intersect != Rectangle.Empty ) {
619                                 
620                                 gtk_paint_box (style, 
621                                                current_gdk_window, 
622                                                (int) StateType.Active,
623                                                (int) ShadowType.Out,
624                                                IntPtr.Zero,
625                                                global_gtk_hscrollbar,
626                                                "hscrollbar",
627                                                intersect.X, intersect.Y,
628                                                intersect.Width, intersect.Height);
629                         }
630                 }
631                 
632                 protected override void ScrollBar_Horizontal_Draw_ThumbMoving_Backwards( int scrollbutton_width, Rectangle thumb_pos, ScrollBar bar, Rectangle clip, Graphics dc ) {
633                         Rectangle r = new Rectangle( scrollbutton_width,  0,
634                                                     thumb_pos.X - scrollbutton_width, bar.ClientRectangle.Height );
635                         Rectangle intersect = Rectangle.Intersect( clip, r );
636                         
637                         if ( intersect != Rectangle.Empty ) {
638                                 
639                                 gtk_paint_box (style, 
640                                                current_gdk_window, 
641                                                (int) StateType.Active,
642                                                (int) ShadowType.Out,
643                                                IntPtr.Zero,
644                                                global_gtk_hscrollbar,
645                                                "hscrollbar",
646                                                intersect.X, intersect.Y,
647                                                intersect.Width, intersect.Height);
648                         }
649                         
650                         r.X = thumb_pos.X + thumb_pos.Width;
651                         r.Y = 0;
652                         r.Width = bar.ClientRectangle.Width -  ( thumb_pos.X + thumb_pos.Width ) - scrollbutton_width;
653                         r.Height = bar.ClientRectangle.Height;
654                         
655                         intersect = Rectangle.Intersect( clip, r );
656                         if ( intersect != Rectangle.Empty ) {
657                                 
658                                 gtk_paint_box (style, 
659                                                current_gdk_window, 
660                                                (int) StateType.Active,
661                                                (int) ShadowType.Out,
662                                                IntPtr.Zero,
663                                                global_gtk_hscrollbar,
664                                                "hscrollbar",
665                                                intersect.X, intersect.Y,
666                                                intersect.Width, intersect.Height);
667                         }
668                 }
669                 
670                 private void DrawScrollBarThumb( Graphics dc, Rectangle area, ScrollBar bar ) {
671                         IntPtr gtk_scrollbar = IntPtr.Zero;
672                         
673                         if (bar.vert)
674                                 gtk_scrollbar = global_gtk_vscrollbar;
675                         else
676                                 gtk_scrollbar = global_gtk_hscrollbar;
677                         
678                         gtk_paint_box (style, 
679                                        current_gdk_window, 
680                                        (int) StateType.Active,
681                                        (int) ShadowType.In,
682                                        IntPtr.Zero,
683                                        gtk_scrollbar,
684                                        "slider",
685                                        area.X, area.Y,
686                                        area.Width, area.Height);
687                         
688 //                      if ( bar.vert ) {
689 //                              if ( area.Height > 12 ) {
690 //                                      int mid_y = area.Y + ( area.Height / 2 );
691 //                                      int mid_x = area.X + ( area.Width / 2 );
692 //                                      
693 //                                      // TODO: add 2 lines
694 //                                      gtk_paint_hline(current_style,
695 //                                                      current_gdk_window,
696 //                                                      (int) StateType.Normal,
697 //                                                      IntPtr.Zero,
698 //                                                      IntPtr.Zero,
699 //                                                      "through",
700 //                                                      mid_x - 4,
701 //                                                      mid_x + 4,
702 //                                                      mid_y);
703 //                              }
704 //                      } else {
705 //                              // draw grip lines only if there is enough space
706 //                              if ( area.Width > 12 ) {
707 //                                      int mid_x = area.X +  ( area.Width / 2 );
708 //                                      int mid_y = area.Y +  ( area.Height / 2 );
709 //                                      
710 //                                      // TODO: add 2 lines
711 //                                      gtk_paint_vline(current_style,
712 //                                                      current_gdk_window,
713 //                                                      (int) StateType.Normal,
714 //                                                      IntPtr.Zero,
715 //                                                      IntPtr.Zero,
716 //                                                      "through",
717 //                                                      mid_y - 4,
718 //                                                      mid_y + 4,
719 //                                                      mid_x);
720 //                              }
721 //                      }
722                 }
723                 #endregion      // ScrollBar
724                 
725                 public override void CPDrawButton (Graphics graphics, Rectangle rectangle, ButtonState state)
726                 {
727                         bool is_pushed = false;
728                         bool is_checked = false;
729                         bool is_flat = false;
730                         bool is_inactive = false;
731                         
732                         if ((state & ButtonState.Pushed) != 0) {
733                                 is_pushed = true;
734                         }
735                         
736                         if ((state & ButtonState.Checked) != 0) {
737                                 is_checked = true;
738                         }
739                         
740                         if ((state & ButtonState.Flat) != 0) {
741                                 is_flat = true;
742                         }
743                         
744                         if ((state & ButtonState.Inactive) != 0) {
745                                 is_inactive = true;
746                         }
747                         
748                         IntPtr style;
749                         
750                         style = gtk_rc_get_style (global_gtk_button);           
751                         style = gtk_style_attach (style, current_gdk_window);  // need it
752                         
753                         StateType state_type = StateType.Normal;
754                         ShadowType shadow_type = ShadowType.In;
755                         string detail = "buttondefault";
756                         
757                         if (is_inactive) {
758                                 state_type = StateType.Insensitive;
759                         } else
760                         if (is_pushed) {
761                                 state_type = StateType.Active;
762                                 shadow_type = ShadowType.Out;
763                                 detail = "button";
764                         }
765                         
766                         gtk_paint_box (style, current_gdk_window,
767                                        (int) state_type,
768                                        (int) shadow_type,
769                                        IntPtr.Zero,
770                                        IntPtr.Zero,
771                                        detail,
772                                        rectangle.X, rectangle.Y,
773                                        rectangle.Width, rectangle.Height);
774                 }
775                 
776                 /* Scroll button: regular button + direction arrow */
777                 public override void CPDrawScrollButton (Graphics dc, Rectangle area, ScrollButton scroll_button_type, ButtonState state)
778                 {
779                         bool enabled = (state == ButtonState.Inactive) ? false: true;
780                         
781                         StateType state_type = enabled ? StateType.Normal : StateType.Insensitive;
782                         
783                         DrawScrollButtonPrimitive (dc, area, state, scroll_button_type);
784                         
785                         if (area.Width < 12 || area.Height < 12) /* Cannot see a thing at smaller sizes */
786                                 return;
787                         
788                         ArrowType arrow_type = 0;
789                         
790                         switch (scroll_button_type) {
791                         case ScrollButton.Up:
792                                 arrow_type = ArrowType.Up;
793                                 break;
794                         case ScrollButton.Down:
795                                 arrow_type = ArrowType.Down;
796                                 break;
797                         case ScrollButton.Right:
798                                 arrow_type = ArrowType.Right;
799                                 break;
800                         case ScrollButton.Left:
801                                 arrow_type = ArrowType.Left;
802                                 break;
803                         default:
804                                 break;
805                         }
806                         
807                         int centerX = area.Left + area.Width / 2;
808                         int centerY = area.Top + area.Height / 2;
809                         int arrow_x = 0, arrow_y = 0, arrow_height = 0, arrow_width = 0;
810                         
811                         switch (scroll_button_type) {
812                         case ScrollButton.Down:
813                         case ScrollButton.Up:
814                                 arrow_x = centerX - 4;
815                                 arrow_y = centerY - 2;
816                                 arrow_width = 8;
817                                 arrow_height = 4;
818                                 break;
819                         case ScrollButton.Left:
820                         case ScrollButton.Right:
821                                 arrow_x = centerX - 2;
822                                 arrow_y = centerY - 4;
823                                 arrow_width = 4;
824                                 arrow_height = 8;
825                                 break;
826                         default:
827                                 break;
828                         }
829                         
830                         gtk_paint_arrow (style, 
831                                          current_gdk_window, 
832                                          (int) state_type,
833                                          (int) ShadowType.In,
834                                          IntPtr.Zero,
835                                          IntPtr.Zero,
836                                          "",            
837                                          (int) arrow_type, true, 
838                                          arrow_x, 
839                                          arrow_y,
840                                          arrow_width, arrow_height);
841                 }
842                 
843                 public void DrawScrollButtonPrimitive (Graphics dc, Rectangle area, ButtonState state, ScrollButton scroll_button_type)
844                 {
845                         StateType state_type = StateType.Normal;
846                         ShadowType shadow_type = ShadowType.In;
847                         
848                         if ((state & ButtonState.Pushed) == ButtonState.Pushed) {
849                                 state_type = StateType.Active;
850                                 shadow_type = ShadowType.Out;
851                         }
852                         
853                         switch (scroll_button_type) {
854                         case ScrollButton.Left:
855                         case ScrollButton.Right:
856                                 gtk_paint_box (style, 
857                                                current_gdk_window, 
858                                                (int) state_type,
859                                                (int) shadow_type,
860                                                IntPtr.Zero,
861                                                global_gtk_hscrollbar,
862                                                "stepper",
863                                                area.X, area.Y,
864                                                area.Width, area.Height);
865                                 break;
866                         case ScrollButton.Up:
867                         case ScrollButton.Down:
868                                 gtk_paint_box (style, 
869                                                current_gdk_window, 
870                                                (int) state_type,
871                                                (int) shadow_type,
872                                                IntPtr.Zero,
873                                                global_gtk_vscrollbar,
874                                                "stepper",
875                                                area.X, area.Y,
876                                                area.Width, area.Height);
877                                 break;
878                         }
879                 }
880                 
881                 private static Color ColorFromGdkColor (GdkColorStruct gtkcolor)
882                 {
883                         return Color.FromArgb (255, 
884                                 (gtkcolor.red >> 8)  & 0xff, 
885                                 (gtkcolor.green  >> 8) & 0xff,
886                                 (gtkcolor.blue >> 8) & 0xff );
887                 }
888
889         } //class
890 }