Mercurial > projects > dwt-linux
changeset 67:15b21862b0ac
List
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Mon, 14 Jan 2008 02:04:54 +0100 |
parents | bb2217c09e61 |
children | 8b1ef6cd4450 |
files | doc-callbacks.txt dwt/internal/gtk/OS.d dwt/widgets/Display.d dwt/widgets/List.d dwt/widgets/Spinner.d dwt/widgets/Widget.d |
diffstat | 6 files changed, 1628 insertions(+), 14 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc-callbacks.txt Mon Jan 14 02:04:54 2008 +0100 @@ -0,0 +1,26 @@ +Callbacks gtk-Java and gtk-D +============================ + + +SWT uses a Mechanism to make callback possible from C -> Java. This mechanism is +implemented in swt/internal/Callback.java and the C libs. It can convert a delegate call +into a simple function pointer. + +This works by generating a whole lot of function wrappers. All with int argument types, +varying in argument count. The Callback class implements a registry for the available +functions and redirect the C call to Java using reflection. + +In the D port, dwt.widgets.Display has the struct CallbackData. It wraps the instance pointer +to the display instance. If a callback uses other userdata, it is wrapped also into the +struct. + +Caution by g_signal_handlers_[un]block_matches: In Java sometime integer constants are passed +to select a callback for enabling/disabling. In D, the Widget class has getter function to get +a pointer to the CallbackData that was used instead of the integer when registering the +callback. + + + + + +
--- a/dwt/internal/gtk/OS.d Sun Jan 13 23:50:55 2008 +0100 +++ b/dwt/internal/gtk/OS.d Mon Jan 14 02:04:54 2008 +0100 @@ -155,6 +155,14 @@ public alias dwt.internal.c.gtk.GtkRange GtkRange; public alias dwt.internal.c.gtk.GtkSpinButton GtkSpinButton; public alias dwt.internal.c.gtk.GtkFrame GtkFrame; +public alias dwt.internal.c.gtk.GtkTreeIter GtkTreeIter; +public alias dwt.internal.c.gtk.GtkTreeStore GtkTreeStore; +public alias dwt.internal.c.gtk.GtkListStore GtkListStore; +public alias dwt.internal.c.gtk.GtkTreeViewColumn GtkTreeViewColumn; +public alias dwt.internal.c.gtk.GtkTreeView GtkTreeView; +public alias dwt.internal.c.gtk.GtkTreePath GtkTreePath; +public alias dwt.internal.c.gtk.GtkTreeSelection GtkTreeSelection; +public alias dwt.internal.c.gtk.GtkTreeModel GtkTreeModel; public alias dwt.internal.c.Xlib.XErrorEvent XErrorEvent; public alias dwt.internal.c.Xlib.XExposeEvent XExposeEvent; @@ -198,6 +206,14 @@ g_signal_emit_by_name( instance, detailed_signal, value1, value2, value3 ); } +private void gtk_list_store_set1(GtkListStore * store , GtkTreeIter * iter, int column, void* value ){ + gtk_list_store_set( store, iter, column, value, -1 ); +} + +private void gtk_tree_model_get1(GtkTreeModel * store , GtkTreeIter * iter, int column, void** value ){ + gtk_tree_model_get( store, iter, column, value, -1 ); +} + // for linux always true, the other possibility would be GDK_WINDOWING_WIN32 private bool GDK_WINDOWING_X11(){ return true; @@ -211,7 +227,6 @@ int g_signal_connect( void* instance, char* sig, GCallback handle, void* ptr ){ return g_signal_connect_data( instance, sig, handle, ptr, cast(GClosureNotify) 0, cast(GConnectFlags)0 ); } - // macro void gdk_cursor_destroy( GdkCursor* cursor ){ gdk_cursor_unref(cursor); @@ -1332,11 +1347,7 @@ mixin ForwardGtkOsCFunc!(.gtk_list_store_insert); mixin ForwardGtkOsCFunc!(.gtk_list_store_newv); mixin ForwardGtkOsCFunc!(.gtk_list_store_remove); - mixin ForwardGtkOsCFunc!(.gtk_list_store_set); - mixin ForwardGtkOsCFunc!(.gtk_list_store_set); - mixin ForwardGtkOsCFunc!(.gtk_list_store_set); - mixin ForwardGtkOsCFunc!(.gtk_list_store_set); - mixin ForwardGtkOsCFunc!(.gtk_list_store_set); + mixin ForwardGtkOsCFunc!(.gtk_list_store_set1); mixin ForwardGtkOsCFunc!(.gtk_main); mixin ForwardGtkOsCFunc!(.gtk_main_iteration); mixin ForwardGtkOsCFunc!(.gtk_main_do_event); @@ -1572,8 +1583,7 @@ mixin ForwardGtkOsCFunc!(.gtk_tooltips_new); mixin ForwardGtkOsCFunc!(.gtk_tooltips_force_window); mixin ForwardGtkOsCFunc!(.gtk_tooltips_set_tip); - mixin ForwardGtkOsCFunc!(.gtk_tree_model_get); - mixin ForwardGtkOsCFunc!(.gtk_tree_model_get); + mixin ForwardGtkOsCFunc!(.gtk_tree_model_get1); mixin ForwardGtkOsCFunc!(.gtk_tree_model_get_iter); mixin ForwardGtkOsCFunc!(.gtk_tree_model_get_iter_first); mixin ForwardGtkOsCFunc!(.gtk_tree_model_get_n_columns); @@ -1592,7 +1602,6 @@ mixin ForwardGtkOsCFunc!(.gtk_tree_path_new); mixin ForwardGtkOsCFunc!(.gtk_tree_path_new_first); mixin ForwardGtkOsCFunc!(.gtk_tree_path_new_from_string); - mixin ForwardGtkOsCFunc!(.gtk_tree_path_new_from_string); mixin ForwardGtkOsCFunc!(.gtk_tree_path_next); mixin ForwardGtkOsCFunc!(.gtk_tree_path_prev); mixin ForwardGtkOsCFunc!(.gtk_tree_path_up);
--- a/dwt/widgets/Display.d Sun Jan 13 23:50:55 2008 +0100 +++ b/dwt/widgets/Display.d Mon Jan 14 02:04:54 2008 +0100 @@ -3783,10 +3783,22 @@ return widget.sizeRequestProc (handle, arg0, user_data); } -int /*long*/ treeSelectionProcMeth (int /*long*/ model, int /*long*/ path, int /*long*/ iter, int /*long*/ data) { +package void doTreeSelectionProcConnect( CallbackData* cbdata, GtkWidget* widget, GtkTreeSelection* selection ){ + cbdata.display = this; + cbdata.data = cast(void*)widget; + OS.gtk_tree_selection_selected_foreach (selection, &treeSelectionProcFunc, widget); +} + +private static extern(C) void treeSelectionProcFunc (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, void* data) { + version(LOG) Stderr.formatln( "Display {}:", __LINE__ ).flush; + auto cbdata = cast(CallbackData*)data; + cbdata.display.treeSelectionProcMeth( model, path, iter, cbdata.data ); +} + +void treeSelectionProcMeth (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, void* data) { Widget widget = getWidget (cast(GtkWidget*)data); if (widget is null) return 0; - return widget.treeSelectionProc (model, path, iter, treeSelection, treeSelectionLength++); + widget.treeSelectionProc (model, path, iter, treeSelection, treeSelectionLength++); } void saveResources () {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/widgets/List.d Mon Jan 14 02:04:54 2008 +0100 @@ -0,0 +1,1567 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +module dwt.widgets.List; + + +import dwt.SWT; +import dwt.internal.gtk.OS; +import dwt.graphics.Point; +import dwt.graphics.Rectangle; +import dwt.events.SelectionListener; +import dwt.events.SelectionEvent; +import dwt.widgets.Scrollable; +import dwt.widgets.Composite; +import dwt.widgets.TypedListener; +import dwt.widgets.Display; + +import Math = tango.math.Math; +import tango.stdc.stringz; +import tango.text.convert.Integer; + +/** + * Instances of this class represent a selectable user interface + * object that displays a list of strings and issues notification + * when a string is selected. A list may be single or multi select. + * <p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>SINGLE, MULTI</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection, DefaultSelection</dd> + * </dl> + * <p> + * Note: Only one of SINGLE and MULTI may be specified. + * </p><p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + */ +public class List : Scrollable { + GtkWidget* modelHandle; + + static final int TEXT_COLUMN = 0; + CallbackData treeSelectionProcCallbackData; + +/** + * Constructs a new instance of this class given its parent + * and a style value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in + * class <code>SWT</code> which is applicable to instances of this + * class, or must be built by <em>bitwise OR</em>'ing together + * (that is, using the <code>int</code> "|" operator) two or more + * of those <code>SWT</code> style constants. The class description + * lists the style constants that are applicable to the class. + * Style bits are also inherited from superclasses. + * </p> + * + * @param parent a composite control which will be the parent of the new instance (cannot be null) + * @param style the style of control to construct + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> + * </ul> + * + * @see SWT#SINGLE + * @see SWT#MULTI + * @see Widget#checkSubclass + * @see Widget#getStyle + */ +public this (Composite parent, int style) { + super (parent, checkStyle (style)); +} + +/** + * Adds the argument to the end of the receiver's list. + * + * @param string the new item + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see #add(String,int) + */ +public void add (char[] string) { + checkWidget(); + if (string is null) error (SWT.ERROR_NULL_ARGUMENT); + char* buffer = toStringz(string); + GtkTreeIter iter; + OS.gtk_list_store_append (cast(GtkListStore*)modelHandle, &iter); + OS.gtk_list_store_set1 (cast(GtkListStore*)modelHandle, &iter, TEXT_COLUMN, buffer); +} + +/** + * Adds the argument to the receiver's list at the given + * zero-relative index. + * <p> + * Note: To add an item at the end of the list, use the + * result of calling <code>getItemCount()</code> as the + * index or use <code>add(String)</code>. + * </p> + * + * @param string the new item + * @param index the index for the item + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list (inclusive)</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see #add(String) + */ +public void add (char[] string, int index) { + checkWidget(); + if (string is null) error (SWT.ERROR_NULL_ARGUMENT); + int count = OS.gtk_tree_model_iter_n_children (cast(GtkTreeStore*)modelHandle, null); + if (!(0 <= index && index <= count)) { + error (SWT.ERROR_INVALID_RANGE); + } + char* buffer = toStringz(string); + GtkTreeIter iter; + /* + * Feature in GTK. It is much faster to append to a list store + * than to insert at the end using gtk_list_store_insert(). + */ + if (index is count) { + OS.gtk_list_store_append (cast(GtkListStore*)modelHandle, &iter); + } else { + OS.gtk_list_store_insert (cast(GtkListStore*)modelHandle, &iter, index); + } + OS.gtk_list_store_set1 (cast(GtkListStore*)modelHandle, &iter, TEXT_COLUMN, buffer); +} + +/** + * Adds the listener to the collection of listeners who will + * be notified when the user changes the receiver's selection, by sending + * it one of the messages defined in the <code>SelectionListener</code> + * interface. + * <p> + * <code>widgetSelected</code> is called when the selection changes. + * <code>widgetDefaultSelected</code> is typically called when an item is double-clicked. + * </p> + * + * @param listener the listener which should be notified when the user changes the receiver's selection + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ +public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener is null) error (SWT.ERROR_NULL_ARGUMENT); + TypedListener typedListener = new TypedListener (listener); + addListener (SWT.Selection,typedListener); + addListener (SWT.DefaultSelection,typedListener); +} + +static int checkStyle (int style) { + return checkBits (style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0); +} + +void createHandle (int index) { + state |= HANDLE; + fixedHandle = cast(GtkWidget*)OS.g_object_new (display.gtk_fixed_get_type (), null); + if (fixedHandle is null) error (SWT.ERROR_NO_HANDLES); + OS.gtk_fixed_set_has_window (cast(GtkFixed*)fixedHandle, true); + scrolledHandle = cast(GtkWidget*)OS.gtk_scrolled_window_new (null, null); + if (scrolledHandle is null) error (SWT.ERROR_NO_HANDLES); + /* + * Columns: + * 0 - text + */ + auto types = [OS.G_TYPE_STRING ()]; + modelHandle = cast(GtkWidget*)OS.gtk_list_store_newv (types.length, cast(uint*)types.ptr); + if (modelHandle is null) error (SWT.ERROR_NO_HANDLES); + handle = OS.gtk_tree_view_new_with_model (modelHandle); + if (handle is null) error (SWT.ERROR_NO_HANDLES); + auto textRenderer = OS.gtk_cell_renderer_text_new (); + if (textRenderer is null) error (SWT.ERROR_NO_HANDLES); + auto columnHandle = OS.gtk_tree_view_column_new (); + if (columnHandle is null) error (SWT.ERROR_NO_HANDLES); + OS.gtk_tree_view_column_pack_start (cast(GtkTreeViewColumn*)columnHandle, textRenderer, true); + OS.gtk_tree_view_column_add_attribute (cast(GtkTreeViewColumn*)columnHandle, textRenderer, OS.text.ptr, TEXT_COLUMN); + OS.gtk_tree_view_insert_column (cast(GtkTreeView*)handle, columnHandle, index); + OS.gtk_container_add (cast(GtkContainer*)fixedHandle, scrolledHandle); + OS.gtk_container_add (cast(GtkContainer*)scrolledHandle, handle); + + int mode = (style & SWT.MULTI) !is 0 ? OS.GTK_SELECTION_MULTIPLE : OS.GTK_SELECTION_BROWSE; + auto selectionHandle = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + OS.gtk_tree_selection_set_mode (selectionHandle, mode); + OS.gtk_tree_view_set_headers_visible (cast(GtkTreeView*)handle, false); + int hsp = (style & SWT.H_SCROLL) !is 0 ? OS.GTK_POLICY_AUTOMATIC : OS.GTK_POLICY_NEVER; + int vsp = (style & SWT.V_SCROLL) !is 0 ? OS.GTK_POLICY_AUTOMATIC : OS.GTK_POLICY_NEVER; + OS.gtk_scrolled_window_set_policy (cast(GtkScrolledWindow*)scrolledHandle, hsp, vsp); + if ((style & SWT.BORDER) !is 0) OS.gtk_scrolled_window_set_shadow_type (cast(GtkScrolledWindow*)scrolledHandle, OS.GTK_SHADOW_ETCHED_IN); + /* + * Bug in GTK. When a treeview is the child of an override shell, + * and if the user has ever invokes the interactive search field, + * and the treeview is disposed on a focus out event, it segment + * faults. The fix is to disable the search field in an override + * shell. + */ + if ((getShell ().style & SWT.ON_TOP) !is 0) { + /* + * Bug in GTK. Until GTK 2.6.5, calling gtk_tree_view_set_enable_search(FALSE) + * would prevent the user from being able to type in text to search the tree. + * After 2.6.5, GTK introduced Ctrl+F as being the key binding for interactive + * search. This meant that even if FALSE was passed to enable_search, the user + * can still bring up the search pop up using the keybinding. GTK also introduced + * the notion of passing a -1 to gtk_set_search_column to disable searching + * (including the search key binding). The fix is to use the right calls + * for the right version. + */ + if (OS.GTK_VERSION >= OS.buildVERSION (2, 6, 5)) { + OS.gtk_tree_view_set_search_column (cast(GtkTreeView*)handle, -1); + } else { + OS.gtk_tree_view_set_enable_search (cast(GtkTreeView*)handle, false); + } + } +} + +public Point computeSize (int wHint, int hHint, bool changed) { + checkWidget (); + if (wHint !is SWT.DEFAULT && wHint < 0) wHint = 0; + if (hHint !is SWT.DEFAULT && hHint < 0) hHint = 0; + Point size = computeNativeSize (handle, wHint, hHint, changed); + Rectangle trim = computeTrim (0, 0, size.x, size.y); + size.x = trim.width; + size.y = trim.height; + return size; +} + +override void deregister() { + super.deregister (); + display.removeWidget (cast(GtkWidget*)OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle)); +} + +/** + * Deselects the item at the given zero-relative index in the receiver. + * If the item at the index was already deselected, it remains + * deselected. Indices that are out of range are ignored. + * + * @param index the index of the item to deselect + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void deselect (int index) { + checkWidget(); + if (!(0 <= index && index < OS.gtk_tree_model_iter_n_children (cast(GtkTreeStore*)modelHandle, null))) return; + GtkTreeIter iter; + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); + OS.gtk_tree_model_iter_nth_child (cast(GtkTreeStore*)modelHandle, &iter, null, index); + OS.gtk_tree_selection_unselect_iter (selection, &iter); + OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); +} + +/** + * Deselects the items at the given zero-relative indices in the receiver. + * If the item at the given zero-relative index in the receiver + * is selected, it is deselected. If the item at the index + * was not selected, it remains deselected. The range of the + * indices is inclusive. Indices that are out of range are ignored. + * + * @param start the start index of the items to deselect + * @param end the end index of the items to deselect + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void deselect (int start, int end) { + checkWidget(); + if (start < 0 && end < 0) return; + int count = OS.gtk_tree_model_iter_n_children (cast(GtkTreeStore*)modelHandle, null); + if (start >= count && end >= count) return; + start = Math.min (count - 1, Math.max (0, start)); + end = Math.min (count - 1, Math.max (0, end)); + GtkTreeIter iter; + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); + for (int index=start; index<=end; index++) { + OS.gtk_tree_model_iter_nth_child (cast(GtkTreeStore*)modelHandle, &iter, null, index); + OS.gtk_tree_selection_unselect_iter (selection, &iter); + } + OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); +} + +/** + * Deselects the items at the given zero-relative indices in the receiver. + * If the item at the given zero-relative index in the receiver + * is selected, it is deselected. If the item at the index + * was not selected, it remains deselected. Indices that are out + * of range and duplicate indices are ignored. + * + * @param indices the array of indices for the items to deselect + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the set of indices is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void deselect (int [] indices) { + checkWidget(); + if (indices is null) error (SWT.ERROR_NULL_ARGUMENT); + GtkTreeIter iter; + int count = OS.gtk_tree_model_iter_n_children (cast(GtkTreeStore*)modelHandle, null); + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); + for (int i=0; i<indices.length; i++) { + int index = indices [i]; + if (index < 0 || index > count - 1) continue; + OS.gtk_tree_model_iter_nth_child (cast(GtkTreeStore*)modelHandle, &iter, null, index); + OS.gtk_tree_selection_unselect_iter (selection, &iter); + } + OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); +} + +/** + * Deselects all selected items in the receiver. + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void deselectAll () { + checkWidget(); + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); + OS.gtk_tree_selection_unselect_all (selection); + OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); +} + +alias Scrollable.dragDetect dragDetect; +override bool dragDetect (int x, int y, bool filter, bool* consume) { + bool selected = false; + if (filter) { + GtkTreePath* path; + if (OS.gtk_tree_view_get_path_at_pos (cast(GtkTreeView*)handle, x, y, &path, null, null, null)) { + if (path !is null) { + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + if (OS.gtk_tree_selection_path_is_selected (selection, path)) selected = true; + OS.gtk_tree_path_free (path); + } + } else { + return false; + } + } + bool dragDetect = super.dragDetect (x, y, filter, consume); + if (dragDetect && selected && consume !is null) *consume = true; + return dragDetect; +} + +GdkDrawable* eventWindow () { + return paintWindow (); +} + +GdkColor* getBackgroundColor () { + return getBaseColor (); +} + +/** + * Returns the zero-relative index of the item which currently + * has the focus in the receiver, or -1 if no item has focus. + * + * @return the index of the selected item + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public int getFocusIndex () { + checkWidget(); + GtkTreePath * path; + OS.gtk_tree_view_get_cursor (cast(GtkTreeView*)handle, &path, null); + if (path is null) return -1; + int* indices = OS.gtk_tree_path_get_indices (path); + int index; + if (indices !is null) index = indices[0]; + OS.gtk_tree_path_free (path); + return index; +} + +GdkColor* getForegroundColor () { + return getTextColor (); +} + +/** + * Returns the item at the given, zero-relative index in the + * receiver. Throws an exception if the index is out of range. + * + * @param index the index of the item to return + * @return the item at the given index + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public char[] getItem (int index) { + checkWidget(); + if (!(0 <= index && index < OS.gtk_tree_model_iter_n_children (cast(GtkTreeStore*)modelHandle, null))) { + error (SWT.ERROR_INVALID_RANGE); + } + char* ptr; + GtkTreeIter iter; + OS.gtk_tree_model_iter_nth_child (cast(GtkTreeStore*)modelHandle, &iter, null, index); + OS.gtk_tree_model_get1 (cast(GtkTreeStore*)modelHandle, &iter, 0, cast(void**)&ptr ); + if (ptr is null) return null; + char[] res = fromUtf8z( ptr ).dup; + OS.g_free (ptr); + return res; +} + +/** + * Returns the number of items contained in the receiver. + * + * @return the number of items + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public int getItemCount () { + checkWidget(); + return OS.gtk_tree_model_iter_n_children (cast(GtkTreeStore*)modelHandle, null); +} + +/** + * Returns the height of the area which would be used to + * display <em>one</em> of the items in the list. + * + * @return the height of one item + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public int getItemHeight () { + checkWidget(); + int itemCount = OS.gtk_tree_model_iter_n_children (cast(GtkTreeStore*)modelHandle, null); + auto column = OS.gtk_tree_view_get_column (cast(GtkTreeView*)handle, 0); + if (itemCount is 0) { + int w, h; + OS.gtk_tree_view_column_cell_get_size (cast(GtkTreeViewColumn*)column, null, null, null, &w, &h); + return h; + } else { + GtkTreeIter iter; + OS.gtk_tree_model_get_iter_first (cast(GtkTreeStore*)modelHandle, &iter); + OS.gtk_tree_view_column_cell_set_cell_data (cast(GtkTreeViewColumn*)column, modelHandle, &iter, false, false); + int w, h; + OS.gtk_tree_view_column_cell_get_size (cast(GtkTreeViewColumn*)column, null, null, null, &w, &h); + return h; + } +} + +/** + * Returns a (possibly empty) array of <code>String</code>s which + * are the items in the receiver. + * <p> + * Note: This is not the actual structure used by the receiver + * to maintain its list of items, so modifying the array will + * not affect the receiver. + * </p> + * + * @return the items in the receiver's list + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public char[] [] getItems () { + checkWidget(); + int count = OS.gtk_tree_model_iter_n_children (cast(GtkTreeStore*)modelHandle, null); + char* ptr; + char[] [] result = new char[][]( count ); + GtkTreeIter iter; + for (int index=0; index<count; index++) { + OS.gtk_tree_model_iter_nth_child (cast(GtkTreeStore*)modelHandle, &iter, null, index); + OS.gtk_tree_model_get1 (cast(GtkTreeStore*)modelHandle, &iter, 0, cast(void**)&ptr); + if (ptr !is null) { + char[] res = fromUtf8z( ptr ).dup; + OS.g_free (ptr); + result [index] = res; + } + } + return result; +} + +/** + * Returns an array of <code>String</code>s that are currently + * selected in the receiver. The order of the items is unspecified. + * An empty array indicates that no items are selected. + * <p> + * Note: This is not the actual structure used by the receiver + * to maintain its selection, so modifying the array will + * not affect the receiver. + * </p> + * @return an array representing the selection + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public char[] [] getSelection () { + checkWidget(); + int [] indices = getSelectionIndices (); + char[] [] result = new char[][](indices.length); + for (int i=0; i<indices.length; i++) { + result [i] = getItem (indices [i]); + } + return result; +} + +/** + * Returns the number of selected items contained in the receiver. + * + * @return the number of selected items + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public int getSelectionCount () { + checkWidget(); + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + if (OS.GTK_VERSION < OS.buildVERSION (2, 2, 0)) { + display.treeSelectionLength = 0; + display.treeSelection = null; + display.doTreeSelectionProcConnect( &treeSelectionProcCallbackData, handle, selection ); + return display.treeSelectionLength; + } + return OS.gtk_tree_selection_count_selected_rows (selection); +} + +/** + * Returns the zero-relative index of the item which is currently + * selected in the receiver, or -1 if no item is selected. + * + * @return the index of the selected item or -1 + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public int getSelectionIndex () { + checkWidget(); + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + if (OS.GTK_VERSION < OS.buildVERSION (2, 2, 0)) { + int itemCount = OS.gtk_tree_model_iter_n_children (cast(GtkTreeStore*)modelHandle, null); + display.treeSelectionLength = 0; + display.treeSelection = new int [itemCount]; + display.doTreeSelectionProcConnect( &treeSelectionProcCallbackData, handle, selection ); + if (display.treeSelectionLength is 0) return -1; + return display.treeSelection [0]; + } + /* + * Bug in GTK. gtk_tree_selection_get_selected_rows() segmentation faults + * in versions smaller than 2.2.4 if the model is NULL. The fix is + * to give a valid pointer instead. + */ + int dummy; + int* model = OS.GTK_VERSION < OS.buildVERSION (2, 2, 4) ? &dummy : null; + auto list = OS.gtk_tree_selection_get_selected_rows (selection, cast(void**)model); + if (list !is null) { + int count = OS.g_list_length (list); + int index; + for (int i=0; i<count; i++) { + auto data = OS.g_list_nth_data (list, i); + auto indices = OS.gtk_tree_path_get_indices (data); + if (indices !is null) { + index = indices[0]; + break; + } + } + OS.g_list_free (list); + return index; + } + return -1; +} + +/** + * Returns the zero-relative indices of the items which are currently + * selected in the receiver. The order of the indices is unspecified. + * The array is empty if no items are selected. + * <p> + * Note: This is not the actual structure used by the receiver + * to maintain its selection, so modifying the array will + * not affect the receiver. + * </p> + * @return the array of indices of the selected items + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public int [] getSelectionIndices () { + checkWidget(); + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + if (OS.GTK_VERSION < OS.buildVERSION (2, 2, 0)) { + int itemCount = OS.gtk_tree_model_iter_n_children (cast(GtkTreeStore*)modelHandle, null); + display.treeSelectionLength = 0; + display.treeSelection = new int [itemCount]; + display.doTreeSelectionProcConnect( &treeSelectionProcCallbackData, handle, selection ); + if (display.treeSelectionLength is display.treeSelection.length) return display.treeSelection; + int [] result = new int [display.treeSelectionLength]; + System.arraycopy (display.treeSelection, 0, result, 0, display.treeSelectionLength); + return result; + } + /* + * Bug in GTK. gtk_tree_selection_get_selected_rows() segmentation faults + * in versions smaller than 2.2.4 if the model is NULL. The fix is + * to give a valid pointer instead. + */ + int dummy; + int* model = OS.GTK_VERSION < OS.buildVERSION (2, 2, 4) ? &dummy : null; + auto list = OS.gtk_tree_selection_get_selected_rows (selection, cast(void**)model); + if (list !is null) { + int count = OS.g_list_length (list); + int [] treeSelection = new int [count]; + int len = 0; + for (int i=0; i<count; i++) { + auto data = OS.g_list_nth_data (list, i); + auto indices = OS.gtk_tree_path_get_indices (data); + if (indices !is null) { + treeSelection [length] = indices [0]; + len++; + } + } + OS.g_list_free (list); + int [] result = treeSelection[0..len].dup; + return result; + } + return [0]; +} + +/** + * Returns the zero-relative index of the item which is currently + * at the top of the receiver. This index can change when items are + * scrolled or new items are added or removed. + * + * @return the index of the top item + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public int getTopIndex () { + checkWidget(); + GtkTreePath* path; + OS.gtk_widget_realize (handle); + if (!OS.gtk_tree_view_get_path_at_pos (cast(GtkTreeView*)handle, 1, 1, &path, null, null, null)) return 0; + if (path is null) return 0; + auto indices = OS.gtk_tree_path_get_indices (path); + int index; + if (indices !is null) index = indices[0]; + OS.gtk_tree_path_free (path); + return index; +} + +override int /*long*/ gtk_changed (GtkWidget* widget) { + postEvent (SWT.Selection); + return 0; +} + +override int /*long*/ gtk_button_press_event (GtkWidget* widget, GdkEventButton* gdkEvent) { + auto result = super.gtk_button_press_event (widget, gdkEvent); + if (result !is 0) return result; + /* + * Feature in GTK. In a multi-select list view, when multiple items are already + * selected, the selection state of the item is toggled and the previous selection + * is cleared. This is not the desired behaviour when bringing up a popup menu. + * Also, when an item is reselected with the right button, the tree view issues + * an unwanted selection event. The workaround is to detect that case and not + * run the default handler when the item is already part of the current selection. + */ + int button = gdkEvent.button; + if (button is 3 && gdkEvent.type is OS.GDK_BUTTON_PRESS) { + GtkTreePath* path; + if (OS.gtk_tree_view_get_path_at_pos (cast(GtkTreeView*)handle, cast(int)gdkEvent.x, cast(int)gdkEvent.y, &path, null, null, null)) { + if (path !is null) { + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + if (OS.gtk_tree_selection_path_is_selected (selection, path)) result = 1; + OS.gtk_tree_path_free (path); + } + } + } + + /* + * Feature in GTK. When the user clicks in a single selection GtkTreeView + * and there are no selected items, the first item is selected automatically + * before the click is processed, causing two selection events. The is fix + * is the set the cursor item to be same as the clicked item to stop the + * widget from automatically selecting the first item. + */ + if ((style & SWT.SINGLE) !is 0 && getSelectionCount () is 0) { + GtkTreePath* path; + if (OS.gtk_tree_view_get_path_at_pos (cast(GtkTreeView*)handle, cast(int)gdkEvent.x, cast(int)gdkEvent.y, &path, null, null, null)) { + if (path !is null) { + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); + OS.gtk_tree_view_set_cursor (cast(GtkTreeView*)handle, path, null, false); + OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); + OS.gtk_tree_path_free (path); + } + } + } + /* + * Bug in GTK. GTK segments fault, if the GtkTreeView widget is + * not in focus and all items in the widget are disposed before + * it finishes processing a button press. The fix is to give + * focus to the widget before it starts processing the event. + */ + if (!OS.GTK_WIDGET_HAS_FOCUS (handle)) { + OS.gtk_widget_grab_focus (handle); + } + return result; +} + +override int /*long*/ gtk_key_press_event (GtkWidget* widget, GdkEventKey* keyEvent) { + auto result = super.gtk_key_press_event (widget, keyEvent); + if (result !is 0) return result; + if (OS.GTK_VERSION < OS.buildVERSION (2, 2 ,0)) { + /* + * Feature in GTK 2.0.x. When an item is default selected using + * the return key, GTK does not issue notification. The fix is + * to issue this notification when the return key is pressed. + */ + int key = keyEvent.keyval; + switch (key) { + case OS.GDK_Return: + case OS.GDK_KP_Enter: { + postEvent (SWT.DefaultSelection); + break; + } + } + } + return result; +} + +override int /*long*/ gtk_popup_menu (GtkWidget* widget) { + auto result = super.gtk_popup_menu (widget); + /* + * Bug in GTK. The context menu for the typeahead in GtkTreeViewer + * opens in the bottom right corner of the screen when Shift+F10 + * is pressed and the typeahead window was not visible. The fix is + * to prevent the context menu from opening by stopping the default + * handler. + * + * NOTE: The bug only happens in GTK 2.6.5 and lower. + */ + return OS.GTK_VERSION < OS.buildVERSION (2, 6, 5) ? 1 : result; +} + +override int /*long*/ gtk_row_activated (int /*long*/ tree, int /*long*/ path, int /*long*/ column) { + postEvent (SWT.DefaultSelection); + return 0; +} + +void hookEvents () { + super.hookEvents(); + auto selection = OS.gtk_tree_view_get_selection(cast(GtkTreeView*)handle); + OS.g_signal_connect_closure (selection, OS.changed.ptr, display.closures [CHANGED], false); + OS.g_signal_connect_closure (handle, OS.row_activated.ptr, display.closures [ROW_ACTIVATED], false); +} + +/** + * Gets the index of an item. + * <p> + * The list is searched starting at 0 until an + * item is found that is equal to the search item. + * If no item is found, -1 is returned. Indexing + * is zero based. + * + * @param string the search item + * @return the index of the item + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public int indexOf (char[] string) { + checkWidget(); + return indexOf (string, 0); +} + +/** + * Searches the receiver's list starting at the given, + * zero-relative index until an item is found that is equal + * to the argument, and returns the index of that item. If + * no item is found or the starting index is out of range, + * returns -1. + * + * @param string the search item + * @param start the zero-relative index at which to start the search + * @return the index of the item + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public int indexOf (char[] string, int start) { + checkWidget(); + if (string is null) error (SWT.ERROR_NULL_ARGUMENT); + char[] [] items = getItems (); + for (int i=start; i<items.length; i++) { + if (items [i] ==/*eq*/ (string)) return i; + } + return -1; +} + +/** + * Returns <code>true</code> if the item is selected, + * and <code>false</code> otherwise. Indices out of + * range are ignored. + * + * @param index the index of the item + * @return the selection state of the item at the index + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public bool isSelected (int index) { + checkWidget(); + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + char* buffer = toStringz(tango.text.convert.Integer.toString(index)); + auto path = OS.gtk_tree_path_new_from_string (buffer); + bool answer = cast(bool)OS.gtk_tree_selection_path_is_selected (selection, path); + OS.gtk_tree_path_free (path); + return answer; +} + +GdkDrawable* paintWindow () { + OS.gtk_widget_realize (handle); + return OS.gtk_tree_view_get_bin_window (cast(GtkTreeView*)handle); +} + +void register () { + super.register (); + display.addWidget (cast(GtkWidget*)OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle), this); +} + +void releaseWidget () { + super.releaseWidget (); + if (modelHandle !is null) OS.g_object_unref (modelHandle); + modelHandle = null; +} + +/** + * Removes the item from the receiver at the given + * zero-relative index. + * + * @param index the index for the item + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void remove (int index) { + checkWidget(); + if (!(0 <= index && index < OS.gtk_tree_model_iter_n_children (cast(GtkTreeStore*)modelHandle, null))) { + error (SWT.ERROR_INVALID_RANGE); + } + GtkTreeIter iter; + OS.gtk_tree_model_iter_nth_child (cast(GtkTreeStore*)modelHandle, &iter, null, index); + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); + OS.gtk_list_store_remove (cast(GtkListStore*)modelHandle, &iter); + OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); +} + +/** + * Removes the items from the receiver which are + * between the given zero-relative start and end + * indices (inclusive). + * + * @param start the start of the range + * @param end the end of the range + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_RANGE - if either the start or end are not between 0 and the number of elements in the list minus 1 (inclusive)</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void remove (int start, int end) { + checkWidget(); + if (start > end) return; + int count = OS.gtk_tree_model_iter_n_children (cast(GtkTreeStore*)modelHandle, null); + if (!(0 <= start && start <= end && end < count)) { + error (SWT.ERROR_INVALID_RANGE); + } + GtkTreeIter iter; + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); + for (int index=end; index>=start; index--) { + OS.gtk_tree_model_iter_nth_child (cast(GtkTreeStore*)modelHandle, &iter, null, index); + OS.gtk_list_store_remove (cast(GtkListStore*)modelHandle, &iter); + } + OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); +} + +/** + * Searches the receiver's list starting at the first item + * until an item is found that is equal to the argument, + * and removes that item from the list. + * + * @param string the item to remove + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the string is not found in the list</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void remove (char[] string) { + checkWidget(); + if (string is null) error (SWT.ERROR_NULL_ARGUMENT); + int index = indexOf (string, 0); + if (index is -1) error (SWT.ERROR_INVALID_ARGUMENT); + remove (index); +} + +/** + * Removes the items from the receiver at the given + * zero-relative indices. + * + * @param indices the array of indices of the items + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li> + * <li>ERROR_NULL_ARGUMENT - if the indices array is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void remove (int [] indices) { + checkWidget(); + if (indices is null) error (SWT.ERROR_NULL_ARGUMENT); + if (indices.length is 0) return; + int [] newIndices = new int []( indices.length ); + System.arraycopy (indices, 0, newIndices, 0, indices.length); + sort (newIndices); + int start = newIndices [newIndices.length - 1], end = newIndices [0]; + int count = getItemCount(); + if (!(0 <= start && start <= end && end < count)) { + error (SWT.ERROR_INVALID_RANGE); + } + GtkTreeIter iter; + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); + int last = -1; + for (int i=0; i<newIndices.length; i++) { + int index = newIndices [i]; + if (index !is last) { + OS.gtk_tree_model_iter_nth_child (cast(GtkTreeStore*)modelHandle, &iter, null, index); + OS.gtk_list_store_remove (cast(GtkListStore*)modelHandle, &iter); + last = index; + } + } + OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); +} + +/** + * Removes all of the items from the receiver. + * <p> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void removeAll () { + checkWidget(); + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); + OS.gtk_list_store_clear (cast(GtkListStore*)modelHandle); + OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); +} + +/** + * Removes the listener from the collection of listeners who will + * be notified when the user changes the receiver's selection. + * + * @param listener the listener which should no longer be notified + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ +public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener is null) error (SWT.ERROR_NULL_ARGUMENT); + if (eventTable is null) return; + eventTable.unhook (SWT.Selection, listener); + eventTable.unhook (SWT.DefaultSelection,listener); +} + +/** + * Selects the item at the given zero-relative index in the receiver's + * list. If the item at the index was already selected, it remains + * selected. Indices that are out of range are ignored. + * + * @param index the index of the item to select + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void select (int index) { + checkWidget(); + if (!(0 <= index && index < OS.gtk_tree_model_iter_n_children (cast(GtkTreeStore*)modelHandle, null))) return; + GtkTreeIter iter; + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); + OS.gtk_tree_model_iter_nth_child (cast(GtkTreeStore*)modelHandle, &iter, null, index); + OS.gtk_tree_selection_select_iter (selection, &iter); + if ((style & SWT.SINGLE) !is 0) { + auto path = OS.gtk_tree_model_get_path (cast(GtkTreeStore*)modelHandle, &iter); + OS.gtk_tree_view_set_cursor (cast(GtkTreeView*)handle, path, null, false); + OS.gtk_tree_path_free (path); + } + OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); +} + +/** + * Selects the items in the range specified by the given zero-relative + * indices in the receiver. The range of indices is inclusive. + * The current selection is not cleared before the new items are selected. + * <p> + * If an item in the given range is not selected, it is selected. + * If an item in the given range was already selected, it remains selected. + * Indices that are out of range are ignored and no items will be selected + * if start is greater than end. + * If the receiver is single-select and there is more than one item in the + * given range, then all indices are ignored. + * + * @param start the start of the range + * @param end the end of the range + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see List#setSelection(int,int) + */ +public void select (int start, int end) { + checkWidget (); + if (end < 0 || start > end || ((style & SWT.SINGLE) !is 0 && start !is end)) return; + int count = OS.gtk_tree_model_iter_n_children (cast(GtkTreeStore*)modelHandle, null); + if (count is 0 || start >= count) return; + start = Math.max (0, start); + end = Math.min (end, count - 1); + GtkTreeIter iter; + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); + for (int index=start; index<=end; index++) { + OS.gtk_tree_model_iter_nth_child (cast(GtkTreeStore*)modelHandle, &iter, null, index); + OS.gtk_tree_selection_select_iter (selection, &iter); + if ((style & SWT.SINGLE) !is 0) { + auto path = OS.gtk_tree_model_get_path (cast(GtkTreeStore*)modelHandle, &iter); + OS.gtk_tree_view_set_cursor (cast(GtkTreeView*)handle, path, null, false); + OS.gtk_tree_path_free (path); + } + } + OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); +} + +/** + * Selects the items at the given zero-relative indices in the receiver. + * The current selection is not cleared before the new items are selected. + * <p> + * If the item at a given index is not selected, it is selected. + * If the item at a given index was already selected, it remains selected. + * Indices that are out of range and duplicate indices are ignored. + * If the receiver is single-select and multiple indices are specified, + * then all indices are ignored. + * + * @param indices the array of indices for the items to select + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the array of indices is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see List#setSelection(int[]) + */ +public void select (int [] indices) { + checkWidget (); + if (indices is null) error (SWT.ERROR_NULL_ARGUMENT); + int length = indices.length; + if (length is 0 || ((style & SWT.SINGLE) !is 0 && length > 1)) return; + GtkTreeIter iter; + int count = OS.gtk_tree_model_iter_n_children (cast(GtkTreeStore*)modelHandle, null); + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); + for (int i=0; i<length; i++) { + int index = indices [i]; + if (!(0 <= index && index < count)) continue; + OS.gtk_tree_model_iter_nth_child (cast(GtkTreeStore*)modelHandle, &iter, null, index); + OS.gtk_tree_selection_select_iter (selection, &iter); + if ((style & SWT.SINGLE) !is 0) { + auto path = OS.gtk_tree_model_get_path (cast(GtkTreeStore*)modelHandle, &iter); + OS.gtk_tree_view_set_cursor (cast(GtkTreeView*)handle, path, null, false); + OS.gtk_tree_path_free (path); + } + } + OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); +} + +/** + * Selects all of the items in the receiver. + * <p> + * If the receiver is single-select, do nothing. + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void selectAll () { + checkWidget(); + if ((style & SWT.SINGLE) !is 0) return; + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); + OS.gtk_tree_selection_select_all (selection); + OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); +} + +void selectFocusIndex (int index) { + /* + * Note that this method both selects and sets the focus to the + * specified index, so any previous selection in the list will be lost. + * gtk does not provide a way to just set focus to a specified list item. + */ + int count = OS.gtk_tree_model_iter_n_children (cast(GtkTreeStore*)modelHandle, null); + if (!(0 <= index && index < count)) return; + GtkTreeIter iter; + OS.gtk_tree_model_iter_nth_child (cast(GtkTreeStore*)modelHandle, &iter, null, index); + auto path = OS.gtk_tree_model_get_path (cast(GtkTreeStore*)modelHandle, &iter); + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); + OS.gtk_tree_view_set_cursor (cast(GtkTreeView*)handle, path, null, false); + /* + * Bug in GTK. For some reason, when an event loop is run from + * within a key pressed handler and a dialog is displayed that + * contains a GtkTreeView, gtk_tree_view_set_cursor() does + * not set the cursor or select the item. The fix is to select the + * item with gtk_tree_selection_select_iter() as well. + * + * NOTE: This happens in GTK 2.2.1 and is fixed in GTK 2.2.4. + */ + OS.gtk_tree_selection_select_iter (selection, &iter); + OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); + OS.gtk_tree_path_free (path); +} + +void setBackgroundColor (GdkColor* color) { + super.setBackgroundColor (color); + OS.gtk_widget_modify_base (handle, 0, color); +} + +int setBounds (int x, int y, int width, int height, bool move, bool resize) { + int result = super.setBounds (x, y, width, height, move, resize); + /* + * Bug on GTK. The tree view sometimes does not get a paint + * event or resizes to a one pixel square when resized in a new + * shell that is not visible after any event loop has been run. The + * problem is intermittent. It doesn't seem to happen the first time + * a new shell is created. The fix is to ensure the tree view is realized + * after it has been resized. + */ + OS.gtk_widget_realize (handle); + /* + * Bug in GTK. An empty GtkTreeView fails to repaint the focus rectangle + * correctly when resized on versions before 2.6.0. The fix is to force + * the widget to redraw. + */ + if (OS.GTK_VERSION < OS.buildVERSION (2, 6, 0) && OS.gtk_tree_model_iter_n_children (cast(GtkTreeStore*)modelHandle, null) is 0) { + redraw (false); + } + return result; +} + +/** + * Sets the text of the item in the receiver's list at the given + * zero-relative index to the string argument. + * + * @param index the index for the item + * @param string the new text for the item + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setItem (int index, char[] string) { + checkWidget(); + if (string is null) error (SWT.ERROR_NULL_ARGUMENT); + if (!(0 <= index && index < OS.gtk_tree_model_iter_n_children (cast(GtkTreeStore*)modelHandle, null))) { + error (SWT.ERROR_INVALID_RANGE); + } + GtkTreeIter iter; + OS.gtk_tree_model_iter_nth_child (cast(GtkTreeStore*)modelHandle, &iter, null, index); + char* buffer = toStringz(string); + OS.gtk_list_store_set1 (cast(GtkListStore*)modelHandle, &iter, TEXT_COLUMN, buffer); +} + +/** + * Sets the receiver's items to be the given array of items. + * + * @param items the array of items + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the items array is null</li> + * <li>ERROR_INVALID_ARGUMENT - if an item in the items array is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setItems (char[] [] items) { + checkWidget(); + if (items is null) error (SWT.ERROR_NULL_ARGUMENT); + for (int i=0; i<items.length; i++) { + if (items [i] is null) error (SWT.ERROR_INVALID_ARGUMENT); + } + auto selection = OS.gtk_tree_view_get_selection (cast(GtkTreeView*)handle); + OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); + OS.gtk_list_store_clear (cast(GtkListStore*)modelHandle); + OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED); + GtkTreeIter iter; + for (int i=0; i<items.length; i++) { + char[] string = items [i]; + char* buffer = toStringz(string); + OS.gtk_list_store_append (cast(GtkListStore*)modelHandle, &iter); + OS.gtk_list_store_set1 (cast(GtkListStore*)modelHandle, &iter, TEXT_COLUMN, buffer); + } +} + +/** + * Selects the item at the given zero-relative index in the receiver. + * If the item at the index was already selected, it remains selected. + * The current selection is first cleared, then the new item is selected. + * Indices that are out of range are ignored. + * + * @param index the index of the item to select + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * @see List#deselectAll() + * @see List#select(int) + */ +public void setSelection (int index) { + checkWidget (); + deselectAll (); + selectFocusIndex (index); + showSelection (); +} + +/** + * Selects the items in the range specified by the given zero-relative + * indices in the receiver. The range of indices is inclusive. + * The current selection is cleared before the new items are selected. + * <p> + * Indices that are out of range are ignored and no items will be selected + * if start is greater than end. + * If the receiver is single-select and there is more than one item in the + * given range, then all indices are ignored. + * + * @param start the start index of the items to select + * @param end the end index of the items to select + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see List#deselectAll() + * @see List#select(int,int) + */ +public void setSelection (int start, int end) { + checkWidget (); + deselectAll (); + if (end < 0 || start > end || ((style & SWT.SINGLE) !is 0 && start !is end)) return; + int count = OS.gtk_tree_model_iter_n_children (cast(GtkTreeStore*)modelHandle, null); + if (count is 0 || start >= count) return; + start = Math.max (0, start); + end = Math.min (end, count - 1); + selectFocusIndex (start); + if ((style & SWT.MULTI) !is 0) { + select (start, end); + } + showSelection (); +} + +/** + * Selects the items at the given zero-relative indices in the receiver. + * The current selection is cleared before the new items are selected. + * <p> + * Indices that are out of range and duplicate indices are ignored. + * If the receiver is single-select and multiple indices are specified, + * then all indices are ignored. + * + * @param indices the indices of the items to select + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the array of indices is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see List#deselectAll() + * @see List#select(int[]) + */ +public void setSelection(int[] indices) { + checkWidget (); + if (indices is null) error (SWT.ERROR_NULL_ARGUMENT); + deselectAll (); + int length = indices.length; + if (length is 0 || ((style & SWT.SINGLE) !is 0 && length > 1)) return; + selectFocusIndex (indices [0]); + if ((style & SWT.MULTI) !is 0) { + select (indices); + } + showSelection (); +} + +/** + * Sets the receiver's selection to be the given array of items. + * The current selection is cleared before the new items are selected. + * <p> + * Items that are not in the receiver are ignored. + * If the receiver is single-select and multiple items are specified, + * then all items are ignored. + * + * @param items the array of items + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the array of items is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see List#deselectAll() + * @see List#select(int[]) + * @see List#setSelection(int[]) + */ +public void setSelection (char[] [] items) { + checkWidget (); + if (items is null) error (SWT.ERROR_NULL_ARGUMENT); + deselectAll (); + int length = items.length; + if (length is 0 || ((style & SWT.SINGLE) !is 0 && length > 1)) return; + bool first = true; + for (int i = 0; i < length; i++) { + int index = 0; + char[] string = items [i]; + if (string !is null) { + while ((index = indexOf (string, index)) !is -1) { + if ((style & SWT.MULTI) !is 0) { + if (first) { + first = false; + selectFocusIndex (index); + } else { + select (index); + } + } else { + selectFocusIndex (index); + break; + } + index++; + } + } + } + showSelection (); +} + +/** + * Sets the zero-relative index of the item which is currently + * at the top of the receiver. This index can change when items + * are scrolled or new items are added and removed. + * + * @param index the index of the top item + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setTopIndex (int index) { + checkWidget(); + if (!(0 <= index && index < OS.gtk_tree_model_iter_n_children (cast(GtkTreeStore*)modelHandle, null))) return; + GtkTreeIter iter; + OS.gtk_tree_model_iter_nth_child (cast(GtkTreeStore*)modelHandle, &iter, null, index); + auto path = OS.gtk_tree_model_get_path (cast(GtkTreeStore*)modelHandle, &iter); + OS.gtk_tree_view_scroll_to_cell (cast(GtkTreeView*)handle, path, null, true, 0, 0); + if (OS.GTK_VERSION < OS.buildVERSION (2, 8, 0)) { + /* + * Bug in GTK. According to the documentation, gtk_tree_view_scroll_to_cell + * should vertically scroll the cell to the top if use_align is true and row_align is 0. + * However, prior to version 2.8 it does not scroll at all. The fix is to determine + * the new location and use gtk_tree_view_scroll_to_point. + * If the widget is a pinhead, calling gtk_tree_view_scroll_to_point + * will have no effect. Therefore, it is still neccessary to call + * gtk_tree_view_scroll_to_cell. + */ + OS.gtk_widget_realize (handle); + GdkRectangle cellRect; + OS.gtk_tree_view_get_cell_area (cast(GtkTreeView*)handle, path, null, &cellRect); + int tx, ty; + OS.gtk_tree_view_widget_to_tree_coords(cast(GtkTreeView*)handle, cellRect.x, cellRect.y, &tx, &ty); + OS.gtk_tree_view_scroll_to_point (cast(GtkTreeView*)handle, -1, ty); + } + OS.gtk_tree_path_free (path); +} + +/** + * Shows the selection. If the selection is already showing in the receiver, + * this method simply returns. Otherwise, the items are scrolled until + * the selection is visible. + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void showSelection () { + checkWidget(); + int index = getSelectionIndex (); + if (index is -1) return; + GtkTreeIter iter; + OS.gtk_tree_model_iter_nth_child (cast(GtkTreeStore*)modelHandle, &iter, null, index); + auto path = OS.gtk_tree_model_get_path (cast(GtkTreeStore*)modelHandle, &iter); + /* + * This code intentionally commented. + * Bug in GTK. According to the documentation, gtk_tree_view_scroll_to_cell + * should scroll the minimum amount to show the cell if use_align is false. + * However, what actually happens is the cell is scrolled to the top. + * The fix is to determine the new location and use gtk_tree_view_scroll_to_point. + * If the widget is a pinhead, calling gtk_tree_view_scroll_to_point + * will have no effect. Therefore, it is still neccessary to + * call gtk_tree_view_scroll_to_cell. + */ +// OS.gtk_tree_view_scroll_to_cell (handle, path, 0, false, 0, 0); + OS.gtk_widget_realize (handle); + GdkRectangle visibleRect; + OS.gtk_tree_view_get_visible_rect (cast(GtkTreeView*)handle, &visibleRect); + GdkRectangle cellRect; + OS.gtk_tree_view_get_cell_area (cast(GtkTreeView*)handle, path, null, &cellRect); + int tx, ty; + OS.gtk_tree_view_widget_to_tree_coords(cast(GtkTreeView*)handle, cellRect.x, cellRect.y, &tx, &ty); + if (ty < visibleRect.y ) { + OS.gtk_tree_view_scroll_to_cell (cast(GtkTreeView*)handle, path, null, true, 0f, 0f); + OS.gtk_tree_view_scroll_to_point (cast(GtkTreeView*)handle, -1, ty); + } else { + int height = Math.min (visibleRect.height, cellRect.height); + if (ty + height > visibleRect.y + visibleRect.height) { + OS.gtk_tree_view_scroll_to_cell (cast(GtkTreeView*)handle, path, null, true, 1f, 0f); + ty += cellRect.height - visibleRect.height; + OS.gtk_tree_view_scroll_to_point (cast(GtkTreeView*)handle, -1, ty); + } + } + OS.gtk_tree_path_free (path); +} + +override void treeSelectionProc (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, int[] selection, int length_) { + if (selection !is null) { + auto indices = OS.gtk_tree_path_get_indices (path); + if (indices !is null) { + selection [length_] = indices[0]; + } + } + return 0; +} + +}
--- a/dwt/widgets/Spinner.d Sun Jan 13 23:50:55 2008 +0100 +++ b/dwt/widgets/Spinner.d Mon Jan 14 02:04:54 2008 +0100 @@ -550,7 +550,7 @@ OS.g_signal_emit_by_name1 (imContext, OS.commit.ptr, cast(int)toStringz(newChars)); } OS.g_signal_handlers_unblock_matched (imContext, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCOMMIT); - OS.g_signal_handlers_block_matched (imContext, mask, id, 0, null, null, udhandle); + OS.g_signal_handlers_block_matched (imContext, mask, id, 0, null, null, cast(void*)handle); if (fixStart !is -1 && fixEnd !is -1) { OS.gtk_editable_set_position (cast(GtkEditable*)handle, fixStart); OS.gtk_editable_select_region (cast(GtkEditable*)handle, fixStart, fixEnd); @@ -652,7 +652,7 @@ OS.g_signal_connect_closure (imContext, OS.commit.ptr, display.closures [COMMIT], false); int id = OS.g_signal_lookup (OS.commit.ptr, OS.gtk_im_context_get_type ()); int mask = OS.G_SIGNAL_MATCH_DATA | OS.G_SIGNAL_MATCH_ID; - OS.g_signal_handlers_block_matched (imContext, mask, id, 0, null, null, udhandle); + OS.g_signal_handlers_block_matched (imContext, mask, id, 0, null, null, cast(void*)handle); } }
--- a/dwt/widgets/Widget.d Sun Jan 13 23:50:55 2008 +0100 +++ b/dwt/widgets/Widget.d Mon Jan 14 02:04:54 2008 +0100 @@ -1509,7 +1509,7 @@ return 0; } -int /*long*/ treeSelectionProc (int /*long*/ model, int /*long*/ path, int /*long*/ iter, int [] selection, int length) { +void treeSelectionProc (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, int[] selection, int length) { return 0; }