Переглянути джерело

gdk_pixbuf_get_type() now returns Size_T.
Changed gadget map to TPtrMap.

woollybah 6 роки тому
батько
коміт
f6d31c4f2c
3 змінених файлів з 7344 додано та 7359 видалено
  1. 1165 1180
      gtk3maxgui.mod/gtkcommon.bmx
  2. 5394 5394
      gtk3maxgui.mod/gtkgadget.bmx
  3. 785 785
      gtk3maxgui.mod/gtkgui.bmx

+ 1165 - 1180
gtk3maxgui.mod/gtkcommon.bmx

@@ -1,1180 +1,1165 @@
-' Copyright (c) 2006-2018 Bruce A Henderson
-' 
-' Permission is hereby granted, free of charge, to any person obtaining a copy
-' of this software and associated documentation files (the "Software"), to deal
-' in the Software without restriction, including without limitation the rights
-' to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-' copies of the Software, and to permit persons to whom the Software is
-' furnished to do so, subject to the following conditions:
-' 
-' The above copyright notice and this permission notice shall be included in
-' all copies or substantial portions of the Software.
-' 
-' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-' THE SOFTWARE.
-' 
-SuperStrict
-
-
-?bmxng
-Import BRL.SystemDefault
-?Not bmxng
-Import BRL.System
-?
-Import MaxGUI.MaxGUI
-Import BRL.LinkedList
-Import BRL.Map
-
-?linux
-'Import "-L/usr/lib/x86_64-linux-gnu/"
-Import "-lgtk-3"
-Import "-lgdk-3"
-Import "-latk-1.0"
-Import "-lgio-2.0"
-Import "-lpangocairo-1.0"
-Import "-lgdk_pixbuf-2.0"
-Import "-lcairo-gobject"
-Import "-lpango-1.0"
-Import "-lcairo"
-Import "-lgobject-2.0"
-Import "-lglib-2.0"
-?
-
-Import "gtkkeymap.bmx"
-Import "elist.bmx"
-
-Extern
-
-	' main loop and events
-	Function gtk_init(argc:Int Ptr, argv:Byte Ptr Ptr Ptr)
-	Function gtk_main_iteration_do:Int(blocking:Int)
-	Function gtk_events_pending:Int()
-	Function gtk_get_current_event_time:Int()
-
-	' gdkscreen
-	Function gdk_screen_get_default:Byte Ptr()
-	Function gdk_screen_get_width:Int(handle:Byte Ptr)
-	Function gdk_screen_get_height:Int(handle:Byte Ptr)
-	Function gdk_screen_get_system_visual:Byte Ptr(handle:Byte Ptr)
-	Function gdk_screen_get_display:Byte Ptr(screen:Byte Ptr)
-	Function gdk_screen_get_n_monitors:Int(screen:Byte Ptr)
-	Function gdk_screen_get_monitor_scale_factor:Int(screen:Byte Ptr, monitor:Int)
-	
-	' visuals
-	Function gdk_visual_get_depth:Int(handle:Byte Ptr)
-	
-	' gdkdisplay
-	Function gdk_display_get_default:Byte Ptr()
-
-	' gdkcursor
-	Function gdk_cursor_new_for_display:Byte Ptr(display:Byte Ptr, cursorType:Int)
-
-	' gtkmessagedialog
-	Function gtk_message_dialog_new:Byte Ptr(parent:Byte Ptr, flags:Int, _type:Int, buttons:Int, message:Byte Ptr)
-
-	' gtkdialog
-	Function gtk_dialog_run:Int(handle:Byte Ptr)
-	Function gtk_dialog_add_button:Byte Ptr(handle:Byte Ptr, buttonText$z, responseId:Int)
-	
-	' gtkwidget
-	Function gtk_widget_destroy(handle:Byte Ptr)
-	Function gtk_widget_show(handle:Byte Ptr)
-	Function gtk_widget_hide(handle:Byte Ptr)
-?bmxng
-	Function gtk_widget_get_preferred_size(handle:Byte Ptr, minSize:GtkRequisition Var, natSize:GtkRequisition Var)
-	Function gtk_widget_get_allocation(handle:Byte Ptr, allocation:GtkAllocation Var)
-	Function gtk_widget_override_color(handle:Byte Ptr, state:Int, color:GdkRGBA Var)
-	Function gtk_widget_size_allocate(handle:Byte Ptr, allocation:GtkAllocation Var)
-	Function gtk_widget_override_background_color(handle:Byte Ptr, state:Int, color:GdkRGBA Var)
-?Not bmxng
-	Function gtk_widget_get_preferred_size(handle:Byte Ptr, minSize:Byte Ptr, natSize:Byte Ptr)
-	Function gtk_widget_get_allocation(handle:Byte Ptr, allocation:Byte Ptr)
-	Function gtk_widget_override_color(handle:Byte Ptr, state:Int, color:Byte Ptr)
-	Function gtk_widget_size_allocate(handle:Byte Ptr, allocation:Byte Ptr)
-	Function gtk_widget_override_background_color(handle:Byte Ptr, state:Int, color:Byte Ptr)
-?
-	Function gtk_widget_grab_default(handle:Byte Ptr)
-	Function gtk_widget_set_size_request(handle:Byte Ptr, width:Int, height:Int)
-	Function gtk_widget_remove_accelerator:Int(handle:Byte Ptr, group:Byte Ptr, key:Int, mods:Int)
-	Function gtk_widget_add_accelerator(handle:Byte Ptr, signal:Byte Ptr, group:Byte Ptr, key:Int, mods:Int, flags:Int)
-	Function gtk_widget_add_events(handle:Byte Ptr, events:Int)
-	Function gtk_widget_set_tooltip_text(handle:Byte Ptr, tooltip:Byte Ptr)
-	Function gtk_widget_set_has_tooltip(handle:Byte Ptr, value:Int)
-	Function gtk_widget_grab_focus(handle:Byte Ptr)
-	Function gtk_widget_queue_draw(handle:Byte Ptr)
-	Function gtk_widget_get_state_flags:Int(handle:Byte Ptr)
-	Function gtk_widget_get_visible:Int(handle:Byte Ptr)
-	Function gtk_widget_set_sensitive(handle:Byte Ptr, sensitive:Int)
-	Function gtk_widget_is_sensitive:Int(handle:Byte Ptr)
-	Function gtk_widget_get_parent_window:Byte Ptr(handle:Byte Ptr)
-	Function gtk_widget_get_pango_context:Byte Ptr(handle:Byte Ptr)
-	Function gtk_widget_get_style_context:Byte Ptr(handle:Byte Ptr)
-	Function gtk_widget_get_window:Byte Ptr(handle:Byte Ptr)
-	Function gtk_widget_has_focus:Int(handle:Byte Ptr)
-	
-	' gtkfilechooserdialog
-	Function gtk_file_chooser_dialog_new:Byte Ptr(title:Byte Ptr, parent:Byte Ptr, action:Int, but1$z, opt1:Int, but2$z, opt2:Int, opt3:Byte Ptr)
-	
-	' gtkfilechooser
-	Function gtk_file_chooser_set_current_folder:Int(handle:Byte Ptr, filename:Byte Ptr)
-	Function gtk_file_chooser_set_filename:Int(handle:Byte Ptr, filename:Byte Ptr)
-	Function gtk_file_chooser_get_filename:Byte Ptr(handle:Byte Ptr)
-	Function gtk_file_chooser_add_filter(handle:Byte Ptr, filter:Byte Ptr)
-
-	' glib
-	Function g_free(mem:Byte Ptr)
-	
-	' gobject
-	Function g_object_unref(handle:Byte Ptr)
-	Function g_object_set_int(handle:Byte Ptr, property:Byte Ptr, value:Int, _null:Byte Ptr=Null) = "void g_object_set(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*) !"
-	Function g_object_set_double(handle:Byte Ptr, property:Byte Ptr, value:Double, _null:Byte Ptr=Null) = "void g_object_set(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*) !"
-	Function g_value_set_string(handle:Byte Ptr, str:Byte Ptr)
-	Function g_value_unset(handle:Byte Ptr)
-	Function g_value_init:Byte Ptr(handle:Byte Ptr, _type:Int)
-	Function g_value_set_object(handle:Byte Ptr, obj:Byte Ptr)
-	Function g_value_get_string:Byte Ptr(handle:Byte Ptr)
-	Function g_object_ref:Byte Ptr(handle:Byte Ptr)
-	Function g_object_connect:Byte Ptr(gtkWidget:Byte Ptr, signalSpec:Byte Ptr, callback(widget:Byte Ptr, pspec:Byte Ptr, gadget:Object), gadget:Object, flag:Int)="g_object_connect"
-	Function g_object_set_data(handle:Byte Ptr, key:Byte Ptr, data:Object)
-		
-	' gtkfilefilter
-	Function gtk_file_filter_new:Byte Ptr()
-	Function gtk_file_filter_set_name(handle:Byte Ptr, name:Byte Ptr)
-	Function gtk_file_filter_add_pattern(handle:Byte Ptr, pattern:Byte Ptr)
-	
-	' pango
-	Function pango_font_description_free(handle:Byte Ptr)
-	Function pango_font_description_new:Byte Ptr()
-	Function pango_font_description_set_family(handle:Byte Ptr, family:Byte Ptr)
-	Function pango_font_description_set_weight(handle:Byte Ptr, weight:Int)
-	Function pango_font_description_set_style(handle:Byte Ptr, style:Int)
-	Function pango_font_description_set_absolute_size(handle:Byte Ptr, size:Double)
-	Function pango_font_description_get_family:Byte Ptr(handle:Byte Ptr)
-	Function pango_font_description_get_style:Int(handle:Byte Ptr)
-	Function pango_font_description_get_weight:Int(handle:Byte Ptr)
-	Function pango_font_description_get_size:Int(handle:Byte Ptr)
-	Function pango_context_set_font_description(handle:Byte Ptr, desc:Byte Ptr)
-	Function pango_context_load_fontset:Byte Ptr(handle:Byte Ptr, desc:Byte Ptr, language:Byte Ptr)
-	Function pango_fontset_foreach(fontset:Byte Ptr, func:Int(_set:Byte Ptr, _font:Byte Ptr ,data:Object), data:Object)
-	Function pango_font_describe:Byte Ptr(font:Byte Ptr)
-	
-	' pango layout
-	Function pango_layout_new:Byte Ptr(context:Byte Ptr)
-	Function pango_layout_set_text(handle:Byte Ptr, Text:Byte Ptr, length:Int)
-	Function pango_layout_get_pixel_size(handle:Byte Ptr, width:Int Ptr, height:Int Ptr)
-	
-	' gdk pango
-	Function gdk_pango_context_get:Byte Ptr()
-	
-	' gtkwindow
-	Function gtk_window_new:Byte Ptr(_type:Int)
-	Function gtk_window_move(handle:Byte Ptr, x:Int, y:Int)
-	Function gtk_window_set_default_size(handle:Byte Ptr, width:Int, height:Int)
-	Function gtk_window_set_decorated(handle:Byte Ptr, setting:Int)
-	Function gtk_window_set_resizable(handle:Byte Ptr, resizable:Int)
-	Function gtk_window_set_type_hint(handle:Byte Ptr, hint:Int)
-?bmxng
-	Function gtk_window_set_geometry_hints(handle:Byte Ptr, widget:Byte Ptr, geometry:GdkGeometry Var, mask:Int)
-?Not bmxng
-	Function gtk_window_set_geometry_hints(handle:Byte Ptr, widget:Byte Ptr, geometry:Byte Ptr, mask:Int)
-?	
-	Function gtk_window_set_transient_for(handle:Byte Ptr, parent:Byte Ptr)
-	Function gtk_window_add_accel_group(handle:Byte Ptr, accelGroup:Byte Ptr)
-	Function gtk_window_get_position(handle:Byte Ptr, x:Int Ptr, y:Int Ptr)
-	Function gtk_window_resize(handle:Byte Ptr, width:Int, height:Int)
-	Function gtk_window_deiconify(handle:Byte Ptr)
-	Function gtk_window_unmaximize(handle:Byte Ptr)
-	Function gtk_window_present(handle:Byte Ptr)
-	Function gtk_window_set_icon(handle:Byte Ptr, icon:Byte Ptr)
-	Function gtk_window_set_title(handle:Byte Ptr, title:Byte Ptr)
-	Function gtk_window_get_title:Byte Ptr(handle:Byte Ptr)
-	Function gtk_window_maximize(handle:Byte Ptr)
-	Function gtk_window_iconify(handle:Byte Ptr)
-	Function gtk_window_get_focus:Byte Ptr(handle:Byte Ptr)
-	
-	' GtkBox
-	Function gtk_box_new:Byte Ptr(orientation:Int, spacing:Int)
-	Function gtk_box_pack_start(handle:Byte Ptr, child:Byte Ptr, expand:Int, fill:Int, padding:Int)
-	Function gtk_box_reorder_child(handle:Byte Ptr, child:Byte Ptr, position:Int)
-
-	' GtkMenuBar
-	Function gtk_menu_bar_new:Byte Ptr()
-	
-	' GtkLayout
-	Function gtk_layout_new:Byte Ptr(hadjustment:Byte Ptr, vadjustment:Byte Ptr)
-	Function gtk_layout_put(handle:Byte Ptr, child:Byte Ptr, x:Int, y:Int)
-	Function gtk_layout_move(handle:Byte Ptr, child:Byte Ptr, x:Int, y:Int)
-	Function gtk_layout_get_bin_window:Byte Ptr(handle:Byte Ptr)
-	
-	' GtkLabel
-	Function gtk_label_new:Byte Ptr(str:Byte Ptr)
-	Function gtk_label_set_xalign(handle:Byte Ptr, xalign:Float)
-	Function gtk_label_set_yalign(handle:Byte Ptr, yalign:Float)
-	Function gtk_label_set_text(handle:Byte Ptr, str:Byte Ptr)
-	Function gtk_label_get_text:Byte Ptr(handle:Byte Ptr)
-	Function gtk_label_set_text_with_mnemonic(handle:Byte Ptr, txt:Byte Ptr)
-	
-	' GtkContainer
-	Function gtk_container_add(handle:Byte Ptr, widget:Byte Ptr)
-	Function gtk_container_set_resize_mode(handle:Byte Ptr, _mode:Int)
-	Function gtk_container_remove(handle:Byte Ptr, widget:Byte Ptr)
-	
-	' signals
-	Function g_signal_cb2:Int(gtkwidget:Byte Ptr, name:Byte Ptr, callback(widget:Byte Ptr, gadget:Object), gadget:Object, destroyhandler(data:Byte Ptr, user: Byte Ptr), flag:Int) = "int g_signal_connect_data(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, int) !"
-	Function g_signal_cb2_ret:Int(gtkwidget:Byte Ptr, name:Byte Ptr, callback:Int(widget:Byte Ptr, gadget:Object), gadget:Object, destroyhandler(data:Byte Ptr, user: Byte Ptr), flag:Int) = "int g_signal_connect_data(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, int) !"
-	Function g_signal_cb3:Int(gtkwidget:Byte Ptr, name:Byte Ptr, callback(widget:Byte Ptr, event:Byte Ptr, gadget:Object), gadget:Object, destroyhandler(data:Byte Ptr, user: Byte Ptr), flag:Int) = "int g_signal_connect_data(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, int) !"
-	Function g_signal_cb3_ret:Int(gtkwidget:Byte Ptr, name:Byte Ptr, callback:Int(widget:Byte Ptr, event:Byte Ptr, gadget:Object), gadget:Object, destroyhandler(data:Byte Ptr, user: Byte Ptr), flag:Int) = "int g_signal_connect_data(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, int) !"
-	Function g_signal_cb3a_ret:Int(gtkwidget:Byte Ptr, name:Byte Ptr, callback:Int(widget:Byte Ptr, value:Int, gadget:Object), gadget:Object, destroyhandler(data:Byte Ptr, user: Byte Ptr), flag:Int) = "int g_signal_connect_data(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, int) !"
-	Function g_signal_cb4:Int(gtkwidget:Byte Ptr, name:Byte Ptr, callback(widget:Byte Ptr,url:Byte Ptr,stream:Byte Ptr,gadget:Object),gadget:Object,destroyhandler(data:Byte Ptr,user: Byte Ptr),flag:Int) = "int g_signal_connect_data(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, int) !"
-	Function g_signal_cb4a:Int(gtkwidget:Byte Ptr, name:Byte Ptr, callback:Int(widget:Byte Ptr,val1:Int,val2:Double,gadget:Object),gadget:Object,destroyhandler(data:Byte Ptr,user: Byte Ptr),flag:Int) = "int g_signal_connect_data(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, int) !"
-	Function g_signal_cb5:Int(gtkwidget:Byte Ptr, name:Byte Ptr, callback(widget:Byte Ptr,val1:Int,val2:Int,val3:Int,gadget:Object),gadget:Object,destroyhandler(data:Byte Ptr,user: Byte Ptr),flag:Int) = "int g_signal_connect_data(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, int) !"
-	Function g_signal_handler_disconnect(gtkwidget:Byte Ptr, handlerid:Long)
-	Function g_signal_tabchange:Int(gtkwidget:Byte Ptr, name:Byte Ptr, callback(widget:Byte Ptr,a:Byte Ptr, index:Int,gadget:Object),gadget:Object,destroyhandler(data:Byte Ptr,user: Byte Ptr),flag:Int) = "int g_signal_connect_data(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, int) !"
-	
-	' accelerator groups
-	Function gtk_accel_group_new:Byte Ptr()
-	Function gtk_accelerator_parse(accel:Byte Ptr, key:Int Ptr, mods:Int Ptr)
-	
-	' GtkMenu
-	Function gtk_menu_popup(handle:Byte Ptr, parentMenuShell:Byte Ptr, parentMenuItem:Byte Ptr, func:Byte Ptr, data:Byte Ptr, button:Int, activateTime:Int)
-	
-	' GtkMisc
-	Function gtk_misc_set_alignment(handle:Byte Ptr, xalign:Float, yalign:Float)
-	
-	' image data
-	Function gdk_pixbuf_new_from_data:Byte Ptr(data:Byte Ptr, colorspace:Int, has_alpha:Int, bits_per_sample:Int, width:Int, height:Int, ..
-                    rowstride:Int, destroy_fn:Byte Ptr, data_fn:Byte Ptr)
-	Function gdk_pixbuf_new_from_bytes:Byte Ptr(data:Byte Ptr, colorspace:Int, has_alpha:Int, bits_per_sample:Int, width:Int, height:Int, rowstride:Int)
-	Function gdk_pixbuf_get_type:Int()
-	Function gdk_pixbuf_copy_area(handle:Byte Ptr, sx:Int, sy:Int, width:Int, height:Int, dest:Byte Ptr, dx:Int, dy:Int)
-	Function gdk_pixbuf_scale_simple:Byte Ptr(src:Byte Ptr, dw:Int, dh:Int, inter:Int)
-	Function gdk_pixbuf_new:Byte Ptr(colorspace:Int, alpha:Int, bps:Int, width:Int, height:Int)
-	Function gdk_pixbuf_copy:Byte Ptr(handle:Byte Ptr)
-	
-	' GtkButton
-	Function gtk_button_set_label(handle:Byte Ptr, label:Byte Ptr)
-	Function gtk_button_set_use_underline(handle:Byte Ptr, useUnderline:Int)
-	Function gtk_button_get_label:Byte Ptr(handle:Byte Ptr)
-	Function gtk_button_new_with_label:Byte Ptr(label:Byte Ptr)
-	Function gtk_button_set_image(handle:Byte Ptr, image:Byte Ptr)
-	Function gtk_button_set_image_position(handle:Byte Ptr, pos:Int)
-	
-	' GtkBin
-	Function gtk_bin_get_child:Byte Ptr(handle:Byte Ptr)
-	
-	' GtkToggleButton
-	Function gtk_toggle_button_get_active:Int(handle:Byte Ptr)
-	Function gtk_toggle_button_set_active(handle:Byte Ptr, active:Int)
-	Function gtk_toggle_button_set_mode(handle:Byte Ptr, indicator:Int)
-	
-	' GtkRadioButton
-	Function gtk_radio_button_new_with_label:Byte Ptr(handle:Byte Ptr, label:Byte Ptr)
-	Function gtk_radio_button_get_group:Byte Ptr(handle:Byte Ptr)
-	
-	' GtkCheckButton
-	Function gtk_check_button_new_with_label:Byte Ptr(label:Byte Ptr)
-	
-	' GtkEventBox
-	Function gtk_event_box_new:Byte Ptr()
-	Function gtk_event_box_set_visible_window(handle:Byte Ptr, visibleWindow:Int)
-	
-	' GtkSeparator
-	Function gtk_separator_new:Byte Ptr(orientation:Int)
-	
-	' GtkFrame
-	Function gtk_frame_new:Byte Ptr(label:Byte Ptr)
-	Function gtk_frame_set_shadow_type(handle:Byte Ptr, shadowType:Int)
-	Function gtk_frame_set_label(handle:Byte Ptr, label:Byte Ptr)
-	
-	' key values
-	Function gdk_keyval_to_unicode:Int(keyval:Int)
-	
-	' GtkEntry
-	Function gtk_entry_new:Byte Ptr()
-	Function gtk_entry_set_visibility(handle:Byte Ptr, visible:Int)
-	Function gtk_entry_get_text:Byte Ptr(handle:Byte Ptr)
-	Function gtk_entry_set_text(handle:Byte Ptr, txt:Byte Ptr)
-	
-	' GtkEditable
-	Function gtk_editable_cut_clipboard(handle:Byte Ptr)
-	Function gtk_editable_copy_clipboard(handle:Byte Ptr)
-	Function gtk_editable_paste_clipboard(handle:Byte Ptr)
-	
-	' GtkListStore
-	Function gtk_list_store_set_value(handle:Byte Ptr, iter:Byte Ptr, column:Int, value:Byte Ptr)
-	Function gtk_list_store_new:Byte Ptr(COLS:Int, type1:Int, type2:Int)
-	Function gtk_list_store_insert(handle:Byte Ptr, iter:Byte Ptr, position:Int)
-	Function gtk_list_store_clear(handle:Byte Ptr)
-	Function gtk_list_store_remove:Int(handle:Byte Ptr, iter:Byte Ptr)
-	
-	' GtkTreeStore
-	Function gtk_tree_store_set_value(handle:Byte Ptr, iter:Byte Ptr, column:Int, value:Byte Ptr)
-	Function gtk_tree_store_append(handle:Byte Ptr, iter:Byte Ptr, parent:Byte Ptr)
-	Function gtk_tree_store_insert(handle:Byte Ptr, iter:Byte Ptr, parent:Byte Ptr, position:Int)
-	Function gtk_tree_store_remove:Int(handle:Byte Ptr, iter:Byte Ptr)
-	Function gtk_tree_store_new:Byte Ptr(columns:Int, _type1:Int, _type2:Int)
-	
-	' GtkTreeView
-	Function gtk_tree_view_append_column:Int(handle:Byte Ptr, column:Byte Ptr)
-	Function gtk_tree_view_new:Byte Ptr()
-	Function gtk_tree_view_set_headers_visible(handle:Byte Ptr, visible:Int)
-	Function gtk_tree_view_get_selection:Byte Ptr(handle:Byte Ptr)
-	Function gtk_tree_view_set_model(handle:Byte Ptr, model:Byte Ptr)
-	Function gtk_tree_view_get_path_at_pos:Int(handle:Byte Ptr, x:Int, y:Int, path:Byte Ptr Ptr, column:Byte Ptr Ptr, cellX:Int Ptr, celly:Int Ptr)
-	Function gtk_tree_view_expand_row:Int(handle:Byte Ptr, path:Byte Ptr, openAll:Int)
-	Function gtk_tree_view_collapse_row:Int(handle:Byte Ptr, path:Byte Ptr)
-	
-	' GtkTreeViewColumn
-	Function gtk_tree_view_column_new:Byte Ptr()
-	Function gtk_tree_view_column_pack_start(handle:Byte Ptr, cell:Byte Ptr, expand:Int)
-	Function gtk_tree_view_column_pack_end(handle:Byte Ptr, cell:Byte Ptr, expand:Int)
-	Function gtk_tree_view_column_add_attribute(handle:Byte Ptr, renderer:Byte Ptr, attr$z, column:Int)
-	
-	' GtkCellRendererPixbuf
-	Function gtk_cell_renderer_pixbuf_new:Byte Ptr()
-
-	' GtkCellRendererText
-	Function gtk_cell_renderer_text_new:Byte Ptr()
-	
-	' GtkCellLayout
-	Function gtk_cell_layout_clear(handle:Byte Ptr)
-	Function gtk_cell_layout_add_attribute(handle:Byte Ptr, cell:Byte Ptr, attr$z, column:Int)
-	Function gtk_cell_layout_pack_start(handle:Byte Ptr, cell:Byte Ptr, expand:Int)
-	Function gtk_cell_layout_pack_end(handle:Byte Ptr, cell:Byte Ptr, expand:Int)
-	
-	' GtkComboBox
-	Function gtk_combo_box_new_with_entry:Byte Ptr()
-	Function gtk_combo_box_new:Byte Ptr()
-	Function gtk_combo_box_set_model(handle:Byte Ptr, model:Byte Ptr)
-	Function gtk_combo_box_set_entry_text_column(handle:Byte Ptr, column:Int)
-	Function gtk_combo_box_get_active:Int(handle:Byte Ptr)
-	Function gtk_combo_box_set_active(handle:Byte Ptr, index:Int)
-	Function gtk_combo_box_get_active_iter:Int(handle:Byte Ptr, iter:Byte Ptr)
-	
-	' GtkTreeModel
-	Function gtk_tree_model_iter_nth_child:Int(handle:Byte Ptr, iter:Byte Ptr, parent:Byte Ptr, index:Int)
-	Function gtk_tree_model_get_value(handle:Byte Ptr, iter:Byte Ptr, column:Int, value:Byte Ptr)
-	Function gtk_tree_model_get_string_from_iter:Byte Ptr(handle:Byte Ptr, iter:Byte Ptr)
-	Function gtk_tree_path_to_string:Byte Ptr(handle:Byte Ptr)
-	Function gtk_tree_path_free(handle:Byte Ptr)
-	Function gtk_tree_path_new_from_string:Byte Ptr(path$z)
-	Function gtk_tree_model_get_iter_from_string:Int(handle:Byte Ptr, iter:Byte Ptr, path$z)
-	Function gtk_tree_model_get_path:Byte Ptr(handle:Byte Ptr, iter:Byte Ptr)
-	
-	' GtkScrolledWindow
-	Function gtk_scrolled_window_new:Byte Ptr(hadjustment:Byte Ptr, vadjustment:Byte Ptr)
-	Function gtk_scrolled_window_set_policy(handle:Byte Ptr, hpolicy:Int, vpolicy:Int)
-	
-	' GtkTreeSelection
-	Function gtk_tree_selection_set_mode(handle:Byte Ptr, _type:Int)
-	Function gtk_tree_selection_select_iter(handle:Byte Ptr, iter:Byte Ptr)
-	Function gtk_tree_selection_unselect_iter(handle:Byte Ptr, iter:Byte Ptr)
-	Function gtk_tree_selection_iter_is_selected:Int(handle:Byte Ptr, iter:Byte Ptr)
-	Function gtk_tree_selection_get_selected:Int(handle:Byte Ptr, model:Byte Ptr Ptr, iter:Byte Ptr)
-	Function gtk_tree_selection_select_path(handle:Byte Ptr, path:Byte Ptr)
-	
-	' GtkRange
-	Function gtk_range_set_range(handle:Byte Ptr, _min:Double, _max:Double)
-	Function gtk_range_set_value(handle:Byte Ptr, value:Double)
-	Function gtk_range_get_value:Double(handle:Byte Ptr)
-	Function gtk_range_set_round_digits(handle:Byte Ptr, roundDigits:Int)
-	Function gtk_range_set_increments(handle:Byte Ptr, _step:Double, _page:Double)
-	Function gtk_range_get_adjustment:Byte Ptr(handle:Byte Ptr)
-	
-	' GtkScale
-	Function gtk_scale_new_with_range:Byte Ptr(orientation:Int, _min:Double, _max:Double, _step:Double)
-	Function gtk_scale_set_draw_value(handle:Byte Ptr, value:Int)
-	
-	' GtkScrollbar
-	Function gtk_scrollbar_new:Byte Ptr(orientation:Int, adjustment:Byte Ptr)
-	
-	' GtkAdjustment
-	Function gtk_adjustment_set_page_size(handle:Byte Ptr, pageSize:Double)
-	
-	' GtkSpinButton
-	Function gtk_spin_button_new_with_range:Byte Ptr(_min:Double, _max:Double, _step:Double)
-	Function gtk_spin_button_set_range(handle:Byte Ptr, _min:Double, _max:Double)
-	Function gtk_spin_button_set_increments(handle:Byte Ptr, _step:Double, _page:Double)
-	Function gtk_spin_button_set_value(handle:Byte Ptr, value:Double)
-	Function gtk_spin_button_get_value:Double(handle:Byte Ptr)
-	
-	' GtkProgressBar
-	Function gtk_progress_bar_new:Byte Ptr()
-	Function gtk_progress_bar_set_fraction(handle:Byte Ptr, fraction:Double)
-	Function gtk_progress_bar_get_fraction:Double(handle:Byte Ptr)
-	
-	' GtkToolbar
-	Function gtk_toolbar_new:Byte Ptr()
-	Function gtk_toolbar_set_style(handle:Byte Ptr, style:Int)
-	Function gtk_toolbar_insert(handle:Byte Ptr, item:Byte Ptr, pos:Int)
-	Function gtk_toolbar_get_item_index:Int(handle:Byte Ptr, item:Byte Ptr)
-	
-	' GtkToolButton
-	Function gtk_tool_button_set_label(handle:Byte Ptr, label:Byte Ptr)
-	Function gtk_tool_button_set_icon_widget(handle:Byte Ptr, icon:Byte Ptr)
-	Function gtk_tool_button_new:Byte Ptr(icon:Byte Ptr, label:Byte Ptr)
-	Function gtk_tool_button_set_icon_name(handle:Byte Ptr, name$z)
-	
-	' GtkToggleToolButton
-	Function gtk_toggle_tool_button_new:Byte Ptr()
-	Function gtk_toggle_tool_button_get_active:Int(handle:Byte Ptr)
-	Function gtk_toggle_tool_button_set_active(handle:Byte Ptr, active:Int)
-	
-	' GtkImage
-	Function gtk_image_new_from_pixbuf:Byte Ptr(pixbuf:Byte Ptr)
-	Function gtk_image_new:Byte Ptr()
-	Function gtk_image_set_from_pixbuf(handle:Byte Ptr, pixbuf:Byte Ptr)
-	Function gtk_image_clear(handle:Byte Ptr)
-	
-	' GtkSeparatorToolItem
-	Function gtk_separator_tool_item_new:Byte Ptr()
-	
-	' GtkToolItem
-	Function gtk_tool_item_set_tooltip_text(handle:Byte Ptr, txt:Byte Ptr)
-	
-	' GtkNotebook
-	Function gtk_notebook_new:Byte Ptr()
-	Function gtk_notebook_set_scrollable(handle:Byte Ptr, scrollable:Int)
-	Function gtk_notebook_get_nth_page:Byte Ptr(handle:Byte Ptr, page:Int)
-	Function gtk_notebook_insert_page:Int(handle:Byte Ptr, child:Byte Ptr, label:Byte Ptr, pos:Int)
-	Function gtk_notebook_get_tab_label:Byte Ptr(handle:Byte Ptr, child:Byte Ptr)
-	Function gtk_notebook_get_current_page:Int(handle:Byte Ptr)
-	Function gtk_notebook_remove_page(handle:Byte Ptr, page:Int)
-	Function gtk_notebook_set_current_page(handle:Byte Ptr, page:Int)
-	
-	' GdkWindow
-	Function gdk_window_get_device_position:Byte Ptr(handle:Byte Ptr, device:Byte Ptr, x:Int Var, y:Int Var, mask:Int Var)
-	Function gdk_window_set_cursor(handle:Byte Ptr, cursor:Byte Ptr)
-	
-	' GdkCairo
-	Function gdk_cairo_create:Byte Ptr(handle:Byte Ptr)
-	Function gdk_cairo_set_source_pixbuf(handle:Byte Ptr, pixbuf:Byte Ptr, x:Double, y:Double)
-	
-	' Cairo
-	Function cairo_paint(handle:Byte Ptr)
-	Function cairo_fill(handle:Byte Ptr)
-	Function cairo_destroy(handle:Byte Ptr)
-	
-	' atoms
-	Function gdk_atom_intern:Byte Ptr(name:Byte Ptr, onlyIfExists:Int)
-	
-	' GtkClipboard
-	Function gtk_clipboard_get:Byte Ptr(selection:Byte Ptr)
-	Function gtk_clipboard_set_text(handle:Byte Ptr, txt:Byte Ptr, length:Int)
-	Function gtk_clipboard_wait_for_text:Byte Ptr(handle:Byte Ptr)
-	
-	' GtkTextBuffer
-	Function gtk_text_buffer_new:Byte Ptr(table:Byte Ptr)
-	Function gtk_text_buffer_get_tag_table:Byte Ptr(handle:Byte Ptr)
-	Function gtk_text_buffer_get_end_iter(handle:Byte Ptr, iter:Byte Ptr)
-	Function gtk_text_buffer_insert(handle:Byte Ptr, iter:Byte Ptr, txt:Byte Ptr, length:Int)
-	Function gtk_text_buffer_get_iter_at_line(handle:Byte Ptr, iter:Byte Ptr, line:Int)
-	Function gtk_text_buffer_get_iter_at_offset(handle:Byte Ptr, iter:Byte Ptr, offset:Int)
-	Function gtk_text_buffer_get_text:Byte Ptr(handle:Byte Ptr, _start:Byte Ptr, _end:Byte Ptr, includeHidden:Int)
-	Function gtk_text_buffer_get_line_count:Int(handle:Byte Ptr)
-	Function gtk_text_buffer_get_char_count:Int(handle:Byte Ptr)
-	Function gtk_text_buffer_get_selection_bounds:Int(handle:Byte Ptr, _start:Byte Ptr, _end:Byte Ptr)
-	Function gtk_text_buffer_set_text(handle:Byte Ptr, txt:Byte Ptr, length:Int)
-	Function gtk_text_buffer_place_cursor(handle:Byte Ptr, where_:Byte Ptr)
-	Function gtk_text_buffer_select_range(handle:Byte Ptr, ins:Byte Ptr, bound:Byte Ptr)
-	Function gtk_text_buffer_cut_clipboard(handle:Byte Ptr, clipboard:Byte Ptr, editable:Int)
-	Function gtk_text_buffer_copy_clipboard(handle:Byte Ptr, clipboard:Byte Ptr)
-	Function gtk_text_buffer_paste_clipboard(handle:Byte Ptr, clipboard:Byte Ptr, overide:Byte Ptr, editable:Int)
-	Function gtk_text_buffer_delete(handle:Byte Ptr, _start:Byte Ptr, _end:Byte Ptr)
-	Function gtk_text_buffer_get_insert:Byte Ptr(handle:Byte Ptr)
-	Function gtk_text_buffer_remove_all_tags(handle:Byte Ptr, _start:Byte Ptr, _end:Byte Ptr)
-	Function gtk_text_buffer_apply_tag(handle:Byte Ptr, tag:Byte Ptr, _start:Byte Ptr, _end:Byte Ptr)
-	
-	' GtkTextView
-	Function gtk_text_view_new_with_buffer:Byte Ptr(handle:Byte Ptr)
-	Function gtk_text_view_set_wrap_mode(handle:Byte Ptr, wrapMode:Int)
-	Function gtk_text_view_set_editable(handle:Byte Ptr, setting:Int)
-	Function gtk_text_view_scroll_to_iter(handle:Byte Ptr, iter:Byte Ptr, withinMargin:Double, useAlign:Int, xAlign:Double, yAlign:Double)
-	Function gtk_text_view_scroll_mark_onscreen(handle:Byte Ptr, mark:Byte Ptr)
-	Function gtk_text_view_get_tabs:Byte Ptr(handle:Byte Ptr)
-	Function gtk_text_view_set_tabs(handle:Byte Ptr, tabs:Byte Ptr)
-		
-	' GtkTextIter
-	Function gtk_text_iter_get_line:Int(handle:Byte Ptr)
-	Function gtk_text_iter_get_offset:Int(handle:Byte Ptr)
-	
-	' GtkTextTagTable
-	Function gtk_text_tag_table_lookup:Byte Ptr(handle:Byte Ptr, txt$z)
-	
-	' pango tab array
-	Function pango_tab_array_free(handle:Byte Ptr)
-	Function pango_tab_array_new_with_positions:Byte Ptr(size:Int, pixels:Int, align:Int, pos:Int)
-	
-	' GtkSeparatorMenuItem
-	Function gtk_separator_menu_item_new:Byte Ptr()
-	
-	' GtkMenuItem
-	Function gtk_menu_item_new_with_mnemonic:Byte Ptr(label:Byte Ptr)
-	Function gtk_menu_item_new_with_label:Byte Ptr(label:Byte Ptr)
-	Function gtk_menu_item_set_submenu(handle:Byte Ptr, submenu:Byte Ptr)
-	
-	' GtkMenu
-	Function gtk_menu_new:Byte Ptr()
-	
-	' GtkMenuShell
-	Function gtk_menu_shell_append(handle:Byte Ptr, child:Byte Ptr)
-	Function gtk_menu_shell_insert(handle:Byte Ptr, child:Byte Ptr, pos:Int)
-	
-	' settings
-	Function gtk_settings_set_string_property(settings:Byte Ptr, name:Byte Ptr, v_string:Byte Ptr, origin:Byte Ptr)
-	Function gtk_settings_get_default:Byte Ptr()
-	
-	' GtkCheckMenuItem
-	Function gtk_check_menu_item_get_active:Int(handle:Byte Ptr)
-	Function gtk_check_menu_item_new_with_mnemonic:Byte Ptr(label:Byte Ptr)
-	Function gtk_check_menu_item_new_with_label:Byte Ptr(label:Byte Ptr)
-	Function gtk_check_menu_item_set_active(handle:Byte Ptr, active:Int)
-
-	' GtkDrawingArea
-	Function gtk_drawing_area_new:Byte Ptr()
-
-	' GtkIconTheme
-	Function gtk_icon_theme_add_builtin_icon(name$z, size:Int, pixbuf:Byte Ptr)
-
-	' GtkColorSelection
-	Function gtk_color_selection_dialog_new:Byte Ptr(title:Byte Ptr)
-	Function gtk_color_selection_dialog_get_color_selection:Byte Ptr(handle:Byte Ptr)
-?bmxng
-	Function gtk_color_selection_set_current_rgba(handle:Byte Ptr, rgba:GdkRGBA Var)
-	Function gtk_color_selection_get_current_rgba(handle:Byte Ptr, rgba:GdkRGBA Var)
-?Not bmxng
-	Function gtk_color_selection_set_current_rgba(handle:Byte Ptr, rgba:Byte Ptr)
-	Function gtk_color_selection_get_current_rgba(handle:Byte Ptr, rgba:Byte Ptr)
-?
-	
-	' GtkFontChooserDialog
-	Function gtk_font_chooser_dialog_new:Byte Ptr(title:Byte Ptr, parent:Byte Ptr)
-	Function gtk_font_chooser_set_font_desc(handle:Byte Ptr, desc:Byte Ptr)
-	Function gtk_font_chooser_get_font_desc:Byte Ptr(handle:Byte Ptr)
-	
-	' GdkMonitor
-	'Function gdk_display_get_primary_monitor:Byte Ptr(display:Byte Ptr)
-	
-	' glue
-	Function bmx_gtk3_gtkdesktop_gethertz:Int()
-	Function bmx_gtk3_gvalue_new:Byte Ptr(_type:Int)
-	Function bmx_gtk3_gvalue_free(_value:Byte Ptr)
-	Function bmx_gtk3_gtktreeiter_new:Byte Ptr()
-	Function bmx_gtk3_gtktreeiter_free(handle:Byte Ptr)
-	Function bmx_gtk3_stylecontext_get_fontdesc:Byte Ptr(handle:Byte Ptr)
-	Function bmx_gtk3_gtktextiter_new:Byte Ptr()
-	Function bmx_gtk3_gtktextiter_free(iter:Byte Ptr)
-?bmxng
-	Function bmx_gtk3_set_text_tag_style:Byte Ptr(handle:Byte Ptr, tag$z, _fg:GdkRGBA Var, _style:Int, _weight:Int, _under:Int, _strike:Int)
-	Function bmx_gtk3_set_text_bg_tag:Byte Ptr(handle:Byte Ptr, tag$z, _bg:GdkRGBA Var)
-?Not bmxng
-	Function bmx_gtk3_set_text_tag_style:Byte Ptr(handle:Byte Ptr, tag$z, _fg:Byte Ptr, _style:Int, _weight:Int, _under:Int, _strike:Int)
-	Function bmx_gtk3_set_text_bg_tag:Byte Ptr(handle:Byte Ptr, tag$z, _bg:Byte Ptr)
-?
-	' event types
-	Function bmx_gtk3maxgui_gdkeventbutton(event:Byte Ptr, x:Double Ptr, y:Double Ptr, button:Int Ptr)
-	Function bmx_gtk3maxgui_gdkeventmotion(event:Byte Ptr, x:Double Ptr, y:Double Ptr, state:Int Ptr)
-	Function bmx_gtk3maxgui_gdkeventscroll(event:Byte Ptr, x:Double Ptr, y:Double Ptr, direction:Int Ptr)
-	Function bmx_gtk3maxgui_gdkeventkey(event:Byte Ptr, keyval:Int Ptr, state:Int Ptr)
-	Function bmx_gtk3maxgui_gdkeventconfigure(event:Byte Ptr, x:Int Ptr, y:Int Ptr, w:Int Ptr, h:Int Ptr)
-	Function bmx_gtk3maxgui_gdkeventwindowstate(event:Byte Ptr, state:Int Ptr)
-	Function bmx_gtk3maxgui_gdkeventmotiondevice:Byte Ptr(event:Byte Ptr)
-
-End Extern
-
-' gadget identifiers
-Const GTK_WINDOW:Int = 0
-Const GTK_BUTTON:Int = 1
-Const GTK_RADIOBUTTON:Int = 2
-Const GTK_CHECKBUTTON:Int = 3
-Const GTK_TOGGLEBUTTON:Int = 4
-Const GTK_LABEL:Int = 5
-Const GTK_MENUITEM:Int = 6
-Const GTK_TEXTFIELD:Int = 7
-Const GTK_TEXTAREA:Int = 8
-Const GTK_PANEL:Int = 9
-Const GTK_COMBOBOX:Int = 10
-Const GTK_HTMLVIEW:Int = 11
-Const GTK_TABBER:Int = 12
-Const GTK_PROGRESSBAR:Int = 13
-Const GTK_SCROLLBAR:Int = 14
-Const GTK_TRACKBAR:Int = 15
-Const GTK_STEPPER:Int = 16
-Const GTK_DESKTOP:Int = 17
-Const GTK_TOOLBAR:Int = 18
-Const GTK_LISTBOX:Int = 19
-Const GTK_TREEVIEW:Int = 20
-Const GTK_CANVAS:Int = 21
-
-
-' GtkDialogFlags
-Const GTK_DIALOG_MODAL:Int = 0
-Const GTK_DIALOG_DESTROY_WITH_PARENT:Int = 1
-
-' GtkButtonsType
-Const GTK_BUTTONS_NONE:Int = 0
-Const GTK_BUTTONS_OK:Int = 1
-Const GTK_BUTTONS_CLOSE:Int = 2
-Const GTK_BUTTONS_CANCEL:Int = 3
-Const GTK_BUTTONS_YES_NO:Int = 4
-Const GTK_BUTTONS_OK_CANCEL:Int = 5
-
-' GtkMessageType
-Const GTK_MESSAGE_INFO:Int = 0
-Const GTK_MESSAGE_WARNING:Int = 1
-Const GTK_MESSAGE_QUESTION:Int = 2
-Const GTK_MESSAGE_ERROR:Int = 3
-Const GTK_MESSAGE_OTHER:Int = 4
-
-' GtkResponseType
-Const GTK_RESPONSE_NONE:Int = -1
-Const GTK_RESPONSE_REJECT:Int = -2
-Const GTK_RESPONSE_ACCEPT:Int = -3
-Const GTK_RESPONSE_DELETE_EVENT:Int = -4
-Const GTK_RESPONSE_OK:Int     = -5
-Const GTK_RESPONSE_CANCEL:Int = -6
-Const GTK_RESPONSE_CLOSE:Int  = -7
-Const GTK_RESPONSE_YES:Int    = -8
-Const GTK_RESPONSE_NO:Int     = -9
-Const GTK_RESPONSE_APPLY:Int  = -10
-Const GTK_RESPONSE_HELP:Int   = -11
-
-' GtkFileChooserAction
-Const GTK_FILE_CHOOSER_ACTION_OPEN:Int = 0
-Const GTK_FILE_CHOOSER_ACTION_SAVE:Int = 1
-Const GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:Int = 2
-Const GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER:Int = 3
-
-' PangoStyle
-Const PANGO_STYLE_NORMAL:Int = 0
-Const PANGO_STYLE_OBLIQUE:Int = 1
-Const PANGO_STYLE_ITALIC:Int = 2
-
-' PangoWeight
-Const PANGO_WEIGHT_ULTRALIGHT:Int = 200
-Const PANGO_WEIGHT_LIGHT:Int = 300
-Const PANGO_WEIGHT_NORMAL:Int = 400
-Const PANGO_WEIGHT_SEMIBOLD:Int = 600
-Const PANGO_WEIGHT_BOLD:Int = 700
-Const PANGO_WEIGHT_ULTRABOLD:Int = 800
-Const PANGO_WEIGHT_HEAVY:Int = 900
-
-' PangoUnderline
-Const PANGO_UNDERLINE_NONE:Int = 0
-Const PANGO_UNDERLINE_SINGLE:Int = 1
-Const PANGO_UNDERLINE_DOUBLE:Int = 2
-Const PANGO_UNDERLINE_LOW:Int = 3
-Const PANGO_UNDERLINE_ERROR:Int = 4
-
-' GtkOrientation
-Const GTK_ORIENTATION_HORIZONTAL:Int = 0
-Const GTK_ORIENTATION_VERTICAL:Int = 1
-
-' gtkwindowtype
-Const GTK_WINDOW_TOPLEVEL:Int = 0
-Const GTK_WINDOW_POPUP:Int = 1
-
-' gtkwindowposition
-Const GTK_WIN_POS_NONE:Int = 0
-Const GTK_WIN_POS_CENTER:Int = 1
-Const GTK_WIN_POS_MOUSE:Int = 2
-Const GTK_WIN_POS_CENTER_ALWAYS:Int = 3
-Const GTK_WIN_POS_CENTER_ON_PARENT:Int = 4
-
-' GdkWindowTypeHint
-Const GDK_WINDOW_TYPE_HINT_NORMAL:Int       = 0
-Const GDK_WINDOW_TYPE_HINT_DIALOG:Int       = 1
-Const GDK_WINDOW_TYPE_HINT_MENU:Int         = 2
-Const GDK_WINDOW_TYPE_HINT_TOOLBAR:Int      = 3
-Const GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:Int = 4
-Const GDK_WINDOW_TYPE_HINT_UTILITY:Int      = 5
-Const GDK_WINDOW_TYPE_HINT_DOCK:Int         = 6
-Const GDK_WINDOW_TYPE_HINT_DESKTOP:Int      = 7
-Const GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU:Int= 8  ' A drop down menu (from a menubar)
-Const GDK_WINDOW_TYPE_HINT_POPUP_MENU:Int   = 9  ' A popup menu (from Right-click)
-Const GDK_WINDOW_TYPE_HINT_TOOLTIP:Int      = 10
-Const GDK_WINDOW_TYPE_HINT_NOTIFICATION:Int = 11
-Const GDK_WINDOW_TYPE_HINT_COMBO:Int        = 12
-Const GDK_WINDOW_TYPE_HINT_DND:Int          = 13
-
-' GdkWindowHints
-Const GDK_HINT_POS:Int	     = 1
-Const GDK_HINT_MIN_SIZE:Int    = 2
-Const GDK_HINT_MAX_SIZE:Int    = 4
-Const GDK_HINT_BASE_SIZE:Int   = 8
-Const GDK_HINT_ASPECT:Int      = 16
-Const GDK_HINT_RESIZE_INC:Int  = 32
-Const GDK_HINT_WIN_GRAVITY:Int = 64
-Const GDK_HINT_USER_POS:Int    = 128
-Const GDK_HINT_USER_SIZE:Int   = 256
-
-' GdkWindowState
-Const GDK_WINDOW_STATE_WITHDRAWN:Int  = 1 Shl 0
-Const GDK_WINDOW_STATE_ICONIFIED:Int  = 1 Shl 1
-Const GDK_WINDOW_STATE_MAXIMIZED:Int  = 1 Shl 2
-Const GDK_WINDOW_STATE_STICKY:Int     = 1 Shl 3
-Const GDK_WINDOW_STATE_FULLSCREEN:Int = 1 Shl 4
-Const GDK_WINDOW_STATE_ABOVE:Int      = 1 Shl 5
-Const GDK_WINDOW_STATE_BELOW:Int      = 1 Shl 6
-Const GDK_WINDOW_STATE_FOCUSED:Int    = 1 Shl 7
-Const GDK_WINDOW_STATE_TILED:Int      = 1 Shl 8
-
-' GdkColorspace
-Const GDK_COLORSPACE_RGB:Int = 0
-
-' GtkStateType
-Const GTK_STATE_FLAG_NORMAL:Int = 0
-Const GTK_STATE_FLAG_ACTIVE:Int = 1
-Const GTK_STATE_FLAG_PRELIGHT:Int = 2
-Const GTK_STATE_FLAG_SELECTED:Int = 3
-Const GTK_STATE_FLAG_INSENSITIVE:Int = 4
-Const GTK_STATE_FLAG_INCONSISTENT:Int = 5
-Const GTK_STATE_FLAG_FOCUSED:Int = 6
-Const GTK_STATE_FLAG_BACKDROP:Int = 7
-Const GTK_STATE_FLAG_DIR_LTR:Int = 8
-Const GTK_STATE_FLAG_DIR_RTL:Int = 9
-
-' GtkAccelFlags
-Const GTK_ACCEL_VISIBLE:Int = 1 ' display in GtkAccelLabel?
-Const GTK_ACCEL_LOCKED:Int  = 2 ' is it removable?
-Const GTK_ACCEL_MASK:Int    = 7
-
-Const GDK_EXPOSURE_MASK:Int = 1 Shl 1
-Const GDK_POINTER_MOTION_MASK:Int = 1 Shl 2
-Const GDK_POINTER_MOTION_HINT_MASK:Int = 1 Shl 3
-Const GDK_BUTTON_MOTION_MASK:Int = 1 Shl 4
-Const GDK_BUTTON1_MOTION_MASK:Int = 1 Shl 5
-Const GDK_BUTTON2_MOTION_MASK:Int = 1 Shl 6
-Const GDK_BUTTON3_MOTION_MASK:Int = 1 Shl 7
-Const GDK_BUTTON_PRESS_MASK:Int = 1 Shl 8
-Const GDK_BUTTON_RELEASE_MASK:Int = 1 Shl 9
-Const GDK_KEY_PRESS_MASK:Int = 1 Shl 10
-Const GDK_KEY_RELEASE_MASK:Int = 1 Shl 11
-Const GDK_ENTER_NOTIFY_MASK:Int = 1 Shl 12
-Const GDK_LEAVE_NOTIFY_MASK:Int = 1 Shl 13
-Const GDK_FOCUS_CHANGE_MASK:Int = 1 Shl 14
-Const GDK_STRUCTURE_MASK:Int = 1 Shl 15
-Const GDK_PROPERTY_CHANGE_MASK:Int = 1 Shl 16
-Const GDK_VISIBILITY_NOTIFY_MASK:Int = 1 Shl 17
-Const GDK_PROXIMITY_IN_MASK:Int = 1 Shl 18
-Const GDK_PROXIMITY_OUT_MASK:Int = 1 Shl 19
-Const GDK_SUBSTRUCTURE_MASK:Int = 1 Shl 20
-Const GDK_SCROLL_MASK:Int = 1 Shl 21
-Const GDK_TOUCH_MASK:Int = 1 Shl 22
-Const GDK_SMOOTH_SCROLL_MASK:Int = 1 Shl 23
-
-' GtkShadowType
-Const GTK_SHADOW_NONE:Int = 0
-Const GTK_SHADOW_IN:Int = 1
-Const GTK_SHADOW_OUT:Int = 2
-Const GTK_SHADOW_ETCHED_IN:Int = 3
-Const GTK_SHADOW_ETCHED_OUT:Int = 4
-
-' GType
-Const G_TYPE_STRING:Int = 16 Shl 2
-Const G_TYPE_POINTER:Int = 17 Shl 2
-
-' GtkPolicyType
-Const GTK_POLICY_ALWAYS:Int = 0
-Const GTK_POLICY_AUTOMATIC:Int = 1
-Const GTK_POLICY_NEVER:Int = 2
-
-' GtkSelectionMode
-Const GTK_SELECTION_NONE:Int = 0                       ' Nothing can be selected
-Const GTK_SELECTION_SINGLE:Int = 1
-Const GTK_SELECTION_BROWSE:Int = 2
-Const GTK_SELECTION_MULTIPLE:Int = 3
-
-' GtkResizeMode
-Const GTK_RESIZE_PARENT:Int = 0
-Const GTK_RESIZE_QUEUE:Int = 1
-Const GTK_RESIZE_IMMEDIATE:Int = 2
-
-' GtkToolbarStyle
-Const GTK_TOOLBAR_ICONS:Int = 0
-Const GTK_TOOLBAR_TEXT:Int = 1
-Const GTK_TOOLBAR_BOTH:Int = 2
-Const GTK_TOOLBAR_BOTH_HORIZ:Int = 3
-
-' GdkScrollDirection
-Const GDK_SCROLL_UP:Int = 0
-Const GDK_SCROLL_DOWN:Int = 1
-Const GDK_SCROLL_LEFT:Int = 2
-Const GDK_SCROLL_RIGHT:Int = 3
-Const GDK_SCROLL_SMOOTH:Int = 4
-
-' GdkInterpType
-Const GDK_INTERP_NEAREST:Int = 0
-Const GDK_INTERP_TILES:Int = 1
-Const GDK_INTERP_BILINEAR:Int = 2
-Const GDK_INTERP_HYPER:Int = 3
-
-' GtkPositionType
-Const GTK_POS_LEFT:Int = 0
-Const GTK_POS_RIGHT:Int = 1
-Const GTK_POS_TOP:Int = 2
-Const GTK_POS_BOTTOM:Int = 3
-
-' GtkWrapMode
-Const GTK_WRAP_NONE:Int = 0
-Const GTK_WRAP_CHAR:Int = 1
-Const GTK_WRAP_WORD:Int = 2
-Const GTK_WRAP_WORD_CHAR:Int = 3
-
-' PangoTabAlign
-Const PANGO_TAB_LEFT:Int = 0
-Const PANGO_TAB_RIGHT:Int = 1
-Const PANGO_TAB_CENTER:Int = 2
-Const PANGO_TAB_NUMERIC:Int = 3
-
-' GdkCursorType
-Const GDK_X_CURSOR:Int = 0
-Const GDK_ARROW:Int = 2
-Const GDK_BASED_ARROW_DOWN:Int = 4
-Const GDK_BASED_ARROW_UP:Int = 6
-Const GDK_BOAT:Int = 8
-Const GDK_BOGOSITY:Int = 10
-Const GDK_BOTTOM_LEFT_CORNER:Int = 12
-Const GDK_BOTTOM_RIGHT_CORNER:Int = 14
-Const GDK_BOTTOM_SIDE:Int = 16
-Const GDK_BOTTOM_TEE:Int = 18
-Const GDK_BOX_SPIRAL:Int = 20
-Const GDK_CENTER_PTR:Int = 22
-Const GDK_CIRCLE:Int = 24
-Const GDK_CLOCK:Int = 26
-Const GDK_COFFEE_MUG:Int = 28
-Const GDK_CROSS:Int = 30
-Const GDK_CROSS_REVERSE:Int = 32
-Const GDK_CROSSHAIR:Int = 34
-Const GDK_DIAMOND_CROSS:Int = 36
-Const GDK_DOT:Int = 38
-Const GDK_DOTBOX:Int = 40
-Const GDK_DOUBLE_ARROW:Int = 42
-Const GDK_DRAFT_LARGE:Int = 44
-Const GDK_DRAFT_SMALL:Int = 46
-Const GDK_DRAPED_BOX:Int = 48
-Const GDK_EXCHANGE:Int = 50
-Const GDK_FLEUR:Int = 52
-Const GDK_GOBBLER:Int = 54
-Const GDK_GUMBY:Int = 56
-Const GDK_HAND1:Int = 58
-Const GDK_HAND2:Int = 60
-Const GDK_HEART:Int = 62
-Const GDK_ICON:Int = 64
-Const GDK_IRON_CROSS:Int = 66
-Const GDK_LEFT_PTR:Int = 68
-Const GDK_LEFT_SIDE:Int = 70
-Const GDK_LEFT_TEE:Int = 72
-Const GDK_LEFTBUTTON:Int = 74
-Const GDK_LL_ANGLE:Int = 76
-Const GDK_LR_ANGLE:Int = 78
-Const GDK_MAN:Int = 80
-Const GDK_MIDDLEBUTTON:Int = 82
-Const GDK_MOUSE:Int = 84
-Const GDK_PENCIL:Int = 86
-Const GDK_PIRATE:Int = 88
-Const GDK_PLUS:Int = 90
-Const GDK_QUESTION_ARROW:Int = 92
-Const GDK_RIGHT_PTR:Int = 94
-Const GDK_RIGHT_SIDE:Int = 96
-Const GDK_RIGHT_TEE:Int = 98
-Const GDK_RIGHTBUTTON:Int = 100
-Const GDK_RTL_LOGO:Int = 102
-Const GDK_SAILBOAT:Int = 104
-Const GDK_SB_DOWN_ARROW:Int = 106
-Const GDK_SB_H_DOUBLE_ARROW:Int = 108
-Const GDK_SB_LEFT_ARROW:Int = 110
-Const GDK_SB_RIGHT_ARROW:Int = 112
-Const GDK_SB_UP_ARROW:Int = 114
-Const GDK_SB_V_DOUBLE_ARROW:Int = 116
-Const GDK_SHUTTLE:Int = 118
-Const GDK_SIZING:Int = 120
-Const GDK_SPIDER:Int = 122
-Const GDK_SPRAYCAN:Int = 124
-Const GDK_STAR:Int = 126
-Const GDK_TARGET:Int = 128
-Const GDK_TCROSS:Int = 130
-Const GDK_TOP_LEFT_ARROW:Int = 132
-Const GDK_TOP_LEFT_CORNER:Int = 134
-Const GDK_TOP_RIGHT_CORNER:Int = 136
-Const GDK_TOP_SIDE:Int = 138
-Const GDK_TOP_TEE:Int = 140
-Const GDK_TREK:Int = 142
-Const GDK_UL_ANGLE:Int = 144
-Const GDK_UMBRELLA:Int = 146
-Const GDK_UR_ANGLE:Int = 148
-Const GDK_WATCH:Int = 150
-Const GDK_XTERM:Int = 152
-Const GDK_BLANK_CURSOR:Int = -2
-Const GDK_CURSOR_IS_PIXMAP:Int = -1
-
-' List of application windows
-' We use it for SetPointer etc.
-Global gtkWindows:TList = New TList
-
-' I know... cup of cocoa anyone?
-Global GadgetMap:TMap=New TMap
-
-' creates an Object out of an "int"
-Type TGTKInteger
-	Field value:Int
-	Function Set:TGTKInteger(value:Int)
-		Local this:TGTKInteger = New TGTKInteger
-		this.value = value
-		Return this
-	End Function
-	Method Compare:Int(o:Object)
-		Return value-TGTKInteger(o).value
-	End Method
-End Type
-
-' creates an Object out of an "Byte Ptr"
-Type TGTKBytePtr
-	Field value:Byte Ptr
-	Function Set:TGTKBytePtr(value:Byte Ptr)
-		Local this:TGTKBytePtr = New TGTKBytePtr
-		this.value = value
-		Return this
-	End Function
-	Method Compare:Int(o:Object)
-		Return value-TGTKBytePtr(o).value
-	End Method
-
-End Type
-
-
-Type TGTKGuiFont Extends TGuiFont
-
-	Field fontDesc:Byte Ptr
-
-	Field context:Byte Ptr
-	Field layout:Byte Ptr
-
-	Method Delete()
-		If fontDesc Then
-			pango_font_description_free(fontDesc)
-			fontDesc = Null
-		EndIf
-
-		If layout Then
-			g_object_unref(layout)
-			layout = Null
-		End If
-
-		If context Then
-			g_object_unref(context)
-			context = Null
-		End If
-	EndMethod
-	
-	Method CharWidth:Int(char:Int)
-		If Not fontDesc Then
-			getPangoDescriptionFromGuiFont(Self)
-		EndIf
-
-		If fontDesc Then
-			If Not context Then
-				context = gdk_pango_context_get()
-				pango_context_set_font_description(context, fontDesc)
-
-				layout = pango_layout_new(context)
-			End If
-
-			Local s:Byte Ptr = Chr(char).ToUTF8String()
-			pango_layout_set_text(layout, s, 1)
-			MemFree(s)
-
-			Local w:Int
-			pango_layout_get_pixel_size(layout, Varptr w, Null)
-
-			Return w
-		End If
-
-		Return 0
-	EndMethod 
-		
-EndType
-
-Rem
-internal: Returns a Pango font description based on a TGuiFont specification. (INTERNAL)
-End Rem
-Function getPangoDescriptionFromGuiFont(font:TGtkGuiFont)
-	If font = Null Then
-		Return
-	End If
-	
-	If Not font.fontDesc Then
-
-		Local fontdesc:Byte Ptr = pango_font_description_new()
-		Local s:Byte Ptr = font.name.toUTF8String()
-			
-		pango_font_description_set_family(fontdesc, s)
-	
-		If font.style & FONT_BOLD Then
-			pango_font_description_set_weight(fontdesc, PANGO_WEIGHT_BOLD)
-		Else
-			pango_font_description_set_weight(fontdesc, PANGO_WEIGHT_NORMAL)
-		End If
-	
-		If font.style & FONT_ITALIC Then
-			pango_font_description_set_style(fontdesc, PANGO_STYLE_ITALIC)
-		End If
-	
-		pango_font_description_set_absolute_size(fontdesc, font.size * 1024)
-	
-		MemFree(s)
-		
-		font.fontDesc = fontDesc
-		
-	End If
-
-End Function
-
-Rem
-internal: Returns a TGuiFont from a pango description object. (INTERNAL)
-End Rem
-Function getGuiFontFromPangoDescription:TGuiFont(fontdesc:Byte Ptr)
-	Local font:TGtkGuiFont = New TGTKGuiFont
-
-	font.name = String.FromUTF8String(pango_font_description_get_family(fontdesc))
-	'font.path = ...
-	Local ital:Int = pango_font_description_get_style(fontdesc)
-	Local bold:Int = pango_font_description_get_weight(fontdesc)
-
-	If ital = PANGO_STYLE_OBLIQUE Or ital = PANGO_STYLE_ITALIC Then
-		font.style:| FONT_ITALIC
-	End If
-
-	If bold > PANGO_WEIGHT_NORMAL Then
-		font.style:| FONT_BOLD
-	End If
-
-	font.size = pango_font_description_get_size(fontdesc) / 1024
-
-	font.fontDesc = fontdesc
-	
-	Return font
-End Function
-
-?bmxng
-Struct GdkGeometry
-?Not bmxng
-Type GdkGeometry
-?
-	Field minWidth:Int
-	Field minHeight:Int
-	Field maxWidth:Int
-	Field maxHeight:Int
-	Field baseWidth:Int
-	Field baseHeight:Int
-	Field widthInc:Int
-	Field heightInc:Int
-	Field minAspect:Double
-	Field maxAspect:Double
-	Field winGravity:Int
-?bmxng
-End Struct
-?Not bmxng
-End Type
-?
-
-?bmxng
-Struct GtkRequisition
-	Field width:Int
-	Field height:Int
-End Struct
-?Not bmxng
-Type GtkRequisition
-	Field width:Int
-	Field height:Int
-End Type
-?
-
-?bmxng
-Struct GdkRectangle
-	Field x:Int
-	Field y:Int
-	Field width:Int
-	Field height:Int
-End Struct
-?Not bmxng
-Type GdkRectangle
-	Field x:Int
-	Field y:Int
-	Field width:Int
-	Field height:Int
-End Type
-?
-
-?bmxng
-Struct GtkAllocation
-	Field x:Int
-	Field y:Int
-	Field width:Int
-	Field height:Int
-End Struct
-?Not bmxng
-Type GtkAllocation
-	Field x:Int
-	Field y:Int
-	Field width:Int
-	Field height:Int
-End Type
-?
-
-?bmxng
-Struct GdkRGBA
-	Field red:Double
-	Field green:Double
-	Field blue:Double
-	Field alpha:Double
-	
-	Method New(red:Double, green:Double, blue:Double, alpha:Double = 1.0)
-		Self.red = red
-		Self.green = green
-		Self.blue = blue
-		Self.alpha = alpha
-	End Method
-	
-End Struct
-?Not bmxng
-Type GdkRGBA
-	Field red:Double
-	Field green:Double
-	Field blue:Double
-	Field alpha:Double
-
-	Method Create:GdkRGBA(red:Double, green:Double, blue:Double, alpha:Double = 1.0)
-		Self.red = red
-		Self.green = green
-		Self.blue = blue
-		Self.alpha = alpha
-		Return Self
-	End Method
-End Type
-?
-
-Global _gtkKeysDown:Int[] = New Int[255]
-
-' returns True if key is already believed to be DOWN/Pressed
-Function gtk3SetKeyDown:Int(key:Int)
-	Assert key < 255, "gtkSetKeyDown key is out of range - " + key
-	
-	If _gtkKeysDown[key] Then
-		Return True
-	End If
-	
-	_gtkKeysDown[key] = 1
-	Return False
-End Function
-
-Function gtk3SetKeyUp(key:Int)
-	Assert key < 255, "gtkSetKeyUp key is out of range - " + key
-	
-	_gtkKeysDown[key] = 0
-End Function
+' Copyright (c) 2006-2018 Bruce A Henderson
+' 
+' Permission is hereby granted, free of charge, to any person obtaining a copy
+' of this software and associated documentation files (the "Software"), to deal
+' in the Software without restriction, including without limitation the rights
+' to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+' copies of the Software, and to permit persons to whom the Software is
+' furnished to do so, subject to the following conditions:
+' 
+' The above copyright notice and this permission notice shall be included in
+' all copies or substantial portions of the Software.
+' 
+' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+' THE SOFTWARE.
+' 
+SuperStrict
+
+
+?bmxng
+Import BRL.SystemDefault
+?Not bmxng
+Import BRL.System
+?
+Import MaxGUI.MaxGUI
+Import BRL.LinkedList
+Import BRL.Map
+
+?linux
+'Import "-L/usr/lib/x86_64-linux-gnu/"
+Import "-lgtk-3"
+Import "-lgdk-3"
+Import "-latk-1.0"
+Import "-lgio-2.0"
+Import "-lpangocairo-1.0"
+Import "-lgdk_pixbuf-2.0"
+Import "-lcairo-gobject"
+Import "-lpango-1.0"
+Import "-lcairo"
+Import "-lgobject-2.0"
+Import "-lglib-2.0"
+?
+
+Import "gtkkeymap.bmx"
+Import "elist.bmx"
+
+Extern
+
+	' main loop and events
+	Function gtk_init(argc:Int Ptr, argv:Byte Ptr Ptr Ptr)
+	Function gtk_main_iteration_do:Int(blocking:Int)
+	Function gtk_events_pending:Int()
+	Function gtk_get_current_event_time:Int()
+
+	' gdkscreen
+	Function gdk_screen_get_default:Byte Ptr()
+	Function gdk_screen_get_width:Int(handle:Byte Ptr)
+	Function gdk_screen_get_height:Int(handle:Byte Ptr)
+	Function gdk_screen_get_system_visual:Byte Ptr(handle:Byte Ptr)
+	Function gdk_screen_get_display:Byte Ptr(screen:Byte Ptr)
+	Function gdk_screen_get_n_monitors:Int(screen:Byte Ptr)
+	Function gdk_screen_get_monitor_scale_factor:Int(screen:Byte Ptr, monitor:Int)
+	
+	' visuals
+	Function gdk_visual_get_depth:Int(handle:Byte Ptr)
+	
+	' gdkdisplay
+	Function gdk_display_get_default:Byte Ptr()
+
+	' gdkcursor
+	Function gdk_cursor_new_for_display:Byte Ptr(display:Byte Ptr, cursorType:Int)
+
+	' gtkmessagedialog
+	Function gtk_message_dialog_new:Byte Ptr(parent:Byte Ptr, flags:Int, _type:Int, buttons:Int, message:Byte Ptr)
+
+	' gtkdialog
+	Function gtk_dialog_run:Int(handle:Byte Ptr)
+	Function gtk_dialog_add_button:Byte Ptr(handle:Byte Ptr, buttonText$z, responseId:Int)
+	
+	' gtkwidget
+	Function gtk_widget_destroy(handle:Byte Ptr)
+	Function gtk_widget_show(handle:Byte Ptr)
+	Function gtk_widget_hide(handle:Byte Ptr)
+?bmxng
+	Function gtk_widget_get_preferred_size(handle:Byte Ptr, minSize:GtkRequisition Var, natSize:GtkRequisition Var)
+	Function gtk_widget_get_allocation(handle:Byte Ptr, allocation:GtkAllocation Var)
+	Function gtk_widget_override_color(handle:Byte Ptr, state:Int, color:GdkRGBA Var)
+	Function gtk_widget_size_allocate(handle:Byte Ptr, allocation:GtkAllocation Var)
+	Function gtk_widget_override_background_color(handle:Byte Ptr, state:Int, color:GdkRGBA Var)
+?Not bmxng
+	Function gtk_widget_get_preferred_size(handle:Byte Ptr, minSize:Byte Ptr, natSize:Byte Ptr)
+	Function gtk_widget_get_allocation(handle:Byte Ptr, allocation:Byte Ptr)
+	Function gtk_widget_override_color(handle:Byte Ptr, state:Int, color:Byte Ptr)
+	Function gtk_widget_size_allocate(handle:Byte Ptr, allocation:Byte Ptr)
+	Function gtk_widget_override_background_color(handle:Byte Ptr, state:Int, color:Byte Ptr)
+?
+	Function gtk_widget_grab_default(handle:Byte Ptr)
+	Function gtk_widget_set_size_request(handle:Byte Ptr, width:Int, height:Int)
+	Function gtk_widget_remove_accelerator:Int(handle:Byte Ptr, group:Byte Ptr, key:Int, mods:Int)
+	Function gtk_widget_add_accelerator(handle:Byte Ptr, signal:Byte Ptr, group:Byte Ptr, key:Int, mods:Int, flags:Int)
+	Function gtk_widget_add_events(handle:Byte Ptr, events:Int)
+	Function gtk_widget_set_tooltip_text(handle:Byte Ptr, tooltip:Byte Ptr)
+	Function gtk_widget_set_has_tooltip(handle:Byte Ptr, value:Int)
+	Function gtk_widget_grab_focus(handle:Byte Ptr)
+	Function gtk_widget_queue_draw(handle:Byte Ptr)
+	Function gtk_widget_get_state_flags:Int(handle:Byte Ptr)
+	Function gtk_widget_get_visible:Int(handle:Byte Ptr)
+	Function gtk_widget_set_sensitive(handle:Byte Ptr, sensitive:Int)
+	Function gtk_widget_is_sensitive:Int(handle:Byte Ptr)
+	Function gtk_widget_get_parent_window:Byte Ptr(handle:Byte Ptr)
+	Function gtk_widget_get_pango_context:Byte Ptr(handle:Byte Ptr)
+	Function gtk_widget_get_style_context:Byte Ptr(handle:Byte Ptr)
+	Function gtk_widget_get_window:Byte Ptr(handle:Byte Ptr)
+	Function gtk_widget_has_focus:Int(handle:Byte Ptr)
+	
+	' gtkfilechooserdialog
+	Function gtk_file_chooser_dialog_new:Byte Ptr(title:Byte Ptr, parent:Byte Ptr, action:Int, but1$z, opt1:Int, but2$z, opt2:Int, opt3:Byte Ptr)
+	
+	' gtkfilechooser
+	Function gtk_file_chooser_set_current_folder:Int(handle:Byte Ptr, filename:Byte Ptr)
+	Function gtk_file_chooser_set_filename:Int(handle:Byte Ptr, filename:Byte Ptr)
+	Function gtk_file_chooser_get_filename:Byte Ptr(handle:Byte Ptr)
+	Function gtk_file_chooser_add_filter(handle:Byte Ptr, filter:Byte Ptr)
+
+	' glib
+	Function g_free(mem:Byte Ptr)
+	
+	' gobject
+	Function g_object_unref(handle:Byte Ptr)
+	Function g_object_set_int(handle:Byte Ptr, property:Byte Ptr, value:Int, _null:Byte Ptr=Null) = "void g_object_set(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*) !"
+	Function g_object_set_double(handle:Byte Ptr, property:Byte Ptr, value:Double, _null:Byte Ptr=Null) = "void g_object_set(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*) !"
+	Function g_value_set_string(handle:Byte Ptr, str:Byte Ptr)
+	Function g_value_unset(handle:Byte Ptr)
+	Function g_value_init:Byte Ptr(handle:Byte Ptr, _type:Size_T)
+	Function g_value_set_object(handle:Byte Ptr, obj:Byte Ptr)
+	Function g_value_get_string:Byte Ptr(handle:Byte Ptr)
+	Function g_object_ref:Byte Ptr(handle:Byte Ptr)
+	Function g_object_connect:Byte Ptr(gtkWidget:Byte Ptr, signalSpec:Byte Ptr, callback(widget:Byte Ptr, pspec:Byte Ptr, gadget:Object), gadget:Object, flag:Int)="g_object_connect"
+	Function g_object_set_data(handle:Byte Ptr, key:Byte Ptr, data:Object)
+		
+	' gtkfilefilter
+	Function gtk_file_filter_new:Byte Ptr()
+	Function gtk_file_filter_set_name(handle:Byte Ptr, name:Byte Ptr)
+	Function gtk_file_filter_add_pattern(handle:Byte Ptr, pattern:Byte Ptr)
+	
+	' pango
+	Function pango_font_description_free(handle:Byte Ptr)
+	Function pango_font_description_new:Byte Ptr()
+	Function pango_font_description_set_family(handle:Byte Ptr, family:Byte Ptr)
+	Function pango_font_description_set_weight(handle:Byte Ptr, weight:Int)
+	Function pango_font_description_set_style(handle:Byte Ptr, style:Int)
+	Function pango_font_description_set_absolute_size(handle:Byte Ptr, size:Double)
+	Function pango_font_description_get_family:Byte Ptr(handle:Byte Ptr)
+	Function pango_font_description_get_style:Int(handle:Byte Ptr)
+	Function pango_font_description_get_weight:Int(handle:Byte Ptr)
+	Function pango_font_description_get_size:Int(handle:Byte Ptr)
+	Function pango_context_set_font_description(handle:Byte Ptr, desc:Byte Ptr)
+	Function pango_context_load_fontset:Byte Ptr(handle:Byte Ptr, desc:Byte Ptr, language:Byte Ptr)
+	Function pango_fontset_foreach(fontset:Byte Ptr, func:Int(_set:Byte Ptr, _font:Byte Ptr ,data:Object), data:Object)
+	Function pango_font_describe:Byte Ptr(font:Byte Ptr)
+	
+	' pango layout
+	Function pango_layout_new:Byte Ptr(context:Byte Ptr)
+	Function pango_layout_set_text(handle:Byte Ptr, Text:Byte Ptr, length:Int)
+	Function pango_layout_get_pixel_size(handle:Byte Ptr, width:Int Ptr, height:Int Ptr)
+	
+	' gdk pango
+	Function gdk_pango_context_get:Byte Ptr()
+	
+	' gtkwindow
+	Function gtk_window_new:Byte Ptr(_type:Int)
+	Function gtk_window_move(handle:Byte Ptr, x:Int, y:Int)
+	Function gtk_window_set_default_size(handle:Byte Ptr, width:Int, height:Int)
+	Function gtk_window_set_decorated(handle:Byte Ptr, setting:Int)
+	Function gtk_window_set_resizable(handle:Byte Ptr, resizable:Int)
+	Function gtk_window_set_type_hint(handle:Byte Ptr, hint:Int)
+?bmxng
+	Function gtk_window_set_geometry_hints(handle:Byte Ptr, widget:Byte Ptr, geometry:GdkGeometry Var, mask:Int)
+?Not bmxng
+	Function gtk_window_set_geometry_hints(handle:Byte Ptr, widget:Byte Ptr, geometry:Byte Ptr, mask:Int)
+?	
+	Function gtk_window_set_transient_for(handle:Byte Ptr, parent:Byte Ptr)
+	Function gtk_window_add_accel_group(handle:Byte Ptr, accelGroup:Byte Ptr)
+	Function gtk_window_get_position(handle:Byte Ptr, x:Int Ptr, y:Int Ptr)
+	Function gtk_window_resize(handle:Byte Ptr, width:Int, height:Int)
+	Function gtk_window_deiconify(handle:Byte Ptr)
+	Function gtk_window_unmaximize(handle:Byte Ptr)
+	Function gtk_window_present(handle:Byte Ptr)
+	Function gtk_window_set_icon(handle:Byte Ptr, icon:Byte Ptr)
+	Function gtk_window_set_title(handle:Byte Ptr, title:Byte Ptr)
+	Function gtk_window_get_title:Byte Ptr(handle:Byte Ptr)
+	Function gtk_window_maximize(handle:Byte Ptr)
+	Function gtk_window_iconify(handle:Byte Ptr)
+	Function gtk_window_get_focus:Byte Ptr(handle:Byte Ptr)
+	
+	' GtkBox
+	Function gtk_box_new:Byte Ptr(orientation:Int, spacing:Int)
+	Function gtk_box_pack_start(handle:Byte Ptr, child:Byte Ptr, expand:Int, fill:Int, padding:Int)
+	Function gtk_box_reorder_child(handle:Byte Ptr, child:Byte Ptr, position:Int)
+
+	' GtkMenuBar
+	Function gtk_menu_bar_new:Byte Ptr()
+	
+	' GtkLayout
+	Function gtk_layout_new:Byte Ptr(hadjustment:Byte Ptr, vadjustment:Byte Ptr)
+	Function gtk_layout_put(handle:Byte Ptr, child:Byte Ptr, x:Int, y:Int)
+	Function gtk_layout_move(handle:Byte Ptr, child:Byte Ptr, x:Int, y:Int)
+	Function gtk_layout_get_bin_window:Byte Ptr(handle:Byte Ptr)
+	
+	' GtkLabel
+	Function gtk_label_new:Byte Ptr(str:Byte Ptr)
+	Function gtk_label_set_xalign(handle:Byte Ptr, xalign:Float)
+	Function gtk_label_set_yalign(handle:Byte Ptr, yalign:Float)
+	Function gtk_label_set_text(handle:Byte Ptr, str:Byte Ptr)
+	Function gtk_label_get_text:Byte Ptr(handle:Byte Ptr)
+	Function gtk_label_set_text_with_mnemonic(handle:Byte Ptr, txt:Byte Ptr)
+	
+	' GtkContainer
+	Function gtk_container_add(handle:Byte Ptr, widget:Byte Ptr)
+	Function gtk_container_set_resize_mode(handle:Byte Ptr, _mode:Int)
+	Function gtk_container_remove(handle:Byte Ptr, widget:Byte Ptr)
+	
+	' signals
+	Function g_signal_cb2:Int(gtkwidget:Byte Ptr, name:Byte Ptr, callback(widget:Byte Ptr, gadget:Object), gadget:Object, destroyhandler(data:Byte Ptr, user: Byte Ptr), flag:Int) = "int g_signal_connect_data(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, int) !"
+	Function g_signal_cb2_ret:Int(gtkwidget:Byte Ptr, name:Byte Ptr, callback:Int(widget:Byte Ptr, gadget:Object), gadget:Object, destroyhandler(data:Byte Ptr, user: Byte Ptr), flag:Int) = "int g_signal_connect_data(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, int) !"
+	Function g_signal_cb3:Int(gtkwidget:Byte Ptr, name:Byte Ptr, callback(widget:Byte Ptr, event:Byte Ptr, gadget:Object), gadget:Object, destroyhandler(data:Byte Ptr, user: Byte Ptr), flag:Int) = "int g_signal_connect_data(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, int) !"
+	Function g_signal_cb3_ret:Int(gtkwidget:Byte Ptr, name:Byte Ptr, callback:Int(widget:Byte Ptr, event:Byte Ptr, gadget:Object), gadget:Object, destroyhandler(data:Byte Ptr, user: Byte Ptr), flag:Int) = "int g_signal_connect_data(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, int) !"
+	Function g_signal_cb3a_ret:Int(gtkwidget:Byte Ptr, name:Byte Ptr, callback:Int(widget:Byte Ptr, value:Int, gadget:Object), gadget:Object, destroyhandler(data:Byte Ptr, user: Byte Ptr), flag:Int) = "int g_signal_connect_data(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, int) !"
+	Function g_signal_cb4:Int(gtkwidget:Byte Ptr, name:Byte Ptr, callback(widget:Byte Ptr,url:Byte Ptr,stream:Byte Ptr,gadget:Object),gadget:Object,destroyhandler(data:Byte Ptr,user: Byte Ptr),flag:Int) = "int g_signal_connect_data(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, int) !"
+	Function g_signal_cb4a:Int(gtkwidget:Byte Ptr, name:Byte Ptr, callback:Int(widget:Byte Ptr,val1:Int,val2:Double,gadget:Object),gadget:Object,destroyhandler(data:Byte Ptr,user: Byte Ptr),flag:Int) = "int g_signal_connect_data(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, int) !"
+	Function g_signal_cb5:Int(gtkwidget:Byte Ptr, name:Byte Ptr, callback(widget:Byte Ptr,val1:Int,val2:Int,val3:Int,gadget:Object),gadget:Object,destroyhandler(data:Byte Ptr,user: Byte Ptr),flag:Int) = "int g_signal_connect_data(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, int) !"
+	Function g_signal_handler_disconnect(gtkwidget:Byte Ptr, handlerid:Long)
+	Function g_signal_tabchange:Int(gtkwidget:Byte Ptr, name:Byte Ptr, callback(widget:Byte Ptr,a:Byte Ptr, index:Int,gadget:Object),gadget:Object,destroyhandler(data:Byte Ptr,user: Byte Ptr),flag:Int) = "int g_signal_connect_data(BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, BBBYTE*, int) !"
+	
+	' accelerator groups
+	Function gtk_accel_group_new:Byte Ptr()
+	Function gtk_accelerator_parse(accel:Byte Ptr, key:Int Ptr, mods:Int Ptr)
+	
+	' GtkMenu
+	Function gtk_menu_popup(handle:Byte Ptr, parentMenuShell:Byte Ptr, parentMenuItem:Byte Ptr, func:Byte Ptr, data:Byte Ptr, button:Int, activateTime:Int)
+	
+	' GtkMisc
+	Function gtk_misc_set_alignment(handle:Byte Ptr, xalign:Float, yalign:Float)
+	
+	' image data
+	Function gdk_pixbuf_new_from_data:Byte Ptr(data:Byte Ptr, colorspace:Int, has_alpha:Int, bits_per_sample:Int, width:Int, height:Int, ..
+                    rowstride:Int, destroy_fn:Byte Ptr, data_fn:Byte Ptr)
+	Function gdk_pixbuf_new_from_bytes:Byte Ptr(data:Byte Ptr, colorspace:Int, has_alpha:Int, bits_per_sample:Int, width:Int, height:Int, rowstride:Int)
+	Function gdk_pixbuf_get_type:Size_T()
+	Function gdk_pixbuf_copy_area(handle:Byte Ptr, sx:Int, sy:Int, width:Int, height:Int, dest:Byte Ptr, dx:Int, dy:Int)
+	Function gdk_pixbuf_scale_simple:Byte Ptr(src:Byte Ptr, dw:Int, dh:Int, inter:Int)
+	Function gdk_pixbuf_new:Byte Ptr(colorspace:Int, alpha:Int, bps:Int, width:Int, height:Int)
+	Function gdk_pixbuf_copy:Byte Ptr(handle:Byte Ptr)
+	
+	' GtkButton
+	Function gtk_button_set_label(handle:Byte Ptr, label:Byte Ptr)
+	Function gtk_button_set_use_underline(handle:Byte Ptr, useUnderline:Int)
+	Function gtk_button_get_label:Byte Ptr(handle:Byte Ptr)
+	Function gtk_button_new_with_label:Byte Ptr(label:Byte Ptr)
+	Function gtk_button_set_image(handle:Byte Ptr, image:Byte Ptr)
+	Function gtk_button_set_image_position(handle:Byte Ptr, pos:Int)
+	
+	' GtkBin
+	Function gtk_bin_get_child:Byte Ptr(handle:Byte Ptr)
+	
+	' GtkToggleButton
+	Function gtk_toggle_button_get_active:Int(handle:Byte Ptr)
+	Function gtk_toggle_button_set_active(handle:Byte Ptr, active:Int)
+	Function gtk_toggle_button_set_mode(handle:Byte Ptr, indicator:Int)
+	
+	' GtkRadioButton
+	Function gtk_radio_button_new_with_label:Byte Ptr(handle:Byte Ptr, label:Byte Ptr)
+	Function gtk_radio_button_get_group:Byte Ptr(handle:Byte Ptr)
+	
+	' GtkCheckButton
+	Function gtk_check_button_new_with_label:Byte Ptr(label:Byte Ptr)
+	
+	' GtkEventBox
+	Function gtk_event_box_new:Byte Ptr()
+	Function gtk_event_box_set_visible_window(handle:Byte Ptr, visibleWindow:Int)
+	
+	' GtkSeparator
+	Function gtk_separator_new:Byte Ptr(orientation:Int)
+	
+	' GtkFrame
+	Function gtk_frame_new:Byte Ptr(label:Byte Ptr)
+	Function gtk_frame_set_shadow_type(handle:Byte Ptr, shadowType:Int)
+	Function gtk_frame_set_label(handle:Byte Ptr, label:Byte Ptr)
+	
+	' key values
+	Function gdk_keyval_to_unicode:Int(keyval:Int)
+	
+	' GtkEntry
+	Function gtk_entry_new:Byte Ptr()
+	Function gtk_entry_set_visibility(handle:Byte Ptr, visible:Int)
+	Function gtk_entry_get_text:Byte Ptr(handle:Byte Ptr)
+	Function gtk_entry_set_text(handle:Byte Ptr, txt:Byte Ptr)
+	
+	' GtkEditable
+	Function gtk_editable_cut_clipboard(handle:Byte Ptr)
+	Function gtk_editable_copy_clipboard(handle:Byte Ptr)
+	Function gtk_editable_paste_clipboard(handle:Byte Ptr)
+	
+	' GtkListStore
+	Function gtk_list_store_set_value(handle:Byte Ptr, iter:Byte Ptr, column:Int, value:Byte Ptr)
+	Function gtk_list_store_new:Byte Ptr(COLS:Int, type1:Size_T, type2:Size_T)
+	Function gtk_list_store_insert(handle:Byte Ptr, iter:Byte Ptr, position:Int)
+	Function gtk_list_store_clear(handle:Byte Ptr)
+	Function gtk_list_store_remove:Int(handle:Byte Ptr, iter:Byte Ptr)
+	
+	' GtkTreeStore
+	Function gtk_tree_store_set_value(handle:Byte Ptr, iter:Byte Ptr, column:Int, value:Byte Ptr)
+	Function gtk_tree_store_append(handle:Byte Ptr, iter:Byte Ptr, parent:Byte Ptr)
+	Function gtk_tree_store_insert(handle:Byte Ptr, iter:Byte Ptr, parent:Byte Ptr, position:Int)
+	Function gtk_tree_store_remove:Int(handle:Byte Ptr, iter:Byte Ptr)
+	Function gtk_tree_store_new:Byte Ptr(columns:Int, _type1:Size_T, _type2:Size_T)
+	
+	' GtkTreeView
+	Function gtk_tree_view_append_column:Int(handle:Byte Ptr, column:Byte Ptr)
+	Function gtk_tree_view_new:Byte Ptr()
+	Function gtk_tree_view_set_headers_visible(handle:Byte Ptr, visible:Int)
+	Function gtk_tree_view_get_selection:Byte Ptr(handle:Byte Ptr)
+	Function gtk_tree_view_set_model(handle:Byte Ptr, model:Byte Ptr)
+	Function gtk_tree_view_get_path_at_pos:Int(handle:Byte Ptr, x:Int, y:Int, path:Byte Ptr Ptr, column:Byte Ptr Ptr, cellX:Int Ptr, celly:Int Ptr)
+	Function gtk_tree_view_expand_row:Int(handle:Byte Ptr, path:Byte Ptr, openAll:Int)
+	Function gtk_tree_view_collapse_row:Int(handle:Byte Ptr, path:Byte Ptr)
+	
+	' GtkTreeViewColumn
+	Function gtk_tree_view_column_new:Byte Ptr()
+	Function gtk_tree_view_column_pack_start(handle:Byte Ptr, cell:Byte Ptr, expand:Int)
+	Function gtk_tree_view_column_pack_end(handle:Byte Ptr, cell:Byte Ptr, expand:Int)
+	Function gtk_tree_view_column_add_attribute(handle:Byte Ptr, renderer:Byte Ptr, attr$z, column:Int)
+	
+	' GtkCellRendererPixbuf
+	Function gtk_cell_renderer_pixbuf_new:Byte Ptr()
+
+	' GtkCellRendererText
+	Function gtk_cell_renderer_text_new:Byte Ptr()
+	
+	' GtkCellLayout
+	Function gtk_cell_layout_clear(handle:Byte Ptr)
+	Function gtk_cell_layout_add_attribute(handle:Byte Ptr, cell:Byte Ptr, attr$z, column:Int)
+	Function gtk_cell_layout_pack_start(handle:Byte Ptr, cell:Byte Ptr, expand:Int)
+	Function gtk_cell_layout_pack_end(handle:Byte Ptr, cell:Byte Ptr, expand:Int)
+	
+	' GtkComboBox
+	Function gtk_combo_box_new_with_entry:Byte Ptr()
+	Function gtk_combo_box_new:Byte Ptr()
+	Function gtk_combo_box_set_model(handle:Byte Ptr, model:Byte Ptr)
+	Function gtk_combo_box_set_entry_text_column(handle:Byte Ptr, column:Int)
+	Function gtk_combo_box_get_active:Int(handle:Byte Ptr)
+	Function gtk_combo_box_set_active(handle:Byte Ptr, index:Int)
+	Function gtk_combo_box_get_active_iter:Int(handle:Byte Ptr, iter:Byte Ptr)
+	
+	' GtkTreeModel
+	Function gtk_tree_model_iter_nth_child:Int(handle:Byte Ptr, iter:Byte Ptr, parent:Byte Ptr, index:Int)
+	Function gtk_tree_model_get_value(handle:Byte Ptr, iter:Byte Ptr, column:Int, value:Byte Ptr)
+	Function gtk_tree_model_get_string_from_iter:Byte Ptr(handle:Byte Ptr, iter:Byte Ptr)
+	Function gtk_tree_path_to_string:Byte Ptr(handle:Byte Ptr)
+	Function gtk_tree_path_free(handle:Byte Ptr)
+	Function gtk_tree_path_new_from_string:Byte Ptr(path$z)
+	Function gtk_tree_model_get_iter_from_string:Int(handle:Byte Ptr, iter:Byte Ptr, path$z)
+	Function gtk_tree_model_get_path:Byte Ptr(handle:Byte Ptr, iter:Byte Ptr)
+	
+	' GtkScrolledWindow
+	Function gtk_scrolled_window_new:Byte Ptr(hadjustment:Byte Ptr, vadjustment:Byte Ptr)
+	Function gtk_scrolled_window_set_policy(handle:Byte Ptr, hpolicy:Int, vpolicy:Int)
+	
+	' GtkTreeSelection
+	Function gtk_tree_selection_set_mode(handle:Byte Ptr, _type:Int)
+	Function gtk_tree_selection_select_iter(handle:Byte Ptr, iter:Byte Ptr)
+	Function gtk_tree_selection_unselect_iter(handle:Byte Ptr, iter:Byte Ptr)
+	Function gtk_tree_selection_iter_is_selected:Int(handle:Byte Ptr, iter:Byte Ptr)
+	Function gtk_tree_selection_get_selected:Int(handle:Byte Ptr, model:Byte Ptr Ptr, iter:Byte Ptr)
+	Function gtk_tree_selection_select_path(handle:Byte Ptr, path:Byte Ptr)
+	
+	' GtkRange
+	Function gtk_range_set_range(handle:Byte Ptr, _min:Double, _max:Double)
+	Function gtk_range_set_value(handle:Byte Ptr, value:Double)
+	Function gtk_range_get_value:Double(handle:Byte Ptr)
+	Function gtk_range_set_round_digits(handle:Byte Ptr, roundDigits:Int)
+	Function gtk_range_set_increments(handle:Byte Ptr, _step:Double, _page:Double)
+	Function gtk_range_get_adjustment:Byte Ptr(handle:Byte Ptr)
+	
+	' GtkScale
+	Function gtk_scale_new_with_range:Byte Ptr(orientation:Int, _min:Double, _max:Double, _step:Double)
+	Function gtk_scale_set_draw_value(handle:Byte Ptr, value:Int)
+	
+	' GtkScrollbar
+	Function gtk_scrollbar_new:Byte Ptr(orientation:Int, adjustment:Byte Ptr)
+	
+	' GtkAdjustment
+	Function gtk_adjustment_set_page_size(handle:Byte Ptr, pageSize:Double)
+	
+	' GtkSpinButton
+	Function gtk_spin_button_new_with_range:Byte Ptr(_min:Double, _max:Double, _step:Double)
+	Function gtk_spin_button_set_range(handle:Byte Ptr, _min:Double, _max:Double)
+	Function gtk_spin_button_set_increments(handle:Byte Ptr, _step:Double, _page:Double)
+	Function gtk_spin_button_set_value(handle:Byte Ptr, value:Double)
+	Function gtk_spin_button_get_value:Double(handle:Byte Ptr)
+	
+	' GtkProgressBar
+	Function gtk_progress_bar_new:Byte Ptr()
+	Function gtk_progress_bar_set_fraction(handle:Byte Ptr, fraction:Double)
+	Function gtk_progress_bar_get_fraction:Double(handle:Byte Ptr)
+	
+	' GtkToolbar
+	Function gtk_toolbar_new:Byte Ptr()
+	Function gtk_toolbar_set_style(handle:Byte Ptr, style:Int)
+	Function gtk_toolbar_insert(handle:Byte Ptr, item:Byte Ptr, pos:Int)
+	Function gtk_toolbar_get_item_index:Int(handle:Byte Ptr, item:Byte Ptr)
+	
+	' GtkToolButton
+	Function gtk_tool_button_set_label(handle:Byte Ptr, label:Byte Ptr)
+	Function gtk_tool_button_set_icon_widget(handle:Byte Ptr, icon:Byte Ptr)
+	Function gtk_tool_button_new:Byte Ptr(icon:Byte Ptr, label:Byte Ptr)
+	Function gtk_tool_button_set_icon_name(handle:Byte Ptr, name$z)
+	
+	' GtkToggleToolButton
+	Function gtk_toggle_tool_button_new:Byte Ptr()
+	Function gtk_toggle_tool_button_get_active:Int(handle:Byte Ptr)
+	Function gtk_toggle_tool_button_set_active(handle:Byte Ptr, active:Int)
+	
+	' GtkImage
+	Function gtk_image_new_from_pixbuf:Byte Ptr(pixbuf:Byte Ptr)
+	Function gtk_image_new:Byte Ptr()
+	Function gtk_image_set_from_pixbuf(handle:Byte Ptr, pixbuf:Byte Ptr)
+	Function gtk_image_clear(handle:Byte Ptr)
+	
+	' GtkSeparatorToolItem
+	Function gtk_separator_tool_item_new:Byte Ptr()
+	
+	' GtkToolItem
+	Function gtk_tool_item_set_tooltip_text(handle:Byte Ptr, txt:Byte Ptr)
+	
+	' GtkNotebook
+	Function gtk_notebook_new:Byte Ptr()
+	Function gtk_notebook_set_scrollable(handle:Byte Ptr, scrollable:Int)
+	Function gtk_notebook_get_nth_page:Byte Ptr(handle:Byte Ptr, page:Int)
+	Function gtk_notebook_insert_page:Int(handle:Byte Ptr, child:Byte Ptr, label:Byte Ptr, pos:Int)
+	Function gtk_notebook_get_tab_label:Byte Ptr(handle:Byte Ptr, child:Byte Ptr)
+	Function gtk_notebook_get_current_page:Int(handle:Byte Ptr)
+	Function gtk_notebook_remove_page(handle:Byte Ptr, page:Int)
+	Function gtk_notebook_set_current_page(handle:Byte Ptr, page:Int)
+	
+	' GdkWindow
+	Function gdk_window_get_device_position:Byte Ptr(handle:Byte Ptr, device:Byte Ptr, x:Int Var, y:Int Var, mask:Int Var)
+	Function gdk_window_set_cursor(handle:Byte Ptr, cursor:Byte Ptr)
+	
+	' GdkCairo
+	Function gdk_cairo_create:Byte Ptr(handle:Byte Ptr)
+	Function gdk_cairo_set_source_pixbuf(handle:Byte Ptr, pixbuf:Byte Ptr, x:Double, y:Double)
+	
+	' Cairo
+	Function cairo_paint(handle:Byte Ptr)
+	Function cairo_fill(handle:Byte Ptr)
+	Function cairo_destroy(handle:Byte Ptr)
+	
+	' atoms
+	Function gdk_atom_intern:Byte Ptr(name:Byte Ptr, onlyIfExists:Int)
+	
+	' GtkClipboard
+	Function gtk_clipboard_get:Byte Ptr(selection:Byte Ptr)
+	Function gtk_clipboard_set_text(handle:Byte Ptr, txt:Byte Ptr, length:Int)
+	Function gtk_clipboard_wait_for_text:Byte Ptr(handle:Byte Ptr)
+	
+	' GtkTextBuffer
+	Function gtk_text_buffer_new:Byte Ptr(table:Byte Ptr)
+	Function gtk_text_buffer_get_tag_table:Byte Ptr(handle:Byte Ptr)
+	Function gtk_text_buffer_get_end_iter(handle:Byte Ptr, iter:Byte Ptr)
+	Function gtk_text_buffer_insert(handle:Byte Ptr, iter:Byte Ptr, txt:Byte Ptr, length:Int)
+	Function gtk_text_buffer_get_iter_at_line(handle:Byte Ptr, iter:Byte Ptr, line:Int)
+	Function gtk_text_buffer_get_iter_at_offset(handle:Byte Ptr, iter:Byte Ptr, offset:Int)
+	Function gtk_text_buffer_get_text:Byte Ptr(handle:Byte Ptr, _start:Byte Ptr, _end:Byte Ptr, includeHidden:Int)
+	Function gtk_text_buffer_get_line_count:Int(handle:Byte Ptr)
+	Function gtk_text_buffer_get_char_count:Int(handle:Byte Ptr)
+	Function gtk_text_buffer_get_selection_bounds:Int(handle:Byte Ptr, _start:Byte Ptr, _end:Byte Ptr)
+	Function gtk_text_buffer_set_text(handle:Byte Ptr, txt:Byte Ptr, length:Int)
+	Function gtk_text_buffer_place_cursor(handle:Byte Ptr, where_:Byte Ptr)
+	Function gtk_text_buffer_select_range(handle:Byte Ptr, ins:Byte Ptr, bound:Byte Ptr)
+	Function gtk_text_buffer_cut_clipboard(handle:Byte Ptr, clipboard:Byte Ptr, editable:Int)
+	Function gtk_text_buffer_copy_clipboard(handle:Byte Ptr, clipboard:Byte Ptr)
+	Function gtk_text_buffer_paste_clipboard(handle:Byte Ptr, clipboard:Byte Ptr, overide:Byte Ptr, editable:Int)
+	Function gtk_text_buffer_delete(handle:Byte Ptr, _start:Byte Ptr, _end:Byte Ptr)
+	Function gtk_text_buffer_get_insert:Byte Ptr(handle:Byte Ptr)
+	Function gtk_text_buffer_remove_all_tags(handle:Byte Ptr, _start:Byte Ptr, _end:Byte Ptr)
+	Function gtk_text_buffer_apply_tag(handle:Byte Ptr, tag:Byte Ptr, _start:Byte Ptr, _end:Byte Ptr)
+	
+	' GtkTextView
+	Function gtk_text_view_new_with_buffer:Byte Ptr(handle:Byte Ptr)
+	Function gtk_text_view_set_wrap_mode(handle:Byte Ptr, wrapMode:Int)
+	Function gtk_text_view_set_editable(handle:Byte Ptr, setting:Int)
+	Function gtk_text_view_scroll_to_iter(handle:Byte Ptr, iter:Byte Ptr, withinMargin:Double, useAlign:Int, xAlign:Double, yAlign:Double)
+	Function gtk_text_view_scroll_mark_onscreen(handle:Byte Ptr, mark:Byte Ptr)
+	Function gtk_text_view_get_tabs:Byte Ptr(handle:Byte Ptr)
+	Function gtk_text_view_set_tabs(handle:Byte Ptr, tabs:Byte Ptr)
+		
+	' GtkTextIter
+	Function gtk_text_iter_get_line:Int(handle:Byte Ptr)
+	Function gtk_text_iter_get_offset:Int(handle:Byte Ptr)
+	
+	' GtkTextTagTable
+	Function gtk_text_tag_table_lookup:Byte Ptr(handle:Byte Ptr, txt$z)
+	
+	' pango tab array
+	Function pango_tab_array_free(handle:Byte Ptr)
+	Function pango_tab_array_new_with_positions:Byte Ptr(size:Int, pixels:Int, align:Int, pos:Int)
+	
+	' GtkSeparatorMenuItem
+	Function gtk_separator_menu_item_new:Byte Ptr()
+	
+	' GtkMenuItem
+	Function gtk_menu_item_new_with_mnemonic:Byte Ptr(label:Byte Ptr)
+	Function gtk_menu_item_new_with_label:Byte Ptr(label:Byte Ptr)
+	Function gtk_menu_item_set_submenu(handle:Byte Ptr, submenu:Byte Ptr)
+	
+	' GtkMenu
+	Function gtk_menu_new:Byte Ptr()
+	
+	' GtkMenuShell
+	Function gtk_menu_shell_append(handle:Byte Ptr, child:Byte Ptr)
+	Function gtk_menu_shell_insert(handle:Byte Ptr, child:Byte Ptr, pos:Int)
+	
+	' settings
+	Function gtk_settings_set_string_property(settings:Byte Ptr, name:Byte Ptr, v_string:Byte Ptr, origin:Byte Ptr)
+	Function gtk_settings_get_default:Byte Ptr()
+	
+	' GtkCheckMenuItem
+	Function gtk_check_menu_item_get_active:Int(handle:Byte Ptr)
+	Function gtk_check_menu_item_new_with_mnemonic:Byte Ptr(label:Byte Ptr)
+	Function gtk_check_menu_item_new_with_label:Byte Ptr(label:Byte Ptr)
+	Function gtk_check_menu_item_set_active(handle:Byte Ptr, active:Int)
+
+	' GtkDrawingArea
+	Function gtk_drawing_area_new:Byte Ptr()
+
+	' GtkIconTheme
+	Function gtk_icon_theme_add_builtin_icon(name$z, size:Int, pixbuf:Byte Ptr)
+
+	' GtkColorSelection
+	Function gtk_color_selection_dialog_new:Byte Ptr(title:Byte Ptr)
+	Function gtk_color_selection_dialog_get_color_selection:Byte Ptr(handle:Byte Ptr)
+?bmxng
+	Function gtk_color_selection_set_current_rgba(handle:Byte Ptr, rgba:GdkRGBA Var)
+	Function gtk_color_selection_get_current_rgba(handle:Byte Ptr, rgba:GdkRGBA Var)
+?Not bmxng
+	Function gtk_color_selection_set_current_rgba(handle:Byte Ptr, rgba:Byte Ptr)
+	Function gtk_color_selection_get_current_rgba(handle:Byte Ptr, rgba:Byte Ptr)
+?
+	
+	' GtkFontChooserDialog
+	Function gtk_font_chooser_dialog_new:Byte Ptr(title:Byte Ptr, parent:Byte Ptr)
+	Function gtk_font_chooser_set_font_desc(handle:Byte Ptr, desc:Byte Ptr)
+	Function gtk_font_chooser_get_font_desc:Byte Ptr(handle:Byte Ptr)
+	
+	' GdkMonitor
+	'Function gdk_display_get_primary_monitor:Byte Ptr(display:Byte Ptr)
+	
+	' glue
+	Function bmx_gtk3_gtkdesktop_gethertz:Int()
+	Function bmx_gtk3_gvalue_new:Byte Ptr(_type:Int)
+	Function bmx_gtk3_gvalue_free(_value:Byte Ptr)
+	Function bmx_gtk3_gtktreeiter_new:Byte Ptr()
+	Function bmx_gtk3_gtktreeiter_free(handle:Byte Ptr)
+	Function bmx_gtk3_stylecontext_get_fontdesc:Byte Ptr(handle:Byte Ptr)
+	Function bmx_gtk3_gtktextiter_new:Byte Ptr()
+	Function bmx_gtk3_gtktextiter_free(iter:Byte Ptr)
+?bmxng
+	Function bmx_gtk3_set_text_tag_style:Byte Ptr(handle:Byte Ptr, tag$z, _fg:GdkRGBA Var, _style:Int, _weight:Int, _under:Int, _strike:Int)
+	Function bmx_gtk3_set_text_bg_tag:Byte Ptr(handle:Byte Ptr, tag$z, _bg:GdkRGBA Var)
+?Not bmxng
+	Function bmx_gtk3_set_text_tag_style:Byte Ptr(handle:Byte Ptr, tag$z, _fg:Byte Ptr, _style:Int, _weight:Int, _under:Int, _strike:Int)
+	Function bmx_gtk3_set_text_bg_tag:Byte Ptr(handle:Byte Ptr, tag$z, _bg:Byte Ptr)
+?
+	' event types
+	Function bmx_gtk3maxgui_gdkeventbutton(event:Byte Ptr, x:Double Ptr, y:Double Ptr, button:Int Ptr)
+	Function bmx_gtk3maxgui_gdkeventmotion(event:Byte Ptr, x:Double Ptr, y:Double Ptr, state:Int Ptr)
+	Function bmx_gtk3maxgui_gdkeventscroll(event:Byte Ptr, x:Double Ptr, y:Double Ptr, direction:Int Ptr)
+	Function bmx_gtk3maxgui_gdkeventkey(event:Byte Ptr, keyval:Int Ptr, state:Int Ptr)
+	Function bmx_gtk3maxgui_gdkeventconfigure(event:Byte Ptr, x:Int Ptr, y:Int Ptr, w:Int Ptr, h:Int Ptr)
+	Function bmx_gtk3maxgui_gdkeventwindowstate(event:Byte Ptr, state:Int Ptr)
+	Function bmx_gtk3maxgui_gdkeventmotiondevice:Byte Ptr(event:Byte Ptr)
+
+End Extern
+
+' gadget identifiers
+Const GTK_WINDOW:Int = 0
+Const GTK_BUTTON:Int = 1
+Const GTK_RADIOBUTTON:Int = 2
+Const GTK_CHECKBUTTON:Int = 3
+Const GTK_TOGGLEBUTTON:Int = 4
+Const GTK_LABEL:Int = 5
+Const GTK_MENUITEM:Int = 6
+Const GTK_TEXTFIELD:Int = 7
+Const GTK_TEXTAREA:Int = 8
+Const GTK_PANEL:Int = 9
+Const GTK_COMBOBOX:Int = 10
+Const GTK_HTMLVIEW:Int = 11
+Const GTK_TABBER:Int = 12
+Const GTK_PROGRESSBAR:Int = 13
+Const GTK_SCROLLBAR:Int = 14
+Const GTK_TRACKBAR:Int = 15
+Const GTK_STEPPER:Int = 16
+Const GTK_DESKTOP:Int = 17
+Const GTK_TOOLBAR:Int = 18
+Const GTK_LISTBOX:Int = 19
+Const GTK_TREEVIEW:Int = 20
+Const GTK_CANVAS:Int = 21
+
+
+' GtkDialogFlags
+Const GTK_DIALOG_MODAL:Int = 0
+Const GTK_DIALOG_DESTROY_WITH_PARENT:Int = 1
+
+' GtkButtonsType
+Const GTK_BUTTONS_NONE:Int = 0
+Const GTK_BUTTONS_OK:Int = 1
+Const GTK_BUTTONS_CLOSE:Int = 2
+Const GTK_BUTTONS_CANCEL:Int = 3
+Const GTK_BUTTONS_YES_NO:Int = 4
+Const GTK_BUTTONS_OK_CANCEL:Int = 5
+
+' GtkMessageType
+Const GTK_MESSAGE_INFO:Int = 0
+Const GTK_MESSAGE_WARNING:Int = 1
+Const GTK_MESSAGE_QUESTION:Int = 2
+Const GTK_MESSAGE_ERROR:Int = 3
+Const GTK_MESSAGE_OTHER:Int = 4
+
+' GtkResponseType
+Const GTK_RESPONSE_NONE:Int = -1
+Const GTK_RESPONSE_REJECT:Int = -2
+Const GTK_RESPONSE_ACCEPT:Int = -3
+Const GTK_RESPONSE_DELETE_EVENT:Int = -4
+Const GTK_RESPONSE_OK:Int     = -5
+Const GTK_RESPONSE_CANCEL:Int = -6
+Const GTK_RESPONSE_CLOSE:Int  = -7
+Const GTK_RESPONSE_YES:Int    = -8
+Const GTK_RESPONSE_NO:Int     = -9
+Const GTK_RESPONSE_APPLY:Int  = -10
+Const GTK_RESPONSE_HELP:Int   = -11
+
+' GtkFileChooserAction
+Const GTK_FILE_CHOOSER_ACTION_OPEN:Int = 0
+Const GTK_FILE_CHOOSER_ACTION_SAVE:Int = 1
+Const GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:Int = 2
+Const GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER:Int = 3
+
+' PangoStyle
+Const PANGO_STYLE_NORMAL:Int = 0
+Const PANGO_STYLE_OBLIQUE:Int = 1
+Const PANGO_STYLE_ITALIC:Int = 2
+
+' PangoWeight
+Const PANGO_WEIGHT_ULTRALIGHT:Int = 200
+Const PANGO_WEIGHT_LIGHT:Int = 300
+Const PANGO_WEIGHT_NORMAL:Int = 400
+Const PANGO_WEIGHT_SEMIBOLD:Int = 600
+Const PANGO_WEIGHT_BOLD:Int = 700
+Const PANGO_WEIGHT_ULTRABOLD:Int = 800
+Const PANGO_WEIGHT_HEAVY:Int = 900
+
+' PangoUnderline
+Const PANGO_UNDERLINE_NONE:Int = 0
+Const PANGO_UNDERLINE_SINGLE:Int = 1
+Const PANGO_UNDERLINE_DOUBLE:Int = 2
+Const PANGO_UNDERLINE_LOW:Int = 3
+Const PANGO_UNDERLINE_ERROR:Int = 4
+
+' GtkOrientation
+Const GTK_ORIENTATION_HORIZONTAL:Int = 0
+Const GTK_ORIENTATION_VERTICAL:Int = 1
+
+' gtkwindowtype
+Const GTK_WINDOW_TOPLEVEL:Int = 0
+Const GTK_WINDOW_POPUP:Int = 1
+
+' gtkwindowposition
+Const GTK_WIN_POS_NONE:Int = 0
+Const GTK_WIN_POS_CENTER:Int = 1
+Const GTK_WIN_POS_MOUSE:Int = 2
+Const GTK_WIN_POS_CENTER_ALWAYS:Int = 3
+Const GTK_WIN_POS_CENTER_ON_PARENT:Int = 4
+
+' GdkWindowTypeHint
+Const GDK_WINDOW_TYPE_HINT_NORMAL:Int       = 0
+Const GDK_WINDOW_TYPE_HINT_DIALOG:Int       = 1
+Const GDK_WINDOW_TYPE_HINT_MENU:Int         = 2
+Const GDK_WINDOW_TYPE_HINT_TOOLBAR:Int      = 3
+Const GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:Int = 4
+Const GDK_WINDOW_TYPE_HINT_UTILITY:Int      = 5
+Const GDK_WINDOW_TYPE_HINT_DOCK:Int         = 6
+Const GDK_WINDOW_TYPE_HINT_DESKTOP:Int      = 7
+Const GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU:Int= 8  ' A drop down menu (from a menubar)
+Const GDK_WINDOW_TYPE_HINT_POPUP_MENU:Int   = 9  ' A popup menu (from Right-click)
+Const GDK_WINDOW_TYPE_HINT_TOOLTIP:Int      = 10
+Const GDK_WINDOW_TYPE_HINT_NOTIFICATION:Int = 11
+Const GDK_WINDOW_TYPE_HINT_COMBO:Int        = 12
+Const GDK_WINDOW_TYPE_HINT_DND:Int          = 13
+
+' GdkWindowHints
+Const GDK_HINT_POS:Int	     = 1
+Const GDK_HINT_MIN_SIZE:Int    = 2
+Const GDK_HINT_MAX_SIZE:Int    = 4
+Const GDK_HINT_BASE_SIZE:Int   = 8
+Const GDK_HINT_ASPECT:Int      = 16
+Const GDK_HINT_RESIZE_INC:Int  = 32
+Const GDK_HINT_WIN_GRAVITY:Int = 64
+Const GDK_HINT_USER_POS:Int    = 128
+Const GDK_HINT_USER_SIZE:Int   = 256
+
+' GdkWindowState
+Const GDK_WINDOW_STATE_WITHDRAWN:Int  = 1 Shl 0
+Const GDK_WINDOW_STATE_ICONIFIED:Int  = 1 Shl 1
+Const GDK_WINDOW_STATE_MAXIMIZED:Int  = 1 Shl 2
+Const GDK_WINDOW_STATE_STICKY:Int     = 1 Shl 3
+Const GDK_WINDOW_STATE_FULLSCREEN:Int = 1 Shl 4
+Const GDK_WINDOW_STATE_ABOVE:Int      = 1 Shl 5
+Const GDK_WINDOW_STATE_BELOW:Int      = 1 Shl 6
+Const GDK_WINDOW_STATE_FOCUSED:Int    = 1 Shl 7
+Const GDK_WINDOW_STATE_TILED:Int      = 1 Shl 8
+
+' GdkColorspace
+Const GDK_COLORSPACE_RGB:Int = 0
+
+' GtkStateType
+Const GTK_STATE_FLAG_NORMAL:Int = 0
+Const GTK_STATE_FLAG_ACTIVE:Int = 1
+Const GTK_STATE_FLAG_PRELIGHT:Int = 2
+Const GTK_STATE_FLAG_SELECTED:Int = 3
+Const GTK_STATE_FLAG_INSENSITIVE:Int = 4
+Const GTK_STATE_FLAG_INCONSISTENT:Int = 5
+Const GTK_STATE_FLAG_FOCUSED:Int = 6
+Const GTK_STATE_FLAG_BACKDROP:Int = 7
+Const GTK_STATE_FLAG_DIR_LTR:Int = 8
+Const GTK_STATE_FLAG_DIR_RTL:Int = 9
+
+' GtkAccelFlags
+Const GTK_ACCEL_VISIBLE:Int = 1 ' display in GtkAccelLabel?
+Const GTK_ACCEL_LOCKED:Int  = 2 ' is it removable?
+Const GTK_ACCEL_MASK:Int    = 7
+
+Const GDK_EXPOSURE_MASK:Int = 1 Shl 1
+Const GDK_POINTER_MOTION_MASK:Int = 1 Shl 2
+Const GDK_POINTER_MOTION_HINT_MASK:Int = 1 Shl 3
+Const GDK_BUTTON_MOTION_MASK:Int = 1 Shl 4
+Const GDK_BUTTON1_MOTION_MASK:Int = 1 Shl 5
+Const GDK_BUTTON2_MOTION_MASK:Int = 1 Shl 6
+Const GDK_BUTTON3_MOTION_MASK:Int = 1 Shl 7
+Const GDK_BUTTON_PRESS_MASK:Int = 1 Shl 8
+Const GDK_BUTTON_RELEASE_MASK:Int = 1 Shl 9
+Const GDK_KEY_PRESS_MASK:Int = 1 Shl 10
+Const GDK_KEY_RELEASE_MASK:Int = 1 Shl 11
+Const GDK_ENTER_NOTIFY_MASK:Int = 1 Shl 12
+Const GDK_LEAVE_NOTIFY_MASK:Int = 1 Shl 13
+Const GDK_FOCUS_CHANGE_MASK:Int = 1 Shl 14
+Const GDK_STRUCTURE_MASK:Int = 1 Shl 15
+Const GDK_PROPERTY_CHANGE_MASK:Int = 1 Shl 16
+Const GDK_VISIBILITY_NOTIFY_MASK:Int = 1 Shl 17
+Const GDK_PROXIMITY_IN_MASK:Int = 1 Shl 18
+Const GDK_PROXIMITY_OUT_MASK:Int = 1 Shl 19
+Const GDK_SUBSTRUCTURE_MASK:Int = 1 Shl 20
+Const GDK_SCROLL_MASK:Int = 1 Shl 21
+Const GDK_TOUCH_MASK:Int = 1 Shl 22
+Const GDK_SMOOTH_SCROLL_MASK:Int = 1 Shl 23
+
+' GtkShadowType
+Const GTK_SHADOW_NONE:Int = 0
+Const GTK_SHADOW_IN:Int = 1
+Const GTK_SHADOW_OUT:Int = 2
+Const GTK_SHADOW_ETCHED_IN:Int = 3
+Const GTK_SHADOW_ETCHED_OUT:Int = 4
+
+' GType
+Const G_TYPE_STRING:Int = 16 Shl 2
+Const G_TYPE_POINTER:Int = 17 Shl 2
+
+' GtkPolicyType
+Const GTK_POLICY_ALWAYS:Int = 0
+Const GTK_POLICY_AUTOMATIC:Int = 1
+Const GTK_POLICY_NEVER:Int = 2
+
+' GtkSelectionMode
+Const GTK_SELECTION_NONE:Int = 0                       ' Nothing can be selected
+Const GTK_SELECTION_SINGLE:Int = 1
+Const GTK_SELECTION_BROWSE:Int = 2
+Const GTK_SELECTION_MULTIPLE:Int = 3
+
+' GtkResizeMode
+Const GTK_RESIZE_PARENT:Int = 0
+Const GTK_RESIZE_QUEUE:Int = 1
+Const GTK_RESIZE_IMMEDIATE:Int = 2
+
+' GtkToolbarStyle
+Const GTK_TOOLBAR_ICONS:Int = 0
+Const GTK_TOOLBAR_TEXT:Int = 1
+Const GTK_TOOLBAR_BOTH:Int = 2
+Const GTK_TOOLBAR_BOTH_HORIZ:Int = 3
+
+' GdkScrollDirection
+Const GDK_SCROLL_UP:Int = 0
+Const GDK_SCROLL_DOWN:Int = 1
+Const GDK_SCROLL_LEFT:Int = 2
+Const GDK_SCROLL_RIGHT:Int = 3
+Const GDK_SCROLL_SMOOTH:Int = 4
+
+' GdkInterpType
+Const GDK_INTERP_NEAREST:Int = 0
+Const GDK_INTERP_TILES:Int = 1
+Const GDK_INTERP_BILINEAR:Int = 2
+Const GDK_INTERP_HYPER:Int = 3
+
+' GtkPositionType
+Const GTK_POS_LEFT:Int = 0
+Const GTK_POS_RIGHT:Int = 1
+Const GTK_POS_TOP:Int = 2
+Const GTK_POS_BOTTOM:Int = 3
+
+' GtkWrapMode
+Const GTK_WRAP_NONE:Int = 0
+Const GTK_WRAP_CHAR:Int = 1
+Const GTK_WRAP_WORD:Int = 2
+Const GTK_WRAP_WORD_CHAR:Int = 3
+
+' PangoTabAlign
+Const PANGO_TAB_LEFT:Int = 0
+Const PANGO_TAB_RIGHT:Int = 1
+Const PANGO_TAB_CENTER:Int = 2
+Const PANGO_TAB_NUMERIC:Int = 3
+
+' GdkCursorType
+Const GDK_X_CURSOR:Int = 0
+Const GDK_ARROW:Int = 2
+Const GDK_BASED_ARROW_DOWN:Int = 4
+Const GDK_BASED_ARROW_UP:Int = 6
+Const GDK_BOAT:Int = 8
+Const GDK_BOGOSITY:Int = 10
+Const GDK_BOTTOM_LEFT_CORNER:Int = 12
+Const GDK_BOTTOM_RIGHT_CORNER:Int = 14
+Const GDK_BOTTOM_SIDE:Int = 16
+Const GDK_BOTTOM_TEE:Int = 18
+Const GDK_BOX_SPIRAL:Int = 20
+Const GDK_CENTER_PTR:Int = 22
+Const GDK_CIRCLE:Int = 24
+Const GDK_CLOCK:Int = 26
+Const GDK_COFFEE_MUG:Int = 28
+Const GDK_CROSS:Int = 30
+Const GDK_CROSS_REVERSE:Int = 32
+Const GDK_CROSSHAIR:Int = 34
+Const GDK_DIAMOND_CROSS:Int = 36
+Const GDK_DOT:Int = 38
+Const GDK_DOTBOX:Int = 40
+Const GDK_DOUBLE_ARROW:Int = 42
+Const GDK_DRAFT_LARGE:Int = 44
+Const GDK_DRAFT_SMALL:Int = 46
+Const GDK_DRAPED_BOX:Int = 48
+Const GDK_EXCHANGE:Int = 50
+Const GDK_FLEUR:Int = 52
+Const GDK_GOBBLER:Int = 54
+Const GDK_GUMBY:Int = 56
+Const GDK_HAND1:Int = 58
+Const GDK_HAND2:Int = 60
+Const GDK_HEART:Int = 62
+Const GDK_ICON:Int = 64
+Const GDK_IRON_CROSS:Int = 66
+Const GDK_LEFT_PTR:Int = 68
+Const GDK_LEFT_SIDE:Int = 70
+Const GDK_LEFT_TEE:Int = 72
+Const GDK_LEFTBUTTON:Int = 74
+Const GDK_LL_ANGLE:Int = 76
+Const GDK_LR_ANGLE:Int = 78
+Const GDK_MAN:Int = 80
+Const GDK_MIDDLEBUTTON:Int = 82
+Const GDK_MOUSE:Int = 84
+Const GDK_PENCIL:Int = 86
+Const GDK_PIRATE:Int = 88
+Const GDK_PLUS:Int = 90
+Const GDK_QUESTION_ARROW:Int = 92
+Const GDK_RIGHT_PTR:Int = 94
+Const GDK_RIGHT_SIDE:Int = 96
+Const GDK_RIGHT_TEE:Int = 98
+Const GDK_RIGHTBUTTON:Int = 100
+Const GDK_RTL_LOGO:Int = 102
+Const GDK_SAILBOAT:Int = 104
+Const GDK_SB_DOWN_ARROW:Int = 106
+Const GDK_SB_H_DOUBLE_ARROW:Int = 108
+Const GDK_SB_LEFT_ARROW:Int = 110
+Const GDK_SB_RIGHT_ARROW:Int = 112
+Const GDK_SB_UP_ARROW:Int = 114
+Const GDK_SB_V_DOUBLE_ARROW:Int = 116
+Const GDK_SHUTTLE:Int = 118
+Const GDK_SIZING:Int = 120
+Const GDK_SPIDER:Int = 122
+Const GDK_SPRAYCAN:Int = 124
+Const GDK_STAR:Int = 126
+Const GDK_TARGET:Int = 128
+Const GDK_TCROSS:Int = 130
+Const GDK_TOP_LEFT_ARROW:Int = 132
+Const GDK_TOP_LEFT_CORNER:Int = 134
+Const GDK_TOP_RIGHT_CORNER:Int = 136
+Const GDK_TOP_SIDE:Int = 138
+Const GDK_TOP_TEE:Int = 140
+Const GDK_TREK:Int = 142
+Const GDK_UL_ANGLE:Int = 144
+Const GDK_UMBRELLA:Int = 146
+Const GDK_UR_ANGLE:Int = 148
+Const GDK_WATCH:Int = 150
+Const GDK_XTERM:Int = 152
+Const GDK_BLANK_CURSOR:Int = -2
+Const GDK_CURSOR_IS_PIXMAP:Int = -1
+
+' List of application windows
+' We use it for SetPointer etc.
+Global gtkWindows:TList = New TList
+
+' I know... cup of cocoa anyone?
+Global GadgetMap:TPtrMap=New TPtrMap
+
+' creates an Object out of an "int"
+Type TGTKInteger
+	Field value:Int
+	Function Set:TGTKInteger(value:Int)
+		Local this:TGTKInteger = New TGTKInteger
+		this.value = value
+		Return this
+	End Function
+	Method Compare:Int(o:Object)
+		Return value-TGTKInteger(o).value
+	End Method
+End Type
+
+Type TGTKGuiFont Extends TGuiFont
+
+	Field fontDesc:Byte Ptr
+
+	Field context:Byte Ptr
+	Field layout:Byte Ptr
+
+	Method Delete()
+		If fontDesc Then
+			pango_font_description_free(fontDesc)
+			fontDesc = Null
+		EndIf
+
+		If layout Then
+			g_object_unref(layout)
+			layout = Null
+		End If
+
+		If context Then
+			g_object_unref(context)
+			context = Null
+		End If
+	EndMethod
+	
+	Method CharWidth:Int(char:Int)
+		If Not fontDesc Then
+			getPangoDescriptionFromGuiFont(Self)
+		EndIf
+
+		If fontDesc Then
+			If Not context Then
+				context = gdk_pango_context_get()
+				pango_context_set_font_description(context, fontDesc)
+
+				layout = pango_layout_new(context)
+			End If
+
+			Local s:Byte Ptr = Chr(char).ToUTF8String()
+			pango_layout_set_text(layout, s, 1)
+			MemFree(s)
+
+			Local w:Int
+			pango_layout_get_pixel_size(layout, Varptr w, Null)
+
+			Return w
+		End If
+
+		Return 0
+	EndMethod 
+		
+EndType
+
+Rem
+internal: Returns a Pango font description based on a TGuiFont specification. (INTERNAL)
+End Rem
+Function getPangoDescriptionFromGuiFont(font:TGtkGuiFont)
+	If font = Null Then
+		Return
+	End If
+	
+	If Not font.fontDesc Then
+
+		Local fontdesc:Byte Ptr = pango_font_description_new()
+		Local s:Byte Ptr = font.name.toUTF8String()
+			
+		pango_font_description_set_family(fontdesc, s)
+	
+		If font.style & FONT_BOLD Then
+			pango_font_description_set_weight(fontdesc, PANGO_WEIGHT_BOLD)
+		Else
+			pango_font_description_set_weight(fontdesc, PANGO_WEIGHT_NORMAL)
+		End If
+	
+		If font.style & FONT_ITALIC Then
+			pango_font_description_set_style(fontdesc, PANGO_STYLE_ITALIC)
+		End If
+	
+		pango_font_description_set_absolute_size(fontdesc, font.size * 1024)
+	
+		MemFree(s)
+		
+		font.fontDesc = fontDesc
+		
+	End If
+
+End Function
+
+Rem
+internal: Returns a TGuiFont from a pango description object. (INTERNAL)
+End Rem
+Function getGuiFontFromPangoDescription:TGuiFont(fontdesc:Byte Ptr)
+	Local font:TGtkGuiFont = New TGTKGuiFont
+
+	font.name = String.FromUTF8String(pango_font_description_get_family(fontdesc))
+	'font.path = ...
+	Local ital:Int = pango_font_description_get_style(fontdesc)
+	Local bold:Int = pango_font_description_get_weight(fontdesc)
+
+	If ital = PANGO_STYLE_OBLIQUE Or ital = PANGO_STYLE_ITALIC Then
+		font.style:| FONT_ITALIC
+	End If
+
+	If bold > PANGO_WEIGHT_NORMAL Then
+		font.style:| FONT_BOLD
+	End If
+
+	font.size = pango_font_description_get_size(fontdesc) / 1024
+
+	font.fontDesc = fontdesc
+	
+	Return font
+End Function
+
+?bmxng
+Struct GdkGeometry
+?Not bmxng
+Type GdkGeometry
+?
+	Field minWidth:Int
+	Field minHeight:Int
+	Field maxWidth:Int
+	Field maxHeight:Int
+	Field baseWidth:Int
+	Field baseHeight:Int
+	Field widthInc:Int
+	Field heightInc:Int
+	Field minAspect:Double
+	Field maxAspect:Double
+	Field winGravity:Int
+?bmxng
+End Struct
+?Not bmxng
+End Type
+?
+
+?bmxng
+Struct GtkRequisition
+	Field width:Int
+	Field height:Int
+End Struct
+?Not bmxng
+Type GtkRequisition
+	Field width:Int
+	Field height:Int
+End Type
+?
+
+?bmxng
+Struct GdkRectangle
+	Field x:Int
+	Field y:Int
+	Field width:Int
+	Field height:Int
+End Struct
+?Not bmxng
+Type GdkRectangle
+	Field x:Int
+	Field y:Int
+	Field width:Int
+	Field height:Int
+End Type
+?
+
+?bmxng
+Struct GtkAllocation
+	Field x:Int
+	Field y:Int
+	Field width:Int
+	Field height:Int
+End Struct
+?Not bmxng
+Type GtkAllocation
+	Field x:Int
+	Field y:Int
+	Field width:Int
+	Field height:Int
+End Type
+?
+
+?bmxng
+Struct GdkRGBA
+	Field red:Double
+	Field green:Double
+	Field blue:Double
+	Field alpha:Double
+	
+	Method New(red:Double, green:Double, blue:Double, alpha:Double = 1.0)
+		Self.red = red
+		Self.green = green
+		Self.blue = blue
+		Self.alpha = alpha
+	End Method
+	
+End Struct
+?Not bmxng
+Type GdkRGBA
+	Field red:Double
+	Field green:Double
+	Field blue:Double
+	Field alpha:Double
+
+	Method Create:GdkRGBA(red:Double, green:Double, blue:Double, alpha:Double = 1.0)
+		Self.red = red
+		Self.green = green
+		Self.blue = blue
+		Self.alpha = alpha
+		Return Self
+	End Method
+End Type
+?
+
+Global _gtkKeysDown:Int[] = New Int[255]
+
+' returns True if key is already believed to be DOWN/Pressed
+Function gtk3SetKeyDown:Int(key:Int)
+	Assert key < 255, "gtkSetKeyDown key is out of range - " + key
+	
+	If _gtkKeysDown[key] Then
+		Return True
+	End If
+	
+	_gtkKeysDown[key] = 1
+	Return False
+End Function
+
+Function gtk3SetKeyUp(key:Int)
+	Assert key < 255, "gtkSetKeyUp key is out of range - " + key
+	
+	_gtkKeysDown[key] = 0
+End Function

+ 5394 - 5394
gtk3maxgui.mod/gtkgadget.bmx

@@ -1,5394 +1,5394 @@
-' Copyright (c) 2006-2018 Bruce A Henderson
-' 
-' Permission is hereby granted, free of charge, to any person obtaining a copy
-' of this software and associated documentation files (the "Software"), to deal
-' in the Software without restriction, including without limitation the rights
-' to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-' copies of the Software, and to permit persons to whom the Software is
-' furnished to do so, subject to the following conditions:
-' 
-' The above copyright notice and this permission notice shall be included in
-' all copies or substantial portions of the Software.
-' 
-' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-' THE SOFTWARE.
-' 
-SuperStrict
-
-Import "gtkcommon.bmx"
-
-Type TGTKGadget Extends TGadget
-
-	Field iclass:Int
-	' usually the pointer to the gtk widget
-	Field handle:Byte Ptr
-
-	Field menubar:Byte Ptr
-	Field menu:Byte Ptr
-
-	' reference to this gadgets' font (if we've ever set it programmatically)
-	Field _font:TGuiFont
-
-	' a map to hold connection handler ids... sometimes we need to disconnect the little buggers.
-	Field connectionMap:TMap = New TMap
-
-	' a unique identifier for this gadget
-	Field accelMapId:String
-	Field accelString:String
-	Field hasAccel:Int
-	
-	Field initialSizing:Int = False
-
-	Field mySetVisible:Int = True
-	Field visible:Int = False
-	
-	' the class id of this gadget in MaxGUI terms.
-	Field maxguiClass:Int
-	
-	Method Init(GadgetClass:Int, _x:Int, _y:Int, _w:Int, _h:Int, _style:Int)
-		SetRect(_x,_y,_w,_h)
-		iclass = GadgetClass
-		kids = New TList
-		style = _style
-	End Method
-
-	Method addConnection(name:String, id:Int)
-		connectionMap.Insert(name, TGTKInteger.Set(id))
-	End Method
-
-	Function Destroy(data:Byte Ptr, closure:Byte Ptr)
-		'Print "Destroy Handler"
-	End Function
-
-	Function Create:TGTKGadget(GadgetClass:Int, x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int, mgclass:Int)
-
-		Local gadget:TGTKGadget
-		
-		Select GadgetClass
-			Case GTK_WINDOW
-				gadget = TGTKWindow.CreateWindow(x, y ,w , h, label, group, style)
-			Case GTK_BUTTON
-				gadget = TGTKButtonPush.CreateButton(x, y ,w , h, label, group, style)
-			Case GTK_RADIOBUTTON
-				gadget = TGTKButtonRadio.CreateButton(x, y ,w , h, label, group, style)
-			Case GTK_CHECKBUTTON
-				gadget = TGTKButtonCheckbox.CreateButton(x, y ,w , h, label, group, style)
-			Case GTK_LABEL
-				gadget = TGTKLabel.CreateLabel(x, y ,w , h, label, group, style)
-			Case GTK_MENUITEM
-				gadget = TGTKMenuItem.CreateMenuItem(label, style, group)
-			Case GTK_TEXTFIELD
-				gadget = TGTKTextField.CreateTextField(x, y ,w , h, label, group, style)
-			Case GTK_HTMLVIEW
-				If gtk3maxgui_htmlview Then
-					gadget = gtk3maxgui_htmlview.CreateHTMLView(x, y ,w , h, label, group, style)
-				Else
-					Throw "No HTMLView specified. You need To Import one!    " + ..
-						" Import Gtk.gtk3webkitgtk"
-				End If
-			Case GTK_TABBER
-				gadget = TGTKTabber.CreateTabber(x, y ,w , h, label, group, style)
-			Case GTK_PANEL
-				gadget = TGTKPanel.CreatePanel(x, y ,w , h, label, group, style)
-			Case GTK_COMBOBOX
-				gadget = TGTKComboBox.CreateComboBox(x, y ,w , h, label, group, style)
-			Case GTK_PROGRESSBAR
-				gadget = TGTKProgressBar.CreateProgressBar(x, y ,w , h, label, group, style)
-			Case GTK_STEPPER
-				gadget = TGTKStepper.CreateStepper(x, y ,w , h, label, group, style)
-			Case GTK_SCROLLBAR
-				gadget = TGTKScrollBar.CreateScrollBar(x, y ,w , h, label, group, style)
-			Case GTK_TRACKBAR
-				gadget = TGTKTrackBar.CreateTrackBar(x, y ,w , h, label, group, style)
-			Case GTK_TEXTAREA
-				' no custom text area? use the default
-				If Not gtk3maxgui_textarea Then
-					gtk3maxgui_textarea = New TGTKDefaultTextAreaDriver
-				End If
-				gadget = gtk3maxgui_textarea.CreateTextArea(x, y ,w , h, label, group, style)
-			Case GTK_TOOLBAR
-				gadget = TGTKToolbar.CreateToolBar(x, y ,w , h, label, group, style)
-			Case GTK_LISTBOX
-				gadget = TGTKListbox.CreateListBox(x, y ,w , h, label, group, style)
-			Case GTK_TREEVIEW
-				gadget = TGTKTreeView.CreateTreeView(x, y ,w , h, label, group, style)
-Rem 
-			Case GTK_CANVAS
-				gadget = TGTKCanvas.CreateCanvas(x, y ,w , h, label, group, style)
-End Rem
-		End Select
-
-		' map the new gadget - so we can find it later if required
-		If gadget Then
-			GadgetMap.Insert(TGTKBytePtr.Set(gadget.handle),gadget)
-		End If
-		
-		If group Then
-			gadget._SetParent group
-		End If
-		gadget.SetShape x,y,w,h
-		' set the maxgui class type
-		gadget.maxguiClass = mgclass
-
-		Return gadget
-	End Function
-
-	Method Delete()
-		Free()
-	End Method
-
-	Method Free:Int()
-		Local gadget:TGTKGadget
-		Local rkids:TList		
-		rkids=kids.Reversed()
-		For gadget = EachIn rkids
-			gadget.Free	
-		Next
-		gadget = TGTKGadget(parent)
-		If gadget Then
-			gadget.kids.remove Self
-		End If
-
-		' remove reference from global reference map
-		If handle Then
-			GadgetMap.Remove(TGTKBytePtr.Set(handle))
-		End If
-		
-		connectionMap.Clear()
-		
-	End Method
-
-	Rem
-	bbdoc: Show or hide the gadget.
-	End Rem
-	Method SetShow:Int(truefalse:Int)
-		visible = truefalse
-		mySetVisible = visible
-		
-		If truefalse Then
-			gtk_widget_show(handle)
-		Else
-			gtk_widget_hide(handle)
-		EndIf
-		
-		UpdateChildVisibility()
-	End Method
-
-	Method UpdateChildVisibility()
-		For Local gadget:TGTKGadget = EachIn kids
-			If Not visible Then
-				gadget.visible = False
-			Else
-				gadget.visible = gadget.mySetVisible
-			End If
-			
-			gadget.UpdateChildVisibility()
-		Next
-	End Method
-
-	' checks text for mnemonics
-	Method processText:String(txt:String)
-		' convert underscores to doubles
-		txt = txt.Replace("_", "__")
-
-		txt = txt.Replace("&&", "$^^$")
-		txt = txt.Replace("&", "_")
-		txt = txt.Replace("$^^$", "&")
-		
-		Return txt
-	End Method
-
-	Method setAccelEntry(keycode:Int, modifier:Int)
-		Local accelKey:Int
-		Local modKey:Int
-		
-		If accelString And hasAccel Then
-			Local accelPtr:Byte Ptr = accelString.ToUTF8String()
-			gtk_accelerator_parse(accelPtr, Varptr accelKey, Varptr modKey)
-			MemFree(accelPtr)
-			If accelKey <> 0 Then
-				gtk_widget_remove_accelerator(handle, getWindow().accelGroup, accelKey, modKey)
-				hasAccel = False
-			End If
-		End If
-
-		' enabling accelerator?	
-		If keycode Then
-			accelString = TGTKKeyMap.accelToString(keycode, modifier)
-			Local accelPtr:Byte Ptr = accelString.ToUTF8String()
-			gtk_accelerator_parse(accelPtr, Varptr accelKey, Varptr modKey)
-			MemFree(accelPtr)
-			gtk_widget_add_accelerator(handle, "activate", getWindow().accelGroup, accelKey, modKey, GTK_ACCEL_VISIBLE)
-			hasAccel = True
-		End If
-	End Method
-	
-	Method setAccelMapId(id:String)
-		accelMapId = id.Replace("&", "")
-	End Method
-
-	' returns the widgets window
-	Method getWindow:TGTKWindow()
-		If Not TGTKWindow(Self) Then
-			If TGTKGadget(parent) Then
-				Return TGTKGadget(parent).getWindow()
-			Else
-				Return Null
-			End If
-		End If
-		
-		Return TGTKWindow(Self)
-	End Method
-
-	Rem
-	bbdoc: Callback for focus lost.
-	End Rem
-	Function OnFocusLost:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		PostGuiEvent(EVENT_GADGETLOSTFOCUS, TGadget(obj))
-	End Function
-	
-	Rem
-	bbdoc: Set the gadget tooltip.
-	End Rem
-	Method setToolTip:Int(tip:String)
-		If tip And tip.length > 0 Then
-			Local tipPtr:Byte Ptr = tip.ToUTF8String()
-			gtk_widget_set_tooltip_text(handle, tipPtr)
-			MemFree(tipPtr)
-		Else
-			gtk_widget_set_has_tooltip(handle, False)
-		End If
-	End Method
-
-	Rem
-	bbdoc: Perform an activation command on the gadget.
-	End Rem
-	Method Activate:Int(cmd:Int)
-		Select cmd
-			Case ACTIVATE_FOCUS
-				gtk_widget_grab_focus(handle)
-			Case ACTIVATE_FORWARD
-			Case ACTIVATE_BACK
-			Case ACTIVATE_REDRAW
-				redraw()
-				PostGuiEvent(EVENT_GADGETPAINT, Self)
-		End Select
-	End Method
-	
-	Method redraw()
-		gtk_widget_queue_draw(handle)
-	End Method
-
-	Rem
-	bbdoc: Return the gadget's client width.
-	End Rem
-	Method ClientWidth:Int()
-		If initialSizing Then
-?bmxng
-			Local minReq:GtkRequisition 
-			Local natReq:GtkRequisition
-?Not bmxng
-			Local minReq:GtkRequisition = New GtkRequisition
-			Local natReq:GtkRequisition = New GtkRequisition
-?
-			gtk_widget_get_preferred_size(handle, minReq, natReq)
-
-			Return natReq.width
-		End If
-		Return width
-	End Method
-
-	Rem
-	bbdoc: Return the gadget's client height.
-	End Rem
-	Method ClientHeight:Int()
-		If initialSizing Then
-?bmxng
-			Local minReq:GtkRequisition 
-			Local natReq:GtkRequisition
-?Not bmxng
-			Local minReq:GtkRequisition = New GtkRequisition
-			Local natReq:GtkRequisition = New GtkRequisition
-?
-			gtk_widget_get_preferred_size(handle, minReq, natReq)
-
-			Return natReq.height
-		End If
-		Return height
-	End Method
-
-	Method Rethink:Int()
-		If handle
-			gtk_layout_move(TGTKContainer(parent).container, handle, Max(xpos,0), Max(ypos,0))
-			gtk_widget_set_size_request(handle, Max(width,0), Max(height,0))
-		End If
-	End Method
-
-	Rem
-	bbdoc: Return the gadget state.
-	End Rem
-	Method State:Int()
-		Local flags:Int
-		Local _state:Int = gtk_widget_get_state_flags(handle)
-
-		Select _state
-			Case GTK_STATE_FLAG_INSENSITIVE
-				flags:| STATE_DISABLED
-			Case GTK_STATE_FLAG_SELECTED
-				flags:| STATE_SELECTED
-			Case GTK_STATE_FLAG_ACTIVE
-				flags:| STATE_ACTIVE
-		End Select
-
-		If Not gtk_widget_get_visible(handle) Then
-			flags:| STATE_HIDDEN
-		End If
-
-		Return flags
-	End Method
-
-End Type
-
-Rem
-bbdoc: The Desktop.
-End Rem
-Type TGTKDesktop Extends TGTKGadget
-
-	Function CreateDesktop:TGTKDesktop()
-		Local this:TGTKDesktop = New TGTKDesktop
-
-		this.initDesktop()
-
-		Return this
-	End Function
-
-	Method initDesktop()
-
-		iclass = GTK_DESKTOP
-
-		handle = gdk_screen_get_default()
-
-		SetArea(0, 0, gdk_screen_get_width(handle), gdk_screen_get_height(handle))
-
-	End Method
-
-	Method Rethink:Int()
-	End Method
-
-	Rem
-	bbdoc: Returns the desktop width.
-	End Rem
-	Method ClientWidth:Int()
-		Return width
-	End Method
-
-	Rem
-	bbdoc: Returns the desktop height.
-	End Rem
-	Method ClientHeight:Int()
-		Return height
-	End Method
-	
-	Rem
-	bbdoc: Returns the desktop depth.
-	End Rem
-	Method GetDepth:Int()
-		Local visual:Byte Ptr = gdk_screen_get_system_visual(handle)
-		Return gdk_visual_get_depth(visual)
-	End Method
-	
-	Rem
-	bbdoc: Returns the desktop hertz.
-	End Rem
-	Method GetHertz:Int()
-		Return bmx_gtk3_gtkdesktop_gethertz()
-	End Method
-	
-	Rem
-	bbdoc: Returns the desktop scale factor that maps from window coordiantes to the actual device pixels.
-	about: On traditional systems this is 1, but on very high density outputs this can be a higher value (often 2).
-	End Rem
-	Method ScaleFactor:Int()
-		Return gdk_screen_get_monitor_scale_factor(handle, 0)
-	End Method
-
-End Type
-
-Rem
-bbdoc: This type handles "internal" widget containers for "Container" gadgets.
-End Rem
-Type TGTKContainer Extends TGTKGadget
-
-	' a multi-row container
-	Field box:Byte Ptr
-
-	' the "Fixed" container that we place gadgets onto
-	Field container:Byte Ptr
-
-	' dont need to free this, as removing radio buttons from it will free itself when empty
-	Field radioGroup:Byte Ptr
-	
-	' initialize the container stuff
-	Method Init(GadgetClass:Int, x:Int, y:Int, w:Int, h:Int, style:Int)
-		Super.init(GadgetClass, x, y, w, h, style)
-
-	End Method
-
-	Method ClientWidth:Int()
-		Return width
-	End Method
-
-	Method ClientHeight:Int()
-		Return height
-	End Method
-
-
-End Type
-
-Rem
-bbdoc: A Window
-End Rem
-Type TGTKWindow Extends TGTKContainer
-
-	Field statusbar:Byte Ptr
-	Field sblabels:Byte Ptr[]
-	
-	Field toolbar:TGTKToolbar
-	Field accelGroup:Byte Ptr
-
-	Field oldCW:Int
-	Field oldCH:Int
-	
-	Field _maximized:Int
-	Field _minimized:Int
-	
-	Field ignoreMoveEvent:Int
-	Field ignoreSizeEvent:Int
-	
-	Function CreateWindow:TGTKWindow(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Local this:TGTKWindow = New TGTKWindow
-
-		this.initWindow(x, y, w, h, label, group, style)
-
-		gtkWindows.addLast(this)
-		
-		Return this
-	End Function
-
-	Method initWindow(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-
-		If group And TGTKDesktop(group)
-			group = Null
-		End If
-		
-		' should only be a window parent!!
-		If group Then
-			Assert TGTKWindow(group), "group not TGTKWindow!"
-		End If
-
-		handle = gtk_window_new(GTK_WINDOW_TOPLEVEL)
-
-		Init(GTK_WINDOW, x, y, w, h, style)
-
-		' container BEGIN
-		box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0)
-		gtk_widget_show(box)
-
-		If style & WINDOW_MENU Then
-			menubar = gtk_menu_bar_new()
-			gtk_box_pack_start(box, menubar, False, True, 0)
-			gtk_widget_show(menubar)
-		End If
-
-		container = gtk_layout_new(Null, Null)
-		
-		gtk_widget_show(container)
-		gtk_box_pack_start(box, container, True, True, 0)
-		' container END
-
-		If style & WINDOW_STATUS Then
-			createStatusbar()
-			SetStatusText("")
-		EndIf
-
-		If (LocalizationMode() & LOCALIZATION_OVERRIDE) Then
-			LocalizeGadget(Self, label)
-		Else
-			SetText(label)
-		EndIf
-
-		gtk_window_move(handle, x, y)
-		gtk_window_set_default_size(handle, w, calcHeight(h))
-
-		gtk_window_set_decorated(handle, (style & WINDOW_TITLEBAR))
-		gtk_window_set_resizable(handle, (style & WINDOW_RESIZABLE))
-		
-		If style & WINDOW_TOOL Then
-			gtk_window_set_type_hint(handle, GDK_WINDOW_TYPE_HINT_UTILITY)
-		End If
-
-		gtk_container_add(handle, box)
-		' some funky window setting up...
-		' It's all rather fiddly, but it appears to work.
-
-?bmxng
-		Local geom:GdkGeometry
-?Not bmxng
-		Local geom:GdkGeometry = New GdkGeometry
-?
-'DebugStop
-		Local hints:Int = 0
-		If style & WINDOW_RESIZABLE Then
-			hints:| GDK_HINT_USER_SIZE
-			geom.minWidth = 16
-			geom.minHeight = 16
-		
-			hints:| GDK_HINT_RESIZE_INC
-			geom.widthInc = 1
-			geom.heightInc = 1
-		Else
-			geom.minWidth = w
-			geom.minHeight = calcHeight(h)
-		End If
-		geom.maxWidth = -1
-		geom.maxHeight = -1
-
-		If Not (style & WINDOW_CLIENTCOORDS) Then
-			geom.baseWidth = w
-			geom.baseHeight = calcHeight(h)
-		Else
-			geom.baseWidth = -1
-			geom.baseHeight = -1
-		End If
-		gtk_window_set_geometry_hints(handle, box, geom, GDK_HINT_POS | GDK_HINT_MIN_SIZE | ..
-			GDK_HINT_BASE_SIZE | GDK_HINT_USER_POS | hints)
-
-		If Not(style & WINDOW_RESIZABLE) Then
-			gtk_widget_set_size_request(handle, w, calcHeight(h))
-		End If
-
-		' connect this window with its parent
-		If group And (style & WINDOW_CHILD) Then
-			gtk_window_set_transient_for(handle, TGTKWindow(group).handle)
-		End If
-
-		Rem
-		A Window produces the following events:
-		EVENT_WINDOWMOVE	Window has been moved
-		EVENT_WINDOWSIZE	Window has been resized
-		EVENT_WINDOWCLOSE	Window close icon clicked
-		EVENT_WINDOWACTIVATE	Window activated
-		EVENT_WINDOWACCEPT	Drag and Drop operation was attempted
-		End Rem
-		' move
-		addConnection("configure-event", g_signal_cb3(handle, "configure-event", OnWindowMoveSize, Self, Destroy, 0))
-		' size
-		addConnection("check-resize", g_signal_cb2(handle, "check-resize", OnWindowSize, Self, Destroy, 0))
-		' close
-		addConnection("delete-event", g_signal_cb3_ret(handle, "delete-event", OnWindowClose, Self, Destroy, 0))
-		' activate
-		addConnection("focus-in-event", g_signal_cb3(handle, "focus-in-event", OnWindowActivate, Self, Destroy, 0))
-		addConnection("focus-out-event", g_signal_cb3_ret(handle, "focus-out-event", OnWindowDeactivate, Self, Destroy, 0))
-		' accept
-		'g_signal_cb3(handle, "XXXXXX", WindowAccept, Self, Destroy, 0)
-		' minimize / maximize
-		addConnection("window-state-event", g_signal_cb3_ret(handle, "window-state-event", OnWindowStateChange, Self, Destroy, 0))
-
-		If style & WINDOW_ACCEPTFILES Then
-
-			'Local entries:Byte Ptr
-			
-			'gtk_drag_dest_set(container, GTK_DEST_DEFAULT_DROP | GTK_DEST_DEFAULT_HIGHLIGHT, Varptr entries, 0, GDK_ACTION_COPY)
-			'gtk_drag_dest_add_uri_targets(container)
-			'gtk_drag_dest_add_text_targets(container)
-			
-			'g_signal_cb6(container, "drag-drop", OnDragDrop, Self, Destroy, 0)
-		End If
-		
-		' used for tabbers - ensure they are redrawn properly when required
-		'g_signal_cb7(container, "draw-background", OnDraw, Self, Destroy, 0)
-
-		accelGroup = gtk_accel_group_new()
-		gtk_window_add_accel_group(handle, accelGroup)
-		setAccelMapId(label)
-
-		If ~style & WINDOW_HIDDEN
-			Setshow(True)
-		Else
-			SetShow(False)
-		End If
-
-	End Method
-
-	Method calcHeight:Int(requestedHeight:Int)
-		If Not (style & WINDOW_CLIENTCOORDS) Then
-			Return requestedHeight	
-		Else
-?bmxng
-			Local minReq:GtkRequisition 
-			Local natReq:GtkRequisition
-?Not bmxng
-			Local minReq:GtkRequisition = New GtkRequisition
-			Local natReq:GtkRequisition = New GtkRequisition
-?
-			If statusbar Then
-				gtk_widget_get_preferred_size(statusbar, minReq, natReq)
-				requestedHeight:+ natReq.height
-			End If
-			If menubar Then
-				gtk_widget_get_preferred_size(menubar, minReq, natReq)
-				requestedHeight:+ natReq.height
-			End If
-			
-			Return requestedHeight
-		End If
-	End Method
-
-	Method deCalcHeight:Int(actualHeight:Int)
-		If Not (style & WINDOW_CLIENTCOORDS) Then
-			Return actualHeight	
-		Else
-?bmxng
-			Local minReq:GtkRequisition 
-			Local natReq:GtkRequisition
-?Not bmxng
-			Local minReq:GtkRequisition = New GtkRequisition
-			Local natReq:GtkRequisition = New GtkRequisition
-?
-			If statusbar Then
-				gtk_widget_get_preferred_size(statusbar, minReq, natReq)
-				actualHeight:- natReq.height
-			End If
-			If menubar Then
-				gtk_widget_get_preferred_size(statusbar, minReq, natReq)
-				actualHeight:- natReq.height
-			End If
-
-			Return actualHeight
-		End If
-	End Method
-	
-	Rem
-	bbdoc: Callback for window size / move
-	End Rem
-	Function OnWindowMoveSize(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		Local x:Int, y:Int, w:Int, h:Int
-		bmx_gtk3maxgui_gdkeventconfigure(event, Varptr x, Varptr y, Varptr w, Varptr h)
-
-		Local win:TGTKWindow = TGTKWindow(obj)
-		If win Then
-			Local change:Int = False
-			
-			h = win.deCalcHeight(h)
-			
-			' Has the window actually changed size/position?
-			If win.width <> w Or win.height <> h Then
-				change = True
-
-				If Not win.ignoreSizeEvent Then
-					PostGuiEvent(EVENT_WINDOWSIZE, TGadget(obj),,,w,h)
-				End If
-			End If
-			
-			gtk_window_get_position(win.handle, Varptr x, Varptr y)
-			
-			If win.xpos <> x Or win.ypos <> y Then
-				change = True
-
-				If Not win.ignoreMoveEvent Then
-					PostGuiEvent(EVENT_WINDOWMOVE, TGadget(obj),,,x,y)
-				End If
-			End If
-
-			If win.ClientHeight() <> win.oldCH Or win.ClientWidth() <> win.oldCW Then
-				win.oldCH = win.ClientHeight()
-				win.oldCW = win.ClientWidth()
-
-				change = True
-			End If
-			
-			' something has changed.. we need to update ourself and tell the children.
-			If change Then
-				win.setRect(x, y, w, h)
-				win.layoutkids()
-			End If
-			
-			win.ignoreMoveEvent = False
-			win.ignoreSizeEvent = False
-		End If
-
-	End Function
-	
-	Method Rethink:Int()
-		gtk_window_move(handle, xpos, ypos)
-		If style & WINDOW_RESIZABLE Then
-			gtk_window_resize(handle, width, calcHeight(height))
-		Else
-			gtk_window_set_default_size(handle, width, calcHeight(height))
-		End If
-		
-		layoutkids() ' we need to do this so the children know we've really changed.
-	End Method
-
-	Rem
-	bbdoc: Callback for window size.
-	about: This event doesn't actually trigger a max size event, but we use it to adjust the client
-	size.
-	End Rem
-	Function OnWindowSize(widget:Byte Ptr, obj:Object)
-		Local win:TGTKWindow = TGTKWindow(obj)
-		If win Then
-			If win.ClientHeight() <> win.oldCH Or win.ClientWidth() <> win.oldCW Then
-				win.oldCH = win.ClientHeight()
-				win.oldCW = win.ClientWidth()
-
-				TGTKContainer(obj).rethink()
-			End If
-		End If
-	End Function
-
-	Rem
-	bbdoc: Callback for window state change.
-	End Rem	
-	Function OnWindowStateChange:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		Local statemask:Int
-		bmx_gtk3maxgui_gdkeventwindowstate(event, Varptr statemask)
-		
-		Local win:TGTKWindow = TGTKWindow(obj)
-		If win Then
-			If statemask & GDK_WINDOW_STATE_ICONIFIED Then
-				win._minimized = Not win._minimized
-			End If
-			
-			If statemask & GDK_WINDOW_STATE_MAXIMIZED Then
-				win._maximized = Not win._maximized
-				
-				' when maximized, we can't be minimized... so clear it
-				If win._maximized Then
-					win._minimized = False
-				End If
-			End If
-
-		End If
-	End Function
-
-	Rem
-	bbdoc: Callback for window close
-	End Rem
-	Function OnWindowClose:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		PostGuiEvent(EVENT_WINDOWCLOSE, TGadget(obj))
-		Return True ' we don't want it to close - that's a user decision :-p
-	End Function
-	
-	Rem
-	bbdoc: Callback for window activate
-	End Rem
-	Function OnWindowActivate(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		PostGuiEvent(EVENT_WINDOWACTIVATE, TGadget(obj))
-	End Function
-
-	Rem
-	bbdoc: Callback for window deactivate
-	about: Not used, but might come in handy at some point...
-	End Rem
-	Function OnWindowDeactivate:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		' We catch this but don't act on it...
-		Return False
-	End Function
-	
-	Function OnDragDrop:Int(widget:Byte Ptr, context:Byte Ptr, x:Int, y:Int, time:Int, obj:Object)
-Print "OnDragDrop"
-	End Function
-
-	Method SetShape:Int(x:Int,y:Int,w:Int,h:Int)
-		If x <> xpos Or y <> ypos Then
-			ignoreMoveEvent = True
-		End If
-		If w <> width Or h <> height Then
-			ignoreSizeEvent = True
-		End If
-		Super.SetShape(Max(x, 0), Max(y, 0), w, h)
-	End Method
-
-	Rem
-	bbdoc: Set the window status text
-	End Rem
-	Method SetStatusText:Int(text:String)
-		If statusbar Then
-
-			Local t:Int, m0:String, m1:String, m2:String
-			m0 = text
-			t = m0.find("~t")
-			If t <> -1 Then
-				m1 = m0[t+1..]
-				m0 = m0[..t]
-			End If
-			t = m1.find("~t")
-			If t <> -1 Then
-				m2 = m1[t+1..]
-				m1 = m1[..t]
-			End If
-			
-			Local mb0:Byte Ptr = m0.ToUTF8String()
-			Local mb1:Byte Ptr = m1.ToUTF8String()
-			Local mb2:Byte Ptr = m2.ToUTF8String()
-			gtk_label_set_text(sblabels[0], mb0)
-			gtk_label_set_text(sblabels[1], mb1)
-			gtk_label_set_text(sblabels[2], mb2)
-			MemFree(mb2)
-			MemFree(mb1)
-			MemFree(mb0)
-
-			If m0.length = 0 And m1.length = 0 And m2.length = 0 Then
-				gtk_widget_show(sblabels[0])
-				gtk_widget_hide(sblabels[1])
-				gtk_widget_hide(sblabels[2])
-			Else
-				If m0.length > 0 Then
-					gtk_widget_show(sblabels[0])
-				Else
-					gtk_widget_hide(sblabels[0])
-				End If
-				
-				If m1.length > 0 Then
-					gtk_widget_show(sblabels[1])
-				Else
-					gtk_widget_hide(sblabels[1])
-				End If
-				
-				If m2.length > 0 Then
-					gtk_widget_show(sblabels[2])
-				Else
-					gtk_widget_hide(sblabels[2])
-				End If
-			End If
-		End If
-	End Method
-
-	Method GetMenu:TGadget()
-		Return Self
-	End Method
-	
-	Method createStatusbar()
-		' our "statusbar" is actually a horizontal box...
-		statusbar = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0)
-		gtk_widget_show(statusbar)
-
-		sblabels = New Byte Ptr[3]
-		
-		For Local i:Int = 0 Until 3
-		
-			Local sblabel:Byte Ptr = gtk_label_new("")
-
-			sblabels[i] = sblabel
-			
-			If i = 0 Then
-				gtk_misc_set_alignment(sblabel, 0, 0.5)
-				'gtk_label_set_yalign(sblabel, 0.5) ' 3.16
-			Else If i = 2 Then
-				gtk_misc_set_alignment(sblabel, 1, 0.5)
-				'gtk_label_set_xalign(sblabel, 1) ' 3.16
-				'gtk_label_set_yalign(sblabel, 0.5) ' 3.16
-			End If
-			
-			gtk_box_pack_start(statusbar, sblabel, True, True, 0)
-		Next
-		
-		' add to the window!
-		gtk_box_pack_start(box, statusbar, False, True, 0)
-	End Method
-
-	Method addToolbar(_toolbar:TGTKToolbar)
-		If toolbar <> Null Then
-			toolbar.free()
-		End If
-
-		toolbar = _toolbar
-
-		' add to the list
-		gtk_box_pack_start(box, toolbar.handle, False, False, 0)
-
-		' we need to move this to the correct place (usually under the menu)
-		If menubar Then
-			gtk_box_reorder_child(box, toolbar.handle, 1)
-		Else
-			gtk_box_reorder_child(box, toolbar.handle, 0)			
-		End If
-
-	End Method
-
-	Method ClientHeight:Int()
-?bmxng
-		Local allocation:GtkAllocation
-?Not bmxng
-		Local allocation:GtkAllocation = New GtkAllocation
-?
-
-		gtk_widget_get_allocation(container, allocation)
-		Local h:Int = allocation.height
-		If h <= 8 Then
-			h = height
-?bmxng
-			Local minReq:GtkRequisition 
-			Local natReq:GtkRequisition
-?Not bmxng
-			Local minReq:GtkRequisition = New GtkRequisition
-			Local natReq:GtkRequisition = New GtkRequisition
-?
-
-			If statusbar Then
-				gtk_widget_get_preferred_size(statusbar, minReq, natReq)
-				h:- natReq.height
-			End If
-			If menubar Then
-				gtk_widget_get_preferred_size(menubar, minReq, natReq)
-				h:- natReq.height
-			End If
-
-		End If
-
-		If toolbar Then
-			h:- toolbar.height
-		End If
-	
-		Return h
-	End Method
-
-	Method ClientWidth:Int()
-
-?bmxng
-		Local allocation:GtkAllocation
-?Not bmxng
-		Local allocation:GtkAllocation = New GtkAllocation
-?
-		gtk_widget_get_allocation(handle, allocation)
-		Local w:Int = allocation.width
-
-		If w <= 8 Then
-			w = width
-		End If
-
-		Return w
-	End Method
-
-	Rem
-	bbdoc: Pop up a popup menu
-	End Rem
-	Method PopupMenu:Int(menu:TGadget,extra:Object=Null)
-		If TGTKMenuItem(menu) Then
-			If TGTKMenuItem(menu).popupMenu Then
-				TGTKMenuItem(menu).popupExtra = extra
-				gtk_menu_popup(TGTKMenuItem(menu).popupMenu, Null, Null, Null, Null, 0, gtk_get_current_event_time())
-			End If
-		End If
-	End Method
-
-	Method free:Int()
-		Super.Free()
-
-		If handle 
-			gtk_widget_destroy(handle)
-		EndIf
-		handle = Null
-
-		gtkWindows.remove(Self)
-	End Method
-
-	Method Activate:Int(cmd:Int)
-		Super.Activate(cmd)
-		
-		If Not visible Return 0
-
-		Select cmd
-			Case ACTIVATE_MAXIMIZE
-				gtk_window_maximize(handle)
-			Case ACTIVATE_MINIMIZE
-				gtk_window_iconify(handle)
-			Case ACTIVATE_RESTORE
-				' since we need to remember if we are maximized while being minimized
-				' we check for minimized first...
-				If _minimized Then
-					gtk_window_deiconify(handle)
-				Else If _maximized Then
-					gtk_window_unmaximize(handle)
-				End If
-			Case ACTIVATE_FOCUS
-				gtk_window_present(handle)
-		End Select
-	End Method
-	
-	Method SetMinimumSize:Int(w:Int, h:Int)
-?bmxng
-		Local geom:GdkGeometry
-?Not bmxng
-		Local geom:GdkGeometry = New GdkGeometry
-?
-		gtk_window_set_geometry_hints(handle, Null, geom, GDK_HINT_MIN_SIZE)
-	End Method
-
-	Rem
-	bbdoc: Sets the window icon with the specified pixmap.
-	End Rem
-	Method setIcon(pix:TPixmap)
-		If pix <> Null Then
-			Local pixmap:TPixmap = pix.convert( PF_RGBA8888 )
-			Local icon:Byte Ptr = gdk_pixbuf_new_from_data(pixmap.pixels, GDK_COLORSPACE_RGB, True, 8, ..
-						pixmap.width, pixmap.height, pixmap.Pitch, Null, Null)
-			gtk_window_set_icon(handle, icon)
-		End If
-	End Method
-	
-	Rem
-	bbdoc: Returns the window state.
-	End Rem
-	Method State:Int()
-		Local flags:Int = Super.state()
-		
-		' Note: you can be maximized and minimized at the same time, so that when
-		' we un-maximize (de-conify) it goes back to maximized.
-		' not sure if we should set them both in this instance. "Not" at the moment...
-		If _minimized Then
-			flags:| STATE_MINIMIZED
-		Else If _maximized Then
-			flags:| STATE_MAXIMIZED
-		End If
-		
-		Return flags
-	End Method
-
-	Method SetText:Int(text:String)
-		Local textPtr:Byte Ptr = text.ToUTF8String()
-		gtk_window_set_title(handle, textPtr)
-		MemFree(textPtr)
-	End Method
-	
-	Method GetText:String()
-		Return String.FromUTF8String(gtk_window_get_title(handle))
-	End Method
-
-	Method toString:String()
-		Return "TGTKWindow"
-	End Method
-End Type
-
-Rem
-bbdoc: A menu item.
-End Rem
-Type TGTKMenuItem Extends TGTKGadget
-	
-	Field popupMenu:Byte Ptr
-
-	Field tag:Int = 0
-	Field ignoreSelection:Int
-	Field isCheckable:Int
-	Field hasMnemonic:Int
-	Field isSeparator:Int
-	Field checked:Int
-	Field text:String
-	Field index:Int
-	Field isStockItem:Int
-	
-	Global popupExtra:Object
-
-	' we use these to remember keycode and modifier just in case we need to make this
-	' menu item a check-type - in which case we delete and create a new one.
-	Field myKeycode:Int
-	Field myModifier:Int
-	
-	Field windowAccelGroup:Byte Ptr
-	
-	Field pixmap:TPixmap
-	Field imagePixbuf:Byte Ptr
-	Field image:Byte Ptr
-	
-	Function CreateMenuItem:TGTKMenuItem(label:String, tag:Int, parent:TGadget)
-		Local this:TGTKMenuItem = New TGTKMenuItem
-
-		this.initMenu(label, tag, parent)
-
-		Return this
-	End Function
-
-	Method initMenu(_label:String, _tag:Int, _parent:TGadget)
-		iclass = GTK_MENUITEM
-		tag = _tag
-		
-		Local originalLabel:String = _label
-
-		If TGTKWindow(_parent) Then
-			windowAccelGroup = TGTKWindow(_parent).accelGroup
-		Else If TGTKMenuItem(_parent)
-			windowAccelGroup = TGTKMenuItem(_parent).windowAccelGroup
-		Else
-			'Throw "menu item has no valid parent"
-			' A popupmenu... perhaps?
-			windowAccelGroup = Null
-		End If
-
-		' localisation
-		If (LocalizationMode() & LOCALIZATION_OVERRIDE) Then
-			MapInsert maxgui_driver._mapLocalized, Self, [_label,""]
-			_label = LocalizeString(_label)
-		End If
-
-		setAccelMapId(_label)
-
-
-		' this is our menu item / text
-		If _label = Null Or _label.length = 0 Then
-			' a separator
-			handle = gtk_separator_menu_item_new()
-			isSeparator = True
-		Else
-	
-			' convert underscores to doubles
-			'_label = _label.replace("_", "__")
-
-			' a normal menu item
-			' Does it have a 
-			Local p:Int = _label.find("&")
-
-			_label = processText(_label)
-			Local _labelPtr:Byte Ptr = _label.ToUTF8String()
-			
-			' does this label have a mnemonic?
-			If p >= 0 Then
-				'_label = _label.replace("&", "_")
-				hasMnemonic = True
-
-				handle = gtk_menu_item_new_with_mnemonic(_labelPtr)
-
-			Else
-
-				handle = gtk_menu_item_new_with_label(_labelPtr)
-
-			End If
-			MemFree(_labelPtr)
-		End If
-
-		text = _label
-
-		' let's hope that at least the parent is set!!
-		If _parent Then
-
-			parent = _parent
-
-			If TGTKWindow(parent) Then
-
-				Assert TGTKWindow(parent).menubar, "Cannot add menu to window created without WINDOW_MENU"
-
-				' add a new menu for the menubar
-				' Note : we never show this!! (on purpose)
-				menu = gtk_menu_new()
-
-				' attach the menu text to the menu
-				gtk_menu_item_set_submenu(handle, menu)
-
-				' add the menu to the menubar
-				' Need to make sure we have a menubar to add it to...
-				' In debug mode we'll have failed the above assertion already.
-				If TGTKWindow(parent).menubar Then
-					gtk_menu_shell_append(TGTKWindow(parent).menubar, handle)
-				End If
-
-			Else If TGTKMenuItem(parent) Then
-
-				If TGTKMenuItem(parent).popupMenu Then
-					gtk_container_add(TGTKMenuItem(parent).popupMenu, handle)
-				Else
-					' we may need to create a sub menu to hold this!
-					If Not TGTKMenuItem(parent).menu Then
-						TGTKMenuItem(parent).menu = gtk_menu_new()
-	
-						' attach the menu text to the menu
-						gtk_menu_item_set_submenu(TGTKMenuItem(parent).handle, TGTKMenuItem(parent).menu)
-	
-					End If
-	
-					gtk_menu_shell_append(TGTKMenuItem(parent).menu, handle)
-					
-				End If
-				' we need to know our position in the menu
-				index = parent.kids.count()
-			End If
-
-			gtk_widget_show(handle)
-
-			' Add an activate signal and store ourself in the menu data
-			If Not TGTKWindow(parent) And Not isSeparator Then
-				addConnection("activate", g_signal_cb2_ret(handle, "activate", MenuSelected, Self, Destroy, 0))
-				g_object_set_data(handle, "_maxmenu", Self)
-			End If
-		Else ' popupmenu...
-			popupMenu = gtk_menu_new()
-
-			' don't add OUR menu item to the list, as it is only a place holder.
-			'gtk_container_add(popupMenu, handle)
-
-			gtk_widget_show(handle)
-		End If
-
-	End Method
-
-	Method SetHotKey:Int(keycode:Int, modifier:Int)
-		myKeycode = keycode
-		myModifier = modifier
-		
-		setAccelEntry(keycode, modifier)
-		
-		' override F10 menu access?
-		If keycode = KEY_F10 And modifier = 0 Then
-			Local settings:Byte Ptr = gtk_settings_get_default()
-			gtk_settings_set_string_property(settings, "gtk-menu-bar-accel", "<alt>F10", AppFile)
-		End If
-	End Method
-
-	Rem
-	bbdoc: Callback function for selecting a menu option.
-	about: Triggers a menu action event.<br>
-	NOTE - We have to ignore "obj" because it is not reliable
-	End Rem
-	Function MenuSelected:Int(widget:Byte Ptr, obj:Object)
-
-		Local _menu:TGTKMenuItem = g_object_get_menudata(widget, "_maxmenu")
-
-		Assert _menu, "Menu data is missing...  !!!!"
-
-		' If this isn't a submenu root (one which has sub menus)
-		' then we can post the event
-		If Not _menu.menu And Not _menu.ignoreSelection Then
-			PostGuiEvent(EVENT_MENUACTION, _menu, _menu.tag,,,,_menu.popupextra)
-			If _menu.popupExtra Then
-				_menu.popupExtra = Null
-			End If
-		End If
-
-		' We need to keep the "checked" flag uptodate...
-		If _menu.isCheckable Then
-			_menu.checked = gtk_check_menu_item_get_active(widget)
-		End If
-		
-		_menu.ignoreSelection = False
-
-		Return True
-
-	End Function
-
-	Method SetSelected:Int(bool:Int)
-
-		' Don't do anything if we are already set...
-		If (checked = bool) And isCheckable Then
-			Return 0
-		End If
-
-		ignoreSelection = True
-
-		' if it's not checkable yet, we need to make it so
-		If Not isCheckable And Not isSeparator And menu = Null Then
-			' remove the current menu
-			If handle Then
-				gtk_widget_destroy(handle)
-				hasAccel = False
-			End If
-
-			Local textPtr:Byte Ptr = text.ToUtf8String()
-			If hasMnemonic Then
-				handle = gtk_check_menu_item_new_with_mnemonic(textPtr)
-			Else
-				handle = gtk_check_menu_item_new_with_label(textPtr)
-			End If
-			MemFree(textPtr)
-			gtk_widget_show(handle)
-
-			' if we originally gave this a keycode / modifier, we need to re-establish it.
-			If myKeycode <> 0 Then
-				SetHotKey(myKeycode, myModifier)
-			End If
-
-			If TGTKWindow(parent) Then
-				' Only insert if menubar exists tho...
-				If TGTKWindow(parent).menubar Then
-					gtk_menu_shell_insert(TGTKWindow(parent).menubar, handle, index)
-				End If
-			Else If TGTKMenuItem(parent) Then
-				If TGTKMenuItem(parent).menu Then
-					gtk_menu_shell_insert(TGTKMenuItem(parent).menu, handle, index)
-				End If
-			EndIf
-
-			' we need to catch toggles!
-			addConnection("toggled", g_signal_cb2_ret(handle, "toggled", MenuSelected, Self, Destroy, 0))
-			g_object_set_data(handle, "_maxmenu", Self)
-
-			isCheckable = True
-
-			' If we are not setting it checked it won't generate a toggle event...
-			If Not bool Then
-				ignoreSelection = False
-			End If
-		End If
-
-		checked = bool
-
-		gtk_check_menu_item_set_active(handle, checked)
-	End Method
-
-	Rem
-	bbdoc: Returns menu state - checked or unchecked
-	End Rem
-	Method State:Int()
-		Local _state:Int = Super.State()
-	
-		If isCheckable Then
-			If gtk_check_menu_item_get_active(handle) Then
-				_state :| STATE_SELECTED
-			End If
-		End If
-
-		Return _state
-	End Method
-
-	Rem
-	bbdoc: Returns the menu text
-	End Rem
-	Method GetText:String()
-		If Not isSeparator Then
-			Return String.FromUTF8String(gtk_label_get_text(gtk_bin_get_child(handle)))
-		End If
-
-		Return ""
-	End Method
-
-	Rem
-	bbdoc: Sets the menu text
-	End Rem
-	Method SetText:Int(label:String)
-		If Not isSeparator Then
-			If label = Null Then
-				label = ""
-			End If
-			
-			text = processText(label)
-
-			Local labelPtr:Byte Ptr = text.ToUTF8String()
-			If label.find("&") >= 0 Then
-				gtk_label_set_text_with_mnemonic(gtk_bin_get_child(handle), labelPtr)
-			Else
-				gtk_label_set_text(gtk_bin_get_child(handle), labelPtr)
-			End If
-			MemFree(labelPtr)
-		End If
-	End Method
-	
-	Method Free:Int()
-		Super.Free()
-
-		If handle
-			gtk_widget_destroy(handle)
-		End If
-		handle = Null
-		menu = Null
-
-		If pixmap Then
-			pixmap = Null
-		End If
-		If image Then
-		'	g_object_unref(image) ' oops.. TODO: we might need this still.
-			image = Null
-		End If
-		If imagePixbuf Then
-			g_object_unref(imagePixbuf)
-			imagePixbuf = Null
-		End If
-
-	End Method
-
-	Method rethink:Int()
-	End Method
-
-	Method DoLayout:Int()
-	End Method
-
-	Method SetPixmap:Int(pix:TPixmap, flags:Int)
-		If Not isSeparator Then
-			If pix Then
-				If PixmapFormat(pix) <> PF_RGBA8888 And PixmapFormat(pix) <> PF_BGRA8888 Then
-					pixmap = pix.convert( PF_RGBA8888 )
-				Else
-					pixmap = pix
-				End If
-				
-				If imagePixbuf Then
-					g_object_unref(imagePixbuf)
-				End If
-	
-				imagePixbuf = gdk_pixbuf_new_from_data(pixmap.pixels, GDK_COLORSPACE_RGB, True, 8, ..
-								pixmap.width, pixmap.height, pixmap.Pitch, Null, Null)
-				
-				If Not image Then
-					image = gtk_image_new()
-				End If
-
-				gtk_image_set_from_pixbuf(image, imagePixbuf)
-			Else
-				If pixmap Then
-					gtk_image_clear(image)
-					pixmap = Null
-				End If
-			End If
-			
-			If image Then
-				' TODO
-				'gtk_image_menu_item_set_image(handle, image)
-			End If
-		End If
-	End Method
-
-	Method toString:String()
-		Return "TGTKMenuItem : " + text + " : " + Super.ToString()
-	End Method
-
-	Method SetEnabled:Int(bool:Int)
-		gtk_widget_set_sensitive(handle, bool)
-	End Method
-
-End Type
-
-Type TGTKIconStrip Extends TIconStrip
-
-	Field images:Byte Ptr[]
-	Field names:String[]
-
-	Function IsNotBlank:Int(pixmap:TPixmap)
-		Local w:Int = pixmap.width
-		Local h:Int = pixmap.height
-		Local c:Int = pixmap.ReadPixel(0,0) 			
-		For Local x:Int = 0 Until h
-			For Local y:Int = 0 Until h
-				If pixmap.ReadPixel(x,y) <> c Then
-					Return True
-				End If
-			Next
-		Next
-	End Function
-	
-	Function Create:TGTKIconStrip(source:Object)
-	
-		Local baseName:String = MilliSecs()
-	
-		Local pix:TPixmap = TPixmap(source)
-		If Not pix Then
-			pix = LoadPixmap(source)
-
-			If Not pix Then
-				Return Null
-			End If
-		End If
-		Local n:Int = pix.width/pix.height
-		If n = 0 Then
-			Return Null
-		End If
-
-		Local pixmap:TPixmap = pix.convert( PF_RGBA8888 )
-
-		Local icons:TGTKIconStrip = New TGTKIconStrip
-		icons.pixmap=pixmap
-		icons.count=n
-		icons.images=New Byte Ptr[n]
-		icons.names = New String[n]
-
-		Local h:Int = pixmap.height
-		Local w:Int = h
-
-		For Local x:Int = 0 Until n
-			Local winpix:TPixmap = pixmap.Window(x*w,0,w,pixmap.height)
-			If IsNotBlank(winpix) Then
-				icons.images[x]= gdk_pixbuf_new_from_data(winpix.pixels, GDK_COLORSPACE_RGB, True, 8, ..
-						w, h, pixmap.Pitch, Null, Null)
-				Local name:String = baseName + "_" + x
-				icons.names[x] = name
-				gtk_icon_theme_add_builtin_icon(name, h, icons.images[x])
-			End If
-		Next
-		Return icons
-	End Function
-
-End Type
-
-Rem
-bbdoc: Base type for button gadgets.
-End Rem
-Type TGTKButton Extends TGTKGadget
-
-	Field hotkey:THotKey
-
-	Field ignoreButtonClick:Int
-
-	Method makeButton(label:String) Abstract
-
-	Method initButton(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		
-		Init(iclass, x, y, w, h, style)
-
-		parent = group
-
-		' localisation
-		If (LocalizationMode() & LOCALIZATION_OVERRIDE) Then
-			MapInsert maxgui_driver._mapLocalized, Self, [label,""]
-			label = LocalizeString(label)
-		End If
-
-		makeButton(label)
-
-		setAccelMapId(label)
-
-		gtk_layout_put(TGTKContainer(parent).container, handle, x, y)
-		gtk_widget_set_size_request(handle, w, Max(h,0))
-
-		sensitivity:| SENSITIZE_MOUSE
-		
-		' Set as default ?
-		If style = BUTTON_OK Then
-			gtk_widget_grab_default(handle)
-		End If
-
-		setShow(True)
-
-		' button clicked handler
-		addConnection("clicked", g_signal_cb2(handle, "clicked", OnButtonClicked, Self, Destroy, 0))
-		' catch right-mouse buttons
-		addConnection("button-press-event", g_signal_cb3_ret(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
-
-		addConnection("enter-notify-event", g_signal_cb3_ret(handle, "enter-notify-event", OnMouseEnter, Self, Destroy, 0))
-		addConnection("leave-notify-event", g_signal_cb3_ret(handle, "leave-notify-event", OnMouseLeave, Self, Destroy, 0))
-
-	End Method
-
-	Rem
-	bbdoc: Callback for button click.
-	End Rem
-	Function OnButtonClicked(widget:Byte Ptr, obj:Object)
-		If Not TGTKButton(obj).ignoreButtonClick Then
-			PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), ButtonState(TGadget(obj)))
-		End If
-		
-		TGTKButton(obj).ignoreButtonClick = False
-	End Function
-
-	Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		Local x:Double, y:Double, button:Int
-		bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
-
-		If button = 3 Then ' right mouse button
-
-			PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),,,x,y)
-
-			Return True
-		End If
-
-		Return False
-	End Function
-
-	Function OnMouseEnter:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-	
-		If TGTKGadget(obj).visible Then
-			PostGuiEvent(EVENT_MOUSEENTER, TGadget(obj))
-		End If
-
-		Return False
-	End Function
-
-	Function OnMouseLeave:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-
-		If TGTKGadget(obj).visible Then
-			PostGuiEvent(EVENT_MOUSELEAVE, TGadget(obj))
-		End If
-
-		Return False
-	End Function
-
-	Rem
-	bbdoc: Sets the button text.
-	End Rem
-	Method SetText:Int(text:String)
-		text = processText(text)
-
-		Local textPtr:Byte Ptr = text.ToUTF8String()
-		gtk_button_set_label(handle, textPtr)
-		MemFree(textPtr)
-		gtk_button_set_use_underline(handle, True)
-	End Method
-
-	Rem
-	bbdoc: Returns the button text.
-	End Rem
-	Method GetText:String()
-		Return String.FromUTF8String(gtk_button_get_label(handle))
-	End Method
-
-	Rem
-	bbdoc: Sets the button text color.
-	End Rem
-	Method SetTextColor:Int(r:Int, g:Int, b:Int)
-		Local color:GdkRGBA = New GdkRGBA(r / 255.0, g / 255.0, b / 255.0)
-		
-		Local buttonLabel:Byte Ptr = gtk_bin_get_child(handle)
-		gtk_widget_override_color(buttonLabel, GTK_STATE_FLAG_NORMAL, color)
-		gtk_widget_override_color(buttonLabel, GTK_STATE_FLAG_ACTIVE, color)
-		gtk_widget_override_color(buttonLabel, GTK_STATE_FLAG_PRELIGHT, color)
-	End Method
-
-	Method free:Int()
-		Super.Free()
-
-		If handle 
-			gtk_widget_destroy(handle)
-		EndIf
-		handle = Null
-
-	End Method
-
-	Rem
-	bbdoc: Sets a hot key for the button.
-	End Rem
-	Method SetHotKey:Int(keycode:Int, modifier:Int)
-		setAccelEntry(keycode, modifier)
-	End Method
-
-	Method toString:String()
-		Return "TGTKButton"
-	End Method
-End Type
-
-Rem
-bbdoc: A push button
-End Rem
-Type TGTKButtonPush Extends TGTKButton
-
-	Function CreateButton:TGTKButtonPush(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Local this:TGTKButtonPush = New TGTKButtonPush
-
-		this.initButton(x, y, w, h, label, group, style)
-
-		Return this
-	End Function
-
-	Method makeButton(label:String)
-
-		label = processText(label)
-		
-		Local labelPtr:Byte Ptr = label.ToUTF8String()
-		handle = gtk_button_new_with_label(labelPtr)
-		MemFree(labelPtr)
-		gtk_button_set_use_underline(handle, True)
-
-		' enable "default" gadget functionality
-		g_object_set_int(handle, "can-default", True)
-	End Method
-
-	Method SetText:Int(text:String)
-		text = processText(text)
-
-		Local textPtr:Byte Ptr = text.ToUTF8String()
-		gtk_button_set_label(handle, textPtr)
-		MemFree(textPtr)
-		gtk_button_set_use_underline(handle, True)
-	End Method
-
-	Method SetPixmap:Int(pix:TPixmap, flags:Int = 0)
-		If pix Then
-			Local pixmap:TPixmap
-			If pix.format <> PF_RGBA8888 Then
-				pixmap = pix.convert( PF_RGBA8888 )
-			Else
-				pixmap = pix
-			End If
-	
-			Local image:Byte Ptr = gtk_image_new_from_pixbuf(gdk_pixbuf_new_from_data(pixmap.pixels, GDK_COLORSPACE_RGB, True, 8, ..
-						pixmap.width, pixmap.height, pixmap.Pitch, Null, Null))
-			If image Then
-				gtk_button_set_image(handle, image)
-				gtk_button_set_image_position(handle, GTK_POS_LEFT)
-			End If
-		End If
-	End Method
-
-	Method toString:String()
-		Return "TGTKButtonPush"
-	End Method
-
-End Type
-
-Rem
-bbdoc: A button which has a toggle-type usage (radio / checkbox)
-End Rem
-Type TGTKToggleButton Extends TGTKButton
-
-	Field isSelected:Int
-
-	Method SetSelected:Int(bool:Int)
-		If bool <> gtk_toggle_button_get_active(handle) Then
-			ignoreButtonClick = True
-		End If
-		
-		gtk_toggle_button_set_active(handle, bool)
-		
-		isSelected = bool
-	End Method
-
-	Method State:Int()
-		Local flags:Int = Super.State()
-
-		If gtk_toggle_button_get_active(handle) Then
-			flags:|STATE_SELECTED
-		End If
-
-		Return flags
-	End Method
-
-	Rem
-	bbdoc: Callback for button click.
-	End Rem
-	Function OnButtonClicked(widget:Byte Ptr, obj:Object)
-		If Not TGTKButton(obj).ignoreButtonClick Then
-			If TGTKToggleButton(obj).isSelected <> gtk_toggle_button_get_active(widget)
-				PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), ButtonState(TGadget(obj)))
-			End If
-			TGTKToggleButton(obj).isSelected = gtk_toggle_button_get_active(widget)
-		End If
-		
-		TGTKButton(obj).ignoreButtonClick = False
-	End Function
-
-	Method disableEvents()
-	End Method
-	
-	Method enableEvents()
-	End Method
-	
-End Type
-
-Rem
-bbdoc: A radio button.
-End Rem
-Type TGTKButtonRadio Extends TGTKToggleButton
-
-	Function CreateButton:TGTKButtonRadio(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Local this:TGTKButtonRadio = New TGTKButtonRadio
-
-		this.initButton(x, y, w, h, label, group, style)
-
-		Return this
-	End Function
-
-	Method makeButton(label:String)
-		Local _group:Byte Ptr = TGTKContainer(parent).radioGroup
-		label = processText(label)
-
-		Local labelPtr:Byte Ptr = label.ToUTF8String()
-		If _group = Null Then
-			handle = gtk_radio_button_new_with_label(Null, labelPtr)
-			gtk_toggle_button_set_active(handle, True)
-			isSelected = True
-		Else
-			handle = gtk_radio_button_new_with_label(_group, labelPtr)
-		End If
-		MemFree(labelPtr)
-		
-		' update the radiogroup, ready for a new radio button...
-		TGTKContainer(parent).radioGroup = gtk_radio_button_get_group(handle)
-		
-		gtk_button_set_use_underline(handle, True)
-		
-		If style & BUTTON_PUSH Then
-			gtk_toggle_button_set_mode(handle, False)
-		End If
-		
-	End Method
-
-	Method SetSelected:Int(bool:Int)
-		disableEvents()
-		
-		gtk_toggle_button_set_active(handle, bool)
-		
-		enableEvents()
-		
-		isSelected = bool
-	End Method
-
-	Function OnButtonClicked(widget:Byte Ptr, obj:Object)
-		TGTKToggleButton(obj).isSelected = gtk_toggle_button_get_active(widget)
-
-		If TGTKToggleButton(obj).isSelected Then
-			PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), ButtonState(TGadget(obj)))
-		End If
-		
-		TGTKButton(obj).ignoreButtonClick = False
-	End Function
-
-	Method disableEvents()
-		For Local gadget:TGTKButtonRadio = EachIn parent.kids
-			Local id:TGTKInteger = TGTKInteger(gadget.connectionMap.ValueForKey("clicked"))
-			If id Then
-				g_signal_handler_disconnect(gadget.handle, id.value)
-			End If
-		Next
-	End Method
-	
-	Method enableEvents()
-		For Local gadget:TGTKButtonRadio = EachIn parent.kids
-			gadget.addConnection("clicked", g_signal_cb2(gadget.handle, "clicked", OnButtonClicked, gadget, Destroy, 0))
-		Next
-	End Method
-
-	Method toString:String()
-		Return "TGTKButtonRadio"
-	End Method
-
-End Type
-
-Rem
-bbdoc: A checkbox button
-End Rem
-Type TGTKButtonCheckbox Extends TGTKToggleButton
-
-	Function CreateButton:TGTKButtonCheckbox(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Local this:TGTKButtonCheckbox = New TGTKButtonCheckbox
-
-		this.initButton(x, y, w, h, label, group, style)
-
-		Return this
-	End Function
-
-	Method makeButton(label:String)
-		label = processText(label)
-		
-		Local labelPtr:Byte Ptr = label.ToUTF8String()
-		handle = gtk_check_button_new_with_label(labelPtr)
-		MemFree(labelPtr)
-		
-		gtk_button_set_use_underline(handle, True)
-
-		If style & BUTTON_PUSH Then
-			gtk_toggle_button_set_mode(handle, False)
-		End If
-
-	End Method
-
-	Method toString:String()
-		Return "TGTKButtonCheckbox"
-	End Method
-
-End Type
-
-Rem
-bbdoc: A label.
-End Rem
-Type TGTKLabel Extends TGTKGadget
-
-	' surrounding frame widget, if any
-	Field frame:Byte Ptr
-	Field hasFrame:Int
-	Field isSeparator:Int
-	Field ebox:Byte Ptr
-
-	Function CreateLabel:TGTKLabel(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Local this:TGTKLabel = New TGTKLabel
-
-		this.initLabel(x, y, w, h, label, group, style)
-
-		Return this
-	End Function
-
-	Method initLabel(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Init(GTK_LABEL, x, y, w, h, style)
-
-		If style & LABEL_FRAME And style & LABEL_SUNKENFRAME Then
-			isSeparator = True
-		End If
-
-		If Not isSeparator Then
-			Local labelPtr:Byte Ptr = label.ToUTF8String()
-			handle = gtk_label_new(labelPtr)
-			MemFree(labelPtr)
-
-			If style & LABEL_RIGHT Then
-				gtk_misc_set_alignment(handle, 1, 0.5)
-			Else If style & LABEL_CENTER Then
-				gtk_misc_set_alignment(handle, 0.5, 0.5)	
-			Else
-				gtk_misc_set_alignment(handle, 0, 0.5)	
-			End If
-
-
-			sensitivity:| SENSITIZE_MOUSE
-			
-			' since a Label can't accept events, we wrap it inside an event box which can
-			ebox = gtk_event_box_new()
-			gtk_event_box_set_visible_window(ebox, False)
-			gtk_widget_add_events(ebox, GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK)
-			
-			addConnection("enter-notify-event", g_signal_cb3_ret(ebox, "enter-notify-event", OnMouseEnter, Self, Destroy, 0))
-			addConnection("leave-notify-event", g_signal_cb3_ret(ebox, "leave-notify-event", OnMouseLeave, Self, Destroy, 0))
-			addConnection("button-press-event", g_signal_cb3_ret(ebox, "button-press-event", OnMouseDown, Self, Destroy, 0))
-
-			' show the box
-			gtk_widget_show(ebox)
-			' add the label to the eventbox
-			gtk_container_add(ebox, handle)
-			
-			If (LocalizationMode() & LOCALIZATION_OVERRIDE) Then
-				LocalizeGadget(Self, label)
-			Else
-				SetText(label)
-			EndIf
-		End If
-
-		' Should we add a frame?
-		If style & LABEL_FRAME Or style & LABEL_SUNKENFRAME Then
-
-			hasFrame = True
-
-			If isSeparator Then
-				If w < h Then
-					frame = gtk_separator_new(GTK_ORIENTATION_VERTICAL)
-				Else
-					frame = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL)
-				End If
-				handle = frame
-			Else
-				frame = gtk_frame_new(Null)
-				If style & LABEL_FRAME Then
-					gtk_frame_set_shadow_type(frame, GTK_SHADOW_ETCHED_IN)
-				Else
-					gtk_frame_set_shadow_type(frame, GTK_SHADOW_IN)
-				End If
-
-				gtk_container_add(frame, ebox)
-
-			End If
-
-			gtk_layout_put(TGTKContainer(group).container, frame, x, y)
-			gtk_widget_set_size_request(frame, w, Max(h,0))
-
-		Else
-			gtk_layout_put(TGTKContainer(group).container, ebox, x, y)
-			gtk_widget_set_size_request(handle, w, Max(h,0))
-		End If
-
-		setShow(True)
-
-	End Method
-
-	Rem
-	bbdoc: Show or Hide the label
-	End Rem
-	Method SetShow:Int(truefalse:Int)
-		visible = truefalse
-		mySetVisible = visible
-		
-		If hasFrame Then
-			If truefalse Then
-				gtk_widget_show(frame)
-			Else
-				gtk_widget_hide(frame)
-			EndIf
-		End If
-
-		If Not isSeparator Then
-			If truefalse Then
-				gtk_widget_show(handle)
-				gtk_widget_show(ebox)
-			Else
-				gtk_widget_hide(ebox)
-			EndIf
-		End If
-	End Method
-
-	Method SetText:Int(text:String)
-		If Not isSeparator Then
-			Local textPtr:Byte Ptr = text.ToUtf8String()
-			gtk_label_set_text(handle, textPtr)
-			MemFree(textPtr)
-		End If
-	End Method
-	
-	Method GetText:String()
-		If Not isSeparator Then
-			Return String.FromUTF8String(gtk_label_get_text(handle))
-		End If
-		Return Null
-	End Method
-
-	Method free:Int()
-		Super.Free()
-
-		If frame
-			gtk_widget_destroy(frame)
-		Else
-			If ebox Then
-				gtk_widget_destroy(ebox)
-			End If
-		EndIf
-		handle = Null
-		frame = Null
-		ebox = Null
-
-	End Method
-
-	Method setToolTip:Int(tip:String)
-	
-		If Not isSeparator Then
-			If tip And tip.length > 0 Then
-				Local tipPtr:Byte Ptr = tip.ToUTF8String()
-				gtk_widget_set_tooltip_text(ebox, tipPtr)
-				MemFree(tipPtr)
-			Else
-				gtk_widget_set_has_tooltip(ebox, False)
-			End If
-		Else
-			If tip And tip.length > 0 Then
-				Local tipPtr:Byte Ptr = tip.ToUTF8String()
-				gtk_widget_set_tooltip_text(handle, tipPtr)
-				MemFree(tipPtr)
-			Else
-				gtk_widget_set_has_tooltip(handle, False)
-			End If
-		End If
-	End Method
-
-	Method Rethink:Int()
-		If frame Then
-			gtk_layout_move(TGTKContainer(parent).container, frame, Max(xpos, 0), Max(ypos, 0))
-			gtk_widget_set_size_request(frame, Max(width,0), Max(height,0))
-		Else If handle Then
-			gtk_layout_move(TGTKContainer(parent).container, ebox, Max(xpos, 0), Max(ypos, 0))
-			gtk_widget_set_size_request(handle, Max(width,0), Max(height,0))
-		End If
-	End Method
-
-	Function OnMouseEnter:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-	
-		If TGTKGadget(obj).visible Then
-			PostGuiEvent(EVENT_MOUSEENTER, TGadget(obj))
-		End If
-		
-		Return False
-	End Function
-
-	Function OnMouseLeave:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-
-		If TGTKGadget(obj).visible Then
-			PostGuiEvent(EVENT_MOUSELEAVE, TGadget(obj))
-		End If
-		
-		Return False
-	End Function
-
-	Rem
-	bbdoc: Callback For mouse button press.
-	End Rem
-	Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		Local x:Double, y:Double, button:Int
-		bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
-		
-		If button = 3 Then ' right mouse button
-
-			PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),,,x,y)
-
-		Else ' other mouse buttons
-			If button = 2 Then
-				button = 3
-			End If
-
-			PostGuiEvent(EVENT_MOUSEDOWN, TGadget(obj),button,,x,y)
-		End If
-		
-		Return True
-	End Function
-
-	Rem
-	bbdoc: Sets the label text color.
-	End Rem
-	Method SetTextColor:Int(r:Int, g:Int, b:Int)
-		Local color:GdkRGBA = New GdkRGBA(r / 255.0, g / 255.0, b / 255.0)
-
-		gtk_widget_override_color(handle, GTK_STATE_FLAG_NORMAL, color)
-
-	End Method
-
-	Method toString:String()
-		Return "TGTKLabel"
-	End Method
-End Type
-
-
-Rem
-bbdoc: Base type for editable gadgets (textfield / textarea).
-End Rem
-Type TGTKEditable Extends TGTKGadget
-
-	Field ignoreTextChange:Int
-
-	Method Activate:Int(cmd:Int)
-		Super.Activate(cmd)
-
-	End Method
-
-	Function OnTextChanged(widget:Byte Ptr, obj:Object)
-		If Not TGTKEditable(obj).ignoreTextChange Then
-			PostGuiEvent(EVENT_GADGETACTION, TGadget(obj))
-		End If
-		
-		If TGTKEditable(obj).ignoreTextChange Then
-			TGTKEditable(obj).ignoreTextChange:-1
-		End If
-	End Function
-
-	' key handler stuff - filtering etc
-	Function OnKeyDown:Int(widget:Byte Ptr, gdkEvent:Byte Ptr, obj:Object)
-		Local source:TGTKEditable = TGTKEditable(obj)
-
-		' only if we are using a filter...
-		If source And source.eventfilter <> Null Then
-			Local _key:Int, _mods:Int
-			bmx_gtk3maxgui_gdkeventkey(gdkEvent, Varptr _key, Varptr _mods)
-			Local key:Int = TGTKKeyMap.mapBack(_key)
-			Local mods:Int = TGTKKeyMap.mapModifierBack(_mods)
-			
-			Local event:TEvent=HotKeyEvent( key,mods, Null )
-			If event Then
-				event.emit()
-				Return True
-			EndIf
-
-			event = CreateEvent(EVENT_KEYDOWN, source, key, mods)
-			
-			If Not source.eventfilter(event, source.context) Then
-				Return True
-			End If
-
-			Local char:Int = gdk_keyval_to_unicode(_key)
-			' we sometimes get 0 from this function when key is valid... so set it to key just so that it has a value.
-			If char = 0 And key <> 0 Then
-				char = key
-			End If
-
-			event = CreateEvent(EVENT_KEYCHAR, source, char, mods)
-			If Not source.eventfilter(event, source.context) Then
-				Return True
-			End If
-		EndIf
-
-		Return False
-	End Function
-End Type
-
-Rem
-bbdoc: A Text field.
-End Rem
-Type TGTKTextField Extends TGTKEditable
-
-	Field isPassword:Int
-	
-	Function CreateTextField:TGTKTextField(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Local this:TGTKTextField = New TGTKTextField
-
-		this.initTextField(x, y, w, h, label, group, style)
-
-		Return this
-	End Function
-
-	Method initTextField(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-
-		handle = gtk_entry_new()
-
-		Init(GTK_TEXTFIELD, x, y, w, h, style)
-
-		If style Then
-			isPassword = True
-
-			gtk_entry_set_visibility(handle, False)
-		End If
-
-		' causes the default gadget to be activated when Enter is pressed inside this Text Field.
-		g_object_set_int(handle, "activates-default", True)
-
-		setShow(True)
-
-		gtk_layout_put(TGTKContainer(group).container, handle, x, y)
-		gtk_widget_set_size_request(handle, w, Max(h,0))
-
-
-		' add callbacks
-		addConnection("changed", g_signal_cb2(handle, "changed", OnTextChanged, Self, Destroy, 0))
-		addConnection("key-press-event", g_signal_cb3_ret(handle, "key-press-event", OnKeyDown, Self, Destroy, 0))
-		addConnection("focus-out-event", g_signal_cb3_ret(handle, "focus-out-event", OnFocusLost, Self, Destroy, 0))
-		' catch right-mouse buttons
-		addConnection("button-press-event", g_signal_cb3_ret(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
-
-	End Method
-
-	Rem
-	bbdoc: Returns the textfield text.
-	End Rem
-	Method GetText:String()
-		Return String.FromUTF8String(gtk_entry_get_text(handle))
-	End Method
-
-	Rem
-	bbdoc: Sets the textfield text.
-	End Rem
-	Method SetText:Int(txt:String)
-		If txt = Null
-			txt = ""
-		End If
-		
-		' when set to blank, it raises 2 change events?
-		If txt = "" And GetText() <> "" Then
-			ignoreTextChange:+1
-		End If
-		
-		If txt <> GetText() Then
-			ignoreTextChange:+1
-		End If
-		
-		Local txtPtr:Byte Ptr = txt.ToUTF8String()
-		gtk_entry_set_text(handle, txtPtr)
-		MemFree(txtPtr)
-	End Method
-
-	Method free:Int()
-		Super.Free()
-
-		If handle 
-			gtk_widget_destroy(handle)
-		EndIf
-		handle = Null
-
-	End Method
-
-	Method Activate:Int(cmd:Int)
-		Super.Activate(cmd)
-
-		Select cmd
-			Case ACTIVATE_CUT
-				gtk_editable_cut_clipboard(handle)
-			Case ACTIVATE_COPY
-				gtk_editable_copy_clipboard(handle)
-			Case ACTIVATE_PASTE
-				gtk_editable_paste_clipboard(handle)
-		End Select
-	End Method
-	
-	Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		Local x:Double, y:Double, button:Int
-		bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
-
-		If button = 3 Then ' right mouse button
-
-			PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),,,x,y)
-
-			Return True
-		End If
-
-		Return False
-	End Function
-
-	Method toString:String()
-		Return "TGTKTextField"
-	End Method
-
-End Type
-
-Rem
-bbdoc: A base for list gadgets.
-End Rem
-Type TGTKList Extends TGTKGadget
-
-	Field icons:TGTKIconStrip
-
-	Field _store:Byte Ptr
-	Field _selection:Byte Ptr
-	' sometimes we need to ignore events because we made them ourselves - rather than the user selecting
-	' something.
-	Field ignoreListChangeEvent:Int
-
-	Method SetIconStrip:Int(iconstrip:TIconStrip)
-		icons = TGTKIconStrip(iconstrip)
-	End Method
-
-	Method populateListRow(index:Int, text:String, tip:String, icon:Int, iter:Byte Ptr)
-
-		' need to put the string in a GValue for placing into the list
-		Local _value:Byte Ptr = bmx_gtk3_gvalue_new(G_TYPE_STRING)
-		'g_value_init(_value, G_TYPE_STRING)
-		Local textPtr:Byte Ptr = text.ToUTF8String()
-	  	g_value_set_string(_value, textPtr)
-		MemFree(textPtr)
-	
-		' set the row value
-		If TGTKListbox(Self) Or TGTKComboBox(Self) Then
-			gtk_list_store_set_value(_store, iter, 1, _value)
-		Else
-			gtk_tree_store_set_value(_store, iter, 1, _value)
-		End If
-	
-		' tidy up !
-		g_value_unset(_value)
-
-
-		Local image:Byte Ptr
-
-		If icons And icon>=0 Then
-			image = icons.images[icon]
-		End If
-
-		If image Then
-			' Insert the appropriate icon
-
-			g_value_init(_value, gdk_pixbuf_get_type())
-		  	g_value_set_object(_value, image)
-		
-			' set the row value
-			If TGTKListbox(Self) Or TGTKComboBox(Self) Then
-				gtk_list_store_set_value(_store, iter, 0, _value)
-			Else
-				gtk_tree_store_set_value(_store, iter, 0, _value)
-			End If
-		
-			' tidy up !
-			g_value_unset(_value)
-		Else
-			' clear out an icon if one is present in this entry
-
-			g_value_init(_value, gdk_pixbuf_get_type())
-		  	g_value_set_object(_value, Null)
-		
-			' set the row value
-			If TGTKListbox(Self) Or TGTKComboBox(Self) Then
-				gtk_list_store_set_value(_store, iter, 0, _value)
-			Else
-				gtk_tree_store_set_value(_store, iter, 0, _value)
-			End If
-		
-			' tidy up !
-			g_value_unset(_value)
-		End If
-
-		bmx_gtk3_gvalue_free(_value)
-		
-	End Method
-
-	Method initColumns()
-		' add a column to the list :
-		Local col:Byte Ptr = gtk_tree_view_column_new()
-
-		' pack column into list 
-		gtk_tree_view_append_column(handle, col)
-
-		Local pixRenderer:Byte Ptr = gtk_cell_renderer_pixbuf_new()
-		Local textRenderer:Byte Ptr = gtk_cell_renderer_text_new()
-
-		' pack cell renderers into column
-		gtk_tree_view_column_pack_start(col, pixRenderer, False)
-		gtk_tree_view_column_pack_end(col, textRenderer, True)
-
-		gtk_tree_view_column_add_attribute(col, pixRenderer, "pixbuf", 0)
-		gtk_tree_view_column_add_attribute(col, textRenderer, "text", 1)
-	End Method
-
-	Function OnSelectionChanged(_sel:Byte Ptr, obj:Object) Abstract
-
-End Type
-
-Rem
-bbdoc: A combo box
-End Rem
-Type TGTKComboBox Extends TGTKList
-
-	Field isEditable:Int
-
-	Function CreateComboBox:TGTKComboBox(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Local this:TGTKComboBox = New TGTKComboBox
-
-		this.initComboBox(x, y, w, h, label, group, style)
-
-		Return this
-	End Function
-
-	Method initComboBox(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-
-		If style = COMBOBOX_EDITABLE Then
-			isEditable = True
-			handle = gtk_combo_box_new_with_entry()
-		Else
-			handle = gtk_combo_box_new()
-		End If
-
-		Init(GTK_COMBOBOX, x, y, w, h, style)
-		
-		' Create a list store of pixbuf and string (the two displayable columns)
-		_store = gtk_list_store_new(2, gdk_pixbuf_get_type(), G_TYPE_STRING)
-
-		gtk_combo_box_set_model(handle, _store)
-		
-		' for editable, we need to tell it which column contains the text part
-		If isEditable Then
-			gtk_combo_box_set_entry_text_column(handle, 1)
-		End If
-		initColumns()
-
-		setShow(True)
-
-		gtk_layout_put(TGTKContainer(group).container, handle, x, y)
-		gtk_widget_set_size_request(handle, w, Max(h,0))
-		
-		addConnection("changed", g_signal_cb2(handle, "changed", OnSelectionChanged, Self, Destroy, 0))
-		' catch right-mouse buttons
-		addConnection("button-press-event", g_signal_cb3_ret(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
-
-	End Method
-	
-	Method initColumns()
-		gtk_cell_layout_clear(handle)
-
-		Local pixRenderer:Byte Ptr = gtk_cell_renderer_pixbuf_new()
-		Local textRenderer:Byte Ptr = gtk_cell_renderer_text_new()
-
-		' pack cell renderers into layout
-		gtk_cell_layout_pack_start(handle, pixRenderer, False)
-		gtk_cell_layout_pack_end(handle, textRenderer, True)
-
-		gtk_cell_layout_add_attribute(handle, pixRenderer, "pixbuf", 0)
-		gtk_cell_layout_add_attribute(handle, textRenderer, "text", 1)
-
-	End Method
-
-	Rem
-	bbdoc: Callback for selection change.
-	End Rem
-	Function OnSelectionChanged(widget:Byte Ptr, obj:Object)
-		Local row:Int = TGTKComboBox(obj).SelectedItem()
-		PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), row,,,,TGadget(obj).ItemExtra(row))
-	End Function
-
-	Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		Local x:Double, y:Double, button:Int
-		bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
-
-		If button = 3 Then ' right mouse button
-
-			Local treePath:Byte Ptr
-			Local row:Int = TGTKComboBox(obj).SelectedItem()
-			
-			If row >= 0 Then
-				PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),row,,x,y,TGTKList(obj).items[row].extra)
-			Else
-				PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),row,,x,y)
-			End If
-			Return True
-		End If
-
-		Return False
-	End Function
-	
-	Method InsertListItem:Int(index:Int, text:String, tip:String, icon:Int, tag:Object)
-		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
-
-		gtk_list_store_insert(_store, iter, index)
-
-		populateListRow(index, text, tip, icon, iter)
-		bmx_gtk3_gtktreeiter_free(iter)
-	End Method
-
-	Method SetListItem:Int(index:Int, text:String, tip:String, icon:Int, tag:Object)
-		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
-		Local found:Int = gtk_tree_model_iter_nth_child(_store, iter, Null, index)
-
-		If found Then
-			populateListRow(index, text, tip, icon, iter)
-		End If
-		bmx_gtk3_gtktreeiter_free(iter)
-	End Method
-
-	Method SelectedItem:Int()
-		Return gtk_combo_box_get_active(handle)
-	End Method
-
-	Method SetListItemState:Int(index:Int ,state:Int)
-		If state & STATE_SELECTED Then
-			gtk_combo_box_set_active(handle, index)
-		End If
-	End Method
-
-	Method ClearListItems:Int()
-		gtk_list_store_clear(_store)
-	End Method
-
-	Method RemoveListItem:Int(index:Int)
-		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
-		Local found:Int = gtk_tree_model_iter_nth_child(_store, iter, Null, index)
-		
-		If found Then
-			gtk_list_store_remove(_store, iter)
-		End If
-		bmx_gtk3_gtktreeiter_free(iter)
-	End Method
-
-	Method ItemText:String(index:Int)
-		If index < 0 Or index >= items.length Then
-			Return GetText()
-		End If
-		Return items[index].text
-	End Method
-
-	Method GetText:String()
-			Local st:String
-			Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
-			Local found:Int = gtk_combo_box_get_active_iter(handle, iter)
-			
-			If found Then
-				Local _value:Byte Ptr = bmx_gtk3_gvalue_new(G_TYPE_STRING)
-				
-				gtk_tree_model_get_value(_store, iter, 0, _value)
-				
-				st = String.FromUTF8String(g_value_get_string(_value))
-				
-				' tidy up !
-				g_value_unset(_value)
-
-				bmx_gtk3_gvalue_free(_value)
-			End If
-			
-			Return st
-	End Method
-
-	Method Free:Int()
-		Super.Free()
-
-		If handle 
-			gtk_widget_destroy(handle)
-		EndIf
-		handle = Null
-	End Method
-
-	Method toString:String()
-		Return "TGTKComboBox"
-	End Method
-
-End Type
-
-Rem
-bbdoc: A scrollable list.
-End Rem
-Type TGTKListWithScrollWindow Extends TGTKList
-
-	Field scrollWindow:Byte Ptr
-
-	Method Init(GadgetClass:Int, x:Int, y:Int, w:Int, h:Int, style:Int)
-		Super.init(iclass, x, y, w, h, style)
-	
-		handle = gtk_tree_view_new()
-		gtk_tree_view_set_headers_visible(handle, False)
-
-		' a reference to the selection object
-		_selection = gtk_tree_view_get_selection(handle)
-
-		' currently we only support SINGLE row selection
-		gtk_tree_selection_set_mode(_selection, GTK_SELECTION_SINGLE)
-
-
-		scrollWindow = gtk_scrolled_window_new(Null, Null)
-		' set container resize mode
-		gtk_container_set_resize_mode(scrollWindow, GTK_RESIZE_QUEUE)
-		' set scrollbar policy
-		gtk_scrolled_window_set_policy(scrollWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC)
-		' show
-		gtk_widget_show(scrollWindow)
-
-		' add the html view to the scroll view
-		gtk_container_add(scrollWindow, handle)
-
-
-		' add callback
-		addConnection("changed", g_signal_cb2(_selection, "changed", OnSelectionChanged, Self, Destroy, 0))
-		
-		' catch right-mouse buttons
-		addConnection("button-press-event", g_signal_cb3_ret(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
-	End Method
-
-	Method SetShow:Int(truefalse:Int)
-		visible = truefalse
-		mySetVisible = visible
-		
-		If truefalse Then
-			gtk_widget_show(scrollWindow)
-			gtk_widget_show(handle)
-		Else
-			gtk_widget_hide(scrollWindow)
-			gtk_widget_hide(handle)
-		EndIf
-
-		UpdateChildVisibility()
-	End Method
-
-	Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-	End Function
-
-End Type
-
-Rem
-bbdoc: List box
-End Rem
-Type TGTKListbox Extends TGTKListWithScrollWindow
-
-
-	Field currentSelection:Int = -1
-
-	Function CreateListBox:TGTKListbox(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Local this:TGTKListbox = New TGTKListbox
-
-		this.initListBox(x, y, w, h, label, group, style)
-
-		Return this
-	End Function
-
-	Method initListBox(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Init(GTK_LISTBOX, x, y, w, h, style)
-
-		' had intended using GTK_TYPE_PIXBUF here but it's a different value every time!?!
-		_store = gtk_list_store_new(2, gdk_pixbuf_get_type(), G_TYPE_STRING)
-
-		initColumns()
-
-		gtk_tree_view_set_model(handle, _store)
-
-		' remove *our* reference to the store... when the list is destroyed this will be too
-		g_object_unref(_store)
-
-		addConnection("row-activated", g_signal_cb4(handle, "row-activated", OnRowActivated, Self, Destroy, 0))
-
-		SetShow(True)
-
-		gtk_layout_put(TGTKContainer(group).container, scrollwindow, x, y)
-		gtk_widget_set_size_request(handle, w, Max(h,0))
-
-	End Method
-
-	Method InsertListItem:Int(index:Int, text:String, tip:String, icon:Int, extra:Object)
-		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
-
-		gtk_list_store_insert(_store, iter, index)
-
-		populateListRow(index, text, tip, icon, iter)
-		bmx_gtk3_gtktreeiter_free(iter)
-	End Method
-
-	Method SetListItem:Int(index:Int, text:String, tip:String, icon:Int, tag:Object)
-		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
-		Local found:Int = gtk_tree_model_iter_nth_child(_store, iter, Null, index)
-		If found Then
-			populateListRow(index, text, tip, icon, iter)
-		End If
-		bmx_gtk3_gtktreeiter_free(iter)
-	End Method
-
-	Rem
-	bbdoc: Removes an item from the list at the given index
-	End Rem
-	Method RemoveListItem:Int(index:Int)
-		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
-		Local found:Int = gtk_tree_model_iter_nth_child(_store, iter, Null, index)
-		
-		If found Then
-			If gtk_tree_selection_iter_is_selected(_selection, iter) Then
-				ignoreListChangeEvent = True
-			End If
-			gtk_list_store_remove(_store, iter)
-		End If
-		bmx_gtk3_gtktreeiter_free(iter)
-	End Method
-
-	Method SetListItemState:Int(index:Int, state:Int)
-		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
-
-		Local found:Int = gtk_tree_model_iter_nth_child(_store, iter, Null, index)
-
-		If found Then
-			If state & STATE_SELECTED Then
-				ignoreListChangeEvent = True
-				gtk_tree_selection_select_iter(_selection, iter)
-			Else
-				If gtk_tree_selection_iter_is_selected(_selection, iter) Then
-					ignoreListChangeEvent = True
-				End If
-					
-				gtk_tree_selection_unselect_iter(_selection, iter)
-			End If
-		End If
-		bmx_gtk3_gtktreeiter_free(iter)
-	End Method
-
-	Method ListItemState:Int(index:Int)
-		Local state:Int = 0
-		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
-
-		Local found:Int = gtk_tree_model_iter_nth_child(_store, iter, Null, index)
-
-		If found Then
-			If gtk_tree_selection_iter_is_selected(_selection, iter) Then
-				state:| STATE_SELECTED
-			End If
-		End If
-
-		bmx_gtk3_gtktreeiter_free(iter)
-		Return state
-	End Method
-
-	Function OnSelectionChanged(_sel:Byte Ptr, obj:Object)
-		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
-
-		Local row:Int = -1
-		Local selected:Int = gtk_tree_selection_get_selected(_sel, Null, iter)
-		If selected Then
-			Local path:Byte Ptr = gtk_tree_model_get_string_from_iter(TGTKList(obj)._store, iter)
-			row = String.fromCString(path).toInt()
-			g_free(path)
-		End If
-
-		If TGTKListbox(obj).currentSelection <> row Then
-		
-			TGTKListbox(obj).currentSelection = row
-			
-			If Not TGTKList(obj).ignoreListChangeEvent Then
-				PostGuiEvent(EVENT_GADGETSELECT, TGadget(obj), row,,,,TGadget(obj).ItemExtra(row))
-			End If
-		End If
-		TGTKList(obj).ignoreListChangeEvent = False
-		
-		bmx_gtk3_gtktreeiter_free(iter)
-	End Function
-
-	Rem
-	bbdoc: Callback for listbox activation (double-click).
-	End Rem
-	Function OnRowActivated(widget:Byte Ptr, treePath:Byte Ptr, treeviewColumn:Byte Ptr, obj:Object)
-		Local p:Byte Ptr = gtk_tree_path_to_string(treePath)
-		Local row:Int
-		
-		If p <> Null Then
-			row = String.fromCString(p).toInt()
-		End If
-
-		' clean up mem
-		g_free(p)
-
-		If row >= 0 Then
-			PostGuiEvent(EVENT_GADGETACTION, TGadget(obj),row ,,,,TGTKList(obj).items[row].extra)
-		Else
-			PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), row)
-		End If
-	End Function
-
-	Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		Local x:Double, y:Double, button:Int
-		bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
-
-		If button = 3 Then ' right mouse button
-
-			Local treePath:Byte Ptr
-			Local row:Int = -1
-			
-		     ' Get tree path For row that was clicked
-			If gtk_tree_view_get_path_at_pos(widget, Int(x), Int(y), Varptr treePath, Null, Null, Null) Then
-				Local p:Byte Ptr = gtk_tree_path_to_string(treePath)
-
-				
-				If p <> Null Then
-					row = String.fromCString(p).toInt()
-				End If
-
-				' clean up mem
-				g_free(p)
-				gtk_tree_path_free(treePath)
-			End If
-		
-			If row >= 0 Then
-				PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),row,,x,y,TGTKList(obj).items[row].extra)
-			Else
-				PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),row,,x,y)
-			End If
-			Return True
-		End If
-
-		Return False
-	End Function
-	
-	Method ClearListItems:Int()
-		If gtk_tree_selection_get_selected(_selection, Null, Null) Then
-			ignoreListChangeEvent = True
-		End If
-		gtk_list_store_clear(_store)
-	End Method
-
-	Method rethink:Int()
-		If handle Then
-			gtk_layout_move(TGTKContainer(parent).container, scrollwindow, Max(xpos, 0), Max(ypos, 0))
-			gtk_widget_set_size_request(scrollwindow, Max(width,0), Max(height,0))
-		End If
-	End Method
-
-	Method Free:Int()
-		Super.free()
-
-		' destroying the widget should destroy the handle (list) too.
-		If scrollWindow Then
-			gtk_widget_destroy(scrollWindow)
-		End If
-		
-		scrollWindow = Null
-		handle = Null
-
-	End Method
-
-	Method toString:String()
-		Return "TGTKListbox"
-	End Method
-
-End Type
-
-Rem
-bbdoc: A node in the tree view.
-End Rem
-Type TGTKTreeViewNode Extends TGTKListWithScrollWindow
-
-	' is this node the root node?
-	Field isRoot:Int
-	' internal representation of node position in the tree
-	Field _path:String
-	' direct access to the node in the tree
-	Field myIter:Byte Ptr
-	' icon to display for this node
-	Field _icon:Int
-	' flag to prevent non-user events from firing
-	Field ignoreExpand:Int
-	Field ignoreCollapse:Int
-	' text of this node
-	Field _text:String
-
-	Function _createNode:TGTKTreeViewNode(parent:TGTKTreeViewNode, index:Int)
-		Local this:TGTKTreeViewNode = New TGTKTreeViewNode
-
-		this.kids = New TEList
-
-		this.handle = parent.handle
-		this._store = parent._store
-		this._selection = parent._selection
-		this.parent = parent
-		this.icons = parent.icons
-
-		this.myIter = bmx_gtk3_gtktreeiter_new()
-
-		this.refreshPath(index)
-		
-		Return this
-	End Function
-
-	Method refreshPath(index:Int)
-		Assert myIter, "Null Iterator!"
-	
-		If parent Then
-			_path = TGTKTreeViewNode(parent)._path
-			If TGTKTreeViewNode(parent)._path.length > 0 Then
-				_path:+ ":"
-			End If
-		Else
-			_path = ""
-		End If
-		_path:+ index
-
-		gtk_tree_model_get_iter_from_string(_store, myIter, _path)
-	End Method
-
-	Method refreshChildPaths()
-		Local i:Int = 0
-		For Local child:TGTKTreeViewNode = EachIn kids
-			child.refreshPath(i)
-			child.refreshChildPaths()
-			i:+ 1
-		Next
-	End Method
-
-	Function OnSelectionChanged(_sel:Byte Ptr, obj:Object)
-		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
-		Local node:TGTKTreeViewNode = Null
-		Local selected:Int = gtk_tree_selection_get_selected(_sel, Null, iter)
-		If selected Then
-			Local p:Byte Ptr = gtk_tree_model_get_string_from_iter(TGTKList(obj)._store, iter)
-			node = TGTKTreeViewNode(obj).findNodeFromPath(String.FromCString(p))
-			g_free(p)
-		End If
-
-		If Not TGTKList(obj).ignoreListChangeEvent Then
-			PostGuiEvent(EVENT_GADGETSELECT, TGadget(obj),,,,,node)
-		End If
-		TGTKList(obj).ignoreListChangeEvent = False
-		bmx_gtk3_gtktreeiter_free(iter)
-	End Function
-
-	Rem
-	bbdoc: Returns the root node for this tree
-	End Rem
-	Method RootNode:TGadget()
-		If Not isRoot Then
-			Return parent.RootNode()
-		End If
-		Return Self
-	End Method
-
-	Rem
-	bbdoc: Inserts a new node as a child at the specified index.
-	End Rem
-	Method InsertNode:TGadget(index:Int, text:String, icon:Int)
-		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
-		Local childNode:TGTKTreeViewNode
-
-		' create a new row in the tree
-		If isRoot Then
-			If index < 0 Then
-				gtk_tree_store_append(_store, iter, Null)
-			Else
-				gtk_tree_store_insert(_store, iter, Null, index)
-			End If
-
-		Else
-			If index < 0 Then
-				gtk_tree_store_append(_store, iter, myIter)
-			Else
-				gtk_tree_store_insert(_store, iter, myIter, index)
-			End If
-		End If
-
-		' add the text / icon to the tree
-		populateListRow(index, text, Null, icon, iter)
-
-		' add the child to the parent kids
-		If index < 0 Or index = CountKids() Then
-			childNode = TGTKTreeViewNode._createNode(Self, CountKids())
-			childNode._text = text
-			kids.addLast(childNode)
-		Else
-			childNode = TGTKTreeViewNode._createNode(Self, index)
-			childNode._text = text
-			TEList(kids).insertElementAt(childNode, index)
-			refreshChildPaths()
-		End If
-
-		childNode._icon = icon
-		
-		If (LocalizationMode() & LOCALIZATION_OVERRIDE) Then
-			LocalizeGadget(childNode, text)
-		Else
-			childNode.SetText(text)
-		EndIf
-
-		bmx_gtk3_gtktreeiter_free(iter)
-		Return childNode
-	End Method
-
-	Rem
-	bbdoc: Changes the tree node text and icon
-	End Rem
-	Method ModifyNode:Int(text:String, icon:Int)
-		' not allowed to modify the root node... quietly ignore the request.
-		If isRoot Then
-			Return 0
-		End If
-
-		_text = text
-		populateListRow(-1, text, Null, icon, myIter)
-	End Method
-
-	Rem
-	bbdoc: Returns the currently selected tree node or null if none selected
-	End Rem
-	Method SelectedNode:TGadget()
-
-		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
-		If gtk_tree_selection_get_selected(_selection, Null, iter) Then
-			Local path:Byte Ptr = gtk_tree_model_get_path(_store, iter)
-
-			Local p:Byte Ptr = gtk_tree_path_to_string(path)
-			Local node:TGTKTreeViewNode = findNodeFromPath(String.FromCString(p))
-
-			g_free(p)
-			gtk_tree_path_free(path)
-			
-			bmx_gtk3_gtktreeiter_free(iter)
-			Return node
-		End If
-
-		bmx_gtk3_gtktreeiter_free(iter)
-		Return Null
-	End Method
-
-	Rem
-	bbdoc: Returns the number of child nodes
-	End Rem
-	Method CountKids:Int()
-		Return kids.count()
-	End Method
-
-	Method Free:Int()
-
-		Super.free()
-
-		If isRoot Then
-			If scrollWindow Then
-				gtk_widget_destroy(scrollWindow)
-			End If
-
-			scrollWindow = Null
-			handle = Null
-		Else
-			' this should always be true... if not, we really want to throw an assertion.
-			' Assert myIter, "Trying to Free() a node twice?"
-			If myIter Then
-				gtk_tree_store_remove(_store, myIter)
-				bmx_gtk3_gtktreeiter_free(myIter)
-				myIter = Null
-				TGTKTreeViewNode(parent).refreshChildPaths()
-			End If
-		End If
-		
-	End Method
-
-	' search always begins from the tree root, so we only need to look through the 
-	' children.. ie. downwards
-	' TODO : make this more efficient...  we should be able to use the path to skip
-	' searching of child nodes of nodes not in our path
-	Method findNodeFromPath:TGTKTreeViewNode(lookup:String)
-		If lookup = _path Then
-			Return Self
-		End If
-
-		Local i:Int = 0
-		For Local child:TGTKTreeViewNode = EachIn kids
-			Local node:TGTKTreeViewNode = child.findNodeFromPath(lookup)
-			If node Then
-				Return node
-			End If
-		Next
-
-		Return Null
-	End Method
-
-	Method Activate:Int(command:Int)
-		Super.Activate(command)
-
-		Select command
-			Case ACTIVATE_EXPAND
-				If _path <> Null And _path.length > 0 Then
-					ignoreExpand = True
-					' get the tree view
-					Local _root:TGTKTreeViewNode = TGTKTreeViewNode(RootNode())
-					' get this node path
-					Local path:Byte Ptr = gtk_tree_path_new_from_string(_path)
-	
-					' expand the node
-					gtk_tree_view_expand_row(_root.handle, path, False)
-	
-					' free stuff
-					gtk_tree_path_free(path)
-				End If
-			Case ACTIVATE_COLLAPSE
-				If _path <> Null And _path.length > 0 Then
-					ignoreCollapse = True
-
-					' get the tree view
-					Local _root:TGTKTreeViewNode = TGTKTreeViewNode(RootNode())
-					' get this node path
-					Local path:Byte Ptr = gtk_tree_path_new_from_string(_path)
-	
-					' expand the node
-					gtk_tree_view_collapse_row(_root.handle, path)
-	
-					' free stuff
-					gtk_tree_path_free(path)
-				End If
-			Case ACTIVATE_SELECT
-				If _path <> Null And _path.length > 0 Then
-					' the tree view should ignore this selection...
-					TGTKTreeViewNode(RootNode()).ignoreListChangeEvent = True
-				
-					' get this node path
-					Local path:Byte Ptr = gtk_tree_path_new_from_string(_path)
-					
-					' set the new selection
-					gtk_tree_selection_select_path(_selection, path)
-					
-					' free stuff
-					gtk_tree_path_free(path)					
-				End If
-		End Select
-	End Method
-	
-	Rem
-	bbdoc: Returns the text for this node.
-	End Rem
-	Method GetText:String()
-		Return _text
-	End Method
-	
-	Rem
-	bbdoc: Sets the text for this node.
-	End Rem
-	Method SetText:Int(text:String)
-		ModifyNode(text, _icon)
-	End Method
-
-	Method toString:String()
-		Return "TGTKTreeViewNode : " + _text + " : " + Super.ToString()
-	End Method
-	
-End Type
-
-Rem
-bbdoc: A tree view.
-End Rem
-Type TGTKTreeView Extends TGTKTreeViewNode
-
-	Function CreateTreeView:TGTKTreeView(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Local this:TGTKTreeView = New TGTKTreeView
-
-		this.initTreeView(x, y, w, h, label, group, style)
-
-		Return this
-	End Function
-
-	Method initTreeView(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Init(GTK_TREEVIEW, x, y, w, h, style)
-
-		ignoreListChangeEvent = True
-		
-		kids = New TEList
-
-		' create the tree store
-		_store = gtk_tree_store_new(2, gdk_pixbuf_get_type(), G_TYPE_STRING)
-
-		' set up the column contents
-		initColumns()
-
-		' attach store to the view
-		gtk_tree_view_set_model(handle, _store)
-
-		' remove *our* reference to the store... when the tree is destroyed this will be too
-		g_object_unref(_store)
-
-		SetShow(True)
-
-		gtk_layout_put(TGTKContainer(group).container, scrollwindow, x, y)
-		gtk_widget_set_size_request(handle, w, Max(h,0))
-
-
-		addConnection("row-activated", g_signal_cb4(handle, "row-activated", OnRowActivated, Self, Destroy, 0))
-		addConnection("row-expanded", g_signal_cb4(handle, "row-expanded", OnRowExpanded, Self, Destroy, 0))
-		addConnection("row-collapsed", g_signal_cb4(handle, "row-collapsed", OnRowCollapsed, Self, Destroy, 0))
-
-		isRoot = True
-	End Method
-
-	Rem
-	bbdoc: Callback For tree-view node activation (Double-click).
-	End Rem
-	Function OnRowActivated(widget:Byte Ptr, treePath:Byte Ptr, treeviewColumn:Byte Ptr, obj:Object)
-		Local p:Byte Ptr = gtk_tree_path_to_string(treePath)
-		Local node:TGTKTreeViewNode = TGTKTreeViewNode(obj).findNodeFromPath(String.FromCString(p))
-
-		' clean up mem
-		g_free(p)
-
-		PostGuiEvent(EVENT_GADGETACTION, TGadget(obj),,,,,node)
-	End Function
-
-	Rem
-	bbdoc: Callback for tree-view node expand.
-	End Rem
-	Function OnRowExpanded(widget:Byte Ptr, treeIter:Byte Ptr, treePath:Byte Ptr, obj:Object)
-		Local p:Byte Ptr = gtk_tree_path_to_string(treePath)
-		Local node:TGTKTreeViewNode = TGTKTreeViewNode(obj).findNodeFromPath(String.FromCString(p))
-
-		' clean up mem
-		g_free(p)
-
-		If Not node.ignoreExpand Then
-			PostGuiEvent(EVENT_GADGETOPEN, TGadget(obj),,,,,node)
-		End If
-
-		node.ignoreExpand = False
-	End Function
-
-	Rem
-	bbdoc: Callback for tree-view node collapse.
-	End Rem
-	Function OnRowCollapsed(widget:Byte Ptr, treeIter:Byte Ptr, treePath:Byte Ptr, obj:Object)
-		Local p:Byte Ptr = gtk_tree_path_to_string(treePath)
-		Local node:TGTKTreeViewNode = TGTKTreeViewNode(obj).findNodeFromPath(String.FromCString(p))
-
-		' clean up mem
-		g_free(p)
-
-		If Not node.ignoreCollapse Then
-			PostGuiEvent(EVENT_GADGETCLOSE, TGadget(obj),,,,,node)
-		End If
-
-		node.ignoreCollapse = False
-	End Function
-
-	Rem
-	bbdoc: Callback for mouse right-click
-	End Rem
-	Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		Local x:Double, y:Double, button:Int
-		bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
-
-		If button = 3 Then ' right mouse button
-			
-			Local node:TGTKTreeViewNode
-			Local treePath:Byte Ptr
-			
-		     ' Get tree path For row that was clicked
-			If gtk_tree_view_get_path_at_pos(widget, Int(x), Int(y), Varptr treePath, Null, Null, Null) Then
-				Local p:Byte Ptr = gtk_tree_path_to_string(treePath)
-				node = TGTKTreeViewNode(obj).findNodeFromPath(String.FromCString(p))
-				
-				' clean up mem
-				g_free(p)
-				gtk_tree_path_free(treePath)
-			End If
-		
-			PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),,,x,y,node)
-
-			Return True
-		End If
-
-		Return False
-	End Function
-	
-	' overriden - does nothing!!
-	Method LayoutKids:Int()
-	End Method
-
-	Method rethink:Int()
-		If handle Then
-			gtk_layout_move(TGTKContainer(parent).container, scrollwindow, Max(xpos, 0), Max(ypos, 0))
-			gtk_widget_set_size_request(scrollwindow, Max(width,0), Max(height,0))
-		End If
-	End Method
-
-	Method toString:String()
-		Return "TGTKTreeView"
-	End Method
-
-End Type
-
-Rem
-bbdoc: A base-type for handling slider / range gadgets - ScrollBar and TrackBar
-End Rem
-Type TGTKRange Extends TGTKGadget
-
-	Field currentValue:Int
-	Field rangeMin:Int
-	Field rangeMax:Int
-
-	Rem
-	bbdoc: Sets the slider range.
-	End Rem
-	Method SetRange:Int(visible:Int, total:Int)
-		rangeMin = Min(visible, total)
-		rangeMax = Max(visible, total)
-		gtk_range_set_range(handle, rangeMin, rangeMax)
-	End Method
-
-	Rem
-	bbdoc: Sets the value on the slider.
-	End Rem
-	Method SetProp:Int(value:Int)
-		currentValue = value
-		gtk_range_set_value(handle, value)
-	End Method
-
-	Rem
-	bbdoc: Returns the current slider value.
-	End Rem
-	Method GetProp:Int()
-		Return gtk_range_get_value(handle)
-	End Method
-
-	Rem
-	bbdoc: Callback for user changing of a slider.
-	about: Tries to keep the value within the desired range.
-	End Rem
-	Function OnChangeValue:Int(widget:Byte Ptr, scrolltype:Int, value:Double, obj:Object)
-		Local v:Int = Max(Min(value, TGTKRange(obj).rangeMax), TGTKRange(obj).rangeMin)
-		If v <> TGTKRange(obj).currentValue Then
-			TGTKRange(obj).currentValue = v
-			PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), v)
-		End If
-
-		Return False
-	End Function
-	
-	Method Free:Int()
-		Super.Free()
-
-		If handle 
-			gtk_widget_destroy(handle)
-		EndIf
-		handle = Null
-	End Method
-
-	Method toString:String()
-		Return "TGTKRange"
-	End Method
-
-End Type
-
-Rem
-bbdoc: A scrollbar
-End Rem
-Type TGTKScrollBar Extends TGTKRange
-
-	Field thumbSize:Int
-	Field Range:Int
-	Field pageSize:Int
-
-	Function CreateScrollBar:TGTKScrollBar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Local this:TGTKScrollBar = New TGTKScrollBar
-
-		this.initScrollBar(x, y, w, h, label, group, style)
-
-		Return this
-	End Function
-
-	Method initScrollBar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-
-		If style & SLIDER_VERTICAL Then
-			handle = gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, Null)
-		Else
-			handle = gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, Null)
-		End If
-
-		Init(GTK_SCROLLBAR, x, y, w, h, style)
-
-		' set the default range
-		SetRange(1, 10)
-
-		setShow(True)
-
-		addConnection("change-value", g_signal_cb4a(handle, "change-value", OnChangeValue, Self, Destroy, 0))
-		
-		gtk_layout_put(TGTKContainer(group).container, handle, x, y)
-		gtk_widget_set_size_request(handle, w, Max(h,0))
-		gtk_range_set_round_digits(handle, 0)
-
-	End Method
-
-	Rem
-	bbdoc: Overrides the default...
-	End Rem
-	Method SetRange:Int(small:Int, big:Int)
-
-		Range = big - small
-		pageSize = small
-		
-		If small <> 0 Then
-			thumbSize = big/small
-			thumbSize = range / thumbSize
-		Else
-			thumbSize = 1
-		End If
-
-		If Range = 0 Then
-			Range = 1
-			thumbSize = 1
-		End If
-
-	    gtk_adjustment_set_page_size(gtk_range_get_adjustment(handle), thumbSize)
-	    gtk_range_set_increments(handle, 1, pageSize)
-	    gtk_range_set_range(handle, 0, Range)
-	    gtk_range_set_value(handle, GetProp())
-	End Method
-
-	Function OnChangeValue:Int(widget:Byte Ptr, scrolltype:Int, value:Double, obj:Object)
-		Local v:Int = Min(TGTKScrollBar(obj).range, Max(value, 0))
-
-		If v <> TGTKRange(obj).currentValue Then
-			TGTKRange(obj).currentValue = v
-			PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), v)
-		End If
-
-		Return False
-	End Function
-
-	Method toString:String()
-		Return "TGTKScrollBar"
-	End Method
-
-End Type
-
-Rem
-bbdoc: A trackbar
-End Rem
-Type TGTKTrackBar Extends TGTKRange
-
-	Function CreateTrackBar:TGTKTrackBar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Local this:TGTKTrackBar = New TGTKTrackBar
-
-		this.initTrackBar(x, y, w, h, label, group, style)
-
-		Return this
-	End Function
-
-	Method initTrackBar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-
-		If style & SLIDER_VERTICAL Then
-			handle = gtk_scale_new_with_range(GTK_ORIENTATION_VERTICAL, 1, 10, 1)
-		Else
-			handle = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, 1, 10, 1)
-		End If
-
-		Init(GTK_TRACKBAR, x, y, w, h, style)
-
-		' set the default range
-		SetRange(1,10)
-
-		gtk_scale_set_draw_value(handle, False)
-
-		setShow(True)
-		
-		addConnection("change-value", g_signal_cb4a(handle, "change-value", OnChangeValue, Self, Destroy, 0))
-
-		gtk_layout_put(TGTKContainer(group).container, handle, x, y)
-		gtk_widget_set_size_request(handle, w, Max(h,0))
-
-	End Method
-
-	Method toString:String()
-		Return "TGTKTrackBar"
-	End Method
-
-End Type
-
-Type TGTKStepper Extends TGTKGadget
-
-	Function CreateStepper:TGTKStepper(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Local this:TGTKStepper = New TGTKStepper
-
-		this.initStepper(x, y, w, h, label, group, style)
-
-		Return this
-	End Function
-
-	Method initStepper(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-	
-		handle = gtk_spin_button_new_with_range(1, 100, 1)
-	
-		Init(GTK_STEPPER, x, y, w, h, style)
-		
-		' init range..
-		SetRange(1,100)
-		gtk_spin_button_set_increments(handle, 1, 10)
-		
-		setShow(True)
-		
-		addConnection("change-value", g_signal_cb3a_ret(handle, "change-value", OnChangeValue, Self, Destroy, 0))
-
-		gtk_layout_put(TGTKContainer(group).container, handle, x, y)
-		gtk_widget_set_size_request(handle, w, Max(h,0))
-	End Method
-
-	Rem
-	bbdoc: Sets the value on the slider.
-	End Rem
-	Method SetProp:Int(value:Int)
-		'currentValue = value
-		gtk_spin_button_set_value(handle, value)
-	End Method
-
-	Rem
-	bbdoc: Returns the current slider value.
-	End Rem
-	Method GetProp:Int()
-		Return gtk_spin_button_get_value(handle)
-	End Method
-
-	Rem
-	bbdoc: Sets the slider range.
-	End Rem
-	Method SetRange:Int(visible:Int, total:Int)
-		Local rangeMin:Int = Min(visible, total)
-		Local rangeMax:Int = Max(visible, total)
-		gtk_spin_button_set_range(handle, rangeMin, rangeMax)
-	End Method
-
-	Function OnChangeValue:Int(widget:Byte Ptr, scrolltype:Int, obj:Object)
-		Local v:Int = gtk_spin_button_get_value(widget)
-
-		PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), v)
-
-		Return False
-	End Function
-
-	Method toString:String()
-		Return "TGTKStepper"
-	End Method
-
-End Type
-
-Rem
-bbdoc: A progress bar
-about: Interestingly, although we can find out the current value, MaxGUI doesn't support it...
-End Rem
-Type TGTKProgressBar Extends TGTKGadget
-
-	Field ebox:Byte Ptr
-
-	Function CreateProgressBar:TGTKProgressBar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Local this:TGTKProgressBar = New TGTKProgressBar
-
-		this.initProgressBar(x, y, w, h, label, group, style)
-
-		Return this
-	End Function
-
-	Method initProgressBar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-
-		handle = gtk_progress_bar_new()
-		
-		Init(GTK_PROGRESSBAR, x, y, w, h, style)
-
-		' required for tooltips functionality
-		gtk_widget_add_events(handle, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK)
-
-		setShow(True)
-
-		gtk_layout_put(TGTKContainer(group).container, handle, x, y)
-		gtk_widget_set_size_request(handle, w, Max(h,0))
-
-	End Method
-
-	Rem
-	bbdoc: Set the value of the progress bar.
-	End Rem
-	Method SetValue:Int(value:Float)
-		value = Min(Max(0, value), 1.0)
-		gtk_progress_bar_set_fraction(handle, value)
-	End Method
-	
-	Rem
-	bbdoc: Get the current value of the progress bar
-	End Rem
-	Method GetValue:Float()
-		Return gtk_progress_bar_get_fraction(handle)
-	End Method
-	
-	Method Free:Int()
-		Super.Free()
-
-		If handle
-			gtk_widget_destroy(handle)
-		EndIf
-		handle = Null
-	End Method
-
-	Method toString:String()
-		Return "TGTKProgressBar"
-	End Method
-
-End Type
-
-Rem
-bbdoc: A Toolbar
-End Rem
-Type TGTKToolbar Extends TGTKGadget
-
-	Field icons:TGTKIconStrip
-	Field toolitems:Byte Ptr[]
-
-	Function CreateToolBar:TGTKToolbar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Local this:TGTKToolbar = New TGTKToolbar
-
-		this.initToolbar(x, y, w, h, label, group, style)
-
-		Return this
-	End Function
-
-	Method initToolbar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-
-		handle = gtk_toolbar_new()
-
-		Init(GTK_TOOLBAR, x, y, w, h, style)
-
-		If TGTKWindow(group) Then
-			TGTKWindow(group).addToolbar(Self)
-		End If
-
-		' show icons only
-		gtk_toolbar_set_style(handle, GTK_TOOLBAR_ICONS)
-
-		gtk_widget_show(handle)
-	End Method
-
-	Method SetIconStrip:Int(iconstrip:TIconStrip)
-		icons = TGTKIconStrip(iconstrip)
-	End Method
-
-	Rem
-	bbdoc: Inserts an item at the specified index.
-	End Rem
-	Method InsertListItem:Int(index:Int, text:String, tip:String, icon:Int, extra:Object)
-		Local image:Byte Ptr		
-
-		If icons And icon>=0 Then
-			image = icons.images[icon]
-		End If
-
-		toolitems = toolitems[..toolitems.length+1]
-		For Local i:Int = toolitems.length - 2 To index Step -1
-			toolitems[i + 1] = toolitems[i]
-		Next
-
-		If image Then
-			Local imageWidget:Byte Ptr = gtk_image_new_from_pixbuf(image)
-			gtk_widget_show(imageWidget)
-	
-			Local textPtr:Byte Ptr = text.ToUTF8String()
-			If items[index].flags = GADGETITEM_TOGGLE Then
-				toolitems[index] = gtk_toggle_tool_button_new()
-				gtk_tool_button_set_label(toolitems[index], textPtr)
-				gtk_tool_button_set_icon_name(toolitems[index], icons.names[icon])
-
-				addConnection("toggled", g_signal_cb2(toolitems[index], "toggled", OnToolItemToggled, Self, Destroy, 0))
-			Else
-				toolitems[index] = gtk_tool_button_new(Null, textPtr)
-				gtk_tool_button_set_label(toolitems[index], textPtr)
-				gtk_tool_button_set_icon_name(toolitems[index], icons.names[icon])
-				
-
-				addConnection("clicked", g_signal_cb2(toolitems[index], "clicked", OnToolItemClicked, Self, Destroy, 0))
-			End If
-			MemFree(textPtr)
-
-			' Add a tooltip
-			SetToolTipIndex(index, tip)
-		Else
-			' no image? Then this is a separator!
-			toolitems[index] = gtk_separator_tool_item_new()
-		End If
-		gtk_widget_show(toolitems[index])
-
-		gtk_toolbar_insert(handle, toolitems[index], index)
-	End Method
-
-	Function OnToolItemToggled(widget:Byte Ptr, obj:Object)
-		Local index:Int = gtk_toolbar_get_item_index(TGTKToolbar(obj).handle, widget)
-		PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), index, gtk_toggle_tool_button_get_active(widget))
-	End Function
-
-	Function OnToolItemClicked(widget:Byte Ptr, obj:Object)
-		Local index:Int = gtk_toolbar_get_item_index(TGTKToolbar(obj).handle, widget)
-		PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), index)
-	End Function
-
-	Method SetListItem:Int(index:Int, text:String, tip:String, icon:Int, extra:Object)
-
-		If toolitems[index] Then
-			gtk_container_remove(handle, toolitems[index])
-
-			For Local i:Int = index Until toolitems.length - 1
-				toolitems[i] = toolitems[i + 1]
-			Next
-			toolitems = toolitems[..toolitems.length - 1]
-		End If
-
-		InsertListItem(index, text, tip, icon, extra)
-	End Method
-
-	Method SetToolTipIndex:Int(index:Int, tip:String)
-		' Add a tooltip
-		If tip And tip.length > 0 Then
-			Local tipPtr:Byte Ptr = tip.ToUTF8String()
-			gtk_tool_item_set_tooltip_text(toolitems[index], tipPtr)
-			MemFree(tipPtr)
-		Else
-			gtk_tool_item_set_tooltip_text(toolitems[index], Null)
-		End If		
-	End Method
-
-	Method SetListItemState:Int(item:Int, state:Int)
-		If state & STATE_DISABLED Then
-			gtk_widget_set_sensitive(toolitems[item], False)
-		Else
-			gtk_widget_set_sensitive(toolitems[item], True)
-		End If
-
-		If items[item].flags = GADGETITEM_TOGGLE Then
-			If state & STATE_SELECTED Then
-				gtk_toggle_tool_button_set_active(toolitems[item], True)
-			Else
-				gtk_toggle_tool_button_set_active(toolitems[item], False)
-			End If
-		End If
-		
-		gtk_widget_queue_draw(handle)
-	End Method
-
-	Method ListItemState:Int(index:Int)
-		Local state:Int = 0
-
-		If Not gtk_widget_is_sensitive(toolitems[index]) Then
-			state:| STATE_DISABLED
-		End If
-
-		If items[index].flags = GADGETITEM_TOGGLE Then
-			If gtk_toggle_tool_button_get_active(toolitems[index]) Then
-				state:| STATE_SELECTED
-			End If
-		End If
-
-		Return state
-	End Method
-
-	Method RemoveListItem:Int(index:Int)
-		If toolitems[index] Then
-			gtk_container_remove(handle, toolitems[index])
-
-			For Local i:Int = index Until toolitems.length - 1
-				toolitems[i] = toolitems[i + 1]
-			Next
-			toolitems = toolitems[..toolitems.length - 1]
-		End If
-	End Method
-
-	Method rethink:Int()
-	End Method
-
-	Method Free:Int()
-		Super.Free()
-
-		If handle
-			gtk_widget_destroy(handle)
-			
-			' assuming that destroying the toolbar will destroy 
-			For Local i:Int = 0 Until toolitems.length
-				toolitems[i] = Null
-			Next
-		EndIf
-		handle = Null
-	End Method
-
-	Method toString:String()
-		Return "TGTKToolbar"
-	End Method
-
-End Type
-
-Rem
-bbdoc: A tabber.
-End Rem
-Type TGTKTabber Extends TGTKContainer
-
-	Field icons:TGTKIconStrip
-	Field images:Byte Ptr[]
-	Field labels:Byte Ptr[]
-	Field pages:Byte Ptr[]
-	Field ignoreChange:Int
-	Field currentIndex:Int = -1
-
-	Function CreateTabber:TGTKTabber(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Local this:TGTKTabber = New TGTKTabber
-
-		this.initTabber(x, y, w, h, label, group, style)
-
-		Return this
-	End Function
-
-	Method initTabber(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-
-		handle = gtk_notebook_new()
-
-		Init(GTK_TABBER, x, y, w, h, style)
-
-		container = gtk_layout_new(Null, Null)
-		gtk_widget_show(container)
-		g_object_ref(container) ' hold an extra ref for our container
-
-		' Scrollable tabs if there are too many to fit on the display
-		gtk_notebook_set_scrollable(handle, True)
-
-		gtk_widget_show(handle)
-
-		g_signal_tabchange(handle, "switch-page", OnTabChanged, Self, Destroy, 0)
-
-		gtk_layout_put(TGTKContainer(group).container, handle, x, y)
-		gtk_widget_set_size_request(handle, w, Max(h,0))
-
-	End Method
-
-	Function OnTabChanged(widget:Byte Ptr, page:Byte Ptr, index:Int, obj:Object)
-		If TGTKTabber(obj).currentIndex >= 0 Then
-			Local child:Byte Ptr = gtk_notebook_get_nth_page(TGTKTabber(obj).handle, TGTKTabber(obj).currentIndex)
-			TGTKTabber(obj).RemoveFromTab(child)
-		End If
-		
-		If index >= 0 Then
-			TGTKTabber(obj).AddToTab(page)
-		End If
-		TGTKTabber(obj).currentIndex = index
-
-		If Not TGTKTabber(obj).ignoreChange Then
-			PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), index,,,,TGadget(obj).ItemExtra(index))
-		End If
-		TGTKTabber(obj).ignoreChange = False
-	End Function
-
-	Rem
-	bbdoc: Inserts a new tab
-	End Rem
-	Method InsertListItem:Int(index:Int, text:String, tip:String, icon:Int, tag:Object)
-
-		Local image:Byte Ptr
-
-		If icons And icon>=0 Then
-			image = icons.images[icon]
-		End If
-
-		images = images[..images.length+1]
-		For Local i:Int = images.length - 2 To index Step -1
-			images[i + 1] = images[i]
-		Next
-
-		labels = labels[..labels.length+1]
-		For Local i:Int = labels.length - 2 To index Step -1
-			labels[i + 1] = labels[i]
-		Next
-		
-		pages = pages[..pages.length+1]
-		For Local i:Int = pages.length - 2 To index Step -1
-			pages[i + 1] = pages[i]
-		Next
-
-		If image Then
-			images[index] = gtk_image_new_from_pixbuf(image)
-			gtk_widget_show(images[index])
-		Else
-			images[index] = gtk_image_new()
-		End If
-
-		' since a Label can't accept events, we wrap it inside an event box which can
-		Local box:Byte Ptr = gtk_event_box_new()
-		gtk_event_box_set_visible_window(box, False)
-		gtk_widget_add_events(box, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK)
-		' show the box
-		gtk_widget_show(box)
-	
-		' create a display label for the tab
-		Local textPtr:Byte Ptr = text.ToUTF8String()
-		labels[index] = gtk_label_new(textPtr)
-		MemFree(textPtr)
-		gtk_widget_show(labels[index])
-		
-		' create a horizontal box to place the image/label combo
-		Local hbox:Byte Ptr = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4)
-		gtk_widget_show(hbox)
-		
-		' add widgets to the hbox
-		gtk_box_pack_start(hbox, images[index], False, False, 0)
-		gtk_box_pack_start(hbox, labels[index], False, False, 0)
-		
-		' add the hbox to the eventbox
-		gtk_container_add(box, hbox)
-
-		' create a child to hold our container.
-		Local child:Byte Ptr = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0)
-		pages[index] = child
-		gtk_widget_show(child)
-
-		gtk_notebook_insert_page(handle, child, box, index)
-
-		' Add a tooltip to the event box
-		SetToolTipIndex(index, tip, box)
-	End Method
-
-	Method SetListItem:Int(index:Int, text:String, tip:String, icon:Int, tag:Object)
-		Local child:Byte Ptr = gtk_notebook_get_nth_page(handle, index)
-		
-		' get the event box to which we set tooltips
-		Local box:Byte Ptr = gtk_notebook_get_tab_label(handle, child)
-
-		' is there an image to show?
-		Local image:Byte Ptr
-		If icons And icon>=0 Then
-			image = icons.images[icon]
-		End If
-
-		If Not image Then
-			' hide image if none
-			gtk_widget_hide(images[index])
-		Else
-			' set and display image
-			gtk_image_set_from_pixbuf(images[index], image)
-			gtk_widget_show(images[index])
-		End If
-
-		' set new text
-		Local textPtr:Byte Ptr = text.ToUTF8String()
-		gtk_label_set_text(labels[index], textPtr)
-		MemFree(textPtr)
-		
-		' Add a tooltip to the event box
-		SetToolTipIndex(index, tip, box)
-	End Method
-
-	Method RemoveListItem:Int(index:Int)
-		Local arr:Byte Ptr[] = images
-		images = images[..images.length-1]
-		For Local i:Int = index To arr.length-2
-			images[i] = arr[i+1]
-		Next
-
-		arr = labels
-		labels = labels[..labels.length-1]
-		For Local i:Int = index To arr.length-2
-			labels[i] = arr[i+1]
-		Next
-
-		arr = pages
-		pages = pages[..pages.length-1]
-		For Local i:Int = index To arr.length-2
-			pages[i] = arr[i+1]
-		Next
-
-		' remove from current tab if required
-		If gtk_notebook_get_current_page(handle) = index Then
-			Local child:Byte Ptr = gtk_notebook_get_nth_page(handle, index)
-			RemoveFromTab(child)
-			currentIndex = -1
-		Else If index < currentIndex Then
-			currentIndex :- 1
-		End If
-		
-		gtk_notebook_remove_page(handle, index)
-		
-	End Method
-
-	Method ListItemState:Int(index:Int)
-		Local state:Int = 0
-
-		If gtk_notebook_get_current_page(handle) = index Then
-			state:| STATE_SELECTED
-		End If
-
-		Return state
-	End Method
-
-	Method SetListItemState:Int(index:Int, state:Int)
-		If state & STATE_SELECTED Then
-			If gtk_notebook_get_current_page(handle) <> index Then
-				ignoreChange = True
-?bmxng
-				IWrappedSystemDriver(SystemDriver()).GetDriver().Poll()
-?Not bmxng
-				brl.System.Driver.Poll() ' update events
-?
-				gtk_notebook_set_current_page(handle, index)
-			End If
-		End If
-	End Method
-
-	Method ClientHeight:Int()
-		Local h:Int = height
-
-		If handle Then
-?bmxng
-			Local minReq:GtkRequisition 
-			Local natReq:GtkRequisition
-?Not bmxng
-			Local minReq:GtkRequisition = New GtkRequisition
-			Local natReq:GtkRequisition = New GtkRequisition
-?
-			gtk_widget_get_preferred_size(handle, minReq, natReq)
-
-			h :- 34 ' FIXME : current hard-coded. Should be height of notebook less tab height and border.
-
-		End If
-
-		Return Max(0, h)
-	End Method
-
-	Method ClientWidth:Int()
-		Local w:Int = width
-
-		If handle Then
-?bmxng
-			Local minReq:GtkRequisition 
-			Local natReq:GtkRequisition
-?Not bmxng
-			Local minReq:GtkRequisition = New GtkRequisition
-			Local natReq:GtkRequisition = New GtkRequisition
-?
-			gtk_widget_get_preferred_size(handle, minReq, natReq)
-			w:- 4 ' FIXME : current hard-coded. Should be width of notebook less borders.
-		End If
-
-		Return Max(0, w)
-	End Method
-
-	Method SetToolTipIndex:Int(index:Int, tip:String, label:Byte Ptr)
-		' Add a tooltip
-		If tip And tip.length > 0 Then
-			Local tipPtr:Byte Ptr = tip.ToUTF8String()
-			gtk_widget_set_tooltip_text(label, tipPtr)
-			MemFree(tipPtr)
-		Else
-			gtk_widget_set_tooltip_text(label, Null)
-		End If		
-	End Method
-
-	Method SetIconStrip:Int(iconstrip:TIconStrip)
-		icons = TGTKIconStrip(iconstrip)
-	End Method
-
-	Method Free:Int()
-		Super.Free()
-		
-		If container Then
-			gtk_widget_destroy(container)
-			container = Null
-		End If
-
-		handle = Null
-		images = Null
-		labels = Null
-	End Method
-
-	Method Rethink:Int()
-		If handle Then
-			gtk_layout_move(TGTKContainer(parent).container, handle, xpos, ypos)
-			gtk_widget_set_size_request(handle, Max(width,0), Max(height,0))
-		End If
-	End Method
-
-	Method toString:String()
-		Return "TGTKTabber"
-	End Method
-	
-	Method RemoveFromTab(page:Byte Ptr)
-		If currentIndex >= 0 Then
-			g_object_ref(container)
-			gtk_container_remove(page, container)
-		End If
-	End Method
-
-	Method AddToTab(page:Byte Ptr)
-		gtk_box_pack_start(page, container, True, True, 0)
-		g_object_unref(container)
-	End Method
-
-End Type
-
-Rem
-bbdoc: A Panel
-End Rem
-Type TGTKPanel Extends TGTKContainer
-
-	Field frame:Byte Ptr
-	Field hasFrame:Int
-	Field panelPixmap:TPixmap
-	Field panelPixbuf:Byte Ptr
-	Field pixmapMode:Int
-	
-	Field drawPixbuf:Int
-	Field visualpixbuf:Byte Ptr
-	Field pbx:Int
-	Field pby:Int
-	
-	Field pane:Int
-
-	Function CreatePanel:TGTKPanel(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int, intoPane:Int = 0)
-		Local this:TGTKPanel = New TGTKPanel
-
-		this.initPanel(x, y, w, h, label, group, style, intoPane)
-
-		Return this
-	End Function
-
-	Method initPanel(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int, intoPane:Int)
-
-		handle = gtk_layout_new(Null, Null)
-
-		Init(GTK_PANEL, x, y, w, h, style)
-
-		container = handle
-		
-		If style & PANEL_ACTIVE
-			sensitivity:| SENSITIZE_MOUSE | SENSITIZE_KEYS
-		End If
-
-		gtk_widget_add_events(handle, GDK_BUTTON_PRESS_MASK | ..
-			GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | ..
-			GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK)' | ..
-'				GDK_POINTER_MOTION_HINT_MASK)
-
-		addConnection("button-press-event", g_signal_cb3_ret(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
-		addConnection("button-release-event", g_signal_cb3_ret(handle, "button-release-event", OnMouseUp, Self, Destroy, 0))
-		addConnection("enter-notify-event", g_signal_cb3_ret(handle, "enter-notify-event", OnMouseEnter, Self, Destroy, 0))
-		addConnection("leave-notify-event", g_signal_cb3_ret(handle, "leave-notify-event", OnMouseLeave, Self, Destroy, 0))
-		addConnection("motion-notify-event", g_signal_cb3_ret(handle, "motion-notify-event", OnMouseMove, Self, Destroy, 0))
-		addConnection("draw", g_signal_cb3_ret(handle, "draw", OnDraw, Self, Destroy, 0))
-		addConnection("scroll-event", g_signal_cb3(handle, "scroll-event", OnScroll, Self, Destroy, 0))
-
-		addConnection("key-press-event", g_signal_cb3_ret(handle, "key-press-event", OnKeyDown, Self, Destroy, 0))
-		addConnection("key-release-event", g_signal_cb3_ret(handle, "key-release-event", OnKeyUp, Self, Destroy, 0))
-
-		gtk_widget_show(handle)
-
-		' Should we add a frame?
-		If style & PANEL_BORDER Or style & PANEL_GROUP Then
-
-			hasFrame = True
-
-			frame = gtk_frame_new(Null)
-			gtk_widget_show(frame)
-
-			' set frame text
-			If (LocalizationMode() & LOCALIZATION_OVERRIDE) Then
-				LocalizeGadget(Self, label)
-			Else
-				SetText(label)
-			EndIf
-			
-			gtk_container_add(frame, handle)
-
-			gtk_layout_put(TGTKContainer(group).container, frame, x, y)
-			gtk_widget_set_size_request(frame, w, Max(h,0))
-
-		Else
-
-			gtk_layout_put(TGTKContainer(group).container, handle, x, y)
-			gtk_widget_set_size_request(handle, w, Max(h,0))
-
-		End If
-
-	End Method
-
-	Rem
-	bbdoc: Callback for mouse button press.
-	End Rem
-	Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		If TGTKPanel(obj).style & PANEL_ACTIVE Then
-			Local x:Double, y:Double, button:Int
-			bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
-
-			If button = 3 Then
-				button = 2
-			Else If button = 2 Then
-				button = 3
-			End If
-
-			PostGuiEvent(EVENT_MOUSEDOWN, TGadget(obj),button,,x,y)
-		End If
-		Return True
-	End Function
-
-	Rem
-	bbdoc: Callback for mouse button release.
-	End Rem
-	Function OnMouseUp:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		If TGTKPanel(obj).style & PANEL_ACTIVE Then
-			Local x:Double, y:Double, button:Int
-			bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
-
-			If button = 3 Then
-				button = 2
-			Else If button = 2 Then
-				button = 3
-			End If
-			
-			PostGuiEvent(EVENT_MOUSEUP, TGadget(obj),button,,x,y)
-		End If
-		Return True
-	End Function
-
-	Rem
-	bbdoc: Callback for mouse enter.
-	End Rem
-	Function OnMouseEnter:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		If TGTKPanel(obj).style & PANEL_ACTIVE Then
-			If TGTKGadget(obj).visible Then
-				PostGuiEvent(EVENT_MOUSEENTER, TGadget(obj))
-			End If
-		End If
-		Return False
-	End Function
-
-	Rem
-	bbdoc: Callback for mouse leave.
-	End Rem
-	Function OnMouseLeave:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		If TGTKPanel(obj).style & PANEL_ACTIVE Then
-			If TGTKGadget(obj).visible Then
-				PostGuiEvent(EVENT_MOUSELEAVE, TGadget(obj))
-			End If
-		End If
-		Return False
-	End Function
-
-	Rem
-	bbdoc: Callback for mouse movement
-	End Rem
-	Function OnMouseMove:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		If TGTKPanel(obj).style & PANEL_ACTIVE Then
-			Local _x:Double, _y:Double, button:Int
-			bmx_gtk3maxgui_gdkeventmotion(event, Varptr _x, Varptr _y, Varptr button)
-			Local x:Int, y:Int
-			
-			' we actually ignore the coords returned by the event and get the
-			' mouse coords relative to this widget's parent
-			gdk_window_get_device_position(gtk_widget_get_parent_window(widget), bmx_gtk3maxgui_gdkeventmotiondevice(event), x, y, button)
-
-			' then we remove the stored coords from that value to get the TRUE coords.
-			x:- TGTKPanel(obj).xpos
-			y:- TGTKPanel(obj).ypos
-			
-			If button & GDK_BUTTON1_MASK Then
-				button = 1
-			Else If button & GDK_BUTTON3_MASK Then
-				button = 2
-			Else If button & GDK_BUTTON2_MASK Then
-				button = 3
-			Else
-				button = 0
-			End If
-			PostGuiEvent(EVENT_MOUSEMOVE, TGadget(obj),button,,x,y)
-		End If
-		Return True
-	End Function
-
-	Function OnDraw:Int(widget:Byte Ptr, cairo:Byte Ptr, obj:Object)
-		Local panel:TGTKPanel = TGTKPanel(obj)
-		If panel Then
-			If panel.drawPixbuf And panel.visualpixbuf Then
-				gdk_cairo_set_source_pixbuf(cairo, panel.visualpixbuf, panel.pbx, panel.pby)
-				cairo_paint(cairo)
-				cairo_fill(cairo)
-			End If
-		End If
-		PostGuiEvent(EVENT_GADGETPAINT, TGadget(obj))
-	End Function
-	
-	Rem
-	bbdoc: Callback for mouse scroll wheel
-	End Rem
-	Function OnScroll(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		If TGTKPanel(obj).style & PANEL_ACTIVE Then
-			Local x:Double, y:Double, direction:Int
-			bmx_gtk3maxgui_gdkeventscroll(event, Varptr x, Varptr y, Varptr direction)
-
-			If direction = GDK_SCROLL_UP Or direction = GDK_SCROLL_LEFT Then
-				PostGuiEvent(EVENT_MOUSEWHEEL, TGadget(obj),-1,,x,y)
-			Else
-				PostGuiEvent(EVENT_MOUSEWHEEL, TGadget(obj),1,,x,y)
-			End If
-		End If
-	End Function
-
-	Rem
-	bbdoc: Callback for key down
-	End Rem
-	Function OnKeyDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		If TGTKPanel(obj).style & PANEL_ACTIVE Then
-			Local _key:Int, _mods:Int
-			bmx_gtk3maxgui_gdkeventkey(event, Varptr _key, Varptr _mods)
-			Local key:Int = TGTKKeyMap.mapBack(_key)
-			Local mods:Int = TGTKKeyMap.mapModifierBack(_mods)
-	
-			If Not gtk3SetKeyDown(key) Then
-				PostGuiEvent(EVENT_KEYDOWN, TGadget(obj), key, mods)
-			Else
-				PostGuiEvent(EVENT_KEYREPEAT, TGadget(obj), key, mods)
-			End If
-
-			Local char:Int = gdk_keyval_to_unicode(_key)
-			' we sometimes get 0 from this function when key is valid... so set it to key just so that it has a value.
-			If char = 0 And key <> 0 Then
-				char = key
-			End If
-			PostGuiEvent(EVENT_KEYCHAR, TGadget(obj), char, mods)
-	
-			Return True
-		End If
-	End Function
-
-	Rem
-	bbdoc: Callback for key up
-	End Rem
-	Function OnKeyUp:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		If TGTKPanel(obj).style & PANEL_ACTIVE Then
-			Local _key:Int, _mods:Int
-			bmx_gtk3maxgui_gdkeventkey(event, Varptr _key, Varptr _mods)
-			Local key:Int = TGTKKeyMap.mapBack(_key)
-			Local mods:Int = TGTKKeyMap.mapModifierBack(_mods)
-			
-			gtk3SetKeyUp(key)
-			PostGuiEvent(EVENT_KEYUP, TGadget(obj), key, mods)
-	
-			Return True
-		End If
-	End Function
-
-	Rem
-	bbdoc: Sets the text of a group panel.
-	End Rem
-	Method SetText:Int(text:String)
-		If style & PANEL_GROUP Then
-			If text = Null Or text.length = 0 Then
-				gtk_frame_set_label(frame, Null)
-			Else
-				Local textPtr:Byte Ptr = text.ToUTF8String()
-				gtk_frame_set_label(frame, textPtr)
-				MemFree(textPtr)
-			End If
-		End If
-	End Method
-
-	Rem
-	bbdoc: Shows or hides a panel
-	End Rem
-	Method SetShow:Int(truefalse:Int)
-		visible = truefalse
-		mySetVisible = visible
-		
-		If truefalse Then
-			If frame Then
-				gtk_widget_show(frame)
-			Else
-				gtk_widget_show(handle)
-			End If
-		Else
-			If frame Then
-				gtk_widget_hide(frame)
-			Else
-				gtk_widget_hide(handle)
-			End If
-		EndIf
-
-		UpdateChildVisibility()
-	End Method
-
-	Method Free:Int()
-		Super.Free()
-
-		If frame Then
-			gtk_widget_destroy(frame)
-		Else
-			If handle Then
-				gtk_widget_destroy(handle)
-			End If
-		End If
-		
-		container = Null
-		handle = Null
-		frame = Null
-		
-		If panelpixmap Then
-			panelpixmap = Null
-		End If
-		If panelPixbuf Then
-			g_object_unref(panelPixbuf)
-			panelPixbuf = Null
-		End If
-	End Method
-
-	Rem
-	bbdoc: Set the panel color.
-	End Rem
-	Method SetColor:Int(r:Int, g:Int, b:Int)
-		Local color:GdkRGBA = New GdkRGBA(r / 255.0, g / 255.0, b / 255.0)
-		gtk_widget_override_background_color(handle, GTK_STATE_FLAG_NORMAL, color)
-	End Method
-
-	Rem
-	bbdoc: Set the panel pixmap.
-	End Rem
-	Method SetPixmap:Int(pixmap:TPixmap, flags:Int)
-		pixmapMode = flags
-		
-		If pixmap Then
-			If PixmapFormat(pixmap) <> PF_RGBA8888 And PixmapFormat(pixmap) <> PF_BGRA8888 Then
-				panelPixmap = pixmap.convert( PF_RGBA8888 )
-			Else
-				panelPixmap = pixmap
-			End If
-			
-			If panelPixbuf Then
-				g_object_unref(panelPixbuf)
-			End If
-
-			panelPixbuf = gdk_pixbuf_new_from_data(panelPixmap.pixels, GDK_COLORSPACE_RGB, True, 8, ..
-							panelPixmap.width, panelPixmap.height, panelPixmap.Pitch, Null, Null)
-		Else
-			If panelPixmap Then
-				panelPixmap = Null
-			End If
-		End If
-		redraw()
-	End Method
-	
-	Method rethink:Int()
-		If frame Then
-			gtk_layout_move(TGTKContainer(parent).container, frame, xpos, ypos)
-			gtk_widget_set_size_request(frame, Max(width,0), Max(height,0))
-		Else If handle Then
-			gtk_layout_move(TGTKContainer(parent).container, handle, xpos, ypos)
-			gtk_widget_set_size_request(handle, Max(width,0), Max(height,0))
-		End If
-		redraw()
-	End Method
-
-	Method redraw()
-
-		If Not panelPixmap Then
-			If panelPixbuf Then
-				g_object_unref(panelPixbuf)
-				panelPixbuf = Null
-			End If
-			If visualpixbuf Then
-				g_object_unref(visualpixbuf)
-				visualpixbuf = Null
-				' make the panel redraw itself
-				gtk_widget_queue_draw(handle)
-			End If
-		End If
-		
-		If panelPixbuf Then
-			
-			If visualpixbuf Then
-				g_object_unref(visualpixbuf)
-			End If
-			Select pixmapMode & (PANELPIXMAP_TILE | PANELPIXMAP_CENTER | PANELPIXMAP_FIT | PANELPIXMAP_FIT2 | PANELPIXMAP_STRETCH)
-				Case PANELPIXMAP_TILE
-
-					pbx = 0
-					pby = 0
-
-					Local w:Float = width
-					Local h:Float = height
-
-					Local wfull:Int = w / panelPixmap.width
-					Local hfull:Int = h / panelPixmap.height
-					
-					Local wpart:Int = w Mod panelPixmap.width
-					Local hpart:Int = h Mod panelPixmap.height
-					
-					visualpixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, True, 8, Int(w), Int(h))
-					
-					For Local x:Int = 0 Until wfull
-					
-						For Local y:Int = 0 Until hfull
-							gdk_pixbuf_copy_area(panelPixbuf, 0, 0, panelPixmap.width, panelPixmap.height, visualpixbuf, x * panelPixmap.width, y * panelPixmap.height)
-						Next
-						
-						If hpart > 0 Then
-							gdk_pixbuf_copy_area(panelPixbuf, 0, 0, panelPixmap.width, hpart, visualpixbuf, x * panelPixmap.width, hfull * panelPixmap.height)
-						End If
-					
-					Next
-					
-					If wpart > 0 Then
-					
-						For Local y:Int = 0 Until hfull
-							gdk_pixbuf_copy_area(panelPixbuf, 0, 0, wpart, panelPixmap.height, visualpixbuf, wfull * panelPixmap.width, y * panelPixmap.height)
-						Next
-					
-						If hpart > 0 Then
-							gdk_pixbuf_copy_area(panelPixbuf, 0, 0, wpart, hpart, visualpixbuf, wfull * panelPixmap.width, hfull * panelPixmap.height)
-						End If
-					
-					End If
-				
-				Case PANELPIXMAP_CENTER
-					visualpixbuf = gdk_pixbuf_copy(panelPixBuf)
-					pbx = width / 2 - panelPixmap.width / 2
-					pby = height / 2 - panelPixmap.height / 2
-					
-				Case PANELPIXMAP_FIT
-					Local _w:Float = width / (panelPixmap.width * 1.0)
-					Local _h:Float = height / (panelPixmap.height * 1.0)
-
-					Local newWidth:Int = Min(_w, _h) * panelPixmap.width
-					Local newHeight:Int = Min(_w, _h) * panelPixmap.height
-
-					pbx = width / 2 - newWidth / 2
-					pby = height / 2 - newHeight / 2
-
-					visualpixbuf = gdk_pixbuf_scale_simple(panelPixbuf, newWidth, newHeight, GDK_INTERP_BILINEAR)
-
-				Case PANELPIXMAP_FIT2
-					Local _w:Float = width / (panelPixmap.width * 1.0)
-					Local _h:Float = height / (panelPixmap.height * 1.0)
-
-					Local newWidth:Int = Max(_w, _h) * panelPixmap.width
-					Local newHeight:Int = Max(_w, _h) * panelPixmap.height
-
-					pbx = width / 2 - newWidth / 2
-					pby = height / 2 - newHeight / 2
-
-					visualpixbuf = gdk_pixbuf_scale_simple(panelPixbuf, newWidth, newHeight, GDK_INTERP_BILINEAR)
-					
-				Case PANELPIXMAP_STRETCH
-					pbx = 0
-					pby = 0
-					visualpixbuf = gdk_pixbuf_scale_simple(panelPixbuf, width, height, GDK_INTERP_BILINEAR)
-			End Select
-			
-			If Not drawPixbuf Then
-				drawPixbuf = True
-			End If
-		
-		End If
-		
-		' make sure the panel refreshes visually
-		Super.redraw()
-	End Method
-
-	Method Activate:Int(cmd:Int)
-		Select cmd
-			Case ACTIVATE_REDRAW
-				redraw()
-		Default
-			Super.Activate(cmd)
-		End Select
-	End Method
-
-	Method toString:String()
-		Return "TGTKPanel"
-	End Method
-End Type
-
-Rem
-bbdoc: A canvas.
-End Rem
-Rem 
-Type TGTKCanvas Extends TGTKGadget
-
-	Field canvas:TGraphics
-	Field Mode:Int
-	
-
-	Function CreateCanvas:TGTKCanvas(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Local this:TGTKCanvas = New TGTKCanvas
-
-		this.initCanvas(x, y, w, h, label, group, style)
-
-		Return this
-	End Function
-
-	Method initCanvas(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-
-		handle = gtk_drawing_area_new()
-
-		Init(GTK_CANVAS, x, y, w, h, style)
-
-		gtk_layout_put(TGTKContainer(group).container, handle, x, y)
-		gtk_widget_set_size_request(handle, w, Max(h,0))
-
-		sensitivity:| SENSITIZE_MOUSE | SENSITIZE_KEYS
-
-		' we need to allow the drawing area to accept focus !
-		g_object_set_int(handle, "can-focus", True)
-
-		' we need to handle our own redrawing...
-		'gtk_widget_set_double_buffered(handle, False)
-
-		addConnection("expose_event", g_signal_cb3(handle, "expose_event", CanvasRedraw, Self, Destroy, 0))
-
-		gtk_widget_add_events(handle, GDK_BUTTON_PRESS_MASK | ..
-			GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | ..
-			GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK)' | ..
-'				GDK_POINTER_MOTION_HINT_MASK)
-
-		addConnection("button-press-event", g_signal_cb3(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
-		addConnection("button-release-event", g_signal_cb3(handle, "button-release-event", OnMouseUp, Self, Destroy, 0))
-		addConnection("enter-notify-event", g_signal_cb3(handle, "enter-notify-event", OnMouseEnter, Self, Destroy, 0))
-		addConnection("leave-notify-event", g_signal_cb3(handle, "leave-notify-event", OnMouseLeave, Self, Destroy, 0))
-		addConnection("motion-notify-event", g_signal_cb3(handle, "motion-notify-event", OnMouseMove, Self, Destroy, 0))
-		addConnection("scroll-event", g_signal_cb3(handle, "scroll-event", OnScroll, Self, Destroy, 0))
-
-		addConnection("key-press-event", g_signal_cb3(handle, "key-press-event", OnKeyDown, Self, Destroy, 0))
-		addConnection("key-release-event", g_signal_cb3(handle, "key-release-event", OnKeyUp, Self, Destroy, 0))
-
-		SetShow(True)
-	End Method
-
-	Function CanvasRedraw(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		PostGuiEvent(EVENT_GADGETPAINT, TGadget(obj))
-	End Function
-	
-	Method AttachGraphics:TGraphics( flags:Int )
-		Mode = flags
-	End Method
-
-	Method CanvasGraphics:TGraphics()
-		If Not canvas Then
-			canvas = BRL.Graphics.AttachGraphics(gdk_x11_drawable_get_xid(gtk_widget_get_window(handle)), Mode)
-		End If
-
-		Return canvas
-	End Method
-
-	Method Activate:Int(cmd:Int)
-		If cmd <> ACTIVATE_REDRAW Then
-			Super.Activate(cmd)
-		End If
-
-		Select cmd
-			Case ACTIVATE_REDRAW
-				gtk_widget_queue_draw(handle)
-		End Select
-	End Method
-
-	Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		Local x:Double, y:Double, button:Int
-		bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
-
-		If button = 3 Then
-			button = 2
-		Else If button = 2 Then
-			button = 3
-		End If
-
-		PostGuiEvent(EVENT_MOUSEDOWN, TGadget(obj),button,,x,y)
-
-		Return True
-	End Function
-	
-	Function OnScroll(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		Local x:Double, y:Double, direction:Int
-		bmx_gtk3maxgui_gdkeventscroll(event, Varptr x, Varptr y, Varptr direction)
-
-		If direction = GDK_SCROLL_UP Or direction = GDK_SCROLL_LEFT Then
-			PostGuiEvent(EVENT_MOUSEWHEEL, TGadget(obj),-1,,x,y)
-		Else
-			PostGuiEvent(EVENT_MOUSEWHEEL, TGadget(obj),1,,x,y)
-		End If
-	End Function
-
-	Function OnMouseUp:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		Local x:Double, y:Double, button:Int
-		bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
-
-		If button = 3 Then
-			button = 2
-		Else If button = 2 Then
-			button = 3
-		End If
-
-		PostGuiEvent(EVENT_MOUSEUP, TGadget(obj),button,,x,y)
-
-		Return True
-	End Function
-
-	Function OnMouseEnter:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		PostGuiEvent(EVENT_MOUSEENTER, TGadget(obj))
-
-		Return True
-	End Function
-
-	Function OnMouseLeave:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-
-		PostGuiEvent(EVENT_MOUSELEAVE, TGadget(obj))
-
-		Return True
-	End Function
-
-	'Rem
-	'bbdoc: Callback for mouse movement
-	'End Rem
-	Function OnMouseMove:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		Local x:Double, y:Double, button:Int
-		bmx_gtk3maxgui_gdkeventmotion(event, Varptr x, Varptr y, Varptr button)
-
-		If button & GDK_BUTTON1_MASK Then
-			button = 1
-		Else If button & GDK_BUTTON3_MASK Then
-			button = 2
-		Else If button & GDK_BUTTON2_MASK Then
-			button = 3
-		Else
-			button = 0
-		End If
-		PostGuiEvent(EVENT_MOUSEMOVE, TGadget(obj),button,,x,y)
-
-		Return True
-	End Function
-
-	Function OnKeyDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		Local _key:Int, _mods:Int
-		bmx_gtk3maxgui_gdkeventkey(event, Varptr _key, Varptr _mods)
-		Local key:Int = TGTKKeyMap.mapBack(_key)
-		Local mods:Int = TGTKKeyMap.mapModifierBack(_mods)
-
-		If Not gtk3SetKeyDown(key) Then
-			PostGuiEvent(EVENT_KEYDOWN, TGadget(obj), key, mods)
-		Else
-			PostGuiEvent(EVENT_KEYREPEAT, TGadget(obj), key, mods)
-		End If
-
-		Local char:Int = gdk_keyval_to_unicode(_key)
-		' we sometimes get 0 from this function when key is valid... so set it to key just so that it has a value.
-		If char = 0 And key <> 0 Then
-			char = key
-		End If
-		PostGuiEvent(EVENT_KEYCHAR, TGadget(obj), char, mods)
-
-		Return True
-	End Function
-
-	Function OnKeyUp:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		Local _key:Int, _mods:Int
-		bmx_gtk3maxgui_gdkeventkey(event, Varptr _key, Varptr _mods)
-		Local key:Int = TGTKKeyMap.mapBack(_key)
-		Local mods:Int = TGTKKeyMap.mapModifierBack(_mods)
-		
-		gtk3SetKeyUp(key)
-		PostGuiEvent(EVENT_KEYUP, TGadget(obj), key, mods)
-
-		Return True
-	End Function
-
-	Method free:Int()
-		Super.free()
-		
-		If canvas
-			canvas.Close()
-			canvas = Null
-		End If
-		
-		If handle 
-			gtk_widget_destroy(handle)
-		EndIf
-		handle = Null
-	End Method
-End Type
-End Rem
-
-Rem
-bbdoc: A text area.
-End Rem
-Type TGTKDefaultTextArea Extends TGTKTextArea
-
-	Field _tabsize:Int = 4
-
-	Field scrollWindow:Byte Ptr
-	Field _textBuffer:Byte Ptr
-	Field _textTagTable:Byte Ptr
-	Field _tabArray:Byte Ptr
-	Field ignoreChange:Int
-	Field fastUpdate:Int = False
-	
-	'Field _selStart:Int
-	'Field _selEnd:Int
-
-	Function CreateTextArea:TGTKTextArea(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Local this:TGTKDefaultTextArea = New TGTKDefaultTextArea
-
-		this.initTextArea(x, y, w, h, label, group, style)
-
-		Return this
-	End Function
-
-	Method initTextArea(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		_textBuffer = gtk_text_buffer_new(Null)
-		_textTagTable = gtk_text_buffer_get_tag_table(_textBuffer)
-
-		handle = gtk_text_view_new_with_buffer(_textBuffer)
-		gtk_widget_show(handle)
-		
-		' we need these events to allow tooltips to work
-		gtk_widget_add_events(handle, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK)
-
-		' use word-wrapping ?
-		If style & TEXTAREA_WORDWRAP Then
-			gtk_text_view_set_wrap_mode(handle, GTK_WRAP_WORD_CHAR)
-		End If
-
-		' a read-only textarea ?
-		If style & TEXTAREA_READONLY Then
-			gtk_text_view_set_editable(handle, False)
-		End If
-
-		Init(GTK_TEXTFIELD, x, y, w, h, style)
-
-		' scrollbars for the textarea...
-		scrollWindow = gtk_scrolled_window_new(Null, Null)
-		' set container resize mode
-		gtk_container_set_resize_mode(scrollWindow, GTK_RESIZE_QUEUE)
-		' set scrollbar policy
-		gtk_scrolled_window_set_policy(scrollWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC)
-		' show
-		gtk_widget_show(scrollWindow)
-
-		' add the text area to the scroll window
-		gtk_container_add(scrollWindow, handle)
-
-
-		addConnection("changed", g_signal_cb2(_textBuffer, "changed", OnTextChanged, Self, Destroy, 0))
-		addConnection("move-cursor", g_signal_cb5(handle, "move-cursor", OnCursorMoved, Self, Destroy, 0))
-		addConnection("button-press-event", g_signal_cb3_ret(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
-		addConnection("button-release-event", g_signal_cb3_ret(handle, "button-release-event", OnMouseUp, Self, Destroy, 0))
-		addConnection("key-press-event", g_signal_cb3_ret(handle, "key-press-event", OnKeyDown, Self, Destroy, 0))
-		addConnection("focus-out-event", g_signal_cb3_ret(handle, "focus-out-event", OnFocusLost, Self, Destroy, 0))
-
-		'g_signal_cb3(handle, "visibility-notify-event", OnVisibilityChange, Self, Destroy, 0)
-
-		gtk_layout_put(TGTKContainer(group).container, scrollwindow, x, y)
-		gtk_widget_set_size_request(handle, w, Max(h,0))
-	End Method
-
-	Rem
-	bbdoc: Callback for text change
-	End Rem
-	Function OnTextChanged(widget:Byte Ptr, obj:Object)
-		If Not TGTKDefaultTextArea(obj).ignoreChange Then
-			PostGuiEvent(EVENT_GADGETSELECT, TGadget(obj))
-			PostGuiEvent(EVENT_GADGETACTION, TGadget(obj))
-		End If
-		TGTKDefaultTextArea(obj).ignoreChange = False
-	End Function
-
-	Rem
-	bbdoc: Callback for text-cursor movement
-	End Rem
-	Function OnCursorMoved(widget:Byte Ptr, _Step:Int, count:Int, extend_selection:Int, obj:Object)
-		PostGuiEvent(EVENT_GADGETSELECT, TGadget(obj))
-	End Function
-
-	Rem
-	bbdoc: Callback for mouse button press
-	End Rem
-	Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		Local x:Double, y:Double, button:Int
-		bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
-
-		If button = 3 Then ' right mouse button
-			' ignore this...  see MouseUp for menu event!
-			Return True
-		End If
-
-		PostGuiEvent(EVENT_GADGETSELECT, TGadget(obj))
-	End Function
-
-	Rem
-	bbdoc: Callback for mouse button release
-	End Rem
-	Function OnMouseUp:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
-		Local x:Double, y:Double, button:Int
-		bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
-
-		If button = 3 Then ' right mouse button
-			PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),,,x,y)
-			Return True
-		End If
-
-		PostGuiEvent(EVENT_GADGETSELECT, TGadget(obj))
-	End Function
-	
-	Rem
-	bbdoc: Adds text to the end of the text.
-	End Rem
-	Method AddText:Int(text:String)
-		Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
-		' get the end of the text
-		gtk_text_buffer_get_end_iter(_textBuffer, _end)
-
-		ignoreChange = True
-		Local textPtr:Byte Ptr = text.ToUTF8String()
-		gtk_text_buffer_insert(_textBuffer, _end, textPtr, -1)
-		MemFree(textPtr)
-
-		gtk_text_buffer_get_end_iter(_textBuffer, _end)
-?bmxng
-		IWrappedSystemDriver(SystemDriver()).GetDriver().Poll()
-?Not bmxng
-		brl.System.Driver.Poll() ' update events, before scrolling to the end...
-?
-		gtk_text_view_scroll_to_iter(handle, _end, 0, False, 0, 0)
-		
-		bmx_gtk3_gtktextiter_free(_end)
-	End Method
-
-	Rem
-	bbdoc: Returns the text For the specified location
-	End Rem
-	Method AreaText:String(pos:Int, length:Int, units:Int)
-		Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
-		Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
-
-		If units = TEXTAREA_LINES Then
-			gtk_text_buffer_get_iter_at_line(_textBuffer, _start, pos)
-			gtk_text_buffer_get_iter_at_line(_textBuffer, _end, pos + length)
-
-		Else ' must be TEXTAREA_CHARS
-			gtk_text_buffer_get_iter_at_offset(_textBuffer, _start, pos)
-			gtk_text_buffer_get_iter_at_offset(_textBuffer, _end, pos + length)
-
-		End If
-
-		Local s:Byte Ptr = gtk_text_buffer_get_text(_textBuffer, _start, _end, False)
-		Local st:String = String.FromUTF8String(s)
-		g_free(s)
-		
-		bmx_gtk3_gtktextiter_free(_start)
-		bmx_gtk3_gtktextiter_free(_end)
-		
-		Return st
-	End Method
-
-	Rem
-	bbdoc: Returns either the number of characters or number of rows.
-	End Rem
-	Method AreaLen:Int(units:Int)
-		If units = TEXTAREA_LINES Then
-			Return gtk_text_buffer_get_line_count(_textBuffer)
-		Else
-			Return gtk_text_buffer_get_char_count(_textBuffer)
-		End If
-	End Method
-
-	Rem
-	bbdoc: Returns the current cursor position value, in characters or lines
-	End Rem
-	Method GetCursorPos:Int(units:Int)
-		Local pos:Int = 0
-		Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
-		Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
-
-		' Since the cursor position might be at the end of selected text, we get the selection
-		' bounds and get the *start* location. If there is no selection, start and end will be the same
-
-		gtk_text_buffer_get_selection_bounds(_textBuffer, _start, _end)
-		
-		If units = TEXTAREA_LINES Then
-			pos = gtk_text_iter_get_line(_start)
-		Else ' must be TEXTAREA_CHARS
-			pos = gtk_text_iter_get_offset(_start)
-		End If
-
-		bmx_gtk3_gtktextiter_free(_start)
-		bmx_gtk3_gtktextiter_free(_end)
-
-		Return pos
-	End Method
-
-	Rem
-	bbdoc: Set the text area visibility.
-	End Rem
-	Method SetShow:Int(truefalse:Int)
-		visible = truefalse
-		mySetVisible = visible
-		
-		If truefalse Then
-			gtk_widget_show(handle)
-			gtk_widget_show(scrollWindow)
-		Else
-			gtk_widget_hide(scrollWindow)
-		EndIf
-	End Method
-
-	Rem
-	bbdoc: Set the text area font.
-	End Rem
-	Method SetFont:Int(font:TGuiFont)
-		Super.SetFont(font)
-
-		' we need to reset the tabs, as it is lost when font is changed.
-		SetTabs(_tabsize)
-	End Method
-
-	Rem
-	bbdoc: Sets the text buffer text
-	End Rem
-	Method SetText:Int(text:String)
-		ignoreChange = True
-		Local textPtr:Byte Ptr = text.ToUTF8String()
-		gtk_text_buffer_set_text(_textBuffer, textPtr, -1)
-		MemFree(textPtr)
-
-		' move the cursor to the start
-		Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
-		gtk_text_buffer_get_iter_at_line(_textBuffer, _start, 0)
-		gtk_text_buffer_place_cursor(_textBuffer, _start)
-		gtk_text_view_scroll_mark_onscreen(handle, gtk_text_buffer_get_insert(_textBuffer))', 0, False, 0, 0.1)
-		
-		bmx_gtk3_gtktextiter_free(_start)
-	End Method
-
-	Rem
-	bbdoc: Set the text area selection
-	End Rem
-	Method SetSelection:Int(pos:Int, length:Int, units:Int)
-
-		Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
-		Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
-
-		If units = TEXTAREA_LINES Then
-			gtk_text_buffer_get_iter_at_line(_textBuffer, _start, pos)
-			gtk_text_buffer_get_iter_at_line(_textBuffer, _end, pos + length)
-
-		Else ' must be TEXTAREA_CHARS
-			gtk_text_buffer_get_iter_at_offset(_textBuffer, _start, pos)
-			gtk_text_buffer_get_iter_at_offset(_textBuffer, _end, pos + length)
-
-		End If
-
-		gtk_text_buffer_place_cursor(_textBuffer, _start)
-		gtk_text_view_scroll_mark_onscreen(handle, gtk_text_buffer_get_insert(_textBuffer))
-		
-		gtk_text_buffer_select_range(_textBuffer, _start, _end)
-
-		PostGuiEvent(EVENT_GADGETSELECT, Self)
-
-		' scroll to the start of the selection
-		' NOTE: setting param4 to False causes it to scroll only as much as required to show the start
-		' Set to True to cause it to always display at the same point on the visible area.
-		gtk_text_view_scroll_to_iter(handle, _start, 0, False, 0, 0.1)
-
-		bmx_gtk3_gtktextiter_free(_start)
-		bmx_gtk3_gtktextiter_free(_end)
-	End Method
-
-	Rem
-	bbdoc: Returns the size of the current selection, in characters or lines.
-	End Rem
-	Method GetSelectionLength:Int(units:Int)
-		Local length:Int = 0
-
-		Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
-		Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
-
-		Local hasSelection:Int = gtk_text_buffer_get_selection_bounds(_textBuffer, _start, _end)
-
-		If hasSelection Then
-
-			If units = TEXTAREA_LINES Then
-
-				length = gtk_text_iter_get_line(_end) - gtk_text_iter_get_line(_start)
-
-			Else ' must be TEXTAREA_CHARS
-
-				length = gtk_text_iter_get_offset(_end) - gtk_text_iter_get_offset(_start)
-
-			End If
-
-		End If
-
-		bmx_gtk3_gtktextiter_free(_start)
-		bmx_gtk3_gtktextiter_free(_end)
-
-		Return length
-	End Method
-
-	Rem
-	bbdoc: Sets the style of part of the text area
-	about: @flags are any mix of TEXTFORMAT_BOLD, TEXTFORMAT_ITALIC, TEXTFORMAT_UNDERLINE and TEXTFORMAT_STRIKETHROUGH.<br>
-	We utilise the buffers' tag table to cache tags that we reuse - based on the attributes.
-	This way we only create one for each different style we actually use in the buffer.<br>
-	Note: "fastUpdate" flag enables or disables the use of gtk_text_buffer_remove_all_tags which strips
-	old tags from the area before applying the new one.<br>
-	Ideally, you would first remove tags before applying new ones, but since removal is slow, the following
-	method can work well :
-	<pre>
-	setFastUpdate(false)
-	SetStyle on whole intended area to "normal" style
-	setFastUpdate(true)
-	iterate thru tokens applying styles..
-	</pre>
-	End Rem
-	Method SetStyle:Int(r:Int, g:Int, b:Int, flags:Int, pos:Int, length:Int, units:Int)
-
-		' Build a style string
-		Local s:Int = r Shl 24 | g Shl 16 | b Shl 8 | (flags & $ff)
-		Local styleText:String = String(s)
-
-		' Does this one already exist?
-		Local _textTag:Byte Ptr = gtk_text_tag_table_lookup(_textTagTable, styleText)
-
-		' nope... so we need to create it
-		If _textTag = Null Then
-
-			Local color:GdkRGBA = New GdkRGBA(r / 255.0, g / 255.0, b / 255.0)
-'
-			Local _style:Int = PANGO_STYLE_NORMAL
-			If flags & TEXTFORMAT_ITALIC Then
-				_style = PANGO_STYLE_ITALIC
-			End If
-			Local _weight:Int = PANGO_WEIGHT_NORMAL
-			If flags & TEXTFORMAT_BOLD Then
-				_weight = PANGO_WEIGHT_BOLD
-			End If
-			Local _under:Int = PANGO_UNDERLINE_NONE
-			If flags & TEXTFORMAT_UNDERLINE Then
-				_under = PANGO_UNDERLINE_SINGLE
-			End If
-			Local _strike:Int = False
-			If flags & TEXTFORMAT_STRIKETHROUGH Then
-				_strike = True
-			End If
-
-			' create and setup the tag
-			_textTag = bmx_gtk3_set_text_tag_style(_textBuffer, styleText, color, _style, _weight, _under, _strike)
-			
-		End If
-
-		applyStyle(pos, length, units, _textTag)
-		
-	End Method
-	
-	Method applyStyle(pos:Int, length:Int, units:Int, _textTag:Byte Ptr)
-		' set up start and end points
-		Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
-		Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
-
-		If units = TEXTAREA_LINES Then
-			gtk_text_buffer_get_iter_at_line(_textBuffer, _start, pos)
-			gtk_text_buffer_get_iter_at_line(_textBuffer, _end, pos + length)
-		Else ' must be TEXTAREA_CHARS
-			gtk_text_buffer_get_iter_at_offset(_textBuffer, _start, pos)
-			gtk_text_buffer_get_iter_at_offset(_textBuffer, _end, pos + length)
-		End If
-
-		' remove any existing tags in the range first - otherwise they'll just pile up
-		' NOTE : except that this is REALLY slow....
-		If Not fastUpdate Then
-			gtk_text_buffer_remove_all_tags(_textBuffer, _start, _end)
-		End If
-
-		' apply the tag to the range
-		gtk_text_buffer_apply_tag(_textBuffer, _textTag, _start, _end)
-		
-		bmx_gtk3_gtktextiter_free(_start)
-		bmx_gtk3_gtktextiter_free(_end)
-	End Method
-
-	Method SetBGStyle(r:Int, g:Int, b:Int, pos:Int, length:Int, units:Int)
-
-		' Build a style string
-		Local styleText:String = r + "_" + g + "_" + b + "_bg"
-
-		' Does this one already exist?
-		Local _textTag:Byte Ptr = gtk_text_tag_table_lookup(_textTagTable, styleText)
-
-		' nope... so we need to create it
-		If _textTag = Null Then
-
-			Local color:GdkRGBA = New GdkRGBA(r / 255.0, g / 255.0, b / 255.0)
-		
-			' create and setup the tag
-			_textTag = bmx_gtk3_set_text_bg_tag(_textBuffer, styleText, color)
-
-		End If
-
-		applyStyle(pos, length, units, _textTag)
-
-	End Method	
-
-	Method ReplaceText:Int(pos:Int, length:Int, text:String, units:Int)
-
-		If length = TEXTAREA_ALL Then
-			SetText(text)
-		Else
-			' set up start and end points
-			Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
-			Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
-	
-			If units = TEXTAREA_LINES Then
-				gtk_text_buffer_get_iter_at_line(_textBuffer, _start, pos)
-				gtk_text_buffer_get_iter_at_line(_textBuffer, _end, pos + length)
-			Else ' must be TEXTAREA_CHARS
-				gtk_text_buffer_get_iter_at_offset(_textBuffer, _start, pos)
-				gtk_text_buffer_get_iter_at_offset(_textBuffer, _end, pos + length)
-			End If
-	
-			' remove the specified range
-			gtk_text_buffer_delete(_textBuffer, _start, _end)
-	
-			' insert new text
-			Local textPtr:Byte Ptr = text.ToUTF8String()
-			gtk_text_buffer_insert(_textBuffer, _start, textPtr, -1)
-			MemFree(textPtr)
-			
-			bmx_gtk3_gtktextiter_free(_start)
-			bmx_gtk3_gtktextiter_free(_end)
-		End If
-	End Method
-
-	Rem
-	bbdoc: Locks the text area.
-	End Rem
-	Method LockText:Int()
-		gtk_text_view_set_editable(handle, False)
-	End Method
-
-	Rem
-	bbdoc: Unlocks the text area
-	End Rem
-	Method UnlockText:Int()
-		gtk_text_view_set_editable(handle, True)
-	End Method
-
-	Rem
-	bbdoc: 
-	End Rem
-	Method SetTabs:Int(tabs:Int)
-
-		' cache the current size
-		_tabsize = tabs
-
-		' get the current tab array - returns Null if default 8-space setting
-		_tabArray = gtk_text_view_get_tabs(handle)
-		
-		If _tabArray <> Null Then
-			pango_tab_array_free(_tabArray)
-		End If
-
-		Local tabmul:Int = 8 * 1024
-		If _font <> Null Then
-			tabmul = _font.size * 1024
-		End If
-
-		_tabArray = pango_tab_array_new_with_positions(1, False, PANGO_TAB_LEFT, tabs * tabmul)
-		gtk_text_view_set_tabs(handle, _tabArray)
-
-	End Method
-
-	Method CharAt:Int(line:Int)
-		Local _iter:Byte Ptr = bmx_gtk3_gtktextiter_new()
-		gtk_text_buffer_get_iter_at_line(_textBuffer, _iter, line)
-		Local ret:Int = gtk_text_iter_get_offset(_iter)
-		bmx_gtk3_gtktextiter_free(_iter)
-		Return ret
-	End Method
-
-	Method LineAt:Int(index:Int)
-		Local _iter:Byte Ptr = bmx_gtk3_gtktextiter_new()
-		gtk_text_buffer_get_iter_at_offset(_textBuffer, _iter, index)
-		Local ret:Int = gtk_text_iter_get_line(_iter)
-		bmx_gtk3_gtktextiter_free(_iter)
-		Return ret
-	End Method
-
-	Method free:Int()
-		Super.Free()
-
-		If scrollWindow Then
-			gtk_widget_destroy(scrollWindow)
-		EndIf
-		handle = Null
-		scrollWindow = Null
-
-	End Method
-
-	Method Activate:Int(cmd:Int)
-		Super.Activate(cmd)
-
-		Select cmd
-			Case ACTIVATE_CUT
-				Local clipboard:Byte Ptr = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", True))
-				gtk_text_buffer_cut_clipboard(_textBuffer, clipboard, True)
-
-			Case ACTIVATE_COPY
-				Local clipboard:Byte Ptr = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", True))
-				gtk_text_buffer_copy_clipboard(_textBuffer, clipboard)
-
-			Case ACTIVATE_PASTE
-				Local clipboard:Byte Ptr = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", True))
-				gtk_text_buffer_paste_clipboard(_textBuffer, clipboard, Null, True)
-
-		End Select
-	End Method
-	
-	Rem
-	bbdoc: Enable to allow *fast* formatting.
-	about: When enabled, highlighting will not be removed before being applied, and since
-	tags are ordered, some highlight may not appear on top of others.
-	End Rem
-	Method setFastUpdate(bool:Int)
-		fastUpdate = bool
-	End Method
-	
-	Method Rethink:Int()
-		If handle Then
-			gtk_layout_move(TGTKContainer(parent).container, scrollWindow, Max(xpos, 0), Max(ypos, 0))
-			gtk_widget_set_size_request(scrollWindow, Max(width,0), Max(height,0))
-		End If
-	End Method
-
-End Type
-
-
-
-Rem
-bbdoc: A base type for html view gadgets.
-about: Implementations are in seperate modules.<br>
-See bah.gtkwebmozilla and bah.gtkwebgtkhtml mods.
-End Rem
-Type TGTKHTMLView Extends TGTKGadget
-	Function CreateHTMLView:TGTKHTMLView(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int) Abstract
-	
-	Method Stop() Abstract
-	Method SetText:Int(url:String) Abstract
-	Method GetText:String() Abstract
-
-End Type
-
-Type TGTKWebDriver
-	Function CreateHTMLView:TGTKHTMLView(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int) Abstract
-End Type
-
-Global gtk3maxgui_htmlview:TGTKWebDriver
-
-Rem
-bbdoc: A base type for text area gadgets.
-about: Implementations are in seperate modules, except for the default TGTKDefaultTextArea
-End Rem
-Type TGTKTextArea Extends TGTKEditable
-	Function CreateTextArea:TGTKTextArea(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int) Abstract
-
-End Type
-
-
-Type TGTKTextAreaDriver
-	Function CreateTextArea:TGTKTextArea(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int) Abstract
-End Type
-
-' default text area driver
-Type TGTKDefaultTextAreaDriver Extends TGTKTextAreaDriver
-	Function CreateTextArea:TGTKTextArea(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
-		Return TGTKDefaultTextArea.CreateTextArea(x, y, w, h, label, group, style)
-	End Function
-End Type
-
-Global gtk3maxgui_textarea:TGTKTextAreaDriver
-
-
-Extern
-	Function g_object_get_menudata:TGTKMenuItem(handle:Byte Ptr, name:Byte Ptr) = "g_object_get_data"
-End Extern
+' Copyright (c) 2006-2018 Bruce A Henderson
+' 
+' Permission is hereby granted, free of charge, to any person obtaining a copy
+' of this software and associated documentation files (the "Software"), to deal
+' in the Software without restriction, including without limitation the rights
+' to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+' copies of the Software, and to permit persons to whom the Software is
+' furnished to do so, subject to the following conditions:
+' 
+' The above copyright notice and this permission notice shall be included in
+' all copies or substantial portions of the Software.
+' 
+' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+' THE SOFTWARE.
+' 
+SuperStrict
+
+Import "gtkcommon.bmx"
+
+Type TGTKGadget Extends TGadget
+
+	Field iclass:Int
+	' usually the pointer to the gtk widget
+	Field handle:Byte Ptr
+
+	Field menubar:Byte Ptr
+	Field menu:Byte Ptr
+
+	' reference to this gadgets' font (if we've ever set it programmatically)
+	Field _font:TGuiFont
+
+	' a map to hold connection handler ids... sometimes we need to disconnect the little buggers.
+	Field connectionMap:TMap = New TMap
+
+	' a unique identifier for this gadget
+	Field accelMapId:String
+	Field accelString:String
+	Field hasAccel:Int
+	
+	Field initialSizing:Int = False
+
+	Field mySetVisible:Int = True
+	Field visible:Int = False
+	
+	' the class id of this gadget in MaxGUI terms.
+	Field maxguiClass:Int
+	
+	Method Init(GadgetClass:Int, _x:Int, _y:Int, _w:Int, _h:Int, _style:Int)
+		SetRect(_x,_y,_w,_h)
+		iclass = GadgetClass
+		kids = New TList
+		style = _style
+	End Method
+
+	Method addConnection(name:String, id:Int)
+		connectionMap.Insert(name, TGTKInteger.Set(id))
+	End Method
+
+	Function Destroy(data:Byte Ptr, closure:Byte Ptr)
+		'Print "Destroy Handler"
+	End Function
+
+	Function Create:TGTKGadget(GadgetClass:Int, x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int, mgclass:Int)
+
+		Local gadget:TGTKGadget
+		
+		Select GadgetClass
+			Case GTK_WINDOW
+				gadget = TGTKWindow.CreateWindow(x, y ,w , h, label, group, style)
+			Case GTK_BUTTON
+				gadget = TGTKButtonPush.CreateButton(x, y ,w , h, label, group, style)
+			Case GTK_RADIOBUTTON
+				gadget = TGTKButtonRadio.CreateButton(x, y ,w , h, label, group, style)
+			Case GTK_CHECKBUTTON
+				gadget = TGTKButtonCheckbox.CreateButton(x, y ,w , h, label, group, style)
+			Case GTK_LABEL
+				gadget = TGTKLabel.CreateLabel(x, y ,w , h, label, group, style)
+			Case GTK_MENUITEM
+				gadget = TGTKMenuItem.CreateMenuItem(label, style, group)
+			Case GTK_TEXTFIELD
+				gadget = TGTKTextField.CreateTextField(x, y ,w , h, label, group, style)
+			Case GTK_HTMLVIEW
+				If gtk3maxgui_htmlview Then
+					gadget = gtk3maxgui_htmlview.CreateHTMLView(x, y ,w , h, label, group, style)
+				Else
+					Throw "No HTMLView specified. You need To Import one!    " + ..
+						" Import Gtk.gtk3webkitgtk"
+				End If
+			Case GTK_TABBER
+				gadget = TGTKTabber.CreateTabber(x, y ,w , h, label, group, style)
+			Case GTK_PANEL
+				gadget = TGTKPanel.CreatePanel(x, y ,w , h, label, group, style)
+			Case GTK_COMBOBOX
+				gadget = TGTKComboBox.CreateComboBox(x, y ,w , h, label, group, style)
+			Case GTK_PROGRESSBAR
+				gadget = TGTKProgressBar.CreateProgressBar(x, y ,w , h, label, group, style)
+			Case GTK_STEPPER
+				gadget = TGTKStepper.CreateStepper(x, y ,w , h, label, group, style)
+			Case GTK_SCROLLBAR
+				gadget = TGTKScrollBar.CreateScrollBar(x, y ,w , h, label, group, style)
+			Case GTK_TRACKBAR
+				gadget = TGTKTrackBar.CreateTrackBar(x, y ,w , h, label, group, style)
+			Case GTK_TEXTAREA
+				' no custom text area? use the default
+				If Not gtk3maxgui_textarea Then
+					gtk3maxgui_textarea = New TGTKDefaultTextAreaDriver
+				End If
+				gadget = gtk3maxgui_textarea.CreateTextArea(x, y ,w , h, label, group, style)
+			Case GTK_TOOLBAR
+				gadget = TGTKToolbar.CreateToolBar(x, y ,w , h, label, group, style)
+			Case GTK_LISTBOX
+				gadget = TGTKListbox.CreateListBox(x, y ,w , h, label, group, style)
+			Case GTK_TREEVIEW
+				gadget = TGTKTreeView.CreateTreeView(x, y ,w , h, label, group, style)
+Rem 
+			Case GTK_CANVAS
+				gadget = TGTKCanvas.CreateCanvas(x, y ,w , h, label, group, style)
+End Rem
+		End Select
+
+		' map the new gadget - so we can find it later if required
+		If gadget Then
+			GadgetMap.Insert(gadget.handle, gadget)
+		End If
+		
+		If group Then
+			gadget._SetParent group
+		End If
+		gadget.SetShape x,y,w,h
+		' set the maxgui class type
+		gadget.maxguiClass = mgclass
+
+		Return gadget
+	End Function
+
+	Method Delete()
+		Free()
+	End Method
+
+	Method Free:Int()
+		Local gadget:TGTKGadget
+		Local rkids:TList		
+		rkids=kids.Reversed()
+		For gadget = EachIn rkids
+			gadget.Free	
+		Next
+		gadget = TGTKGadget(parent)
+		If gadget Then
+			gadget.kids.remove Self
+		End If
+
+		' remove reference from global reference map
+		If handle Then
+			GadgetMap.Remove(handle)
+		End If
+		
+		connectionMap.Clear()
+		
+	End Method
+
+	Rem
+	bbdoc: Show or hide the gadget.
+	End Rem
+	Method SetShow:Int(truefalse:Int)
+		visible = truefalse
+		mySetVisible = visible
+		
+		If truefalse Then
+			gtk_widget_show(handle)
+		Else
+			gtk_widget_hide(handle)
+		EndIf
+		
+		UpdateChildVisibility()
+	End Method
+
+	Method UpdateChildVisibility()
+		For Local gadget:TGTKGadget = EachIn kids
+			If Not visible Then
+				gadget.visible = False
+			Else
+				gadget.visible = gadget.mySetVisible
+			End If
+			
+			gadget.UpdateChildVisibility()
+		Next
+	End Method
+
+	' checks text for mnemonics
+	Method processText:String(txt:String)
+		' convert underscores to doubles
+		txt = txt.Replace("_", "__")
+
+		txt = txt.Replace("&&", "$^^$")
+		txt = txt.Replace("&", "_")
+		txt = txt.Replace("$^^$", "&")
+		
+		Return txt
+	End Method
+
+	Method setAccelEntry(keycode:Int, modifier:Int)
+		Local accelKey:Int
+		Local modKey:Int
+		
+		If accelString And hasAccel Then
+			Local accelPtr:Byte Ptr = accelString.ToUTF8String()
+			gtk_accelerator_parse(accelPtr, Varptr accelKey, Varptr modKey)
+			MemFree(accelPtr)
+			If accelKey <> 0 Then
+				gtk_widget_remove_accelerator(handle, getWindow().accelGroup, accelKey, modKey)
+				hasAccel = False
+			End If
+		End If
+
+		' enabling accelerator?	
+		If keycode Then
+			accelString = TGTKKeyMap.accelToString(keycode, modifier)
+			Local accelPtr:Byte Ptr = accelString.ToUTF8String()
+			gtk_accelerator_parse(accelPtr, Varptr accelKey, Varptr modKey)
+			MemFree(accelPtr)
+			gtk_widget_add_accelerator(handle, "activate", getWindow().accelGroup, accelKey, modKey, GTK_ACCEL_VISIBLE)
+			hasAccel = True
+		End If
+	End Method
+	
+	Method setAccelMapId(id:String)
+		accelMapId = id.Replace("&", "")
+	End Method
+
+	' returns the widgets window
+	Method getWindow:TGTKWindow()
+		If Not TGTKWindow(Self) Then
+			If TGTKGadget(parent) Then
+				Return TGTKGadget(parent).getWindow()
+			Else
+				Return Null
+			End If
+		End If
+		
+		Return TGTKWindow(Self)
+	End Method
+
+	Rem
+	bbdoc: Callback for focus lost.
+	End Rem
+	Function OnFocusLost:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		PostGuiEvent(EVENT_GADGETLOSTFOCUS, TGadget(obj))
+	End Function
+	
+	Rem
+	bbdoc: Set the gadget tooltip.
+	End Rem
+	Method setToolTip:Int(tip:String)
+		If tip And tip.length > 0 Then
+			Local tipPtr:Byte Ptr = tip.ToUTF8String()
+			gtk_widget_set_tooltip_text(handle, tipPtr)
+			MemFree(tipPtr)
+		Else
+			gtk_widget_set_has_tooltip(handle, False)
+		End If
+	End Method
+
+	Rem
+	bbdoc: Perform an activation command on the gadget.
+	End Rem
+	Method Activate:Int(cmd:Int)
+		Select cmd
+			Case ACTIVATE_FOCUS
+				gtk_widget_grab_focus(handle)
+			Case ACTIVATE_FORWARD
+			Case ACTIVATE_BACK
+			Case ACTIVATE_REDRAW
+				redraw()
+				PostGuiEvent(EVENT_GADGETPAINT, Self)
+		End Select
+	End Method
+	
+	Method redraw()
+		gtk_widget_queue_draw(handle)
+	End Method
+
+	Rem
+	bbdoc: Return the gadget's client width.
+	End Rem
+	Method ClientWidth:Int()
+		If initialSizing Then
+?bmxng
+			Local minReq:GtkRequisition 
+			Local natReq:GtkRequisition
+?Not bmxng
+			Local minReq:GtkRequisition = New GtkRequisition
+			Local natReq:GtkRequisition = New GtkRequisition
+?
+			gtk_widget_get_preferred_size(handle, minReq, natReq)
+
+			Return natReq.width
+		End If
+		Return width
+	End Method
+
+	Rem
+	bbdoc: Return the gadget's client height.
+	End Rem
+	Method ClientHeight:Int()
+		If initialSizing Then
+?bmxng
+			Local minReq:GtkRequisition 
+			Local natReq:GtkRequisition
+?Not bmxng
+			Local minReq:GtkRequisition = New GtkRequisition
+			Local natReq:GtkRequisition = New GtkRequisition
+?
+			gtk_widget_get_preferred_size(handle, minReq, natReq)
+
+			Return natReq.height
+		End If
+		Return height
+	End Method
+
+	Method Rethink:Int()
+		If handle
+			gtk_layout_move(TGTKContainer(parent).container, handle, Max(xpos,0), Max(ypos,0))
+			gtk_widget_set_size_request(handle, Max(width,0), Max(height,0))
+		End If
+	End Method
+
+	Rem
+	bbdoc: Return the gadget state.
+	End Rem
+	Method State:Int()
+		Local flags:Int
+		Local _state:Int = gtk_widget_get_state_flags(handle)
+
+		Select _state
+			Case GTK_STATE_FLAG_INSENSITIVE
+				flags:| STATE_DISABLED
+			Case GTK_STATE_FLAG_SELECTED
+				flags:| STATE_SELECTED
+			Case GTK_STATE_FLAG_ACTIVE
+				flags:| STATE_ACTIVE
+		End Select
+
+		If Not gtk_widget_get_visible(handle) Then
+			flags:| STATE_HIDDEN
+		End If
+
+		Return flags
+	End Method
+
+End Type
+
+Rem
+bbdoc: The Desktop.
+End Rem
+Type TGTKDesktop Extends TGTKGadget
+
+	Function CreateDesktop:TGTKDesktop()
+		Local this:TGTKDesktop = New TGTKDesktop
+
+		this.initDesktop()
+
+		Return this
+	End Function
+
+	Method initDesktop()
+
+		iclass = GTK_DESKTOP
+
+		handle = gdk_screen_get_default()
+
+		SetArea(0, 0, gdk_screen_get_width(handle), gdk_screen_get_height(handle))
+
+	End Method
+
+	Method Rethink:Int()
+	End Method
+
+	Rem
+	bbdoc: Returns the desktop width.
+	End Rem
+	Method ClientWidth:Int()
+		Return width
+	End Method
+
+	Rem
+	bbdoc: Returns the desktop height.
+	End Rem
+	Method ClientHeight:Int()
+		Return height
+	End Method
+	
+	Rem
+	bbdoc: Returns the desktop depth.
+	End Rem
+	Method GetDepth:Int()
+		Local visual:Byte Ptr = gdk_screen_get_system_visual(handle)
+		Return gdk_visual_get_depth(visual)
+	End Method
+	
+	Rem
+	bbdoc: Returns the desktop hertz.
+	End Rem
+	Method GetHertz:Int()
+		Return bmx_gtk3_gtkdesktop_gethertz()
+	End Method
+	
+	Rem
+	bbdoc: Returns the desktop scale factor that maps from window coordiantes to the actual device pixels.
+	about: On traditional systems this is 1, but on very high density outputs this can be a higher value (often 2).
+	End Rem
+	Method ScaleFactor:Int()
+		Return gdk_screen_get_monitor_scale_factor(handle, 0)
+	End Method
+
+End Type
+
+Rem
+bbdoc: This type handles "internal" widget containers for "Container" gadgets.
+End Rem
+Type TGTKContainer Extends TGTKGadget
+
+	' a multi-row container
+	Field box:Byte Ptr
+
+	' the "Fixed" container that we place gadgets onto
+	Field container:Byte Ptr
+
+	' dont need to free this, as removing radio buttons from it will free itself when empty
+	Field radioGroup:Byte Ptr
+	
+	' initialize the container stuff
+	Method Init(GadgetClass:Int, x:Int, y:Int, w:Int, h:Int, style:Int)
+		Super.init(GadgetClass, x, y, w, h, style)
+
+	End Method
+
+	Method ClientWidth:Int()
+		Return width
+	End Method
+
+	Method ClientHeight:Int()
+		Return height
+	End Method
+
+
+End Type
+
+Rem
+bbdoc: A Window
+End Rem
+Type TGTKWindow Extends TGTKContainer
+
+	Field statusbar:Byte Ptr
+	Field sblabels:Byte Ptr[]
+	
+	Field toolbar:TGTKToolbar
+	Field accelGroup:Byte Ptr
+
+	Field oldCW:Int
+	Field oldCH:Int
+	
+	Field _maximized:Int
+	Field _minimized:Int
+	
+	Field ignoreMoveEvent:Int
+	Field ignoreSizeEvent:Int
+	
+	Function CreateWindow:TGTKWindow(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Local this:TGTKWindow = New TGTKWindow
+
+		this.initWindow(x, y, w, h, label, group, style)
+
+		gtkWindows.addLast(this)
+		
+		Return this
+	End Function
+
+	Method initWindow(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+
+		If group And TGTKDesktop(group)
+			group = Null
+		End If
+		
+		' should only be a window parent!!
+		If group Then
+			Assert TGTKWindow(group), "group not TGTKWindow!"
+		End If
+
+		handle = gtk_window_new(GTK_WINDOW_TOPLEVEL)
+
+		Init(GTK_WINDOW, x, y, w, h, style)
+
+		' container BEGIN
+		box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0)
+		gtk_widget_show(box)
+
+		If style & WINDOW_MENU Then
+			menubar = gtk_menu_bar_new()
+			gtk_box_pack_start(box, menubar, False, True, 0)
+			gtk_widget_show(menubar)
+		End If
+
+		container = gtk_layout_new(Null, Null)
+		
+		gtk_widget_show(container)
+		gtk_box_pack_start(box, container, True, True, 0)
+		' container END
+
+		If style & WINDOW_STATUS Then
+			createStatusbar()
+			SetStatusText("")
+		EndIf
+
+		If (LocalizationMode() & LOCALIZATION_OVERRIDE) Then
+			LocalizeGadget(Self, label)
+		Else
+			SetText(label)
+		EndIf
+
+		gtk_window_move(handle, x, y)
+		gtk_window_set_default_size(handle, w, calcHeight(h))
+
+		gtk_window_set_decorated(handle, (style & WINDOW_TITLEBAR))
+		gtk_window_set_resizable(handle, (style & WINDOW_RESIZABLE))
+		
+		If style & WINDOW_TOOL Then
+			gtk_window_set_type_hint(handle, GDK_WINDOW_TYPE_HINT_UTILITY)
+		End If
+
+		gtk_container_add(handle, box)
+		' some funky window setting up...
+		' It's all rather fiddly, but it appears to work.
+
+?bmxng
+		Local geom:GdkGeometry
+?Not bmxng
+		Local geom:GdkGeometry = New GdkGeometry
+?
+'DebugStop
+		Local hints:Int = 0
+		If style & WINDOW_RESIZABLE Then
+			hints:| GDK_HINT_USER_SIZE
+			geom.minWidth = 16
+			geom.minHeight = 16
+		
+			hints:| GDK_HINT_RESIZE_INC
+			geom.widthInc = 1
+			geom.heightInc = 1
+		Else
+			geom.minWidth = w
+			geom.minHeight = calcHeight(h)
+		End If
+		geom.maxWidth = -1
+		geom.maxHeight = -1
+
+		If Not (style & WINDOW_CLIENTCOORDS) Then
+			geom.baseWidth = w
+			geom.baseHeight = calcHeight(h)
+		Else
+			geom.baseWidth = -1
+			geom.baseHeight = -1
+		End If
+		gtk_window_set_geometry_hints(handle, box, geom, GDK_HINT_POS | GDK_HINT_MIN_SIZE | ..
+			GDK_HINT_BASE_SIZE | GDK_HINT_USER_POS | hints)
+
+		If Not(style & WINDOW_RESIZABLE) Then
+			gtk_widget_set_size_request(handle, w, calcHeight(h))
+		End If
+
+		' connect this window with its parent
+		If group And (style & WINDOW_CHILD) Then
+			gtk_window_set_transient_for(handle, TGTKWindow(group).handle)
+		End If
+
+		Rem
+		A Window produces the following events:
+		EVENT_WINDOWMOVE	Window has been moved
+		EVENT_WINDOWSIZE	Window has been resized
+		EVENT_WINDOWCLOSE	Window close icon clicked
+		EVENT_WINDOWACTIVATE	Window activated
+		EVENT_WINDOWACCEPT	Drag and Drop operation was attempted
+		End Rem
+		' move
+		addConnection("configure-event", g_signal_cb3(handle, "configure-event", OnWindowMoveSize, Self, Destroy, 0))
+		' size
+		addConnection("check-resize", g_signal_cb2(handle, "check-resize", OnWindowSize, Self, Destroy, 0))
+		' close
+		addConnection("delete-event", g_signal_cb3_ret(handle, "delete-event", OnWindowClose, Self, Destroy, 0))
+		' activate
+		addConnection("focus-in-event", g_signal_cb3(handle, "focus-in-event", OnWindowActivate, Self, Destroy, 0))
+		addConnection("focus-out-event", g_signal_cb3_ret(handle, "focus-out-event", OnWindowDeactivate, Self, Destroy, 0))
+		' accept
+		'g_signal_cb3(handle, "XXXXXX", WindowAccept, Self, Destroy, 0)
+		' minimize / maximize
+		addConnection("window-state-event", g_signal_cb3_ret(handle, "window-state-event", OnWindowStateChange, Self, Destroy, 0))
+
+		If style & WINDOW_ACCEPTFILES Then
+
+			'Local entries:Byte Ptr
+			
+			'gtk_drag_dest_set(container, GTK_DEST_DEFAULT_DROP | GTK_DEST_DEFAULT_HIGHLIGHT, Varptr entries, 0, GDK_ACTION_COPY)
+			'gtk_drag_dest_add_uri_targets(container)
+			'gtk_drag_dest_add_text_targets(container)
+			
+			'g_signal_cb6(container, "drag-drop", OnDragDrop, Self, Destroy, 0)
+		End If
+		
+		' used for tabbers - ensure they are redrawn properly when required
+		'g_signal_cb7(container, "draw-background", OnDraw, Self, Destroy, 0)
+
+		accelGroup = gtk_accel_group_new()
+		gtk_window_add_accel_group(handle, accelGroup)
+		setAccelMapId(label)
+
+		If ~style & WINDOW_HIDDEN
+			Setshow(True)
+		Else
+			SetShow(False)
+		End If
+
+	End Method
+
+	Method calcHeight:Int(requestedHeight:Int)
+		If Not (style & WINDOW_CLIENTCOORDS) Then
+			Return requestedHeight	
+		Else
+?bmxng
+			Local minReq:GtkRequisition 
+			Local natReq:GtkRequisition
+?Not bmxng
+			Local minReq:GtkRequisition = New GtkRequisition
+			Local natReq:GtkRequisition = New GtkRequisition
+?
+			If statusbar Then
+				gtk_widget_get_preferred_size(statusbar, minReq, natReq)
+				requestedHeight:+ natReq.height
+			End If
+			If menubar Then
+				gtk_widget_get_preferred_size(menubar, minReq, natReq)
+				requestedHeight:+ natReq.height
+			End If
+			
+			Return requestedHeight
+		End If
+	End Method
+
+	Method deCalcHeight:Int(actualHeight:Int)
+		If Not (style & WINDOW_CLIENTCOORDS) Then
+			Return actualHeight	
+		Else
+?bmxng
+			Local minReq:GtkRequisition 
+			Local natReq:GtkRequisition
+?Not bmxng
+			Local minReq:GtkRequisition = New GtkRequisition
+			Local natReq:GtkRequisition = New GtkRequisition
+?
+			If statusbar Then
+				gtk_widget_get_preferred_size(statusbar, minReq, natReq)
+				actualHeight:- natReq.height
+			End If
+			If menubar Then
+				gtk_widget_get_preferred_size(statusbar, minReq, natReq)
+				actualHeight:- natReq.height
+			End If
+
+			Return actualHeight
+		End If
+	End Method
+	
+	Rem
+	bbdoc: Callback for window size / move
+	End Rem
+	Function OnWindowMoveSize(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		Local x:Int, y:Int, w:Int, h:Int
+		bmx_gtk3maxgui_gdkeventconfigure(event, Varptr x, Varptr y, Varptr w, Varptr h)
+
+		Local win:TGTKWindow = TGTKWindow(obj)
+		If win Then
+			Local change:Int = False
+			
+			h = win.deCalcHeight(h)
+			
+			' Has the window actually changed size/position?
+			If win.width <> w Or win.height <> h Then
+				change = True
+
+				If Not win.ignoreSizeEvent Then
+					PostGuiEvent(EVENT_WINDOWSIZE, TGadget(obj),,,w,h)
+				End If
+			End If
+			
+			gtk_window_get_position(win.handle, Varptr x, Varptr y)
+			
+			If win.xpos <> x Or win.ypos <> y Then
+				change = True
+
+				If Not win.ignoreMoveEvent Then
+					PostGuiEvent(EVENT_WINDOWMOVE, TGadget(obj),,,x,y)
+				End If
+			End If
+
+			If win.ClientHeight() <> win.oldCH Or win.ClientWidth() <> win.oldCW Then
+				win.oldCH = win.ClientHeight()
+				win.oldCW = win.ClientWidth()
+
+				change = True
+			End If
+			
+			' something has changed.. we need to update ourself and tell the children.
+			If change Then
+				win.setRect(x, y, w, h)
+				win.layoutkids()
+			End If
+			
+			win.ignoreMoveEvent = False
+			win.ignoreSizeEvent = False
+		End If
+
+	End Function
+	
+	Method Rethink:Int()
+		gtk_window_move(handle, xpos, ypos)
+		If style & WINDOW_RESIZABLE Then
+			gtk_window_resize(handle, width, calcHeight(height))
+		Else
+			gtk_window_set_default_size(handle, width, calcHeight(height))
+		End If
+		
+		layoutkids() ' we need to do this so the children know we've really changed.
+	End Method
+
+	Rem
+	bbdoc: Callback for window size.
+	about: This event doesn't actually trigger a max size event, but we use it to adjust the client
+	size.
+	End Rem
+	Function OnWindowSize(widget:Byte Ptr, obj:Object)
+		Local win:TGTKWindow = TGTKWindow(obj)
+		If win Then
+			If win.ClientHeight() <> win.oldCH Or win.ClientWidth() <> win.oldCW Then
+				win.oldCH = win.ClientHeight()
+				win.oldCW = win.ClientWidth()
+
+				TGTKContainer(obj).rethink()
+			End If
+		End If
+	End Function
+
+	Rem
+	bbdoc: Callback for window state change.
+	End Rem	
+	Function OnWindowStateChange:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		Local statemask:Int
+		bmx_gtk3maxgui_gdkeventwindowstate(event, Varptr statemask)
+		
+		Local win:TGTKWindow = TGTKWindow(obj)
+		If win Then
+			If statemask & GDK_WINDOW_STATE_ICONIFIED Then
+				win._minimized = Not win._minimized
+			End If
+			
+			If statemask & GDK_WINDOW_STATE_MAXIMIZED Then
+				win._maximized = Not win._maximized
+				
+				' when maximized, we can't be minimized... so clear it
+				If win._maximized Then
+					win._minimized = False
+				End If
+			End If
+
+		End If
+	End Function
+
+	Rem
+	bbdoc: Callback for window close
+	End Rem
+	Function OnWindowClose:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		PostGuiEvent(EVENT_WINDOWCLOSE, TGadget(obj))
+		Return True ' we don't want it to close - that's a user decision :-p
+	End Function
+	
+	Rem
+	bbdoc: Callback for window activate
+	End Rem
+	Function OnWindowActivate(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		PostGuiEvent(EVENT_WINDOWACTIVATE, TGadget(obj))
+	End Function
+
+	Rem
+	bbdoc: Callback for window deactivate
+	about: Not used, but might come in handy at some point...
+	End Rem
+	Function OnWindowDeactivate:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		' We catch this but don't act on it...
+		Return False
+	End Function
+	
+	Function OnDragDrop:Int(widget:Byte Ptr, context:Byte Ptr, x:Int, y:Int, time:Int, obj:Object)
+Print "OnDragDrop"
+	End Function
+
+	Method SetShape:Int(x:Int,y:Int,w:Int,h:Int)
+		If x <> xpos Or y <> ypos Then
+			ignoreMoveEvent = True
+		End If
+		If w <> width Or h <> height Then
+			ignoreSizeEvent = True
+		End If
+		Super.SetShape(Max(x, 0), Max(y, 0), w, h)
+	End Method
+
+	Rem
+	bbdoc: Set the window status text
+	End Rem
+	Method SetStatusText:Int(text:String)
+		If statusbar Then
+
+			Local t:Int, m0:String, m1:String, m2:String
+			m0 = text
+			t = m0.find("~t")
+			If t <> -1 Then
+				m1 = m0[t+1..]
+				m0 = m0[..t]
+			End If
+			t = m1.find("~t")
+			If t <> -1 Then
+				m2 = m1[t+1..]
+				m1 = m1[..t]
+			End If
+			
+			Local mb0:Byte Ptr = m0.ToUTF8String()
+			Local mb1:Byte Ptr = m1.ToUTF8String()
+			Local mb2:Byte Ptr = m2.ToUTF8String()
+			gtk_label_set_text(sblabels[0], mb0)
+			gtk_label_set_text(sblabels[1], mb1)
+			gtk_label_set_text(sblabels[2], mb2)
+			MemFree(mb2)
+			MemFree(mb1)
+			MemFree(mb0)
+
+			If m0.length = 0 And m1.length = 0 And m2.length = 0 Then
+				gtk_widget_show(sblabels[0])
+				gtk_widget_hide(sblabels[1])
+				gtk_widget_hide(sblabels[2])
+			Else
+				If m0.length > 0 Then
+					gtk_widget_show(sblabels[0])
+				Else
+					gtk_widget_hide(sblabels[0])
+				End If
+				
+				If m1.length > 0 Then
+					gtk_widget_show(sblabels[1])
+				Else
+					gtk_widget_hide(sblabels[1])
+				End If
+				
+				If m2.length > 0 Then
+					gtk_widget_show(sblabels[2])
+				Else
+					gtk_widget_hide(sblabels[2])
+				End If
+			End If
+		End If
+	End Method
+
+	Method GetMenu:TGadget()
+		Return Self
+	End Method
+	
+	Method createStatusbar()
+		' our "statusbar" is actually a horizontal box...
+		statusbar = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0)
+		gtk_widget_show(statusbar)
+
+		sblabels = New Byte Ptr[3]
+		
+		For Local i:Int = 0 Until 3
+		
+			Local sblabel:Byte Ptr = gtk_label_new("")
+
+			sblabels[i] = sblabel
+			
+			If i = 0 Then
+				gtk_misc_set_alignment(sblabel, 0, 0.5)
+				'gtk_label_set_yalign(sblabel, 0.5) ' 3.16
+			Else If i = 2 Then
+				gtk_misc_set_alignment(sblabel, 1, 0.5)
+				'gtk_label_set_xalign(sblabel, 1) ' 3.16
+				'gtk_label_set_yalign(sblabel, 0.5) ' 3.16
+			End If
+			
+			gtk_box_pack_start(statusbar, sblabel, True, True, 0)
+		Next
+		
+		' add to the window!
+		gtk_box_pack_start(box, statusbar, False, True, 0)
+	End Method
+
+	Method addToolbar(_toolbar:TGTKToolbar)
+		If toolbar <> Null Then
+			toolbar.free()
+		End If
+
+		toolbar = _toolbar
+
+		' add to the list
+		gtk_box_pack_start(box, toolbar.handle, False, False, 0)
+
+		' we need to move this to the correct place (usually under the menu)
+		If menubar Then
+			gtk_box_reorder_child(box, toolbar.handle, 1)
+		Else
+			gtk_box_reorder_child(box, toolbar.handle, 0)			
+		End If
+
+	End Method
+
+	Method ClientHeight:Int()
+?bmxng
+		Local allocation:GtkAllocation
+?Not bmxng
+		Local allocation:GtkAllocation = New GtkAllocation
+?
+
+		gtk_widget_get_allocation(container, allocation)
+		Local h:Int = allocation.height
+		If h <= 8 Then
+			h = height
+?bmxng
+			Local minReq:GtkRequisition 
+			Local natReq:GtkRequisition
+?Not bmxng
+			Local minReq:GtkRequisition = New GtkRequisition
+			Local natReq:GtkRequisition = New GtkRequisition
+?
+
+			If statusbar Then
+				gtk_widget_get_preferred_size(statusbar, minReq, natReq)
+				h:- natReq.height
+			End If
+			If menubar Then
+				gtk_widget_get_preferred_size(menubar, minReq, natReq)
+				h:- natReq.height
+			End If
+
+		End If
+
+		If toolbar Then
+			h:- toolbar.height
+		End If
+	
+		Return h
+	End Method
+
+	Method ClientWidth:Int()
+
+?bmxng
+		Local allocation:GtkAllocation
+?Not bmxng
+		Local allocation:GtkAllocation = New GtkAllocation
+?
+		gtk_widget_get_allocation(handle, allocation)
+		Local w:Int = allocation.width
+
+		If w <= 8 Then
+			w = width
+		End If
+
+		Return w
+	End Method
+
+	Rem
+	bbdoc: Pop up a popup menu
+	End Rem
+	Method PopupMenu:Int(menu:TGadget,extra:Object=Null)
+		If TGTKMenuItem(menu) Then
+			If TGTKMenuItem(menu).popupMenu Then
+				TGTKMenuItem(menu).popupExtra = extra
+				gtk_menu_popup(TGTKMenuItem(menu).popupMenu, Null, Null, Null, Null, 0, gtk_get_current_event_time())
+			End If
+		End If
+	End Method
+
+	Method free:Int()
+		Super.Free()
+
+		If handle 
+			gtk_widget_destroy(handle)
+		EndIf
+		handle = Null
+
+		gtkWindows.remove(Self)
+	End Method
+
+	Method Activate:Int(cmd:Int)
+		Super.Activate(cmd)
+		
+		If Not visible Return 0
+
+		Select cmd
+			Case ACTIVATE_MAXIMIZE
+				gtk_window_maximize(handle)
+			Case ACTIVATE_MINIMIZE
+				gtk_window_iconify(handle)
+			Case ACTIVATE_RESTORE
+				' since we need to remember if we are maximized while being minimized
+				' we check for minimized first...
+				If _minimized Then
+					gtk_window_deiconify(handle)
+				Else If _maximized Then
+					gtk_window_unmaximize(handle)
+				End If
+			Case ACTIVATE_FOCUS
+				gtk_window_present(handle)
+		End Select
+	End Method
+	
+	Method SetMinimumSize:Int(w:Int, h:Int)
+?bmxng
+		Local geom:GdkGeometry
+?Not bmxng
+		Local geom:GdkGeometry = New GdkGeometry
+?
+		gtk_window_set_geometry_hints(handle, Null, geom, GDK_HINT_MIN_SIZE)
+	End Method
+
+	Rem
+	bbdoc: Sets the window icon with the specified pixmap.
+	End Rem
+	Method setIcon(pix:TPixmap)
+		If pix <> Null Then
+			Local pixmap:TPixmap = pix.convert( PF_RGBA8888 )
+			Local icon:Byte Ptr = gdk_pixbuf_new_from_data(pixmap.pixels, GDK_COLORSPACE_RGB, True, 8, ..
+						pixmap.width, pixmap.height, pixmap.Pitch, Null, Null)
+			gtk_window_set_icon(handle, icon)
+		End If
+	End Method
+	
+	Rem
+	bbdoc: Returns the window state.
+	End Rem
+	Method State:Int()
+		Local flags:Int = Super.state()
+		
+		' Note: you can be maximized and minimized at the same time, so that when
+		' we un-maximize (de-conify) it goes back to maximized.
+		' not sure if we should set them both in this instance. "Not" at the moment...
+		If _minimized Then
+			flags:| STATE_MINIMIZED
+		Else If _maximized Then
+			flags:| STATE_MAXIMIZED
+		End If
+		
+		Return flags
+	End Method
+
+	Method SetText:Int(text:String)
+		Local textPtr:Byte Ptr = text.ToUTF8String()
+		gtk_window_set_title(handle, textPtr)
+		MemFree(textPtr)
+	End Method
+	
+	Method GetText:String()
+		Return String.FromUTF8String(gtk_window_get_title(handle))
+	End Method
+
+	Method toString:String()
+		Return "TGTKWindow"
+	End Method
+End Type
+
+Rem
+bbdoc: A menu item.
+End Rem
+Type TGTKMenuItem Extends TGTKGadget
+	
+	Field popupMenu:Byte Ptr
+
+	Field tag:Int = 0
+	Field ignoreSelection:Int
+	Field isCheckable:Int
+	Field hasMnemonic:Int
+	Field isSeparator:Int
+	Field checked:Int
+	Field text:String
+	Field index:Int
+	Field isStockItem:Int
+	
+	Global popupExtra:Object
+
+	' we use these to remember keycode and modifier just in case we need to make this
+	' menu item a check-type - in which case we delete and create a new one.
+	Field myKeycode:Int
+	Field myModifier:Int
+	
+	Field windowAccelGroup:Byte Ptr
+	
+	Field pixmap:TPixmap
+	Field imagePixbuf:Byte Ptr
+	Field image:Byte Ptr
+	
+	Function CreateMenuItem:TGTKMenuItem(label:String, tag:Int, parent:TGadget)
+		Local this:TGTKMenuItem = New TGTKMenuItem
+
+		this.initMenu(label, tag, parent)
+
+		Return this
+	End Function
+
+	Method initMenu(_label:String, _tag:Int, _parent:TGadget)
+		iclass = GTK_MENUITEM
+		tag = _tag
+		
+		Local originalLabel:String = _label
+
+		If TGTKWindow(_parent) Then
+			windowAccelGroup = TGTKWindow(_parent).accelGroup
+		Else If TGTKMenuItem(_parent)
+			windowAccelGroup = TGTKMenuItem(_parent).windowAccelGroup
+		Else
+			'Throw "menu item has no valid parent"
+			' A popupmenu... perhaps?
+			windowAccelGroup = Null
+		End If
+
+		' localisation
+		If (LocalizationMode() & LOCALIZATION_OVERRIDE) Then
+			MapInsert maxgui_driver._mapLocalized, Self, [_label,""]
+			_label = LocalizeString(_label)
+		End If
+
+		setAccelMapId(_label)
+
+
+		' this is our menu item / text
+		If _label = Null Or _label.length = 0 Then
+			' a separator
+			handle = gtk_separator_menu_item_new()
+			isSeparator = True
+		Else
+	
+			' convert underscores to doubles
+			'_label = _label.replace("_", "__")
+
+			' a normal menu item
+			' Does it have a 
+			Local p:Int = _label.find("&")
+
+			_label = processText(_label)
+			Local _labelPtr:Byte Ptr = _label.ToUTF8String()
+			
+			' does this label have a mnemonic?
+			If p >= 0 Then
+				'_label = _label.replace("&", "_")
+				hasMnemonic = True
+
+				handle = gtk_menu_item_new_with_mnemonic(_labelPtr)
+
+			Else
+
+				handle = gtk_menu_item_new_with_label(_labelPtr)
+
+			End If
+			MemFree(_labelPtr)
+		End If
+
+		text = _label
+
+		' let's hope that at least the parent is set!!
+		If _parent Then
+
+			parent = _parent
+
+			If TGTKWindow(parent) Then
+
+				Assert TGTKWindow(parent).menubar, "Cannot add menu to window created without WINDOW_MENU"
+
+				' add a new menu for the menubar
+				' Note : we never show this!! (on purpose)
+				menu = gtk_menu_new()
+
+				' attach the menu text to the menu
+				gtk_menu_item_set_submenu(handle, menu)
+
+				' add the menu to the menubar
+				' Need to make sure we have a menubar to add it to...
+				' In debug mode we'll have failed the above assertion already.
+				If TGTKWindow(parent).menubar Then
+					gtk_menu_shell_append(TGTKWindow(parent).menubar, handle)
+				End If
+
+			Else If TGTKMenuItem(parent) Then
+
+				If TGTKMenuItem(parent).popupMenu Then
+					gtk_container_add(TGTKMenuItem(parent).popupMenu, handle)
+				Else
+					' we may need to create a sub menu to hold this!
+					If Not TGTKMenuItem(parent).menu Then
+						TGTKMenuItem(parent).menu = gtk_menu_new()
+	
+						' attach the menu text to the menu
+						gtk_menu_item_set_submenu(TGTKMenuItem(parent).handle, TGTKMenuItem(parent).menu)
+	
+					End If
+	
+					gtk_menu_shell_append(TGTKMenuItem(parent).menu, handle)
+					
+				End If
+				' we need to know our position in the menu
+				index = parent.kids.count()
+			End If
+
+			gtk_widget_show(handle)
+
+			' Add an activate signal and store ourself in the menu data
+			If Not TGTKWindow(parent) And Not isSeparator Then
+				addConnection("activate", g_signal_cb2_ret(handle, "activate", MenuSelected, Self, Destroy, 0))
+				g_object_set_data(handle, "_maxmenu", Self)
+			End If
+		Else ' popupmenu...
+			popupMenu = gtk_menu_new()
+
+			' don't add OUR menu item to the list, as it is only a place holder.
+			'gtk_container_add(popupMenu, handle)
+
+			gtk_widget_show(handle)
+		End If
+
+	End Method
+
+	Method SetHotKey:Int(keycode:Int, modifier:Int)
+		myKeycode = keycode
+		myModifier = modifier
+		
+		setAccelEntry(keycode, modifier)
+		
+		' override F10 menu access?
+		If keycode = KEY_F10 And modifier = 0 Then
+			Local settings:Byte Ptr = gtk_settings_get_default()
+			gtk_settings_set_string_property(settings, "gtk-menu-bar-accel", "<alt>F10", AppFile)
+		End If
+	End Method
+
+	Rem
+	bbdoc: Callback function for selecting a menu option.
+	about: Triggers a menu action event.<br>
+	NOTE - We have to ignore "obj" because it is not reliable
+	End Rem
+	Function MenuSelected:Int(widget:Byte Ptr, obj:Object)
+
+		Local _menu:TGTKMenuItem = g_object_get_menudata(widget, "_maxmenu")
+
+		Assert _menu, "Menu data is missing...  !!!!"
+
+		' If this isn't a submenu root (one which has sub menus)
+		' then we can post the event
+		If Not _menu.menu And Not _menu.ignoreSelection Then
+			PostGuiEvent(EVENT_MENUACTION, _menu, _menu.tag,,,,_menu.popupextra)
+			If _menu.popupExtra Then
+				_menu.popupExtra = Null
+			End If
+		End If
+
+		' We need to keep the "checked" flag uptodate...
+		If _menu.isCheckable Then
+			_menu.checked = gtk_check_menu_item_get_active(widget)
+		End If
+		
+		_menu.ignoreSelection = False
+
+		Return True
+
+	End Function
+
+	Method SetSelected:Int(bool:Int)
+
+		' Don't do anything if we are already set...
+		If (checked = bool) And isCheckable Then
+			Return 0
+		End If
+
+		ignoreSelection = True
+
+		' if it's not checkable yet, we need to make it so
+		If Not isCheckable And Not isSeparator And menu = Null Then
+			' remove the current menu
+			If handle Then
+				gtk_widget_destroy(handle)
+				hasAccel = False
+			End If
+
+			Local textPtr:Byte Ptr = text.ToUtf8String()
+			If hasMnemonic Then
+				handle = gtk_check_menu_item_new_with_mnemonic(textPtr)
+			Else
+				handle = gtk_check_menu_item_new_with_label(textPtr)
+			End If
+			MemFree(textPtr)
+			gtk_widget_show(handle)
+
+			' if we originally gave this a keycode / modifier, we need to re-establish it.
+			If myKeycode <> 0 Then
+				SetHotKey(myKeycode, myModifier)
+			End If
+
+			If TGTKWindow(parent) Then
+				' Only insert if menubar exists tho...
+				If TGTKWindow(parent).menubar Then
+					gtk_menu_shell_insert(TGTKWindow(parent).menubar, handle, index)
+				End If
+			Else If TGTKMenuItem(parent) Then
+				If TGTKMenuItem(parent).menu Then
+					gtk_menu_shell_insert(TGTKMenuItem(parent).menu, handle, index)
+				End If
+			EndIf
+
+			' we need to catch toggles!
+			addConnection("toggled", g_signal_cb2_ret(handle, "toggled", MenuSelected, Self, Destroy, 0))
+			g_object_set_data(handle, "_maxmenu", Self)
+
+			isCheckable = True
+
+			' If we are not setting it checked it won't generate a toggle event...
+			If Not bool Then
+				ignoreSelection = False
+			End If
+		End If
+
+		checked = bool
+
+		gtk_check_menu_item_set_active(handle, checked)
+	End Method
+
+	Rem
+	bbdoc: Returns menu state - checked or unchecked
+	End Rem
+	Method State:Int()
+		Local _state:Int = Super.State()
+	
+		If isCheckable Then
+			If gtk_check_menu_item_get_active(handle) Then
+				_state :| STATE_SELECTED
+			End If
+		End If
+
+		Return _state
+	End Method
+
+	Rem
+	bbdoc: Returns the menu text
+	End Rem
+	Method GetText:String()
+		If Not isSeparator Then
+			Return String.FromUTF8String(gtk_label_get_text(gtk_bin_get_child(handle)))
+		End If
+
+		Return ""
+	End Method
+
+	Rem
+	bbdoc: Sets the menu text
+	End Rem
+	Method SetText:Int(label:String)
+		If Not isSeparator Then
+			If label = Null Then
+				label = ""
+			End If
+			
+			text = processText(label)
+
+			Local labelPtr:Byte Ptr = text.ToUTF8String()
+			If label.find("&") >= 0 Then
+				gtk_label_set_text_with_mnemonic(gtk_bin_get_child(handle), labelPtr)
+			Else
+				gtk_label_set_text(gtk_bin_get_child(handle), labelPtr)
+			End If
+			MemFree(labelPtr)
+		End If
+	End Method
+	
+	Method Free:Int()
+		Super.Free()
+
+		If handle
+			gtk_widget_destroy(handle)
+		End If
+		handle = Null
+		menu = Null
+
+		If pixmap Then
+			pixmap = Null
+		End If
+		If image Then
+		'	g_object_unref(image) ' oops.. TODO: we might need this still.
+			image = Null
+		End If
+		If imagePixbuf Then
+			g_object_unref(imagePixbuf)
+			imagePixbuf = Null
+		End If
+
+	End Method
+
+	Method rethink:Int()
+	End Method
+
+	Method DoLayout:Int()
+	End Method
+
+	Method SetPixmap:Int(pix:TPixmap, flags:Int)
+		If Not isSeparator Then
+			If pix Then
+				If PixmapFormat(pix) <> PF_RGBA8888 And PixmapFormat(pix) <> PF_BGRA8888 Then
+					pixmap = pix.convert( PF_RGBA8888 )
+				Else
+					pixmap = pix
+				End If
+				
+				If imagePixbuf Then
+					g_object_unref(imagePixbuf)
+				End If
+	
+				imagePixbuf = gdk_pixbuf_new_from_data(pixmap.pixels, GDK_COLORSPACE_RGB, True, 8, ..
+								pixmap.width, pixmap.height, pixmap.Pitch, Null, Null)
+				
+				If Not image Then
+					image = gtk_image_new()
+				End If
+
+				gtk_image_set_from_pixbuf(image, imagePixbuf)
+			Else
+				If pixmap Then
+					gtk_image_clear(image)
+					pixmap = Null
+				End If
+			End If
+			
+			If image Then
+				' TODO
+				'gtk_image_menu_item_set_image(handle, image)
+			End If
+		End If
+	End Method
+
+	Method toString:String()
+		Return "TGTKMenuItem : " + text + " : " + Super.ToString()
+	End Method
+
+	Method SetEnabled:Int(bool:Int)
+		gtk_widget_set_sensitive(handle, bool)
+	End Method
+
+End Type
+
+Type TGTKIconStrip Extends TIconStrip
+
+	Field images:Byte Ptr[]
+	Field names:String[]
+
+	Function IsNotBlank:Int(pixmap:TPixmap)
+		Local w:Int = pixmap.width
+		Local h:Int = pixmap.height
+		Local c:Int = pixmap.ReadPixel(0,0) 			
+		For Local x:Int = 0 Until h
+			For Local y:Int = 0 Until h
+				If pixmap.ReadPixel(x,y) <> c Then
+					Return True
+				End If
+			Next
+		Next
+	End Function
+	
+	Function Create:TGTKIconStrip(source:Object)
+	
+		Local baseName:String = MilliSecs()
+	
+		Local pix:TPixmap = TPixmap(source)
+		If Not pix Then
+			pix = LoadPixmap(source)
+
+			If Not pix Then
+				Return Null
+			End If
+		End If
+		Local n:Int = pix.width/pix.height
+		If n = 0 Then
+			Return Null
+		End If
+
+		Local pixmap:TPixmap = pix.convert( PF_RGBA8888 )
+
+		Local icons:TGTKIconStrip = New TGTKIconStrip
+		icons.pixmap=pixmap
+		icons.count=n
+		icons.images=New Byte Ptr[n]
+		icons.names = New String[n]
+
+		Local h:Int = pixmap.height
+		Local w:Int = h
+
+		For Local x:Int = 0 Until n
+			Local winpix:TPixmap = pixmap.Window(x*w,0,w,pixmap.height)
+			If IsNotBlank(winpix) Then
+				icons.images[x]= gdk_pixbuf_new_from_data(winpix.pixels, GDK_COLORSPACE_RGB, True, 8, ..
+						w, h, pixmap.Pitch, Null, Null)
+				Local name:String = baseName + "_" + x
+				icons.names[x] = name
+				gtk_icon_theme_add_builtin_icon(name, h, icons.images[x])
+			End If
+		Next
+		Return icons
+	End Function
+
+End Type
+
+Rem
+bbdoc: Base type for button gadgets.
+End Rem
+Type TGTKButton Extends TGTKGadget
+
+	Field hotkey:THotKey
+
+	Field ignoreButtonClick:Int
+
+	Method makeButton(label:String) Abstract
+
+	Method initButton(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		
+		Init(iclass, x, y, w, h, style)
+
+		parent = group
+
+		' localisation
+		If (LocalizationMode() & LOCALIZATION_OVERRIDE) Then
+			MapInsert maxgui_driver._mapLocalized, Self, [label,""]
+			label = LocalizeString(label)
+		End If
+
+		makeButton(label)
+
+		setAccelMapId(label)
+
+		gtk_layout_put(TGTKContainer(parent).container, handle, x, y)
+		gtk_widget_set_size_request(handle, w, Max(h,0))
+
+		sensitivity:| SENSITIZE_MOUSE
+		
+		' Set as default ?
+		If style = BUTTON_OK Then
+			gtk_widget_grab_default(handle)
+		End If
+
+		setShow(True)
+
+		' button clicked handler
+		addConnection("clicked", g_signal_cb2(handle, "clicked", OnButtonClicked, Self, Destroy, 0))
+		' catch right-mouse buttons
+		addConnection("button-press-event", g_signal_cb3_ret(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
+
+		addConnection("enter-notify-event", g_signal_cb3_ret(handle, "enter-notify-event", OnMouseEnter, Self, Destroy, 0))
+		addConnection("leave-notify-event", g_signal_cb3_ret(handle, "leave-notify-event", OnMouseLeave, Self, Destroy, 0))
+
+	End Method
+
+	Rem
+	bbdoc: Callback for button click.
+	End Rem
+	Function OnButtonClicked(widget:Byte Ptr, obj:Object)
+		If Not TGTKButton(obj).ignoreButtonClick Then
+			PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), ButtonState(TGadget(obj)))
+		End If
+		
+		TGTKButton(obj).ignoreButtonClick = False
+	End Function
+
+	Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		Local x:Double, y:Double, button:Int
+		bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
+
+		If button = 3 Then ' right mouse button
+
+			PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),,,x,y)
+
+			Return True
+		End If
+
+		Return False
+	End Function
+
+	Function OnMouseEnter:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+	
+		If TGTKGadget(obj).visible Then
+			PostGuiEvent(EVENT_MOUSEENTER, TGadget(obj))
+		End If
+
+		Return False
+	End Function
+
+	Function OnMouseLeave:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+
+		If TGTKGadget(obj).visible Then
+			PostGuiEvent(EVENT_MOUSELEAVE, TGadget(obj))
+		End If
+
+		Return False
+	End Function
+
+	Rem
+	bbdoc: Sets the button text.
+	End Rem
+	Method SetText:Int(text:String)
+		text = processText(text)
+
+		Local textPtr:Byte Ptr = text.ToUTF8String()
+		gtk_button_set_label(handle, textPtr)
+		MemFree(textPtr)
+		gtk_button_set_use_underline(handle, True)
+	End Method
+
+	Rem
+	bbdoc: Returns the button text.
+	End Rem
+	Method GetText:String()
+		Return String.FromUTF8String(gtk_button_get_label(handle))
+	End Method
+
+	Rem
+	bbdoc: Sets the button text color.
+	End Rem
+	Method SetTextColor:Int(r:Int, g:Int, b:Int)
+		Local color:GdkRGBA = New GdkRGBA(r / 255.0, g / 255.0, b / 255.0)
+		
+		Local buttonLabel:Byte Ptr = gtk_bin_get_child(handle)
+		gtk_widget_override_color(buttonLabel, GTK_STATE_FLAG_NORMAL, color)
+		gtk_widget_override_color(buttonLabel, GTK_STATE_FLAG_ACTIVE, color)
+		gtk_widget_override_color(buttonLabel, GTK_STATE_FLAG_PRELIGHT, color)
+	End Method
+
+	Method free:Int()
+		Super.Free()
+
+		If handle 
+			gtk_widget_destroy(handle)
+		EndIf
+		handle = Null
+
+	End Method
+
+	Rem
+	bbdoc: Sets a hot key for the button.
+	End Rem
+	Method SetHotKey:Int(keycode:Int, modifier:Int)
+		setAccelEntry(keycode, modifier)
+	End Method
+
+	Method toString:String()
+		Return "TGTKButton"
+	End Method
+End Type
+
+Rem
+bbdoc: A push button
+End Rem
+Type TGTKButtonPush Extends TGTKButton
+
+	Function CreateButton:TGTKButtonPush(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Local this:TGTKButtonPush = New TGTKButtonPush
+
+		this.initButton(x, y, w, h, label, group, style)
+
+		Return this
+	End Function
+
+	Method makeButton(label:String)
+
+		label = processText(label)
+		
+		Local labelPtr:Byte Ptr = label.ToUTF8String()
+		handle = gtk_button_new_with_label(labelPtr)
+		MemFree(labelPtr)
+		gtk_button_set_use_underline(handle, True)
+
+		' enable "default" gadget functionality
+		g_object_set_int(handle, "can-default", True)
+	End Method
+
+	Method SetText:Int(text:String)
+		text = processText(text)
+
+		Local textPtr:Byte Ptr = text.ToUTF8String()
+		gtk_button_set_label(handle, textPtr)
+		MemFree(textPtr)
+		gtk_button_set_use_underline(handle, True)
+	End Method
+
+	Method SetPixmap:Int(pix:TPixmap, flags:Int = 0)
+		If pix Then
+			Local pixmap:TPixmap
+			If pix.format <> PF_RGBA8888 Then
+				pixmap = pix.convert( PF_RGBA8888 )
+			Else
+				pixmap = pix
+			End If
+	
+			Local image:Byte Ptr = gtk_image_new_from_pixbuf(gdk_pixbuf_new_from_data(pixmap.pixels, GDK_COLORSPACE_RGB, True, 8, ..
+						pixmap.width, pixmap.height, pixmap.Pitch, Null, Null))
+			If image Then
+				gtk_button_set_image(handle, image)
+				gtk_button_set_image_position(handle, GTK_POS_LEFT)
+			End If
+		End If
+	End Method
+
+	Method toString:String()
+		Return "TGTKButtonPush"
+	End Method
+
+End Type
+
+Rem
+bbdoc: A button which has a toggle-type usage (radio / checkbox)
+End Rem
+Type TGTKToggleButton Extends TGTKButton
+
+	Field isSelected:Int
+
+	Method SetSelected:Int(bool:Int)
+		If bool <> gtk_toggle_button_get_active(handle) Then
+			ignoreButtonClick = True
+		End If
+		
+		gtk_toggle_button_set_active(handle, bool)
+		
+		isSelected = bool
+	End Method
+
+	Method State:Int()
+		Local flags:Int = Super.State()
+
+		If gtk_toggle_button_get_active(handle) Then
+			flags:|STATE_SELECTED
+		End If
+
+		Return flags
+	End Method
+
+	Rem
+	bbdoc: Callback for button click.
+	End Rem
+	Function OnButtonClicked(widget:Byte Ptr, obj:Object)
+		If Not TGTKButton(obj).ignoreButtonClick Then
+			If TGTKToggleButton(obj).isSelected <> gtk_toggle_button_get_active(widget)
+				PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), ButtonState(TGadget(obj)))
+			End If
+			TGTKToggleButton(obj).isSelected = gtk_toggle_button_get_active(widget)
+		End If
+		
+		TGTKButton(obj).ignoreButtonClick = False
+	End Function
+
+	Method disableEvents()
+	End Method
+	
+	Method enableEvents()
+	End Method
+	
+End Type
+
+Rem
+bbdoc: A radio button.
+End Rem
+Type TGTKButtonRadio Extends TGTKToggleButton
+
+	Function CreateButton:TGTKButtonRadio(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Local this:TGTKButtonRadio = New TGTKButtonRadio
+
+		this.initButton(x, y, w, h, label, group, style)
+
+		Return this
+	End Function
+
+	Method makeButton(label:String)
+		Local _group:Byte Ptr = TGTKContainer(parent).radioGroup
+		label = processText(label)
+
+		Local labelPtr:Byte Ptr = label.ToUTF8String()
+		If _group = Null Then
+			handle = gtk_radio_button_new_with_label(Null, labelPtr)
+			gtk_toggle_button_set_active(handle, True)
+			isSelected = True
+		Else
+			handle = gtk_radio_button_new_with_label(_group, labelPtr)
+		End If
+		MemFree(labelPtr)
+		
+		' update the radiogroup, ready for a new radio button...
+		TGTKContainer(parent).radioGroup = gtk_radio_button_get_group(handle)
+		
+		gtk_button_set_use_underline(handle, True)
+		
+		If style & BUTTON_PUSH Then
+			gtk_toggle_button_set_mode(handle, False)
+		End If
+		
+	End Method
+
+	Method SetSelected:Int(bool:Int)
+		disableEvents()
+		
+		gtk_toggle_button_set_active(handle, bool)
+		
+		enableEvents()
+		
+		isSelected = bool
+	End Method
+
+	Function OnButtonClicked(widget:Byte Ptr, obj:Object)
+		TGTKToggleButton(obj).isSelected = gtk_toggle_button_get_active(widget)
+
+		If TGTKToggleButton(obj).isSelected Then
+			PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), ButtonState(TGadget(obj)))
+		End If
+		
+		TGTKButton(obj).ignoreButtonClick = False
+	End Function
+
+	Method disableEvents()
+		For Local gadget:TGTKButtonRadio = EachIn parent.kids
+			Local id:TGTKInteger = TGTKInteger(gadget.connectionMap.ValueForKey("clicked"))
+			If id Then
+				g_signal_handler_disconnect(gadget.handle, id.value)
+			End If
+		Next
+	End Method
+	
+	Method enableEvents()
+		For Local gadget:TGTKButtonRadio = EachIn parent.kids
+			gadget.addConnection("clicked", g_signal_cb2(gadget.handle, "clicked", OnButtonClicked, gadget, Destroy, 0))
+		Next
+	End Method
+
+	Method toString:String()
+		Return "TGTKButtonRadio"
+	End Method
+
+End Type
+
+Rem
+bbdoc: A checkbox button
+End Rem
+Type TGTKButtonCheckbox Extends TGTKToggleButton
+
+	Function CreateButton:TGTKButtonCheckbox(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Local this:TGTKButtonCheckbox = New TGTKButtonCheckbox
+
+		this.initButton(x, y, w, h, label, group, style)
+
+		Return this
+	End Function
+
+	Method makeButton(label:String)
+		label = processText(label)
+		
+		Local labelPtr:Byte Ptr = label.ToUTF8String()
+		handle = gtk_check_button_new_with_label(labelPtr)
+		MemFree(labelPtr)
+		
+		gtk_button_set_use_underline(handle, True)
+
+		If style & BUTTON_PUSH Then
+			gtk_toggle_button_set_mode(handle, False)
+		End If
+
+	End Method
+
+	Method toString:String()
+		Return "TGTKButtonCheckbox"
+	End Method
+
+End Type
+
+Rem
+bbdoc: A label.
+End Rem
+Type TGTKLabel Extends TGTKGadget
+
+	' surrounding frame widget, if any
+	Field frame:Byte Ptr
+	Field hasFrame:Int
+	Field isSeparator:Int
+	Field ebox:Byte Ptr
+
+	Function CreateLabel:TGTKLabel(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Local this:TGTKLabel = New TGTKLabel
+
+		this.initLabel(x, y, w, h, label, group, style)
+
+		Return this
+	End Function
+
+	Method initLabel(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Init(GTK_LABEL, x, y, w, h, style)
+
+		If style & LABEL_FRAME And style & LABEL_SUNKENFRAME Then
+			isSeparator = True
+		End If
+
+		If Not isSeparator Then
+			Local labelPtr:Byte Ptr = label.ToUTF8String()
+			handle = gtk_label_new(labelPtr)
+			MemFree(labelPtr)
+
+			If style & LABEL_RIGHT Then
+				gtk_misc_set_alignment(handle, 1, 0.5)
+			Else If style & LABEL_CENTER Then
+				gtk_misc_set_alignment(handle, 0.5, 0.5)	
+			Else
+				gtk_misc_set_alignment(handle, 0, 0.5)	
+			End If
+
+
+			sensitivity:| SENSITIZE_MOUSE
+			
+			' since a Label can't accept events, we wrap it inside an event box which can
+			ebox = gtk_event_box_new()
+			gtk_event_box_set_visible_window(ebox, False)
+			gtk_widget_add_events(ebox, GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK)
+			
+			addConnection("enter-notify-event", g_signal_cb3_ret(ebox, "enter-notify-event", OnMouseEnter, Self, Destroy, 0))
+			addConnection("leave-notify-event", g_signal_cb3_ret(ebox, "leave-notify-event", OnMouseLeave, Self, Destroy, 0))
+			addConnection("button-press-event", g_signal_cb3_ret(ebox, "button-press-event", OnMouseDown, Self, Destroy, 0))
+
+			' show the box
+			gtk_widget_show(ebox)
+			' add the label to the eventbox
+			gtk_container_add(ebox, handle)
+			
+			If (LocalizationMode() & LOCALIZATION_OVERRIDE) Then
+				LocalizeGadget(Self, label)
+			Else
+				SetText(label)
+			EndIf
+		End If
+
+		' Should we add a frame?
+		If style & LABEL_FRAME Or style & LABEL_SUNKENFRAME Then
+
+			hasFrame = True
+
+			If isSeparator Then
+				If w < h Then
+					frame = gtk_separator_new(GTK_ORIENTATION_VERTICAL)
+				Else
+					frame = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL)
+				End If
+				handle = frame
+			Else
+				frame = gtk_frame_new(Null)
+				If style & LABEL_FRAME Then
+					gtk_frame_set_shadow_type(frame, GTK_SHADOW_ETCHED_IN)
+				Else
+					gtk_frame_set_shadow_type(frame, GTK_SHADOW_IN)
+				End If
+
+				gtk_container_add(frame, ebox)
+
+			End If
+
+			gtk_layout_put(TGTKContainer(group).container, frame, x, y)
+			gtk_widget_set_size_request(frame, w, Max(h,0))
+
+		Else
+			gtk_layout_put(TGTKContainer(group).container, ebox, x, y)
+			gtk_widget_set_size_request(handle, w, Max(h,0))
+		End If
+
+		setShow(True)
+
+	End Method
+
+	Rem
+	bbdoc: Show or Hide the label
+	End Rem
+	Method SetShow:Int(truefalse:Int)
+		visible = truefalse
+		mySetVisible = visible
+		
+		If hasFrame Then
+			If truefalse Then
+				gtk_widget_show(frame)
+			Else
+				gtk_widget_hide(frame)
+			EndIf
+		End If
+
+		If Not isSeparator Then
+			If truefalse Then
+				gtk_widget_show(handle)
+				gtk_widget_show(ebox)
+			Else
+				gtk_widget_hide(ebox)
+			EndIf
+		End If
+	End Method
+
+	Method SetText:Int(text:String)
+		If Not isSeparator Then
+			Local textPtr:Byte Ptr = text.ToUtf8String()
+			gtk_label_set_text(handle, textPtr)
+			MemFree(textPtr)
+		End If
+	End Method
+	
+	Method GetText:String()
+		If Not isSeparator Then
+			Return String.FromUTF8String(gtk_label_get_text(handle))
+		End If
+		Return Null
+	End Method
+
+	Method free:Int()
+		Super.Free()
+
+		If frame
+			gtk_widget_destroy(frame)
+		Else
+			If ebox Then
+				gtk_widget_destroy(ebox)
+			End If
+		EndIf
+		handle = Null
+		frame = Null
+		ebox = Null
+
+	End Method
+
+	Method setToolTip:Int(tip:String)
+	
+		If Not isSeparator Then
+			If tip And tip.length > 0 Then
+				Local tipPtr:Byte Ptr = tip.ToUTF8String()
+				gtk_widget_set_tooltip_text(ebox, tipPtr)
+				MemFree(tipPtr)
+			Else
+				gtk_widget_set_has_tooltip(ebox, False)
+			End If
+		Else
+			If tip And tip.length > 0 Then
+				Local tipPtr:Byte Ptr = tip.ToUTF8String()
+				gtk_widget_set_tooltip_text(handle, tipPtr)
+				MemFree(tipPtr)
+			Else
+				gtk_widget_set_has_tooltip(handle, False)
+			End If
+		End If
+	End Method
+
+	Method Rethink:Int()
+		If frame Then
+			gtk_layout_move(TGTKContainer(parent).container, frame, Max(xpos, 0), Max(ypos, 0))
+			gtk_widget_set_size_request(frame, Max(width,0), Max(height,0))
+		Else If handle Then
+			gtk_layout_move(TGTKContainer(parent).container, ebox, Max(xpos, 0), Max(ypos, 0))
+			gtk_widget_set_size_request(handle, Max(width,0), Max(height,0))
+		End If
+	End Method
+
+	Function OnMouseEnter:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+	
+		If TGTKGadget(obj).visible Then
+			PostGuiEvent(EVENT_MOUSEENTER, TGadget(obj))
+		End If
+		
+		Return False
+	End Function
+
+	Function OnMouseLeave:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+
+		If TGTKGadget(obj).visible Then
+			PostGuiEvent(EVENT_MOUSELEAVE, TGadget(obj))
+		End If
+		
+		Return False
+	End Function
+
+	Rem
+	bbdoc: Callback For mouse button press.
+	End Rem
+	Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		Local x:Double, y:Double, button:Int
+		bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
+		
+		If button = 3 Then ' right mouse button
+
+			PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),,,x,y)
+
+		Else ' other mouse buttons
+			If button = 2 Then
+				button = 3
+			End If
+
+			PostGuiEvent(EVENT_MOUSEDOWN, TGadget(obj),button,,x,y)
+		End If
+		
+		Return True
+	End Function
+
+	Rem
+	bbdoc: Sets the label text color.
+	End Rem
+	Method SetTextColor:Int(r:Int, g:Int, b:Int)
+		Local color:GdkRGBA = New GdkRGBA(r / 255.0, g / 255.0, b / 255.0)
+
+		gtk_widget_override_color(handle, GTK_STATE_FLAG_NORMAL, color)
+
+	End Method
+
+	Method toString:String()
+		Return "TGTKLabel"
+	End Method
+End Type
+
+
+Rem
+bbdoc: Base type for editable gadgets (textfield / textarea).
+End Rem
+Type TGTKEditable Extends TGTKGadget
+
+	Field ignoreTextChange:Int
+
+	Method Activate:Int(cmd:Int)
+		Super.Activate(cmd)
+
+	End Method
+
+	Function OnTextChanged(widget:Byte Ptr, obj:Object)
+		If Not TGTKEditable(obj).ignoreTextChange Then
+			PostGuiEvent(EVENT_GADGETACTION, TGadget(obj))
+		End If
+		
+		If TGTKEditable(obj).ignoreTextChange Then
+			TGTKEditable(obj).ignoreTextChange:-1
+		End If
+	End Function
+
+	' key handler stuff - filtering etc
+	Function OnKeyDown:Int(widget:Byte Ptr, gdkEvent:Byte Ptr, obj:Object)
+		Local source:TGTKEditable = TGTKEditable(obj)
+
+		' only if we are using a filter...
+		If source And source.eventfilter <> Null Then
+			Local _key:Int, _mods:Int
+			bmx_gtk3maxgui_gdkeventkey(gdkEvent, Varptr _key, Varptr _mods)
+			Local key:Int = TGTKKeyMap.mapBack(_key)
+			Local mods:Int = TGTKKeyMap.mapModifierBack(_mods)
+			
+			Local event:TEvent=HotKeyEvent( key,mods, Null )
+			If event Then
+				event.emit()
+				Return True
+			EndIf
+
+			event = CreateEvent(EVENT_KEYDOWN, source, key, mods)
+			
+			If Not source.eventfilter(event, source.context) Then
+				Return True
+			End If
+
+			Local char:Int = gdk_keyval_to_unicode(_key)
+			' we sometimes get 0 from this function when key is valid... so set it to key just so that it has a value.
+			If char = 0 And key <> 0 Then
+				char = key
+			End If
+
+			event = CreateEvent(EVENT_KEYCHAR, source, char, mods)
+			If Not source.eventfilter(event, source.context) Then
+				Return True
+			End If
+		EndIf
+
+		Return False
+	End Function
+End Type
+
+Rem
+bbdoc: A Text field.
+End Rem
+Type TGTKTextField Extends TGTKEditable
+
+	Field isPassword:Int
+	
+	Function CreateTextField:TGTKTextField(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Local this:TGTKTextField = New TGTKTextField
+
+		this.initTextField(x, y, w, h, label, group, style)
+
+		Return this
+	End Function
+
+	Method initTextField(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+
+		handle = gtk_entry_new()
+
+		Init(GTK_TEXTFIELD, x, y, w, h, style)
+
+		If style Then
+			isPassword = True
+
+			gtk_entry_set_visibility(handle, False)
+		End If
+
+		' causes the default gadget to be activated when Enter is pressed inside this Text Field.
+		g_object_set_int(handle, "activates-default", True)
+
+		setShow(True)
+
+		gtk_layout_put(TGTKContainer(group).container, handle, x, y)
+		gtk_widget_set_size_request(handle, w, Max(h,0))
+
+
+		' add callbacks
+		addConnection("changed", g_signal_cb2(handle, "changed", OnTextChanged, Self, Destroy, 0))
+		addConnection("key-press-event", g_signal_cb3_ret(handle, "key-press-event", OnKeyDown, Self, Destroy, 0))
+		addConnection("focus-out-event", g_signal_cb3_ret(handle, "focus-out-event", OnFocusLost, Self, Destroy, 0))
+		' catch right-mouse buttons
+		addConnection("button-press-event", g_signal_cb3_ret(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
+
+	End Method
+
+	Rem
+	bbdoc: Returns the textfield text.
+	End Rem
+	Method GetText:String()
+		Return String.FromUTF8String(gtk_entry_get_text(handle))
+	End Method
+
+	Rem
+	bbdoc: Sets the textfield text.
+	End Rem
+	Method SetText:Int(txt:String)
+		If txt = Null
+			txt = ""
+		End If
+		
+		' when set to blank, it raises 2 change events?
+		If txt = "" And GetText() <> "" Then
+			ignoreTextChange:+1
+		End If
+		
+		If txt <> GetText() Then
+			ignoreTextChange:+1
+		End If
+		
+		Local txtPtr:Byte Ptr = txt.ToUTF8String()
+		gtk_entry_set_text(handle, txtPtr)
+		MemFree(txtPtr)
+	End Method
+
+	Method free:Int()
+		Super.Free()
+
+		If handle 
+			gtk_widget_destroy(handle)
+		EndIf
+		handle = Null
+
+	End Method
+
+	Method Activate:Int(cmd:Int)
+		Super.Activate(cmd)
+
+		Select cmd
+			Case ACTIVATE_CUT
+				gtk_editable_cut_clipboard(handle)
+			Case ACTIVATE_COPY
+				gtk_editable_copy_clipboard(handle)
+			Case ACTIVATE_PASTE
+				gtk_editable_paste_clipboard(handle)
+		End Select
+	End Method
+	
+	Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		Local x:Double, y:Double, button:Int
+		bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
+
+		If button = 3 Then ' right mouse button
+
+			PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),,,x,y)
+
+			Return True
+		End If
+
+		Return False
+	End Function
+
+	Method toString:String()
+		Return "TGTKTextField"
+	End Method
+
+End Type
+
+Rem
+bbdoc: A base for list gadgets.
+End Rem
+Type TGTKList Extends TGTKGadget
+
+	Field icons:TGTKIconStrip
+
+	Field _store:Byte Ptr
+	Field _selection:Byte Ptr
+	' sometimes we need to ignore events because we made them ourselves - rather than the user selecting
+	' something.
+	Field ignoreListChangeEvent:Int
+
+	Method SetIconStrip:Int(iconstrip:TIconStrip)
+		icons = TGTKIconStrip(iconstrip)
+	End Method
+
+	Method populateListRow(index:Int, text:String, tip:String, icon:Int, iter:Byte Ptr)
+
+		' need to put the string in a GValue for placing into the list
+		Local _value:Byte Ptr = bmx_gtk3_gvalue_new(G_TYPE_STRING)
+		'g_value_init(_value, G_TYPE_STRING)
+		Local textPtr:Byte Ptr = text.ToUTF8String()
+	  	g_value_set_string(_value, textPtr)
+		MemFree(textPtr)
+	
+		' set the row value
+		If TGTKListbox(Self) Or TGTKComboBox(Self) Then
+			gtk_list_store_set_value(_store, iter, 1, _value)
+		Else
+			gtk_tree_store_set_value(_store, iter, 1, _value)
+		End If
+	
+		' tidy up !
+		g_value_unset(_value)
+
+
+		Local image:Byte Ptr
+
+		If icons And icon>=0 Then
+			image = icons.images[icon]
+		End If
+
+		If image Then
+			' Insert the appropriate icon
+
+			g_value_init(_value, gdk_pixbuf_get_type())
+		  	g_value_set_object(_value, image)
+		
+			' set the row value
+			If TGTKListbox(Self) Or TGTKComboBox(Self) Then
+				gtk_list_store_set_value(_store, iter, 0, _value)
+			Else
+				gtk_tree_store_set_value(_store, iter, 0, _value)
+			End If
+		
+			' tidy up !
+			g_value_unset(_value)
+		Else
+			' clear out an icon if one is present in this entry
+
+			g_value_init(_value, gdk_pixbuf_get_type())
+		  	g_value_set_object(_value, Null)
+		
+			' set the row value
+			If TGTKListbox(Self) Or TGTKComboBox(Self) Then
+				gtk_list_store_set_value(_store, iter, 0, _value)
+			Else
+				gtk_tree_store_set_value(_store, iter, 0, _value)
+			End If
+		
+			' tidy up !
+			g_value_unset(_value)
+		End If
+
+		bmx_gtk3_gvalue_free(_value)
+		
+	End Method
+
+	Method initColumns()
+		' add a column to the list :
+		Local col:Byte Ptr = gtk_tree_view_column_new()
+
+		' pack column into list 
+		gtk_tree_view_append_column(handle, col)
+
+		Local pixRenderer:Byte Ptr = gtk_cell_renderer_pixbuf_new()
+		Local textRenderer:Byte Ptr = gtk_cell_renderer_text_new()
+
+		' pack cell renderers into column
+		gtk_tree_view_column_pack_start(col, pixRenderer, False)
+		gtk_tree_view_column_pack_end(col, textRenderer, True)
+
+		gtk_tree_view_column_add_attribute(col, pixRenderer, "pixbuf", 0)
+		gtk_tree_view_column_add_attribute(col, textRenderer, "text", 1)
+	End Method
+
+	Function OnSelectionChanged(_sel:Byte Ptr, obj:Object) Abstract
+
+End Type
+
+Rem
+bbdoc: A combo box
+End Rem
+Type TGTKComboBox Extends TGTKList
+
+	Field isEditable:Int
+
+	Function CreateComboBox:TGTKComboBox(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Local this:TGTKComboBox = New TGTKComboBox
+
+		this.initComboBox(x, y, w, h, label, group, style)
+
+		Return this
+	End Function
+
+	Method initComboBox(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+
+		If style = COMBOBOX_EDITABLE Then
+			isEditable = True
+			handle = gtk_combo_box_new_with_entry()
+		Else
+			handle = gtk_combo_box_new()
+		End If
+
+		Init(GTK_COMBOBOX, x, y, w, h, style)
+		
+		' Create a list store of pixbuf and string (the two displayable columns)
+		_store = gtk_list_store_new(2, gdk_pixbuf_get_type(), G_TYPE_STRING)
+
+		gtk_combo_box_set_model(handle, _store)
+		
+		' for editable, we need to tell it which column contains the text part
+		If isEditable Then
+			gtk_combo_box_set_entry_text_column(handle, 1)
+		End If
+		initColumns()
+
+		setShow(True)
+
+		gtk_layout_put(TGTKContainer(group).container, handle, x, y)
+		gtk_widget_set_size_request(handle, w, Max(h,0))
+		
+		addConnection("changed", g_signal_cb2(handle, "changed", OnSelectionChanged, Self, Destroy, 0))
+		' catch right-mouse buttons
+		addConnection("button-press-event", g_signal_cb3_ret(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
+
+	End Method
+	
+	Method initColumns()
+		gtk_cell_layout_clear(handle)
+
+		Local pixRenderer:Byte Ptr = gtk_cell_renderer_pixbuf_new()
+		Local textRenderer:Byte Ptr = gtk_cell_renderer_text_new()
+
+		' pack cell renderers into layout
+		gtk_cell_layout_pack_start(handle, pixRenderer, False)
+		gtk_cell_layout_pack_end(handle, textRenderer, True)
+
+		gtk_cell_layout_add_attribute(handle, pixRenderer, "pixbuf", 0)
+		gtk_cell_layout_add_attribute(handle, textRenderer, "text", 1)
+
+	End Method
+
+	Rem
+	bbdoc: Callback for selection change.
+	End Rem
+	Function OnSelectionChanged(widget:Byte Ptr, obj:Object)
+		Local row:Int = TGTKComboBox(obj).SelectedItem()
+		PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), row,,,,TGadget(obj).ItemExtra(row))
+	End Function
+
+	Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		Local x:Double, y:Double, button:Int
+		bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
+
+		If button = 3 Then ' right mouse button
+
+			Local treePath:Byte Ptr
+			Local row:Int = TGTKComboBox(obj).SelectedItem()
+			
+			If row >= 0 Then
+				PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),row,,x,y,TGTKList(obj).items[row].extra)
+			Else
+				PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),row,,x,y)
+			End If
+			Return True
+		End If
+
+		Return False
+	End Function
+	
+	Method InsertListItem:Int(index:Int, text:String, tip:String, icon:Int, tag:Object)
+		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
+
+		gtk_list_store_insert(_store, iter, index)
+
+		populateListRow(index, text, tip, icon, iter)
+		bmx_gtk3_gtktreeiter_free(iter)
+	End Method
+
+	Method SetListItem:Int(index:Int, text:String, tip:String, icon:Int, tag:Object)
+		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
+		Local found:Int = gtk_tree_model_iter_nth_child(_store, iter, Null, index)
+
+		If found Then
+			populateListRow(index, text, tip, icon, iter)
+		End If
+		bmx_gtk3_gtktreeiter_free(iter)
+	End Method
+
+	Method SelectedItem:Int()
+		Return gtk_combo_box_get_active(handle)
+	End Method
+
+	Method SetListItemState:Int(index:Int ,state:Int)
+		If state & STATE_SELECTED Then
+			gtk_combo_box_set_active(handle, index)
+		End If
+	End Method
+
+	Method ClearListItems:Int()
+		gtk_list_store_clear(_store)
+	End Method
+
+	Method RemoveListItem:Int(index:Int)
+		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
+		Local found:Int = gtk_tree_model_iter_nth_child(_store, iter, Null, index)
+		
+		If found Then
+			gtk_list_store_remove(_store, iter)
+		End If
+		bmx_gtk3_gtktreeiter_free(iter)
+	End Method
+
+	Method ItemText:String(index:Int)
+		If index < 0 Or index >= items.length Then
+			Return GetText()
+		End If
+		Return items[index].text
+	End Method
+
+	Method GetText:String()
+			Local st:String
+			Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
+			Local found:Int = gtk_combo_box_get_active_iter(handle, iter)
+			
+			If found Then
+				Local _value:Byte Ptr = bmx_gtk3_gvalue_new(G_TYPE_STRING)
+				
+				gtk_tree_model_get_value(_store, iter, 0, _value)
+				
+				st = String.FromUTF8String(g_value_get_string(_value))
+				
+				' tidy up !
+				g_value_unset(_value)
+
+				bmx_gtk3_gvalue_free(_value)
+			End If
+			
+			Return st
+	End Method
+
+	Method Free:Int()
+		Super.Free()
+
+		If handle 
+			gtk_widget_destroy(handle)
+		EndIf
+		handle = Null
+	End Method
+
+	Method toString:String()
+		Return "TGTKComboBox"
+	End Method
+
+End Type
+
+Rem
+bbdoc: A scrollable list.
+End Rem
+Type TGTKListWithScrollWindow Extends TGTKList
+
+	Field scrollWindow:Byte Ptr
+
+	Method Init(GadgetClass:Int, x:Int, y:Int, w:Int, h:Int, style:Int)
+		Super.init(iclass, x, y, w, h, style)
+	
+		handle = gtk_tree_view_new()
+		gtk_tree_view_set_headers_visible(handle, False)
+
+		' a reference to the selection object
+		_selection = gtk_tree_view_get_selection(handle)
+
+		' currently we only support SINGLE row selection
+		gtk_tree_selection_set_mode(_selection, GTK_SELECTION_SINGLE)
+
+
+		scrollWindow = gtk_scrolled_window_new(Null, Null)
+		' set container resize mode
+		gtk_container_set_resize_mode(scrollWindow, GTK_RESIZE_QUEUE)
+		' set scrollbar policy
+		gtk_scrolled_window_set_policy(scrollWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC)
+		' show
+		gtk_widget_show(scrollWindow)
+
+		' add the html view to the scroll view
+		gtk_container_add(scrollWindow, handle)
+
+
+		' add callback
+		addConnection("changed", g_signal_cb2(_selection, "changed", OnSelectionChanged, Self, Destroy, 0))
+		
+		' catch right-mouse buttons
+		addConnection("button-press-event", g_signal_cb3_ret(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
+	End Method
+
+	Method SetShow:Int(truefalse:Int)
+		visible = truefalse
+		mySetVisible = visible
+		
+		If truefalse Then
+			gtk_widget_show(scrollWindow)
+			gtk_widget_show(handle)
+		Else
+			gtk_widget_hide(scrollWindow)
+			gtk_widget_hide(handle)
+		EndIf
+
+		UpdateChildVisibility()
+	End Method
+
+	Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+	End Function
+
+End Type
+
+Rem
+bbdoc: List box
+End Rem
+Type TGTKListbox Extends TGTKListWithScrollWindow
+
+
+	Field currentSelection:Int = -1
+
+	Function CreateListBox:TGTKListbox(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Local this:TGTKListbox = New TGTKListbox
+
+		this.initListBox(x, y, w, h, label, group, style)
+
+		Return this
+	End Function
+
+	Method initListBox(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Init(GTK_LISTBOX, x, y, w, h, style)
+
+		' had intended using GTK_TYPE_PIXBUF here but it's a different value every time!?!
+		_store = gtk_list_store_new(2, gdk_pixbuf_get_type(), G_TYPE_STRING)
+
+		initColumns()
+
+		gtk_tree_view_set_model(handle, _store)
+
+		' remove *our* reference to the store... when the list is destroyed this will be too
+		g_object_unref(_store)
+
+		addConnection("row-activated", g_signal_cb4(handle, "row-activated", OnRowActivated, Self, Destroy, 0))
+
+		SetShow(True)
+
+		gtk_layout_put(TGTKContainer(group).container, scrollwindow, x, y)
+		gtk_widget_set_size_request(handle, w, Max(h,0))
+
+	End Method
+
+	Method InsertListItem:Int(index:Int, text:String, tip:String, icon:Int, extra:Object)
+		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
+
+		gtk_list_store_insert(_store, iter, index)
+
+		populateListRow(index, text, tip, icon, iter)
+		bmx_gtk3_gtktreeiter_free(iter)
+	End Method
+
+	Method SetListItem:Int(index:Int, text:String, tip:String, icon:Int, tag:Object)
+		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
+		Local found:Int = gtk_tree_model_iter_nth_child(_store, iter, Null, index)
+		If found Then
+			populateListRow(index, text, tip, icon, iter)
+		End If
+		bmx_gtk3_gtktreeiter_free(iter)
+	End Method
+
+	Rem
+	bbdoc: Removes an item from the list at the given index
+	End Rem
+	Method RemoveListItem:Int(index:Int)
+		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
+		Local found:Int = gtk_tree_model_iter_nth_child(_store, iter, Null, index)
+		
+		If found Then
+			If gtk_tree_selection_iter_is_selected(_selection, iter) Then
+				ignoreListChangeEvent = True
+			End If
+			gtk_list_store_remove(_store, iter)
+		End If
+		bmx_gtk3_gtktreeiter_free(iter)
+	End Method
+
+	Method SetListItemState:Int(index:Int, state:Int)
+		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
+
+		Local found:Int = gtk_tree_model_iter_nth_child(_store, iter, Null, index)
+
+		If found Then
+			If state & STATE_SELECTED Then
+				ignoreListChangeEvent = True
+				gtk_tree_selection_select_iter(_selection, iter)
+			Else
+				If gtk_tree_selection_iter_is_selected(_selection, iter) Then
+					ignoreListChangeEvent = True
+				End If
+					
+				gtk_tree_selection_unselect_iter(_selection, iter)
+			End If
+		End If
+		bmx_gtk3_gtktreeiter_free(iter)
+	End Method
+
+	Method ListItemState:Int(index:Int)
+		Local state:Int = 0
+		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
+
+		Local found:Int = gtk_tree_model_iter_nth_child(_store, iter, Null, index)
+
+		If found Then
+			If gtk_tree_selection_iter_is_selected(_selection, iter) Then
+				state:| STATE_SELECTED
+			End If
+		End If
+
+		bmx_gtk3_gtktreeiter_free(iter)
+		Return state
+	End Method
+
+	Function OnSelectionChanged(_sel:Byte Ptr, obj:Object)
+		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
+
+		Local row:Int = -1
+		Local selected:Int = gtk_tree_selection_get_selected(_sel, Null, iter)
+		If selected Then
+			Local path:Byte Ptr = gtk_tree_model_get_string_from_iter(TGTKList(obj)._store, iter)
+			row = String.fromCString(path).toInt()
+			g_free(path)
+		End If
+
+		If TGTKListbox(obj).currentSelection <> row Then
+		
+			TGTKListbox(obj).currentSelection = row
+			
+			If Not TGTKList(obj).ignoreListChangeEvent Then
+				PostGuiEvent(EVENT_GADGETSELECT, TGadget(obj), row,,,,TGadget(obj).ItemExtra(row))
+			End If
+		End If
+		TGTKList(obj).ignoreListChangeEvent = False
+		
+		bmx_gtk3_gtktreeiter_free(iter)
+	End Function
+
+	Rem
+	bbdoc: Callback for listbox activation (double-click).
+	End Rem
+	Function OnRowActivated(widget:Byte Ptr, treePath:Byte Ptr, treeviewColumn:Byte Ptr, obj:Object)
+		Local p:Byte Ptr = gtk_tree_path_to_string(treePath)
+		Local row:Int
+		
+		If p <> Null Then
+			row = String.fromCString(p).toInt()
+		End If
+
+		' clean up mem
+		g_free(p)
+
+		If row >= 0 Then
+			PostGuiEvent(EVENT_GADGETACTION, TGadget(obj),row ,,,,TGTKList(obj).items[row].extra)
+		Else
+			PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), row)
+		End If
+	End Function
+
+	Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		Local x:Double, y:Double, button:Int
+		bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
+
+		If button = 3 Then ' right mouse button
+
+			Local treePath:Byte Ptr
+			Local row:Int = -1
+			
+		     ' Get tree path For row that was clicked
+			If gtk_tree_view_get_path_at_pos(widget, Int(x), Int(y), Varptr treePath, Null, Null, Null) Then
+				Local p:Byte Ptr = gtk_tree_path_to_string(treePath)
+
+				
+				If p <> Null Then
+					row = String.fromCString(p).toInt()
+				End If
+
+				' clean up mem
+				g_free(p)
+				gtk_tree_path_free(treePath)
+			End If
+		
+			If row >= 0 Then
+				PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),row,,x,y,TGTKList(obj).items[row].extra)
+			Else
+				PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),row,,x,y)
+			End If
+			Return True
+		End If
+
+		Return False
+	End Function
+	
+	Method ClearListItems:Int()
+		If gtk_tree_selection_get_selected(_selection, Null, Null) Then
+			ignoreListChangeEvent = True
+		End If
+		gtk_list_store_clear(_store)
+	End Method
+
+	Method rethink:Int()
+		If handle Then
+			gtk_layout_move(TGTKContainer(parent).container, scrollwindow, Max(xpos, 0), Max(ypos, 0))
+			gtk_widget_set_size_request(scrollwindow, Max(width,0), Max(height,0))
+		End If
+	End Method
+
+	Method Free:Int()
+		Super.free()
+
+		' destroying the widget should destroy the handle (list) too.
+		If scrollWindow Then
+			gtk_widget_destroy(scrollWindow)
+		End If
+		
+		scrollWindow = Null
+		handle = Null
+
+	End Method
+
+	Method toString:String()
+		Return "TGTKListbox"
+	End Method
+
+End Type
+
+Rem
+bbdoc: A node in the tree view.
+End Rem
+Type TGTKTreeViewNode Extends TGTKListWithScrollWindow
+
+	' is this node the root node?
+	Field isRoot:Int
+	' internal representation of node position in the tree
+	Field _path:String
+	' direct access to the node in the tree
+	Field myIter:Byte Ptr
+	' icon to display for this node
+	Field _icon:Int
+	' flag to prevent non-user events from firing
+	Field ignoreExpand:Int
+	Field ignoreCollapse:Int
+	' text of this node
+	Field _text:String
+
+	Function _createNode:TGTKTreeViewNode(parent:TGTKTreeViewNode, index:Int)
+		Local this:TGTKTreeViewNode = New TGTKTreeViewNode
+
+		this.kids = New TEList
+
+		this.handle = parent.handle
+		this._store = parent._store
+		this._selection = parent._selection
+		this.parent = parent
+		this.icons = parent.icons
+
+		this.myIter = bmx_gtk3_gtktreeiter_new()
+
+		this.refreshPath(index)
+		
+		Return this
+	End Function
+
+	Method refreshPath(index:Int)
+		Assert myIter, "Null Iterator!"
+	
+		If parent Then
+			_path = TGTKTreeViewNode(parent)._path
+			If TGTKTreeViewNode(parent)._path.length > 0 Then
+				_path:+ ":"
+			End If
+		Else
+			_path = ""
+		End If
+		_path:+ index
+
+		gtk_tree_model_get_iter_from_string(_store, myIter, _path)
+	End Method
+
+	Method refreshChildPaths()
+		Local i:Int = 0
+		For Local child:TGTKTreeViewNode = EachIn kids
+			child.refreshPath(i)
+			child.refreshChildPaths()
+			i:+ 1
+		Next
+	End Method
+
+	Function OnSelectionChanged(_sel:Byte Ptr, obj:Object)
+		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
+		Local node:TGTKTreeViewNode = Null
+		Local selected:Int = gtk_tree_selection_get_selected(_sel, Null, iter)
+		If selected Then
+			Local p:Byte Ptr = gtk_tree_model_get_string_from_iter(TGTKList(obj)._store, iter)
+			node = TGTKTreeViewNode(obj).findNodeFromPath(String.FromCString(p))
+			g_free(p)
+		End If
+
+		If Not TGTKList(obj).ignoreListChangeEvent Then
+			PostGuiEvent(EVENT_GADGETSELECT, TGadget(obj),,,,,node)
+		End If
+		TGTKList(obj).ignoreListChangeEvent = False
+		bmx_gtk3_gtktreeiter_free(iter)
+	End Function
+
+	Rem
+	bbdoc: Returns the root node for this tree
+	End Rem
+	Method RootNode:TGadget()
+		If Not isRoot Then
+			Return parent.RootNode()
+		End If
+		Return Self
+	End Method
+
+	Rem
+	bbdoc: Inserts a new node as a child at the specified index.
+	End Rem
+	Method InsertNode:TGadget(index:Int, text:String, icon:Int)
+		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
+		Local childNode:TGTKTreeViewNode
+
+		' create a new row in the tree
+		If isRoot Then
+			If index < 0 Then
+				gtk_tree_store_append(_store, iter, Null)
+			Else
+				gtk_tree_store_insert(_store, iter, Null, index)
+			End If
+
+		Else
+			If index < 0 Then
+				gtk_tree_store_append(_store, iter, myIter)
+			Else
+				gtk_tree_store_insert(_store, iter, myIter, index)
+			End If
+		End If
+
+		' add the text / icon to the tree
+		populateListRow(index, text, Null, icon, iter)
+
+		' add the child to the parent kids
+		If index < 0 Or index = CountKids() Then
+			childNode = TGTKTreeViewNode._createNode(Self, CountKids())
+			childNode._text = text
+			kids.addLast(childNode)
+		Else
+			childNode = TGTKTreeViewNode._createNode(Self, index)
+			childNode._text = text
+			TEList(kids).insertElementAt(childNode, index)
+			refreshChildPaths()
+		End If
+
+		childNode._icon = icon
+		
+		If (LocalizationMode() & LOCALIZATION_OVERRIDE) Then
+			LocalizeGadget(childNode, text)
+		Else
+			childNode.SetText(text)
+		EndIf
+
+		bmx_gtk3_gtktreeiter_free(iter)
+		Return childNode
+	End Method
+
+	Rem
+	bbdoc: Changes the tree node text and icon
+	End Rem
+	Method ModifyNode:Int(text:String, icon:Int)
+		' not allowed to modify the root node... quietly ignore the request.
+		If isRoot Then
+			Return 0
+		End If
+
+		_text = text
+		populateListRow(-1, text, Null, icon, myIter)
+	End Method
+
+	Rem
+	bbdoc: Returns the currently selected tree node or null if none selected
+	End Rem
+	Method SelectedNode:TGadget()
+
+		Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
+		If gtk_tree_selection_get_selected(_selection, Null, iter) Then
+			Local path:Byte Ptr = gtk_tree_model_get_path(_store, iter)
+
+			Local p:Byte Ptr = gtk_tree_path_to_string(path)
+			Local node:TGTKTreeViewNode = findNodeFromPath(String.FromCString(p))
+
+			g_free(p)
+			gtk_tree_path_free(path)
+			
+			bmx_gtk3_gtktreeiter_free(iter)
+			Return node
+		End If
+
+		bmx_gtk3_gtktreeiter_free(iter)
+		Return Null
+	End Method
+
+	Rem
+	bbdoc: Returns the number of child nodes
+	End Rem
+	Method CountKids:Int()
+		Return kids.count()
+	End Method
+
+	Method Free:Int()
+
+		Super.free()
+
+		If isRoot Then
+			If scrollWindow Then
+				gtk_widget_destroy(scrollWindow)
+			End If
+
+			scrollWindow = Null
+			handle = Null
+		Else
+			' this should always be true... if not, we really want to throw an assertion.
+			' Assert myIter, "Trying to Free() a node twice?"
+			If myIter Then
+				gtk_tree_store_remove(_store, myIter)
+				bmx_gtk3_gtktreeiter_free(myIter)
+				myIter = Null
+				TGTKTreeViewNode(parent).refreshChildPaths()
+			End If
+		End If
+		
+	End Method
+
+	' search always begins from the tree root, so we only need to look through the 
+	' children.. ie. downwards
+	' TODO : make this more efficient...  we should be able to use the path to skip
+	' searching of child nodes of nodes not in our path
+	Method findNodeFromPath:TGTKTreeViewNode(lookup:String)
+		If lookup = _path Then
+			Return Self
+		End If
+
+		Local i:Int = 0
+		For Local child:TGTKTreeViewNode = EachIn kids
+			Local node:TGTKTreeViewNode = child.findNodeFromPath(lookup)
+			If node Then
+				Return node
+			End If
+		Next
+
+		Return Null
+	End Method
+
+	Method Activate:Int(command:Int)
+		Super.Activate(command)
+
+		Select command
+			Case ACTIVATE_EXPAND
+				If _path <> Null And _path.length > 0 Then
+					ignoreExpand = True
+					' get the tree view
+					Local _root:TGTKTreeViewNode = TGTKTreeViewNode(RootNode())
+					' get this node path
+					Local path:Byte Ptr = gtk_tree_path_new_from_string(_path)
+	
+					' expand the node
+					gtk_tree_view_expand_row(_root.handle, path, False)
+	
+					' free stuff
+					gtk_tree_path_free(path)
+				End If
+			Case ACTIVATE_COLLAPSE
+				If _path <> Null And _path.length > 0 Then
+					ignoreCollapse = True
+
+					' get the tree view
+					Local _root:TGTKTreeViewNode = TGTKTreeViewNode(RootNode())
+					' get this node path
+					Local path:Byte Ptr = gtk_tree_path_new_from_string(_path)
+	
+					' expand the node
+					gtk_tree_view_collapse_row(_root.handle, path)
+	
+					' free stuff
+					gtk_tree_path_free(path)
+				End If
+			Case ACTIVATE_SELECT
+				If _path <> Null And _path.length > 0 Then
+					' the tree view should ignore this selection...
+					TGTKTreeViewNode(RootNode()).ignoreListChangeEvent = True
+				
+					' get this node path
+					Local path:Byte Ptr = gtk_tree_path_new_from_string(_path)
+					
+					' set the new selection
+					gtk_tree_selection_select_path(_selection, path)
+					
+					' free stuff
+					gtk_tree_path_free(path)					
+				End If
+		End Select
+	End Method
+	
+	Rem
+	bbdoc: Returns the text for this node.
+	End Rem
+	Method GetText:String()
+		Return _text
+	End Method
+	
+	Rem
+	bbdoc: Sets the text for this node.
+	End Rem
+	Method SetText:Int(text:String)
+		ModifyNode(text, _icon)
+	End Method
+
+	Method toString:String()
+		Return "TGTKTreeViewNode : " + _text + " : " + Super.ToString()
+	End Method
+	
+End Type
+
+Rem
+bbdoc: A tree view.
+End Rem
+Type TGTKTreeView Extends TGTKTreeViewNode
+
+	Function CreateTreeView:TGTKTreeView(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Local this:TGTKTreeView = New TGTKTreeView
+
+		this.initTreeView(x, y, w, h, label, group, style)
+
+		Return this
+	End Function
+
+	Method initTreeView(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Init(GTK_TREEVIEW, x, y, w, h, style)
+
+		ignoreListChangeEvent = True
+		
+		kids = New TEList
+
+		' create the tree store
+		_store = gtk_tree_store_new(2, gdk_pixbuf_get_type(), G_TYPE_STRING)
+
+		' set up the column contents
+		initColumns()
+
+		' attach store to the view
+		gtk_tree_view_set_model(handle, _store)
+
+		' remove *our* reference to the store... when the tree is destroyed this will be too
+		g_object_unref(_store)
+
+		SetShow(True)
+
+		gtk_layout_put(TGTKContainer(group).container, scrollwindow, x, y)
+		gtk_widget_set_size_request(handle, w, Max(h,0))
+
+
+		addConnection("row-activated", g_signal_cb4(handle, "row-activated", OnRowActivated, Self, Destroy, 0))
+		addConnection("row-expanded", g_signal_cb4(handle, "row-expanded", OnRowExpanded, Self, Destroy, 0))
+		addConnection("row-collapsed", g_signal_cb4(handle, "row-collapsed", OnRowCollapsed, Self, Destroy, 0))
+
+		isRoot = True
+	End Method
+
+	Rem
+	bbdoc: Callback For tree-view node activation (Double-click).
+	End Rem
+	Function OnRowActivated(widget:Byte Ptr, treePath:Byte Ptr, treeviewColumn:Byte Ptr, obj:Object)
+		Local p:Byte Ptr = gtk_tree_path_to_string(treePath)
+		Local node:TGTKTreeViewNode = TGTKTreeViewNode(obj).findNodeFromPath(String.FromCString(p))
+
+		' clean up mem
+		g_free(p)
+
+		PostGuiEvent(EVENT_GADGETACTION, TGadget(obj),,,,,node)
+	End Function
+
+	Rem
+	bbdoc: Callback for tree-view node expand.
+	End Rem
+	Function OnRowExpanded(widget:Byte Ptr, treeIter:Byte Ptr, treePath:Byte Ptr, obj:Object)
+		Local p:Byte Ptr = gtk_tree_path_to_string(treePath)
+		Local node:TGTKTreeViewNode = TGTKTreeViewNode(obj).findNodeFromPath(String.FromCString(p))
+
+		' clean up mem
+		g_free(p)
+
+		If Not node.ignoreExpand Then
+			PostGuiEvent(EVENT_GADGETOPEN, TGadget(obj),,,,,node)
+		End If
+
+		node.ignoreExpand = False
+	End Function
+
+	Rem
+	bbdoc: Callback for tree-view node collapse.
+	End Rem
+	Function OnRowCollapsed(widget:Byte Ptr, treeIter:Byte Ptr, treePath:Byte Ptr, obj:Object)
+		Local p:Byte Ptr = gtk_tree_path_to_string(treePath)
+		Local node:TGTKTreeViewNode = TGTKTreeViewNode(obj).findNodeFromPath(String.FromCString(p))
+
+		' clean up mem
+		g_free(p)
+
+		If Not node.ignoreCollapse Then
+			PostGuiEvent(EVENT_GADGETCLOSE, TGadget(obj),,,,,node)
+		End If
+
+		node.ignoreCollapse = False
+	End Function
+
+	Rem
+	bbdoc: Callback for mouse right-click
+	End Rem
+	Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		Local x:Double, y:Double, button:Int
+		bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
+
+		If button = 3 Then ' right mouse button
+			
+			Local node:TGTKTreeViewNode
+			Local treePath:Byte Ptr
+			
+		     ' Get tree path For row that was clicked
+			If gtk_tree_view_get_path_at_pos(widget, Int(x), Int(y), Varptr treePath, Null, Null, Null) Then
+				Local p:Byte Ptr = gtk_tree_path_to_string(treePath)
+				node = TGTKTreeViewNode(obj).findNodeFromPath(String.FromCString(p))
+				
+				' clean up mem
+				g_free(p)
+				gtk_tree_path_free(treePath)
+			End If
+		
+			PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),,,x,y,node)
+
+			Return True
+		End If
+
+		Return False
+	End Function
+	
+	' overriden - does nothing!!
+	Method LayoutKids:Int()
+	End Method
+
+	Method rethink:Int()
+		If handle Then
+			gtk_layout_move(TGTKContainer(parent).container, scrollwindow, Max(xpos, 0), Max(ypos, 0))
+			gtk_widget_set_size_request(scrollwindow, Max(width,0), Max(height,0))
+		End If
+	End Method
+
+	Method toString:String()
+		Return "TGTKTreeView"
+	End Method
+
+End Type
+
+Rem
+bbdoc: A base-type for handling slider / range gadgets - ScrollBar and TrackBar
+End Rem
+Type TGTKRange Extends TGTKGadget
+
+	Field currentValue:Int
+	Field rangeMin:Int
+	Field rangeMax:Int
+
+	Rem
+	bbdoc: Sets the slider range.
+	End Rem
+	Method SetRange:Int(visible:Int, total:Int)
+		rangeMin = Min(visible, total)
+		rangeMax = Max(visible, total)
+		gtk_range_set_range(handle, rangeMin, rangeMax)
+	End Method
+
+	Rem
+	bbdoc: Sets the value on the slider.
+	End Rem
+	Method SetProp:Int(value:Int)
+		currentValue = value
+		gtk_range_set_value(handle, value)
+	End Method
+
+	Rem
+	bbdoc: Returns the current slider value.
+	End Rem
+	Method GetProp:Int()
+		Return gtk_range_get_value(handle)
+	End Method
+
+	Rem
+	bbdoc: Callback for user changing of a slider.
+	about: Tries to keep the value within the desired range.
+	End Rem
+	Function OnChangeValue:Int(widget:Byte Ptr, scrolltype:Int, value:Double, obj:Object)
+		Local v:Int = Max(Min(value, TGTKRange(obj).rangeMax), TGTKRange(obj).rangeMin)
+		If v <> TGTKRange(obj).currentValue Then
+			TGTKRange(obj).currentValue = v
+			PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), v)
+		End If
+
+		Return False
+	End Function
+	
+	Method Free:Int()
+		Super.Free()
+
+		If handle 
+			gtk_widget_destroy(handle)
+		EndIf
+		handle = Null
+	End Method
+
+	Method toString:String()
+		Return "TGTKRange"
+	End Method
+
+End Type
+
+Rem
+bbdoc: A scrollbar
+End Rem
+Type TGTKScrollBar Extends TGTKRange
+
+	Field thumbSize:Int
+	Field Range:Int
+	Field pageSize:Int
+
+	Function CreateScrollBar:TGTKScrollBar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Local this:TGTKScrollBar = New TGTKScrollBar
+
+		this.initScrollBar(x, y, w, h, label, group, style)
+
+		Return this
+	End Function
+
+	Method initScrollBar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+
+		If style & SLIDER_VERTICAL Then
+			handle = gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, Null)
+		Else
+			handle = gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, Null)
+		End If
+
+		Init(GTK_SCROLLBAR, x, y, w, h, style)
+
+		' set the default range
+		SetRange(1, 10)
+
+		setShow(True)
+
+		addConnection("change-value", g_signal_cb4a(handle, "change-value", OnChangeValue, Self, Destroy, 0))
+		
+		gtk_layout_put(TGTKContainer(group).container, handle, x, y)
+		gtk_widget_set_size_request(handle, w, Max(h,0))
+		gtk_range_set_round_digits(handle, 0)
+
+	End Method
+
+	Rem
+	bbdoc: Overrides the default...
+	End Rem
+	Method SetRange:Int(small:Int, big:Int)
+
+		Range = big - small
+		pageSize = small
+		
+		If small <> 0 Then
+			thumbSize = big/small
+			thumbSize = range / thumbSize
+		Else
+			thumbSize = 1
+		End If
+
+		If Range = 0 Then
+			Range = 1
+			thumbSize = 1
+		End If
+
+	    gtk_adjustment_set_page_size(gtk_range_get_adjustment(handle), thumbSize)
+	    gtk_range_set_increments(handle, 1, pageSize)
+	    gtk_range_set_range(handle, 0, Range)
+	    gtk_range_set_value(handle, GetProp())
+	End Method
+
+	Function OnChangeValue:Int(widget:Byte Ptr, scrolltype:Int, value:Double, obj:Object)
+		Local v:Int = Min(TGTKScrollBar(obj).range, Max(value, 0))
+
+		If v <> TGTKRange(obj).currentValue Then
+			TGTKRange(obj).currentValue = v
+			PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), v)
+		End If
+
+		Return False
+	End Function
+
+	Method toString:String()
+		Return "TGTKScrollBar"
+	End Method
+
+End Type
+
+Rem
+bbdoc: A trackbar
+End Rem
+Type TGTKTrackBar Extends TGTKRange
+
+	Function CreateTrackBar:TGTKTrackBar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Local this:TGTKTrackBar = New TGTKTrackBar
+
+		this.initTrackBar(x, y, w, h, label, group, style)
+
+		Return this
+	End Function
+
+	Method initTrackBar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+
+		If style & SLIDER_VERTICAL Then
+			handle = gtk_scale_new_with_range(GTK_ORIENTATION_VERTICAL, 1, 10, 1)
+		Else
+			handle = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, 1, 10, 1)
+		End If
+
+		Init(GTK_TRACKBAR, x, y, w, h, style)
+
+		' set the default range
+		SetRange(1,10)
+
+		gtk_scale_set_draw_value(handle, False)
+
+		setShow(True)
+		
+		addConnection("change-value", g_signal_cb4a(handle, "change-value", OnChangeValue, Self, Destroy, 0))
+
+		gtk_layout_put(TGTKContainer(group).container, handle, x, y)
+		gtk_widget_set_size_request(handle, w, Max(h,0))
+
+	End Method
+
+	Method toString:String()
+		Return "TGTKTrackBar"
+	End Method
+
+End Type
+
+Type TGTKStepper Extends TGTKGadget
+
+	Function CreateStepper:TGTKStepper(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Local this:TGTKStepper = New TGTKStepper
+
+		this.initStepper(x, y, w, h, label, group, style)
+
+		Return this
+	End Function
+
+	Method initStepper(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+	
+		handle = gtk_spin_button_new_with_range(1, 100, 1)
+	
+		Init(GTK_STEPPER, x, y, w, h, style)
+		
+		' init range..
+		SetRange(1,100)
+		gtk_spin_button_set_increments(handle, 1, 10)
+		
+		setShow(True)
+		
+		addConnection("change-value", g_signal_cb3a_ret(handle, "change-value", OnChangeValue, Self, Destroy, 0))
+
+		gtk_layout_put(TGTKContainer(group).container, handle, x, y)
+		gtk_widget_set_size_request(handle, w, Max(h,0))
+	End Method
+
+	Rem
+	bbdoc: Sets the value on the slider.
+	End Rem
+	Method SetProp:Int(value:Int)
+		'currentValue = value
+		gtk_spin_button_set_value(handle, value)
+	End Method
+
+	Rem
+	bbdoc: Returns the current slider value.
+	End Rem
+	Method GetProp:Int()
+		Return gtk_spin_button_get_value(handle)
+	End Method
+
+	Rem
+	bbdoc: Sets the slider range.
+	End Rem
+	Method SetRange:Int(visible:Int, total:Int)
+		Local rangeMin:Int = Min(visible, total)
+		Local rangeMax:Int = Max(visible, total)
+		gtk_spin_button_set_range(handle, rangeMin, rangeMax)
+	End Method
+
+	Function OnChangeValue:Int(widget:Byte Ptr, scrolltype:Int, obj:Object)
+		Local v:Int = gtk_spin_button_get_value(widget)
+
+		PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), v)
+
+		Return False
+	End Function
+
+	Method toString:String()
+		Return "TGTKStepper"
+	End Method
+
+End Type
+
+Rem
+bbdoc: A progress bar
+about: Interestingly, although we can find out the current value, MaxGUI doesn't support it...
+End Rem
+Type TGTKProgressBar Extends TGTKGadget
+
+	Field ebox:Byte Ptr
+
+	Function CreateProgressBar:TGTKProgressBar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Local this:TGTKProgressBar = New TGTKProgressBar
+
+		this.initProgressBar(x, y, w, h, label, group, style)
+
+		Return this
+	End Function
+
+	Method initProgressBar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+
+		handle = gtk_progress_bar_new()
+		
+		Init(GTK_PROGRESSBAR, x, y, w, h, style)
+
+		' required for tooltips functionality
+		gtk_widget_add_events(handle, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK)
+
+		setShow(True)
+
+		gtk_layout_put(TGTKContainer(group).container, handle, x, y)
+		gtk_widget_set_size_request(handle, w, Max(h,0))
+
+	End Method
+
+	Rem
+	bbdoc: Set the value of the progress bar.
+	End Rem
+	Method SetValue:Int(value:Float)
+		value = Min(Max(0, value), 1.0)
+		gtk_progress_bar_set_fraction(handle, value)
+	End Method
+	
+	Rem
+	bbdoc: Get the current value of the progress bar
+	End Rem
+	Method GetValue:Float()
+		Return gtk_progress_bar_get_fraction(handle)
+	End Method
+	
+	Method Free:Int()
+		Super.Free()
+
+		If handle
+			gtk_widget_destroy(handle)
+		EndIf
+		handle = Null
+	End Method
+
+	Method toString:String()
+		Return "TGTKProgressBar"
+	End Method
+
+End Type
+
+Rem
+bbdoc: A Toolbar
+End Rem
+Type TGTKToolbar Extends TGTKGadget
+
+	Field icons:TGTKIconStrip
+	Field toolitems:Byte Ptr[]
+
+	Function CreateToolBar:TGTKToolbar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Local this:TGTKToolbar = New TGTKToolbar
+
+		this.initToolbar(x, y, w, h, label, group, style)
+
+		Return this
+	End Function
+
+	Method initToolbar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+
+		handle = gtk_toolbar_new()
+
+		Init(GTK_TOOLBAR, x, y, w, h, style)
+
+		If TGTKWindow(group) Then
+			TGTKWindow(group).addToolbar(Self)
+		End If
+
+		' show icons only
+		gtk_toolbar_set_style(handle, GTK_TOOLBAR_ICONS)
+
+		gtk_widget_show(handle)
+	End Method
+
+	Method SetIconStrip:Int(iconstrip:TIconStrip)
+		icons = TGTKIconStrip(iconstrip)
+	End Method
+
+	Rem
+	bbdoc: Inserts an item at the specified index.
+	End Rem
+	Method InsertListItem:Int(index:Int, text:String, tip:String, icon:Int, extra:Object)
+		Local image:Byte Ptr		
+
+		If icons And icon>=0 Then
+			image = icons.images[icon]
+		End If
+
+		toolitems = toolitems[..toolitems.length+1]
+		For Local i:Int = toolitems.length - 2 To index Step -1
+			toolitems[i + 1] = toolitems[i]
+		Next
+
+		If image Then
+			Local imageWidget:Byte Ptr = gtk_image_new_from_pixbuf(image)
+			gtk_widget_show(imageWidget)
+	
+			Local textPtr:Byte Ptr = text.ToUTF8String()
+			If items[index].flags = GADGETITEM_TOGGLE Then
+				toolitems[index] = gtk_toggle_tool_button_new()
+				gtk_tool_button_set_label(toolitems[index], textPtr)
+				gtk_tool_button_set_icon_name(toolitems[index], icons.names[icon])
+
+				addConnection("toggled", g_signal_cb2(toolitems[index], "toggled", OnToolItemToggled, Self, Destroy, 0))
+			Else
+				toolitems[index] = gtk_tool_button_new(Null, textPtr)
+				gtk_tool_button_set_label(toolitems[index], textPtr)
+				gtk_tool_button_set_icon_name(toolitems[index], icons.names[icon])
+				
+
+				addConnection("clicked", g_signal_cb2(toolitems[index], "clicked", OnToolItemClicked, Self, Destroy, 0))
+			End If
+			MemFree(textPtr)
+
+			' Add a tooltip
+			SetToolTipIndex(index, tip)
+		Else
+			' no image? Then this is a separator!
+			toolitems[index] = gtk_separator_tool_item_new()
+		End If
+		gtk_widget_show(toolitems[index])
+
+		gtk_toolbar_insert(handle, toolitems[index], index)
+	End Method
+
+	Function OnToolItemToggled(widget:Byte Ptr, obj:Object)
+		Local index:Int = gtk_toolbar_get_item_index(TGTKToolbar(obj).handle, widget)
+		PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), index, gtk_toggle_tool_button_get_active(widget))
+	End Function
+
+	Function OnToolItemClicked(widget:Byte Ptr, obj:Object)
+		Local index:Int = gtk_toolbar_get_item_index(TGTKToolbar(obj).handle, widget)
+		PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), index)
+	End Function
+
+	Method SetListItem:Int(index:Int, text:String, tip:String, icon:Int, extra:Object)
+
+		If toolitems[index] Then
+			gtk_container_remove(handle, toolitems[index])
+
+			For Local i:Int = index Until toolitems.length - 1
+				toolitems[i] = toolitems[i + 1]
+			Next
+			toolitems = toolitems[..toolitems.length - 1]
+		End If
+
+		InsertListItem(index, text, tip, icon, extra)
+	End Method
+
+	Method SetToolTipIndex:Int(index:Int, tip:String)
+		' Add a tooltip
+		If tip And tip.length > 0 Then
+			Local tipPtr:Byte Ptr = tip.ToUTF8String()
+			gtk_tool_item_set_tooltip_text(toolitems[index], tipPtr)
+			MemFree(tipPtr)
+		Else
+			gtk_tool_item_set_tooltip_text(toolitems[index], Null)
+		End If		
+	End Method
+
+	Method SetListItemState:Int(item:Int, state:Int)
+		If state & STATE_DISABLED Then
+			gtk_widget_set_sensitive(toolitems[item], False)
+		Else
+			gtk_widget_set_sensitive(toolitems[item], True)
+		End If
+
+		If items[item].flags = GADGETITEM_TOGGLE Then
+			If state & STATE_SELECTED Then
+				gtk_toggle_tool_button_set_active(toolitems[item], True)
+			Else
+				gtk_toggle_tool_button_set_active(toolitems[item], False)
+			End If
+		End If
+		
+		gtk_widget_queue_draw(handle)
+	End Method
+
+	Method ListItemState:Int(index:Int)
+		Local state:Int = 0
+
+		If Not gtk_widget_is_sensitive(toolitems[index]) Then
+			state:| STATE_DISABLED
+		End If
+
+		If items[index].flags = GADGETITEM_TOGGLE Then
+			If gtk_toggle_tool_button_get_active(toolitems[index]) Then
+				state:| STATE_SELECTED
+			End If
+		End If
+
+		Return state
+	End Method
+
+	Method RemoveListItem:Int(index:Int)
+		If toolitems[index] Then
+			gtk_container_remove(handle, toolitems[index])
+
+			For Local i:Int = index Until toolitems.length - 1
+				toolitems[i] = toolitems[i + 1]
+			Next
+			toolitems = toolitems[..toolitems.length - 1]
+		End If
+	End Method
+
+	Method rethink:Int()
+	End Method
+
+	Method Free:Int()
+		Super.Free()
+
+		If handle
+			gtk_widget_destroy(handle)
+			
+			' assuming that destroying the toolbar will destroy 
+			For Local i:Int = 0 Until toolitems.length
+				toolitems[i] = Null
+			Next
+		EndIf
+		handle = Null
+	End Method
+
+	Method toString:String()
+		Return "TGTKToolbar"
+	End Method
+
+End Type
+
+Rem
+bbdoc: A tabber.
+End Rem
+Type TGTKTabber Extends TGTKContainer
+
+	Field icons:TGTKIconStrip
+	Field images:Byte Ptr[]
+	Field labels:Byte Ptr[]
+	Field pages:Byte Ptr[]
+	Field ignoreChange:Int
+	Field currentIndex:Int = -1
+
+	Function CreateTabber:TGTKTabber(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Local this:TGTKTabber = New TGTKTabber
+
+		this.initTabber(x, y, w, h, label, group, style)
+
+		Return this
+	End Function
+
+	Method initTabber(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+
+		handle = gtk_notebook_new()
+
+		Init(GTK_TABBER, x, y, w, h, style)
+
+		container = gtk_layout_new(Null, Null)
+		gtk_widget_show(container)
+		g_object_ref(container) ' hold an extra ref for our container
+
+		' Scrollable tabs if there are too many to fit on the display
+		gtk_notebook_set_scrollable(handle, True)
+
+		gtk_widget_show(handle)
+
+		g_signal_tabchange(handle, "switch-page", OnTabChanged, Self, Destroy, 0)
+
+		gtk_layout_put(TGTKContainer(group).container, handle, x, y)
+		gtk_widget_set_size_request(handle, w, Max(h,0))
+
+	End Method
+
+	Function OnTabChanged(widget:Byte Ptr, page:Byte Ptr, index:Int, obj:Object)
+		If TGTKTabber(obj).currentIndex >= 0 Then
+			Local child:Byte Ptr = gtk_notebook_get_nth_page(TGTKTabber(obj).handle, TGTKTabber(obj).currentIndex)
+			TGTKTabber(obj).RemoveFromTab(child)
+		End If
+		
+		If index >= 0 Then
+			TGTKTabber(obj).AddToTab(page)
+		End If
+		TGTKTabber(obj).currentIndex = index
+
+		If Not TGTKTabber(obj).ignoreChange Then
+			PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), index,,,,TGadget(obj).ItemExtra(index))
+		End If
+		TGTKTabber(obj).ignoreChange = False
+	End Function
+
+	Rem
+	bbdoc: Inserts a new tab
+	End Rem
+	Method InsertListItem:Int(index:Int, text:String, tip:String, icon:Int, tag:Object)
+
+		Local image:Byte Ptr
+
+		If icons And icon>=0 Then
+			image = icons.images[icon]
+		End If
+
+		images = images[..images.length+1]
+		For Local i:Int = images.length - 2 To index Step -1
+			images[i + 1] = images[i]
+		Next
+
+		labels = labels[..labels.length+1]
+		For Local i:Int = labels.length - 2 To index Step -1
+			labels[i + 1] = labels[i]
+		Next
+		
+		pages = pages[..pages.length+1]
+		For Local i:Int = pages.length - 2 To index Step -1
+			pages[i + 1] = pages[i]
+		Next
+
+		If image Then
+			images[index] = gtk_image_new_from_pixbuf(image)
+			gtk_widget_show(images[index])
+		Else
+			images[index] = gtk_image_new()
+		End If
+
+		' since a Label can't accept events, we wrap it inside an event box which can
+		Local box:Byte Ptr = gtk_event_box_new()
+		gtk_event_box_set_visible_window(box, False)
+		gtk_widget_add_events(box, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK)
+		' show the box
+		gtk_widget_show(box)
+	
+		' create a display label for the tab
+		Local textPtr:Byte Ptr = text.ToUTF8String()
+		labels[index] = gtk_label_new(textPtr)
+		MemFree(textPtr)
+		gtk_widget_show(labels[index])
+		
+		' create a horizontal box to place the image/label combo
+		Local hbox:Byte Ptr = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4)
+		gtk_widget_show(hbox)
+		
+		' add widgets to the hbox
+		gtk_box_pack_start(hbox, images[index], False, False, 0)
+		gtk_box_pack_start(hbox, labels[index], False, False, 0)
+		
+		' add the hbox to the eventbox
+		gtk_container_add(box, hbox)
+
+		' create a child to hold our container.
+		Local child:Byte Ptr = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0)
+		pages[index] = child
+		gtk_widget_show(child)
+
+		gtk_notebook_insert_page(handle, child, box, index)
+
+		' Add a tooltip to the event box
+		SetToolTipIndex(index, tip, box)
+	End Method
+
+	Method SetListItem:Int(index:Int, text:String, tip:String, icon:Int, tag:Object)
+		Local child:Byte Ptr = gtk_notebook_get_nth_page(handle, index)
+		
+		' get the event box to which we set tooltips
+		Local box:Byte Ptr = gtk_notebook_get_tab_label(handle, child)
+
+		' is there an image to show?
+		Local image:Byte Ptr
+		If icons And icon>=0 Then
+			image = icons.images[icon]
+		End If
+
+		If Not image Then
+			' hide image if none
+			gtk_widget_hide(images[index])
+		Else
+			' set and display image
+			gtk_image_set_from_pixbuf(images[index], image)
+			gtk_widget_show(images[index])
+		End If
+
+		' set new text
+		Local textPtr:Byte Ptr = text.ToUTF8String()
+		gtk_label_set_text(labels[index], textPtr)
+		MemFree(textPtr)
+		
+		' Add a tooltip to the event box
+		SetToolTipIndex(index, tip, box)
+	End Method
+
+	Method RemoveListItem:Int(index:Int)
+		Local arr:Byte Ptr[] = images
+		images = images[..images.length-1]
+		For Local i:Int = index To arr.length-2
+			images[i] = arr[i+1]
+		Next
+
+		arr = labels
+		labels = labels[..labels.length-1]
+		For Local i:Int = index To arr.length-2
+			labels[i] = arr[i+1]
+		Next
+
+		arr = pages
+		pages = pages[..pages.length-1]
+		For Local i:Int = index To arr.length-2
+			pages[i] = arr[i+1]
+		Next
+
+		' remove from current tab if required
+		If gtk_notebook_get_current_page(handle) = index Then
+			Local child:Byte Ptr = gtk_notebook_get_nth_page(handle, index)
+			RemoveFromTab(child)
+			currentIndex = -1
+		Else If index < currentIndex Then
+			currentIndex :- 1
+		End If
+		
+		gtk_notebook_remove_page(handle, index)
+		
+	End Method
+
+	Method ListItemState:Int(index:Int)
+		Local state:Int = 0
+
+		If gtk_notebook_get_current_page(handle) = index Then
+			state:| STATE_SELECTED
+		End If
+
+		Return state
+	End Method
+
+	Method SetListItemState:Int(index:Int, state:Int)
+		If state & STATE_SELECTED Then
+			If gtk_notebook_get_current_page(handle) <> index Then
+				ignoreChange = True
+?bmxng
+				IWrappedSystemDriver(SystemDriver()).GetDriver().Poll()
+?Not bmxng
+				brl.System.Driver.Poll() ' update events
+?
+				gtk_notebook_set_current_page(handle, index)
+			End If
+		End If
+	End Method
+
+	Method ClientHeight:Int()
+		Local h:Int = height
+
+		If handle Then
+?bmxng
+			Local minReq:GtkRequisition 
+			Local natReq:GtkRequisition
+?Not bmxng
+			Local minReq:GtkRequisition = New GtkRequisition
+			Local natReq:GtkRequisition = New GtkRequisition
+?
+			gtk_widget_get_preferred_size(handle, minReq, natReq)
+
+			h :- 34 ' FIXME : current hard-coded. Should be height of notebook less tab height and border.
+
+		End If
+
+		Return Max(0, h)
+	End Method
+
+	Method ClientWidth:Int()
+		Local w:Int = width
+
+		If handle Then
+?bmxng
+			Local minReq:GtkRequisition 
+			Local natReq:GtkRequisition
+?Not bmxng
+			Local minReq:GtkRequisition = New GtkRequisition
+			Local natReq:GtkRequisition = New GtkRequisition
+?
+			gtk_widget_get_preferred_size(handle, minReq, natReq)
+			w:- 4 ' FIXME : current hard-coded. Should be width of notebook less borders.
+		End If
+
+		Return Max(0, w)
+	End Method
+
+	Method SetToolTipIndex:Int(index:Int, tip:String, label:Byte Ptr)
+		' Add a tooltip
+		If tip And tip.length > 0 Then
+			Local tipPtr:Byte Ptr = tip.ToUTF8String()
+			gtk_widget_set_tooltip_text(label, tipPtr)
+			MemFree(tipPtr)
+		Else
+			gtk_widget_set_tooltip_text(label, Null)
+		End If		
+	End Method
+
+	Method SetIconStrip:Int(iconstrip:TIconStrip)
+		icons = TGTKIconStrip(iconstrip)
+	End Method
+
+	Method Free:Int()
+		Super.Free()
+		
+		If container Then
+			gtk_widget_destroy(container)
+			container = Null
+		End If
+
+		handle = Null
+		images = Null
+		labels = Null
+	End Method
+
+	Method Rethink:Int()
+		If handle Then
+			gtk_layout_move(TGTKContainer(parent).container, handle, xpos, ypos)
+			gtk_widget_set_size_request(handle, Max(width,0), Max(height,0))
+		End If
+	End Method
+
+	Method toString:String()
+		Return "TGTKTabber"
+	End Method
+	
+	Method RemoveFromTab(page:Byte Ptr)
+		If currentIndex >= 0 Then
+			g_object_ref(container)
+			gtk_container_remove(page, container)
+		End If
+	End Method
+
+	Method AddToTab(page:Byte Ptr)
+		gtk_box_pack_start(page, container, True, True, 0)
+		g_object_unref(container)
+	End Method
+
+End Type
+
+Rem
+bbdoc: A Panel
+End Rem
+Type TGTKPanel Extends TGTKContainer
+
+	Field frame:Byte Ptr
+	Field hasFrame:Int
+	Field panelPixmap:TPixmap
+	Field panelPixbuf:Byte Ptr
+	Field pixmapMode:Int
+	
+	Field drawPixbuf:Int
+	Field visualpixbuf:Byte Ptr
+	Field pbx:Int
+	Field pby:Int
+	
+	Field pane:Int
+
+	Function CreatePanel:TGTKPanel(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int, intoPane:Int = 0)
+		Local this:TGTKPanel = New TGTKPanel
+
+		this.initPanel(x, y, w, h, label, group, style, intoPane)
+
+		Return this
+	End Function
+
+	Method initPanel(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int, intoPane:Int)
+
+		handle = gtk_layout_new(Null, Null)
+
+		Init(GTK_PANEL, x, y, w, h, style)
+
+		container = handle
+		
+		If style & PANEL_ACTIVE
+			sensitivity:| SENSITIZE_MOUSE | SENSITIZE_KEYS
+		End If
+
+		gtk_widget_add_events(handle, GDK_BUTTON_PRESS_MASK | ..
+			GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | ..
+			GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK)' | ..
+'				GDK_POINTER_MOTION_HINT_MASK)
+
+		addConnection("button-press-event", g_signal_cb3_ret(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
+		addConnection("button-release-event", g_signal_cb3_ret(handle, "button-release-event", OnMouseUp, Self, Destroy, 0))
+		addConnection("enter-notify-event", g_signal_cb3_ret(handle, "enter-notify-event", OnMouseEnter, Self, Destroy, 0))
+		addConnection("leave-notify-event", g_signal_cb3_ret(handle, "leave-notify-event", OnMouseLeave, Self, Destroy, 0))
+		addConnection("motion-notify-event", g_signal_cb3_ret(handle, "motion-notify-event", OnMouseMove, Self, Destroy, 0))
+		addConnection("draw", g_signal_cb3_ret(handle, "draw", OnDraw, Self, Destroy, 0))
+		addConnection("scroll-event", g_signal_cb3(handle, "scroll-event", OnScroll, Self, Destroy, 0))
+
+		addConnection("key-press-event", g_signal_cb3_ret(handle, "key-press-event", OnKeyDown, Self, Destroy, 0))
+		addConnection("key-release-event", g_signal_cb3_ret(handle, "key-release-event", OnKeyUp, Self, Destroy, 0))
+
+		gtk_widget_show(handle)
+
+		' Should we add a frame?
+		If style & PANEL_BORDER Or style & PANEL_GROUP Then
+
+			hasFrame = True
+
+			frame = gtk_frame_new(Null)
+			gtk_widget_show(frame)
+
+			' set frame text
+			If (LocalizationMode() & LOCALIZATION_OVERRIDE) Then
+				LocalizeGadget(Self, label)
+			Else
+				SetText(label)
+			EndIf
+			
+			gtk_container_add(frame, handle)
+
+			gtk_layout_put(TGTKContainer(group).container, frame, x, y)
+			gtk_widget_set_size_request(frame, w, Max(h,0))
+
+		Else
+
+			gtk_layout_put(TGTKContainer(group).container, handle, x, y)
+			gtk_widget_set_size_request(handle, w, Max(h,0))
+
+		End If
+
+	End Method
+
+	Rem
+	bbdoc: Callback for mouse button press.
+	End Rem
+	Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		If TGTKPanel(obj).style & PANEL_ACTIVE Then
+			Local x:Double, y:Double, button:Int
+			bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
+
+			If button = 3 Then
+				button = 2
+			Else If button = 2 Then
+				button = 3
+			End If
+
+			PostGuiEvent(EVENT_MOUSEDOWN, TGadget(obj),button,,x,y)
+		End If
+		Return True
+	End Function
+
+	Rem
+	bbdoc: Callback for mouse button release.
+	End Rem
+	Function OnMouseUp:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		If TGTKPanel(obj).style & PANEL_ACTIVE Then
+			Local x:Double, y:Double, button:Int
+			bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
+
+			If button = 3 Then
+				button = 2
+			Else If button = 2 Then
+				button = 3
+			End If
+			
+			PostGuiEvent(EVENT_MOUSEUP, TGadget(obj),button,,x,y)
+		End If
+		Return True
+	End Function
+
+	Rem
+	bbdoc: Callback for mouse enter.
+	End Rem
+	Function OnMouseEnter:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		If TGTKPanel(obj).style & PANEL_ACTIVE Then
+			If TGTKGadget(obj).visible Then
+				PostGuiEvent(EVENT_MOUSEENTER, TGadget(obj))
+			End If
+		End If
+		Return False
+	End Function
+
+	Rem
+	bbdoc: Callback for mouse leave.
+	End Rem
+	Function OnMouseLeave:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		If TGTKPanel(obj).style & PANEL_ACTIVE Then
+			If TGTKGadget(obj).visible Then
+				PostGuiEvent(EVENT_MOUSELEAVE, TGadget(obj))
+			End If
+		End If
+		Return False
+	End Function
+
+	Rem
+	bbdoc: Callback for mouse movement
+	End Rem
+	Function OnMouseMove:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		If TGTKPanel(obj).style & PANEL_ACTIVE Then
+			Local _x:Double, _y:Double, button:Int
+			bmx_gtk3maxgui_gdkeventmotion(event, Varptr _x, Varptr _y, Varptr button)
+			Local x:Int, y:Int
+			
+			' we actually ignore the coords returned by the event and get the
+			' mouse coords relative to this widget's parent
+			gdk_window_get_device_position(gtk_widget_get_parent_window(widget), bmx_gtk3maxgui_gdkeventmotiondevice(event), x, y, button)
+
+			' then we remove the stored coords from that value to get the TRUE coords.
+			x:- TGTKPanel(obj).xpos
+			y:- TGTKPanel(obj).ypos
+			
+			If button & GDK_BUTTON1_MASK Then
+				button = 1
+			Else If button & GDK_BUTTON3_MASK Then
+				button = 2
+			Else If button & GDK_BUTTON2_MASK Then
+				button = 3
+			Else
+				button = 0
+			End If
+			PostGuiEvent(EVENT_MOUSEMOVE, TGadget(obj),button,,x,y)
+		End If
+		Return True
+	End Function
+
+	Function OnDraw:Int(widget:Byte Ptr, cairo:Byte Ptr, obj:Object)
+		Local panel:TGTKPanel = TGTKPanel(obj)
+		If panel Then
+			If panel.drawPixbuf And panel.visualpixbuf Then
+				gdk_cairo_set_source_pixbuf(cairo, panel.visualpixbuf, panel.pbx, panel.pby)
+				cairo_paint(cairo)
+				cairo_fill(cairo)
+			End If
+		End If
+		PostGuiEvent(EVENT_GADGETPAINT, TGadget(obj))
+	End Function
+	
+	Rem
+	bbdoc: Callback for mouse scroll wheel
+	End Rem
+	Function OnScroll(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		If TGTKPanel(obj).style & PANEL_ACTIVE Then
+			Local x:Double, y:Double, direction:Int
+			bmx_gtk3maxgui_gdkeventscroll(event, Varptr x, Varptr y, Varptr direction)
+
+			If direction = GDK_SCROLL_UP Or direction = GDK_SCROLL_LEFT Then
+				PostGuiEvent(EVENT_MOUSEWHEEL, TGadget(obj),-1,,x,y)
+			Else
+				PostGuiEvent(EVENT_MOUSEWHEEL, TGadget(obj),1,,x,y)
+			End If
+		End If
+	End Function
+
+	Rem
+	bbdoc: Callback for key down
+	End Rem
+	Function OnKeyDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		If TGTKPanel(obj).style & PANEL_ACTIVE Then
+			Local _key:Int, _mods:Int
+			bmx_gtk3maxgui_gdkeventkey(event, Varptr _key, Varptr _mods)
+			Local key:Int = TGTKKeyMap.mapBack(_key)
+			Local mods:Int = TGTKKeyMap.mapModifierBack(_mods)
+	
+			If Not gtk3SetKeyDown(key) Then
+				PostGuiEvent(EVENT_KEYDOWN, TGadget(obj), key, mods)
+			Else
+				PostGuiEvent(EVENT_KEYREPEAT, TGadget(obj), key, mods)
+			End If
+
+			Local char:Int = gdk_keyval_to_unicode(_key)
+			' we sometimes get 0 from this function when key is valid... so set it to key just so that it has a value.
+			If char = 0 And key <> 0 Then
+				char = key
+			End If
+			PostGuiEvent(EVENT_KEYCHAR, TGadget(obj), char, mods)
+	
+			Return True
+		End If
+	End Function
+
+	Rem
+	bbdoc: Callback for key up
+	End Rem
+	Function OnKeyUp:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		If TGTKPanel(obj).style & PANEL_ACTIVE Then
+			Local _key:Int, _mods:Int
+			bmx_gtk3maxgui_gdkeventkey(event, Varptr _key, Varptr _mods)
+			Local key:Int = TGTKKeyMap.mapBack(_key)
+			Local mods:Int = TGTKKeyMap.mapModifierBack(_mods)
+			
+			gtk3SetKeyUp(key)
+			PostGuiEvent(EVENT_KEYUP, TGadget(obj), key, mods)
+	
+			Return True
+		End If
+	End Function
+
+	Rem
+	bbdoc: Sets the text of a group panel.
+	End Rem
+	Method SetText:Int(text:String)
+		If style & PANEL_GROUP Then
+			If text = Null Or text.length = 0 Then
+				gtk_frame_set_label(frame, Null)
+			Else
+				Local textPtr:Byte Ptr = text.ToUTF8String()
+				gtk_frame_set_label(frame, textPtr)
+				MemFree(textPtr)
+			End If
+		End If
+	End Method
+
+	Rem
+	bbdoc: Shows or hides a panel
+	End Rem
+	Method SetShow:Int(truefalse:Int)
+		visible = truefalse
+		mySetVisible = visible
+		
+		If truefalse Then
+			If frame Then
+				gtk_widget_show(frame)
+			Else
+				gtk_widget_show(handle)
+			End If
+		Else
+			If frame Then
+				gtk_widget_hide(frame)
+			Else
+				gtk_widget_hide(handle)
+			End If
+		EndIf
+
+		UpdateChildVisibility()
+	End Method
+
+	Method Free:Int()
+		Super.Free()
+
+		If frame Then
+			gtk_widget_destroy(frame)
+		Else
+			If handle Then
+				gtk_widget_destroy(handle)
+			End If
+		End If
+		
+		container = Null
+		handle = Null
+		frame = Null
+		
+		If panelpixmap Then
+			panelpixmap = Null
+		End If
+		If panelPixbuf Then
+			g_object_unref(panelPixbuf)
+			panelPixbuf = Null
+		End If
+	End Method
+
+	Rem
+	bbdoc: Set the panel color.
+	End Rem
+	Method SetColor:Int(r:Int, g:Int, b:Int)
+		Local color:GdkRGBA = New GdkRGBA(r / 255.0, g / 255.0, b / 255.0)
+		gtk_widget_override_background_color(handle, GTK_STATE_FLAG_NORMAL, color)
+	End Method
+
+	Rem
+	bbdoc: Set the panel pixmap.
+	End Rem
+	Method SetPixmap:Int(pixmap:TPixmap, flags:Int)
+		pixmapMode = flags
+		
+		If pixmap Then
+			If PixmapFormat(pixmap) <> PF_RGBA8888 And PixmapFormat(pixmap) <> PF_BGRA8888 Then
+				panelPixmap = pixmap.convert( PF_RGBA8888 )
+			Else
+				panelPixmap = pixmap
+			End If
+			
+			If panelPixbuf Then
+				g_object_unref(panelPixbuf)
+			End If
+
+			panelPixbuf = gdk_pixbuf_new_from_data(panelPixmap.pixels, GDK_COLORSPACE_RGB, True, 8, ..
+							panelPixmap.width, panelPixmap.height, panelPixmap.Pitch, Null, Null)
+		Else
+			If panelPixmap Then
+				panelPixmap = Null
+			End If
+		End If
+		redraw()
+	End Method
+	
+	Method rethink:Int()
+		If frame Then
+			gtk_layout_move(TGTKContainer(parent).container, frame, xpos, ypos)
+			gtk_widget_set_size_request(frame, Max(width,0), Max(height,0))
+		Else If handle Then
+			gtk_layout_move(TGTKContainer(parent).container, handle, xpos, ypos)
+			gtk_widget_set_size_request(handle, Max(width,0), Max(height,0))
+		End If
+		redraw()
+	End Method
+
+	Method redraw()
+
+		If Not panelPixmap Then
+			If panelPixbuf Then
+				g_object_unref(panelPixbuf)
+				panelPixbuf = Null
+			End If
+			If visualpixbuf Then
+				g_object_unref(visualpixbuf)
+				visualpixbuf = Null
+				' make the panel redraw itself
+				gtk_widget_queue_draw(handle)
+			End If
+		End If
+		
+		If panelPixbuf Then
+			
+			If visualpixbuf Then
+				g_object_unref(visualpixbuf)
+			End If
+			Select pixmapMode & (PANELPIXMAP_TILE | PANELPIXMAP_CENTER | PANELPIXMAP_FIT | PANELPIXMAP_FIT2 | PANELPIXMAP_STRETCH)
+				Case PANELPIXMAP_TILE
+
+					pbx = 0
+					pby = 0
+
+					Local w:Float = width
+					Local h:Float = height
+
+					Local wfull:Int = w / panelPixmap.width
+					Local hfull:Int = h / panelPixmap.height
+					
+					Local wpart:Int = w Mod panelPixmap.width
+					Local hpart:Int = h Mod panelPixmap.height
+					
+					visualpixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, True, 8, Int(w), Int(h))
+					
+					For Local x:Int = 0 Until wfull
+					
+						For Local y:Int = 0 Until hfull
+							gdk_pixbuf_copy_area(panelPixbuf, 0, 0, panelPixmap.width, panelPixmap.height, visualpixbuf, x * panelPixmap.width, y * panelPixmap.height)
+						Next
+						
+						If hpart > 0 Then
+							gdk_pixbuf_copy_area(panelPixbuf, 0, 0, panelPixmap.width, hpart, visualpixbuf, x * panelPixmap.width, hfull * panelPixmap.height)
+						End If
+					
+					Next
+					
+					If wpart > 0 Then
+					
+						For Local y:Int = 0 Until hfull
+							gdk_pixbuf_copy_area(panelPixbuf, 0, 0, wpart, panelPixmap.height, visualpixbuf, wfull * panelPixmap.width, y * panelPixmap.height)
+						Next
+					
+						If hpart > 0 Then
+							gdk_pixbuf_copy_area(panelPixbuf, 0, 0, wpart, hpart, visualpixbuf, wfull * panelPixmap.width, hfull * panelPixmap.height)
+						End If
+					
+					End If
+				
+				Case PANELPIXMAP_CENTER
+					visualpixbuf = gdk_pixbuf_copy(panelPixBuf)
+					pbx = width / 2 - panelPixmap.width / 2
+					pby = height / 2 - panelPixmap.height / 2
+					
+				Case PANELPIXMAP_FIT
+					Local _w:Float = width / (panelPixmap.width * 1.0)
+					Local _h:Float = height / (panelPixmap.height * 1.0)
+
+					Local newWidth:Int = Min(_w, _h) * panelPixmap.width
+					Local newHeight:Int = Min(_w, _h) * panelPixmap.height
+
+					pbx = width / 2 - newWidth / 2
+					pby = height / 2 - newHeight / 2
+
+					visualpixbuf = gdk_pixbuf_scale_simple(panelPixbuf, newWidth, newHeight, GDK_INTERP_BILINEAR)
+
+				Case PANELPIXMAP_FIT2
+					Local _w:Float = width / (panelPixmap.width * 1.0)
+					Local _h:Float = height / (panelPixmap.height * 1.0)
+
+					Local newWidth:Int = Max(_w, _h) * panelPixmap.width
+					Local newHeight:Int = Max(_w, _h) * panelPixmap.height
+
+					pbx = width / 2 - newWidth / 2
+					pby = height / 2 - newHeight / 2
+
+					visualpixbuf = gdk_pixbuf_scale_simple(panelPixbuf, newWidth, newHeight, GDK_INTERP_BILINEAR)
+					
+				Case PANELPIXMAP_STRETCH
+					pbx = 0
+					pby = 0
+					visualpixbuf = gdk_pixbuf_scale_simple(panelPixbuf, width, height, GDK_INTERP_BILINEAR)
+			End Select
+			
+			If Not drawPixbuf Then
+				drawPixbuf = True
+			End If
+		
+		End If
+		
+		' make sure the panel refreshes visually
+		Super.redraw()
+	End Method
+
+	Method Activate:Int(cmd:Int)
+		Select cmd
+			Case ACTIVATE_REDRAW
+				redraw()
+		Default
+			Super.Activate(cmd)
+		End Select
+	End Method
+
+	Method toString:String()
+		Return "TGTKPanel"
+	End Method
+End Type
+
+Rem
+bbdoc: A canvas.
+End Rem
+Rem 
+Type TGTKCanvas Extends TGTKGadget
+
+	Field canvas:TGraphics
+	Field Mode:Int
+	
+
+	Function CreateCanvas:TGTKCanvas(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Local this:TGTKCanvas = New TGTKCanvas
+
+		this.initCanvas(x, y, w, h, label, group, style)
+
+		Return this
+	End Function
+
+	Method initCanvas(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+
+		handle = gtk_drawing_area_new()
+
+		Init(GTK_CANVAS, x, y, w, h, style)
+
+		gtk_layout_put(TGTKContainer(group).container, handle, x, y)
+		gtk_widget_set_size_request(handle, w, Max(h,0))
+
+		sensitivity:| SENSITIZE_MOUSE | SENSITIZE_KEYS
+
+		' we need to allow the drawing area to accept focus !
+		g_object_set_int(handle, "can-focus", True)
+
+		' we need to handle our own redrawing...
+		'gtk_widget_set_double_buffered(handle, False)
+
+		addConnection("expose_event", g_signal_cb3(handle, "expose_event", CanvasRedraw, Self, Destroy, 0))
+
+		gtk_widget_add_events(handle, GDK_BUTTON_PRESS_MASK | ..
+			GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | ..
+			GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK)' | ..
+'				GDK_POINTER_MOTION_HINT_MASK)
+
+		addConnection("button-press-event", g_signal_cb3(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
+		addConnection("button-release-event", g_signal_cb3(handle, "button-release-event", OnMouseUp, Self, Destroy, 0))
+		addConnection("enter-notify-event", g_signal_cb3(handle, "enter-notify-event", OnMouseEnter, Self, Destroy, 0))
+		addConnection("leave-notify-event", g_signal_cb3(handle, "leave-notify-event", OnMouseLeave, Self, Destroy, 0))
+		addConnection("motion-notify-event", g_signal_cb3(handle, "motion-notify-event", OnMouseMove, Self, Destroy, 0))
+		addConnection("scroll-event", g_signal_cb3(handle, "scroll-event", OnScroll, Self, Destroy, 0))
+
+		addConnection("key-press-event", g_signal_cb3(handle, "key-press-event", OnKeyDown, Self, Destroy, 0))
+		addConnection("key-release-event", g_signal_cb3(handle, "key-release-event", OnKeyUp, Self, Destroy, 0))
+
+		SetShow(True)
+	End Method
+
+	Function CanvasRedraw(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		PostGuiEvent(EVENT_GADGETPAINT, TGadget(obj))
+	End Function
+	
+	Method AttachGraphics:TGraphics( flags:Int )
+		Mode = flags
+	End Method
+
+	Method CanvasGraphics:TGraphics()
+		If Not canvas Then
+			canvas = BRL.Graphics.AttachGraphics(gdk_x11_drawable_get_xid(gtk_widget_get_window(handle)), Mode)
+		End If
+
+		Return canvas
+	End Method
+
+	Method Activate:Int(cmd:Int)
+		If cmd <> ACTIVATE_REDRAW Then
+			Super.Activate(cmd)
+		End If
+
+		Select cmd
+			Case ACTIVATE_REDRAW
+				gtk_widget_queue_draw(handle)
+		End Select
+	End Method
+
+	Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		Local x:Double, y:Double, button:Int
+		bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
+
+		If button = 3 Then
+			button = 2
+		Else If button = 2 Then
+			button = 3
+		End If
+
+		PostGuiEvent(EVENT_MOUSEDOWN, TGadget(obj),button,,x,y)
+
+		Return True
+	End Function
+	
+	Function OnScroll(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		Local x:Double, y:Double, direction:Int
+		bmx_gtk3maxgui_gdkeventscroll(event, Varptr x, Varptr y, Varptr direction)
+
+		If direction = GDK_SCROLL_UP Or direction = GDK_SCROLL_LEFT Then
+			PostGuiEvent(EVENT_MOUSEWHEEL, TGadget(obj),-1,,x,y)
+		Else
+			PostGuiEvent(EVENT_MOUSEWHEEL, TGadget(obj),1,,x,y)
+		End If
+	End Function
+
+	Function OnMouseUp:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		Local x:Double, y:Double, button:Int
+		bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
+
+		If button = 3 Then
+			button = 2
+		Else If button = 2 Then
+			button = 3
+		End If
+
+		PostGuiEvent(EVENT_MOUSEUP, TGadget(obj),button,,x,y)
+
+		Return True
+	End Function
+
+	Function OnMouseEnter:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		PostGuiEvent(EVENT_MOUSEENTER, TGadget(obj))
+
+		Return True
+	End Function
+
+	Function OnMouseLeave:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+
+		PostGuiEvent(EVENT_MOUSELEAVE, TGadget(obj))
+
+		Return True
+	End Function
+
+	'Rem
+	'bbdoc: Callback for mouse movement
+	'End Rem
+	Function OnMouseMove:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		Local x:Double, y:Double, button:Int
+		bmx_gtk3maxgui_gdkeventmotion(event, Varptr x, Varptr y, Varptr button)
+
+		If button & GDK_BUTTON1_MASK Then
+			button = 1
+		Else If button & GDK_BUTTON3_MASK Then
+			button = 2
+		Else If button & GDK_BUTTON2_MASK Then
+			button = 3
+		Else
+			button = 0
+		End If
+		PostGuiEvent(EVENT_MOUSEMOVE, TGadget(obj),button,,x,y)
+
+		Return True
+	End Function
+
+	Function OnKeyDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		Local _key:Int, _mods:Int
+		bmx_gtk3maxgui_gdkeventkey(event, Varptr _key, Varptr _mods)
+		Local key:Int = TGTKKeyMap.mapBack(_key)
+		Local mods:Int = TGTKKeyMap.mapModifierBack(_mods)
+
+		If Not gtk3SetKeyDown(key) Then
+			PostGuiEvent(EVENT_KEYDOWN, TGadget(obj), key, mods)
+		Else
+			PostGuiEvent(EVENT_KEYREPEAT, TGadget(obj), key, mods)
+		End If
+
+		Local char:Int = gdk_keyval_to_unicode(_key)
+		' we sometimes get 0 from this function when key is valid... so set it to key just so that it has a value.
+		If char = 0 And key <> 0 Then
+			char = key
+		End If
+		PostGuiEvent(EVENT_KEYCHAR, TGadget(obj), char, mods)
+
+		Return True
+	End Function
+
+	Function OnKeyUp:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		Local _key:Int, _mods:Int
+		bmx_gtk3maxgui_gdkeventkey(event, Varptr _key, Varptr _mods)
+		Local key:Int = TGTKKeyMap.mapBack(_key)
+		Local mods:Int = TGTKKeyMap.mapModifierBack(_mods)
+		
+		gtk3SetKeyUp(key)
+		PostGuiEvent(EVENT_KEYUP, TGadget(obj), key, mods)
+
+		Return True
+	End Function
+
+	Method free:Int()
+		Super.free()
+		
+		If canvas
+			canvas.Close()
+			canvas = Null
+		End If
+		
+		If handle 
+			gtk_widget_destroy(handle)
+		EndIf
+		handle = Null
+	End Method
+End Type
+End Rem
+
+Rem
+bbdoc: A text area.
+End Rem
+Type TGTKDefaultTextArea Extends TGTKTextArea
+
+	Field _tabsize:Int = 4
+
+	Field scrollWindow:Byte Ptr
+	Field _textBuffer:Byte Ptr
+	Field _textTagTable:Byte Ptr
+	Field _tabArray:Byte Ptr
+	Field ignoreChange:Int
+	Field fastUpdate:Int = False
+	
+	'Field _selStart:Int
+	'Field _selEnd:Int
+
+	Function CreateTextArea:TGTKTextArea(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Local this:TGTKDefaultTextArea = New TGTKDefaultTextArea
+
+		this.initTextArea(x, y, w, h, label, group, style)
+
+		Return this
+	End Function
+
+	Method initTextArea(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		_textBuffer = gtk_text_buffer_new(Null)
+		_textTagTable = gtk_text_buffer_get_tag_table(_textBuffer)
+
+		handle = gtk_text_view_new_with_buffer(_textBuffer)
+		gtk_widget_show(handle)
+		
+		' we need these events to allow tooltips to work
+		gtk_widget_add_events(handle, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK)
+
+		' use word-wrapping ?
+		If style & TEXTAREA_WORDWRAP Then
+			gtk_text_view_set_wrap_mode(handle, GTK_WRAP_WORD_CHAR)
+		End If
+
+		' a read-only textarea ?
+		If style & TEXTAREA_READONLY Then
+			gtk_text_view_set_editable(handle, False)
+		End If
+
+		Init(GTK_TEXTFIELD, x, y, w, h, style)
+
+		' scrollbars for the textarea...
+		scrollWindow = gtk_scrolled_window_new(Null, Null)
+		' set container resize mode
+		gtk_container_set_resize_mode(scrollWindow, GTK_RESIZE_QUEUE)
+		' set scrollbar policy
+		gtk_scrolled_window_set_policy(scrollWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC)
+		' show
+		gtk_widget_show(scrollWindow)
+
+		' add the text area to the scroll window
+		gtk_container_add(scrollWindow, handle)
+
+
+		addConnection("changed", g_signal_cb2(_textBuffer, "changed", OnTextChanged, Self, Destroy, 0))
+		addConnection("move-cursor", g_signal_cb5(handle, "move-cursor", OnCursorMoved, Self, Destroy, 0))
+		addConnection("button-press-event", g_signal_cb3_ret(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
+		addConnection("button-release-event", g_signal_cb3_ret(handle, "button-release-event", OnMouseUp, Self, Destroy, 0))
+		addConnection("key-press-event", g_signal_cb3_ret(handle, "key-press-event", OnKeyDown, Self, Destroy, 0))
+		addConnection("focus-out-event", g_signal_cb3_ret(handle, "focus-out-event", OnFocusLost, Self, Destroy, 0))
+
+		'g_signal_cb3(handle, "visibility-notify-event", OnVisibilityChange, Self, Destroy, 0)
+
+		gtk_layout_put(TGTKContainer(group).container, scrollwindow, x, y)
+		gtk_widget_set_size_request(handle, w, Max(h,0))
+	End Method
+
+	Rem
+	bbdoc: Callback for text change
+	End Rem
+	Function OnTextChanged(widget:Byte Ptr, obj:Object)
+		If Not TGTKDefaultTextArea(obj).ignoreChange Then
+			PostGuiEvent(EVENT_GADGETSELECT, TGadget(obj))
+			PostGuiEvent(EVENT_GADGETACTION, TGadget(obj))
+		End If
+		TGTKDefaultTextArea(obj).ignoreChange = False
+	End Function
+
+	Rem
+	bbdoc: Callback for text-cursor movement
+	End Rem
+	Function OnCursorMoved(widget:Byte Ptr, _Step:Int, count:Int, extend_selection:Int, obj:Object)
+		PostGuiEvent(EVENT_GADGETSELECT, TGadget(obj))
+	End Function
+
+	Rem
+	bbdoc: Callback for mouse button press
+	End Rem
+	Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		Local x:Double, y:Double, button:Int
+		bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
+
+		If button = 3 Then ' right mouse button
+			' ignore this...  see MouseUp for menu event!
+			Return True
+		End If
+
+		PostGuiEvent(EVENT_GADGETSELECT, TGadget(obj))
+	End Function
+
+	Rem
+	bbdoc: Callback for mouse button release
+	End Rem
+	Function OnMouseUp:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
+		Local x:Double, y:Double, button:Int
+		bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
+
+		If button = 3 Then ' right mouse button
+			PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),,,x,y)
+			Return True
+		End If
+
+		PostGuiEvent(EVENT_GADGETSELECT, TGadget(obj))
+	End Function
+	
+	Rem
+	bbdoc: Adds text to the end of the text.
+	End Rem
+	Method AddText:Int(text:String)
+		Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
+		' get the end of the text
+		gtk_text_buffer_get_end_iter(_textBuffer, _end)
+
+		ignoreChange = True
+		Local textPtr:Byte Ptr = text.ToUTF8String()
+		gtk_text_buffer_insert(_textBuffer, _end, textPtr, -1)
+		MemFree(textPtr)
+
+		gtk_text_buffer_get_end_iter(_textBuffer, _end)
+?bmxng
+		IWrappedSystemDriver(SystemDriver()).GetDriver().Poll()
+?Not bmxng
+		brl.System.Driver.Poll() ' update events, before scrolling to the end...
+?
+		gtk_text_view_scroll_to_iter(handle, _end, 0, False, 0, 0)
+		
+		bmx_gtk3_gtktextiter_free(_end)
+	End Method
+
+	Rem
+	bbdoc: Returns the text For the specified location
+	End Rem
+	Method AreaText:String(pos:Int, length:Int, units:Int)
+		Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
+		Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
+
+		If units = TEXTAREA_LINES Then
+			gtk_text_buffer_get_iter_at_line(_textBuffer, _start, pos)
+			gtk_text_buffer_get_iter_at_line(_textBuffer, _end, pos + length)
+
+		Else ' must be TEXTAREA_CHARS
+			gtk_text_buffer_get_iter_at_offset(_textBuffer, _start, pos)
+			gtk_text_buffer_get_iter_at_offset(_textBuffer, _end, pos + length)
+
+		End If
+
+		Local s:Byte Ptr = gtk_text_buffer_get_text(_textBuffer, _start, _end, False)
+		Local st:String = String.FromUTF8String(s)
+		g_free(s)
+		
+		bmx_gtk3_gtktextiter_free(_start)
+		bmx_gtk3_gtktextiter_free(_end)
+		
+		Return st
+	End Method
+
+	Rem
+	bbdoc: Returns either the number of characters or number of rows.
+	End Rem
+	Method AreaLen:Int(units:Int)
+		If units = TEXTAREA_LINES Then
+			Return gtk_text_buffer_get_line_count(_textBuffer)
+		Else
+			Return gtk_text_buffer_get_char_count(_textBuffer)
+		End If
+	End Method
+
+	Rem
+	bbdoc: Returns the current cursor position value, in characters or lines
+	End Rem
+	Method GetCursorPos:Int(units:Int)
+		Local pos:Int = 0
+		Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
+		Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
+
+		' Since the cursor position might be at the end of selected text, we get the selection
+		' bounds and get the *start* location. If there is no selection, start and end will be the same
+
+		gtk_text_buffer_get_selection_bounds(_textBuffer, _start, _end)
+		
+		If units = TEXTAREA_LINES Then
+			pos = gtk_text_iter_get_line(_start)
+		Else ' must be TEXTAREA_CHARS
+			pos = gtk_text_iter_get_offset(_start)
+		End If
+
+		bmx_gtk3_gtktextiter_free(_start)
+		bmx_gtk3_gtktextiter_free(_end)
+
+		Return pos
+	End Method
+
+	Rem
+	bbdoc: Set the text area visibility.
+	End Rem
+	Method SetShow:Int(truefalse:Int)
+		visible = truefalse
+		mySetVisible = visible
+		
+		If truefalse Then
+			gtk_widget_show(handle)
+			gtk_widget_show(scrollWindow)
+		Else
+			gtk_widget_hide(scrollWindow)
+		EndIf
+	End Method
+
+	Rem
+	bbdoc: Set the text area font.
+	End Rem
+	Method SetFont:Int(font:TGuiFont)
+		Super.SetFont(font)
+
+		' we need to reset the tabs, as it is lost when font is changed.
+		SetTabs(_tabsize)
+	End Method
+
+	Rem
+	bbdoc: Sets the text buffer text
+	End Rem
+	Method SetText:Int(text:String)
+		ignoreChange = True
+		Local textPtr:Byte Ptr = text.ToUTF8String()
+		gtk_text_buffer_set_text(_textBuffer, textPtr, -1)
+		MemFree(textPtr)
+
+		' move the cursor to the start
+		Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
+		gtk_text_buffer_get_iter_at_line(_textBuffer, _start, 0)
+		gtk_text_buffer_place_cursor(_textBuffer, _start)
+		gtk_text_view_scroll_mark_onscreen(handle, gtk_text_buffer_get_insert(_textBuffer))', 0, False, 0, 0.1)
+		
+		bmx_gtk3_gtktextiter_free(_start)
+	End Method
+
+	Rem
+	bbdoc: Set the text area selection
+	End Rem
+	Method SetSelection:Int(pos:Int, length:Int, units:Int)
+
+		Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
+		Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
+
+		If units = TEXTAREA_LINES Then
+			gtk_text_buffer_get_iter_at_line(_textBuffer, _start, pos)
+			gtk_text_buffer_get_iter_at_line(_textBuffer, _end, pos + length)
+
+		Else ' must be TEXTAREA_CHARS
+			gtk_text_buffer_get_iter_at_offset(_textBuffer, _start, pos)
+			gtk_text_buffer_get_iter_at_offset(_textBuffer, _end, pos + length)
+
+		End If
+
+		gtk_text_buffer_place_cursor(_textBuffer, _start)
+		gtk_text_view_scroll_mark_onscreen(handle, gtk_text_buffer_get_insert(_textBuffer))
+		
+		gtk_text_buffer_select_range(_textBuffer, _start, _end)
+
+		PostGuiEvent(EVENT_GADGETSELECT, Self)
+
+		' scroll to the start of the selection
+		' NOTE: setting param4 to False causes it to scroll only as much as required to show the start
+		' Set to True to cause it to always display at the same point on the visible area.
+		gtk_text_view_scroll_to_iter(handle, _start, 0, False, 0, 0.1)
+
+		bmx_gtk3_gtktextiter_free(_start)
+		bmx_gtk3_gtktextiter_free(_end)
+	End Method
+
+	Rem
+	bbdoc: Returns the size of the current selection, in characters or lines.
+	End Rem
+	Method GetSelectionLength:Int(units:Int)
+		Local length:Int = 0
+
+		Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
+		Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
+
+		Local hasSelection:Int = gtk_text_buffer_get_selection_bounds(_textBuffer, _start, _end)
+
+		If hasSelection Then
+
+			If units = TEXTAREA_LINES Then
+
+				length = gtk_text_iter_get_line(_end) - gtk_text_iter_get_line(_start)
+
+			Else ' must be TEXTAREA_CHARS
+
+				length = gtk_text_iter_get_offset(_end) - gtk_text_iter_get_offset(_start)
+
+			End If
+
+		End If
+
+		bmx_gtk3_gtktextiter_free(_start)
+		bmx_gtk3_gtktextiter_free(_end)
+
+		Return length
+	End Method
+
+	Rem
+	bbdoc: Sets the style of part of the text area
+	about: @flags are any mix of TEXTFORMAT_BOLD, TEXTFORMAT_ITALIC, TEXTFORMAT_UNDERLINE and TEXTFORMAT_STRIKETHROUGH.<br>
+	We utilise the buffers' tag table to cache tags that we reuse - based on the attributes.
+	This way we only create one for each different style we actually use in the buffer.<br>
+	Note: "fastUpdate" flag enables or disables the use of gtk_text_buffer_remove_all_tags which strips
+	old tags from the area before applying the new one.<br>
+	Ideally, you would first remove tags before applying new ones, but since removal is slow, the following
+	method can work well :
+	<pre>
+	setFastUpdate(false)
+	SetStyle on whole intended area to "normal" style
+	setFastUpdate(true)
+	iterate thru tokens applying styles..
+	</pre>
+	End Rem
+	Method SetStyle:Int(r:Int, g:Int, b:Int, flags:Int, pos:Int, length:Int, units:Int)
+
+		' Build a style string
+		Local s:Int = r Shl 24 | g Shl 16 | b Shl 8 | (flags & $ff)
+		Local styleText:String = String(s)
+
+		' Does this one already exist?
+		Local _textTag:Byte Ptr = gtk_text_tag_table_lookup(_textTagTable, styleText)
+
+		' nope... so we need to create it
+		If _textTag = Null Then
+
+			Local color:GdkRGBA = New GdkRGBA(r / 255.0, g / 255.0, b / 255.0)
+'
+			Local _style:Int = PANGO_STYLE_NORMAL
+			If flags & TEXTFORMAT_ITALIC Then
+				_style = PANGO_STYLE_ITALIC
+			End If
+			Local _weight:Int = PANGO_WEIGHT_NORMAL
+			If flags & TEXTFORMAT_BOLD Then
+				_weight = PANGO_WEIGHT_BOLD
+			End If
+			Local _under:Int = PANGO_UNDERLINE_NONE
+			If flags & TEXTFORMAT_UNDERLINE Then
+				_under = PANGO_UNDERLINE_SINGLE
+			End If
+			Local _strike:Int = False
+			If flags & TEXTFORMAT_STRIKETHROUGH Then
+				_strike = True
+			End If
+
+			' create and setup the tag
+			_textTag = bmx_gtk3_set_text_tag_style(_textBuffer, styleText, color, _style, _weight, _under, _strike)
+			
+		End If
+
+		applyStyle(pos, length, units, _textTag)
+		
+	End Method
+	
+	Method applyStyle(pos:Int, length:Int, units:Int, _textTag:Byte Ptr)
+		' set up start and end points
+		Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
+		Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
+
+		If units = TEXTAREA_LINES Then
+			gtk_text_buffer_get_iter_at_line(_textBuffer, _start, pos)
+			gtk_text_buffer_get_iter_at_line(_textBuffer, _end, pos + length)
+		Else ' must be TEXTAREA_CHARS
+			gtk_text_buffer_get_iter_at_offset(_textBuffer, _start, pos)
+			gtk_text_buffer_get_iter_at_offset(_textBuffer, _end, pos + length)
+		End If
+
+		' remove any existing tags in the range first - otherwise they'll just pile up
+		' NOTE : except that this is REALLY slow....
+		If Not fastUpdate Then
+			gtk_text_buffer_remove_all_tags(_textBuffer, _start, _end)
+		End If
+
+		' apply the tag to the range
+		gtk_text_buffer_apply_tag(_textBuffer, _textTag, _start, _end)
+		
+		bmx_gtk3_gtktextiter_free(_start)
+		bmx_gtk3_gtktextiter_free(_end)
+	End Method
+
+	Method SetBGStyle(r:Int, g:Int, b:Int, pos:Int, length:Int, units:Int)
+
+		' Build a style string
+		Local styleText:String = r + "_" + g + "_" + b + "_bg"
+
+		' Does this one already exist?
+		Local _textTag:Byte Ptr = gtk_text_tag_table_lookup(_textTagTable, styleText)
+
+		' nope... so we need to create it
+		If _textTag = Null Then
+
+			Local color:GdkRGBA = New GdkRGBA(r / 255.0, g / 255.0, b / 255.0)
+		
+			' create and setup the tag
+			_textTag = bmx_gtk3_set_text_bg_tag(_textBuffer, styleText, color)
+
+		End If
+
+		applyStyle(pos, length, units, _textTag)
+
+	End Method	
+
+	Method ReplaceText:Int(pos:Int, length:Int, text:String, units:Int)
+
+		If length = TEXTAREA_ALL Then
+			SetText(text)
+		Else
+			' set up start and end points
+			Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
+			Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
+	
+			If units = TEXTAREA_LINES Then
+				gtk_text_buffer_get_iter_at_line(_textBuffer, _start, pos)
+				gtk_text_buffer_get_iter_at_line(_textBuffer, _end, pos + length)
+			Else ' must be TEXTAREA_CHARS
+				gtk_text_buffer_get_iter_at_offset(_textBuffer, _start, pos)
+				gtk_text_buffer_get_iter_at_offset(_textBuffer, _end, pos + length)
+			End If
+	
+			' remove the specified range
+			gtk_text_buffer_delete(_textBuffer, _start, _end)
+	
+			' insert new text
+			Local textPtr:Byte Ptr = text.ToUTF8String()
+			gtk_text_buffer_insert(_textBuffer, _start, textPtr, -1)
+			MemFree(textPtr)
+			
+			bmx_gtk3_gtktextiter_free(_start)
+			bmx_gtk3_gtktextiter_free(_end)
+		End If
+	End Method
+
+	Rem
+	bbdoc: Locks the text area.
+	End Rem
+	Method LockText:Int()
+		gtk_text_view_set_editable(handle, False)
+	End Method
+
+	Rem
+	bbdoc: Unlocks the text area
+	End Rem
+	Method UnlockText:Int()
+		gtk_text_view_set_editable(handle, True)
+	End Method
+
+	Rem
+	bbdoc: 
+	End Rem
+	Method SetTabs:Int(tabs:Int)
+
+		' cache the current size
+		_tabsize = tabs
+
+		' get the current tab array - returns Null if default 8-space setting
+		_tabArray = gtk_text_view_get_tabs(handle)
+		
+		If _tabArray <> Null Then
+			pango_tab_array_free(_tabArray)
+		End If
+
+		Local tabmul:Int = 8 * 1024
+		If _font <> Null Then
+			tabmul = _font.size * 1024
+		End If
+
+		_tabArray = pango_tab_array_new_with_positions(1, False, PANGO_TAB_LEFT, tabs * tabmul)
+		gtk_text_view_set_tabs(handle, _tabArray)
+
+	End Method
+
+	Method CharAt:Int(line:Int)
+		Local _iter:Byte Ptr = bmx_gtk3_gtktextiter_new()
+		gtk_text_buffer_get_iter_at_line(_textBuffer, _iter, line)
+		Local ret:Int = gtk_text_iter_get_offset(_iter)
+		bmx_gtk3_gtktextiter_free(_iter)
+		Return ret
+	End Method
+
+	Method LineAt:Int(index:Int)
+		Local _iter:Byte Ptr = bmx_gtk3_gtktextiter_new()
+		gtk_text_buffer_get_iter_at_offset(_textBuffer, _iter, index)
+		Local ret:Int = gtk_text_iter_get_line(_iter)
+		bmx_gtk3_gtktextiter_free(_iter)
+		Return ret
+	End Method
+
+	Method free:Int()
+		Super.Free()
+
+		If scrollWindow Then
+			gtk_widget_destroy(scrollWindow)
+		EndIf
+		handle = Null
+		scrollWindow = Null
+
+	End Method
+
+	Method Activate:Int(cmd:Int)
+		Super.Activate(cmd)
+
+		Select cmd
+			Case ACTIVATE_CUT
+				Local clipboard:Byte Ptr = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", True))
+				gtk_text_buffer_cut_clipboard(_textBuffer, clipboard, True)
+
+			Case ACTIVATE_COPY
+				Local clipboard:Byte Ptr = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", True))
+				gtk_text_buffer_copy_clipboard(_textBuffer, clipboard)
+
+			Case ACTIVATE_PASTE
+				Local clipboard:Byte Ptr = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", True))
+				gtk_text_buffer_paste_clipboard(_textBuffer, clipboard, Null, True)
+
+		End Select
+	End Method
+	
+	Rem
+	bbdoc: Enable to allow *fast* formatting.
+	about: When enabled, highlighting will not be removed before being applied, and since
+	tags are ordered, some highlight may not appear on top of others.
+	End Rem
+	Method setFastUpdate(bool:Int)
+		fastUpdate = bool
+	End Method
+	
+	Method Rethink:Int()
+		If handle Then
+			gtk_layout_move(TGTKContainer(parent).container, scrollWindow, Max(xpos, 0), Max(ypos, 0))
+			gtk_widget_set_size_request(scrollWindow, Max(width,0), Max(height,0))
+		End If
+	End Method
+
+End Type
+
+
+
+Rem
+bbdoc: A base type for html view gadgets.
+about: Implementations are in seperate modules.<br>
+See bah.gtkwebmozilla and bah.gtkwebgtkhtml mods.
+End Rem
+Type TGTKHTMLView Extends TGTKGadget
+	Function CreateHTMLView:TGTKHTMLView(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int) Abstract
+	
+	Method Stop() Abstract
+	Method SetText:Int(url:String) Abstract
+	Method GetText:String() Abstract
+
+End Type
+
+Type TGTKWebDriver
+	Function CreateHTMLView:TGTKHTMLView(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int) Abstract
+End Type
+
+Global gtk3maxgui_htmlview:TGTKWebDriver
+
+Rem
+bbdoc: A base type for text area gadgets.
+about: Implementations are in seperate modules, except for the default TGTKDefaultTextArea
+End Rem
+Type TGTKTextArea Extends TGTKEditable
+	Function CreateTextArea:TGTKTextArea(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int) Abstract
+
+End Type
+
+
+Type TGTKTextAreaDriver
+	Function CreateTextArea:TGTKTextArea(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int) Abstract
+End Type
+
+' default text area driver
+Type TGTKDefaultTextAreaDriver Extends TGTKTextAreaDriver
+	Function CreateTextArea:TGTKTextArea(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
+		Return TGTKDefaultTextArea.CreateTextArea(x, y, w, h, label, group, style)
+	End Function
+End Type
+
+Global gtk3maxgui_textarea:TGTKTextAreaDriver
+
+
+Extern
+	Function g_object_get_menudata:TGTKMenuItem(handle:Byte Ptr, name:Byte Ptr) = "g_object_get_data"
+End Extern

+ 785 - 785
gtk3maxgui.mod/gtkgui.bmx

@@ -1,785 +1,785 @@
-' Copyright (c) 2006-2018 Bruce A Henderson
-' 
-' Permission is hereby granted, free of charge, to any person obtaining a copy
-' of this software and associated documentation files (the "Software"), to deal
-' in the Software without restriction, including without limitation the rights
-' to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-' copies of the Software, and to permit persons to whom the Software is
-' furnished to do so, subject to the following conditions:
-' 
-' The above copyright notice and this permission notice shall be included in
-' all copies or substantial portions of the Software.
-' 
-' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-' THE SOFTWARE.
-' 
-SuperStrict
-
-Import "gtkcommon.bmx"
-Import "gtkgadget.bmx"
-?linux
-Import "fdhandler.c"
-?
-Import "gtkglue.c"
-Import "gdkevents.c"
-
-
-Global GTK3Driver:TGTK3GUIDriver =New TGTK3GUIDriver
-
-Type TGTK3GuiSystemDriver Extends TGTK3SystemDriver
-	Field	gui:TGTK3GUIDriver
-?linux
-	Field gsource:Byte Ptr
-?
-	
-	Method Poll()
-		While gtk_events_pending()
-			gtk_main_iteration_do(False)
-'			bbSystemPoll() ' dont't think we need this now?
-		Wend
-?Not linux
-		Super.Wait()
-?
-	End Method
-		
-	Method Wait()
-		gtk_main_iteration_do(True)
-	End Method
-			
-	Function Create:TGTK3GuiSystemDriver(host:TGTK3GUIDriver)
-		Local	guisystem:TGTK3GuiSystemDriver		
-		guisystem=New TGTK3GuiSystemDriver
-		guisystem.gui=host
-?linux
-		' attach max's fd to a glib event source so things like timers can work
-		guisystem.gsource = bmx_gtk_event_source_new(bbSystemAsyncFD())
-?
-		Return guisystem
-	End Function
-	
-End Type
-
-?bmxng
-Type TGTK3SystemDriver Extends TSystemDriver Implements IWrappedSystemDriver
-?Not bmxng
-Type TGTK3SystemDriver Extends TSystemDriver
-?
-	Field NativeDriver:TSystemDriver
-	
-	Field _desktop:TGTKDesktop
-
-?Not bmxng
-	Method New()
-		NativeDriver=brl.System.Driver
-	End Method
-?bmxng
-	Method SetDriver(driver:TSystemDriver)
-		NativeDriver = driver
-	End Method
-	
-	Method GetDriver:TSystemDriver()
-		Return NativeDriver
-	End Method
-	
-	Method Name:String()
-		Return "GTK3SystemDriver"
-	End Method
-?
-	Method Poll()
-		NativeDriver.Poll()
-	End Method
-		
-	Method Wait()
-		NativeDriver.Wait()
-	End Method
-	
-	Method Emit( osevent:Byte Ptr,source:Object )
-		Throw "oops"
-	End Method
-
-	Method IsFullScreen:Int()
-		Return False
-	End Method	
-
-	Method SetMouseVisible(bool:Int)
-		NativeDriver.SetMouseVisible bool
-	End Method
-
-	Method MoveMouse( x:Int, y:Int )
-		NativeDriver.MoveMouse x,y
-	End Method
-
-	Rem
-	internal: Notify user.
-	End Rem
-	Method Notify( text:String, serious:Int )
-		If text = Null Then
-			text = ""
-		End If
-		
-		serious = Max(0,Min(serious, 1))
-
-		Local textPtr:Byte Ptr = text.ToUTF8String()
-		Local req:Byte Ptr = gtk_message_dialog_new(Null, GTK_DIALOG_MODAL, serious, GTK_BUTTONS_OK, textPtr)
-		MemFree(textPtr)
-
-		Local res:Int = gtk_dialog_run(req)
-
-		gtk_widget_destroy(req)
-	End Method
-	
-	Rem
-	internal: Request user confirmation.
-	End Rem
-	Method Confirm:Int( text:String, serious:Int )
-		If text = Null Then
-			text = ""
-		End If
-		
-		serious = Max(0,Min(serious, 1))
-
-		Local textPtr:Byte Ptr = text.ToUTF8String()
-		Local req:Byte Ptr = gtk_message_dialog_new(Null, GTK_DIALOG_MODAL, serious, GTK_BUTTONS_YES_NO, textPtr)
-		MemFree(textPtr)
-
-		Local res:Int = gtk_dialog_run(req)
-
-		gtk_widget_destroy(req)
-
-		If res = GTK_RESPONSE_YES Then
-			Return True
-		Else
-			Return False
-		End If
-	End Method
-	
-	Rem
-	internal: Request user confirmation or cancellation.
-	End Rem
-	Method Proceed:Int( text:String, serious:Int )
-		If text = Null Then
-			text = ""
-		End If
-		
-		serious = Max(0,Min(serious, 1))
-		If Not serious Then
-			serious = GTK_MESSAGE_QUESTION
-		End If
-
-		Local textPtr:Byte Ptr = text.ToUTF8String()
-		Local req:Byte Ptr = gtk_message_dialog_new(Null, GTK_DIALOG_MODAL, serious, GTK_BUTTONS_YES_NO, textPtr)
-		MemFree(textPtr)
-
-		' add a cancel button
-		gtk_dialog_add_button(req, "_Cancel", GTK_RESPONSE_CANCEL)
-
-		Local res:Int = gtk_dialog_run(req)
-
-		gtk_widget_destroy(req)
-
-		Select res
-			Case GTK_RESPONSE_YES
-				Return True
-			Case GTK_RESPONSE_NO
-				Return False
-			Case GTK_RESPONSE_CANCEL
-				Return -1
-		End Select
-	End Method
-
-	Method RequestFile:String( text:String,exts:String, Save:Int,file:String )
-		Local req:Byte Ptr
-		Local f:String
-		Local opensave:Int
-		Local reqButton:String
-
-		If Save Then
-			opensave = GTK_FILE_CHOOSER_ACTION_SAVE
-			reqButton = "_Save"
-		Else
-			opensave = GTK_FILE_CHOOSER_ACTION_OPEN
-			reqButton = "_Open"
-		End If
-
-		If text = Null Or text.length = 0 Then
-			req = gtk_file_chooser_dialog_new(Null, Null, ..
-				opensave, "_Cancel", GTK_RESPONSE_CANCEL, ..
-				reqButton, GTK_RESPONSE_ACCEPT, Null)
-		Else
-			Local textPtr:Byte Ptr = text.ToUTF8String()
-			req = gtk_file_chooser_dialog_new(textPtr, Null, ..
-				opensave, "_Cancel", GTK_RESPONSE_CANCEL, ..
-				reqButton, GTK_RESPONSE_ACCEPT, Null)
-			MemFree(textPtr)
-		End If
-
-		Local Current:String = CurrentDir()
-		Local currentPtr:Byte Ptr = Current.ToUTF8String()
-		gtk_file_chooser_set_current_folder(req, currentPtr)
-		MemFree(currentPtr)
-
-		' set the path if there was one.
-		If file <> Null And file.length > 0 Then
-			If Not save And Not FileType(file) Then
-				file = ""
-			End If
-			Local filePtr:Byte Ptr = file.ToUTF8String()
-			gtk_file_chooser_set_filename(req, filePtr)
-			MemFree(filePtr)
-		End If
-
-		' set up filters, if any
-		'The optional extensions String can either be a comma separated list of file extensions
-		'or as in the following example groups of extensions that begin with a "group:" and separated
-		'by a semicolon.
-
-		If exts Then
-
-			Local groups:String[] = exts.Split(";")
-
-			For Local group:Int = 0 Until groups.length
-
-				If groups[group].length > 0 Then
-
-					Local pairs:String[] = groups[group].Split(":")
-	
-					Local name:String = Null
-					Local ex:String[]
-
-					If pairs.length = 1 Then
-						ex = pairs[0].Split(",")
-					Else
-						name = pairs[0]
-						ex = pairs[1].Split(",")
-					End If
-
-					' add a filter
-					Local filter:Byte Ptr = gtk_file_filter_new()
-					
-					If name <> Null Then
-						Local namePtr:Byte Ptr = name.ToUTF8String()
-						gtk_file_filter_set_name(filter, namePtr)
-						MemFree(namePtr)
-					End If
-
-					For Local i:Int = 0 Until ex.length
-						Local s:String = ex[i].Trim()
-
-						If s <> "*" Then
-							s = "*." + s
-						End If
-
-						Local sPtr:Byte Ptr = s.ToUTF8String()
-						gtk_file_filter_add_pattern(filter, sPtr)
-						MemFree(sPtr)
-
-					Next
-
-					gtk_file_chooser_add_filter(req, filter)
-					' we don't need to clean up the filter object, as gtk takes ownership of it when
-					' we add it to the chooser.
-
-				End If
-
-			Next
-
-		End If
-
-		Local res:Int = gtk_dialog_run(req)
-
-		If res = GTK_RESPONSE_ACCEPT Then
-			Local fptr:Byte Ptr = gtk_file_chooser_get_filename(req)
-			If fptr Then
-				f = String.FromUTF8String(fptr)
-				g_free(fptr)
-			End If
-		End If
-
-		gtk_widget_destroy(req)
-
-		Return f
-	End Method
-	
-	Method RequestDir:String( text:String, path:String )
-		Local p:String = Null
-		Local req:Byte Ptr
-
-		If text = Null Or text.length = 0 Then
-			req = gtk_file_chooser_dialog_new(Null, Null, ..
-				GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, "_Cancel", GTK_RESPONSE_CANCEL, ..
-				"_Open", GTK_RESPONSE_ACCEPT, Null)
-		Else
-			Local textPtr:Byte Ptr = text.ToUTF8String()
-			req = gtk_file_chooser_dialog_new(textPtr, Null, ..
-				GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, "_Cancel", GTK_RESPONSE_CANCEL, ..
-				"_Open", GTK_RESPONSE_ACCEPT, Null)
-			MemFree(textPtr)
-		End If
-
-		' set the path if there was one.
-		If path <> Null And path.length > 0 Then
-			' just in case the path is bad.. we'll set it to current
-			If Not FileType(path) Then
-				path = CurrentDir()
-			End If
-		Else
-			path = CurrentDir()
-		End If
-
-		Local pathPtr:Byte Ptr = path.ToUTF8String()
-		gtk_file_chooser_set_current_folder(req, pathPtr)
-		gtk_file_chooser_set_filename(req, pathPtr)
-		MemFree(pathPtr)
-
-
-		Local res:Int = gtk_dialog_run(req)
-
-		If res = GTK_RESPONSE_ACCEPT Then
-			Local f:Byte Ptr = gtk_file_chooser_get_filename(req)
-			If f Then
-				p = String.FromUTF8String(f)
-				g_free(f)
-			End If
-		End If
-
-		gtk_widget_destroy(req)
-
-		Return p
-	End Method
-
-	Method OpenURL:Int( url:String )
-		Return NativeDriver.OpenURL(url)
-	End Method
-
-	Method DesktopWidth:Int()
-		If Not _desktop Then
-			_desktop = TGTKDesktop.CreateDesktop()
-		End If
-		
-		Return _desktop.ClientWidth()
-	End Method
-	
-	Method DesktopHeight:Int()
-		If Not _desktop Then
-			_desktop = TGTKDesktop.CreateDesktop()
-		End If
-
-		Return _desktop.ClientHeight()
-	End Method
-
-	Method DesktopDepth:Int()
-		If Not _desktop Then
-			_desktop = TGTKDesktop.CreateDesktop()
-		End If
-		
-		Return _desktop.GetDepth()
-	End Method
-
-	Method DesktopHertz:Int()
-		If Not _desktop Then
-			_desktop = TGTKDesktop.CreateDesktop()
-		End If
-
-		Return _desktop.GetHertz()
-	End Method
-
-End Type
-
-
-Type TGTK3GUIDriver Extends TMaxGUIDriver
-
-	Method New()
-?bmxng
-		InitSystemDriver(TGTK3GuiSystemDriver.Create(Self))
-?Not bmxng
-		brl.System.Driver=TGTK3GuiSystemDriver.Create(Self)
-?
-		gtk_init(Null, Null)
-		maxgui_driver=Self
-	End Method
-
-	Method LoadFont:TGuiFont(name:String, size:Int, flags:Int)
-		Local font:TGuiFont = New TGTKGuiFont
-		font.name = name
-		font.size = size
-		font.style = flags
-		
-		Return DoLoadFont(font)
-	End Method
-	
-	Method DoLoadFont:TGuiFont(font:TGuiFont)
-		Local widget:Byte Ptr = gtk_label_new(Null)
-		Local _context:Byte Ptr = gtk_widget_get_pango_context(widget)
-
-		getPangoDescriptionFromGuiFont(TGtkGuiFont(font))
-		'Local fontdesc:Byte Ptr = font.fontDesc
-		Local _fontset:Byte Ptr = pango_context_load_fontset(_context, TGtkGuiFont(font).fontDesc, Null)
-
-		pango_fontset_foreach(_fontset, fontforeach, font)
-
-		'pango_font_description_free(fontdesc)
-
-		gtk_widget_destroy(widget)
-		g_object_unref(_context)
-
-		If font.path = "OK!" Then
-			font.path = ""
-			Return font
-		Else
-			Select font.name
-				Case "Lucida"
-					font.name = "DejaVu Sans Mono"
-					font = DoLoadFont(font)
-				Case "DejaVu Sans Mono"
-					font.name = "Droid Sans Mono"
-					font = DoLoadFont(font)
-				Case "Droid Sans Mono"
-					font.name = "FreeMono"
-					font = DoLoadFont(font)
-				Case "FreeMono"
-					Return Null
-				Default ' try a default...
-					font.name = "Lucida"
-					font = DoLoadFont(font)
-			End Select
-
-			If font Then
-				Return font
-			End If
-		
-			Return Null
-		End If
-	End Method
-
-	Method LibraryFont:TGuiFont( fontType:Int = GUIFONT_SYSTEM, size:Double = 0, style:Int = FONT_NORMAL )
-		If fontType = GUIFONT_SYSTEM Then
-			Local widget:Byte Ptr = gtk_label_new(Null)
-			Local defaultStyle:Byte Ptr = gtk_widget_get_style_context(widget)
-			Local font:Byte Ptr = bmx_gtk3_stylecontext_get_fontdesc(defaultStyle)
-			
-			Local f:TGuiFont = getGuiFontFromPangoDescription(font)
-			TGtkGuiFont(f).fontDesc = Null
-
-			gtk_widget_destroy(widget)
-
-			If size <= 0 Then
-				size = f.size
-			End If
-
-			Return LoadFontWithDouble( f.name, size, f.style | style )
-		Else
-			Return Super.LibraryFont( fontType, size, style )
-		EndIf
-	End Method
-
-	Method LoadFontWithDouble:TGuiFont(name:String, size:Double, flags:Int)
-		Local font:TGuiFont = New TGTKGuiFont
-		font.name = name
-		font.size = size
-		font.style = flags
-		
-		Return DoLoadFont(font)
-	End Method
-
-	Function fontforeach:Int(fontset:Byte Ptr, _font:Byte Ptr, data:Object)
-		Local fontdesc:Byte Ptr = pango_font_describe(_font)
-		Local thisfont:TGuiFont = getGuiFontFromPangoDescription(fontdesc)
-
-		If thisfont.name.toLower() = TGuiFont(data).name.tolower()  Then
-			TGuiFont(data).name = thisfont.name
-
-			TGuiFont(data).path = "OK!"
-			Return True
-		End If
-	End Function
-
-	Method CreateGadget:TGadget(GadgetClass:Int, name:String, x:Int, y:Int, w:Int, h:Int,group:TGadget, style:Int)
-		Local gadget:TGTKGadget
-		Local gtkclass:Int = -1
-		Local gtkGroup:TGTKGadget
-
-		Select GadgetClass
-			Case GADGET_DESKTOP
-				Return TGTKDesktop.CreateDesktop()
-			Case GADGET_WINDOW
-				gtkclass = GTK_WINDOW
-			Case GADGET_BUTTON
-				gtkclass = GTK_BUTTON
-				Select style
-					Case BUTTON_CHECKBOX,BUTTON_CHECKBOX|BUTTON_PUSH
-						gtkclass = GTK_CHECKBUTTON
-					Case BUTTON_RADIO,BUTTON_RADIO|BUTTON_PUSH
-						gtkclass = GTK_RADIOBUTTON
-					Case BUTTON_OK
-					Case BUTTON_CANCEL
-				End Select
-			Case GADGET_PANEL
-				gtkclass = GTK_PANEL
-			Case GADGET_TEXTFIELD
-				gtkclass = GTK_TEXTFIELD
-			Case GADGET_TEXTAREA
-				gtkclass = GTK_TEXTAREA
-			Case GADGET_COMBOBOX
-				gtkclass = GTK_COMBOBOX
-			Case GADGET_LISTBOX
-				gtkclass = GTK_LISTBOX
-			Case GADGET_TOOLBAR
-				gtkclass = GTK_TOOLBAR
-			Case GADGET_TABBER
-				gtkclass = GTK_TABBER
-			Case GADGET_TREEVIEW
-				gtkclass = GTK_TREEVIEW
-			Case GADGET_HTMLVIEW
-				gtkclass = GTK_HTMLVIEW
-			Case GADGET_LABEL
-				gtkclass = GTK_LABEL
-			Case GADGET_SLIDER
-				If style & SLIDER_STEPPER Then
-					gtkclass = GTK_STEPPER
-				Else If style & SLIDER_TRACKBAR Then
-					gtkclass = GTK_TRACKBAR
-				Else
-					gtkclass = GTK_SCROLLBAR
-				End If
-			Case GADGET_PROGBAR
-				gtkclass = GTK_PROGRESSBAR
-			Case GADGET_MENUITEM
-				gtkclass = GTK_MENUITEM
-Rem 
-			Case GADGET_CANVAS
-				gtkclass = GTK_CANVAS
-End Rem
-		End Select
-
-		gtkgroup = TGTKGadget(group)
-
-		If gtkclass > -1 Then
-			gadget = TGTKGadget.Create(gtkclass, x, y, w, h, name, gtkgroup, style, GadgetClass)
-		End If
-
-		Return gadget
-	End Method
-
-	Rem
-	internal: Returns the currently active gadget.
-	End Rem
-	Method ActiveGadget:TGadget()
-		For Local w:TGTKWindow = EachIn gtkWindows
-			' get the focussed widget for the window
-			Local widget:Byte Ptr = gtk_window_get_focus(w.handle)
-			
-			If widget Then ' we need a gadget to test!
-				' but is this window currently in focus (belonging to the toplevel window?)
-				If gtk_widget_has_focus(widget) Then
-					Return GadgetFromHandle(widget)
-				End If
-			End If
-		Next
-	End Method
-
-	Rem
-	internal: Pops up a color requester
-	End Rem
-	Method RequestColor:Int(r:Int, g:Int, b:Int)
-		Local argb:Int = Null
-
-		Local color:GdkRGBA = New GdkRGBA
-		color.red = r / 255.0
-		color.green = g / 255.0
-		color.blue = b / 255.0
-
-		Local req:Byte Ptr = gtk_color_selection_dialog_new("Select color")
-		Local colsel:Byte Ptr = gtk_color_selection_dialog_get_color_selection(req)
-		gtk_color_selection_set_current_rgba(colsel, color)
-
-		Local res:Int = gtk_dialog_run(req)
-
-		If res = GTK_RESPONSE_OK Then
-			gtk_color_selection_get_current_rgba(colsel, color)
-
-			argb = $ff000000 | (color.red * 255) Shl 16 | (color.green * 255) Shl 8  | (color.blue * 255) 
-		End If
-
-		gtk_widget_destroy(req)
-
-		Return argb
-	End Method
-
-	Rem
-	internal: Pops up a font requester.
-	End Rem
-	Method RequestFont:TGuiFont(font:TGuiFont)
-		Local req:Byte Ptr = gtk_font_chooser_dialog_new("Choose font", Null)
-		If font Then
-			getPangoDescriptionFromGuiFont(TGtkGuiFont(font))
-			gtk_font_chooser_set_font_desc(req, TGtkGuiFont(font).fontDesc)
-		End If
-
-		Local res:Int = gtk_dialog_run(req)
-
-		If res = GTK_RESPONSE_OK Then
-			' the requestor returns a Pango font description... so we need to 
-			Local fontdesc:Byte Ptr = gtk_font_chooser_get_font_desc(req)
-
-			font = getGuiFontFromPangoDescription(fontdesc)
-		End If
-
-		gtk_widget_destroy(req)
-
-		Return font
-	End Method
-
-	Method SetPointer:Int(shape:Int)
-		Local screen:Byte Ptr = gdk_screen_get_default()
-
-		Local cursorType:Int
-		Select shape
-			'Case POINTER_DEFAULT
-			'Case POINTER_ARROW
-			Case POINTER_IBEAM
-				cursorType = GDK_XTERM
-			Case POINTER_WAIT
-				cursorType = GDK_WATCH
-			Case POINTER_CROSS
-				cursorType = GDK_CROSSHAIR
-			Case POINTER_UPARROW
-				cursorType = GDK_CENTER_PTR
-			Case POINTER_SIZENWSE
-				cursorType = GDK_TOP_LEFT_CORNER
-			Case POINTER_SIZENESW
-				cursorType = GDK_TOP_RIGHT_CORNER
-			Case POINTER_SIZEWE
-				cursorType = GDK_SB_H_DOUBLE_ARROW
-			Case POINTER_SIZENS
-				cursorType = GDK_SB_V_DOUBLE_ARROW
-			Case POINTER_SIZEALL
-				cursorType = GDK_FLEUR
-			Case POINTER_NO
-				cursorType = GDK_PIRATE
-			Case POINTER_HAND
-				cursorType = GDK_HAND2
-			Case POINTER_APPSTARTING
-				cursorType = GDK_WATCH
-			Case POINTER_HELP
-				cursorType = GDK_QUESTION_ARROW
-			Default
-				cursorType = GDK_LEFT_PTR
-		End Select
-		
-		Local cursor:Byte Ptr = gdk_cursor_new_for_display(gdk_screen_get_display(screen), cursorType)
-		
-		For Local window:TGTKWindow = EachIn gtkWindows
-			If gtk_widget_get_window(window.handle) Then
-				gdk_window_set_cursor(gtk_widget_get_window(window.handle), cursor)
-			End If
-		Next
-	End Method
-
-	Method LoadIconStrip:TIconStrip(source:Object)
-		Return TGTKIconStrip.Create(source)
-	End Method
-
-	Method UserName$()
-	End Method
-	
-	Method ComputerName$()
-	End Method
-	
-	Rem
-	bbdoc: Sets the clipboard with the current text
-	End Rem
-	Method SetClipboardText(text:String)
-		Local clipboard:Byte Ptr = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", True))
-		
-		Local textPtr:Byte Ptr = text.ToUTF8String()
-		gtk_clipboard_set_text(clipboard, textPtr, -1)
-		MemFree(textPtr)
-	End Method
-	
-	Rem
-	bbdoc: Gets the text from the clipboard
-	End Rem
-	Method ClipboardText:String()
-		Local clipboard:Byte Ptr = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", True))
-		
-		Local txtPtr:Byte Ptr = gtk_clipboard_wait_for_text(clipboard)
-		Local s:String = String.FromUTF8String(txtPtr)
-		g_free(txtPtr)
-		Return s
-	End Method
-	
-End Type
-
-Function GadgetFromHandle:TGTKGadget( handle:Byte Ptr )
-	Return TGTKGadget( GadgetMap.ValueForKey( TGTKBytePtr.Set(handle) ) )
-End Function
-
-Rem
-bbdoc: Sets the tooltip text for the gadget.
-about: Note: Until BRL add gadget tooltip functionality, consider this function API volatile.
-<p>Parameters:
-<ul>
-<li><b>gadget</b> : the gadget to apply the tooltip</li>
-<li><b>tip</b> : the tooltip text or Null to clear</li>
-</ul>
-</p>
-End Rem
-'Function SetGadgetToolTip(gadget:TGadget, tip:String)
-'	TGTKGadget(gadget).setToolTip(tip)
-'End Function
-
-Rem
-bbdoc: Sets the application icon.
-about: Note: Until BRL add app icon functionality, consider this function API volatile.
-End Rem
-Function SetAppIcon(pix:TPixmap)
-'	If pix <> Null Then
-'		Local pixmap:TPixmap
-'		If pix.format <> PF_RGBA8888 Then
-'			pixmap = pix.convert( PF_RGBA8888 )
-'		Else
-'			pixmap = pix
-'		End If
-'
-'		Local icon:Byte Ptr = gdk_pixbuf_new_from_data(pixmap.pixels, GDK_COLORSPACE_RGB, True, 8, ..
-'					pixmap.width, pixmap.height, pixmap.Pitch, Null, Null)
-'		gtk_window_set_default_icon(icon)
-'	End If
-End Function
-
-Rem
-bbdoc: Sets the button image using the specified pixmap.
-about: Note: Until BRL add button image functionality, consider this function API volatile.
-End Rem
-Function SetButtonPixmap(gadget:TGadget, pixmap:TPixmap)
-'	If TGTKButtonPush(gadget) And pixmap Then
-'		TGTKButtonPush(gadget).setPixmap(pixmap)
-'	End If
-End Function
-
-Rem
-bbdoc: Returns pointer coordinates relative to window.
-End Rem
-Function GetWindowPointerPos(window:TGadget, x:Int Var, y:Int Var)
-	'If TGTKWindow(window) Then
-	'	gtk_widget_get_pointer(TGTKWindow(window).handle, x, y)
-	'End If
-End Function
-
-Rem
-bbdoc: Returns pointer coordinates relative to the screen.
-End Rem
-Function GetScreenPointerPos(x:Int Var, y:Int Var)
-'	gdk_display_get_pointer(gdk_display_get_default(), Null, x, y, Null)
-End Function
-
-?linux
-Extern
-	Function bmx_gtk_event_source_new:Byte Ptr(fd:Int)
-End Extern
-?
+' Copyright (c) 2006-2018 Bruce A Henderson
+' 
+' Permission is hereby granted, free of charge, to any person obtaining a copy
+' of this software and associated documentation files (the "Software"), to deal
+' in the Software without restriction, including without limitation the rights
+' to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+' copies of the Software, and to permit persons to whom the Software is
+' furnished to do so, subject to the following conditions:
+' 
+' The above copyright notice and this permission notice shall be included in
+' all copies or substantial portions of the Software.
+' 
+' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+' THE SOFTWARE.
+' 
+SuperStrict
+
+Import "gtkcommon.bmx"
+Import "gtkgadget.bmx"
+?linux
+Import "fdhandler.c"
+?
+Import "gtkglue.c"
+Import "gdkevents.c"
+
+
+Global GTK3Driver:TGTK3GUIDriver =New TGTK3GUIDriver
+
+Type TGTK3GuiSystemDriver Extends TGTK3SystemDriver
+	Field	gui:TGTK3GUIDriver
+?linux
+	Field gsource:Byte Ptr
+?
+	
+	Method Poll()
+		While gtk_events_pending()
+			gtk_main_iteration_do(False)
+'			bbSystemPoll() ' dont't think we need this now?
+		Wend
+?Not linux
+		Super.Wait()
+?
+	End Method
+		
+	Method Wait()
+		gtk_main_iteration_do(True)
+	End Method
+			
+	Function Create:TGTK3GuiSystemDriver(host:TGTK3GUIDriver)
+		Local	guisystem:TGTK3GuiSystemDriver		
+		guisystem=New TGTK3GuiSystemDriver
+		guisystem.gui=host
+?linux
+		' attach max's fd to a glib event source so things like timers can work
+		guisystem.gsource = bmx_gtk_event_source_new(bbSystemAsyncFD())
+?
+		Return guisystem
+	End Function
+	
+End Type
+
+?bmxng
+Type TGTK3SystemDriver Extends TSystemDriver Implements IWrappedSystemDriver
+?Not bmxng
+Type TGTK3SystemDriver Extends TSystemDriver
+?
+	Field NativeDriver:TSystemDriver
+	
+	Field _desktop:TGTKDesktop
+
+?Not bmxng
+	Method New()
+		NativeDriver=brl.System.Driver
+	End Method
+?bmxng
+	Method SetDriver(driver:TSystemDriver)
+		NativeDriver = driver
+	End Method
+	
+	Method GetDriver:TSystemDriver()
+		Return NativeDriver
+	End Method
+	
+	Method Name:String()
+		Return "GTK3SystemDriver"
+	End Method
+?
+	Method Poll()
+		NativeDriver.Poll()
+	End Method
+		
+	Method Wait()
+		NativeDriver.Wait()
+	End Method
+	
+	Method Emit( osevent:Byte Ptr,source:Object )
+		Throw "oops"
+	End Method
+
+	Method IsFullScreen:Int()
+		Return False
+	End Method	
+
+	Method SetMouseVisible(bool:Int)
+		NativeDriver.SetMouseVisible bool
+	End Method
+
+	Method MoveMouse( x:Int, y:Int )
+		NativeDriver.MoveMouse x,y
+	End Method
+
+	Rem
+	internal: Notify user.
+	End Rem
+	Method Notify( text:String, serious:Int )
+		If text = Null Then
+			text = ""
+		End If
+		
+		serious = Max(0,Min(serious, 1))
+
+		Local textPtr:Byte Ptr = text.ToUTF8String()
+		Local req:Byte Ptr = gtk_message_dialog_new(Null, GTK_DIALOG_MODAL, serious, GTK_BUTTONS_OK, textPtr)
+		MemFree(textPtr)
+
+		Local res:Int = gtk_dialog_run(req)
+
+		gtk_widget_destroy(req)
+	End Method
+	
+	Rem
+	internal: Request user confirmation.
+	End Rem
+	Method Confirm:Int( text:String, serious:Int )
+		If text = Null Then
+			text = ""
+		End If
+		
+		serious = Max(0,Min(serious, 1))
+
+		Local textPtr:Byte Ptr = text.ToUTF8String()
+		Local req:Byte Ptr = gtk_message_dialog_new(Null, GTK_DIALOG_MODAL, serious, GTK_BUTTONS_YES_NO, textPtr)
+		MemFree(textPtr)
+
+		Local res:Int = gtk_dialog_run(req)
+
+		gtk_widget_destroy(req)
+
+		If res = GTK_RESPONSE_YES Then
+			Return True
+		Else
+			Return False
+		End If
+	End Method
+	
+	Rem
+	internal: Request user confirmation or cancellation.
+	End Rem
+	Method Proceed:Int( text:String, serious:Int )
+		If text = Null Then
+			text = ""
+		End If
+		
+		serious = Max(0,Min(serious, 1))
+		If Not serious Then
+			serious = GTK_MESSAGE_QUESTION
+		End If
+
+		Local textPtr:Byte Ptr = text.ToUTF8String()
+		Local req:Byte Ptr = gtk_message_dialog_new(Null, GTK_DIALOG_MODAL, serious, GTK_BUTTONS_YES_NO, textPtr)
+		MemFree(textPtr)
+
+		' add a cancel button
+		gtk_dialog_add_button(req, "_Cancel", GTK_RESPONSE_CANCEL)
+
+		Local res:Int = gtk_dialog_run(req)
+
+		gtk_widget_destroy(req)
+
+		Select res
+			Case GTK_RESPONSE_YES
+				Return True
+			Case GTK_RESPONSE_NO
+				Return False
+			Case GTK_RESPONSE_CANCEL
+				Return -1
+		End Select
+	End Method
+
+	Method RequestFile:String( text:String,exts:String, Save:Int,file:String )
+		Local req:Byte Ptr
+		Local f:String
+		Local opensave:Int
+		Local reqButton:String
+
+		If Save Then
+			opensave = GTK_FILE_CHOOSER_ACTION_SAVE
+			reqButton = "_Save"
+		Else
+			opensave = GTK_FILE_CHOOSER_ACTION_OPEN
+			reqButton = "_Open"
+		End If
+
+		If text = Null Or text.length = 0 Then
+			req = gtk_file_chooser_dialog_new(Null, Null, ..
+				opensave, "_Cancel", GTK_RESPONSE_CANCEL, ..
+				reqButton, GTK_RESPONSE_ACCEPT, Null)
+		Else
+			Local textPtr:Byte Ptr = text.ToUTF8String()
+			req = gtk_file_chooser_dialog_new(textPtr, Null, ..
+				opensave, "_Cancel", GTK_RESPONSE_CANCEL, ..
+				reqButton, GTK_RESPONSE_ACCEPT, Null)
+			MemFree(textPtr)
+		End If
+
+		Local Current:String = CurrentDir()
+		Local currentPtr:Byte Ptr = Current.ToUTF8String()
+		gtk_file_chooser_set_current_folder(req, currentPtr)
+		MemFree(currentPtr)
+
+		' set the path if there was one.
+		If file <> Null And file.length > 0 Then
+			If Not save And Not FileType(file) Then
+				file = ""
+			End If
+			Local filePtr:Byte Ptr = file.ToUTF8String()
+			gtk_file_chooser_set_filename(req, filePtr)
+			MemFree(filePtr)
+		End If
+
+		' set up filters, if any
+		'The optional extensions String can either be a comma separated list of file extensions
+		'or as in the following example groups of extensions that begin with a "group:" and separated
+		'by a semicolon.
+
+		If exts Then
+
+			Local groups:String[] = exts.Split(";")
+
+			For Local group:Int = 0 Until groups.length
+
+				If groups[group].length > 0 Then
+
+					Local pairs:String[] = groups[group].Split(":")
+	
+					Local name:String = Null
+					Local ex:String[]
+
+					If pairs.length = 1 Then
+						ex = pairs[0].Split(",")
+					Else
+						name = pairs[0]
+						ex = pairs[1].Split(",")
+					End If
+
+					' add a filter
+					Local filter:Byte Ptr = gtk_file_filter_new()
+					
+					If name <> Null Then
+						Local namePtr:Byte Ptr = name.ToUTF8String()
+						gtk_file_filter_set_name(filter, namePtr)
+						MemFree(namePtr)
+					End If
+
+					For Local i:Int = 0 Until ex.length
+						Local s:String = ex[i].Trim()
+
+						If s <> "*" Then
+							s = "*." + s
+						End If
+
+						Local sPtr:Byte Ptr = s.ToUTF8String()
+						gtk_file_filter_add_pattern(filter, sPtr)
+						MemFree(sPtr)
+
+					Next
+
+					gtk_file_chooser_add_filter(req, filter)
+					' we don't need to clean up the filter object, as gtk takes ownership of it when
+					' we add it to the chooser.
+
+				End If
+
+			Next
+
+		End If
+
+		Local res:Int = gtk_dialog_run(req)
+
+		If res = GTK_RESPONSE_ACCEPT Then
+			Local fptr:Byte Ptr = gtk_file_chooser_get_filename(req)
+			If fptr Then
+				f = String.FromUTF8String(fptr)
+				g_free(fptr)
+			End If
+		End If
+
+		gtk_widget_destroy(req)
+
+		Return f
+	End Method
+	
+	Method RequestDir:String( text:String, path:String )
+		Local p:String = Null
+		Local req:Byte Ptr
+
+		If text = Null Or text.length = 0 Then
+			req = gtk_file_chooser_dialog_new(Null, Null, ..
+				GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, "_Cancel", GTK_RESPONSE_CANCEL, ..
+				"_Open", GTK_RESPONSE_ACCEPT, Null)
+		Else
+			Local textPtr:Byte Ptr = text.ToUTF8String()
+			req = gtk_file_chooser_dialog_new(textPtr, Null, ..
+				GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, "_Cancel", GTK_RESPONSE_CANCEL, ..
+				"_Open", GTK_RESPONSE_ACCEPT, Null)
+			MemFree(textPtr)
+		End If
+
+		' set the path if there was one.
+		If path <> Null And path.length > 0 Then
+			' just in case the path is bad.. we'll set it to current
+			If Not FileType(path) Then
+				path = CurrentDir()
+			End If
+		Else
+			path = CurrentDir()
+		End If
+
+		Local pathPtr:Byte Ptr = path.ToUTF8String()
+		gtk_file_chooser_set_current_folder(req, pathPtr)
+		gtk_file_chooser_set_filename(req, pathPtr)
+		MemFree(pathPtr)
+
+
+		Local res:Int = gtk_dialog_run(req)
+
+		If res = GTK_RESPONSE_ACCEPT Then
+			Local f:Byte Ptr = gtk_file_chooser_get_filename(req)
+			If f Then
+				p = String.FromUTF8String(f)
+				g_free(f)
+			End If
+		End If
+
+		gtk_widget_destroy(req)
+
+		Return p
+	End Method
+
+	Method OpenURL:Int( url:String )
+		Return NativeDriver.OpenURL(url)
+	End Method
+
+	Method DesktopWidth:Int()
+		If Not _desktop Then
+			_desktop = TGTKDesktop.CreateDesktop()
+		End If
+		
+		Return _desktop.ClientWidth()
+	End Method
+	
+	Method DesktopHeight:Int()
+		If Not _desktop Then
+			_desktop = TGTKDesktop.CreateDesktop()
+		End If
+
+		Return _desktop.ClientHeight()
+	End Method
+
+	Method DesktopDepth:Int()
+		If Not _desktop Then
+			_desktop = TGTKDesktop.CreateDesktop()
+		End If
+		
+		Return _desktop.GetDepth()
+	End Method
+
+	Method DesktopHertz:Int()
+		If Not _desktop Then
+			_desktop = TGTKDesktop.CreateDesktop()
+		End If
+
+		Return _desktop.GetHertz()
+	End Method
+
+End Type
+
+
+Type TGTK3GUIDriver Extends TMaxGUIDriver
+
+	Method New()
+?bmxng
+		InitSystemDriver(TGTK3GuiSystemDriver.Create(Self))
+?Not bmxng
+		brl.System.Driver=TGTK3GuiSystemDriver.Create(Self)
+?
+		gtk_init(Null, Null)
+		maxgui_driver=Self
+	End Method
+
+	Method LoadFont:TGuiFont(name:String, size:Int, flags:Int)
+		Local font:TGuiFont = New TGTKGuiFont
+		font.name = name
+		font.size = size
+		font.style = flags
+		
+		Return DoLoadFont(font)
+	End Method
+	
+	Method DoLoadFont:TGuiFont(font:TGuiFont)
+		Local widget:Byte Ptr = gtk_label_new(Null)
+		Local _context:Byte Ptr = gtk_widget_get_pango_context(widget)
+
+		getPangoDescriptionFromGuiFont(TGtkGuiFont(font))
+		'Local fontdesc:Byte Ptr = font.fontDesc
+		Local _fontset:Byte Ptr = pango_context_load_fontset(_context, TGtkGuiFont(font).fontDesc, Null)
+
+		pango_fontset_foreach(_fontset, fontforeach, font)
+
+		'pango_font_description_free(fontdesc)
+
+		gtk_widget_destroy(widget)
+		g_object_unref(_context)
+
+		If font.path = "OK!" Then
+			font.path = ""
+			Return font
+		Else
+			Select font.name
+				Case "Lucida"
+					font.name = "DejaVu Sans Mono"
+					font = DoLoadFont(font)
+				Case "DejaVu Sans Mono"
+					font.name = "Droid Sans Mono"
+					font = DoLoadFont(font)
+				Case "Droid Sans Mono"
+					font.name = "FreeMono"
+					font = DoLoadFont(font)
+				Case "FreeMono"
+					Return Null
+				Default ' try a default...
+					font.name = "Lucida"
+					font = DoLoadFont(font)
+			End Select
+
+			If font Then
+				Return font
+			End If
+		
+			Return Null
+		End If
+	End Method
+
+	Method LibraryFont:TGuiFont( fontType:Int = GUIFONT_SYSTEM, size:Double = 0, style:Int = FONT_NORMAL )
+		If fontType = GUIFONT_SYSTEM Then
+			Local widget:Byte Ptr = gtk_label_new(Null)
+			Local defaultStyle:Byte Ptr = gtk_widget_get_style_context(widget)
+			Local font:Byte Ptr = bmx_gtk3_stylecontext_get_fontdesc(defaultStyle)
+			
+			Local f:TGuiFont = getGuiFontFromPangoDescription(font)
+			TGtkGuiFont(f).fontDesc = Null
+
+			gtk_widget_destroy(widget)
+
+			If size <= 0 Then
+				size = f.size
+			End If
+
+			Return LoadFontWithDouble( f.name, size, f.style | style )
+		Else
+			Return Super.LibraryFont( fontType, size, style )
+		EndIf
+	End Method
+
+	Method LoadFontWithDouble:TGuiFont(name:String, size:Double, flags:Int)
+		Local font:TGuiFont = New TGTKGuiFont
+		font.name = name
+		font.size = size
+		font.style = flags
+		
+		Return DoLoadFont(font)
+	End Method
+
+	Function fontforeach:Int(fontset:Byte Ptr, _font:Byte Ptr, data:Object)
+		Local fontdesc:Byte Ptr = pango_font_describe(_font)
+		Local thisfont:TGuiFont = getGuiFontFromPangoDescription(fontdesc)
+
+		If thisfont.name.toLower() = TGuiFont(data).name.tolower()  Then
+			TGuiFont(data).name = thisfont.name
+
+			TGuiFont(data).path = "OK!"
+			Return True
+		End If
+	End Function
+
+	Method CreateGadget:TGadget(GadgetClass:Int, name:String, x:Int, y:Int, w:Int, h:Int,group:TGadget, style:Int)
+		Local gadget:TGTKGadget
+		Local gtkclass:Int = -1
+		Local gtkGroup:TGTKGadget
+
+		Select GadgetClass
+			Case GADGET_DESKTOP
+				Return TGTKDesktop.CreateDesktop()
+			Case GADGET_WINDOW
+				gtkclass = GTK_WINDOW
+			Case GADGET_BUTTON
+				gtkclass = GTK_BUTTON
+				Select style
+					Case BUTTON_CHECKBOX,BUTTON_CHECKBOX|BUTTON_PUSH
+						gtkclass = GTK_CHECKBUTTON
+					Case BUTTON_RADIO,BUTTON_RADIO|BUTTON_PUSH
+						gtkclass = GTK_RADIOBUTTON
+					Case BUTTON_OK
+					Case BUTTON_CANCEL
+				End Select
+			Case GADGET_PANEL
+				gtkclass = GTK_PANEL
+			Case GADGET_TEXTFIELD
+				gtkclass = GTK_TEXTFIELD
+			Case GADGET_TEXTAREA
+				gtkclass = GTK_TEXTAREA
+			Case GADGET_COMBOBOX
+				gtkclass = GTK_COMBOBOX
+			Case GADGET_LISTBOX
+				gtkclass = GTK_LISTBOX
+			Case GADGET_TOOLBAR
+				gtkclass = GTK_TOOLBAR
+			Case GADGET_TABBER
+				gtkclass = GTK_TABBER
+			Case GADGET_TREEVIEW
+				gtkclass = GTK_TREEVIEW
+			Case GADGET_HTMLVIEW
+				gtkclass = GTK_HTMLVIEW
+			Case GADGET_LABEL
+				gtkclass = GTK_LABEL
+			Case GADGET_SLIDER
+				If style & SLIDER_STEPPER Then
+					gtkclass = GTK_STEPPER
+				Else If style & SLIDER_TRACKBAR Then
+					gtkclass = GTK_TRACKBAR
+				Else
+					gtkclass = GTK_SCROLLBAR
+				End If
+			Case GADGET_PROGBAR
+				gtkclass = GTK_PROGRESSBAR
+			Case GADGET_MENUITEM
+				gtkclass = GTK_MENUITEM
+Rem 
+			Case GADGET_CANVAS
+				gtkclass = GTK_CANVAS
+End Rem
+		End Select
+
+		gtkgroup = TGTKGadget(group)
+
+		If gtkclass > -1 Then
+			gadget = TGTKGadget.Create(gtkclass, x, y, w, h, name, gtkgroup, style, GadgetClass)
+		End If
+
+		Return gadget
+	End Method
+
+	Rem
+	internal: Returns the currently active gadget.
+	End Rem
+	Method ActiveGadget:TGadget()
+		For Local w:TGTKWindow = EachIn gtkWindows
+			' get the focussed widget for the window
+			Local widget:Byte Ptr = gtk_window_get_focus(w.handle)
+			
+			If widget Then ' we need a gadget to test!
+				' but is this window currently in focus (belonging to the toplevel window?)
+				If gtk_widget_has_focus(widget) Then
+					Return GadgetFromHandle(widget)
+				End If
+			End If
+		Next
+	End Method
+
+	Rem
+	internal: Pops up a color requester
+	End Rem
+	Method RequestColor:Int(r:Int, g:Int, b:Int)
+		Local argb:Int = Null
+
+		Local color:GdkRGBA = New GdkRGBA
+		color.red = r / 255.0
+		color.green = g / 255.0
+		color.blue = b / 255.0
+
+		Local req:Byte Ptr = gtk_color_selection_dialog_new("Select color")
+		Local colsel:Byte Ptr = gtk_color_selection_dialog_get_color_selection(req)
+		gtk_color_selection_set_current_rgba(colsel, color)
+
+		Local res:Int = gtk_dialog_run(req)
+
+		If res = GTK_RESPONSE_OK Then
+			gtk_color_selection_get_current_rgba(colsel, color)
+
+			argb = $ff000000 | (color.red * 255) Shl 16 | (color.green * 255) Shl 8  | (color.blue * 255) 
+		End If
+
+		gtk_widget_destroy(req)
+
+		Return argb
+	End Method
+
+	Rem
+	internal: Pops up a font requester.
+	End Rem
+	Method RequestFont:TGuiFont(font:TGuiFont)
+		Local req:Byte Ptr = gtk_font_chooser_dialog_new("Choose font", Null)
+		If font Then
+			getPangoDescriptionFromGuiFont(TGtkGuiFont(font))
+			gtk_font_chooser_set_font_desc(req, TGtkGuiFont(font).fontDesc)
+		End If
+
+		Local res:Int = gtk_dialog_run(req)
+
+		If res = GTK_RESPONSE_OK Then
+			' the requestor returns a Pango font description... so we need to 
+			Local fontdesc:Byte Ptr = gtk_font_chooser_get_font_desc(req)
+
+			font = getGuiFontFromPangoDescription(fontdesc)
+		End If
+
+		gtk_widget_destroy(req)
+
+		Return font
+	End Method
+
+	Method SetPointer:Int(shape:Int)
+		Local screen:Byte Ptr = gdk_screen_get_default()
+
+		Local cursorType:Int
+		Select shape
+			'Case POINTER_DEFAULT
+			'Case POINTER_ARROW
+			Case POINTER_IBEAM
+				cursorType = GDK_XTERM
+			Case POINTER_WAIT
+				cursorType = GDK_WATCH
+			Case POINTER_CROSS
+				cursorType = GDK_CROSSHAIR
+			Case POINTER_UPARROW
+				cursorType = GDK_CENTER_PTR
+			Case POINTER_SIZENWSE
+				cursorType = GDK_TOP_LEFT_CORNER
+			Case POINTER_SIZENESW
+				cursorType = GDK_TOP_RIGHT_CORNER
+			Case POINTER_SIZEWE
+				cursorType = GDK_SB_H_DOUBLE_ARROW
+			Case POINTER_SIZENS
+				cursorType = GDK_SB_V_DOUBLE_ARROW
+			Case POINTER_SIZEALL
+				cursorType = GDK_FLEUR
+			Case POINTER_NO
+				cursorType = GDK_PIRATE
+			Case POINTER_HAND
+				cursorType = GDK_HAND2
+			Case POINTER_APPSTARTING
+				cursorType = GDK_WATCH
+			Case POINTER_HELP
+				cursorType = GDK_QUESTION_ARROW
+			Default
+				cursorType = GDK_LEFT_PTR
+		End Select
+		
+		Local cursor:Byte Ptr = gdk_cursor_new_for_display(gdk_screen_get_display(screen), cursorType)
+		
+		For Local window:TGTKWindow = EachIn gtkWindows
+			If gtk_widget_get_window(window.handle) Then
+				gdk_window_set_cursor(gtk_widget_get_window(window.handle), cursor)
+			End If
+		Next
+	End Method
+
+	Method LoadIconStrip:TIconStrip(source:Object)
+		Return TGTKIconStrip.Create(source)
+	End Method
+
+	Method UserName$()
+	End Method
+	
+	Method ComputerName$()
+	End Method
+	
+	Rem
+	bbdoc: Sets the clipboard with the current text
+	End Rem
+	Method SetClipboardText(text:String)
+		Local clipboard:Byte Ptr = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", True))
+		
+		Local textPtr:Byte Ptr = text.ToUTF8String()
+		gtk_clipboard_set_text(clipboard, textPtr, -1)
+		MemFree(textPtr)
+	End Method
+	
+	Rem
+	bbdoc: Gets the text from the clipboard
+	End Rem
+	Method ClipboardText:String()
+		Local clipboard:Byte Ptr = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", True))
+		
+		Local txtPtr:Byte Ptr = gtk_clipboard_wait_for_text(clipboard)
+		Local s:String = String.FromUTF8String(txtPtr)
+		g_free(txtPtr)
+		Return s
+	End Method
+	
+End Type
+
+Function GadgetFromHandle:TGTKGadget( handle:Byte Ptr )
+	Return TGTKGadget( GadgetMap.ValueForKey( handle ) )
+End Function
+
+Rem
+bbdoc: Sets the tooltip text for the gadget.
+about: Note: Until BRL add gadget tooltip functionality, consider this function API volatile.
+<p>Parameters:
+<ul>
+<li><b>gadget</b> : the gadget to apply the tooltip</li>
+<li><b>tip</b> : the tooltip text or Null to clear</li>
+</ul>
+</p>
+End Rem
+'Function SetGadgetToolTip(gadget:TGadget, tip:String)
+'	TGTKGadget(gadget).setToolTip(tip)
+'End Function
+
+Rem
+bbdoc: Sets the application icon.
+about: Note: Until BRL add app icon functionality, consider this function API volatile.
+End Rem
+Function SetAppIcon(pix:TPixmap)
+'	If pix <> Null Then
+'		Local pixmap:TPixmap
+'		If pix.format <> PF_RGBA8888 Then
+'			pixmap = pix.convert( PF_RGBA8888 )
+'		Else
+'			pixmap = pix
+'		End If
+'
+'		Local icon:Byte Ptr = gdk_pixbuf_new_from_data(pixmap.pixels, GDK_COLORSPACE_RGB, True, 8, ..
+'					pixmap.width, pixmap.height, pixmap.Pitch, Null, Null)
+'		gtk_window_set_default_icon(icon)
+'	End If
+End Function
+
+Rem
+bbdoc: Sets the button image using the specified pixmap.
+about: Note: Until BRL add button image functionality, consider this function API volatile.
+End Rem
+Function SetButtonPixmap(gadget:TGadget, pixmap:TPixmap)
+'	If TGTKButtonPush(gadget) And pixmap Then
+'		TGTKButtonPush(gadget).setPixmap(pixmap)
+'	End If
+End Function
+
+Rem
+bbdoc: Returns pointer coordinates relative to window.
+End Rem
+Function GetWindowPointerPos(window:TGadget, x:Int Var, y:Int Var)
+	'If TGTKWindow(window) Then
+	'	gtk_widget_get_pointer(TGTKWindow(window).handle, x, y)
+	'End If
+End Function
+
+Rem
+bbdoc: Returns pointer coordinates relative to the screen.
+End Rem
+Function GetScreenPointerPos(x:Int Var, y:Int Var)
+'	gdk_display_get_pointer(gdk_display_get_default(), Null, x, y, Null)
+End Function
+
+?linux
+Extern
+	Function bmx_gtk_event_source_new:Byte Ptr(fd:Int)
+End Extern
+?