2006-01-18 Alexander Olk <alex.olk@googlemail.com>
[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 //      Hint:   Currently ThemeGtk doesn't work without a modified Control class, it doesn't like
42 //              double buffering. As soon as DoubleBufferingSupported is implemented it should run
43 //              out of the box. Alex.
44
45
46 // NOT COMPLETE
47
48 using System;
49 using System.Drawing;
50 using System.Drawing.Drawing2D;
51 using System.Drawing.Imaging;
52 using System.Reflection;
53 using System.Runtime.InteropServices;
54
55 namespace System.Windows.Forms
56 {
57         internal class ThemeGtk : ThemeWin32Classic
58         {               
59                 /* GTK enums */
60                 internal enum StateType 
61                 {
62                         Normal,
63                         Active,
64                         Prelight,
65                         Selected,
66                         Insensitive,
67                 }       
68
69                 internal enum ShadowType 
70                 {
71                         None,
72                         In,
73                         Out,
74                         EtchedIn,
75                         EtchedOut,
76                 }       
77
78                 internal enum ArrowType 
79                 {
80                         Up,
81                         Down,
82                         Left,
83                         Right,
84                 }
85
86                 /* Structs */
87                 [StructLayout(LayoutKind.Sequential)]   
88                 internal struct GdkColorStruct
89                 {
90                         internal int pixel;
91                         internal short red;
92                         internal short green;
93                         internal short blue;
94                 }
95
96                 [StructLayout(LayoutKind.Sequential)]   
97                 internal struct GtkStyleStruct
98                 {
99                         [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=12)]
100                         internal byte[] obj; /* GObject is 12 bytes*/
101                         [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
102                         internal GdkColorStruct[] fg;
103                         [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]               
104                         internal GdkColorStruct[] bg;
105                         [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
106                         internal GdkColorStruct[] light;
107                         [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
108                         internal GdkColorStruct[] dark;
109                         [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
110                         internal GdkColorStruct[] mid;
111                         [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
112                         internal GdkColorStruct[] text;
113                         [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
114                         internal GdkColorStruct[] baseclr;
115                         [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)]
116                         internal GdkColorStruct[] text_aa;              /* Halfway between text/base */
117   
118                         internal GdkColorStruct black;
119                         internal GdkColorStruct white;
120
121                         /* TODO: There is more stuff that we will add when we need it*/
122                 }
123
124                         
125                 /* GDK imports */
126                 [DllImport("libgdk-x11-2.0.so")]
127                 internal static extern IntPtr gdk_display_manager_get ();
128
129                 [DllImport("libgdk-x11-2.0.so")]
130                 internal static extern IntPtr gdk_display_manager_get_default_display (IntPtr display_manager);
131
132                 [DllImport("libgdk-x11-2.0.so")]
133                 internal static extern void gdk_display_manager_set_default_display (IntPtr display_manager, IntPtr display);
134
135                 [DllImport("libgdk-x11-2.0.so")]
136                 internal static extern IntPtr gdk_x11_display_get_xdisplay (IntPtr display);
137
138                 [DllImport("libgdk-x11-2.0.so")]
139                 static extern IntPtr gdk_window_foreign_new_for_display (IntPtr display, uint anid);
140
141                 [DllImport("libgdk-x11-2.0.so")]
142                 static extern bool gdk_init_check(out int argc, string argv);   
143
144                 /* GTK imports */               
145                 [DllImport("libgtk-x11-2.0.so")]
146                 static extern bool gtk_init_check (out int argc, string argv);
147
148                 [DllImport("libgtk-x11-2.0.so")]
149                 static extern IntPtr gtk_adjustment_new (double value, double lower, double upper, double step_increment, double page_increment, double page_size);
150
151                 [DllImport("libgtk-x11-2.0.so")]
152                 static extern IntPtr gtk_rc_get_style (IntPtr widget);
153
154                 [DllImport("libgtk-x11-2.0.so")]
155                 static extern IntPtr gtk_vscrollbar_new(IntPtr adjustment);
156
157                 [DllImport("libgtk-x11-2.0.so")]
158                 static extern IntPtr gtk_style_attach (IntPtr raw, IntPtr window);
159
160                 [DllImport("libgtk-x11-2.0.so")]
161                 static extern IntPtr gtk_rc_style_new ();
162
163                 [DllImport("libgtk-x11-2.0.so")]
164                 static extern IntPtr gtk_invisible_new ();
165
166                 [DllImport("libgtk-x11-2.0.so")]
167                 static extern void gtk_widget_ensure_style (IntPtr raw);
168
169                 [DllImport("libgtk-x11-2.0.so")]
170                 static extern IntPtr gtk_widget_get_style (IntPtr raw);
171
172                 [DllImport("libgtk-x11-2.0.so")]
173                 static extern void gtk_style_detach (IntPtr raw);
174                 
175                 [DllImport("libgtk-x11-2.0.so")]
176                 static extern IntPtr  gtk_button_new ();
177
178                 /* GTK Drawing */
179                 [DllImport("libgtk-x11-2.0.so")]
180                 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);
181
182                 [DllImport("libgtk-x11-2.0.so")]
183                 static extern void gtk_paint_arrow (IntPtr style, IntPtr window, int state_type, int shadow_type, 
184                                                     IntPtr area, IntPtr widget, string detail, int arrow_type, bool fill, int x, int y, int width, int height);
185
186                 [DllImport("libgtk-x11-2.0.so")]
187                 static extern void gtk_paint_slider (IntPtr style, IntPtr window, int state_type, int shadow_type, 
188                                                      IntPtr area, IntPtr widget, string detail, int x, int y, int width, int height, int orientation);
189
190                 [DllImport("libgtk-x11-2.0.so")]
191                 static extern void gtk_paint_box (IntPtr style, IntPtr window, int state_type, int shadow_type, 
192                                                   IntPtr area, IntPtr widget, string detail, int x, int y, int width, int height);
193                 
194                 [DllImport("libgtk-x11-2.0.so")]
195                 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);
196                 
197                 [DllImport("libgtk-x11-2.0.so")]
198                 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);
199                 
200                 [DllImport("libgtk-x11-2.0.so")]
201                 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);
202
203                 /* Data */
204                 static protected IntPtr dispmgr;
205                 static protected IntPtr gdkdisplay;
206                 static protected IntPtr widget;
207                 static protected IntPtr style;
208                 static protected SolidBrush br_buttonface;
209                 static protected SolidBrush br_buttontext;
210                 
211                 IntPtr global_gtk_button = gtk_button_new();
212
213                 public static void InitGtk ()
214                 {       
215                         Console.WriteLine ("ThemeGtk Init");            
216                         int argc = 0;
217                         string argv = "";
218                         
219                         gdk_init_check (out argc, argv);        
220
221                         dispmgr =  gdk_display_manager_get ();
222                         gdkdisplay =  gdk_display_manager_get_default_display (dispmgr);
223                         gtk_init_check (out argc, argv);
224
225                         widget = gtk_invisible_new ();
226                         gtk_widget_ensure_style (widget);
227                         style = gtk_widget_get_style (widget);                  
228
229                         XplatUIX11.GetInstance().SetDisplay (gdk_x11_display_get_xdisplay (gdkdisplay));
230                 }
231
232                 public void LoadSysDefaultColors ()
233                 {
234                         GtkStyleStruct style_struct;                    
235                         
236                         style_struct = (GtkStyleStruct) Marshal.PtrToStructure (style, typeof (GtkStyleStruct));                        
237                         defaultWindowBackColor = ColorFromGdkColor (style_struct.bg[0]);
238                         defaultWindowForeColor = ColorFromGdkColor (style_struct.fg[0]);
239                 }
240
241                 public ThemeGtk () : base ()
242                 {
243                         Console.WriteLine ("ThemeGtk constructor");
244                         InitGtk ();
245                         default_font =  new Font (FontFamily.GenericSansSerif, 8.25f);
246                         
247                         LoadSysDefaultColors ();        
248
249                         br_buttonface = new SolidBrush (defaultWindowBackColor);                
250                         br_buttontext = new SolidBrush (defaultWindowForeColor);                        
251                         always_draw_hotkeys = true;
252                 }       
253
254                 public override bool DoubleBufferingSupported {
255                         get {return false; }
256                 }
257                 
258 //              public override Color ColorControl {
259 //                      get { return Color.Blue;}
260 //              }
261                 
262                 protected override void ButtonBase_DrawButton(ButtonBase button, Graphics dc)
263                 {
264                         Rectangle buttonRectangle = button.ClientRectangle;
265                         
266                         IntPtr gdkwindow = gdk_window_foreign_new_for_display (gdkdisplay, (uint) button.Handle);
267                         
268                         IntPtr style;
269                         
270                         style = gtk_rc_get_style (global_gtk_button);           
271                         style = gtk_style_attach (style, gdkwindow);  // need it
272                         
273                         StateType state_type = StateType.Normal;
274                         ShadowType shadow_type = ShadowType.In;
275                         string detail = "buttondefault";
276                         
277                         if (!button.is_enabled) {
278                                 state_type = StateType.Insensitive;
279                         } else
280                         if (button.is_pressed) {
281                                 state_type = StateType.Active;
282                                 shadow_type = ShadowType.Out;
283                                 detail = "button";
284                         } else
285                         if (button.is_entered) {
286                                 state_type = StateType.Prelight;
287                         }
288                         
289                         if (button.flat_style != FlatStyle.Popup || (button.flat_style == FlatStyle.Popup && button.is_entered))
290                         gtk_paint_box (style, gdkwindow,
291                                        (int) state_type,
292                                        (int) shadow_type,
293                                        IntPtr.Zero,
294                                        IntPtr.Zero,
295                                        detail,
296                                        buttonRectangle.X, buttonRectangle.Y,
297                                        buttonRectangle.Width, buttonRectangle.Height);
298                 }
299                 
300                 protected override void ButtonBase_DrawFocus( ButtonBase button, Graphics dc ) {
301                         
302                         if ( !button.is_enabled || button.flat_style == FlatStyle.Popup )
303                                 return;
304                         
305                         Rectangle focus_rect = new Rectangle( button.ClientRectangle.X + 5, button.ClientRectangle.Y + 5, button.ClientRectangle.Width - 10, button.ClientRectangle.Height - 10 );
306                         
307                         IntPtr gdkwindow = gdk_window_foreign_new_for_display (gdkdisplay, (uint) button.Handle);
308                         
309                         IntPtr style;
310                         
311                         style = gtk_rc_get_style (global_gtk_button);           
312                         style = gtk_style_attach (style, gdkwindow);  // need it
313                         
314                         gtk_paint_focus (style,
315                                          gdkwindow,
316                                          (int) StateType.Active,
317                                          IntPtr.Zero,
318                                          IntPtr.Zero,
319                                          "button",
320                                          focus_rect.X,
321                                          focus_rect.Y,
322                                          focus_rect.Width,
323                                          focus_rect.Height);
324                 }
325                 
326 #if updated             
327                 public void DrawScrollButton (Graphics dc, Rectangle area, ScrollButton type, ButtonState state,
328                         IntPtr gdkwindow, IntPtr style)
329                 {
330                         ArrowType arrow_type = 0;
331
332                         gtk_paint_box (style, 
333                                         gdkwindow, 
334                                         (int) StateType.Normal,
335                                         (int) ShadowType.Out,
336                                         IntPtr.Zero,
337                                         IntPtr.Zero,
338                                         "trough",                                       
339                                         area.X, area.Y,
340                                         area.Width, area.Height);
341                         
342                         /* Calc arrows coordinates */
343                         switch (type) {
344                         case ScrollButton.Up:
345                                 arrow_type = ArrowType.Up;
346                                 break;
347                         case ScrollButton.Down:
348                                 arrow_type = ArrowType.Down;
349                                 break;
350                         case ScrollButton.Right:
351                                 arrow_type = ArrowType.Right;
352                                 break;
353                         case ScrollButton.Left:
354                                 arrow_type = ArrowType.Left;
355                                 break;
356                         default:
357                                 break;
358                         }
359                                 
360
361                         gtk_paint_arrow (style, 
362                                         gdkwindow, 
363                                         (int) StateType.Normal,
364                                         (int) ShadowType.In,
365                                         IntPtr.Zero,
366                                         IntPtr.Zero,
367                                         "",             
368                                         (int) arrow_type, true, 
369                                         area.X + ((area.Width - (area.Width/2) ) / 2), 
370                                         area.Y + ((area.Height - (area.Height/2) ) / 2),
371                                         area.Width / 2, area.Height / 2);                       
372                 
373                 }
374
375                 public override void DrawScrollBar (Graphics dc, Rectangle area, ScrollBar bar,
376                         ref Rectangle thumb_pos, ref Rectangle first_arrow_area, ref Rectangle second_arrow_area, 
377                         ButtonState first_arrow, ButtonState second_arrow, ref int scrollbutton_width, 
378                         ref int scrollbutton_height, bool vert)
379                 {
380                         IntPtr gdkwindow = gdk_window_foreign_new_for_display (gdkdisplay, (uint) bar.Handle);                  
381                         IntPtr adj = gtk_adjustment_new (0, 0, 0, 0, 0, 0);
382                         IntPtr scrollbar = gtk_vscrollbar_new (adj);
383                         IntPtr style;
384                                        
385                         style = gtk_rc_get_style (scrollbar);           
386                         style = gtk_style_attach (style, gdkwindow);  // need it                        
387                         
388                         /* Background */
389                         gtk_paint_box (style, 
390                                 gdkwindow, 
391                                 (int) StateType.Active,
392                                 (int) ShadowType.In,
393                                 IntPtr.Zero,
394                                 IntPtr.Zero,
395                                 "trough",
396                                 area.X, area.Y,
397                                 area.Width, area.Height);
398
399                         /* See gtk_range_expose */
400                         first_arrow_area.X = first_arrow_area. Y = 0;
401                         first_arrow_area.Width = scrollbutton_width;
402                         first_arrow_area.Height = scrollbutton_height;
403
404                         if (vert) {             
405
406                                 second_arrow_area.X = 0;
407                                 second_arrow_area.Y = area.Height - scrollbutton_height;
408                                 second_arrow_area.Width = scrollbutton_width;
409                                 second_arrow_area.Height = scrollbutton_height;
410
411                                 /* First button*/
412                                 DrawScrollButton (dc, first_arrow_area, ScrollButton.Up, first_arrow,
413                                         gdkwindow, style);
414
415                                 /* Second button*/
416                                 DrawScrollButton (dc, second_arrow_area, ScrollButton.Down, second_arrow,
417                                         gdkwindow, style);
418
419                         } else {
420
421                                 second_arrow_area.Y = 0;
422                                 second_arrow_area.X = area.Width - scrollbutton_width;
423                                 second_arrow_area.Width = scrollbutton_width;
424                                 second_arrow_area.Height = scrollbutton_height;
425
426                                 /* First button*/
427                                 DrawScrollButton (dc, first_arrow_area, ScrollButton.Left, first_arrow,
428                                         gdkwindow, style);
429
430                                 /* Second button*/
431                                 DrawScrollButton (dc, second_arrow_area, ScrollButton.Right, second_arrow,
432                                         gdkwindow, style);
433
434                         }
435
436                         /* Slider */
437                         gtk_paint_slider (style, 
438                                 gdkwindow, 
439                                 (int) StateType.Normal,
440                                 (int) ShadowType.Out,
441                                 IntPtr.Zero,
442                                 IntPtr.Zero,
443                                 "",             
444                                 thumb_pos.X, thumb_pos.Y,
445                                 thumb_pos.Width, thumb_pos.Height,
446                                 (int) Orientation.Vertical);
447
448                         //gtk_style_detach (style);
449                 }
450 #endif
451                 
452                 private static Color ColorFromGdkColor (GdkColorStruct gtkcolor)
453                 {
454                         return Color.FromArgb (255, 
455                                 (gtkcolor.red >> 8)  & 0xff, 
456                                 (gtkcolor.green  >> 8) & 0xff,
457                                 (gtkcolor.blue >> 8) & 0xff );
458                 }
459
460         } //class
461 }