summaryrefslogtreecommitdiff
path: root/iup/src/gtk
diff options
context:
space:
mode:
Diffstat (limited to 'iup/src/gtk')
-rwxr-xr-xiup/src/gtk/iupgtk_button.c477
-rwxr-xr-xiup/src/gtk/iupgtk_canvas.c624
-rwxr-xr-xiup/src/gtk/iupgtk_clipboard.c125
-rwxr-xr-xiup/src/gtk/iupgtk_colordlg.c211
-rwxr-xr-xiup/src/gtk/iupgtk_common.c830
-rwxr-xr-xiup/src/gtk/iupgtk_dialog.c1023
-rwxr-xr-xiup/src/gtk/iupgtk_drv.h82
-rwxr-xr-xiup/src/gtk/iupgtk_filedlg.c536
-rwxr-xr-xiup/src/gtk/iupgtk_focus.c44
-rwxr-xr-xiup/src/gtk/iupgtk_font.c413
-rwxr-xr-xiup/src/gtk/iupgtk_fontdlg.c91
-rwxr-xr-xiup/src/gtk/iupgtk_frame.c155
-rwxr-xr-xiup/src/gtk/iupgtk_globalattrib.c211
-rwxr-xr-xiup/src/gtk/iupgtk_help.c52
-rwxr-xr-xiup/src/gtk/iupgtk_image.c430
-rwxr-xr-xiup/src/gtk/iupgtk_key.c422
-rwxr-xr-xiup/src/gtk/iupgtk_label.c318
-rwxr-xr-xiup/src/gtk/iupgtk_list.c1439
-rwxr-xr-xiup/src/gtk/iupgtk_loop.c93
-rwxr-xr-xiup/src/gtk/iupgtk_menu.c525
-rwxr-xr-xiup/src/gtk/iupgtk_messagedlg.c128
-rwxr-xr-xiup/src/gtk/iupgtk_open.c172
-rwxr-xr-xiup/src/gtk/iupgtk_progressbar.c131
-rwxr-xr-xiup/src/gtk/iupgtk_tabs.c444
-rwxr-xr-xiup/src/gtk/iupgtk_text.c1716
-rwxr-xr-xiup/src/gtk/iupgtk_timer.c61
-rwxr-xr-xiup/src/gtk/iupgtk_tips.c100
-rwxr-xr-xiup/src/gtk/iupgtk_toggle.c519
-rwxr-xr-xiup/src/gtk/iupgtk_tree.c2369
-rwxr-xr-xiup/src/gtk/iupgtk_val.c208
30 files changed, 13949 insertions, 0 deletions
diff --git a/iup/src/gtk/iupgtk_button.c b/iup/src/gtk/iupgtk_button.c
new file mode 100755
index 0000000..18be87c
--- /dev/null
+++ b/iup/src/gtk/iupgtk_button.c
@@ -0,0 +1,477 @@
+/** \file
+ * \brief Button Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_image.h"
+#include "iup_button.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_image.h"
+#include "iup_key.h"
+
+#include "iupgtk_drv.h"
+
+
+#if !GTK_CHECK_VERSION(2, 6, 0)
+static void gtk_button_set_image(GtkButton *button, GtkWidget *image)
+{
+}
+static GtkWidget* gtk_button_get_image(GtkButton *button)
+{
+ return NULL;
+}
+#endif
+
+void iupdrvButtonAddBorders(int *x, int *y)
+{
+#ifdef WIN32
+ int border_size = 2*5;
+#else
+#ifdef HILDON
+ int border_size = 2*7+1; /* borders are not symetric */
+#else
+ int border_size = 2*5+1; /* borders are not symetric */
+#endif
+#endif
+ (*x) += border_size;
+ (*y) += border_size;
+}
+
+static void gtk_button_children_callback(GtkWidget *widget, gpointer client_data)
+{
+ if (GTK_IS_LABEL(widget))
+ {
+ GtkLabel **label = (GtkLabel**) client_data;
+ *label = (GtkLabel*)widget;
+ }
+}
+
+static GtkLabel* gtkButtonGetLabel(Ihandle* ih)
+{
+ if (ih->data->type == IUP_BUTTON_TEXT) /* text only */
+ return (GtkLabel*)gtk_bin_get_child((GtkBin*)ih->handle);
+ else if (ih->data->type == IUP_BUTTON_BOTH) /* both */
+ {
+ /* when both is set, button contains an GtkAlignment,
+ that contains a GtkBox, that contains a label and an image */
+ GtkContainer *container = (GtkContainer*)gtk_bin_get_child((GtkBin*)gtk_bin_get_child((GtkBin*)ih->handle));
+ GtkLabel* label = NULL;
+ gtk_container_foreach(container, gtk_button_children_callback, &label);
+ return label;
+ }
+ return NULL;
+}
+
+static int gtkButtonSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type != IUP_BUTTON_IMAGE) /* text or both */
+ {
+ GtkLabel* label = gtkButtonGetLabel(ih);
+ iupgtkSetMnemonicTitle(ih, label, value);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int gtkButtonSetAlignmentAttrib(Ihandle* ih, const char* value)
+{
+ GtkButton* button = (GtkButton*)ih->handle;
+ PangoAlignment alignment;
+ float xalign, yalign;
+ char value1[30]="", value2[30]="";
+
+ iupStrToStrStr(value, value1, value2, ':');
+
+ if (iupStrEqualNoCase(value1, "ARIGHT"))
+ {
+ xalign = 1.0f;
+ alignment = PANGO_ALIGN_RIGHT;
+ }
+ else if (iupStrEqualNoCase(value1, "ACENTER"))
+ {
+ xalign = 0.5f;
+ alignment = PANGO_ALIGN_CENTER;
+ }
+ else /* "ALEFT" */
+ {
+ xalign = 0;
+ alignment = PANGO_ALIGN_LEFT;
+ }
+
+ if (iupStrEqualNoCase(value2, "ABOTTOM"))
+ yalign = 1.0f;
+ else if (iupStrEqualNoCase(value2, "ATOP"))
+ yalign = 0;
+ else /* ACENTER (default) */
+ yalign = 0.5f;
+
+ gtk_button_set_alignment(button, xalign, yalign);
+
+ if (ih->data->type == IUP_BUTTON_TEXT && !GTK_IS_COLOR_BUTTON(ih->handle)) /* text only */
+ {
+ PangoLayout* layout = gtk_label_get_layout(gtkButtonGetLabel(ih));
+ if (layout) pango_layout_set_alignment(layout, alignment);
+ }
+
+ return 1;
+}
+
+static int gtkButtonSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x');
+ if (ih->handle)
+ {
+ if (ih->data->type == IUP_BUTTON_TEXT) /* text only */
+ {
+ GtkMisc* misc = (GtkMisc*)gtk_bin_get_child((GtkBin*)ih->handle);
+ gtk_misc_set_padding(misc, ih->data->horiz_padding, ih->data->vert_padding);
+ }
+ else
+ {
+ GtkAlignment* alignment = (GtkAlignment*)gtk_bin_get_child((GtkBin*)ih->handle);
+ gtk_alignment_set_padding(alignment, ih->data->vert_padding, ih->data->vert_padding,
+ ih->data->horiz_padding, ih->data->horiz_padding);
+ }
+ }
+ return 0;
+}
+
+#ifdef WIN32
+static int gtkButtonSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_BUTTON_TEXT && GTK_IS_COLOR_BUTTON(ih->handle))
+ {
+ GdkColor color;
+ unsigned char r, g, b;
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgdkColorSet(&color, r, g, b);
+ gtk_color_button_set_color((GtkColorButton*)ih->handle, &color);
+ return 1;
+ }
+
+ return iupdrvBaseSetBgColorAttrib(ih, value);
+}
+#endif
+
+static int gtkButtonSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ GtkLabel* label = gtkButtonGetLabel(ih);
+ if (!label) return 0;
+
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgtkBaseSetFgColor((GtkWidget*)label, r, g, b);
+
+ return 1;
+}
+
+static int gtkButtonSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ iupdrvSetStandardFontAttrib(ih, value);
+
+ if (ih->handle)
+ {
+ GtkLabel* label = gtkButtonGetLabel(ih);
+ if (!label) return 1;
+
+ gtk_widget_modify_font((GtkWidget*)label, (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih));
+ if (ih->data->type == IUP_BUTTON_TEXT && !GTK_IS_COLOR_BUTTON(ih->handle)) /* text only */
+ iupgtkFontUpdatePangoLayout(ih, gtk_label_get_layout(label));
+ }
+ return 1;
+}
+
+static void gtkButtonSetPixbuf(Ihandle* ih, const char* name, int make_inactive)
+{
+ GtkButton* button = (GtkButton*)ih->handle;
+ GtkImage* image = (GtkImage*)gtk_button_get_image(button);
+
+ if (name && image)
+ {
+ GdkPixbuf* pixbuf = iupImageGetImage(name, ih, make_inactive);
+ GdkPixbuf* old_pixbuf = gtk_image_get_pixbuf(image);
+ if (pixbuf != old_pixbuf)
+ gtk_image_set_from_pixbuf(image, pixbuf);
+ return;
+ }
+
+ /* if not defined */
+#if GTK_CHECK_VERSION(2, 8, 0)
+ if (image)
+ gtk_image_clear(image);
+#endif
+}
+
+static int gtkButtonSetImageAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type != IUP_BUTTON_TEXT) /* image or both */
+ {
+ if (iupdrvIsActive(ih))
+ gtkButtonSetPixbuf(ih, value, 0);
+ else
+ {
+ if (!iupAttribGet(ih, "IMINACTIVE"))
+ {
+ /* if not active and IMINACTIVE is not defined
+ then automaticaly create one based on IMAGE */
+ gtkButtonSetPixbuf(ih, value, 1); /* make_inactive */
+ }
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkButtonSetImInactiveAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type != IUP_BUTTON_TEXT) /* image or both */
+ {
+ if (!iupdrvIsActive(ih))
+ {
+ if (value)
+ gtkButtonSetPixbuf(ih, value, 0);
+ else
+ {
+ /* if not defined then automaticaly create one based on IMAGE */
+ char* name = iupAttribGet(ih, "IMAGE");
+ gtkButtonSetPixbuf(ih, name, 1); /* make_inactive */
+ }
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkButtonSetActiveAttrib(Ihandle* ih, const char* value)
+{
+ /* update the inactive image if necessary */
+ if (ih->data->type != IUP_BUTTON_TEXT) /* image or both */
+ {
+ if (!iupStrBoolean(value))
+ {
+ char* name = iupAttribGet(ih, "IMINACTIVE");
+ if (name)
+ gtkButtonSetPixbuf(ih, name, 0);
+ else
+ {
+ /* if not defined then automaticaly create one based on IMAGE */
+ name = iupAttribGet(ih, "IMAGE");
+ gtkButtonSetPixbuf(ih, name, 1); /* make_inactive */
+ }
+ }
+ else
+ {
+ /* must restore the normal image */
+ char* name = iupAttribGet(ih, "IMAGE");
+ gtkButtonSetPixbuf(ih, name, 0);
+ }
+ }
+
+ return iupBaseSetActiveAttrib(ih, value);
+}
+
+static int gtkButtonSetFocusOnClickAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value))
+ gtk_button_set_focus_on_click((GtkButton*)ih->handle, TRUE);
+ else
+ gtk_button_set_focus_on_click((GtkButton*)ih->handle, FALSE);
+ return 1;
+}
+
+static gboolean gtkButtonEnterLeaveEvent(GtkWidget *widget, GdkEventCrossing *evt, Ihandle *ih)
+{
+ iupgtkEnterLeaveEvent(widget, evt, ih);
+ (void)widget;
+
+ if (evt->type == GDK_ENTER_NOTIFY)
+ gtk_button_set_relief((GtkButton*)ih->handle, GTK_RELIEF_NORMAL);
+ else if (evt->type == GDK_LEAVE_NOTIFY)
+ gtk_button_set_relief((GtkButton*)ih->handle, GTK_RELIEF_NONE);
+
+ return FALSE;
+}
+
+static gboolean gtkButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih)
+{
+ if (iupgtkButtonEvent(widget, evt, ih)==TRUE)
+ return TRUE;
+
+ if (ih->data->type != IUP_BUTTON_TEXT) /* image or both */
+ {
+ char* name = iupAttribGet(ih, "IMPRESS");
+ if (name)
+ {
+ if (evt->type == GDK_BUTTON_PRESS)
+ gtkButtonSetPixbuf(ih, name, 0);
+ else
+ {
+ name = iupAttribGet(ih, "IMAGE");
+ gtkButtonSetPixbuf(ih, name, 0);
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+static void gtkButtonClicked(GtkButton *widget, Ihandle* ih)
+{
+ Icallback cb = IupGetCallback(ih, "ACTION");
+ if (cb)
+ {
+ if (cb(ih) == IUP_CLOSE)
+ IupExitLoop();
+ }
+ (void)widget;
+}
+
+static int gtkButtonMapMethod(Ihandle* ih)
+{
+ int impress;
+ char* value;
+
+ ih->handle = gtk_button_new();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ value = iupAttribGet(ih, "IMAGE");
+ if (value)
+ {
+ gtk_button_set_image((GtkButton*)ih->handle, gtk_image_new());
+ ih->data->type = IUP_BUTTON_IMAGE;
+
+ value = iupAttribGet(ih, "TITLE");
+ if (value)
+ {
+ GtkSettings* settings = gtk_widget_get_settings(ih->handle);
+ g_object_set(settings, "gtk-button-images", (int)TRUE, NULL);
+
+ gtk_button_set_label((GtkButton*)ih->handle, value);
+ ih->data->type |= IUP_BUTTON_TEXT;
+
+#if GTK_CHECK_VERSION(2, 10, 0)
+ gtk_button_set_image_position((GtkButton*)ih->handle, ih->data->img_position); /* IUP and GTK have the same Ids */
+#endif
+ }
+ }
+ else
+ {
+ char* title = iupAttribGet(ih, "TITLE");
+ if (!title)
+ {
+#ifdef WIN32
+ if (iupAttribGet(ih, "BGCOLOR"))
+ {
+ gtk_widget_destroy(ih->handle);
+ ih->handle = gtk_color_button_new();
+ }
+ else
+ gtk_button_set_label((GtkButton*)ih->handle, "");
+#else
+ gtk_button_set_label((GtkButton*)ih->handle, "");
+#endif
+ }
+ else
+ gtk_button_set_label((GtkButton*)ih->handle, title);
+ ih->data->type = IUP_BUTTON_TEXT;
+ }
+
+ /* add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ if (!iupAttribGetBoolean(ih, "CANFOCUS"))
+ GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS;
+
+ value = iupAttribGet(ih, "IMPRESS");
+ impress = (ih->data->type & IUP_BUTTON_IMAGE && value)? 1: 0;
+ if (!impress && iupAttribGetBoolean(ih, "FLAT"))
+ {
+ gtk_button_set_relief((GtkButton*)ih->handle, GTK_RELIEF_NONE);
+
+ g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(gtkButtonEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(gtkButtonEnterLeaveEvent), ih);
+ }
+ else
+ {
+ if (impress && !iupAttribGetStr(ih, "IMPRESSBORDER"))
+ gtk_button_set_relief((GtkButton*)ih->handle, GTK_RELIEF_NONE);
+ else
+ gtk_button_set_relief((GtkButton*)ih->handle, GTK_RELIEF_NORMAL);
+
+ g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ }
+
+ g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "clicked", G_CALLBACK(gtkButtonClicked), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "button-press-event", G_CALLBACK(gtkButtonEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "button-release-event",G_CALLBACK(gtkButtonEvent), ih);
+
+ gtk_widget_realize(ih->handle);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvButtonInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkButtonMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Overwrite Common */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, gtkButtonSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED);
+
+ /* Overwrite Visual */
+ iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, gtkButtonSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+
+ /* Visual */
+#ifdef WIN32
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkButtonSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+#else
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+#endif
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, gtkButtonSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "TITLE", NULL, gtkButtonSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupButton only */
+ iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, gtkButtonSetAlignmentAttrib, "ACENTER:ACENTER", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, gtkButtonSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, gtkButtonSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMPRESS", NULL, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FOCUSONCLICK", NULL, gtkButtonSetFocusOnClickAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "PADDING", iupButtonGetPaddingAttrib, gtkButtonSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "MARKUP", NULL, NULL, NULL, NULL, IUPAF_DEFAULT);
+}
diff --git a/iup/src/gtk/iupgtk_canvas.c b/iup/src/gtk/iupgtk_canvas.c
new file mode 100755
index 0000000..daae4ad
--- /dev/null
+++ b/iup/src/gtk/iupgtk_canvas.c
@@ -0,0 +1,624 @@
+/** \file
+ * \brief Canvas Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+#include <limits.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_dialog.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvinfo.h"
+#include "iup_drvfont.h"
+#include "iup_canvas.h"
+#include "iup_key.h"
+
+#include "iupgtk_drv.h"
+
+
+static int gtkCanvasScroll2Iup(GtkScrollType scroll, int vert)
+{
+ switch(scroll)
+ {
+ case GTK_SCROLL_STEP_UP:
+ return IUP_SBUP;
+ case GTK_SCROLL_STEP_DOWN:
+ return IUP_SBDN;
+ case GTK_SCROLL_PAGE_UP:
+ return IUP_SBPGUP;
+ case GTK_SCROLL_PAGE_DOWN:
+ return IUP_SBPGDN;
+ case GTK_SCROLL_STEP_LEFT:
+ return IUP_SBLEFT;
+ case GTK_SCROLL_STEP_RIGHT:
+ return IUP_SBRIGHT;
+ case GTK_SCROLL_PAGE_LEFT:
+ return IUP_SBPGLEFT;
+ case GTK_SCROLL_PAGE_RIGHT:
+ return IUP_SBPGRIGHT;
+ case GTK_SCROLL_STEP_BACKWARD:
+ return vert? IUP_SBUP: IUP_SBLEFT;
+ case GTK_SCROLL_STEP_FORWARD:
+ return vert? IUP_SBDN: IUP_SBRIGHT;
+ case GTK_SCROLL_PAGE_BACKWARD:
+ return vert? IUP_SBPGUP: IUP_SBPGLEFT;
+ case GTK_SCROLL_PAGE_FORWARD:
+ return vert? IUP_SBPGDN: IUP_SBPGRIGHT;
+ case GTK_SCROLL_JUMP:
+ case GTK_SCROLL_START:
+ case GTK_SCROLL_END:
+ return vert? IUP_SBPOSV: IUP_SBPOSH;
+ case GTK_SCROLL_NONE:
+ return -1;
+ }
+
+ /* No IUP_SBDRAGV or IUP_SBDRAGH support in GTK */
+
+ return -1;
+}
+
+static gboolean gtkCanvasHChangeValue(GtkRange *range, GtkScrollType scroll, double value, Ihandle *ih)
+{
+ double posx, posy;
+ IFniff cb;
+
+ double xmin = iupAttribGetFloat(ih, "XMIN");
+ double xmax = iupAttribGetFloat(ih, "XMAX");
+ double dx = iupAttribGetFloat(ih, "DX");
+ if (value < xmin) value = xmin;
+ if (value > xmax-dx) value = xmax-dx;
+
+ posx = value;
+ ih->data->posx = (float)posx;
+ posy = ih->data->posy;
+
+ cb = (IFniff)IupGetCallback(ih,"SCROLL_CB");
+ if (cb)
+ {
+ int op = gtkCanvasScroll2Iup(scroll, 0);
+ if (op == -1)
+ return FALSE;
+
+ cb(ih, op, (float)posx, (float)posy);
+ }
+ else
+ {
+ IFnff cb = (IFnff)IupGetCallback(ih,"ACTION");
+ if (cb)
+ cb (ih, (float)posx, (float)posy);
+ }
+
+ (void)range;
+ return FALSE;
+}
+
+static gboolean gtkCanvasVChangeValue(GtkRange *range, GtkScrollType scroll, double value, Ihandle *ih)
+{
+ double posx, posy;
+ IFniff cb;
+
+ double ymin = iupAttribGetFloat(ih, "YMIN");
+ double ymax = iupAttribGetFloat(ih, "YMAX");
+ double dy = iupAttribGetFloat(ih, "DY");
+ if (value < ymin) value = ymin;
+ if (value > ymax-dy) value = ymax-dy;
+
+ posy = value;
+ ih->data->posy = (float)posy;
+ posx = ih->data->posx;
+
+ cb = (IFniff)IupGetCallback(ih,"SCROLL_CB");
+ if (cb)
+ {
+ int op = gtkCanvasScroll2Iup(scroll, 1);
+ if (op == -1)
+ return FALSE;
+
+ cb(ih, op, (float)posx, (float)posy);
+ }
+ else
+ {
+ IFnff cb = (IFnff)IupGetCallback(ih,"ACTION");
+ if (cb)
+ cb (ih, (float)posx, (float)posy);
+ }
+
+ (void)range;
+ return FALSE;
+}
+
+static gboolean gtkCanvasScrollEvent(GtkWidget *widget, GdkEventScroll *evt, Ihandle *ih)
+{
+ IFnfiis wcb = (IFnfiis)IupGetCallback(ih, "WHEEL_CB");
+ if (wcb)
+ {
+ int delta = evt->direction==GDK_SCROLL_UP||evt->direction==GDK_SCROLL_LEFT? 1: -1;
+ char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT;
+ int button = evt->direction==GDK_SCROLL_UP||evt->direction==GDK_SCROLL_LEFT? 4: 5;
+ iupgtkButtonKeySetStatus(evt->state, button, status, 0);
+
+ wcb(ih, (float)delta, (int)evt->x, (int)evt->y, status);
+ }
+ else
+ {
+ IFniff scb = (IFniff)IupGetCallback(ih,"SCROLL_CB");
+ int delta = evt->direction==GDK_SCROLL_UP||evt->direction==GDK_SCROLL_LEFT? 1: -1;
+
+ if (evt->direction==GDK_SCROLL_UP || evt->direction==GDK_SCROLL_DOWN)
+ {
+ float posy = ih->data->posy;
+ posy -= delta*iupAttribGetFloat(ih, "DY")/10.0f;
+ IupSetfAttribute(ih, "POSY", "%g", posy);
+ }
+ else
+ {
+ float posx = ih->data->posx;
+ posx -= delta*iupAttribGetFloat(ih, "DX")/10.0f;
+ IupSetfAttribute(ih, "POSX", "%g", posx);
+ }
+
+ if (scb)
+ {
+ int scroll_gtk2iup[4] = {IUP_SBUP, IUP_SBDN, IUP_SBLEFT, IUP_SBRIGHT};
+ int op = scroll_gtk2iup[evt->direction];
+ scb(ih,op,ih->data->posx,ih->data->posy);
+ }
+ }
+ (void)widget;
+ return TRUE;
+}
+
+static gboolean gtkCanvasButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih)
+{
+ if (evt->type == GDK_BUTTON_PRESS)
+ {
+ /* Force focus on canvas click */
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ gtk_widget_grab_focus(ih->handle);
+ }
+
+ return iupgtkButtonEvent(widget, evt, ih);
+}
+
+static int gtkCanvasSetBgColorAttrib(Ihandle* ih, const char* value);
+
+static gboolean gtkCanvasExposeEvent(GtkWidget *widget, GdkEventExpose *evt, Ihandle *ih)
+{
+ IFnff cb = (IFnff)IupGetCallback(ih,"ACTION");
+ if (cb)
+ {
+ if (!iupAttribGet(ih, "_IUPGTK_NO_BGCOLOR"))
+ gtkCanvasSetBgColorAttrib(ih, iupAttribGetStr(ih, "BGCOLOR")); /* reset to update window attributes */
+
+ iupAttribSetStrf(ih, "CLIPRECT", "%d %d %d %d", evt->area.x, evt->area.y, evt->area.x+evt->area.width-1, evt->area.y+evt->area.height-1);
+ cb(ih,ih->data->posx,ih->data->posy);
+ iupAttribSetStr(ih, "CLIPRECT", NULL);
+ }
+
+ (void)widget;
+ return TRUE; /* stop other handlers */
+}
+
+static gboolean gtkCanvasConfigureEvent(GtkWidget *widget, GdkEventConfigure *evt, Ihandle *ih)
+{
+ IFnii cb = (IFnii)IupGetCallback(ih,"RESIZE_CB");
+ if (cb)
+ cb(ih,evt->width,evt->height);
+
+ (void)widget;
+ return FALSE;
+}
+
+static GtkScrolledWindow* gtkCanvasGetScrolledWindow(Ihandle* ih)
+{
+ return (GtkScrolledWindow*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+}
+
+static int gtkCanvasSetXAutoHideAttrib(Ihandle* ih, const char *value)
+{
+ GtkPolicyType vscrollbar_policy;
+ gtk_scrolled_window_get_policy(gtkCanvasGetScrolledWindow(ih), NULL, &vscrollbar_policy);
+
+ if (ih->data->sb & IUP_SB_HORIZ)
+ {
+ GtkPolicyType hscrollbar_policy;
+
+ if (iupStrBoolean(value))
+ hscrollbar_policy = GTK_POLICY_AUTOMATIC;
+ else
+ hscrollbar_policy = GTK_POLICY_ALWAYS;
+
+ gtk_scrolled_window_set_policy(gtkCanvasGetScrolledWindow(ih), hscrollbar_policy, vscrollbar_policy);
+ }
+ else
+ gtk_scrolled_window_set_policy(gtkCanvasGetScrolledWindow(ih), GTK_POLICY_NEVER, vscrollbar_policy);
+
+ return 1;
+}
+
+static int gtkCanvasSetYAutoHideAttrib(Ihandle* ih, const char *value)
+{
+ GtkPolicyType hscrollbar_policy;
+ gtk_scrolled_window_get_policy(gtkCanvasGetScrolledWindow(ih), &hscrollbar_policy, NULL);
+
+ if (ih->data->sb & IUP_SB_VERT)
+ {
+ GtkPolicyType vscrollbar_policy;
+
+ if (iupStrBoolean(value))
+ vscrollbar_policy = GTK_POLICY_AUTOMATIC;
+ else
+ vscrollbar_policy = GTK_POLICY_ALWAYS;
+
+ gtk_scrolled_window_set_policy(gtkCanvasGetScrolledWindow(ih), hscrollbar_policy, vscrollbar_policy);
+ }
+ else
+ gtk_scrolled_window_set_policy(gtkCanvasGetScrolledWindow(ih), hscrollbar_policy, GTK_POLICY_NEVER);
+
+ return 1;
+}
+
+static int gtkCanvasCheckScroll(double min, double max, double *page, double *pos)
+{
+ double old_pos = *pos;
+ double range = max-min;
+ if (*page > range) *page = range;
+ if (*page <= 0) *page = range/10.;
+
+ if (*pos < min) *pos = min;
+ if (*pos > (max - *page)) *pos = max - *page;
+
+ if (old_pos == *pos)
+ return 0;
+ else
+ return 1;
+}
+
+static int gtkCanvasSetDXAttrib(Ihandle* ih, const char *value)
+{
+ if (ih->data->sb & IUP_SB_HORIZ)
+ {
+ double xmin, xmax, linex;
+ float dx;
+ int value_changed;
+ GtkAdjustment* sb_horiz = gtk_scrolled_window_get_hadjustment(gtkCanvasGetScrolledWindow(ih));
+ if (!sb_horiz) return 1;
+
+ if (!iupStrToFloat(value, &dx))
+ return 1;
+
+ xmin = iupAttribGetFloat(ih, "XMIN");
+ xmax = iupAttribGetFloat(ih, "XMAX");
+
+ if (!iupAttribGet(ih,"LINEX"))
+ {
+ linex = dx/10;
+ if (linex==0)
+ linex = 1;
+ }
+ else
+ linex = iupAttribGetFloat(ih,"LINEX");
+
+ sb_horiz->lower = xmin;
+ sb_horiz->upper = xmax;
+ sb_horiz->step_increment = linex;
+ sb_horiz->page_size = dx;
+
+ value_changed = gtkCanvasCheckScroll(xmin, xmax, &sb_horiz->page_size, &sb_horiz->value);
+ sb_horiz->page_increment = sb_horiz->page_size;
+
+ gtk_adjustment_changed(sb_horiz);
+
+ if (value_changed)
+ gtk_adjustment_value_changed(sb_horiz);
+ }
+ return 1;
+}
+
+static int gtkCanvasSetDYAttrib(Ihandle* ih, const char *value)
+{
+ if (ih->data->sb & IUP_SB_VERT)
+ {
+ double ymin, ymax, liney;
+ float dy;
+ int value_changed;
+ GtkAdjustment* sb_vert = gtk_scrolled_window_get_vadjustment(gtkCanvasGetScrolledWindow(ih));
+ if (!sb_vert) return 1;
+
+ if (!iupStrToFloat(value, &dy))
+ return 1;
+
+ ymin = iupAttribGetFloat(ih, "YMIN");
+ ymax = iupAttribGetFloat(ih, "YMAX");
+
+ if (!iupAttribGet(ih,"LINEY"))
+ {
+ liney = dy/10;
+ if (liney==0)
+ liney = 1;
+ }
+ else
+ liney = iupAttribGetFloat(ih,"LINEY");
+
+ sb_vert->lower = ymin;
+ sb_vert->upper = ymax;
+ sb_vert->step_increment = liney;
+ sb_vert->page_size = dy;
+
+ value_changed = gtkCanvasCheckScroll(ymin, ymax, &sb_vert->page_size, &sb_vert->value);
+ sb_vert->page_increment = sb_vert->page_size;
+
+ gtk_adjustment_changed(sb_vert);
+
+ if (value_changed)
+ gtk_adjustment_value_changed(sb_vert);
+ }
+ return 1;
+}
+
+static int gtkCanvasSetPosXAttrib(Ihandle* ih, const char *value)
+{
+ if (ih->data->sb & IUP_SB_HORIZ)
+ {
+ float posx, xmin, xmax, dx;
+ GtkAdjustment* sb_horiz = gtk_scrolled_window_get_hadjustment(gtkCanvasGetScrolledWindow(ih));
+ if (!sb_horiz) return 1;
+
+ if (!iupStrToFloat(value, &posx))
+ return 1;
+
+ xmin = iupAttribGetFloat(ih, "XMIN");
+ xmax = iupAttribGetFloat(ih, "XMAX");
+ dx = iupAttribGetFloat(ih, "DX");
+
+ if (posx < xmin) posx = xmin;
+ if (posx > (xmax - dx)) posx = xmax - dx;
+ ih->data->posx = posx;
+
+ gtk_adjustment_set_value(sb_horiz, posx);
+ }
+ return 1;
+}
+
+static int gtkCanvasSetPosYAttrib(Ihandle* ih, const char *value)
+{
+ if (ih->data->sb & IUP_SB_VERT)
+ {
+ float posy, ymin, ymax, dy;
+ GtkAdjustment* sb_vert = gtk_scrolled_window_get_vadjustment(gtkCanvasGetScrolledWindow(ih));
+ if (!sb_vert) return 1;
+
+ if (!iupStrToFloat(value, &posy))
+ return 1;
+
+ ymin = iupAttribGetFloat(ih, "YMIN");
+ ymax = iupAttribGetFloat(ih, "YMAX");
+ dy = iupAttribGetFloat(ih, "DY");
+
+ if (posy < ymin) posy = ymin;
+ if (posy > (ymax - dy)) posy = ymax - dy;
+ ih->data->posy = posy;
+
+ gtk_adjustment_set_value(sb_vert, posy);
+ }
+ return 1;
+}
+
+static int gtkCanvasSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ GtkScrolledWindow* scrolled_window = gtkCanvasGetScrolledWindow(ih);
+ unsigned char r, g, b;
+
+ /* ignore given value, must use only from parent for the scrollbars */
+ char* parent_value = iupBaseNativeParentGetBgColor(ih);
+
+ if (iupStrToRGB(parent_value, &r, &g, &b))
+ {
+ GtkWidget* sb;
+
+ iupgtkBaseSetBgColor((GtkWidget*)scrolled_window, r, g, b);
+
+#if GTK_CHECK_VERSION(2, 8, 0)
+ sb = gtk_scrolled_window_get_hscrollbar(scrolled_window);
+ if (sb) iupgtkBaseSetBgColor(sb, r, g, b);
+ sb = gtk_scrolled_window_get_vscrollbar(scrolled_window);
+ if (sb) iupgtkBaseSetBgColor(sb, r, g, b);
+#endif
+ }
+
+ if (!IupGetCallback(ih, "ACTION"))
+ {
+ /* enable automatic double buffering */
+ gtk_widget_set_double_buffered(ih->handle, TRUE);
+ gtk_widget_set_double_buffered((GtkWidget*)scrolled_window, TRUE);
+ return iupdrvBaseSetBgColorAttrib(ih, value);
+ }
+ else
+ {
+ /* disable automatic double buffering */
+ gtk_widget_set_double_buffered(ih->handle, FALSE);
+ gtk_widget_set_double_buffered((GtkWidget*)scrolled_window, FALSE);
+ gdk_window_set_back_pixmap(ih->handle->window, NULL, FALSE);
+ iupAttribSetStr(ih, "_IUPGTK_NO_BGCOLOR", "1");
+ return 1;
+ }
+}
+
+static char* gtkCanvasGetDrawableAttrib(Ihandle* ih)
+{
+ return (char*)ih->handle->window;
+}
+
+static void gtkCanvasDummyLogFunc(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
+{
+ /* does nothing */
+ (void)log_domain;
+ (void)log_level;
+ (void)message;
+ (void)user_data;
+}
+
+static int gtkCanvasMapMethod(Ihandle* ih)
+{
+ GtkScrolledWindow* scrolled_window;
+ void* visual;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ ih->data->sb = iupBaseGetScrollbar(ih);
+
+ visual = (void*)IupGetAttribute(ih, "VISUAL"); /* defined by the OpenGL Canvas in X11 or NULL */
+ if (visual)
+ iupgtkPushVisualAndColormap(visual, (void*)iupAttribGet(ih, "COLORMAP"));
+
+ ih->handle = gtk_drawing_area_new();
+
+ if (visual)
+ gtk_widget_pop_colormap();
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ scrolled_window = (GtkScrolledWindow*)gtk_scrolled_window_new(NULL, NULL);
+ if (!scrolled_window)
+ return IUP_ERROR;
+
+ {
+ /* to avoid the "cannot add non scrollable widget" warning */
+#if GTK_CHECK_VERSION(2, 6, 0)
+ GLogFunc def_func = g_log_set_default_handler(gtkCanvasDummyLogFunc, NULL);
+#endif
+ gtk_container_add((GtkContainer*)scrolled_window, ih->handle);
+#if GTK_CHECK_VERSION(2, 6, 0)
+ g_log_set_default_handler(def_func, NULL);
+#endif
+ }
+
+ gtk_widget_show((GtkWidget*)scrolled_window);
+
+ iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)scrolled_window);
+
+ /* add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-release-event", G_CALLBACK(iupgtkKeyReleaseEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "expose-event", G_CALLBACK(gtkCanvasExposeEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "button-press-event", G_CALLBACK(gtkCanvasButtonEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "button-release-event",G_CALLBACK(gtkCanvasButtonEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "motion-notify-event",G_CALLBACK(iupgtkMotionNotifyEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "scroll-event",G_CALLBACK(gtkCanvasScrollEvent), ih);
+
+#if GTK_CHECK_VERSION(2, 8, 0)
+ g_signal_connect(G_OBJECT(gtk_scrolled_window_get_hscrollbar(scrolled_window)), "change-value",G_CALLBACK(gtkCanvasHChangeValue), ih);
+ g_signal_connect(G_OBJECT(gtk_scrolled_window_get_vscrollbar(scrolled_window)), "change-value",G_CALLBACK(gtkCanvasVChangeValue), ih);
+#endif
+
+ /* To receive mouse events on a drawing area, you will need to enable them. */
+ gtk_widget_add_events(ih->handle, GDK_EXPOSURE_MASK|
+ GDK_POINTER_MOTION_MASK|GDK_BUTTON_MOTION_MASK|
+ GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK|
+ GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK|
+ GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK|
+ GDK_FOCUS_CHANGE_MASK|GDK_STRUCTURE_MASK);
+
+ /* To receive keyboard events, you will need to set the GTK_CAN_FOCUS flag on the drawing area. */
+ if (ih->iclass->is_interactive)
+ {
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ GTK_WIDGET_FLAGS(ih->handle) |= GTK_CAN_FOCUS;
+ }
+
+ if (iupAttribGetBoolean(ih, "BORDER"))
+ gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_IN);
+ else
+ gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_NONE);
+
+ gtk_widget_realize((GtkWidget*)scrolled_window);
+ gtk_widget_realize(ih->handle);
+
+ /* must be connected after realize or a RESIZE_CB will happen before MAP_CB
+ works only for the GtkDrawingArea. */
+ g_signal_connect(G_OBJECT(ih->handle), "configure-event", G_CALLBACK(gtkCanvasConfigureEvent), ih);
+
+ /* configure for DRAG&DROP */
+ if (IupGetCallback(ih, "DROPFILES_CB"))
+ iupAttribSetStr(ih, "DRAGDROP", "YES");
+
+ /* update a mnemonic in a label if necessary */
+ iupgtkUpdateMnemonic(ih);
+
+ /* configure scrollbar */
+ if (ih->data->sb)
+ {
+ GtkPolicyType hscrollbar_policy = GTK_POLICY_NEVER, vscrollbar_policy = GTK_POLICY_NEVER;
+ if (ih->data->sb & IUP_SB_HORIZ)
+ hscrollbar_policy = GTK_POLICY_AUTOMATIC;
+ if (ih->data->sb & IUP_SB_VERT)
+ vscrollbar_policy = GTK_POLICY_AUTOMATIC;
+ gtk_scrolled_window_set_policy(scrolled_window, hscrollbar_policy, vscrollbar_policy);
+ }
+ else
+ gtk_scrolled_window_set_policy(scrolled_window, GTK_POLICY_NEVER, GTK_POLICY_NEVER);
+
+ /* force the update of BGCOLOR here, to let derived classes ignore it if ACTION is defined */
+ gtkCanvasSetBgColorAttrib(ih, iupAttribGetStr(ih, "BGCOLOR"));
+
+ return IUP_NOERROR;
+}
+
+void iupdrvCanvasInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkCanvasMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkCanvasSetBgColorAttrib, "255 255 255", NULL, IUPAF_DEFAULT); /* force new default value */
+
+ /* IupCanvas only */
+ iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupgtkSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CURSOR", NULL, iupdrvBaseSetCursorAttrib, IUPAF_SAMEASSYSTEM, "ARROW", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DRAWSIZE", iupdrvBaseGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "DX", NULL, gtkCanvasSetDXAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "DY", NULL, gtkCanvasSetDYAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "POSX", iupCanvasGetPosXAttrib, gtkCanvasSetPosXAttrib, "0.0", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "POSY", iupCanvasGetPosYAttrib, gtkCanvasSetPosYAttrib, "0.0", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "XAUTOHIDE", NULL, gtkCanvasSetXAutoHideAttrib, "YES", NULL, IUPAF_DEFAULT); /* force new default value */
+ iupClassRegisterAttribute(ic, "YAUTOHIDE", NULL, gtkCanvasSetYAutoHideAttrib, "YES", NULL, IUPAF_DEFAULT); /* force new default value */
+
+ iupClassRegisterAttribute(ic, "DRAWABLE", gtkCanvasGetDrawableAttrib, NULL, NULL, NULL, IUPAF_NO_STRING);
+ //iupClassRegisterAttribute(ic, "CD_GDK", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT);
+
+ /* IupCanvas Windows or X only */
+#ifdef WIN32
+ iupClassRegisterAttribute(ic, "HWND", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_NO_INHERIT);
+#else
+ iupClassRegisterAttribute(ic, "XWINDOW", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+ iupClassRegisterAttribute(ic, "XDISPLAY", (IattribGetFunc)iupdrvGetDisplay, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+#endif
+}
+
diff --git a/iup/src/gtk/iupgtk_clipboard.c b/iup/src/gtk/iupgtk_clipboard.c
new file mode 100755
index 0000000..f07a3e6
--- /dev/null
+++ b/iup/src/gtk/iupgtk_clipboard.c
@@ -0,0 +1,125 @@
+/** \file
+ * \brief Clipboard for the GTK Driver.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <gtk/gtk.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_image.h"
+
+#include "iupgtk_drv.h"
+
+
+static int gtkClipboardSetTextAttrib(Ihandle *ih, const char *value)
+{
+ GtkClipboard *clipboard = gtk_clipboard_get_for_display(gdk_display_get_default(), gdk_atom_intern("CLIPBOARD", FALSE));
+ gtk_clipboard_set_text(clipboard, value, -1);
+ (void)ih;
+ return 0;
+}
+
+static char* gtkClipboardGetTextAttrib(Ihandle *ih)
+{
+ GtkClipboard *clipboard = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE));
+ (void)ih;
+ return iupgtkStrConvertFromUTF8(gtk_clipboard_wait_for_text(clipboard));
+}
+
+static int gtkClipboardSetImageAttrib(Ihandle *ih, const char *value)
+{
+#if GTK_CHECK_VERSION(2, 6, 0)
+ GtkClipboard *clipboard = gtk_clipboard_get (gdk_atom_intern("CLIPBOARD", FALSE));
+ GdkPixbuf *pixbuf = (GdkPixbuf*)iupImageGetImage(value, ih, 0);
+ if (pixbuf)
+ gtk_clipboard_set_image (clipboard, pixbuf);
+#endif
+ return 0;
+}
+
+static int gtkClipboardSetNativeImageAttrib(Ihandle *ih, const char *value)
+{
+#if GTK_CHECK_VERSION(2, 6, 0)
+ GtkClipboard *clipboard;
+ (void)ih;
+
+ if (!value)
+ return 0;
+
+ clipboard = gtk_clipboard_get (gdk_atom_intern("CLIPBOARD", FALSE));
+
+ gtk_clipboard_set_image (clipboard, (GdkPixbuf*)value);
+#endif
+ return 0;
+}
+
+static char* gtkClipboardGetNativeImageAttrib(Ihandle *ih)
+{
+#if GTK_CHECK_VERSION(2, 6, 0)
+ GtkClipboard *clipboard = gtk_clipboard_get (gdk_atom_intern("CLIPBOARD", FALSE));
+ (void)ih;
+ return (char*)gtk_clipboard_wait_for_image (clipboard);
+#else
+ return NULL;
+#endif
+}
+
+static char* gtkClipboardGetTextAvailableAttrib(Ihandle *ih)
+{
+ GtkClipboard *clipboard = gtk_clipboard_get (gdk_atom_intern("CLIPBOARD", FALSE));
+ (void)ih;
+ if (gtk_clipboard_wait_is_text_available(clipboard))
+ return "YES";
+ else
+ return "NO";
+}
+
+static char* gtkClipboardGetImageAvailableAttrib(Ihandle *ih)
+{
+#if GTK_CHECK_VERSION(2, 6, 0)
+ GtkClipboard *clipboard = gtk_clipboard_get (gdk_atom_intern("CLIPBOARD", FALSE));
+ (void)ih;
+ if (gtk_clipboard_wait_is_image_available(clipboard))
+ return "YES";
+ else
+ return "NO";
+#else
+ return NULL;
+#endif
+}
+
+/******************************************************************************/
+
+Ihandle* IupClipboard(void)
+{
+ return IupCreate("clipboard");
+}
+
+Iclass* iupClipboardGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "clipboard";
+ ic->format = NULL; /* no parameters */
+ ic->nativetype = IUP_TYPECONTROL;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 0;
+
+ /* Attribute functions */
+ iupClassRegisterAttribute(ic, "TEXT", gtkClipboardGetTextAttrib, gtkClipboardSetTextAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "NATIVEIMAGE", gtkClipboardGetNativeImageAttrib, gtkClipboardSetNativeImageAttrib, NULL, NULL, IUPAF_NO_STRING|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, gtkClipboardSetImageAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TEXTAVAILABLE", gtkClipboardGetTextAvailableAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGEAVAILABLE", gtkClipboardGetImageAvailableAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ return ic;
+}
diff --git a/iup/src/gtk/iupgtk_colordlg.c b/iup/src/gtk/iupgtk_colordlg.c
new file mode 100755
index 0000000..9177f91
--- /dev/null
+++ b/iup/src/gtk/iupgtk_colordlg.c
@@ -0,0 +1,211 @@
+/** \file
+ * \brief IupColorDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include <string.h>
+#include <memory.h>
+#include <stdio.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+
+#include "iupgtk_drv.h"
+
+
+static char* gtkColorDlgPaletteToString(const char* palette)
+{
+ char iup_str[20], *gtk_str, *palette_p;
+ char* str = iupStrGetMemory(300);
+ int off = 0, inc;
+ GdkColor color;
+
+ gtk_str = iupStrDup(palette);
+ iupStrReplace(gtk_str, ':', 0);
+
+ while (palette && *palette)
+ {
+ if (!gdk_color_parse (gtk_str, &color))
+ return NULL;
+
+ inc = sprintf(iup_str, "%d %d %d;", (int)iupCOLOR16TO8(color.red), (int)iupCOLOR16TO8(color.green), (int)iupCOLOR16TO8(color.blue));
+ memcpy(str+off, iup_str, inc);
+ off += inc;
+ palette_p = strchr(palette, ':');
+ if (palette_p)
+ {
+ palette_p++;
+ gtk_str += palette_p-palette;
+ }
+ palette = palette_p;
+ }
+ str[off-1] = 0; /* remove last separator */
+ return str;
+}
+
+static void gtkColorDlgGetPalette(Ihandle* ih, GtkColorSelection* colorsel)
+{
+ char *palette, *str;
+
+ GtkSettings *settings = gtk_widget_get_settings(GTK_WIDGET(colorsel));
+ g_object_get(settings, "gtk-color-palette", &palette, NULL);
+
+ str = gtkColorDlgPaletteToString(palette);
+ if (str) iupAttribStoreStr(ih, "COLORTABLE", str);
+ g_free(palette);
+}
+
+static char* gtkColorDlgStringToPalette(const char* str)
+{
+ char gtk_str[20];
+ char* palette = iupStrGetMemory(200);
+ int off = 0;
+ unsigned char r, g, b;
+
+ while (str && *str)
+ {
+ if (!iupStrToRGB(str, &r, &g, &b))
+ return NULL;
+
+ sprintf(gtk_str, "#%02X%02X%02X:", (int)r, (int)g, (int)b);
+ memcpy(palette+off, gtk_str, 8);
+ off += 8;
+ str = strchr(str, ';');
+ if (str) str++;
+ }
+ palette[off-1] = 0; /* remove last separator */
+ return palette;
+}
+
+static void gtkColorDlgSetPalette(GtkColorSelection* colorsel, char* str)
+{
+ GtkSettings *settings = gtk_widget_get_settings(GTK_WIDGET(colorsel));
+ gchar* palette = gtkColorDlgStringToPalette(str);
+ if (palette)
+ gtk_settings_set_string_property(settings,
+ "gtk-color-palette",
+ palette,
+ "gtk_color_selection_palette_to_string");
+}
+
+static int gtkColorDlgPopup(Ihandle* ih, int x, int y)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ GtkColorSelectionDialog* dialog;
+ GtkColorSelection* colorsel;
+ GdkColor color;
+ char *value;
+ unsigned char r = 0, g = 0, b = 0, a = 255;
+ int response, ret;
+
+ iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */
+ iupAttribSetInt(ih, "_IUPDLG_Y", y);
+
+ dialog = (GtkColorSelectionDialog*)gtk_color_selection_dialog_new(iupgtkStrConvertToUTF8(iupAttribGet(ih, "TITLE")));
+ if (!dialog)
+ return IUP_ERROR;
+
+ if (parent)
+ gtk_window_set_transient_for((GtkWindow*)dialog, (GtkWindow*)parent);
+
+ ret = iupStrToRGBA(iupAttribGet(ih, "VALUE"), &r, &g, &b, &a);
+
+ colorsel = (GtkColorSelection*)dialog->colorsel;
+ iupgdkColorSet(&color, r, g, b);
+ gtk_color_selection_set_current_color(colorsel, &color);
+
+ value = iupAttribGetStr(ih, "ALPHA");
+ if (value)
+ {
+ int alpha;
+ if (iupStrToInt(value, &alpha))
+ {
+ if (alpha<0) alpha=0;
+ if (alpha>255) alpha=255;
+ gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
+ gtk_color_selection_set_current_alpha(colorsel, iupCOLOR8TO16(alpha));
+ }
+ }
+ else if (iupAttribGetBoolean(ih, "SHOWALPHA") || ret == 4)
+ {
+ gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
+ gtk_color_selection_set_current_alpha(colorsel, iupCOLOR8TO16(a));
+ }
+ else
+ gtk_color_selection_set_has_opacity_control(colorsel, FALSE);
+
+ value = iupAttribGetStr(ih, "COLORTABLE");
+ if (value)
+ {
+ gtk_color_selection_set_has_palette (colorsel, TRUE);
+ gtkColorDlgSetPalette(colorsel, value);
+ }
+ else if (iupAttribGetBoolean(ih, "SHOWCOLORTABLE"))
+ gtk_color_selection_set_has_palette (colorsel, TRUE);
+ else
+ gtk_color_selection_set_has_palette (colorsel, FALSE);
+
+ if (IupGetCallback(ih, "HELP_CB"))
+ gtk_widget_show(dialog->help_button);
+
+ /* initialize the widget */
+ gtk_widget_realize(GTK_WIDGET(dialog));
+
+ ih->handle = GTK_WIDGET(dialog);
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL;
+
+ do
+ {
+ response = gtk_dialog_run(GTK_DIALOG(dialog));
+
+ if (response == GTK_RESPONSE_HELP)
+ {
+ Icallback cb = IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ response = GTK_RESPONSE_CANCEL;
+ }
+ } while (response == GTK_RESPONSE_HELP);
+
+ if (response == GTK_RESPONSE_OK)
+ {
+ GdkColor color;
+ gtk_color_selection_get_current_color(colorsel, &color);
+ IupSetAttribute(ih, "STATUS", "1");
+
+ if (gtk_color_selection_get_has_opacity_control(colorsel))
+ {
+ int alpha = gtk_color_selection_get_current_alpha(colorsel);
+ iupAttribSetInt(ih, "ALPHA", (int)iupCOLOR16TO8(alpha));
+ iupAttribSetStrf(ih, "VALUE", "%d %d %d %d", (int)iupCOLOR16TO8(color.red), (int)iupCOLOR16TO8(color.green), (int)iupCOLOR16TO8(color.blue), (int)iupCOLOR16TO8(alpha));
+ }
+ else
+ iupAttribSetStrf(ih, "VALUE", "%d %d %d", (int)iupCOLOR16TO8(color.red), (int)iupCOLOR16TO8(color.green), (int)iupCOLOR16TO8(color.blue));
+
+ if (gtk_color_selection_get_has_palette(colorsel))
+ gtkColorDlgGetPalette(ih, colorsel);
+ }
+ else
+ {
+ iupAttribSetStr(ih, "ALPHA", NULL);
+ iupAttribSetStr(ih, "VALUE", NULL);
+ iupAttribSetStr(ih, "COLORTABLE", NULL);
+ iupAttribSetStr(ih, "STATUS", NULL);
+ }
+
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+
+ return IUP_NOERROR;
+}
+
+void iupdrvColorDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = gtkColorDlgPopup;
+}
diff --git a/iup/src/gtk/iupgtk_common.c b/iup/src/gtk/iupgtk_common.c
new file mode 100755
index 0000000..40368f2
--- /dev/null
+++ b/iup/src/gtk/iupgtk_common.c
@@ -0,0 +1,830 @@
+/** \file
+ * \brief GTK Base Functions
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <gtk/gtk.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+#include "iupkey.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_key.h"
+#include "iup_str.h"
+#include "iup_class.h"
+#include "iup_attrib.h"
+#include "iup_focus.h"
+#include "iup_key.h"
+#include "iup_image.h"
+#include "iup_drv.h"
+
+#include "iupgtk_drv.h"
+
+
+/* WARNING: in GTK there are many controls that are not native windows,
+ so "->window" will NOT return a native window exclusive of that control,
+ in fact it can return a base native window shared by many controls.
+ IupCanvas is a special case that uses an exclusive native window. */
+
+/* GTK only has abssolute positioning using a GtkFixed container,
+ so all elements returned by iupChildTreeGetNativeParentHandle should be a GtkFixed.
+ If not looks in the native parent. */
+static GtkFixed* gtkGetFixedParent(Ihandle* ih)
+{
+ GtkWidget* widget = iupChildTreeGetNativeParentHandle(ih);
+ while (widget && !GTK_IS_FIXED(widget))
+ widget = gtk_widget_get_parent(widget);
+ return (GtkFixed*)widget;
+}
+
+void iupgtkUpdateMnemonic(Ihandle* ih)
+{
+ GtkLabel* label = (GtkLabel*)iupAttribGet(ih, "_IUPGTK_LABELMNEMONIC");
+ if (label) gtk_label_set_mnemonic_widget(label, ih->handle);
+}
+
+void iupdrvActivate(Ihandle* ih)
+{
+ gtk_widget_activate(ih->handle);
+}
+
+void iupdrvReparent(Ihandle* ih)
+{
+ GtkFixed* fixed = gtkGetFixedParent(ih);
+ GtkWidget* widget = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (!widget) widget = ih->handle;
+ gtk_widget_reparent(widget, (GtkWidget*)fixed);
+}
+
+void iupgtkBaseAddToParent(Ihandle* ih)
+{
+ GtkFixed* fixed = gtkGetFixedParent(ih);
+ GtkWidget* widget = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (!widget) widget = ih->handle;
+
+ gtk_fixed_put(fixed, widget, 0, 0);
+}
+
+void iupdrvBaseLayoutUpdateMethod(Ihandle *ih)
+{
+ GtkFixed* fixed = gtkGetFixedParent(ih);
+ GtkWidget* widget = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (!widget) widget = ih->handle;
+
+ gtk_fixed_move(fixed, widget, ih->x, ih->y);
+ gtk_widget_set_size_request(widget, ih->currentwidth, ih->currentheight);
+}
+
+void iupdrvBaseUnMapMethod(Ihandle* ih)
+{
+ GtkWidget* widget = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (!widget) widget = ih->handle;
+ gtk_widget_unrealize(widget);
+ gtk_widget_destroy(widget); /* To match the call to gtk_*****_new */
+}
+
+void iupdrvDisplayUpdate(Ihandle *ih)
+{
+ /* Post a REDRAW */
+ gtk_widget_queue_draw(ih->handle);
+}
+
+void iupdrvDisplayRedraw(Ihandle *ih)
+{
+ GdkWindow* window = ih->handle->window;
+ /* Post a REDRAW */
+ gtk_widget_queue_draw(ih->handle);
+ /* Force a REDRAW */
+ if (window)
+ gdk_window_process_updates(window, FALSE);
+}
+
+void iupdrvScreenToClient(Ihandle* ih, int *x, int *y)
+{
+ gint win_x = 0, win_y = 0;
+ GdkWindow* window = ih->handle->window;
+ if (window)
+ gdk_window_get_origin(window, &win_x, &win_y);
+ *x = *x - win_x;
+ *y = *y - win_y;
+}
+
+gboolean iupgtkShowHelp(GtkWidget *widget, GtkWidgetHelpType *arg1, Ihandle *ih)
+{
+ Icallback cb;
+ (void)widget;
+ (void)arg1;
+
+ cb = IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ IupExitLoop();
+
+ return FALSE;
+}
+
+gboolean iupgtkEnterLeaveEvent(GtkWidget *widget, GdkEventCrossing *evt, Ihandle *ih)
+{
+ Icallback cb = NULL;
+ (void)widget;
+
+ if (evt->type == GDK_ENTER_NOTIFY)
+ cb = IupGetCallback(ih, "ENTERWINDOW_CB");
+ else if (evt->type == GDK_LEAVE_NOTIFY)
+ cb = IupGetCallback(ih, "LEAVEWINDOW_CB");
+
+ if (cb)
+ cb(ih);
+
+ return FALSE;
+}
+
+int iupgtkSetMnemonicTitle(Ihandle* ih, GtkLabel* label, const char* value)
+{
+ char c = '_';
+ char* str;
+
+ if (!value)
+ value = "";
+
+ str = iupStrProcessMnemonic(value, &c, 1); /* replace & by c, the returned value of c is ignored in GTK */
+ if (str != value)
+ {
+ gtk_label_set_text_with_mnemonic(label, iupgtkStrConvertToUTF8(str));
+ free(str);
+ return 1;
+ }
+ else
+ {
+ if (iupAttribGetBoolean(ih, "MARKUP"))
+ gtk_label_set_markup(label, iupgtkStrConvertToUTF8(str));
+ else
+ gtk_label_set_text(label, iupgtkStrConvertToUTF8(str));
+ }
+ return 0;
+}
+
+int iupdrvBaseSetZorderAttrib(Ihandle* ih, const char* value)
+{
+ if (iupdrvIsVisible(ih))
+ {
+ GdkWindow* window = ih->handle->window;
+ if (iupStrEqualNoCase(value, "TOP"))
+ gdk_window_raise(window);
+ else
+ gdk_window_lower(window);
+ }
+
+ return 0;
+}
+
+void iupdrvSetVisible(Ihandle* ih, int visible)
+{
+ GtkWidget* container = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (visible)
+ {
+ if (container) gtk_widget_show(container);
+ gtk_widget_show(ih->handle);
+ }
+ else
+ {
+ if (container) gtk_widget_hide(container);
+ gtk_widget_hide(ih->handle);
+ }
+}
+
+int iupdrvIsVisible(Ihandle* ih)
+{
+ if (GTK_WIDGET_VISIBLE(ih->handle))
+ {
+ /* if marked as visible, since we use gtk_widget_hide and NOT gtk_widget_hide_all
+ must check its parents. */
+ Ihandle* parent = ih->parent;
+ while (parent)
+ {
+ if (parent->iclass->nativetype != IUP_TYPEVOID)
+ {
+ if (!GTK_WIDGET_VISIBLE(parent->handle))
+ return 0;
+ }
+
+ parent = parent->parent;
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+int iupdrvIsActive(Ihandle *ih)
+{
+ return (GTK_WIDGET_IS_SENSITIVE(ih->handle));
+}
+
+void iupdrvSetActive(Ihandle* ih, int enable)
+{
+ GtkWidget* container = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (container) gtk_widget_set_sensitive(container, enable);
+ gtk_widget_set_sensitive(ih->handle, enable);
+}
+
+char* iupdrvBaseGetXAttrib(Ihandle *ih)
+{
+ GdkWindow* window = ih->handle->window;
+ GtkWidget* container = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (container) window = container->window;
+
+ if (window)
+ {
+ char* str = iupStrGetMemory(20);
+ int x, y;
+ gdk_window_get_origin(window, &x, &y);
+ x += ih->handle->allocation.x;
+ sprintf(str, "%d", x);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+char* iupdrvBaseGetYAttrib(Ihandle *ih)
+{
+ GdkWindow* window = ih->handle->window;
+ GtkWidget* container = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (container) window = container->window;
+
+ if (window)
+ {
+ char* str = iupStrGetMemory(20);
+ int x, y;
+ gdk_window_get_origin(window, &x, &y);
+ y += ih->handle->allocation.y;
+ sprintf(str, "%d", y);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+char* iupdrvBaseGetClientSizeAttrib(Ihandle *ih)
+{
+ char* str = iupStrGetMemory(20);
+ int w, h;
+ GdkWindow* window = ih->handle->window;
+
+ if (window)
+ gdk_drawable_get_size(window, &w, &h);
+ else
+ return NULL;
+
+ sprintf(str, "%dx%d", w, h);
+ return str;
+}
+
+static GdkColor gtkDarkerColor(GdkColor *color)
+{
+ GdkColor dark_color = {0L,0,0,0};
+
+ dark_color.red = (color->red*9)/10;
+ dark_color.green = (color->green*9)/10;
+ dark_color.blue = (color->blue*9)/10;
+
+ return dark_color;
+}
+
+static guint16 gtkCROP16(int x)
+{
+ if (x > 65535) return 65535;
+ return (guint16)x;
+}
+
+static GdkColor gtkLighterColor(GdkColor *color)
+{
+ GdkColor light_color = {0L,0,0,0};
+
+ light_color.red = gtkCROP16(((int)color->red*11)/10);
+ light_color.green = gtkCROP16(((int)color->green*11)/10);
+ light_color.blue = gtkCROP16(((int)color->blue*11)/10);
+
+ return light_color;
+}
+
+void iupgtkBaseSetBgColor(InativeHandle* handle, unsigned char r, unsigned char g, unsigned char b)
+{
+ GtkRcStyle *rc_style;
+ GdkColor color;
+
+ iupgdkColorSet(&color, r, g, b);
+
+ rc_style = gtk_widget_get_modifier_style(handle);
+ rc_style->base[GTK_STATE_NORMAL] = rc_style->bg[GTK_STATE_NORMAL] = rc_style->bg[GTK_STATE_INSENSITIVE] = color;
+ rc_style->bg[GTK_STATE_ACTIVE] = rc_style->base[GTK_STATE_ACTIVE] = gtkDarkerColor(&color);
+ rc_style->base[GTK_STATE_PRELIGHT] = rc_style->bg[GTK_STATE_PRELIGHT] = rc_style->base[GTK_STATE_INSENSITIVE] = gtkLighterColor(&color);
+
+ rc_style->color_flags[GTK_STATE_NORMAL] |= GTK_RC_BASE | GTK_RC_BG;
+ rc_style->color_flags[GTK_STATE_ACTIVE] |= GTK_RC_BASE | GTK_RC_BG;
+ rc_style->color_flags[GTK_STATE_PRELIGHT] |= GTK_RC_BASE | GTK_RC_BG;
+ rc_style->color_flags[GTK_STATE_INSENSITIVE] |= GTK_RC_BASE | GTK_RC_BG;
+
+ gtk_widget_modify_style(handle, rc_style);
+}
+
+int iupdrvBaseSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgtkBaseSetBgColor(ih->handle, r, g, b);
+
+ /* DO NOT NEED TO UPDATE GTK IMAGES SINCE THEY DO NOT DEPEND ON BGCOLOR */
+
+ return 1;
+}
+
+void iupgtkBaseSetFgGdkColor(InativeHandle* handle, GdkColor *color)
+{
+ GtkRcStyle *rc_style;
+
+ rc_style = gtk_widget_get_modifier_style(handle);
+ rc_style->fg[GTK_STATE_ACTIVE] = rc_style->fg[GTK_STATE_NORMAL] = rc_style->fg[GTK_STATE_PRELIGHT] = *color;
+ rc_style->text[GTK_STATE_ACTIVE] = rc_style->text[GTK_STATE_NORMAL] = rc_style->text[GTK_STATE_PRELIGHT] = *color;
+ rc_style->color_flags[GTK_STATE_NORMAL] |= GTK_RC_TEXT | GTK_RC_FG;
+ rc_style->color_flags[GTK_STATE_ACTIVE] |= GTK_RC_TEXT | GTK_RC_FG;
+ rc_style->color_flags[GTK_STATE_PRELIGHT] |= GTK_RC_TEXT | GTK_RC_FG;
+
+ /* do not set at CHILD_CONTAINER */
+ gtk_widget_modify_style(handle, rc_style);
+}
+
+void iupgtkBaseSetFgColor(InativeHandle* handle, unsigned char r, unsigned char g, unsigned char b)
+{
+ GdkColor color;
+ iupgdkColorSet(&color, r, g, b);
+ iupgtkBaseSetFgGdkColor(handle, &color);
+}
+
+int iupdrvBaseSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgtkBaseSetFgColor(ih->handle, r, g, b);
+
+ return 1;
+}
+
+static GdkCursor* gtkEmptyCursor(Ihandle* ih)
+{
+ /* creates an empty cursor */
+ GdkColor cursor_color = {0L,0,0,0};
+ char bitsnull[1] = {0x00};
+
+ GdkWindow* window = ih->handle->window;
+ GdkPixmap* pixmapnull = gdk_bitmap_create_from_data(
+ (GdkDrawable*)window,
+ bitsnull,
+ 1,1);
+ GdkCursor* cur = gdk_cursor_new_from_pixmap(
+ pixmapnull,
+ pixmapnull,
+ &cursor_color,
+ &cursor_color,
+ 0,0);
+
+ g_object_unref(pixmapnull);
+
+ return cur;
+}
+
+static GdkCursor* gtkGetCursor(Ihandle* ih, const char* name)
+{
+ static struct {
+ const char* iupname;
+ int sysname;
+ } table[] = {
+ { "NONE", 0},
+ { "NULL", 0},
+ { "ARROW", GDK_LEFT_PTR},
+ { "BUSY", GDK_WATCH},
+ { "CROSS", GDK_CROSSHAIR},
+ { "HAND", GDK_HAND2},
+ { "HELP", GDK_QUESTION_ARROW},
+ { "IUP", GDK_QUESTION_ARROW},
+ { "MOVE", GDK_FLEUR},
+ { "PEN", GDK_PENCIL},
+ { "RESIZE_N", GDK_TOP_SIDE},
+ { "RESIZE_S", GDK_BOTTOM_SIDE},
+ { "RESIZE_NS", GDK_SB_V_DOUBLE_ARROW},
+ { "RESIZE_W", GDK_LEFT_SIDE},
+ { "RESIZE_E", GDK_RIGHT_SIDE},
+ { "RESIZE_WE", GDK_SB_H_DOUBLE_ARROW},
+ { "RESIZE_NE", GDK_TOP_RIGHT_CORNER},
+ { "RESIZE_SE", GDK_BOTTOM_RIGHT_CORNER},
+ { "RESIZE_NW", GDK_TOP_LEFT_CORNER},
+ { "RESIZE_SW", GDK_BOTTOM_LEFT_CORNER},
+ { "TEXT", GDK_XTERM},
+ { "UPARROW", GDK_CENTER_PTR}
+ };
+
+ GdkCursor* cur;
+ char str[50];
+ int i, count = sizeof(table)/sizeof(table[0]);
+
+ /* check the cursor cache first (per control)*/
+ sprintf(str, "_IUPGTK_CURSOR_%s", name);
+ cur = (GdkCursor*)iupAttribGet(ih, str);
+ if (cur)
+ return cur;
+
+ /* check the pre-defined IUP names first */
+ for (i = 0; i < count; i++)
+ {
+ if (iupStrEqualNoCase(name, table[i].iupname))
+ {
+ if (table[i].sysname)
+ cur = gdk_cursor_new(table[i].sysname);
+ else
+ cur = gtkEmptyCursor(ih);
+
+ break;
+ }
+ }
+
+ if (i == count)
+ {
+ /* check for a name defined cursor */
+ cur = iupImageGetCursor(name);
+ }
+
+ /* save the cursor in cache */
+ iupAttribSetStr(ih, str, (char*)cur);
+
+ return cur;
+}
+
+int iupdrvBaseSetCursorAttrib(Ihandle* ih, const char* value)
+{
+ GdkCursor* cur = gtkGetCursor(ih, value);
+ if (cur)
+ {
+ GdkWindow* window = ih->handle->window;
+ if (window)
+ gdk_window_set_cursor(window, cur);
+ return 1;
+ }
+ return 0;
+}
+
+void iupgdkColorSet(GdkColor* color, unsigned char r, unsigned char g, unsigned char b)
+{
+ color->red = iupCOLOR8TO16(r);
+ color->green = iupCOLOR8TO16(g);
+ color->blue = iupCOLOR8TO16(b);
+ color->pixel = 0;
+}
+
+static void gtkDragDataReceived(GtkWidget* w, GdkDragContext* context, int x, int y,
+ GtkSelectionData* seldata, guint info, guint time, Ihandle* ih)
+{
+ gchar **uris = NULL;
+ int i, count;
+
+ IFnsiii cb = (IFnsiii)IupGetCallback(ih, "DROPFILES_CB");
+ if (!cb) return;
+
+#if GTK_CHECK_VERSION(2, 6, 0)
+ uris = g_uri_list_extract_uris((char*)seldata->data);
+#endif
+
+ if (!uris)
+ return;
+
+ count = 0;
+ while (uris[count])
+ count++;
+
+ for (i=0; i<count; i++)
+ {
+ char* filename = uris[i];
+ if (iupStrEqualPartial(filename, "file://"))
+ {
+ filename += strlen("file://");
+ if (filename[2] == ':') /* in Windows there is an extra '/' at the begining. */
+ filename++;
+ }
+ if (cb(ih, filename, count-i-1, x, y) == IUP_IGNORE)
+ break;
+ }
+
+ g_strfreev (uris);
+ (void)time;
+ (void)info;
+ (void)w;
+ (void)context;
+}
+
+int iupgtkSetDragDropAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value))
+ {
+ GtkTargetEntry dragtypes[] = { { "text/uri-list", 0, 0 } };
+ gtk_drag_dest_set(ih->handle, GTK_DEST_DEFAULT_ALL, dragtypes,
+ sizeof(dragtypes) / sizeof(dragtypes[0]), GDK_ACTION_COPY);
+ g_signal_connect(G_OBJECT(ih->handle), "drag_data_received", G_CALLBACK(gtkDragDataReceived), ih);
+ }
+ else
+ {
+ gtk_drag_dest_unset(ih->handle);
+ }
+ return 1;
+}
+
+int iupdrvGetScrollbarSize(void)
+{
+ static int size = 0;
+
+ if (size == 0)
+ {
+ GtkRequisition requisition;
+ GtkWidget* win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ GtkWidget* sb = gtk_vscrollbar_new(NULL);
+ gtk_container_add((GtkContainer*)win, sb);
+ gtk_widget_realize(win);
+ gtk_widget_size_request(sb, &requisition);
+ size = requisition.width;
+ gtk_widget_destroy(win);
+ }
+
+ return size;
+}
+
+void iupdrvDrawFocusRect(Ihandle* ih, void* _gc, int x, int y, int w, int h)
+{
+ GdkWindow* window = ih->handle->window;
+ GtkStyle *style = gtk_widget_get_style(ih->handle);
+ (void)_gc;
+
+ gtk_paint_focus(style, window, GTK_WIDGET_STATE(ih->handle), NULL, ih->handle, NULL, x, y, w, h);
+}
+
+void iupdrvBaseRegisterCommonAttrib(Iclass* ic)
+{
+#ifdef WIN32
+ iupClassRegisterAttribute(ic, "HFONT", iupgtkGetFontIdAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+#else
+ iupClassRegisterAttribute(ic, "XFONTID", iupgtkGetFontIdAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+#endif
+ iupClassRegisterAttribute(ic, "PANGOFONTDESC", iupgtkGetPangoFontDescAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+}
+
+static int gtkStrIsAscii(const char* str)
+{
+ while(*str)
+ {
+ int c = *str;
+ if (c < 0)
+ return 0;
+ str++;
+ }
+ return 1;
+}
+
+static char* gtkStrToUTF8(const char *str, const char* charset)
+{
+ return g_convert(str, -1, "UTF-8", charset, NULL, NULL, NULL);
+}
+
+static char* gtkStrFromUTF8(const char *str, const char* charset)
+{
+ return g_convert(str, -1, charset, "UTF-8", NULL, NULL, NULL);
+}
+
+static char* gktLastConvertUTF8 = NULL;
+
+void iupgtkReleaseConvertUTF8(void)
+{
+ if (gktLastConvertUTF8)
+ g_free(gktLastConvertUTF8);
+}
+
+char* iupgtkStrConvertToUTF8(const char* str) /* From IUP to GTK */
+{
+ if (!str || *str == 0)
+ return (char*)str;
+
+ if (iupgtk_utf8autoconvert) /* this means str is in current locale */
+ {
+ const char *charset = NULL;
+ if (g_get_charset(&charset)==TRUE) /* current locale is already UTF-8 */
+ {
+ if (g_utf8_validate(str, -1, NULL))
+ return (char*)str;
+ else
+ {
+ if (gktLastConvertUTF8)
+ g_free(gktLastConvertUTF8);
+ gktLastConvertUTF8 = gtkStrToUTF8(str, "ISO8859-1"); /* if string is not UTF-8, assume ISO8859-1 */
+ if (!gktLastConvertUTF8) return (char*)str;
+ return gktLastConvertUTF8;
+ }
+ }
+ else
+ {
+ if (gtkStrIsAscii(str) || !charset)
+ return (char*)str;
+ else if (charset)
+ {
+ if (gktLastConvertUTF8)
+ g_free(gktLastConvertUTF8);
+ gktLastConvertUTF8 = gtkStrToUTF8(str, charset);
+ if (!gktLastConvertUTF8) return (char*)str;
+ return gktLastConvertUTF8;
+ }
+ }
+ }
+ return (char*)str;
+}
+
+char* iupgtkStrConvertFromUTF8(const char* str) /* From GTK to IUP */
+{
+ if (!str || *str == 0)
+ return (char*)str;
+
+ if (iupgtk_utf8autoconvert) /* this means str is in current locale */
+ {
+ const gchar *charset = NULL;
+ if (g_get_charset(&charset)==TRUE) /* current locale is already UTF-8 */
+ {
+ if (g_utf8_validate(str, -1, NULL))
+ return (char*)str;
+ else
+ {
+ if (gktLastConvertUTF8)
+ g_free(gktLastConvertUTF8);
+ gktLastConvertUTF8 = gtkStrFromUTF8(str, "ISO8859-1"); /* if string is not UTF-8, assume ISO8859-1 */
+ if (!gktLastConvertUTF8) return (char*)str;
+ return gktLastConvertUTF8;
+ }
+ }
+ else
+ {
+ if (gtkStrIsAscii(str) || !charset)
+ return (char*)str;
+ else if (charset)
+ {
+ if (gktLastConvertUTF8)
+ g_free(gktLastConvertUTF8);
+ gktLastConvertUTF8 = gtkStrFromUTF8(str, charset);
+ if (!gktLastConvertUTF8) return (char*)str;
+ return gktLastConvertUTF8;
+ }
+ }
+ }
+ return (char*)str;
+}
+
+static gboolean gtkGetFilenameCharset(const gchar **filename_charset)
+{
+ const gchar **charsets = NULL;
+ gboolean is_utf8 = FALSE;
+
+#if GTK_CHECK_VERSION(2, 6, 0)
+ is_utf8 = g_get_filename_charsets (&charsets);
+#endif
+
+ if (filename_charset && charsets)
+ *filename_charset = charsets[0];
+
+ return is_utf8;
+}
+
+char* iupgtkStrConvertToFilename(const char* str) /* From IUP to Filename */
+{
+ if (!str || *str == 0)
+ return (char*)str;
+
+ if (iupgtk_utf8autoconvert) /* this means str is in current locale */
+ return (char*)str;
+ else
+ {
+ const gchar *charset = NULL;
+ if (gtkGetFilenameCharset(&charset)==TRUE) /* current locale is already UTF-8 */
+ {
+ if (g_utf8_validate(str, -1, NULL))
+ return (char*)str;
+ else
+ {
+ if (gktLastConvertUTF8)
+ g_free(gktLastConvertUTF8);
+ gktLastConvertUTF8 = gtkStrFromUTF8(str, "ISO8859-1"); /* if string is not UTF-8, assume ISO8859-1 */
+ if (!gktLastConvertUTF8) return (char*)str;
+ return gktLastConvertUTF8;
+ }
+ }
+ else
+ {
+ if (gtkStrIsAscii(str) || !charset)
+ return (char*)str;
+ else if (charset)
+ {
+ if (gktLastConvertUTF8)
+ g_free(gktLastConvertUTF8);
+ gktLastConvertUTF8 = gtkStrFromUTF8(str, charset);
+ if (!gktLastConvertUTF8) return (char*)str;
+ return gktLastConvertUTF8;
+ }
+ }
+ }
+ return (char*)str;
+}
+
+char* iupgtkStrConvertFromFilename(const char* str) /* From Filename to IUP */
+{
+ if (!str || *str == 0)
+ return (char*)str;
+
+ if (iupgtk_utf8autoconvert) /* this means str is in current locale */
+ return (char*)str;
+ else
+ {
+ const char *charset = NULL;
+ if (gtkGetFilenameCharset(&charset)==TRUE) /* current locale is already UTF-8 */
+ {
+ if (g_utf8_validate(str, -1, NULL))
+ return (char*)str;
+ else
+ {
+ if (gktLastConvertUTF8)
+ g_free(gktLastConvertUTF8);
+ gktLastConvertUTF8 = gtkStrToUTF8(str, "ISO8859-1"); /* if string is not UTF-8, assume ISO8859-1 */
+ if (!gktLastConvertUTF8) return (char*)str;
+ return gktLastConvertUTF8;
+ }
+ }
+ else
+ {
+ if (gtkStrIsAscii(str) || !charset)
+ return (char*)str;
+ else if (charset)
+ {
+ if (gktLastConvertUTF8)
+ g_free(gktLastConvertUTF8);
+ gktLastConvertUTF8 = gtkStrToUTF8(str, charset);
+ if (!gktLastConvertUTF8) return (char*)str;
+ return gktLastConvertUTF8;
+ }
+ }
+ }
+ return (char*)str;
+}
+
+gboolean iupgtkMotionNotifyEvent(GtkWidget *widget, GdkEventMotion *evt, Ihandle *ih)
+{
+ IFniis cb = (IFniis)IupGetCallback(ih,"MOTION_CB");
+ if (cb)
+ {
+ char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT;
+ iupgtkButtonKeySetStatus(evt->state, 0, status, 0);
+ cb(ih, (int)evt->x, (int)evt->y, status);
+ }
+
+ (void)widget;
+ return FALSE;
+}
+
+gboolean iupgtkButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih)
+{
+ IFniiiis cb = (IFniiiis)IupGetCallback(ih,"BUTTON_CB");
+ if (cb)
+ {
+ int doubleclick = 0, ret, press = 1;
+ int b = IUP_BUTTON1+(evt->button-1);
+ char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT;
+
+ if (evt->type == GDK_BUTTON_RELEASE)
+ press = 0;
+
+ if (evt->type == GDK_2BUTTON_PRESS)
+ doubleclick = 1;
+
+ iupgtkButtonKeySetStatus(evt->state, evt->button, status, doubleclick);
+
+ ret = cb(ih, b, press, (int)evt->x, (int)evt->y, status);
+ if (ret==IUP_CLOSE)
+ IupExitLoop();
+ else if (ret==IUP_IGNORE)
+ return TRUE;
+ }
+
+ (void)widget;
+ return FALSE;
+}
diff --git a/iup/src/gtk/iupgtk_dialog.c b/iup/src/gtk/iupgtk_dialog.c
new file mode 100755
index 0000000..46c0ce1
--- /dev/null
+++ b/iup/src/gtk/iupgtk_dialog.c
@@ -0,0 +1,1023 @@
+/** \file
+ * \brief IupDialog class
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#ifdef HILDON
+#include <hildon/hildon-program.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <time.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_class.h"
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_dlglist.h"
+#include "iup_attrib.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_drvinfo.h"
+#include "iup_focus.h"
+#include "iup_str.h"
+#define _IUPDLG_PRIVATE
+#include "iup_dialog.h"
+#include "iup_image.h"
+
+#include "iupgtk_drv.h"
+
+
+static void gtkDialogSetMinMax(Ihandle* ih, int min_w, int min_h, int max_w, int max_h);
+
+/****************************************************************
+ Utilities
+****************************************************************/
+
+int iupdrvDialogIsVisible(Ihandle* ih)
+{
+ return iupdrvIsVisible(ih);
+}
+
+void iupdrvDialogUpdateSize(Ihandle* ih)
+{
+ int width, height;
+ gtk_window_get_size((GtkWindow*)ih->handle, &width, &height);
+ ih->currentwidth = width;
+ ih->currentheight = height;
+}
+
+void iupdrvDialogGetSize(InativeHandle* handle, int *w, int *h)
+{
+ int width, height;
+ gtk_window_get_size((GtkWindow*)handle, &width, &height);
+ if (w) *w = width;
+ if (h) *h = height;
+}
+
+void iupdrvDialogSetVisible(Ihandle* ih, int visible)
+{
+ if (visible)
+ gtk_widget_show(ih->handle);
+ else
+ gtk_widget_hide(ih->handle);
+}
+
+void iupdrvDialogGetPosition(InativeHandle* handle, int *x, int *y)
+{
+ gtk_window_get_position((GtkWindow*)handle, x, y);
+}
+
+void iupdrvDialogSetPosition(Ihandle *ih, int x, int y)
+{
+ gtk_window_move((GtkWindow*)ih->handle, x, y);
+}
+
+static int gtkDialogGetMenuSize(Ihandle* ih)
+{
+#ifdef HILDON
+ return 0;
+#else
+ if (ih->data->menu)
+ return iupdrvMenuGetMenuBarSize(ih->data->menu);
+ else
+ return 0;
+#endif
+}
+
+static int gtkDialogGetWindowDecor(Ihandle* ih, int *win_border, int *win_caption)
+{
+ int x, y, frame_x, frame_y;
+ gdk_window_get_origin(ih->handle->window, &x, &y);
+ gdk_window_get_root_origin(ih->handle->window, &frame_x, &frame_y);
+ *win_border = x-frame_x;
+ *win_caption = y-frame_y-*win_border;
+ return 1; /* just for compatibility with iupdrvGetWindowDecor */
+}
+
+void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu)
+{
+#ifdef HILDON
+ /* In Hildon, borders have fixed dimensions, but are drawn as part
+ of the client area! */
+ if (border)
+ *border = (iupAttribGetBoolean(ih, "HILDONWINDOW") && !iupAttribGetBoolean(ih, "FULLSCREEN")) ? 12 : 0;
+ if (caption)
+ *caption = 0;
+ if (menu)
+ *menu = 0;
+#else
+ static int native_border = 0;
+ static int native_caption = 0;
+
+ int has_caption = iupAttribGetBoolean(ih, "MAXBOX") ||
+ iupAttribGetBoolean(ih, "MINBOX") ||
+ iupAttribGetBoolean(ih, "MENUBOX") ||
+ IupGetAttribute(ih, "TITLE"); /* must use IupGetAttribute to check from the native implementation */
+
+ int has_border = has_caption ||
+ iupAttribGetBoolean(ih, "RESIZE") ||
+ iupAttribGetBoolean(ih, "BORDER");
+
+ *menu = gtkDialogGetMenuSize(ih);
+
+ if (ih->handle && iupdrvIsVisible(ih))
+ {
+ int win_border, win_caption;
+
+ if (gtkDialogGetWindowDecor(ih, &win_border, &win_caption))
+ {
+#ifdef WIN32
+ if (*menu)
+ win_caption -= *menu;
+#endif
+
+ *border = 0;
+ if (has_border)
+ *border = win_border;
+
+ *caption = 0;
+ if (has_caption)
+ *caption = win_caption;
+
+ if (!native_border && *border)
+ native_border = win_border;
+
+ if (!native_caption && *caption)
+ native_caption = win_caption;
+ }
+ }
+
+ /* I could not set the size of the window including the decorations when the dialog is hidden */
+ /* So we have to estimate the size of borders and caption when the dialog is hidden */
+
+ *border = 0;
+ if (has_border)
+ {
+ if (native_border)
+ *border = native_border;
+ else
+ *border = 5;
+ }
+
+ *caption = 0;
+ if (has_caption)
+ {
+ if (native_caption)
+ *caption = native_caption;
+ else
+ *caption = 20;
+ }
+#endif
+}
+
+int iupdrvDialogSetPlacement(Ihandle* ih)
+{
+ char* placement;
+ int old_state = ih->data->show_state;
+ ih->data->show_state = IUP_SHOW;
+
+ if (iupAttribGetBoolean(ih, "FULLSCREEN"))
+ {
+ gtk_window_fullscreen((GtkWindow*)ih->handle);
+ return 1;
+ }
+
+ placement = iupAttribGet(ih, "PLACEMENT");
+ if (!placement)
+ {
+ if (old_state == IUP_MAXIMIZE || old_state == IUP_MINIMIZE)
+ ih->data->show_state = IUP_RESTORE;
+
+ gtk_window_unmaximize((GtkWindow*)ih->handle);
+ gtk_window_deiconify((GtkWindow*)ih->handle);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(placement, "MINIMIZED"))
+ {
+ ih->data->show_state = IUP_MINIMIZE;
+ gtk_window_iconify((GtkWindow*)ih->handle);
+ }
+ else if (iupStrEqualNoCase(placement, "MAXIMIZED"))
+ {
+ ih->data->show_state = IUP_MAXIMIZE;
+ gtk_window_maximize((GtkWindow*)ih->handle);
+ }
+ else if (iupStrEqualNoCase(placement, "FULL"))
+ {
+ int width, height, x, y;
+ int border, caption, menu;
+ iupdrvDialogGetDecoration(ih, &border, &caption, &menu);
+
+ /* position the decoration outside the screen */
+ x = -(border);
+ y = -(border+caption+menu);
+
+ /* the dialog client area will cover the task bar */
+ iupdrvGetFullSize(&width, &height);
+
+ height += menu; /* menu is inside the client area. */
+
+ /* set the new size and position */
+ /* The resize evt will update the layout */
+ gtk_window_move((GtkWindow*)ih->handle, x, y);
+ gtk_window_resize((GtkWindow*)ih->handle, width, height);
+
+ if (old_state == IUP_MAXIMIZE || old_state == IUP_MINIMIZE)
+ ih->data->show_state = IUP_RESTORE;
+ }
+
+ iupAttribSetStr(ih, "PLACEMENT", NULL); /* reset to NORMAL */
+
+ return 1;
+}
+
+
+/****************************************************************
+ Callbacks and Events
+****************************************************************/
+
+
+gboolean iupgtkDialogDeleteEvent(GtkWidget *widget, GdkEvent *evt, Ihandle *ih)
+{
+ Icallback cb;
+ (void)widget;
+ (void)evt;
+
+ /* even when ACTIVE=NO the dialog gets this evt */
+ if (!iupdrvIsActive(ih))
+ return TRUE;
+
+ cb = IupGetCallback(ih, "CLOSE_CB");
+ if (cb)
+ {
+ int ret = cb(ih);
+ if (ret == IUP_IGNORE)
+ return TRUE;
+ if (ret == IUP_CLOSE)
+ IupExitLoop();
+ }
+
+ IupHide(ih); /* default: close the window */
+
+ return TRUE; /* do not propagate */
+}
+
+static gboolean gtkDialogConfigureEvent(GtkWidget *widget, GdkEventConfigure *evt, Ihandle *ih)
+{
+ int old_width, old_height, old_x, old_y;
+ gint x, y;
+ (void)widget;
+
+#ifndef HILDON
+ /* In hildon the menu is not a menubar */
+ if (ih->data->menu && ih->data->menu->handle)
+ gtk_widget_set_size_request(ih->data->menu->handle, evt->width, -1);
+#endif
+
+ if (ih->data->ignore_resize) return FALSE;
+
+ old_width = iupAttribGetInt(ih, "_IUPGTK_OLD_WIDTH");
+ old_height = iupAttribGetInt(ih, "_IUPGTK_OLD_HEIGHT");
+
+ /* Check the size change, because configure is called also for position changes */
+ if (evt->width != old_width || evt->height != old_height)
+ {
+ IFnii cb;
+ int border, caption, menu;
+ iupAttribSetInt(ih, "_IUPGTK_OLD_WIDTH", evt->width);
+ iupAttribSetInt(ih, "_IUPGTK_OLD_HEIGHT", evt->height);
+
+ iupdrvDialogGetDecoration(ih, &border, &caption, &menu);
+
+ /* update dialog size */
+#ifdef HILDON
+ /* In Hildon, the configure event contains the window size, not the client area size */
+ ih->currentwidth = evt->width;
+ ih->currentheight = evt->height;
+#else
+ ih->currentwidth = evt->width + 2*border;
+ ih->currentheight = evt->height + 2*border + caption; /* menu is inside the window client area */
+#endif
+
+ cb = (IFnii)IupGetCallback(ih, "RESIZE_CB");
+ if (!cb || cb(ih, evt->width, evt->height - menu)!=IUP_IGNORE) /* width and height here are for the client area */
+ {
+ ih->data->ignore_resize = 1;
+ IupRefresh(ih);
+ ih->data->ignore_resize = 0;
+ }
+ }
+
+ old_x = iupAttribGetInt(ih, "_IUPGTK_OLD_X");
+ old_y = iupAttribGetInt(ih, "_IUPGTK_OLD_Y");
+ gtk_window_get_position((GtkWindow*)ih->handle, &x, &y); /* ignore evt->x and evt->y because they are the clientpos and not X/Y */
+
+ /* Check the position change, because configure is called also for size changes */
+ if (x != old_x || y != old_y)
+ {
+ IFnii cb;
+ iupAttribSetInt(ih, "_IUPGTK_OLD_X", x);
+ iupAttribSetInt(ih, "_IUPGTK_OLD_Y", y);
+
+ cb = (IFnii)IupGetCallback(ih, "MOVE_CB");
+ if (cb)
+ cb(ih, x, y);
+ }
+
+ return FALSE;
+}
+
+static gboolean gtkDialogWindowStateEvent(GtkWidget *widget, GdkEventWindowState *evt, Ihandle *ih)
+{
+ int state = -1;
+ (void)widget;
+
+ if ((evt->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) && /* if flag changed and */
+ (evt->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) && /* is now set */
+ !(evt->new_window_state & GDK_WINDOW_STATE_WITHDRAWN)) /* is visible */
+ state = IUP_MAXIMIZE;
+ else if ((evt->changed_mask & GDK_WINDOW_STATE_ICONIFIED) &&
+ (evt->new_window_state & GDK_WINDOW_STATE_ICONIFIED) &&
+ !(evt->new_window_state & GDK_WINDOW_STATE_WITHDRAWN))
+ state = IUP_MINIMIZE;
+ else if ((evt->changed_mask & GDK_WINDOW_STATE_ICONIFIED) &&
+ (evt->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) &&
+ !(evt->new_window_state & GDK_WINDOW_STATE_WITHDRAWN))
+ state = IUP_MAXIMIZE;
+ else if (((evt->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) && /* maximized changed */
+ !(evt->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) && /* not maximized */
+ !(evt->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) && /* is visible */
+ !(evt->new_window_state & GDK_WINDOW_STATE_ICONIFIED)) /* not minimized */
+ || /* OR */
+ ((evt->changed_mask & GDK_WINDOW_STATE_ICONIFIED) && /* minimized changed */
+ !(evt->new_window_state & GDK_WINDOW_STATE_ICONIFIED) && /* not minimized */
+ !(evt->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) && /* is visible */
+ !(evt->new_window_state & GDK_WINDOW_STATE_MAXIMIZED))) /* not maximized */
+ state = IUP_RESTORE;
+
+ if (state < 0)
+ return FALSE;
+
+ if (ih->data->show_state != state)
+ {
+ IFni cb;
+ ih->data->show_state = state;
+
+ cb = (IFni)IupGetCallback(ih, "SHOW_CB");
+ if (cb && cb(ih, state) == IUP_CLOSE)
+ IupExitLoop();
+ }
+
+ return FALSE;
+}
+
+static gboolean gtkDialogChildDestroyEvent(GtkWidget *widget, Ihandle *ih)
+{
+ /* It seems that the documentation for this callback is not correct */
+ /* The second parameter must be the user_data or it will fail. */
+ (void)widget;
+
+ /* If the IUP dialog was not destroyed, destroy it here. */
+ if (iupObjectCheck(ih))
+ IupDestroy(ih);
+
+ /* this callback is usefull to destroy children dialogs when the parent is destroyed. */
+ /* The application is responsable for destroying the children before this happen. */
+
+ return FALSE;
+}
+
+
+/****************************************************************
+ Idialog Methods
+****************************************************************/
+
+
+/* replace the common dialog SetChildrenPosition method because of
+ the menu that it is inside the dialog. */
+static void gtkDialogSetChildrenPositionMethod(Ihandle* ih, int x, int y)
+{
+ int menu_h = gtkDialogGetMenuSize(ih);
+ (void)x;
+ (void)y;
+
+ /* Child coordinates are relative to client left-top corner. */
+ iupBaseSetPosition(ih->firstchild, 0, menu_h);
+}
+
+static void* gtkDialogGetInnerNativeContainerHandleMethod(Ihandle* ih, Ihandle* child)
+{
+ (void)child;
+ return (void*)gtk_bin_get_child((GtkBin*)ih->handle);
+}
+
+static int gtkDialogMapMethod(Ihandle* ih)
+{
+ int decorations = 0;
+ int functions = 0;
+ InativeHandle* parent;
+ GtkWidget* fixed;
+
+#ifdef HILDON
+ if (iupAttribGetBoolean(ih, "HILDONWINDOW"))
+ {
+ HildonProgram *program = HILDON_PROGRAM(hildon_program_get_instance());
+ ih->handle = hildon_window_new();
+ if (ih->handle)
+ hildon_program_add_window(program, HILDON_WINDOW(ih->handle));
+ }
+ else
+ {
+ iupAttribSetStr(ih, "DIALOGHINT", "YES"); /* otherwise not displayed correctly */
+ ih->handle = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ }
+#else
+ ih->handle = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+#endif
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ parent = iupDialogGetNativeParent(ih);
+ if (parent)
+ {
+ gtk_window_set_transient_for((GtkWindow*)ih->handle, (GtkWindow*)parent);
+
+ /* manually remove child windows when parent is destroyed */
+ g_signal_connect(G_OBJECT(parent), "destroy", G_CALLBACK(gtkDialogChildDestroyEvent), ih);
+ }
+
+ g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+
+ /* The iupgtkKeyPressEvent of the control with the focus will propagate the key up to the dialog. */
+ /* Inside iupgtkKeyPressEvent we test this to avoid duplicate calls. */
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "configure-event", G_CALLBACK(gtkDialogConfigureEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "window-state-event", G_CALLBACK(gtkDialogWindowStateEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "delete-event", G_CALLBACK(iupgtkDialogDeleteEvent), ih);
+
+ gtk_window_set_default_size((GtkWindow*)ih->handle, 100, 100); /* set this to avoid size calculation problems */
+
+ if (iupAttribGetBoolean(ih, "DIALOGHINT"))
+ gtk_window_set_type_hint(GTK_WINDOW(ih->handle), GDK_WINDOW_TYPE_HINT_DIALOG);
+
+ /* the container that will receive the child element. */
+ fixed = gtk_fixed_new();
+ gtk_container_add((GtkContainer*)ih->handle, fixed);
+ gtk_widget_show(fixed);
+
+ /* initialize the widget */
+ gtk_widget_realize(ih->handle);
+
+ if (iupAttribGetBoolean(ih, "DIALOGFRAME")) {
+ iupAttribSetStr(ih, "RESIZE", "NO");
+ }
+
+ if (!iupAttribGetBoolean(ih, "RESIZE")) {
+ iupAttribSetStr(ih, "MAXBOX", "NO"); /* Must also remove these, so RESIZE=NO can work */
+ iupAttribSetStr(ih, "MINBOX", "NO");
+ }
+
+ if (IupGetAttribute(ih, "TITLE")) { /* must use IupGetAttribute to check from the native implementation */
+ functions |= GDK_FUNC_MOVE;
+ decorations |= GDK_DECOR_TITLE;
+ }
+
+ if (iupAttribGetBoolean(ih, "MENUBOX")) {
+ functions |= GDK_FUNC_CLOSE;
+ decorations |= GDK_DECOR_MENU;
+ }
+
+ if (iupAttribGetBoolean(ih, "MINBOX")) {
+ functions |= GDK_FUNC_MINIMIZE;
+ decorations |= GDK_DECOR_MINIMIZE;
+ }
+
+ if (iupAttribGetBoolean(ih, "MAXBOX")) {
+ functions |= GDK_FUNC_MAXIMIZE;
+ decorations |= GDK_DECOR_MAXIMIZE;
+ }
+
+ if (iupAttribGetBoolean(ih, "RESIZE")) {
+ functions |= GDK_FUNC_RESIZE;
+ decorations |= GDK_DECOR_RESIZEH;
+ }
+
+ if (iupAttribGetBoolean(ih, "BORDER"))
+ decorations |= GDK_DECOR_BORDER;
+
+ if (decorations == 0)
+ gtk_window_set_decorated((GtkWindow*)ih->handle, FALSE);
+ else
+ {
+ GdkWindow* window = ih->handle->window;
+ if (window)
+ {
+ gdk_window_set_decorations(window, (GdkWMDecoration)decorations);
+ gdk_window_set_functions(window, (GdkWMFunction)functions);
+ }
+ }
+
+ /* configure for DRAG&DROP */
+ if (IupGetCallback(ih, "DROPFILES_CB"))
+ iupAttribSetStr(ih, "DRAGDROP", "YES");
+
+ {
+ /* Reset the DLGBGCOLOR global attribute
+ if it is the first time a dialog is created.
+ The value returned by gtk_style_new is not accurate. */
+ GtkStyle* style = gtk_widget_get_style(ih->handle);
+ if (style && IupGetGlobal("_IUP_RESET_GLOBALCOLORS"))
+ {
+ iupgtkUpdateGlobalColors(style);
+ IupSetGlobal("_IUP_RESET_GLOBALCOLORS", NULL);
+ }
+ }
+
+ /* configure the size range */
+ gtkDialogSetMinMax(ih, 1, 1, 65535, 65535); /* MINSIZE and MAXSIZE default values */
+
+ /* Ignore VISIBLE before mapping */
+ iupAttribSetStr(ih, "VISIBLE", NULL);
+
+ return IUP_NOERROR;
+}
+
+static void gtkDialogUnMapMethod(Ihandle* ih)
+{
+ GtkWidget* fixed;
+#if GTK_CHECK_VERSION(2, 10, 0)
+ GtkStatusIcon* status_icon;
+#endif
+
+ if (ih->data->menu)
+ {
+ ih->data->menu->handle = NULL; /* the dialog will destroy the native menu */
+ IupDestroy(ih->data->menu);
+ }
+
+#if GTK_CHECK_VERSION(2, 10, 0)
+ status_icon = (GtkStatusIcon*)iupAttribGet(ih, "_IUPDLG_STATUSICON");
+ if (status_icon)
+ g_object_unref(status_icon);
+#endif
+
+ fixed = gtk_bin_get_child((GtkBin*)ih->handle);
+ gtk_widget_unrealize(fixed);
+ gtk_widget_destroy(fixed);
+
+ gtk_widget_unrealize(ih->handle); /* To match the call to gtk_widget_realize */
+ gtk_widget_destroy(ih->handle); /* To match the call to gtk_window_new */
+}
+
+static void gtkDialogLayoutUpdateMethod(Ihandle *ih)
+{
+ int border, caption, menu;
+ int width, height;
+
+ if (ih->data->ignore_resize ||
+ iupAttribGet(ih, "_IUPGTK_FS_STYLE"))
+ return;
+
+ /* for dialogs the position is not updated here */
+ ih->data->ignore_resize = 1;
+
+ iupdrvDialogGetDecoration(ih, &border, &caption, &menu);
+
+ /* set size excluding the border */
+ width = ih->currentwidth - 2*border;
+ height = ih->currentheight - 2*border - caption; /* menu is inside the client area. */
+ gtk_window_resize((GtkWindow*)ih->handle, width, height);
+
+ if (!iupAttribGetBoolean(ih, "RESIZE"))
+ {
+ GdkGeometry geometry;
+ geometry.min_width = width;
+ geometry.min_height = height;
+ geometry.max_width = width;
+ geometry.max_height = height;
+ gtk_window_set_geometry_hints((GtkWindow*)ih->handle, ih->handle,
+ &geometry, (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE));
+ }
+
+ ih->data->ignore_resize = 0;
+}
+
+
+/****************************************************************************
+ Attributes
+****************************************************************************/
+
+static void gtkDialogSetMinMax(Ihandle* ih, int min_w, int min_h, int max_w, int max_h)
+{
+ /* The minmax size restricts the client area */
+ GdkGeometry geometry;
+ int decorwidth = 0, decorheight = 0;
+ iupDialogGetDecorSize(ih, &decorwidth, &decorheight);
+
+ geometry.min_width = 1;
+ if (min_w > decorwidth)
+ geometry.min_width = min_w-decorwidth;
+
+ geometry.min_height = 1;
+ if (min_h > decorheight)
+ geometry.min_height = min_h-decorheight;
+
+ geometry.max_width = 65535;
+ if (max_w > decorwidth && max_w > geometry.min_width)
+ geometry.max_width = max_w-decorwidth;
+
+ geometry.max_height = 65535;
+ if (max_h > decorheight && max_w > geometry.min_height)
+ geometry.max_height = max_h-decorheight;
+
+ gtk_window_set_geometry_hints((GtkWindow*)ih->handle, ih->handle,
+ &geometry, (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE));
+}
+
+static int gtkDialogSetMinSizeAttrib(Ihandle* ih, const char* value)
+{
+ int min_w = 1, min_h = 1; /* MINSIZE default value */
+ int max_w = 65535, max_h = 65535; /* MAXSIZE default value */
+ iupStrToIntInt(value, &min_w, &min_h, 'x');
+
+ /* if MAXSIZE also set, must be also updated here */
+ iupStrToIntInt(iupAttribGet(ih, "MAXSIZE"), &max_w, &max_h, 'x');
+
+ gtkDialogSetMinMax(ih, min_w, min_h, max_w, max_h);
+ return 1;
+}
+
+static int gtkDialogSetMaxSizeAttrib(Ihandle* ih, const char* value)
+{
+ int min_w = 1, min_h = 1; /* MINSIZE default value */
+ int max_w = 65535, max_h = 65535; /* MAXSIZE default value */
+ iupStrToIntInt(value, &max_w, &max_h, 'x');
+
+ /* if MINSIZE also set, must be also updated here */
+ iupStrToIntInt(iupAttribGet(ih, "MINSIZE"), &min_w, &min_h, 'x');
+
+ gtkDialogSetMinMax(ih, min_w, min_h, max_w, max_h);
+ return 1;
+}
+
+static char* gtkDialogGetXAttrib(Ihandle *ih)
+{
+ char* str = iupStrGetMemory(20);
+
+ gint x = 0;
+ gtk_window_get_position((GtkWindow*)ih->handle, &x, NULL);
+
+ sprintf(str, "%d", x);
+ return str;
+}
+
+static char* gtkDialogGetYAttrib(Ihandle *ih)
+{
+ char* str = iupStrGetMemory(20);
+
+ gint y = 0;
+ gtk_window_get_position((GtkWindow*)ih->handle, NULL, &y);
+
+ sprintf(str, "%d", y);
+ return str;
+}
+
+static int gtkDialogSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ value = "";
+ gtk_window_set_title((GtkWindow*)ih->handle, iupgtkStrConvertToUTF8(value));
+ return 0;
+}
+
+static char* gtkDialogGetTitleAttrib(Ihandle* ih)
+{
+ const char* title = gtk_window_get_title((GtkWindow*)ih->handle);
+
+ if (!title || title[0] == 0)
+ return NULL;
+ else
+ return iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(title));
+}
+
+static char* gtkDialogGetClientSizeAttrib(Ihandle *ih)
+{
+ char* str = iupStrGetMemory(20);
+
+ int width, height;
+ gtk_window_get_size((GtkWindow*)ih->handle, &width, &height);
+ height -= gtkDialogGetMenuSize(ih);
+
+ sprintf(str, "%dx%d", width, height);
+ return str;
+}
+
+static int gtkDialogSetFullScreenAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value))
+ {
+ if (!iupAttribGet(ih, "_IUPGTK_FS_STYLE"))
+ {
+ /* save the previous decoration attributes */
+ /* during fullscreen these attributes can be consulted by the application */
+ iupAttribStoreStr(ih, "_IUPGTK_FS_MAXBOX", iupAttribGet(ih, "MAXBOX"));
+ iupAttribStoreStr(ih, "_IUPGTK_FS_MINBOX", iupAttribGet(ih, "MINBOX"));
+ iupAttribStoreStr(ih, "_IUPGTK_FS_MENUBOX",iupAttribGet(ih, "MENUBOX"));
+ iupAttribStoreStr(ih, "_IUPGTK_FS_RESIZE", iupAttribGet(ih, "RESIZE"));
+ iupAttribStoreStr(ih, "_IUPGTK_FS_BORDER", iupAttribGet(ih, "BORDER"));
+ iupAttribStoreStr(ih, "_IUPGTK_FS_TITLE", IupGetAttribute(ih, "TITLE")); /* must use IupGetAttribute to check from the native implementation */
+
+ /* remove the decorations attributes */
+ iupAttribSetStr(ih, "MAXBOX", "NO");
+ iupAttribSetStr(ih, "MINBOX", "NO");
+ iupAttribSetStr(ih, "MENUBOX", "NO");
+ IupSetAttribute(ih, "TITLE", NULL); iupAttribSetStr(ih, "TITLE", NULL); /* remove from the hash table if we are during IupMap */
+ iupAttribSetStr(ih, "RESIZE", "NO");
+ iupAttribSetStr(ih, "BORDER", "NO");
+
+ if (iupdrvIsVisible(ih))
+ gtk_window_fullscreen((GtkWindow*)ih->handle);
+
+ iupAttribSetStr(ih, "_IUPGTK_FS_STYLE", "YES");
+ }
+ }
+ else
+ {
+ char* fs_style = iupAttribGet(ih, "_IUPGTK_FS_STYLE");
+ if (fs_style)
+ {
+ iupAttribSetStr(ih, "_IUPGTK_FS_STYLE", NULL);
+
+ /* restore the decorations attributes */
+ iupAttribStoreStr(ih, "MAXBOX", iupAttribGet(ih, "_IUPGTK_FS_MAXBOX"));
+ iupAttribStoreStr(ih, "MINBOX", iupAttribGet(ih, "_IUPGTK_FS_MINBOX"));
+ iupAttribStoreStr(ih, "MENUBOX",iupAttribGet(ih, "_IUPGTK_FS_MENUBOX"));
+ IupSetAttribute(ih, "TITLE", iupAttribGet(ih, "_IUPGTK_FS_TITLE")); /* must use IupSetAttribute to update the native implementation */
+ iupAttribStoreStr(ih, "RESIZE", iupAttribGet(ih, "_IUPGTK_FS_RESIZE"));
+ iupAttribStoreStr(ih, "BORDER", iupAttribGet(ih, "_IUPGTK_FS_BORDER"));
+
+ if (iupdrvIsVisible(ih))
+ gtk_window_unfullscreen((GtkWindow*)ih->handle);
+
+ /* remove auxiliar attributes */
+ iupAttribSetStr(ih, "_IUPGTK_FS_MAXBOX", NULL);
+ iupAttribSetStr(ih, "_IUPGTK_FS_MINBOX", NULL);
+ iupAttribSetStr(ih, "_IUPGTK_FS_MENUBOX",NULL);
+ iupAttribSetStr(ih, "_IUPGTK_FS_RESIZE", NULL);
+ iupAttribSetStr(ih, "_IUPGTK_FS_BORDER", NULL);
+ iupAttribSetStr(ih, "_IUPGTK_FS_TITLE", NULL);
+ }
+ }
+ return 1;
+}
+
+static int gtkDialogSetTopMostAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value))
+ gtk_window_set_keep_above((GtkWindow*)ih->handle, TRUE);
+ else
+ gtk_window_set_keep_above((GtkWindow*)ih->handle, FALSE);
+ return 1;
+}
+
+#if GTK_CHECK_VERSION(2, 12, 0)
+static int gtkDialogSetOpacityAttrib(Ihandle *ih, const char *value)
+{
+ int opacity;
+ if (!iupStrToInt(value, &opacity))
+ return 0;
+
+ gtk_window_set_opacity((GtkWindow*)ih->handle, (double)opacity/255.0);
+ return 1;
+}
+#endif
+
+static int gtkDialogSetIconAttrib(Ihandle* ih, const char *value)
+{
+ if (!value)
+ gtk_window_set_icon((GtkWindow*)ih->handle, NULL);
+ else
+ {
+ GdkPixbuf* icon = (GdkPixbuf*)iupImageGetIcon(value);
+ if (icon)
+ gtk_window_set_icon((GtkWindow*)ih->handle, icon);
+ }
+ return 1;
+}
+
+static int gtkDialogSetBackgroundAttrib(Ihandle* ih, const char* value)
+{
+ if (iupdrvBaseSetBgColorAttrib(ih, value))
+ {
+ GtkStyle *style = gtk_widget_get_style(ih->handle);
+ if (style->bg_pixmap[GTK_STATE_NORMAL])
+ {
+ style = gtk_style_copy(style);
+ style->bg_pixmap[GTK_STATE_NORMAL] = NULL;
+ gtk_widget_set_style(ih->handle, style);
+ }
+ return 1;
+ }
+ else
+ {
+ GdkPixbuf* pixbuf = iupImageGetImage(value, ih, 0);
+ if (pixbuf)
+ {
+ GdkPixmap* pixmap;
+ GtkStyle *style;
+
+ gdk_pixbuf_render_pixmap_and_mask(pixbuf, &pixmap, NULL, 255);
+
+ style = gtk_style_copy(gtk_widget_get_style(ih->handle));
+ style->bg_pixmap[GTK_STATE_NORMAL] = pixmap;
+ gtk_widget_set_style(ih->handle, style);
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+#if GTK_CHECK_VERSION(2, 10, 0)
+static int gtkDialogTaskDoubleClick(int button)
+{
+ static int last_button = -1;
+ static GTimer* timer = NULL;
+ if (last_button == -1 || last_button != button)
+ {
+ last_button = button;
+ if (timer)
+ g_timer_destroy(timer);
+ timer = g_timer_new();
+ return 0;
+ }
+ else
+ {
+ double seconds;
+
+ if (!timer) /* just in case */
+ return 0;
+
+ seconds = g_timer_elapsed(timer, NULL);
+ if (seconds < 0.4)
+ {
+ /* reset state */
+ g_timer_destroy(timer);
+ timer = NULL;
+ last_button = -1;
+ return 1;
+ }
+ else
+ {
+ g_timer_reset(timer);
+ return 0;
+ }
+ }
+}
+
+static void gtkDialogTaskAction(GtkStatusIcon *status_icon, Ihandle *ih)
+{
+ /* from GTK source code it is called only when button==1 and pressed==1 */
+ int button = 1;
+ int pressed = 1;
+ int dclick = gtkDialogTaskDoubleClick(button);
+ IFniii cb = (IFniii)IupGetCallback(ih, "TRAYCLICK_CB");
+ if (cb && cb(ih, button, pressed, dclick) == IUP_CLOSE)
+ IupExitLoop();
+ (void)status_icon;
+}
+
+static void gtkDialogTaskPopupMenu(GtkStatusIcon *status_icon, guint gbutton, guint activate_time, Ihandle *ih)
+{
+ /* from GTK source code it is called only when button==3 and pressed==1 */
+ int button = 3;
+ int pressed = 1;
+ int dclick = gtkDialogTaskDoubleClick(button);
+ IFniii cb = (IFniii)IupGetCallback(ih, "TRAYCLICK_CB");
+ if (cb && cb(ih, button, pressed, dclick) == IUP_CLOSE)
+ IupExitLoop();
+ (void)activate_time;
+ (void)gbutton;
+ (void)status_icon;
+}
+
+static GtkStatusIcon* gtkDialogGetStatusIcon(Ihandle *ih)
+{
+ GtkStatusIcon* status_icon = (GtkStatusIcon*)iupAttribGet(ih, "_IUPDLG_STATUSICON");
+ if (!status_icon)
+ {
+ status_icon = gtk_status_icon_new();
+
+ g_signal_connect(G_OBJECT(status_icon), "activate", G_CALLBACK(gtkDialogTaskAction), ih);
+ g_signal_connect(G_OBJECT(status_icon), "popup-menu", G_CALLBACK(gtkDialogTaskPopupMenu), ih);
+
+ iupAttribSetStr(ih, "_IUPDLG_STATUSICON", (char*)status_icon);
+ }
+ return status_icon;
+}
+
+static int gtkDialogSetTrayAttrib(Ihandle *ih, const char *value)
+{
+ GtkStatusIcon* status_icon = gtkDialogGetStatusIcon(ih);
+ gtk_status_icon_set_visible(status_icon, iupStrBoolean(value));
+ return 1;
+}
+
+static int gtkDialogSetTrayTipAttrib(Ihandle *ih, const char *value)
+{
+ GtkStatusIcon* status_icon = gtkDialogGetStatusIcon(ih);
+#if GTK_CHECK_VERSION(2, 16, 0)
+ if (value)
+ {
+ gtk_status_icon_set_has_tooltip(status_icon, TRUE);
+ gtk_status_icon_set_tooltip_text(status_icon, value);
+ }
+ else
+ gtk_status_icon_set_has_tooltip(status_icon, FALSE);
+#else
+ gtk_status_icon_set_tooltip(status_icon, value);
+#endif
+ return 1;
+}
+
+static int gtkDialogSetTrayImageAttrib(Ihandle *ih, const char *value)
+{
+ GtkStatusIcon* status_icon = gtkDialogGetStatusIcon(ih);
+ GdkPixbuf* icon = (GdkPixbuf*)iupImageGetIcon(value);
+ gtk_status_icon_set_from_pixbuf(status_icon, icon);
+ return 1;
+}
+#endif /* GTK_CHECK_VERSION(2, 10, 0) */
+
+void iupdrvDialogInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class methods */
+ ic->Map = gtkDialogMapMethod;
+ ic->UnMap = gtkDialogUnMapMethod;
+ ic->LayoutUpdate = gtkDialogLayoutUpdateMethod;
+ ic->GetInnerNativeContainerHandle = gtkDialogGetInnerNativeContainerHandleMethod;
+ ic->SetChildrenPosition = gtkDialogSetChildrenPositionMethod;
+
+ /* Callback Windows and GTK Only */
+ iupClassRegisterCallback(ic, "TRAYCLICK_CB", "iii");
+
+ /* Driver Dependent Attribute functions */
+
+#ifdef WIN32
+ iupClassRegisterAttribute(ic, "HWND", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_NO_INHERIT);
+#else
+ iupClassRegisterAttribute(ic, "XWINDOW", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+#endif
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, "DLGBGCOLOR", NULL, IUPAF_DEFAULT); /* force new default value */
+
+ /* Overwrite Visual */
+ iupClassRegisterAttribute(ic, "X", gtkDialogGetXAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "Y", gtkDialogGetYAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT);
+
+ /* Base Container */
+ iupClassRegisterAttribute(ic, "CLIENTSIZE", gtkDialogGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "TITLE", gtkDialogGetTitleAttrib, gtkDialogSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupDialog only */
+ iupClassRegisterAttribute(ic, "BACKGROUND", NULL, gtkDialogSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ICON", NULL, gtkDialogSetIconAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FULLSCREEN", NULL, gtkDialogSetFullScreenAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MINSIZE", NULL, gtkDialogSetMinSizeAttrib, IUPAF_SAMEASSYSTEM, "1x1", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MAXSIZE", NULL, gtkDialogSetMaxSizeAttrib, IUPAF_SAMEASSYSTEM, "65535x65535", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SAVEUNDER", NULL, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); /* saveunder not supported in GTK */
+
+ /* IupDialog Windows and GTK Only */
+ iupClassRegisterAttribute(ic, "TOPMOST", NULL, gtkDialogSetTopMostAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupgtkSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DIALOGHINT", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+#if GTK_CHECK_VERSION(2, 12, 0)
+ iupClassRegisterAttribute(ic, "OPACITY", NULL, gtkDialogSetOpacityAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+#endif
+#if GTK_CHECK_VERSION(2, 10, 0)
+ iupClassRegisterAttribute(ic, "TRAY", NULL, gtkDialogSetTrayAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TRAYIMAGE", NULL, gtkDialogSetTrayImageAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TRAYTIP", NULL, gtkDialogSetTrayTipAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+#endif
+}
diff --git a/iup/src/gtk/iupgtk_drv.h b/iup/src/gtk/iupgtk_drv.h
new file mode 100755
index 0000000..ade2a4a
--- /dev/null
+++ b/iup/src/gtk/iupgtk_drv.h
@@ -0,0 +1,82 @@
+/** \file
+ * \brief GTK Driver
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUPGTK_DRV_H
+#define __IUPGTK_DRV_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* global variables, declared in iupgtk_globalattrib.c */
+extern int iupgtk_utf8autoconvert;
+
+
+/* common */
+gboolean iupgtkEnterLeaveEvent(GtkWidget *widget, GdkEventCrossing *evt, Ihandle* ih);
+gboolean iupgtkShowHelp(GtkWidget *widget, GtkWidgetHelpType *arg1, Ihandle* ih);
+GtkFixed* iupgtkBaseGetFixed(Ihandle* ih);
+void iupgtkBaseAddToParent(Ihandle* ih);
+void iupgdkColorSet(GdkColor* color, unsigned char r, unsigned char g, unsigned char b);
+int iupgtkSetDragDropAttrib(Ihandle* ih, const char* value);
+int iupgtkSetMnemonicTitle(Ihandle* ih, GtkLabel* label, const char* value);
+char* iupgtkStrConvertToUTF8(const char* str);
+char* iupgtkStrConvertFromUTF8(const char* str);
+void iupgtkReleaseConvertUTF8(void);
+char* iupgtkStrConvertFromFilename(const char* str);
+char* iupgtkStrConvertToFilename(const char* str);
+void iupgtkUpdateMnemonic(Ihandle* ih);
+gboolean iupgtkMotionNotifyEvent(GtkWidget *widget, GdkEventMotion *evt, Ihandle *ih);
+gboolean iupgtkButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih);
+void iupgtkBaseSetBgColor(InativeHandle* handle, unsigned char r, unsigned char g, unsigned char b);
+void iupgtkBaseSetFgColor(InativeHandle* handle, unsigned char r, unsigned char g, unsigned char b);
+void iupgtkBaseSetFgGdkColor(InativeHandle* handle, GdkColor *color);
+
+
+/* focus */
+gboolean iupgtkFocusInOutEvent(GtkWidget *widget, GdkEventFocus *evt, Ihandle* ih);
+
+
+/* key */
+gboolean iupgtkKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle* ih);
+gboolean iupgtkKeyReleaseEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle* ih);
+void iupgtkButtonKeySetStatus(guint state, unsigned int but, char* status, int doubleclick);
+void iupgtkKeyEncode(int key, guint *keyval, guint *state);
+
+
+/* font */
+char* iupgtkGetPangoFontDescAttrib(Ihandle *ih);
+char* iupgtkGetFontIdAttrib(Ihandle *ih);
+PangoFontDescription* iupgtkGetPangoFontDesc(const char* value);
+char* iupgtkFindPangoFontDesc(PangoFontDescription* fontdesc);
+void iupgtkFontUpdatePangoLayout(Ihandle* ih, PangoLayout* layout);
+void iupgtkFontUpdateObjectPangoLayout(Ihandle* ih, gpointer object);
+
+/* There are PANGO_SCALE Pango units in one device unit.
+ For an output backend where a device unit is a pixel,
+ a size value of 10 * PANGO_SCALE gives 10 pixels. */
+#define IUPGTK_PANGOUNITS2PIXELS(_x) (((_x) + PANGO_SCALE/2) / PANGO_SCALE)
+#define IUPGTK_PIXELS2PANGOUNITS(_x) ((_x) * PANGO_SCALE)
+
+
+/* open */
+char* iupgtkGetNativeWindowHandle(Ihandle* ih);
+void iupgtkPushVisualAndColormap(void* visual, void* colormap);
+void* iupgtkGetNativeGraphicsContext(GtkWidget* widget);
+void iupgtkReleaseNativeGraphicsContext(GtkWidget* widget, void* gc);
+void iupgtkUpdateGlobalColors(GtkStyle* style);
+
+
+/* dialog */
+gboolean iupgtkDialogDeleteEvent(GtkWidget *widget, GdkEvent *evt, Ihandle *ih);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/gtk/iupgtk_filedlg.c b/iup/src/gtk/iupgtk_filedlg.c
new file mode 100755
index 0000000..5426910
--- /dev/null
+++ b/iup/src/gtk/iupgtk_filedlg.c
@@ -0,0 +1,536 @@
+/** \file
+ * \brief IupFileDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <stdio.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drvinfo.h"
+#include "iup_dialog.h"
+#include "iup_strmessage.h"
+#include "iup_array.h"
+#include "iup_drvinfo.h"
+
+#include "iupgtk_drv.h"
+
+
+static void iupStrRemoveChar(char* str, char c)
+{
+ char* p = str;
+ while (*str)
+ {
+ if (*str != c)
+ {
+ *p = *str;
+ p++;
+ }
+
+ str++;
+ }
+ *p = 0;
+}
+
+static void gtkFileDlgGetNextFilter(char** str, char** name, char** pattern)
+{
+ int len;
+ *name = *str;
+
+ len = strlen(*name);
+ *pattern = (*name)+len+1;
+
+ len = strlen(*pattern);
+ *str = (*pattern)+len+1;
+
+ iupStrReplace(*pattern, ';', 0); /* remove other patterns */
+}
+
+static void gtkFileDlgGetMultipleFiles(Ihandle* ih, GSList* list)
+{
+ int len, cur_len, dir_len = -1;
+ char *filename, *all_names;
+ Iarray* names_array = iupArrayCreate(1024, 1); /* just set an initial size, but count is 0 */
+
+ while (list)
+ {
+ filename = (char*)list->data;
+ len = strlen(filename);
+
+ if (dir_len == -1)
+ {
+ dir_len = len;
+
+ while (dir_len && (filename[dir_len] != '/' && filename[dir_len] != '\\'))
+ dir_len--;
+
+ cur_len = iupArrayCount(names_array);
+ all_names = iupArrayAdd(names_array, dir_len+1);
+ memcpy(all_names+cur_len, filename, dir_len);
+ all_names[cur_len+dir_len] = '|';
+
+ dir_len++; /* skip separator */
+ }
+ len -= dir_len; /* remove directory */
+
+ cur_len = iupArrayCount(names_array);
+ all_names = iupArrayAdd(names_array, len+1);
+ memcpy(all_names+cur_len, filename+dir_len, len);
+ all_names[cur_len+len] = '|';
+
+ g_free(filename);
+ list = list->next;
+ }
+
+ cur_len = iupArrayCount(names_array);
+ all_names = iupArrayInc(names_array);
+ all_names[cur_len+1] = 0;
+
+ iupAttribStoreStr(ih, "VALUE", iupgtkStrConvertFromFilename(all_names));
+
+ iupArrayDestroy(names_array);
+}
+
+#ifdef WIN32
+#include <gdk/gdkwin32.h>
+#else
+#include <gdk/gdkx.h>
+#endif
+
+static void gtkFileDlgUpdatePreviewGLCanvas(Ihandle* ih)
+{
+ Ihandle* glcanvas = IupGetAttributeHandle(ih, "PREVIEWGLCANVAS");
+ if (glcanvas)
+ {
+#ifdef WIN32
+ iupAttribSetStr(glcanvas, "HWND", iupAttribGet(ih, "HWND"));
+#else
+ iupAttribSetStr(glcanvas, "XWINDOW", iupAttribGet(ih, "XWINDOW"));
+#endif
+ glcanvas->iclass->Map(glcanvas);
+ }
+}
+
+static void gtkFileDlgPreviewRealize(GtkWidget *widget, Ihandle *ih)
+{
+ iupAttribSetStr(ih, "PREVIEWDC", iupgtkGetNativeGraphicsContext(widget));
+ iupAttribSetStr(ih, "WID", (char*)widget);
+
+#ifdef WIN32
+ iupAttribSetStr(ih, "HWND", (char*)GDK_WINDOW_HWND(widget->window));
+#else
+ iupAttribSetStr(ih, "XWINDOW", (char*)GDK_WINDOW_XID(widget->window));
+ iupAttribSetStr(ih, "XDISPLAY", (char*)iupdrvGetDisplay());
+#endif
+ gtkFileDlgUpdatePreviewGLCanvas(ih);
+}
+
+static void gtkFileDlgRealize(GtkWidget *widget, Ihandle *ih)
+{
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ cb(ih, NULL, "INIT");
+
+ (void)widget;
+}
+
+static gboolean gtkFileDlgPreviewConfigureEvent(GtkWidget *widget, GdkEventConfigure *evt, Ihandle *ih)
+{
+ iupAttribSetInt(ih, "PREVIEWWIDTH", evt->width);
+ iupAttribSetInt(ih, "PREVIEWHEIGHT", evt->height);
+
+ (void)widget;
+ return FALSE;
+}
+
+static gboolean gtkFileDlgPreviewExposeEvent(GtkWidget *widget, GdkEventExpose *evt, Ihandle *ih)
+{
+ GtkFileChooser *file_chooser = (GtkFileChooser*)iupAttribGet(ih, "_IUPDLG_FILE_CHOOSER");
+ char *filename = gtk_file_chooser_get_preview_filename(file_chooser);
+
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ if (iupdrvIsFile(filename))
+ cb(ih, iupgtkStrConvertFromFilename(filename), "PAINT");
+ else
+ cb(ih, NULL, "PAINT");
+
+ g_free (filename);
+
+ (void)evt;
+ (void)widget;
+ return TRUE; /* stop other handlers */
+}
+
+static void gtkFileDlgUpdatePreview(GtkFileChooser *file_chooser, Ihandle* ih)
+{
+ char *filename = gtk_file_chooser_get_preview_filename(file_chooser);
+
+ if (iupdrvIsFile(filename))
+ {
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ cb(ih, iupgtkStrConvertFromFilename(filename), "SELECT");
+ }
+
+ g_free (filename);
+
+ gtk_file_chooser_set_preview_widget_active(file_chooser, TRUE);
+}
+
+static int gtkFileDlgPopup(Ihandle* ih, int x, int y)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ GtkWidget* dialog;
+ GtkWidget* preview_canvas = NULL;
+ GtkFileChooserAction action;
+ IFnss file_cb;
+ char* value;
+ int response, filter_count = 0;
+
+ iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */
+ iupAttribSetInt(ih, "_IUPDLG_Y", y);
+
+ value = iupAttribGetStr(ih, "DIALOGTYPE");
+ if (iupStrEqualNoCase(value, "SAVE"))
+ action = GTK_FILE_CHOOSER_ACTION_SAVE;
+ else if (iupStrEqualNoCase(value, "DIR"))
+ action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
+ else
+ action = GTK_FILE_CHOOSER_ACTION_OPEN;
+
+ value = iupAttribGet(ih, "TITLE");
+ if (!value)
+ {
+ GtkStockItem item;
+
+ if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ value = GTK_STOCK_SAVE_AS;
+ else
+ value = GTK_STOCK_OPEN;
+
+ gtk_stock_lookup(value, &item);
+ value = item.label;
+
+ iupAttribStoreStr(ih, "TITLE", iupgtkStrConvertFromUTF8(value));
+ value = iupAttribGet(ih, "TITLE");
+ iupStrRemoveChar(value, '_');
+ }
+
+ dialog = gtk_file_chooser_dialog_new(iupgtkStrConvertToUTF8(value), (GtkWindow*)parent, action,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ NULL);
+ if (!dialog)
+ return IUP_ERROR;
+
+ if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_SAVE, GTK_RESPONSE_OK);
+ else if (action == GTK_FILE_CHOOSER_ACTION_OPEN)
+ gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OPEN, GTK_RESPONSE_OK);
+ else
+ gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OK, GTK_RESPONSE_OK);
+
+ if (IupGetCallback(ih, "HELP_CB"))
+ gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_HELP, GTK_RESPONSE_HELP);
+
+#if GTK_CHECK_VERSION(2, 6, 0)
+ if (iupAttribGetBoolean(ih, "SHOWHIDDEN"))
+ gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dialog), TRUE);
+#endif
+
+ if (iupAttribGetBoolean(ih, "MULTIPLEFILES") && action == GTK_FILE_CHOOSER_ACTION_OPEN)
+ gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
+
+#if GTK_CHECK_VERSION(2, 8, 0)
+ if (!iupAttribGetBoolean(ih, "NOOVERWRITEPROMPT") && action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
+#endif
+
+ /* just check for the path inside FILE */
+ value = iupAttribGet(ih, "FILE");
+ if (value && (value[0] == '/' || value[1] == ':'))
+ {
+ char* dir = iupStrFileGetPath(value);
+ int len = strlen(dir);
+ iupAttribStoreStr(ih, "DIRECTORY", dir);
+ free(dir);
+ iupAttribStoreStr(ih, "FILE", value+len);
+ }
+
+ value = iupAttribGet(ih, "DIRECTORY");
+ if (value)
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), iupgtkStrConvertToFilename(value));
+
+ value = iupAttribGet(ih, "FILE");
+ if (value)
+ {
+ if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), iupgtkStrConvertToFilename(value));
+ else
+ {
+ if (iupdrvIsFile(value)) /* check if file exists */
+ gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), iupgtkStrConvertToFilename(value));
+ }
+ }
+
+ value = iupAttribGet(ih, "EXTFILTER");
+ if (value)
+ {
+ char *name, *pattern, *filters = iupStrDup(value), *p;
+ char atrib[30];
+ int i;
+ int filter_index = iupAttribGetInt(ih, "FILTERUSED");
+ if (!filter_index)
+ filter_index = 1;
+
+ filter_count = iupStrReplace(filters, '|', 0) / 2;
+
+ p = filters;
+ for (i=0; i<filter_count; i++)
+ {
+ GtkFileFilter *filter = gtk_file_filter_new();
+
+ gtkFileDlgGetNextFilter(&p, &name, &pattern);
+
+ gtk_file_filter_set_name(filter, iupgtkStrConvertToUTF8(name));
+ gtk_file_filter_add_pattern(filter, pattern);
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
+
+ sprintf(atrib, "_IUPDLG_FILTER%d", i+1);
+ iupAttribSetStr(ih, atrib, (char*)filter);
+
+ if (i+1 == filter_index)
+ gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
+ }
+
+ free(filters);
+ }
+ else
+ {
+ value = iupAttribGet(ih, "FILTER");
+ if (value)
+ {
+ GtkFileFilter *filter = gtk_file_filter_new();
+ char* info = iupAttribGet(ih, "FILTERINFO");
+ if (!info)
+ info = value;
+
+ gtk_file_filter_set_name(filter, iupgtkStrConvertToUTF8(info));
+ gtk_file_filter_add_pattern(filter, value);
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
+ }
+ }
+
+ file_cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ if (file_cb && action != GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+ {
+ g_signal_connect(GTK_FILE_CHOOSER(dialog), "update-preview", G_CALLBACK(gtkFileDlgUpdatePreview), ih);
+ g_signal_connect(dialog, "realize", G_CALLBACK(gtkFileDlgRealize), ih);
+
+ if (iupAttribGetBoolean(ih, "SHOWPREVIEW"))
+ {
+ GtkWidget* frame = gtk_frame_new(NULL);
+ gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
+ gtk_widget_set_size_request(frame, 180, 150);
+
+ preview_canvas = gtk_drawing_area_new();
+ gtk_widget_set_double_buffered(preview_canvas, FALSE);
+ gtk_container_add(GTK_CONTAINER(frame), preview_canvas);
+ gtk_widget_show(preview_canvas);
+
+ g_signal_connect(preview_canvas, "configure-event", G_CALLBACK(gtkFileDlgPreviewConfigureEvent), ih);
+ g_signal_connect(preview_canvas, "expose-event", G_CALLBACK(gtkFileDlgPreviewExposeEvent), ih);
+ g_signal_connect(preview_canvas, "realize", G_CALLBACK(gtkFileDlgPreviewRealize), ih);
+
+ iupAttribSetStr(ih, "_IUPDLG_FILE_CHOOSER", (char*)dialog);
+
+ gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(dialog), frame);
+ }
+ }
+
+ /* initialize the widget */
+ gtk_widget_realize(GTK_WIDGET(dialog));
+
+ ih->handle = GTK_WIDGET(dialog);
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL; /* reset handle */
+
+ do
+ {
+ response = gtk_dialog_run(GTK_DIALOG(dialog));
+
+ if (response == GTK_RESPONSE_HELP)
+ {
+ Icallback cb = IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ response = GTK_RESPONSE_CANCEL;
+ }
+ else if (response == GTK_RESPONSE_OK)
+ {
+ char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+ int file_exist = iupdrvIsFile(filename);
+ int dir_exist = iupdrvIsDirectory(filename);
+ g_free(filename);
+
+ if (action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+ {
+ if (!dir_exist)
+ {
+ iupStrMessageShowError(ih, "IUP_INVALIDDIR");
+ response = GTK_RESPONSE_HELP; /* to leave the dialog open */
+ continue;
+ }
+ }
+ else if (!iupAttribGetBoolean(ih, "MULTIPLEFILES"))
+ {
+ if (dir_exist)
+ {
+ iupStrMessageShowError(ih, "IUP_FILEISDIR");
+ response = GTK_RESPONSE_HELP; /* to leave the dialog open */
+ continue;
+ }
+
+ if (!file_exist) /* if do not exist check ALLOWNEW */
+ {
+ value = iupAttribGet(ih, "ALLOWNEW");
+ if (!value)
+ {
+ if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ value = "YES";
+ else
+ value = "NO";
+ }
+
+ if (!iupStrBoolean(value))
+ {
+ iupStrMessageShowError(ih, "IUP_FILENOTEXIST");
+ response = GTK_RESPONSE_HELP; /* to leave the dialog open */
+ continue;
+ }
+ }
+
+ if (file_cb)
+ {
+ char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+ int ret = file_cb(ih, iupgtkStrConvertFromFilename(filename), "OK");
+ g_free(filename);
+
+ if (ret == IUP_IGNORE)
+ {
+ response = GTK_RESPONSE_HELP; /* to leave the dialog open */
+ continue;
+ }
+ }
+ }
+ }
+ } while (response == GTK_RESPONSE_HELP);
+
+ if (file_cb)
+ {
+ if (iupAttribGetBoolean(ih, "SHOWPREVIEW"))
+ iupgtkReleaseNativeGraphicsContext(preview_canvas, (void*)iupAttribGet(ih, "PREVIEWDC"));
+
+ file_cb(ih, NULL, "FINISH");
+ }
+
+ if (response == GTK_RESPONSE_OK)
+ {
+ int file_exist, dir_exist;
+
+ if (filter_count)
+ {
+ int i;
+ char atrib[30];
+ GtkFileFilter* filter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog));
+
+ for (i=0; i<filter_count; i++)
+ {
+ sprintf(atrib, "_IUPDLG_FILTER%d", i+1);
+ if (filter == (GtkFileFilter*)iupAttribGet(ih, atrib))
+ iupAttribSetInt(ih, "FILTERUSED", i+1);
+ }
+ }
+
+ if (iupAttribGetBoolean(ih, "MULTIPLEFILES"))
+ {
+ GSList* file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
+
+ if (file_list->next) /* if more than one file */
+ gtkFileDlgGetMultipleFiles(ih, file_list);
+ else
+ {
+ char* filename = (char*)file_list->data;
+ iupAttribStoreStr(ih, "VALUE", iupgtkStrConvertFromFilename(filename));
+ g_free(filename);
+ }
+
+ g_slist_free(file_list);
+ file_exist = 1;
+ dir_exist = 0;
+ }
+ else
+ {
+ char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+ iupAttribStoreStr(ih, "VALUE", iupgtkStrConvertFromFilename(filename));
+ file_exist = iupdrvIsFile(filename);
+ dir_exist = iupdrvIsDirectory(filename);
+ g_free(filename);
+ }
+
+ if (dir_exist)
+ {
+ iupAttribSetStr(ih, "FILEEXIST", NULL);
+ iupAttribSetStr(ih, "STATUS", "0");
+ }
+ else
+ {
+ if (file_exist) /* check if file exists */
+ {
+ iupAttribSetStr(ih, "FILEEXIST", "YES");
+ iupAttribSetStr(ih, "STATUS", "0");
+ }
+ else
+ {
+ iupAttribSetStr(ih, "FILEEXIST", "NO");
+ iupAttribSetStr(ih, "STATUS", "1");
+ }
+ }
+
+ if (action != GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER && !iupAttribGetBoolean(ih, "NOCHANGEDIR")) /* do change the current directory */
+ {
+ /* GtkFileChooser does not change the current directory */
+ char* dir = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
+ if (dir) iupdrvSetCurrentDirectory(dir);
+ g_free(dir);
+ }
+ }
+ else
+ {
+ iupAttribSetStr(ih, "FILTERUSED", NULL);
+ iupAttribSetStr(ih, "VALUE", NULL);
+ iupAttribSetStr(ih, "FILEEXIST", NULL);
+ iupAttribSetStr(ih, "STATUS", "-1");
+ }
+
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+
+ return IUP_NOERROR;
+}
+
+void iupdrvFileDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = gtkFileDlgPopup;
+
+ /* IupFileDialog Windows and GTK Only */
+ iupClassRegisterAttribute(ic, "EXTFILTER", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FILTERINFO", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FILTERUSED", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MULTIPLEFILES", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/gtk/iupgtk_focus.c b/iup/src/gtk/iupgtk_focus.c
new file mode 100755
index 0000000..fa596ba
--- /dev/null
+++ b/iup/src/gtk/iupgtk_focus.c
@@ -0,0 +1,44 @@
+/** \file
+ * \brief GTK Focus
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include <stdio.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_focus.h"
+#include "iup_attrib.h"
+#include "iup_drv.h"
+#include "iup_assert.h"
+#include "iup_drv.h"
+
+#include "iupgtk_drv.h"
+
+
+void iupdrvSetFocus(Ihandle *ih)
+{
+ gtk_widget_grab_focus(ih->handle);
+}
+
+gboolean iupgtkFocusInOutEvent(GtkWidget *widget, GdkEventFocus *evt, Ihandle *ih)
+{
+ (void)widget;
+
+ if (evt->in)
+ {
+ /* even when ACTIVE=NO the dialog gets this evt */
+ if (!iupdrvIsActive(ih))
+ return TRUE;
+
+ iupCallGetFocusCb(ih);
+ }
+ else
+ iupCallKillFocusCb(ih);
+
+ return FALSE;
+}
diff --git a/iup/src/gtk/iupgtk_font.c b/iup/src/gtk/iupgtk_font.c
new file mode 100755
index 0000000..f7ff348
--- /dev/null
+++ b/iup/src/gtk/iupgtk_font.c
@@ -0,0 +1,413 @@
+/** \file
+ * \brief GTK Font mapping
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include "iup.h"
+
+#include "iup_str.h"
+#include "iup_attrib.h"
+#include "iup_array.h"
+#include "iup_object.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_assert.h"
+
+#include "iupgtk_drv.h"
+
+
+typedef struct _IgtkFont
+{
+ char standardfont[200];
+ PangoFontDescription* fontdesc;
+ PangoAttribute* strikethrough;
+ PangoAttribute* underline;
+ PangoLayout* layout;
+ int charwidth, charheight;
+} IgtkFont;
+
+static Iarray* gtk_fonts = NULL;
+static PangoContext *gtk_fonts_context = NULL;
+
+static void gtkFontUpdate(IgtkFont* gtkfont)
+{
+ PangoAttrList *attrs;
+
+ pango_layout_set_font_description(gtkfont->layout, gtkfont->fontdesc);
+
+ attrs = pango_layout_get_attributes(gtkfont->layout);
+ if (!attrs)
+ {
+ attrs = pango_attr_list_new();
+ pango_attr_list_insert(attrs, pango_attribute_copy(gtkfont->strikethrough));
+ pango_attr_list_insert(attrs, pango_attribute_copy(gtkfont->underline));
+ pango_layout_set_attributes(gtkfont->layout, attrs);
+ }
+ else
+ {
+ pango_attr_list_change(attrs, pango_attribute_copy(gtkfont->strikethrough));
+ pango_attr_list_change(attrs, pango_attribute_copy(gtkfont->underline));
+ }
+}
+
+static IgtkFont* gtkFindFont(const char *standardfont)
+{
+ PangoFontMetrics* metrics;
+ PangoFontDescription* fontdesc;
+ int i,
+ is_underline = 0,
+ is_strikeout = 0,
+ count = iupArrayCount(gtk_fonts);
+
+ IgtkFont* fonts = (IgtkFont*)iupArrayGetData(gtk_fonts);
+
+ /* Check if the standardfont already exists in cache */
+ for (i = 0; i < count; i++)
+ {
+ if (iupStrEqualNoCase(standardfont, fonts[i].standardfont))
+ return &fonts[i];
+ }
+
+ /* not found, create a new one */
+ {
+ int size = 0, is_pango = 0;
+ int is_bold = 0,
+ is_italic = 0;
+ char typeface[1024];
+ const char* mapped_name;
+
+ /* parse the old Windows format first */
+ if (!iupFontParseWin(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParseX(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ return NULL;
+ else
+ is_pango = 1;
+ }
+ }
+
+ mapped_name = iupFontGetPangoName(typeface);
+ if (mapped_name)
+ strcpy(typeface, mapped_name);
+
+ if (is_pango && !is_underline && !is_strikeout && size>0)
+ fontdesc = pango_font_description_from_string(standardfont);
+ else
+ {
+ char new_standardfont[200];
+ if (size<0)
+ {
+ double res = ((double)gdk_screen_get_width(gdk_screen_get_default()) / (double)gdk_screen_get_width_mm(gdk_screen_get_default())); /* pixels/mm */
+ /* 1 point = 1/72 inch 1 inch = 25.4 mm */
+ /* pixel = ((point/72)*25.4)*pixel/mm */
+ size = (int)((-size/res)*2.83464567 + 0.5); /* from pixels to points */
+ }
+
+ sprintf(new_standardfont, "%s, %s%s%d", typeface, is_bold?"Bold ":"", is_italic?"Italic ":"", size);
+
+ fontdesc = pango_font_description_from_string(new_standardfont);
+ }
+ }
+
+ if (!fontdesc)
+ return NULL;
+
+ /* create room in the array */
+ fonts = (IgtkFont*)iupArrayInc(gtk_fonts);
+
+ strcpy(fonts[i].standardfont, standardfont);
+ fonts[i].fontdesc = fontdesc;
+ fonts[i].strikethrough = pango_attr_strikethrough_new(is_strikeout? TRUE: FALSE);
+ fonts[i].underline = pango_attr_underline_new(is_underline? PANGO_UNDERLINE_SINGLE: PANGO_UNDERLINE_NONE);
+ fonts[i].layout = pango_layout_new(gtk_fonts_context);
+
+ metrics = pango_context_get_metrics(gtk_fonts_context, fontdesc, pango_context_get_language(gtk_fonts_context));
+ fonts[i].charheight = pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics);
+ fonts[i].charheight = IUPGTK_PANGOUNITS2PIXELS(fonts[i].charheight);
+ fonts[i].charwidth = pango_font_metrics_get_approximate_char_width(metrics);
+ fonts[i].charwidth = IUPGTK_PANGOUNITS2PIXELS(fonts[i].charwidth);
+ pango_font_metrics_unref(metrics);
+
+ gtkFontUpdate(&(fonts[i]));
+
+ return &fonts[i];
+}
+
+static PangoLayout* gtkFontGetWidgetPangoLayout(Ihandle *ih)
+{
+ int inherit;
+ char *def_value;
+ /* only check the native implementation */
+ return (PangoLayout*)iupClassObjectGetAttribute(ih, "PANGOLAYOUT", &def_value, &inherit);
+}
+
+static IgtkFont* gtkFontCreateNativeFont(Ihandle* ih, const char* value)
+{
+ IgtkFont *gtkfont = gtkFindFont(value);
+ if (!gtkfont)
+ {
+ iupERROR1("Failed to create Font: %s", value);
+ return NULL;
+ }
+
+ iupAttribSetStr(ih, "_IUP_GTKFONT", (char*)gtkfont);
+ return gtkfont;
+}
+
+static IgtkFont* gtkFontGet(Ihandle *ih)
+{
+ IgtkFont* gtkfont = (IgtkFont*)iupAttribGet(ih, "_IUP_GTKFONT");
+ if (!gtkfont)
+ gtkfont = gtkFontCreateNativeFont(ih, iupGetFontAttrib(ih));
+ return gtkfont;
+}
+
+void iupgtkFontUpdatePangoLayout(Ihandle* ih, PangoLayout* layout)
+{
+ IgtkFont* gtkfont;
+ PangoAttrList *attrs;
+
+ if (!layout)
+ return;
+
+ gtkfont = gtkFontGet(ih);
+ if (!gtkfont)
+ return;
+
+ attrs = pango_layout_get_attributes(layout);
+ if (!attrs)
+ {
+ attrs = pango_attr_list_new();
+ pango_attr_list_insert(attrs, pango_attribute_copy(gtkfont->strikethrough));
+ pango_attr_list_insert(attrs, pango_attribute_copy(gtkfont->underline));
+ pango_layout_set_attributes(layout, attrs);
+ }
+ else
+ {
+ pango_attr_list_change(attrs, pango_attribute_copy(gtkfont->strikethrough));
+ pango_attr_list_change(attrs, pango_attribute_copy(gtkfont->underline));
+ }
+}
+
+void iupgtkFontUpdateObjectPangoLayout(Ihandle* ih, gpointer object)
+{
+ PangoAttrList *attrs;
+
+ IgtkFont* gtkfont = gtkFontGet(ih);
+ if (!gtkfont)
+ return;
+
+ g_object_get(object, "attributes", &attrs, NULL);
+ if (!attrs)
+ {
+ attrs = pango_attr_list_new();
+ pango_attr_list_insert(attrs, pango_attribute_copy(gtkfont->strikethrough));
+ pango_attr_list_insert(attrs, pango_attribute_copy(gtkfont->underline));
+ g_object_set(object, "attributes", attrs, NULL);
+ }
+ else
+ {
+ pango_attr_list_change(attrs, pango_attribute_copy(gtkfont->strikethrough));
+ pango_attr_list_change(attrs, pango_attribute_copy(gtkfont->underline));
+ }
+}
+
+char* iupdrvGetSystemFont(void)
+{
+ static char systemfont[200] = "";
+ GtkStyle* style;
+ GtkWidget* widget = gtk_invisible_new();
+ gtk_widget_realize(widget);
+ style = gtk_widget_get_style(widget);
+ if (!style || !style->font_desc)
+ strcpy(systemfont, "Sans, 10");
+ else
+ {
+ char* desc = pango_font_description_to_string(style->font_desc);
+ strcpy(systemfont, desc);
+ g_free(desc);
+ }
+ gtk_widget_unrealize(widget);
+ gtk_widget_destroy(widget);
+ return systemfont;
+}
+
+char* iupgtkFindPangoFontDesc(PangoFontDescription* fontdesc)
+{
+ int i, count = iupArrayCount(gtk_fonts);
+ IgtkFont* fonts = (IgtkFont*)iupArrayGetData(gtk_fonts);
+
+ /* Check if the standardfont already exists in cache */
+ for (i = 0; i < count; i++)
+ {
+ if (pango_font_description_equal(fontdesc, fonts[i].fontdesc))
+ return fonts[i].standardfont;
+ }
+
+ return NULL;
+}
+
+PangoFontDescription* iupgtkGetPangoFontDesc(const char* value)
+{
+ IgtkFont *gtkfont = gtkFindFont(value);
+ if (!gtkfont)
+ {
+ iupERROR1("Failed to create Font: %s", value);
+ return NULL;
+ }
+ return gtkfont->fontdesc;
+}
+
+char* iupgtkGetPangoFontDescAttrib(Ihandle *ih)
+{
+ IgtkFont* gtkfont = gtkFontGet(ih);
+ if (!gtkfont)
+ return NULL;
+ else
+ return (char*)gtkfont->fontdesc;
+}
+
+char* iupgtkGetFontIdAttrib(Ihandle *ih)
+{
+ IgtkFont* gtkfont = gtkFontGet(ih);
+ if (!gtkfont)
+ return NULL;
+ else
+ {
+ GdkFont* gdk_font = gdk_font_from_description(gtkfont->fontdesc);
+ return (char*)gdk_font_id(gdk_font); /* In UNIX will return an X Font ID, in Win32 will return an HFONT */
+ }
+}
+
+int iupdrvSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ IgtkFont* gtkfont = gtkFontCreateNativeFont(ih, value);
+ if (!gtkfont)
+ return 1;
+
+ /* If FONT is changed, must update the SIZE attribute */
+ iupBaseUpdateSizeFromFont(ih);
+
+ /* FONT attribute must be able to be set before mapping,
+ so the font is enable for size calculation. */
+ if (ih->handle && (ih->iclass->nativetype != IUP_TYPEVOID))
+ {
+ gtk_widget_modify_font(ih->handle, gtkfont->fontdesc);
+ iupgtkFontUpdatePangoLayout(ih, gtkFontGetWidgetPangoLayout(ih));
+ }
+
+ return 1;
+}
+
+void iupdrvFontGetMultiLineStringSize(Ihandle* ih, const char* str, int *w, int *h)
+{
+ int max_w;
+
+ IgtkFont* gtkfont = gtkFontGet(ih);
+ if (!gtkfont)
+ {
+ if (w) *w = 0;
+ if (h) *h = 0;
+ return;
+ }
+
+ if (!str)
+ {
+ if (w) *w = 0;
+ if (h) *h = gtkfont->charheight * 1;
+ return;
+ }
+
+ max_w = 0;
+ if (str[0])
+ {
+ int dummy_h;
+
+ pango_layout_set_attributes(gtkfont->layout, NULL);
+
+ if (iupAttribGetBoolean(ih, "MARKUP"))
+ pango_layout_set_markup(gtkfont->layout, iupgtkStrConvertToUTF8(str), -1);
+ else
+ pango_layout_set_text(gtkfont->layout, iupgtkStrConvertToUTF8(str), -1);
+
+ pango_layout_get_pixel_size(gtkfont->layout, &max_w, &dummy_h);
+ }
+
+ if (w) *w = max_w;
+ if (h) *h = gtkfont->charheight * iupStrLineCount(str);
+}
+
+int iupdrvFontGetStringWidth(Ihandle* ih, const char* str)
+{
+ IgtkFont* gtkfont;
+ int len, w;
+ char* line_end;
+
+ if (!str || str[0]==0)
+ return 0;
+
+ gtkfont = gtkFontGet(ih);
+ if (!gtkfont)
+ return 0;
+
+ line_end = strchr(str, '\n');
+ if (line_end)
+ len = line_end-str;
+ else
+ len = strlen(str);
+
+ if (iupAttribGetBoolean(ih, "MARKUP"))
+ pango_layout_set_markup(gtkfont->layout, iupgtkStrConvertToUTF8(str), len);
+ else
+ pango_layout_set_text(gtkfont->layout, iupgtkStrConvertToUTF8(str), len);
+
+ pango_layout_get_pixel_size(gtkfont->layout, &w, NULL);
+ return w;
+}
+
+void iupdrvFontGetCharSize(Ihandle* ih, int *charwidth, int *charheight)
+{
+ IgtkFont* gtkfont = gtkFontGet(ih);
+ if (!gtkfont)
+ {
+ if (charwidth) *charwidth = 0;
+ if (charheight) *charheight = 0;
+ return;
+ }
+
+ if (charheight)
+ *charheight = gtkfont->charheight;
+
+ if (charwidth)
+ *charwidth = gtkfont->charwidth;
+}
+
+void iupdrvFontInit(void)
+{
+ gtk_fonts = iupArrayCreate(50, sizeof(IgtkFont));
+ gtk_fonts_context = gdk_pango_context_get();
+ pango_context_set_language(gtk_fonts_context, gtk_get_default_language());
+}
+
+void iupdrvFontFinish(void)
+{
+ int i, count = iupArrayCount(gtk_fonts);
+ IgtkFont* fonts = (IgtkFont*)iupArrayGetData(gtk_fonts);
+ for (i = 0; i < count; i++)
+ {
+ pango_font_description_free(fonts[i].fontdesc);
+ pango_attribute_destroy(fonts[i].strikethrough);
+ pango_attribute_destroy(fonts[i].underline);
+ }
+ iupArrayDestroy(gtk_fonts);
+ g_object_unref(gtk_fonts_context);
+}
diff --git a/iup/src/gtk/iupgtk_fontdlg.c b/iup/src/gtk/iupgtk_fontdlg.c
new file mode 100755
index 0000000..5769cbc
--- /dev/null
+++ b/iup/src/gtk/iupgtk_fontdlg.c
@@ -0,0 +1,91 @@
+/** \file
+ * \brief IupFontDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include <string.h>
+#include <memory.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+
+#include "iupgtk_drv.h"
+
+
+static int gtkFontDlgPopup(Ihandle* ih, int x, int y)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ GtkFontSelectionDialog* dialog;
+ int response;
+ char* preview_text;
+
+ iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */
+ iupAttribSetInt(ih, "_IUPDLG_Y", y);
+
+ dialog = (GtkFontSelectionDialog*)gtk_font_selection_dialog_new(iupgtkStrConvertToUTF8(iupAttribGet(ih, "TITLE")));
+ if (!dialog)
+ return IUP_ERROR;
+
+ if (parent)
+ gtk_window_set_transient_for((GtkWindow*)dialog, (GtkWindow*)parent);
+
+ gtk_font_selection_dialog_set_font_name(dialog, iupAttribGet(ih, "VALUE"));
+
+ preview_text = iupAttribGet(ih, "PREVIEWTEXT");
+ if (preview_text)
+ gtk_font_selection_dialog_set_preview_text(dialog, preview_text);
+
+ if (IupGetCallback(ih, "HELP_CB"))
+ gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_HELP, GTK_RESPONSE_HELP);
+
+ /* initialize the widget */
+ gtk_widget_realize(GTK_WIDGET(dialog));
+
+ ih->handle = GTK_WIDGET(dialog);
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL;
+
+ do
+ {
+ response = gtk_dialog_run(GTK_DIALOG(dialog));
+
+ if (response == GTK_RESPONSE_HELP)
+ {
+ Icallback cb = IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ response = GTK_RESPONSE_CANCEL;
+ }
+ } while (response == GTK_RESPONSE_HELP);
+
+ if (response == GTK_RESPONSE_OK)
+ {
+ char* fontname = gtk_font_selection_dialog_get_font_name(dialog);
+ iupAttribStoreStr(ih, "VALUE", fontname);
+ g_free(fontname);
+ iupAttribSetStr(ih, "STATUS", "1");
+ }
+ else
+ {
+ iupAttribSetStr(ih, "VALUE", NULL);
+ iupAttribSetStr(ih, "STATUS", NULL);
+ }
+
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+
+ return IUP_NOERROR;
+}
+
+void iupdrvFontDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = gtkFontDlgPopup;
+
+ /* IupFontDialog GTK Only */
+ iupClassRegisterAttribute(ic, "PREVIEWTEXT", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/gtk/iupgtk_frame.c b/iup/src/gtk/iupgtk_frame.c
new file mode 100755
index 0000000..022c6c7
--- /dev/null
+++ b/iup/src/gtk/iupgtk_frame.c
@@ -0,0 +1,155 @@
+/** \file
+ * \brief Frame Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+
+#include "iupgtk_drv.h"
+
+
+void iupdrvFrameGetDecorOffset(Ihandle* ih, int *x, int *y)
+{
+ (void)ih;
+ *x = 0;
+ *y = 0;
+}
+
+static char* gtkFrameGetTitleAttrib(Ihandle* ih)
+{
+ GtkFrame* frame = (GtkFrame*)ih->handle;
+ return iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_frame_get_label(frame)));
+}
+
+static int gtkFrameSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ GtkFrame* frame = (GtkFrame*)ih->handle;
+ gtk_frame_set_label(frame, iupgtkStrConvertToUTF8(value));
+ return 0;
+}
+
+static int gtkFrameSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ GtkWidget* label = gtk_frame_get_label_widget((GtkFrame*)ih->handle);
+
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ if (label)
+ iupgtkBaseSetBgColor(label, r, g, b);
+
+ iupgtkBaseSetBgColor(ih->handle, r, g, b);
+
+ return 1;
+}
+
+static int gtkFrameSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ GtkWidget* label = gtk_frame_get_label_widget((GtkFrame*)ih->handle);
+ if (!label) return 0;
+
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgtkBaseSetFgColor(label, r, g, b);
+
+ return 1;
+}
+
+static int gtkFrameSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ iupdrvSetStandardFontAttrib(ih, value);
+
+ if (ih->handle)
+ {
+ GtkWidget* label = gtk_frame_get_label_widget((GtkFrame*)ih->handle);
+ if (!label) return 1;
+
+ gtk_widget_modify_font(label, (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih));
+ iupgtkFontUpdatePangoLayout(ih, gtk_label_get_layout((GtkLabel*)label));
+ }
+ return 1;
+}
+
+static void* gtkFrameGetInnerNativeContainerHandleMethod(Ihandle* ih, Ihandle* child)
+{
+ (void)child;
+ return (void*)gtk_bin_get_child((GtkBin*)ih->handle);
+}
+
+static int gtkFrameMapMethod(Ihandle* ih)
+{
+ char *value, *title;
+ GtkWidget *fixed;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ title = iupAttribGet(ih, "TITLE");
+
+ ih->handle = gtk_frame_new(NULL);
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ if (title)
+ iupAttribSetStr(ih, "_IUPFRAME_HAS_TITLE", "1");
+ else
+ {
+ value = iupAttribGetStr(ih, "SUNKEN");
+ if (iupStrBoolean(value))
+ gtk_frame_set_shadow_type((GtkFrame*)ih->handle, GTK_SHADOW_IN);
+ else
+ gtk_frame_set_shadow_type((GtkFrame*)ih->handle, GTK_SHADOW_ETCHED_IN);
+ }
+
+ /* the container that will receive the child element. */
+ fixed = gtk_fixed_new();
+ gtk_container_add((GtkContainer*)ih->handle, fixed);
+ gtk_widget_show(fixed);
+
+ /* Add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ gtk_widget_realize(ih->handle);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvFrameInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkFrameMapMethod;
+ ic->GetInnerNativeContainerHandle = gtkFrameGetInnerNativeContainerHandleMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Overwrite Common */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, gtkFrameSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED);
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkFrameSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, gtkFrameSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "TITLE", gtkFrameGetTitleAttrib, gtkFrameSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/gtk/iupgtk_globalattrib.c b/iup/src/gtk/iupgtk_globalattrib.c
new file mode 100755
index 0000000..eebe799
--- /dev/null
+++ b/iup/src/gtk/iupgtk_globalattrib.c
@@ -0,0 +1,211 @@
+/** \file
+ * \brief GTK Driver iupdrvSetGlobal
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvinfo.h"
+#include "iup_strmessage.h"
+
+#include "iupgtk_drv.h"
+
+
+int iupgtk_utf8autoconvert = 1;
+
+static void gtkGlobalSendKey(int key, int press)
+{
+ Ihandle* focus;
+ gint nkeys = 0;
+ GdkKeymapKey *keys;
+ GdkEventKey evt;
+ memset(&evt, 0, sizeof(GdkEventKey));
+ evt.send_event = TRUE;
+
+ focus = IupGetFocus();
+ if (!focus)
+ return;
+ evt.window = focus->handle->window;
+
+ iupgtkKeyEncode(key, &evt.keyval, &evt.state);
+ if (!evt.keyval)
+ return;
+
+ if (!gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), evt.keyval, &keys, &nkeys))
+ return;
+ evt.hardware_keycode = (guint16)keys[0].keycode;
+ evt.group = (guint8)keys[0].group;
+
+ if (press & 0x01)
+ {
+ evt.type = GDK_KEY_PRESS;
+ gdk_display_put_event(gdk_display_get_default(), (GdkEvent*)&evt);
+ }
+
+ if (press & 0x02)
+ {
+ evt.type = GDK_KEY_RELEASE;
+ gdk_display_put_event(gdk_display_get_default(), (GdkEvent*)&evt);
+ }
+}
+
+int iupdrvSetGlobal(const char *name, const char *value)
+{
+ if (iupStrEqual(name, "LANGUAGE"))
+ {
+ iupStrMessageUpdateLanguage(value);
+ return 1;
+ }
+ if (iupStrEqual(name, "CURSORPOS"))
+ {
+#if GTK_CHECK_VERSION(2, 8, 0)
+ int x, y;
+ if (iupStrToIntInt(value, &x, &y, 'x') == 2)
+ gdk_display_warp_pointer(gdk_display_get_default(), gdk_screen_get_default(), x, y);
+#endif
+ return 0;
+ }
+ if (iupStrEqual(name, "UTF8AUTOCONVERT"))
+ {
+ if (!value || iupStrBoolean(value))
+ iupgtk_utf8autoconvert = 1;
+ else
+ iupgtk_utf8autoconvert = 0;
+ return 0;
+ }
+ if (iupStrEqual(name, "KEYPRESS"))
+ {
+ int key;
+ if (iupStrToInt(value, &key))
+ gtkGlobalSendKey(key, 0x01);
+ return 0;
+ }
+ if (iupStrEqual(name, "KEYRELEASE"))
+ {
+ int key;
+ if (iupStrToInt(value, &key))
+ gtkGlobalSendKey(key, 0x02);
+ return 0;
+ }
+ if (iupStrEqual(name, "KEY"))
+ {
+ int key;
+ if (iupStrToInt(value, &key))
+ gtkGlobalSendKey(key, 0x03);
+ return 0;
+ }
+ return 1;
+}
+
+char *iupdrvGetGlobal(const char *name)
+{
+ if (iupStrEqual(name, "CURSORPOS"))
+ {
+ char *str = iupStrGetMemory(50);
+ int x, y;
+ iupdrvGetCursorPos(&x, &y);
+ sprintf(str, "%dx%d", (int)x, (int)y);
+ return str;
+ }
+ if (iupStrEqual(name, "SHIFTKEY"))
+ {
+ char key[5];
+ iupdrvGetKeyState(key);
+ if (key[0] == 'S')
+ return "ON";
+ else
+ return "OFF";
+ }
+ if (iupStrEqual(name, "CONTROLKEY"))
+ {
+ char key[5];
+ iupdrvGetKeyState(key);
+ if (key[1] == 'C')
+ return "ON";
+ else
+ return "OFF";
+ }
+ if (iupStrEqual(name, "MODKEYSTATE"))
+ {
+ char *str = iupStrGetMemory(5);
+ iupdrvGetKeyState(str);
+ return str;
+ }
+ if (iupStrEqual(name, "SCREENSIZE"))
+ {
+ char *str = iupStrGetMemory(50);
+ int w, h;
+ iupdrvGetScreenSize(&w, &h);
+ sprintf(str, "%dx%d", w, h);
+ return str;
+ }
+ if (iupStrEqual(name, "FULLSIZE"))
+ {
+ char *str = iupStrGetMemory(50);
+ int w, h;
+ iupdrvGetFullSize(&w, &h);
+ sprintf(str, "%dx%d", w, h);
+ return str;
+ }
+ if (iupStrEqual(name, "SCREENDEPTH"))
+ {
+ char *str = iupStrGetMemory(50);
+ int bpp = iupdrvGetScreenDepth();
+ sprintf(str, "%d", bpp);
+ return str;
+ }
+ if (iupStrEqual(name, "VIRTUALSCREEN"))
+ {
+ char *str = iupStrGetMemory(50);
+ GdkScreen *screen = gdk_screen_get_default();
+ GdkWindow *root = gdk_screen_get_root_window(gdk_screen_get_default());
+ int x = 0;
+ int y = 0;
+ int w = gdk_screen_get_width(screen);
+ int h = gdk_screen_get_height(screen);
+ gdk_window_get_root_origin(root, &x, &y);
+ sprintf(str, "%d %d %d %d", x, y, w, h);
+ return str;
+ }
+ if (iupStrEqual(name, "MONITORSINFO"))
+ {
+ int i;
+ GdkScreen *screen = gdk_screen_get_default();
+ int monitors_count = gdk_screen_get_n_monitors(screen);
+ char *str = iupStrGetMemory(monitors_count*50);
+ char* pstr = str;
+ GdkRectangle rect;
+
+ for (i=0; i < monitors_count; i++)
+ {
+ gdk_screen_get_monitor_geometry(screen, i, &rect);
+ pstr += sprintf(pstr, "%d %d %d %d\n", rect.x, rect.y, rect.width, rect.height);
+ }
+
+ return str;
+ }
+ if (iupStrEqual(name, "TRUECOLORCANVAS"))
+ {
+ if (gdk_visual_get_best_depth() > 8)
+ return "YES";
+ else
+ return "NO";
+ }
+ if (iupStrEqual(name, "UTF8AUTOCONVERT"))
+ {
+ if (iupgtk_utf8autoconvert)
+ return "YES";
+ else
+ return "NO";
+ }
+ return NULL;
+}
diff --git a/iup/src/gtk/iupgtk_help.c b/iup/src/gtk/iupgtk_help.c
new file mode 100755
index 0000000..270677f
--- /dev/null
+++ b/iup/src/gtk/iupgtk_help.c
@@ -0,0 +1,52 @@
+/** \file
+ * \brief GTK Driver IupHelp for non Windows systems
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "iup.h"
+
+#include "iup_str.h"
+
+int IupHelp(const char *url)
+{
+ GError *error = NULL;
+ gchar *argv[3];
+ int ret;
+ char *browser = getenv("IUP_HELPAPP");
+ if (!browser)
+ browser = IupGetGlobal("HELPAPP");
+
+ if (!browser)
+ {
+ char* system = IupGetGlobal("SYSTEM");
+ if (iupStrEqualNoCase(system, "Linux") ||
+ iupStrEqualNoCase(system, "FreeBSD"))
+ browser = "firefox";
+ else if (iupStrEqualNoCase(system, "Darwin"))
+ browser = "safari";
+ else if (iupStrEqualPartial(system, "CYGWIN"))
+ browser = "iexplore";
+ else
+ browser = "netscape";
+ }
+
+ argv[0] = browser;
+ argv[1] = (gchar*)url;
+ argv[2] = NULL;
+
+ ret = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error);
+
+ if (error)
+ g_error_free(error);
+
+ if (!ret)
+ return -1;
+ return 1;
+}
diff --git a/iup/src/gtk/iupgtk_image.c b/iup/src/gtk/iupgtk_image.c
new file mode 100755
index 0000000..b261974
--- /dev/null
+++ b/iup/src/gtk/iupgtk_image.c
@@ -0,0 +1,430 @@
+/** \file
+ * \brief Image Resource.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_image.h"
+#include "iup_drvinfo.h"
+
+#include "iupgtk_drv.h"
+
+
+void iupdrvImageGetRawData(void* handle, unsigned char* imgdata)
+{
+ GdkPixbuf* pixbuf = (GdkPixbuf*)handle;
+ int w, h, y, x, bpp;
+ guchar *pixdata, *pixline_data;
+ int rowstride, channels, planesize;
+ unsigned char *r, *g, *b, *a;
+
+ if (!iupdrvImageGetInfo(handle, &w, &h, &bpp))
+ return;
+
+ if (bpp==8)
+ return;
+
+ pixdata = gdk_pixbuf_get_pixels(pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride(pixbuf);
+ channels = gdk_pixbuf_get_n_channels(pixbuf);
+
+ /* planes are separated in imgdata */
+ planesize = w*h;
+ r = imgdata;
+ g = imgdata+planesize;
+ b = imgdata+2*planesize;
+ a = imgdata+3*planesize;
+ for (y=0; y<h; y++)
+ {
+ int lineoffset = (h-1 - y)*w; /* imgdata is bottom up */
+ pixline_data = pixdata + y * rowstride;
+ for(x=0;x<w;x++)
+ {
+ int pos = x*channels;
+ r[lineoffset+x] = pixline_data[pos];
+ g[lineoffset+x] = pixline_data[pos+1];
+ b[lineoffset+x] = pixline_data[pos+2];
+
+ if (bpp == 32)
+ a[lineoffset+x] = pixline_data[pos+3];
+ }
+ }
+}
+
+void* iupdrvImageCreateImageRaw(int width, int height, int bpp, iupColor* colors, int colors_count, unsigned char *imgdata)
+{
+ GdkPixbuf* pixbuf;
+ guchar *pixdata, *pixline_data;
+ int rowstride, channels;
+ unsigned char *line_data;
+ int x, y, has_alpha = (bpp==32);
+ (void)colors_count;
+
+ pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, has_alpha, 8, width, height);
+ if (!pixbuf)
+ return NULL;
+
+ pixdata = gdk_pixbuf_get_pixels(pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride(pixbuf);
+ channels = gdk_pixbuf_get_n_channels(pixbuf);
+
+ /* GdkPixbuf is top-bottom */
+ /* imgdata is bottom up */
+
+ if (bpp == 8)
+ {
+ for (y=0; y<height; y++)
+ {
+ pixline_data = pixdata + y * rowstride;
+ line_data = imgdata + (height-1 - y) * width; /* imgdata is bottom up */
+
+ for (x=0; x<width; x++)
+ {
+ unsigned char index = line_data[x];
+ iupColor* c = &colors[index];
+ guchar *r = &pixline_data[channels*x],
+ *g = r+1,
+ *b = g+1;
+
+ *r = c->r;
+ *g = c->g;
+ *b = c->b;
+ }
+ }
+ }
+ else /* bpp == 32 or bpp == 24 */
+ {
+ /* planes are separated in imgdata */
+ int planesize = width*height;
+ unsigned char *r = imgdata,
+ *g = imgdata+planesize,
+ *b = imgdata+2*planesize,
+ *a = imgdata+3*planesize;
+ for (y=0; y<height; y++)
+ {
+ int lineoffset = (height-1 - y)*width; /* imgdata is bottom up */
+ pixline_data = pixdata + y * rowstride;
+ for(x=0;x<width;x++)
+ {
+ int pos = x*channels;
+ pixline_data[pos] = r[lineoffset+x];
+ pixline_data[pos+1] = g[lineoffset+x];
+ pixline_data[pos+2] = b[lineoffset+x];
+
+ if (bpp == 32)
+ pixline_data[pos+3] = a[lineoffset+x];
+ }
+ }
+ }
+
+ return pixbuf;
+}
+
+void* iupdrvImageCreateImage(Ihandle *ih, const char* bgcolor, int make_inactive)
+{
+ GdkPixbuf* pixbuf;
+ guchar *pixdata, *pixline_data;
+ int rowstride, channels;
+ unsigned char *imgdata, *line_data, bg_r=0, bg_g=0, bg_b=0;
+ int x, y, i, bpp, colors_count = 0, has_alpha = 0;
+ iupColor colors[256];
+
+ bpp = iupAttribGetInt(ih, "BPP");
+
+ if (bpp == 8)
+ has_alpha = iupImageInitColorTable(ih, colors, &colors_count);
+ else if (bpp == 32)
+ has_alpha = 1;
+
+ pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, has_alpha, 8, ih->currentwidth, ih->currentheight);
+ if (!pixbuf)
+ return NULL;
+
+ pixdata = gdk_pixbuf_get_pixels(pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride(pixbuf);
+ channels = gdk_pixbuf_get_n_channels(pixbuf);
+ imgdata = (unsigned char*)iupAttribGetStr(ih, "WID");
+
+ if (make_inactive)
+ iupStrToRGB(bgcolor, &bg_r, &bg_g, &bg_b);
+
+ if (bpp == 8)
+ {
+ if (make_inactive)
+ {
+ for (i=0;i<colors_count;i++)
+ {
+ if (colors[i].a == 0)
+ {
+ colors[i].r = bg_r;
+ colors[i].g = bg_g;
+ colors[i].b = bg_b;
+ colors[i].a = 255;
+ }
+
+ iupImageColorMakeInactive(&(colors[i].r), &(colors[i].g), &(colors[i].b),
+ bg_r, bg_g, bg_b);
+ }
+ }
+
+ for (y=0; y<ih->currentheight; y++)
+ {
+ pixline_data = pixdata + y * rowstride;
+ line_data = imgdata + y * ih->currentwidth;
+
+ for (x=0; x<ih->currentwidth; x++)
+ {
+ unsigned char index = line_data[x];
+ iupColor* c = &colors[index];
+ guchar *r = &pixline_data[channels*x],
+ *g = r+1,
+ *b = g+1,
+ *a = b+1;
+
+ *r = c->r;
+ *g = c->g;
+ *b = c->b;
+
+ if (has_alpha)
+ *a = c->a;
+ }
+ }
+ }
+ else /* bpp == 32 or bpp == 24 */
+ {
+ for (y=0; y<ih->currentheight; y++)
+ {
+ pixline_data = pixdata + y * rowstride;
+ line_data = imgdata + y * ih->currentwidth*channels;
+
+ memcpy(pixline_data, line_data, ih->currentwidth*channels);
+
+ if (make_inactive)
+ {
+ for (x=0; x<ih->currentwidth; x++)
+ {
+ guchar *r = &pixline_data[channels*x],
+ *g = r+1,
+ *b = g+1,
+ *a = b+1;
+
+ if (has_alpha)
+ {
+ if (*a != 255)
+ {
+ *r = iupALPHABLEND(*r, bg_r, *a);
+ *g = iupALPHABLEND(*g, bg_g, *a);
+ *b = iupALPHABLEND(*b, bg_b, *a);
+ }
+ else
+ *a = 255;
+ }
+
+ iupImageColorMakeInactive(r, g, b,
+ bg_r, bg_g, bg_b);
+ }
+ }
+ }
+ }
+
+ return pixbuf;
+}
+
+void* iupdrvImageCreateIcon(Ihandle *ih)
+{
+ return iupdrvImageCreateImage(ih, NULL, 0);
+}
+
+void* iupdrvImageCreateCursor(Ihandle *ih)
+{
+ GdkCursor *cursor;
+ int hx, hy, bpp;
+
+ hx=0; hy=0;
+ iupStrToIntInt(iupAttribGet(ih, "HOTSPOT"), &hx, &hy, ':');
+
+ bpp = iupAttribGetInt(ih, "BPP");
+
+ if (bpp == 8 && !iupAttribGet(ih, "3"))
+ {
+ GdkPixmap *source, *mask;
+ GdkColor fg, bg;
+ unsigned char r, g, b;
+ char *sbits, *mbits, *sb, *mb;
+ int y, x, line_size = (ih->currentwidth+7)/8;
+ int size_bytes = line_size*ih->currentheight;
+ unsigned char* imgdata = (unsigned char*)iupAttribGetStr(ih, "WID");
+
+ r = 255; g = 255; b = 255;
+ iupStrToRGB(iupAttribGet(ih, "1"), &r, &g, &b );
+ iupgdkColorSet(&fg, r, g, b);
+
+ r = 0; g = 0; b = 0;
+ iupStrToRGB(iupAttribGet(ih, "2"), &r, &g, &b );
+ iupgdkColorSet(&bg, r, g, b);
+
+ sbits = (char*)malloc(2*size_bytes);
+ if (!sbits) return NULL;
+ memset(sbits, 0, 2*size_bytes);
+ mbits = sbits + size_bytes;
+
+ sb = sbits;
+ mb = mbits;
+ for (y=0; y<ih->currentheight; y++)
+ {
+ for (x=0; x<ih->currentwidth; x++)
+ {
+ int byte = x/8;
+ int bit = x%8;
+ int index = (int)imgdata[y*ih->currentwidth+x];
+ /* index==0 is transparent */
+ if (index == 1)
+ sb[byte] = (char)(sb[byte] | (1<<bit));
+ if (index != 0)
+ mb[byte] = (char)(mb[byte] | (1<<bit));
+ }
+
+ sb += line_size;
+ mb += line_size;
+ }
+
+ source = gdk_bitmap_create_from_data(NULL, sbits, ih->currentwidth, ih->currentheight);
+ mask = gdk_bitmap_create_from_data(NULL, mbits, ih->currentwidth, ih->currentheight);
+
+ cursor = gdk_cursor_new_from_pixmap(source, mask, &fg, &bg, hx, hy);
+
+ gdk_pixmap_unref(source);
+ gdk_pixmap_unref(mask);
+ free(sbits);
+ }
+ else
+ {
+ GdkPixbuf* pixbuf = iupdrvImageCreateImage(ih, NULL, 0);
+ cursor = gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pixbuf, hx, hy);
+ g_object_unref(pixbuf);
+ }
+
+ return cursor;
+}
+
+void* iupdrvImageCreateMask(Ihandle *ih)
+{
+ int bpp;
+ GdkPixmap *mask;
+ char *bits, *sb;
+ int y, x, line_size = (ih->currentwidth+7)/8;
+ int size_bytes = line_size*ih->currentheight;
+ unsigned char* imgdata = (unsigned char*)iupAttribGetStr(ih, "WID");
+ unsigned char colors[256];
+
+ bpp = iupAttribGetInt(ih, "BPP");
+ if (bpp > 8)
+ return NULL;
+
+ bits = (char*)malloc(size_bytes);
+ if (!bits) return NULL;
+ memset(bits, 0, size_bytes);
+
+ iupImageInitNonBgColors(ih, colors);
+
+ sb = bits;
+ for (y=0; y<ih->currentheight; y++)
+ {
+ for (x=0; x<ih->currentwidth; x++)
+ {
+ int byte = x/8;
+ int bit = x%8;
+ int index = (int)imgdata[y*ih->currentwidth+x];
+ if (colors[index])
+ sb[byte] = (char)(sb[byte] | (1<<bit));
+ }
+
+ sb += line_size;
+ }
+
+ mask = gdk_bitmap_create_from_data(NULL, bits, ih->currentwidth, ih->currentheight);
+
+ free(bits);
+
+ return mask;
+}
+
+void* iupdrvImageLoad(const char* name, int type)
+{
+ if (type == IUPIMAGE_CURSOR)
+#if GTK_CHECK_VERSION(2, 8, 0)
+ return gdk_cursor_new_from_name(gdk_display_get_default(), name);
+#else
+ return NULL;
+#endif
+ else
+ {
+ GtkIconTheme *icon_theme;
+ GdkPixbuf *pixbuf = NULL;
+
+ icon_theme = gtk_icon_theme_get_default();
+ if (gtk_icon_theme_has_icon(icon_theme, name))
+ {
+ GError *error = NULL;
+ pixbuf = gtk_icon_theme_load_icon(icon_theme, name,
+ 24, /* size */
+ 0, /* flags */
+ &error);
+ if (error)
+ g_error_free(error);
+ }
+
+ if (!pixbuf)
+ {
+ GError *error = NULL;
+ pixbuf = gdk_pixbuf_new_from_file(name, &error);
+ if (error)
+ g_error_free(error);
+ }
+
+ return pixbuf;
+ }
+}
+
+int iupdrvImageGetInfo(void* handle, int *w, int *h, int *bpp)
+{
+ GdkPixbuf* pixbuf = (GdkPixbuf*)handle;
+ if (!GDK_IS_PIXBUF(pixbuf))
+ {
+ if (w) *w = 0;
+ if (h) *h = 0;
+ if (bpp) *bpp = 0;
+ return 0;
+ }
+ if (w) *w = gdk_pixbuf_get_width(pixbuf);
+ if (h) *h = gdk_pixbuf_get_height(pixbuf);
+ if (bpp) *bpp = iupImageNormBpp(gdk_pixbuf_get_bits_per_sample(pixbuf)*gdk_pixbuf_get_n_channels(pixbuf));
+ return 1;
+}
+
+int iupdrvImageGetRawInfo(void* handle, int *w, int *h, int *bpp, iupColor* colors, int *colors_count)
+{
+ /* GdkPixbuf are only 24 bpp or 32 bpp */
+ (void)colors;
+ (void)colors_count;
+ return iupdrvImageGetInfo(handle, w, h, bpp);
+}
+
+void iupdrvImageDestroy(void* handle, int type)
+{
+ if (type == IUPIMAGE_CURSOR)
+ gdk_cursor_unref((GdkCursor*)handle);
+ else
+ g_object_unref(handle);
+}
diff --git a/iup/src/gtk/iupgtk_key.c b/iup/src/gtk/iupgtk_key.c
new file mode 100755
index 0000000..5aec919
--- /dev/null
+++ b/iup/src/gtk/iupgtk_key.c
@@ -0,0 +1,422 @@
+/** \file
+ * \brief GTK Driver keyboard mapping
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+#include "iupkey.h"
+
+#include "iup_object.h"
+#include "iup_key.h"
+
+#include "iupgtk_drv.h"
+
+
+typedef struct _Igtk2iupkey
+{
+ guint gtkcode;
+ int iupcode;
+ int s_iupcode;
+ int c_iupcode;
+ int m_iupcode;
+ int y_iupcode;
+} Igtk2iupkey;
+
+static Igtk2iupkey gtkkey_map[] = {
+
+{ GDK_Escape, K_ESC, K_sESC, K_cESC, K_mESC ,K_yESC },
+{ GDK_Pause, K_PAUSE, K_sPAUSE, K_cPAUSE, K_mPAUSE ,K_yPAUSE },
+{ GDK_Print, K_Print, K_sPrint, K_cPrint, K_mPrint ,K_yPrint },
+{ GDK_Menu, K_Menu, K_sMenu, K_cMenu, K_mMenu ,K_yMenu },
+
+{ GDK_Home, K_HOME, K_sHOME, K_cHOME, K_mHOME ,K_yHOME },
+{ GDK_Up, K_UP, K_sUP, K_cUP, K_mUP ,K_yUP },
+{ GDK_Prior, K_PGUP, K_sPGUP, K_cPGUP, K_mPGUP ,K_yPGUP },
+{ GDK_Left, K_LEFT, K_sLEFT, K_cLEFT, K_mLEFT ,K_yLEFT },
+{ GDK_Begin, K_MIDDLE,K_sMIDDLE, K_cMIDDLE,K_mMIDDLE,K_yMIDDLE},
+{ GDK_Right, K_RIGHT, K_sRIGHT, K_cRIGHT, K_mRIGHT ,K_yRIGHT },
+{ GDK_End, K_END, K_sEND, K_cEND, K_mEND ,K_yEND },
+{ GDK_Down, K_DOWN, K_sDOWN, K_cDOWN, K_mDOWN ,K_yDOWN },
+{ GDK_Next, K_PGDN, K_sPGDN, K_cPGDN, K_mPGDN ,K_yPGDN },
+{ GDK_Insert, K_INS, K_sINS, K_cINS, K_mINS ,K_yINS },
+{ GDK_Delete, K_DEL, K_sDEL, K_cDEL, K_mDEL ,K_yDEL },
+{ GDK_space, K_SP, K_sSP, K_cSP, K_mSP ,K_ySP },
+{ GDK_Tab, K_TAB, K_sTAB, K_cTAB, K_mTAB ,K_yTAB },
+{ GDK_Return, K_CR, K_sCR, K_cCR, K_mCR ,K_yCR },
+{ GDK_BackSpace, K_BS, K_sBS, K_cBS, K_mBS ,K_yBS },
+
+{ GDK_1, K_1, K_exclam, K_c1, K_m1, K_y1 },
+{ GDK_2, K_2, K_at, K_c2, K_m2, K_y2 },
+{ GDK_3, K_3, K_numbersign, K_c3, K_m3, K_y3 },
+{ GDK_4, K_4, K_dollar, K_c4, K_m4, K_y4 },
+{ GDK_5, K_5, K_percent, K_c5, K_m5, K_y5 },
+{ GDK_6, K_6, K_circum, K_c6, K_m6, K_y6 },
+{ GDK_7, K_7, K_ampersand, K_c7, K_m7, K_y7 },
+{ GDK_8, K_8, K_asterisk, K_c8, K_m8, K_y8 },
+{ GDK_9, K_9, K_parentleft, K_c9, K_m9, K_y9 },
+{ GDK_0, K_0, K_parentright, K_c0, K_m0, K_y0 },
+
+/* Shift will be flaged so s_iupcode will contain the right code */
+{ GDK_exclam, K_1, K_exclam, K_c1, K_m1, K_y1 },
+{ GDK_at, K_2, K_at, K_c2, K_m2, K_y2 },
+{ GDK_numbersign, K_3, K_numbersign, K_c3, K_m3, K_y3 },
+{ GDK_dollar, K_4, K_dollar, K_c4, K_m4, K_y4 },
+{ GDK_percent, K_5, K_percent, K_c5, K_m5, K_y5 },
+{ GDK_dead_diaeresis, K_6, K_circum, K_c6, K_m6, K_y6 },
+{ GDK_ampersand, K_7, K_ampersand, K_c7, K_m7, K_y7 },
+{ GDK_asterisk, K_8, K_asterisk, K_c8, K_m8, K_y8 },
+{ GDK_parenleft, K_9, K_parentleft, K_c9, K_m9, K_y9 },
+{ GDK_parenright, K_0, K_parentright, K_c0, K_m0, K_y0 },
+
+{ GDK_a, K_a, K_A, K_cA, K_mA, K_yA },
+{ GDK_b, K_b, K_B, K_cB, K_mB, K_yB },
+{ GDK_c, K_c, K_C, K_cC, K_mC, K_yC },
+{ GDK_d, K_d, K_D, K_cD, K_mD, K_yD },
+{ GDK_e, K_e, K_E, K_cE, K_mE, K_yE },
+{ GDK_f, K_f, K_F, K_cF, K_mF, K_yF },
+{ GDK_g, K_g, K_G, K_cG, K_mG, K_yG },
+{ GDK_h, K_h, K_H, K_cH, K_mH, K_yH },
+{ GDK_i, K_i, K_I, K_cI, K_mI, K_yI },
+{ GDK_j, K_j, K_J, K_cJ, K_mJ, K_yJ },
+{ GDK_k, K_k, K_K, K_cK, K_mK, K_yK },
+{ GDK_l, K_l, K_L, K_cL, K_mL, K_yL },
+{ GDK_m, K_m, K_M, K_cM, K_mM, K_yM },
+{ GDK_n, K_n, K_N, K_cN, K_mN, K_yN },
+{ GDK_o, K_o, K_O, K_cO, K_mO, K_yO },
+{ GDK_p, K_p, K_P, K_cP, K_mP, K_yP },
+{ GDK_q, K_q, K_Q, K_cQ, K_mQ, K_yQ },
+{ GDK_r, K_r, K_R, K_cR, K_mR, K_yR },
+{ GDK_s, K_s, K_S, K_cS, K_mS, K_yS },
+{ GDK_t, K_t, K_T, K_cT, K_mT, K_yT },
+{ GDK_u, K_u, K_U, K_cU, K_mU, K_yU },
+{ GDK_v, K_v, K_V, K_cV, K_mV, K_yV },
+{ GDK_w, K_w, K_W, K_cW, K_mW, K_yW },
+{ GDK_x, K_x, K_X, K_cX, K_mX, K_yX },
+{ GDK_y, K_y, K_Y, K_cY, K_mY, K_yY },
+{ GDK_z, K_z, K_Z, K_cZ, K_mZ, K_yZ },
+
+/* Shift will be flaged so s_iupcode will contain the right code */
+{ GDK_A, K_a, K_A, K_cA, K_mA, K_yA },
+{ GDK_B, K_b, K_B, K_cB, K_mB, K_yB },
+{ GDK_C, K_c, K_C, K_cC, K_mC, K_yC },
+{ GDK_D, K_d, K_D, K_cD, K_mD, K_yD },
+{ GDK_E, K_e, K_E, K_cE, K_mE, K_yE },
+{ GDK_F, K_f, K_F, K_cF, K_mF, K_yF },
+{ GDK_G, K_g, K_G, K_cG, K_mG, K_yG },
+{ GDK_H, K_h, K_H, K_cH, K_mH, K_yH },
+{ GDK_I, K_i, K_I, K_cI, K_mI, K_yI },
+{ GDK_J, K_j, K_J, K_cJ, K_mJ, K_yJ },
+{ GDK_K, K_k, K_K, K_cK, K_mK, K_yK },
+{ GDK_L, K_l, K_L, K_cL, K_mL, K_yL },
+{ GDK_M, K_m, K_M, K_cM, K_mM, K_yM },
+{ GDK_N, K_n, K_N, K_cN, K_mN, K_yN },
+{ GDK_O, K_o, K_O, K_cO, K_mO, K_yO },
+{ GDK_P, K_p, K_P, K_cP, K_mP, K_yP },
+{ GDK_Q, K_q, K_Q, K_cQ, K_mQ, K_yQ },
+{ GDK_R, K_r, K_R, K_cR, K_mR, K_yR },
+{ GDK_S, K_s, K_S, K_cS, K_mS, K_yS },
+{ GDK_T, K_t, K_T, K_cT, K_mT, K_yT },
+{ GDK_U, K_u, K_U, K_cU, K_mU, K_yU },
+{ GDK_V, K_v, K_V, K_cV, K_mV, K_yV },
+{ GDK_W, K_w, K_W, K_cW, K_mW, K_yW },
+{ GDK_X, K_x, K_X, K_cX, K_mX, K_yX },
+{ GDK_Y, K_y, K_Y, K_cY, K_mY, K_yY },
+{ GDK_Z, K_z, K_Z, K_cZ, K_mZ, K_yZ },
+
+{ GDK_F1, K_F1, K_sF1, K_cF1, K_mF1, K_yF1 },
+{ GDK_F2, K_F2, K_sF2, K_cF2, K_mF2, K_yF2 },
+{ GDK_F3, K_F3, K_sF3, K_cF3, K_mF3, K_yF3 },
+{ GDK_F4, K_F4, K_sF4, K_cF4, K_mF4, K_yF4 },
+{ GDK_F5, K_F5, K_sF5, K_cF5, K_mF5, K_yF5 },
+{ GDK_F6, K_F6, K_sF6, K_cF6, K_mF6, K_yF6 },
+{ GDK_F7, K_F7, K_sF7, K_cF7, K_mF7, K_yF7 },
+{ GDK_F8, K_F8, K_sF8, K_cF8, K_mF8, K_yF8 },
+{ GDK_F9, K_F9, K_sF9, K_cF9, K_mF9, K_yF9 },
+{ GDK_F10, K_F10, K_sF10, K_cF10, K_mF10, K_yF10 },
+{ GDK_F11, K_F11, K_sF11, K_cF11, K_mF11, K_yF11 },
+{ GDK_F12, K_F12, K_sF12, K_cF12, K_mF12, K_yF12 },
+
+{ GDK_semicolon, K_semicolon, K_colon, K_cSemicolon, K_mSemicolon, K_ySemicolon },
+{ GDK_equal, K_equal, K_plus, K_cEqual, K_mEqual, K_yEqual },
+{ GDK_comma, K_comma, K_less, K_cComma, K_mComma, K_yComma },
+{ GDK_minus, K_minus, K_underscore, K_cMinus, K_mMinus, K_yMinus },
+{ GDK_period, K_period, K_greater, K_cPeriod, K_mPeriod, K_yPeriod },
+{ GDK_slash, K_slash, K_question, K_cSlash, K_mSlash, K_ySlash },
+{ GDK_grave, K_grave, K_tilde, 0, 0, 0 },
+{ GDK_bracketleft, K_bracketleft, K_braceleft, K_cBracketleft, K_mBracketleft, K_yBracketleft },
+{ GDK_backslash, K_backslash, K_bar, K_cBackslash, K_mBackslash, K_yBackslash },
+{ GDK_bracketright,K_bracketright, K_braceright, K_cBracketright,K_mBracketright,K_yBracketright },
+{ GDK_apostrophe, K_apostrophe, K_quotedbl, 0, 0, 0 },
+
+/* Shift will be flaged so s_iupcode will contain the right code */
+{ GDK_colon, K_semicolon, K_colon, K_cSemicolon, K_mSemicolon, K_ySemicolon },
+{ GDK_plus, K_equal, K_plus, K_cEqual, K_mEqual, K_yEqual },
+{ GDK_less, K_comma, K_less, K_cComma, K_mComma, K_yComma },
+{ GDK_underscore, K_minus, K_underscore, K_cMinus, K_mMinus, K_yMinus },
+{ GDK_greater, K_period, K_greater, K_cPeriod, K_mPeriod, K_yPeriod },
+{ GDK_question, K_slash, K_question, K_cSlash, K_mSlash, K_ySlash },
+{ GDK_braceleft, K_bracketleft, K_braceleft, K_cBracketleft, K_mBracketleft, K_yBracketleft },
+{ GDK_bar, K_backslash, K_bar, K_cBackslash, K_mBackslash, K_yBackslash },
+{ GDK_braceright, K_bracketright, K_braceright, K_cBracketright,K_mBracketright,K_yBracketright },
+{ GDK_quotedbl, K_apostrophe, K_quotedbl, 0, 0, 0 },
+
+{ GDK_KP_0, K_0, K_0, K_c0, K_m0, K_y0 },
+{ GDK_KP_1, K_1, K_1, K_c1, K_m1, K_y1 },
+{ GDK_KP_2, K_2, K_2, K_c2, K_m2, K_y2 },
+{ GDK_KP_3, K_3, K_3, K_c3, K_m3, K_y3 },
+{ GDK_KP_4, K_4, K_4, K_c4, K_m4, K_y4 },
+{ GDK_KP_5, K_5, K_5, K_c5, K_m5, K_y5 },
+{ GDK_KP_6, K_6, K_6, K_c6, K_m6, K_y6 },
+{ GDK_KP_7, K_7, K_7, K_c7, K_m7, K_y7 },
+{ GDK_KP_8, K_8, K_8, K_c8, K_m8, K_y8 },
+{ GDK_KP_9, K_9, K_9, K_c9, K_m9, K_y9 },
+{ GDK_KP_Multiply, K_asterisk, K_sAsterisk, K_cAsterisk, K_mAsterisk, K_yAsterisk },
+{ GDK_KP_Add, K_plus, K_sPlus, K_cPlus, K_mPlus, K_yPlus },
+{ GDK_KP_Subtract, K_minus, K_sMinus, K_cMinus, K_mMinus, K_yMinus },
+{ GDK_KP_Decimal, K_period, K_sPeriod, K_cPeriod, K_mPeriod, K_yPeriod },
+{ GDK_KP_Divide, K_slash, K_sSlash, K_cSlash, K_mSlash, K_ySlash },
+{ GDK_KP_Separator, K_comma, K_sComma, K_cComma, K_mComma, K_yComma },
+
+{ GDK_ccedilla, K_ccedilla, K_Ccedilla, K_cCcedilla, K_mCcedilla, K_yCcedilla },
+{ GDK_Ccedilla, K_ccedilla, K_Ccedilla, K_cCcedilla, K_mCcedilla, K_yCcedilla },
+
+{ GDK_dead_tilde, K_tilde, K_circum, 0, 0, 0 },
+{ GDK_dead_acute, K_acute, K_grave, 0, 0, 0 },
+{ GDK_dead_grave, K_grave, K_tilde, 0, 0, 0 },
+{ GDK_dead_circumflex, K_tilde, K_circum, 0, 0, 0 },
+
+{ GDK_KP_F1, K_F1, K_sF1, K_cF1, K_mF1, K_yF1 },
+{ GDK_KP_F2, K_F2, K_sF2, K_cF2, K_mF2, K_yF2 },
+{ GDK_KP_F3, K_F3, K_sF3, K_cF3, K_mF3, K_yF3 },
+{ GDK_KP_F4, K_F4, K_sF4, K_cF4, K_mF4, K_yF4 },
+{ GDK_KP_Space, K_SP, K_sSP, K_cSP, K_mSP ,K_ySP },
+{ GDK_KP_Tab, K_TAB, K_sTAB, K_cTAB, K_mTAB ,K_yTAB },
+{ GDK_KP_Equal, K_equal, 0, K_cEqual, K_mEqual, K_yEqual },
+
+{ GDK_KP_Enter, K_CR, K_sCR, K_cCR, K_mCR, K_yCR },
+{ GDK_KP_Home, K_HOME, K_sHOME, K_cHOME, K_mHOME, K_yHOME },
+{ GDK_KP_Up, K_UP, K_sUP, K_cUP, K_mUP, K_yUP },
+{ GDK_KP_Page_Up, K_PGUP, K_sPGUP, K_cPGUP, K_mPGUP, K_yPGUP },
+{ GDK_KP_Left, K_LEFT, K_sLEFT, K_cLEFT, K_mLEFT, K_yLEFT },
+{ GDK_KP_Begin, K_MIDDLE,K_sMIDDLE, K_cMIDDLE,K_mMIDDLE,K_yMIDDLE},
+{ GDK_KP_Right, K_RIGHT, K_sRIGHT, K_cRIGHT, K_mRIGHT, K_yRIGHT },
+{ GDK_KP_End, K_END, K_sEND, K_cEND, K_mEND, K_yEND },
+{ GDK_KP_Down, K_DOWN, K_sDOWN, K_cDOWN, K_mDOWN, K_yDOWN },
+{ GDK_KP_Page_Down, K_PGDN, K_sPGDN, K_cPGDN, K_mPGDN, K_yPGDN },
+{ GDK_KP_Insert, K_INS, K_sINS, K_cINS, K_mINS, K_yINS },
+{ GDK_KP_Delete, K_DEL, K_sDEL, K_cDEL, K_mDEL, K_yDEL }
+
+};
+
+void iupgtkKeyEncode(int key, guint *keyval, guint *state)
+{
+ int i, iupcode = key & 0xFF; /* 0-255 interval */
+ int count = sizeof(gtkkey_map)/sizeof(gtkkey_map[0]);
+ for (i = 0; i < count; i++)
+ {
+ Igtk2iupkey* key_map = &(gtkkey_map[i]);
+ if (key_map->iupcode == iupcode)
+ {
+ *keyval = key_map->gtkcode;
+ *state = 0;
+
+ if (iupcode != key)
+ {
+ if (key_map->c_iupcode == key)
+ *state = GDK_CONTROL_MASK;
+ else if (key_map->m_iupcode == key)
+ *state = GDK_MOD1_MASK;
+ else if (key_map->y_iupcode == key)
+ *state = GDK_MOD4_MASK;
+ else if (key_map->s_iupcode == key)
+ *state = GDK_SHIFT_MASK;
+ }
+ return;
+ }
+ else if (key_map->s_iupcode == key) /* There are Shift keys bellow 256 */
+ {
+ *keyval = key_map->gtkcode;
+ *state = GDK_SHIFT_MASK;
+
+ if ((*keyval >= GDK_a) &&
+ (*keyval <= GDK_z))
+ {
+ /* remap to upper case */
+ *keyval -= GDK_a-GDK_A;
+ }
+ return;
+ }
+ }
+}
+
+static int gtkKeyMap2Iup(int state, int i)
+{
+ int code = 0;
+ if (state & GDK_CONTROL_MASK) /* Ctrl */
+ code = gtkkey_map[i].c_iupcode;
+ else if (state & GDK_MOD1_MASK ||
+ state & GDK_MOD5_MASK) /* Alt */
+ code = gtkkey_map[i].m_iupcode;
+ else if (state & GDK_MOD4_MASK) /* Apple/Win */
+ code = gtkkey_map[i].y_iupcode;
+ else if (state & GDK_LOCK_MASK) /* CapsLock */
+ {
+ if ((state & GDK_SHIFT_MASK) || !iupKeyCanCaps(gtkkey_map[i].iupcode))
+ return gtkkey_map[i].iupcode;
+ else
+ code = gtkkey_map[i].s_iupcode;
+ }
+ else if (state & GDK_SHIFT_MASK) /* Shift */
+ code = gtkkey_map[i].s_iupcode;
+ else
+ return gtkkey_map[i].iupcode;
+
+ if (!code)
+ code = gtkkey_map[i].iupcode;
+
+ return code;
+}
+
+static int gtkKeyDecode(GdkEventKey *evt)
+{
+ int i;
+ int count = sizeof(gtkkey_map)/sizeof(gtkkey_map[0]);
+ guint keyval = evt->keyval;
+
+ if ((evt->state & GDK_MOD2_MASK) && /* NumLock */
+ (keyval >= GDK_KP_Home) &&
+ (keyval <= GDK_KP_Delete))
+ {
+ /* remap to numeric keys */
+ guint remap_numkey[] = {GDK_KP_7, GDK_KP_4, GDK_KP_8, GDK_KP_6, GDK_KP_2, GDK_KP_9, GDK_KP_3, GDK_KP_1, GDK_KP_5, GDK_KP_0, GDK_KP_Decimal};
+ keyval = remap_numkey[keyval-GDK_KP_Home];
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ if (gtkkey_map[i].gtkcode == keyval)
+ return gtkKeyMap2Iup(evt->state, i);
+ }
+
+ return 0;
+}
+
+gboolean iupgtkKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
+{
+ int result;
+ int code = gtkKeyDecode(evt);
+ if (code == 0)
+ return FALSE;
+
+ /* Avoid duplicate calls if a child of the dialog contains the focus.
+ GTK will call the callback for the child and for the dialog */
+ if (ih->iclass->nativetype == IUP_TYPEDIALOG && ih != IupGetFocus())
+ return FALSE;
+
+ result = iupKeyCallKeyCb(ih, code);
+ if (result == IUP_CLOSE)
+ {
+ IupExitLoop();
+ return FALSE;
+ }
+ if (result == IUP_IGNORE)
+ return TRUE;
+
+ /* in the previous callback the dialog could be destroyed */
+ if (iupObjectCheck(ih))
+ {
+ /* this is called only for canvas */
+ if (ih->iclass->nativetype == IUP_TYPECANVAS)
+ {
+ result = iupKeyCallKeyPressCb(ih, code, 1);
+ if (result == IUP_CLOSE)
+ {
+ IupExitLoop();
+ return FALSE;
+ }
+ if (result == IUP_IGNORE)
+ return TRUE;
+ }
+
+ if (!iupKeyProcessNavigation(ih, code, evt->state & GDK_SHIFT_MASK))
+ return TRUE;
+
+ /* compensate the show-help limitation.
+ * It is not called on F1, only on Shift+F1 and Ctrl+F1. */
+ if (code == K_F1)
+ {
+ Icallback cb = IupGetCallback(ih, "HELP_CB");
+ if (cb)
+ {
+ if (cb(ih) == IUP_CLOSE)
+ IupExitLoop();
+ }
+ }
+ }
+
+ (void)widget;
+ return FALSE;
+}
+
+gboolean iupgtkKeyReleaseEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
+{
+ /* this is called only for canvas */
+ int result;
+ int code = gtkKeyDecode(evt);
+ if (code == 0)
+ return FALSE;
+
+ result = iupKeyCallKeyPressCb(ih, code, 0);
+ if (result == IUP_CLOSE)
+ {
+ IupExitLoop();
+ return FALSE;
+ }
+ if (result == IUP_IGNORE)
+ return TRUE;
+
+ (void)widget;
+ return FALSE;
+}
+
+void iupgtkButtonKeySetStatus(guint state, unsigned int but, char* status, int doubleclick)
+{
+ if (state & GDK_SHIFT_MASK)
+ iupKEYSETSHIFT(status);
+
+ if (state & GDK_CONTROL_MASK)
+ iupKEYSETCONTROL(status);
+
+ if ((state & GDK_BUTTON1_MASK) || but==1)
+ iupKEYSETBUTTON1(status);
+
+ if ((state & GDK_BUTTON2_MASK) || but==2)
+ iupKEYSETBUTTON2(status);
+
+ if ((state & GDK_BUTTON3_MASK) || but==3)
+ iupKEYSETBUTTON3(status);
+
+ if ((state & GDK_BUTTON4_MASK) || but==4)
+ iupKEYSETBUTTON4(status);
+
+ if ((state & GDK_BUTTON5_MASK) || but==5)
+ iupKEYSETBUTTON5(status);
+
+ if (state & GDK_MOD1_MASK || state & GDK_MOD5_MASK) /* Alt */
+ iupKEYSETALT(status);
+
+ if (state & GDK_MOD4_MASK) /* Apple/Win */
+ iupKEYSETSYS(status);
+
+ if (doubleclick)
+ iupKEYSETDOUBLE(status);
+}
+
diff --git a/iup/src/gtk/iupgtk_label.c b/iup/src/gtk/iupgtk_label.c
new file mode 100755
index 0000000..49d5c6d
--- /dev/null
+++ b/iup/src/gtk/iupgtk_label.c
@@ -0,0 +1,318 @@
+/** \file
+ * \brief Label Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_image.h"
+#include "iup_label.h"
+#include "iup_drv.h"
+#include "iup_image.h"
+#include "iup_focus.h"
+
+#include "iupgtk_drv.h"
+
+
+static int gtkLabelSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_LABEL_TEXT)
+ {
+ GtkLabel* label = (GtkLabel*)ih->handle;
+ if (iupgtkSetMnemonicTitle(ih, label, value))
+ {
+ Ihandle* next = iupFocusNextInteractive(ih);
+ if (next)
+ {
+ if (next->handle)
+ gtk_label_set_mnemonic_widget(label, next->handle);
+ else
+ iupAttribSetStr(next, "_IUPGTK_LABELMNEMONIC", (char*)label); /* used by iupgtkUpdateMnemonic */
+ }
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+static int gtkLabelSetWordWrapAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_LABEL_TEXT)
+ {
+ GtkLabel* label = (GtkLabel*)ih->handle;
+ if (iupStrBoolean(value))
+ gtk_label_set_line_wrap(label, TRUE);
+ else
+ gtk_label_set_line_wrap(label, FALSE);
+ return 1;
+ }
+ return 0;
+}
+
+static int gtkLabelSetEllipsisAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_LABEL_TEXT)
+ {
+#if GTK_CHECK_VERSION(2, 6, 0)
+ GtkLabel* label = (GtkLabel*)ih->handle;
+ if (iupStrBoolean(value))
+ gtk_label_set_ellipsize(label, PANGO_ELLIPSIZE_END);
+ else
+ gtk_label_set_ellipsize(label, PANGO_ELLIPSIZE_NONE);
+#endif
+ return 1;
+ }
+ return 0;
+}
+
+static int gtkLabelSetAlignmentAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT)
+ {
+ GtkMisc* misc = (GtkMisc*)ih->handle;
+ PangoAlignment alignment;
+ float xalign, yalign;
+ char value1[30]="", value2[30]="";
+
+ iupStrToStrStr(value, value1, value2, ':');
+
+ if (iupStrEqualNoCase(value1, "ARIGHT"))
+ {
+ xalign = 1.0f;
+ alignment = PANGO_ALIGN_RIGHT;
+ }
+ else if (iupStrEqualNoCase(value1, "ACENTER"))
+ {
+ xalign = 0.5f;
+ alignment = PANGO_ALIGN_CENTER;
+ }
+ else /* "ALEFT" */
+ {
+ xalign = 0;
+ alignment = PANGO_ALIGN_LEFT;
+ }
+
+ if (iupStrEqualNoCase(value2, "ABOTTOM"))
+ yalign = 1.0f;
+ else if (iupStrEqualNoCase(value2, "ATOP"))
+ yalign = 0;
+ else /* ACENTER (default) */
+ yalign = 0.5f;
+
+ gtk_misc_set_alignment(misc, xalign, yalign);
+
+ if (ih->data->type == IUP_LABEL_TEXT)
+ pango_layout_set_alignment(gtk_label_get_layout((GtkLabel*)ih->handle), alignment);
+
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkLabelSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x');
+
+ if (ih->handle && ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT)
+ {
+ GtkMisc* misc = (GtkMisc*)ih->handle;
+ gtk_misc_set_padding(misc, ih->data->horiz_padding, ih->data->vert_padding);
+ }
+ return 0;
+}
+
+static char* gtkLabelGetPangoLayoutAttrib(Ihandle* ih)
+{
+ if (ih->data->type == IUP_LABEL_TEXT)
+ return (char*)gtk_label_get_layout((GtkLabel*)ih->handle);
+ else
+ return NULL;
+}
+
+static void gtkLabelSetPixbuf(Ihandle* ih, const char* name, int make_inactive)
+{
+ GtkImage* image_label = (GtkImage*)ih->handle;
+
+ if (name)
+ {
+ GdkPixbuf* pixbuf = iupImageGetImage(name, ih, make_inactive);
+ GdkPixbuf* old_pixbuf = gtk_image_get_pixbuf(image_label);
+ if (pixbuf != old_pixbuf)
+ gtk_image_set_from_pixbuf(image_label, pixbuf);
+ return;
+ }
+
+ /* if not defined */
+#if GTK_CHECK_VERSION(2, 8, 0)
+ gtk_image_clear(image_label);
+#endif
+}
+
+static int gtkLabelSetImageAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_LABEL_IMAGE)
+ {
+ if (iupdrvIsActive(ih))
+ gtkLabelSetPixbuf(ih, value, 0);
+ else
+ {
+ if (!iupAttribGet(ih, "IMINACTIVE"))
+ {
+ /* if not active and IMINACTIVE is not defined
+ then automaticaly create one based on IMAGE */
+ gtkLabelSetPixbuf(ih, value, 1); /* make_inactive */
+ }
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkLabelSetImInactiveAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_LABEL_IMAGE)
+ {
+ if (!iupdrvIsActive(ih))
+ {
+ if (value)
+ gtkLabelSetPixbuf(ih, value, 0);
+ else
+ {
+ /* if not defined then automaticaly create one based on IMAGE */
+ char* name = iupAttribGet(ih, "IMAGE");
+ gtkLabelSetPixbuf(ih, name, 1); /* make_inactive */
+ }
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkLabelSetActiveAttrib(Ihandle* ih, const char* value)
+{
+ /* update the inactive image if necessary */
+ if (ih->data->type == IUP_LABEL_IMAGE)
+ {
+ if (!iupStrBoolean(value))
+ {
+ char* name = iupAttribGet(ih, "IMINACTIVE");
+ if (name)
+ gtkLabelSetPixbuf(ih, name, 0);
+ else
+ {
+ /* if not defined then automaticaly create one based on IMAGE */
+ name = iupAttribGet(ih, "IMAGE");
+ gtkLabelSetPixbuf(ih, name, 1); /* make_inactive */
+ }
+ }
+ else
+ {
+ /* must restore the normal image */
+ char* name = iupAttribGet(ih, "IMAGE");
+ gtkLabelSetPixbuf(ih, name, 0);
+ }
+ }
+
+ return iupBaseSetActiveAttrib(ih, value);
+}
+
+static int gtkLabelMapMethod(Ihandle* ih)
+{
+ char* value;
+ GtkWidget *label;
+
+ value = iupAttribGet(ih, "SEPARATOR");
+ if (value)
+ {
+ if (iupStrEqualNoCase(value, "HORIZONTAL"))
+ {
+ ih->data->type = IUP_LABEL_SEP_HORIZ;
+ label = gtk_hseparator_new();
+ }
+ else /* "VERTICAL" */
+ {
+ ih->data->type = IUP_LABEL_SEP_VERT;
+ label = gtk_vseparator_new();
+ }
+ }
+ else
+ {
+ value = iupAttribGet(ih, "IMAGE");
+ if (value)
+ {
+ ih->data->type = IUP_LABEL_IMAGE;
+ label = gtk_image_new();
+ }
+ else
+ {
+ ih->data->type = IUP_LABEL_TEXT;
+ label = gtk_label_new(NULL);
+ }
+ }
+
+ if (!label)
+ return IUP_ERROR;
+
+ ih->handle = label;
+
+ /* add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ gtk_widget_realize(label);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvLabelInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkLabelMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Common GTK only (when text is in a secondary element) */
+ iupClassRegisterAttribute(ic, "PANGOLAYOUT", gtkLabelGetPangoLayoutAttrib, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+
+ /* Overwrite Visual */
+ iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, gtkLabelSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iupdrvBaseSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "TITLE", NULL, gtkLabelSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupLabel only */
+ iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, gtkLabelSetAlignmentAttrib, "ALEFT:ACENTER", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, gtkLabelSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "PADDING", iupLabelGetPaddingAttrib, gtkLabelSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+
+ /* IupLabel GTK and Motif only */
+ iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, gtkLabelSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupLabel Windows and GTK only */
+ iupClassRegisterAttribute(ic, "WORDWRAP", NULL, gtkLabelSetWordWrapAttrib, NULL, NULL, IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "ELLIPSIS", NULL, gtkLabelSetEllipsisAttrib, NULL, NULL, IUPAF_DEFAULT);
+
+ /* IupLabel GTK only */
+ iupClassRegisterAttribute(ic, "MARKUP", NULL, NULL, NULL, NULL, IUPAF_DEFAULT);
+}
diff --git a/iup/src/gtk/iupgtk_list.c b/iup/src/gtk/iupgtk_list.c
new file mode 100755
index 0000000..80f6cce
--- /dev/null
+++ b/iup/src/gtk/iupgtk_list.c
@@ -0,0 +1,1439 @@
+/** \file
+ * \brief List Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_mask.h"
+#include "iup_key.h"
+#include "iup_list.h"
+
+#include "iupgtk_drv.h"
+
+
+static void gtkListSelectionChanged(GtkTreeSelection* selection, Ihandle* ih);
+static void gtkListComboBoxChanged(GtkComboBox* widget, Ihandle* ih);
+
+
+void iupdrvListAddItemSpace(Ihandle* ih, int *h)
+{
+ (void)ih;
+ *h += 3;
+}
+
+void iupdrvListAddBorders(Ihandle* ih, int *x, int *y)
+{
+ int border_size = 2*5;
+ (*x) += border_size;
+ (*y) += border_size;
+
+ if (ih->data->is_dropdown)
+ {
+#ifdef HILDON
+ (*x) += 9; /* extra space for the dropdown button */
+#else
+ (*x) += 5; /* extra space for the dropdown button */
+#endif
+
+ if (ih->data->has_editbox)
+ (*x) += 5; /* another extra space for the dropdown button */
+ else
+ {
+ (*y) += 4; /* extra padding space */
+ (*x) += 4; /* extra padding space */
+ }
+ }
+ else
+ {
+ if (ih->data->has_editbox)
+ (*y) += 2*3; /* internal border between editbox and list */
+ }
+}
+
+static int gtkListConvertXYToPos(Ihandle* ih, int x, int y)
+{
+ if (!ih->data->is_dropdown)
+ {
+ GtkTreePath* path;
+ if (gtk_tree_view_get_dest_row_at_pos((GtkTreeView*)ih->handle, x, y, &path, NULL))
+ {
+ int* indices = gtk_tree_path_get_indices(path);
+ int pos = indices[0]+1; /* IUP starts at 1 */
+ gtk_tree_path_free (path);
+ return pos;
+ }
+ }
+
+ return -1;
+}
+
+static GtkTreeModel* gtkListGetModel(Ihandle* ih)
+{
+ if (ih->data->is_dropdown)
+ return gtk_combo_box_get_model((GtkComboBox*)ih->handle);
+ else
+ return gtk_tree_view_get_model((GtkTreeView*)ih->handle);
+}
+
+int iupdrvListGetCount(Ihandle* ih)
+{
+ GtkTreeModel *model = gtkListGetModel(ih);
+ return gtk_tree_model_iter_n_children(model, NULL);
+}
+
+void iupdrvListAppendItem(Ihandle* ih, const char* value)
+{
+ GtkTreeModel *model = gtkListGetModel(ih);
+ GtkTreeIter iter;
+ gtk_list_store_append(GTK_LIST_STORE(model), &iter);
+ gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, iupgtkStrConvertToUTF8(value), -1);
+}
+
+void iupdrvListInsertItem(Ihandle* ih, int pos, const char* value)
+{
+ GtkTreeModel *model = gtkListGetModel(ih);
+ GtkTreeIter iter;
+ gtk_list_store_insert(GTK_LIST_STORE(model), &iter, pos);
+ gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, iupgtkStrConvertToUTF8(value), -1);
+}
+
+void iupdrvListRemoveItem(Ihandle* ih, int pos)
+{
+ GtkTreeModel *model = gtkListGetModel(ih);
+ GtkTreeIter iter;
+ if (gtk_tree_model_iter_nth_child(model, &iter, NULL, pos))
+ {
+ if (ih->data->is_dropdown && !ih->data->has_editbox)
+ {
+ /* must check if removing the current item */
+ int curpos = gtk_combo_box_get_active((GtkComboBox*)ih->handle);
+ if (pos == curpos)
+ {
+ if (curpos > 0) curpos--;
+ else curpos++;
+
+ gtk_combo_box_set_active((GtkComboBox*)ih->handle, curpos);
+ }
+ }
+
+ gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
+ }
+}
+
+void iupdrvListRemoveAllItems(Ihandle* ih)
+{
+ GtkTreeModel *model = gtkListGetModel(ih);
+ gtk_list_store_clear(GTK_LIST_STORE(model));
+}
+
+
+/*********************************************************************************/
+
+
+static int gtkListSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ iupdrvSetStandardFontAttrib(ih, value);
+
+ if (ih->handle)
+ {
+ if (ih->data->is_dropdown)
+ {
+ GtkCellRenderer* renderer = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER");
+ if (renderer)
+ {
+ g_object_set(G_OBJECT(renderer), "font-desc", (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih), NULL);
+ iupgtkFontUpdateObjectPangoLayout(ih, G_OBJECT(renderer));
+ }
+ }
+
+ if (ih->data->has_editbox)
+ {
+ GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ gtk_widget_modify_font((GtkWidget*)entry, (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih));
+ iupgtkFontUpdatePangoLayout(ih, gtk_entry_get_layout(entry));
+ }
+ }
+ return 1;
+}
+
+static char* gtkListGetIdValueAttrib(Ihandle* ih, const char* name_id)
+{
+ int pos = iupListGetPos(ih, name_id);
+ if (pos != -1)
+ {
+ GtkTreeIter iter;
+ GtkTreeModel* model = gtkListGetModel(ih);
+ if (gtk_tree_model_iter_nth_child(model, &iter, NULL, pos))
+ {
+ gchar *text = NULL;
+ gtk_tree_model_get(model, &iter, 0, &text, -1);
+ if (text)
+ {
+ char* ret_str = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(text));
+ g_free(text);
+ return ret_str;
+ }
+ }
+ }
+ return NULL;
+}
+
+static int gtkListSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+
+ GtkScrolledWindow* scrolled_window = (GtkScrolledWindow*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (scrolled_window && !ih->data->is_dropdown)
+ {
+ /* ignore given value, must use only from parent for the scrollbars */
+ char* parent_value = iupBaseNativeParentGetBgColor(ih);
+
+ if (iupStrToRGB(parent_value, &r, &g, &b))
+ {
+ GtkWidget* sb;
+
+ if (!GTK_IS_SCROLLED_WINDOW(scrolled_window))
+ scrolled_window = (GtkScrolledWindow*)iupAttribGet(ih, "_IUPGTK_SCROLLED_WINDOW");
+
+ iupgtkBaseSetBgColor((GtkWidget*)scrolled_window, r, g, b);
+
+#if GTK_CHECK_VERSION(2, 8, 0)
+ sb = gtk_scrolled_window_get_hscrollbar(scrolled_window);
+ if (sb) iupgtkBaseSetBgColor(sb, r, g, b);
+
+ sb = gtk_scrolled_window_get_vscrollbar(scrolled_window);
+ if (sb) iupgtkBaseSetBgColor(sb, r, g, b);
+#endif
+ }
+ }
+
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ if (ih->data->has_editbox)
+ {
+ GtkWidget* entry = (GtkWidget*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ iupgtkBaseSetBgColor(entry, r, g, b);
+ }
+
+ {
+ GtkCellRenderer* renderer = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER");
+ if (renderer)
+ {
+ GdkColor color;
+ iupgdkColorSet(&color, r, g, b);
+ g_object_set(G_OBJECT(renderer), "cell-background-gdk", &color, NULL);
+ }
+ }
+
+ return iupdrvBaseSetBgColorAttrib(ih, value);
+}
+
+static int gtkListSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgtkBaseSetFgColor(ih->handle, r, g, b);
+
+ if (ih->data->has_editbox)
+ {
+ GtkWidget* entry = (GtkWidget*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ iupgtkBaseSetFgColor(entry, r, g, b);
+ }
+
+ {
+ GtkCellRenderer* renderer = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER");
+ if (renderer)
+ {
+ GdkColor color;
+ iupgdkColorSet(&color, r, g, b);
+ g_object_set(G_OBJECT(renderer), "foreground-gdk", &color, NULL);
+ }
+ }
+
+ return 1;
+}
+
+static char* gtkListGetValueAttrib(Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ return iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_entry_get_text(entry)));
+ }
+ else
+ {
+ if (ih->data->is_dropdown)
+ {
+ int pos = gtk_combo_box_get_active((GtkComboBox*)ih->handle);
+ char* str = iupStrGetMemory(50);
+ sprintf(str, "%d", pos+1); /* IUP starts at 1 */
+ return str;
+ }
+ else
+ {
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+ if (!ih->data->is_multiple)
+ {
+ GtkTreeIter iter;
+ GtkTreeModel* tree_model;
+ if (gtk_tree_selection_get_selected(selection, &tree_model, &iter))
+ {
+ char* str;
+ GtkTreePath *path = gtk_tree_model_get_path(tree_model, &iter);
+ int* indices = gtk_tree_path_get_indices(path);
+ str = iupStrGetMemory(50);
+ sprintf(str, "%d", indices[0]+1); /* IUP starts at 1 */
+ gtk_tree_path_free (path);
+ return str;
+ }
+ }
+ else
+ {
+ GList *il, *list = gtk_tree_selection_get_selected_rows(selection, NULL);
+ int count = iupdrvListGetCount(ih);
+ char* str = iupStrGetMemory(count+1);
+ memset(str, '-', count);
+ str[count]=0;
+ for (il=list; il; il=il->next)
+ {
+ GtkTreePath* path = (GtkTreePath*)il->data;
+ int* indices = gtk_tree_path_get_indices(path);
+ str[indices[0]] = '+';
+ gtk_tree_path_free(path);
+ }
+ g_list_free(list);
+ return str;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static int gtkListSetValueAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->has_editbox)
+ {
+ GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ if (!value) value = "";
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ gtk_entry_set_text(entry, iupgtkStrConvertToUTF8(value));
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ }
+ else
+ {
+ if (ih->data->is_dropdown)
+ {
+ int pos;
+ GtkTreeModel *model = gtkListGetModel(ih);
+ g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkListComboBoxChanged), ih);
+ if (iupStrToInt(value, &pos)==1 &&
+ (pos>0 && pos<gtk_tree_model_iter_n_children(model, NULL)))
+ {
+ gtk_combo_box_set_active((GtkComboBox*)ih->handle, pos-1); /* IUP starts at 1 */
+ iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos);
+ }
+ else
+ {
+ gtk_combo_box_set_active((GtkComboBox*)ih->handle, -1); /* none */
+ iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL);
+ }
+ g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkListComboBoxChanged), ih);
+ }
+ else
+ {
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+ if (!ih->data->is_multiple)
+ {
+ int pos;
+ g_signal_handlers_block_by_func(G_OBJECT(selection), G_CALLBACK(gtkListSelectionChanged), ih);
+ if (iupStrToInt(value, &pos)==1)
+ {
+ GtkTreePath* path = gtk_tree_path_new_from_indices(pos-1, -1); /* IUP starts at 1 */
+ gtk_tree_selection_select_path(selection, path);
+ gtk_tree_path_free(path);
+ iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos);
+ }
+ else
+ {
+ gtk_tree_selection_unselect_all(selection);
+ iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL);
+ }
+ g_signal_handlers_unblock_by_func(G_OBJECT(selection), G_CALLBACK(gtkListSelectionChanged), ih);
+ }
+ else
+ {
+ /* User has changed a multiple selection on a simple list. */
+ int i, len, count;
+
+ g_signal_handlers_block_by_func(G_OBJECT(selection), G_CALLBACK(gtkListSelectionChanged), ih);
+
+ /* Clear all selections */
+ gtk_tree_selection_unselect_all(selection);
+
+ if (!value)
+ {
+ iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL);
+ return 0;
+ }
+
+ len = strlen(value);
+ count = iupdrvListGetCount(ih);
+ if (len < count)
+ count = len;
+
+ /* update selection list */
+ for (i = 0; i<count; i++)
+ {
+ if (value[i]=='+')
+ {
+ GtkTreePath* path = gtk_tree_path_new_from_indices(i, -1);
+ gtk_tree_selection_select_path(selection, path);
+ gtk_tree_path_free(path);
+ }
+ }
+ iupAttribStoreStr(ih, "_IUPLIST_OLDVALUE", value);
+ g_signal_handlers_unblock_by_func(G_OBJECT(selection), G_CALLBACK(gtkListSelectionChanged), ih);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int gtkListSetShowDropdownAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->is_dropdown)
+ {
+ if (iupStrBoolean(value))
+ gtk_combo_box_popup((GtkComboBox*)ih->handle);
+ else
+ gtk_combo_box_popdown((GtkComboBox*)ih->handle);
+ }
+ return 0;
+}
+
+static int gtkListSetTopItemAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->is_dropdown)
+ {
+ int pos = 1;
+ if (iupStrToInt(value, &pos))
+ {
+ GtkTreePath* path = gtk_tree_path_new_from_indices(pos-1, -1); /* IUP starts at 1 */
+ gtk_tree_view_scroll_to_cell((GtkTreeView*)ih->handle, path, NULL, FALSE, 0, 0);
+ gtk_tree_path_free(path);
+ }
+ }
+ return 0;
+}
+
+static int gtkListSetSpacingAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->is_dropdown)
+ return 0;
+
+ if (!iupStrToInt(value, &ih->data->spacing))
+ ih->data->spacing = 0;
+
+ if (ih->handle)
+ {
+ GtkCellRenderer* renderer = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER");
+ if (renderer)
+ g_object_set(G_OBJECT(renderer), "xpad", ih->data->spacing,
+ "ypad", ih->data->spacing,
+ NULL);
+ return 0;
+ }
+ else
+ return 1; /* store until not mapped, when mapped will be set again */
+}
+
+static int gtkListSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->has_editbox)
+ return 0;
+
+ iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x');
+ if (ih->handle)
+ {
+#if GTK_CHECK_VERSION(2, 10, 0)
+ GtkEntry* entry;
+ GtkBorder border;
+ border.bottom = border.top = ih->data->vert_padding;
+ border.left = border.right = ih->data->horiz_padding;
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ gtk_entry_set_inner_border(entry, &border);
+#endif
+ return 0;
+ }
+ else
+ return 1; /* store until not mapped, when mapped will be set again */
+}
+
+static int gtkListSetSelectionAttrib(Ihandle* ih, const char* value)
+{
+ int start=1, end=1;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return 0;
+ if (!value)
+ return 0;
+
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ if (!value || iupStrEqualNoCase(value, "NONE"))
+ {
+ gtk_editable_select_region(GTK_EDITABLE(entry), 0, 0);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(value, "ALL"))
+ {
+ gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
+ return 0;
+ }
+
+ if (iupStrToIntInt(value, &start, &end, ':')!=2)
+ return 0;
+
+ if(start<1 || end<1)
+ return 0;
+
+ start--; /* IUP starts at 1 */
+ end--;
+
+ gtk_editable_select_region(GTK_EDITABLE(entry), start, end);
+
+ return 0;
+}
+
+static char* gtkListGetSelectionAttrib(Ihandle* ih)
+{
+ char *str;
+ int start, end;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return NULL;
+
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ if (gtk_editable_get_selection_bounds(GTK_EDITABLE(entry), &start, &end))
+ {
+ start++; /* IUP starts at 1 */
+ end++;
+ str = iupStrGetMemory(100);
+ sprintf(str, "%d:%d", (int)start, (int)end);
+ return str;
+ }
+
+ return NULL;
+}
+
+static int gtkListSetSelectionPosAttrib(Ihandle* ih, const char* value)
+{
+ int start=0, end=0;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return 0;
+ if (!value)
+ return 0;
+
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ if (!value || iupStrEqualNoCase(value, "NONE"))
+ {
+ gtk_editable_select_region(GTK_EDITABLE(entry), 0, 0);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(value, "ALL"))
+ {
+ gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
+ return 0;
+ }
+
+ if (iupStrToIntInt(value, &start, &end, ':')!=2)
+ return 0;
+
+ if(start<0 || end<0)
+ return 0;
+
+ gtk_editable_select_region(GTK_EDITABLE(entry), start, end);
+
+ return 0;
+}
+
+static char* gtkListGetSelectionPosAttrib(Ihandle* ih)
+{
+ int start, end;
+ char *str;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return NULL;
+
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ if (gtk_editable_get_selection_bounds(GTK_EDITABLE(entry), &start, &end))
+ {
+ str = iupStrGetMemory(100);
+ sprintf(str, "%d:%d", (int)start, (int)end);
+ return str;
+ }
+
+ return NULL;
+}
+
+static int gtkListSetSelectedTextAttrib(Ihandle* ih, const char* value)
+{
+ int start, end;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return 0;
+ if (!value)
+ return 0;
+
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ if (gtk_editable_get_selection_bounds(GTK_EDITABLE(entry), &start, &end))
+ {
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ gtk_editable_delete_selection(GTK_EDITABLE(entry));
+ gtk_editable_insert_text(GTK_EDITABLE(entry), iupgtkStrConvertToUTF8(value), -1, &start);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ }
+
+ return 0;
+}
+
+static char* gtkListGetSelectedTextAttrib(Ihandle* ih)
+{
+ int start, end;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return NULL;
+
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ if (gtk_editable_get_selection_bounds(GTK_EDITABLE(entry), &start, &end))
+ {
+ char* selectedtext = gtk_editable_get_chars(GTK_EDITABLE(entry), start, end);
+ char* str = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(selectedtext));
+ g_free(selectedtext);
+ return str;
+ }
+
+ return NULL;
+}
+
+static int gtkListSetCaretAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 1;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return 0;
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ pos--; /* IUP starts at 1 */
+ if (pos < 0) pos = 0;
+
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ gtk_editable_set_position(GTK_EDITABLE(entry), pos);
+
+ return 0;
+}
+
+static char* gtkListGetCaretAttrib(Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ char* str = iupStrGetMemory(50);
+ GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ int pos = gtk_editable_get_position(GTK_EDITABLE(entry));
+ pos++; /* IUP starts at 1 */
+ sprintf(str, "%d", (int)pos);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+static int gtkListSetCaretPosAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 0;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return 0;
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 0) pos = 0;
+
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ gtk_editable_set_position(GTK_EDITABLE(entry), pos);
+
+ return 0;
+}
+
+static char* gtkListGetCaretPosAttrib(Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ char* str = iupStrGetMemory(50);
+ GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ int pos = gtk_editable_get_position(GTK_EDITABLE(entry));
+ sprintf(str, "%d", (int)pos);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+static int gtkListSetScrollToAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 1;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return 0;
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 1) pos = 1;
+ pos--; /* return to GTK referece */
+
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ gtk_editable_set_position(GTK_EDITABLE(entry), pos);
+
+ return 0;
+}
+
+static int gtkListSetScrollToPosAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 0;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return 0;
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 0) pos = 0;
+
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ gtk_editable_set_position(GTK_EDITABLE(entry), pos);
+
+ return 0;
+}
+
+static int gtkListSetInsertAttrib(Ihandle* ih, const char* value)
+{
+ gint pos;
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return 0;
+ if (!value)
+ return 0;
+
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); /* disable callbacks */
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ pos = gtk_editable_get_position(GTK_EDITABLE(entry));
+ gtk_editable_insert_text(GTK_EDITABLE(entry), iupgtkStrConvertToUTF8(value), -1, &pos);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+
+ return 0;
+}
+
+static int gtkListSetAppendAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->has_editbox)
+ {
+ GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ gint pos = strlen(gtk_entry_get_text(entry))+1;
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); /* disable callbacks */
+ gtk_editable_insert_text(GTK_EDITABLE(entry), iupgtkStrConvertToUTF8(value), -1, &pos);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ }
+ return 0;
+}
+
+static int gtkListSetNCAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!iupStrToInt(value, &ih->data->nc))
+ ih->data->nc = INT_MAX;
+
+ if (ih->handle)
+ {
+ GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ gtk_entry_set_max_length(entry, ih->data->nc);
+ }
+
+ return 0;
+}
+
+static int gtkListSetClipboardAttrib(Ihandle *ih, const char *value)
+{
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ if (iupStrEqualNoCase(value, "COPY"))
+ gtk_editable_copy_clipboard(GTK_EDITABLE(entry));
+ else if (iupStrEqualNoCase(value, "CUT"))
+ gtk_editable_cut_clipboard(GTK_EDITABLE(entry));
+ else if (iupStrEqualNoCase(value, "PASTE"))
+ gtk_editable_paste_clipboard(GTK_EDITABLE(entry));
+ else if (iupStrEqualNoCase(value, "CLEAR"))
+ gtk_editable_delete_selection(GTK_EDITABLE(entry));
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ return 0;
+}
+
+static int gtkListSetReadOnlyAttrib(Ihandle* ih, const char* value)
+{
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return 0;
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ gtk_editable_set_editable(GTK_EDITABLE(entry), !iupStrBoolean(value));
+ return 0;
+}
+
+static char* gtkListGetReadOnlyAttrib(Ihandle* ih)
+{
+ GtkEntry* entry;
+ if (!ih->data->has_editbox)
+ return NULL;
+ entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ if (!gtk_editable_get_editable(GTK_EDITABLE(entry)))
+ return "YES";
+ else
+ return "NO";
+}
+
+
+/*********************************************************************************/
+
+
+static void gtkListEditMoveCursor(GtkWidget* entry, GtkMovementStep step, gint count, gboolean extend_selection, Ihandle* ih)
+{
+ int pos;
+
+ IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB");
+ if (!cb) return;
+
+ pos = gtk_editable_get_position(GTK_EDITABLE(entry));
+
+ if (pos != ih->data->last_caret_pos)
+ {
+ ih->data->last_caret_pos = pos;
+
+ cb(ih, 1, pos+1, pos);
+ }
+
+ (void)step;
+ (void)count;
+ (void)extend_selection;
+}
+
+static gboolean gtkListEditKeyPressEvent(GtkWidget* entry, GdkEventKey *evt, Ihandle *ih)
+{
+ if (iupgtkKeyPressEvent(entry, evt, ih) == TRUE)
+ return TRUE;
+
+ if ((evt->keyval == GDK_Up || evt->keyval == GDK_KP_Up) ||
+ (evt->keyval == GDK_Prior || evt->keyval == GDK_KP_Page_Up) ||
+ (evt->keyval == GDK_Down || evt->keyval == GDK_KP_Down) ||
+ (evt->keyval == GDK_Next || evt->keyval == GDK_KP_Page_Down))
+ {
+ int pos = -1;
+ GtkTreeIter iter;
+ GtkTreeModel* model = NULL;
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+ if (gtk_tree_selection_get_selected(selection, &model, &iter))
+ {
+ GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
+ int* indices = gtk_tree_path_get_indices(path);
+ pos = indices[0];
+ gtk_tree_path_free(path);
+ }
+
+ if (pos == -1)
+ pos = 0;
+ else if (evt->keyval == GDK_Up || evt->keyval == GDK_KP_Up)
+ {
+ pos--;
+ if (pos < 0) pos = 0;
+ }
+ else if (evt->keyval == GDK_Prior || evt->keyval == GDK_KP_Page_Up)
+ {
+ pos -= 5;
+ if (pos < 0) pos = 0;
+ }
+ else if (evt->keyval == GDK_Down || evt->keyval == GDK_KP_Down)
+ {
+ int count = gtk_tree_model_iter_n_children(model, NULL);
+ pos++;
+ if (pos > count-1) pos = count-1;
+ }
+ else if (evt->keyval == GDK_Next || evt->keyval == GDK_KP_Page_Down)
+ {
+ int count = gtk_tree_model_iter_n_children(model, NULL);
+ pos += 5;
+ if (pos > count-1) pos = count-1;
+ }
+
+ if (pos != -1)
+ {
+ GtkTreePath* path = gtk_tree_path_new_from_indices(pos, -1);
+ g_signal_handlers_block_by_func(G_OBJECT(selection), G_CALLBACK(gtkListSelectionChanged), ih);
+ gtk_tree_selection_select_path(selection, path);
+ g_signal_handlers_unblock_by_func(G_OBJECT(selection), G_CALLBACK(gtkListSelectionChanged), ih);
+ gtk_tree_path_free(path);
+ iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos);
+
+ if (!model) model = gtkListGetModel(ih);
+
+ if (gtk_tree_model_iter_nth_child(model, &iter, NULL, pos))
+ {
+ gchar *text = NULL;
+ gtk_tree_model_get(model, &iter, 0, &text, -1);
+ if (text)
+ {
+ gtk_entry_set_text((GtkEntry*)entry, text);
+ g_free(text);
+ }
+ }
+
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean gtkListEditKeyReleaseEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
+{
+ gtkListEditMoveCursor(widget, 0, 0, 0, ih);
+ (void)evt;
+ return FALSE;
+}
+
+static gboolean gtkListEditButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih)
+{
+ gtkListEditMoveCursor(widget, 0, 0, 0, ih);
+ (void)evt;
+ return FALSE;
+}
+
+static int gtkListCallEditCb(Ihandle* ih, GtkEditable *editable, const char* insert_value, int len, int start, int end)
+{
+ char *new_value, *value;
+ int ret = -1, key = 0;
+
+ IFnis cb = (IFnis)IupGetCallback(ih, "EDIT_CB");
+ if (!cb && !ih->data->mask)
+ return -1; /* continue */
+
+ value = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_entry_get_text(GTK_ENTRY(editable))));
+
+ if (!insert_value)
+ {
+ new_value = iupStrDup(value);
+ if (end<0) end = strlen(value)+1;
+ iupStrRemove(new_value, start, end, 1);
+ }
+ else
+ {
+ if (!value)
+ new_value = iupStrDup(insert_value);
+ else
+ {
+ if (len < end-start)
+ {
+ new_value = iupStrDup(value);
+ new_value = iupStrInsert(new_value, insert_value, start, end);
+ }
+ else
+ new_value = iupStrInsert(value, insert_value, start, end);
+ }
+ }
+
+ if (insert_value && insert_value[0]!=0 && insert_value[1]==0)
+ key = insert_value[0];
+
+ if (!new_value)
+ return -1; /* continue */
+
+ if (ih->data->nc && (int)strlen(new_value) > ih->data->nc)
+ {
+ if (new_value != value) free(new_value);
+ return 0; /* abort */
+ }
+
+ if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0)
+ {
+ if (new_value != value) free(new_value);
+ return 0; /* abort */
+ }
+
+ if (cb)
+ {
+ int cb_ret = cb(ih, key, (char*)new_value);
+ if (cb_ret==IUP_IGNORE)
+ ret = 0; /* abort */
+ else if (cb_ret==IUP_CLOSE)
+ {
+ IupExitLoop();
+ ret = 0; /* abort */
+ }
+ else if (cb_ret!=0 && key!=0 &&
+ cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE)
+ ret = cb_ret; /* abort and replace */
+ }
+
+ if (new_value != value) free(new_value);
+ return ret; /* continue */
+}
+
+static void gtkListEditDeleteText(GtkEditable *editable, int start, int end, Ihandle* ih)
+{
+ if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB"))
+ return;
+
+ if (gtkListCallEditCb(ih, editable, NULL, 0, start, end)==0)
+ g_signal_stop_emission_by_name(editable, "delete_text");
+}
+
+static void gtkListEditInsertText(GtkEditable *editable, char *insert_value, int len, int *pos, Ihandle* ih)
+{
+ int ret;
+
+ if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB"))
+ return;
+
+ ret = gtkListCallEditCb(ih, editable, iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(insert_value)), len, *pos, *pos);
+ if (ret == 0)
+ g_signal_stop_emission_by_name(editable, "insert_text");
+ else if (ret != -1)
+ {
+ insert_value[0] = (char)ret; /* replace key */
+
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ gtk_editable_insert_text(editable, insert_value, 1, pos);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+
+ g_signal_stop_emission_by_name(editable, "insert_text");
+ }
+}
+
+static void gtkListEditChanged(void* dummy, Ihandle* ih)
+{
+ if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB"))
+ return;
+
+ iupBaseCallValueChangedCb(ih);
+ (void)dummy;
+}
+
+static void gtkListComboBoxPopupShownChanged(GtkComboBox* widget, GParamSpec *pspec, Ihandle* ih)
+{
+ IFni cb = (IFni)IupGetCallback(ih, "DROPDOWN_CB");
+ if (cb)
+ {
+ gboolean popup_shown;
+ g_object_get(widget, "popup-shown", &popup_shown, NULL);
+ cb(ih, popup_shown);
+ }
+ (void)pspec;
+}
+
+static void gtkListComboBoxChanged(GtkComboBox* widget, Ihandle* ih)
+{
+ IFnsii cb = (IFnsii)IupGetCallback(ih, "ACTION");
+ if (cb)
+ {
+ int pos = gtk_combo_box_get_active((GtkComboBox*)ih->handle);
+ pos++; /* IUP starts at 1 */
+ iupListSingleCallActionCallback(ih, cb, pos);
+ }
+
+ if (!ih->data->has_editbox)
+ iupBaseCallValueChangedCb(ih);
+
+ (void)widget;
+}
+
+static gboolean gtkListSimpleKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
+{
+ if (iupgtkKeyPressEvent(widget, evt, ih) == TRUE)
+ return TRUE;
+
+ if (evt->keyval == GDK_Return || evt->keyval == GDK_KP_Enter)
+ return TRUE; /* used to avoid the call to DBLCLICK_CB in the default processing */
+ return FALSE;
+}
+
+static void gtkListRowActivated(GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, Ihandle* ih)
+{
+ IFnis cb = (IFnis) IupGetCallback(ih, "DBLCLICK_CB");
+ if (cb)
+ {
+ int* indices = gtk_tree_path_get_indices(path);
+ iupListSingleCallDblClickCallback(ih, cb, indices[0]+1); /* IUP starts at 1 */
+ }
+ (void)column;
+ (void)tree_view;
+}
+
+static void gtkListSelectionChanged(GtkTreeSelection* selection, Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ /* must manually update its contents */
+ GtkTreeIter iter;
+ GtkTreeModel* tree_model;
+ if (gtk_tree_selection_get_selected(selection, &tree_model, &iter))
+ {
+ GtkTreePath *path = gtk_tree_model_get_path(tree_model, &iter);
+ char* value = NULL;
+ gtk_tree_model_get(tree_model, &iter, 0, &value, -1);
+ if (value)
+ {
+ GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY");
+ gtk_entry_set_text(entry, value);
+ g_free(value);
+ }
+ gtk_tree_path_free(path);
+ }
+ }
+
+ if (!ih->data->is_multiple)
+ {
+ IFnsii cb = (IFnsii)IupGetCallback(ih, "ACTION");
+ if (cb)
+ {
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iter;
+ GtkTreeModel* tree_model;
+ if (gtk_tree_selection_get_selected(selection, &tree_model, &iter))
+ {
+ GtkTreePath *path = gtk_tree_model_get_path(tree_model, &iter);
+ int* indices = gtk_tree_path_get_indices(path);
+ iupListSingleCallActionCallback(ih, cb, indices[0]+1); /* IUP starts at 1 */
+ gtk_tree_path_free (path);
+ }
+ }
+ }
+ else
+ {
+ IFns multi_cb = (IFns)IupGetCallback(ih, "MULTISELECT_CB");
+ IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION");
+ if (multi_cb || cb)
+ {
+ GList *il, *list = gtk_tree_selection_get_selected_rows(selection, NULL);
+ int i, sel_count = g_list_length(list);
+ int* pos = malloc(sizeof(int)*sel_count);
+ for (il=list, i=0; il; il=il->next, i++)
+ {
+ GtkTreePath* path = (GtkTreePath*)il->data;
+ int* indices = gtk_tree_path_get_indices(path);
+ pos[i] = indices[0];
+ gtk_tree_path_free(path);
+ }
+ g_list_free(list);
+
+ iupListMultipleCallActionCallback(ih, cb, multi_cb, pos, sel_count);
+ free(pos);
+ }
+ }
+
+ if (!ih->data->has_editbox)
+ iupBaseCallValueChangedCb(ih);
+}
+
+
+/*********************************************************************************/
+
+
+static int gtkListMapMethod(Ihandle* ih)
+{
+ GtkScrolledWindow* scrolled_window = NULL;
+ GtkListStore *store;
+
+ store = gtk_list_store_new(1, G_TYPE_STRING);
+
+ if (ih->data->is_dropdown)
+ {
+ GtkCellRenderer *renderer = NULL;
+
+ if (ih->data->has_editbox)
+ ih->handle = gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL(store), 0);
+ else
+ ih->handle = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
+ g_object_unref(store);
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ g_object_set(G_OBJECT(ih->handle), "has-frame", TRUE, NULL);
+
+ if (ih->data->has_editbox)
+ {
+ GtkWidget *entry;
+#if GTK_CHECK_VERSION(2, 12, 0)
+ GList* list = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(ih->handle));
+ renderer = list->data;
+ g_list_free(list);
+#endif
+
+ entry = gtk_bin_get_child(GTK_BIN(ih->handle));
+ iupAttribSetStr(ih, "_IUPGTK_ENTRY", (char*)entry);
+
+ g_signal_connect(G_OBJECT(entry), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(entry), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(entry), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(entry), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(entry), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+ g_signal_connect(G_OBJECT(entry), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih);
+
+ g_signal_connect(G_OBJECT(entry), "delete-text", G_CALLBACK(gtkListEditDeleteText), ih);
+ g_signal_connect(G_OBJECT(entry), "insert-text", G_CALLBACK(gtkListEditInsertText), ih);
+ /* g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(gtkListEditChanged), ih); */
+ g_signal_connect_after(G_OBJECT(entry), "move-cursor", G_CALLBACK(gtkListEditMoveCursor), ih); /* only report some caret movements */
+ g_signal_connect_after(G_OBJECT(entry), "key-release-event", G_CALLBACK(gtkListEditKeyReleaseEvent), ih);
+ g_signal_connect(G_OBJECT(entry), "button-press-event", G_CALLBACK(gtkListEditButtonEvent), ih); /* if connected "after" then it is ignored */
+ g_signal_connect(G_OBJECT(entry), "button-release-event",G_CALLBACK(gtkListEditButtonEvent), ih);
+
+ if (!iupAttribGetBoolean(ih, "CANFOCUS"))
+ GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS;
+ }
+ else
+ {
+ /* had to add an event box just to get get/killfocus,enter/leave events */
+ GtkWidget *box = gtk_event_box_new();
+ gtk_container_add((GtkContainer*)box, ih->handle);
+ iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)box);
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(ih->handle), renderer, TRUE);
+ gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(ih->handle), renderer, "text", 0, NULL);
+
+ g_signal_connect(G_OBJECT(box), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(box), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(box), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(box), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+
+ if (!iupAttribGetBoolean(ih, "CANFOCUS"))
+ GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS;
+ else
+ GTK_WIDGET_FLAGS(box) |= GTK_CAN_FOCUS;
+ }
+
+ g_signal_connect(ih->handle, "changed", G_CALLBACK(gtkListComboBoxChanged), ih);
+ g_signal_connect(ih->handle, "notify::popup-shown", G_CALLBACK(gtkListComboBoxPopupShownChanged), ih);
+
+ if (renderer)
+ {
+ renderer->xpad = 0;
+ renderer->ypad = 0;
+ iupAttribSetStr(ih, "_IUPGTK_RENDERER", (char*)renderer);
+ }
+ }
+ else
+ {
+ GtkCellRenderer *renderer;
+ GtkTreeSelection* selection;
+ GtkTreeViewColumn *column;
+ GtkPolicyType scrollbar_policy;
+
+ ih->handle = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
+ g_object_unref(store);
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ scrolled_window = (GtkScrolledWindow*)gtk_scrolled_window_new(NULL, NULL);
+
+ if (ih->data->has_editbox)
+ {
+ GtkBox* vbox = (GtkBox*)gtk_vbox_new(FALSE, 0);
+
+ GtkWidget *entry = gtk_entry_new();
+ gtk_widget_show(entry);
+ gtk_box_pack_start(vbox, entry, FALSE, FALSE, 0);
+ iupAttribSetStr(ih, "_IUPGTK_ENTRY", (char*)entry);
+
+ gtk_widget_show((GtkWidget*)vbox);
+ gtk_box_pack_end(vbox, (GtkWidget*)scrolled_window, TRUE, TRUE, 0);
+ iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)vbox);
+ iupAttribSetStr(ih, "_IUPGTK_SCROLLED_WINDOW", (char*)scrolled_window);
+
+ GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS; /* focus goes only to the edit box */
+ if (!iupAttribGetBoolean(ih, "CANFOCUS"))
+ GTK_WIDGET_FLAGS(entry) &= ~GTK_CAN_FOCUS;
+
+ g_signal_connect(G_OBJECT(entry), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(entry), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(entry), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(entry), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(entry), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+
+ g_signal_connect(G_OBJECT(entry), "delete-text", G_CALLBACK(gtkListEditDeleteText), ih);
+ g_signal_connect(G_OBJECT(entry), "insert-text", G_CALLBACK(gtkListEditInsertText), ih);
+ g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(gtkListEditChanged), ih);
+ g_signal_connect_after(G_OBJECT(entry), "move-cursor", G_CALLBACK(gtkListEditMoveCursor), ih); /* only report some caret movements */
+ g_signal_connect(G_OBJECT(entry), "key-press-event", G_CALLBACK(gtkListEditKeyPressEvent), ih);
+ g_signal_connect_after(G_OBJECT(entry), "key-release-event", G_CALLBACK(gtkListEditKeyReleaseEvent), ih);
+ g_signal_connect(G_OBJECT(entry), "button-press-event", G_CALLBACK(gtkListEditButtonEvent), ih); /* if connected "after" then it is ignored */
+ g_signal_connect(G_OBJECT(entry), "button-release-event",G_CALLBACK(gtkListEditButtonEvent), ih);
+ }
+ else
+ {
+ iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)scrolled_window);
+
+ if (!iupAttribGetBoolean(ih, "CANFOCUS"))
+ GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS;
+
+ g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(gtkListSimpleKeyPressEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+ }
+
+ column = gtk_tree_view_column_new();
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(column), renderer, TRUE);
+ gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(column), renderer, "text", 0, NULL);
+
+ iupAttribSetStr(ih, "_IUPGTK_RENDERER", (char*)renderer);
+ g_object_set(G_OBJECT(renderer), "xpad", 0, NULL);
+ g_object_set(G_OBJECT(renderer), "ypad", 0, NULL);
+
+ gtk_tree_view_append_column(GTK_TREE_VIEW(ih->handle), column);
+ gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(ih->handle), FALSE);
+ gtk_tree_view_set_enable_search(GTK_TREE_VIEW(ih->handle), FALSE); /* TODO: check "start-interactive-search" signal */
+
+ gtk_container_add((GtkContainer*)scrolled_window, ih->handle);
+ gtk_widget_show((GtkWidget*)scrolled_window);
+ gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_IN);
+
+ if (ih->data->sb)
+ {
+ if (iupAttribGetBoolean(ih, "AUTOHIDE"))
+ scrollbar_policy = GTK_POLICY_AUTOMATIC;
+ else
+ scrollbar_policy = GTK_POLICY_ALWAYS;
+ }
+ else
+ scrollbar_policy = GTK_POLICY_NEVER;
+
+ gtk_scrolled_window_set_policy(scrolled_window, scrollbar_policy, scrollbar_policy);
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+ if (!ih->data->has_editbox && ih->data->is_multiple)
+ {
+ gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
+#if GTK_CHECK_VERSION(2, 10, 0)
+ gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(ih->handle), TRUE);
+#endif
+ }
+ else
+ gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
+
+ g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(gtkListSelectionChanged), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "row-activated", G_CALLBACK(gtkListRowActivated), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "motion-notify-event",G_CALLBACK(iupgtkMotionNotifyEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "button-press-event", G_CALLBACK(iupgtkButtonEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "button-release-event",G_CALLBACK(iupgtkButtonEvent), ih);
+ }
+
+ if (iupAttribGetBoolean(ih, "SORT"))
+ gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), 0, GTK_SORT_ASCENDING);
+
+ /* add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ if (scrolled_window)
+ gtk_widget_realize((GtkWidget*)scrolled_window);
+ gtk_widget_realize(ih->handle);
+
+ /* configure for DRAG&DROP */
+ if (IupGetCallback(ih, "DROPFILES_CB"))
+ iupAttribSetStr(ih, "DRAGDROP", "YES");
+
+ IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)gtkListConvertXYToPos);
+
+ iupListSetInitialItems(ih);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvListInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkListMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Overwrite Common */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, gtkListSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED);
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkListSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, gtkListSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT);
+
+ /* IupList only */
+ iupClassRegisterAttributeId(ic, "IDVALUE", gtkListGetIdValueAttrib, iupListSetIdValueAttrib, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "VALUE", gtkListGetValueAttrib, gtkListSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SHOWDROPDOWN", NULL, gtkListSetShowDropdownAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TOPITEM", NULL, gtkListSetTopItemAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupgtkSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPACING", iupListGetSpacingAttrib, gtkListSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED);
+
+ iupClassRegisterAttribute(ic, "PADDING", iupListGetPaddingAttrib, gtkListSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "SELECTEDTEXT", gtkListGetSelectedTextAttrib, gtkListSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTION", gtkListGetSelectionAttrib, gtkListSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTIONPOS", gtkListGetSelectionPosAttrib, gtkListSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CARET", gtkListGetCaretAttrib, gtkListSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CARETPOS", gtkListGetCaretPosAttrib, gtkListSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "INSERT", NULL, gtkListSetInsertAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "APPEND", NULL, gtkListSetAppendAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "READONLY", gtkListGetReadOnlyAttrib, gtkListSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "NC", iupListGetNCAttrib, gtkListSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, gtkListSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SCROLLTO", NULL, gtkListSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, gtkListSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/gtk/iupgtk_loop.c b/iup/src/gtk/iupgtk_loop.c
new file mode 100755
index 0000000..e349a45
--- /dev/null
+++ b/iup/src/gtk/iupgtk_loop.c
@@ -0,0 +1,93 @@
+/** \file
+ * \brief GTK Message Loop
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+
+/* local variables */
+static IFidle gtk_idle_cb = NULL;
+static guint gtk_idle_id;
+
+static gboolean gtkIdleFunc(gpointer data)
+{
+ (void)data;
+ if (gtk_idle_cb)
+ {
+ int ret = gtk_idle_cb();
+ if (ret == IUP_CLOSE)
+ {
+ gtk_idle_cb = NULL;
+ IupExitLoop();
+ return FALSE; /* removes the idle */
+ }
+ if (ret == IUP_IGNORE)
+ {
+ gtk_idle_cb = NULL;
+ return FALSE; /* removes the idle */
+ }
+
+ return TRUE; /* keeps the idle */
+ }
+
+ return FALSE; /* removes the idle */
+}
+
+void iupdrvSetIdleFunction(Icallback f)
+{
+ if (gtk_idle_cb)
+ g_source_remove(gtk_idle_id);
+
+ gtk_idle_cb = (IFidle)f;
+
+ if (gtk_idle_cb)
+ gtk_idle_id = g_idle_add(gtkIdleFunc, NULL);
+}
+
+void IupExitLoop(void)
+{
+ if (gtk_main_iteration_do(FALSE)==FALSE)
+ gtk_main_quit();
+}
+
+int IupMainLoopLevel(void)
+{
+ return gtk_main_level();
+}
+
+int IupMainLoop(void)
+{
+ gtk_main();
+ return IUP_NOERROR;
+}
+
+int IupLoopStep(void)
+{
+ if (gtk_main_iteration_do(FALSE))
+ return IUP_CLOSE;
+ return IUP_DEFAULT;
+}
+
+void IupFlush(void)
+{
+ IFidle old_gtk_idle_cb = NULL;
+ if (gtk_idle_cb)
+ {
+ old_gtk_idle_cb = gtk_idle_cb;
+ iupdrvSetIdleFunction(NULL);
+ }
+
+ while (gtk_events_pending())
+ gtk_main_iteration();
+
+ if (old_gtk_idle_cb)
+ iupdrvSetIdleFunction((Icallback)old_gtk_idle_cb);
+}
diff --git a/iup/src/gtk/iupgtk_menu.c b/iup/src/gtk/iupgtk_menu.c
new file mode 100755
index 0000000..c12fbea
--- /dev/null
+++ b/iup/src/gtk/iupgtk_menu.c
@@ -0,0 +1,525 @@
+/** \file
+ * \brief Menu Resources
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#ifdef HILDON
+#include <hildon/hildon-window.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_attrib.h"
+#include "iup_dialog.h"
+#include "iup_str.h"
+#include "iup_label.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_image.h"
+#include "iup_menu.h"
+
+#include "iupgtk_drv.h"
+
+
+typedef struct _ImenuPos
+{
+ int x, y;
+} ImenuPos;
+
+static void gtkMenuPositionFunc(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, ImenuPos *menupos)
+{
+ *x = menupos->x;
+ *y = menupos->y;
+ *push_in = FALSE;
+ (void)menu;
+}
+
+int iupdrvMenuPopup(Ihandle* ih, int x, int y)
+{
+ ImenuPos menupos;
+ menupos.x = x;
+ menupos.y = y;
+ gtk_menu_popup((GtkMenu*)ih->handle, NULL, NULL, (GtkMenuPositionFunc)gtkMenuPositionFunc,
+ (gpointer)&menupos, 0, gtk_get_current_event_time());
+ gtk_main();
+ return IUP_NOERROR;
+}
+
+int iupdrvMenuGetMenuBarSize(Ihandle* ih)
+{
+ int ch;
+ iupdrvFontGetCharSize(ih, NULL, &ch);
+#ifdef WIN32
+ return 3 + ch + 3;
+#else
+ return 4 + ch + 4;
+#endif
+}
+
+static void gtkItemUpdateImage(Ihandle* ih, const char* value, const char* image, const char* impress)
+{
+ GdkPixbuf* pixbuf;
+
+ if (!impress || !iupStrBoolean(value))
+ pixbuf = iupImageGetImage(image, ih, 0);
+ else
+ pixbuf = iupImageGetImage(impress, ih, 0);
+
+ if (pixbuf)
+ {
+ GtkWidget* image_label = gtk_image_menu_item_get_image((GtkImageMenuItem*)ih->handle);
+ if (!image_label)
+ {
+ image_label = gtk_image_new();
+ gtk_image_menu_item_set_image((GtkImageMenuItem*)ih->handle, image_label);
+ }
+
+ if (pixbuf != gtk_image_get_pixbuf((GtkImage*)image_label))
+ gtk_image_set_from_pixbuf((GtkImage*)image_label, pixbuf);
+ }
+ else
+ gtk_image_menu_item_set_image((GtkImageMenuItem*)ih->handle, NULL);
+}
+
+
+/*******************************************************************************************/
+
+
+static void gtkMenuMap(GtkWidget *widget, Ihandle* ih)
+{
+ Icallback cb = IupGetCallback(ih, "OPEN_CB");
+ if (!cb && ih->parent) cb = (Icallback)IupGetCallback(ih->parent, "OPEN_CB"); /* check also in the Submenu */
+ if (cb) cb(ih);
+
+ (void)widget;
+}
+
+static void gtkMenuUnMap(GtkWidget *widget, Ihandle* ih)
+{
+ Icallback cb = IupGetCallback(ih, "MENUCLOSE_CB");
+ if (!cb && ih->parent) cb = (Icallback)IupGetCallback(ih->parent, "MENUCLOSE_CB"); /* check also in the Submenu */
+ if (cb) cb(ih);
+
+ (void)widget;
+}
+
+static void gtkPopupMenuUnMap(GtkWidget *widget, Ihandle* ih)
+{
+ gtkMenuUnMap(widget, ih);
+
+ /* quit the popup loop */
+ gtk_main_quit();
+}
+
+static void gtkItemSelect(GtkWidget *widget, Ihandle* ih)
+{
+ Icallback cb = IupGetCallback(ih, "HIGHLIGHT_CB");
+ if (cb)
+ cb(ih);
+
+ cb = IupGetCallback(ih, "HELP_CB");
+ if (cb)
+ gtk_menu_set_active((GtkMenu*)ih->parent->handle, IupGetChildPos(ih->parent, ih));
+
+ (void)widget;
+}
+
+static void gtkItemActivate(GtkWidget *widget, Ihandle* ih)
+{
+ Icallback cb;
+
+ if (GTK_IS_CHECK_MENU_ITEM(ih->handle) && !iupAttribGetBoolean(ih, "AUTOTOGGLE") && !iupAttribGetBoolean(ih->parent, "RADIO"))
+ {
+ /* GTK by default will do autotoggle */
+ g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkItemActivate), ih);
+ gtk_check_menu_item_set_active((GtkCheckMenuItem*)ih->handle, !gtk_check_menu_item_get_active((GtkCheckMenuItem*)ih->handle));
+ g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkItemActivate), ih);
+ }
+
+ if (GTK_IS_IMAGE_MENU_ITEM(ih->handle))
+ {
+ if (iupAttribGetBoolean(ih, "AUTOTOGGLE"))
+ {
+ if (iupAttribGetBoolean(ih, "VALUE"))
+ iupAttribSetStr(ih, "VALUE", "OFF");
+ else
+ iupAttribSetStr(ih, "VALUE", "ON");
+
+ gtkItemUpdateImage(ih, iupAttribGet(ih, "VALUE"), iupAttribGet(ih, "IMAGE"), iupAttribGet(ih, "IMPRESS"));
+ }
+ }
+
+ cb = IupGetCallback(ih, "ACTION");
+ if (cb && cb(ih)==IUP_CLOSE)
+ IupExitLoop();
+
+ (void)widget;
+}
+
+static gboolean gtkMenuKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
+{
+ if (evt->keyval == GDK_F1)
+ {
+ Ihandle* child;
+ GtkWidget* active = gtk_menu_get_active((GtkMenu*)widget);
+ for (child=ih->firstchild; child; child=child->brother)
+ {
+ if (child->handle == active)
+ iupgtkShowHelp(NULL, NULL, child);
+ }
+ }
+
+ (void)widget;
+ (void)evt;
+ return FALSE;
+}
+
+
+/*******************************************************************************************/
+
+
+static int gtkMenuMapMethod(Ihandle* ih)
+{
+ if (iupMenuIsMenuBar(ih))
+ {
+ /* top level menu used for MENU attribute in IupDialog (a menu bar) */
+#ifdef HILDON
+ Ihandle *pih;
+ ih->handle = gtk_menu_new();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ pih = iupChildTreeGetNativeParent(ih);
+ hildon_window_set_menu(HILDON_WINDOW(pih->handle), GTK_MENU(ih->handle));
+#else
+ ih->handle = gtk_menu_bar_new();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ iupgtkBaseAddToParent(ih);
+#endif
+ }
+ else
+ {
+ ih->handle = gtk_menu_new();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ if (ih->parent)
+ {
+ /* parent is a submenu */
+ gtk_menu_item_set_submenu((GtkMenuItem*)ih->parent->handle, ih->handle);
+
+ g_signal_connect(G_OBJECT(ih->handle), "map", G_CALLBACK(gtkMenuMap), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "unmap", G_CALLBACK(gtkMenuUnMap), ih);
+ }
+ else
+ {
+ /* top level menu used for IupPopup */
+ iupAttribSetStr(ih, "_IUPGTK_POPUP_MENU", "1");
+
+ g_signal_connect(G_OBJECT(ih->handle), "map", G_CALLBACK(gtkMenuMap), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "unmap", G_CALLBACK(gtkPopupMenuUnMap), ih);
+ }
+ }
+
+ gtk_widget_add_events(ih->handle, GDK_KEY_PRESS_MASK);
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(gtkMenuKeyPressEvent), ih);
+
+ ih->serial = iupMenuGetChildId(ih);
+ gtk_widget_show(ih->handle);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvMenuInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkMenuMapMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+
+ /* Used by iupdrvMenuGetMenuBarSize */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, NULL, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_DEFAULT); /* use inheritance to retrieve standard fonts */
+
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, NULL, NULL, IUPAF_DEFAULT);
+}
+
+
+/*******************************************************************************************/
+
+static int gtkItemSetTitleImageAttrib(Ihandle* ih, const char* value)
+{
+ if (GTK_IS_IMAGE_MENU_ITEM(ih->handle))
+ {
+ gtkItemUpdateImage(ih, NULL, value, NULL);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkItemSetImageAttrib(Ihandle* ih, const char* value)
+{
+ if (GTK_IS_IMAGE_MENU_ITEM(ih->handle))
+ {
+ gtkItemUpdateImage(ih, iupAttribGet(ih, "VALUE"), value, iupAttribGet(ih, "IMPRESS"));
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkItemSetImpressAttrib(Ihandle* ih, const char* value)
+{
+ if (GTK_IS_IMAGE_MENU_ITEM(ih->handle))
+ {
+ gtkItemUpdateImage(ih, iupAttribGet(ih, "VALUE"), iupAttribGet(ih, "IMAGE"), value);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkItemSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ char *str;
+ GtkWidget* label;
+
+ if (!value)
+ {
+ str = " ";
+ value = str;
+ }
+ else
+ str = iupMenuProcessTitle(ih, value);
+
+ label = gtk_bin_get_child((GtkBin*)ih->handle);
+
+ iupgtkSetMnemonicTitle(ih, (GtkLabel*)label, str);
+
+ if (str != value) free(str);
+ return 1;
+}
+
+static int gtkItemSetValueAttrib(Ihandle* ih, const char* value)
+{
+ if (GTK_IS_CHECK_MENU_ITEM(ih->handle))
+ {
+ if (iupAttribGetBoolean(ih->parent, "RADIO"))
+ value = "ON";
+
+ g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkItemActivate), ih);
+ gtk_check_menu_item_set_active((GtkCheckMenuItem*)ih->handle, iupStrBoolean(value));
+ g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkItemActivate), ih);
+ return 0;
+ }
+ else if (GTK_IS_IMAGE_MENU_ITEM(ih->handle))
+ {
+ gtkItemUpdateImage(ih, value, iupAttribGet(ih, "IMAGE"), iupAttribGet(ih, "IMPRESS"));
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static char* gtkItemGetValueAttrib(Ihandle* ih)
+{
+ if (GTK_IS_CHECK_MENU_ITEM(ih->handle))
+ {
+ if (gtk_check_menu_item_get_active((GtkCheckMenuItem*)ih->handle))
+ return "ON";
+ else
+ return "OFF";
+ }
+ else
+ return NULL;
+}
+
+static int gtkItemMapMethod(Ihandle* ih)
+{
+ int pos;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+#ifndef HILDON
+ if (iupMenuIsMenuBar(ih->parent))
+ ih->handle = gtk_menu_item_new_with_label("");
+ else
+#endif
+ {
+ if (iupAttribGet(ih, "IMAGE")||iupAttribGet(ih, "TITLEIMAGE"))
+ ih->handle = gtk_image_menu_item_new_with_label("");
+ else if (iupAttribGetBoolean(ih->parent, "RADIO"))
+ {
+ GtkRadioMenuItem* last_tg = (GtkRadioMenuItem*)iupAttribGet(ih->parent, "_IUPGTK_LASTRADIOITEM");
+ if (last_tg)
+ ih->handle = gtk_radio_menu_item_new_with_label_from_widget(last_tg, "");
+ else
+ ih->handle = gtk_radio_menu_item_new_with_label(NULL, "");
+ iupAttribSetStr(ih->parent, "_IUPGTK_LASTRADIOITEM", (char*)ih->handle);
+ }
+ else
+ {
+ char* hidemark = iupAttribGetStr(ih, "HIDEMARK");
+ if (!hidemark && gtk_check_version(2, 14, 0) == NULL)
+ {
+ /* force HIDEMARK if VALUE is defined before Map, after GTK 2.14 */
+ if (!iupAttribGet(ih, "VALUE"))
+ hidemark = "YES";
+ }
+
+ if (iupStrBoolean(hidemark))
+ ih->handle = gtk_menu_item_new_with_label("");
+ else
+ ih->handle = gtk_check_menu_item_new_with_label("");
+ }
+ }
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ ih->serial = iupMenuGetChildId(ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "select", G_CALLBACK(gtkItemSelect), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "activate", G_CALLBACK(gtkItemActivate), ih);
+
+ pos = IupGetChildPos(ih->parent, ih);
+ gtk_menu_shell_insert((GtkMenuShell*)ih->parent->handle, ih->handle, pos);
+ gtk_widget_show(ih->handle);
+
+ iupUpdateStandardFontAttrib(ih);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvItemInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkItemMapMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+
+ /* Common */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, iupdrvSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); /* use inheritance to retrieve standard fonts */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iupBaseSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* IupItem only */
+ iupClassRegisterAttribute(ic, "VALUE", gtkItemGetValueAttrib, gtkItemSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TITLE", NULL, gtkItemSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TITLEIMAGE", NULL, gtkItemSetTitleImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, gtkItemSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMPRESS", NULL, gtkItemSetImpressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupItem GTK and Motif only */
+ iupClassRegisterAttribute(ic, "HIDEMARK", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED);
+}
+
+
+/*******************************************************************************************/
+
+
+static int gtkSubmenuSetImageAttrib(Ihandle* ih, const char* value)
+{
+ if (GTK_IS_IMAGE_MENU_ITEM(ih->handle))
+ {
+ gtkItemUpdateImage(ih, NULL, value, NULL);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int motSubmenuMapMethod(Ihandle* ih)
+{
+ int pos;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+#ifndef HILDON
+ if (iupMenuIsMenuBar(ih->parent))
+ ih->handle = gtk_menu_item_new_with_label("");
+ else
+#endif
+ ih->handle = gtk_image_menu_item_new_with_label("");
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ ih->serial = iupMenuGetChildId(ih);
+
+ pos = IupGetChildPos(ih->parent, ih);
+ gtk_menu_shell_insert((GtkMenuShell*)ih->parent->handle, ih->handle, pos);
+ gtk_widget_show(ih->handle);
+
+ g_signal_connect(G_OBJECT(ih->handle), "select", G_CALLBACK(gtkItemSelect), ih);
+
+ iupUpdateStandardFontAttrib(ih);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvSubmenuInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = motSubmenuMapMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+
+ /* Common */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, iupdrvSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); /* use inheritance to retrieve standard fonts */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iupBaseSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* IupSubmenu only */
+ iupClassRegisterAttribute(ic, "TITLE", NULL, gtkItemSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, gtkSubmenuSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+}
+
+
+/*******************************************************************************************/
+
+
+static int gtkSeparatorMapMethod(Ihandle* ih)
+{
+ int pos;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ ih->handle = gtk_separator_menu_item_new();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ ih->serial = iupMenuGetChildId(ih);
+
+ pos = IupGetChildPos(ih->parent, ih);
+ gtk_menu_shell_insert((GtkMenuShell*)ih->parent->handle, ih->handle, pos);
+ gtk_widget_show(ih->handle);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvSeparatorInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkSeparatorMapMethod;
+ ic->UnMap = iupdrvBaseUnMapMethod;
+}
diff --git a/iup/src/gtk/iupgtk_messagedlg.c b/iup/src/gtk/iupgtk_messagedlg.c
new file mode 100755
index 0000000..a036af6
--- /dev/null
+++ b/iup/src/gtk/iupgtk_messagedlg.c
@@ -0,0 +1,128 @@
+/** \file
+ * \brief GTK IupMessageDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+
+#include "iupgtk_drv.h"
+
+/* Sometimes GTK decides to invert the buttons position because of the GNOME Guidelines.
+ To avoid that we define different Ids for the buttons. */
+#define IUP_RESPONSE_1 -100
+#define IUP_RESPONSE_2 -200
+#define IUP_RESPONSE_HELP -300
+
+#ifndef GTK_MESSAGE_OTHER
+#define GTK_MESSAGE_OTHER GTK_MESSAGE_INFO
+#endif
+
+static int gtkMessageDlgPopup(Ihandle* ih, int x, int y)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ GtkMessageType type = GTK_MESSAGE_OTHER;
+ GtkWidget* dialog;
+ char *icon, *buttons, *title;
+ int response, num_but = 2;
+
+ iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */
+ iupAttribSetInt(ih, "_IUPDLG_Y", y);
+
+ icon = iupAttribGetStr(ih, "DIALOGTYPE");
+ if (iupStrEqualNoCase(icon, "ERROR"))
+ type = GTK_MESSAGE_ERROR;
+ else if (iupStrEqualNoCase(icon, "WARNING"))
+ type = GTK_MESSAGE_WARNING;
+ else if (iupStrEqualNoCase(icon, "INFORMATION"))
+ type = GTK_MESSAGE_INFO;
+ else if (iupStrEqualNoCase(icon, "QUESTION"))
+ type = GTK_MESSAGE_QUESTION;
+
+ dialog = gtk_message_dialog_new((GtkWindow*)parent,
+ 0,
+ type,
+ GTK_BUTTONS_NONE,
+ iupgtkStrConvertToUTF8(iupAttribGet(ih, "VALUE")));
+ if (!dialog)
+ return IUP_ERROR;
+
+ title = iupAttribGet(ih, "TITLE");
+ if (title)
+ gtk_window_set_title(GTK_WINDOW(dialog), iupgtkStrConvertToUTF8(title));
+
+ buttons = iupAttribGetStr(ih, "BUTTONS");
+ if (iupStrEqualNoCase(buttons, "OKCANCEL"))
+ {
+ gtk_dialog_add_button(GTK_DIALOG(dialog),
+ GTK_STOCK_OK,
+ IUP_RESPONSE_1);
+ gtk_dialog_add_button(GTK_DIALOG(dialog),
+ GTK_STOCK_CANCEL,
+ IUP_RESPONSE_2);
+ }
+ else if (iupStrEqualNoCase(buttons, "YESNO"))
+ {
+ gtk_dialog_add_button(GTK_DIALOG(dialog),
+ GTK_STOCK_YES,
+ IUP_RESPONSE_1);
+ gtk_dialog_add_button(GTK_DIALOG(dialog),
+ GTK_STOCK_NO,
+ IUP_RESPONSE_2);
+ }
+ else /* OK */
+ {
+ gtk_dialog_add_button(GTK_DIALOG(dialog),
+ GTK_STOCK_OK,
+ IUP_RESPONSE_1);
+ num_but = 1;
+ }
+
+ if (IupGetCallback(ih, "HELP_CB"))
+ gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_HELP, IUP_RESPONSE_HELP);
+
+ if (num_but == 2 && iupAttribGetInt(ih, "BUTTONDEFAULT") == 2)
+ gtk_dialog_set_default_response(GTK_DIALOG(dialog), IUP_RESPONSE_2);
+ else
+ gtk_dialog_set_default_response(GTK_DIALOG(dialog), IUP_RESPONSE_1);
+
+ /* initialize the widget */
+ gtk_widget_realize(dialog);
+
+ ih->handle = dialog;
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL;
+
+ do
+ {
+ response = gtk_dialog_run(GTK_DIALOG(dialog));
+
+ if (response == IUP_RESPONSE_HELP)
+ {
+ Icallback cb = IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ response = (num_but == 2)? IUP_RESPONSE_2: IUP_RESPONSE_1;
+ }
+ } while (response == IUP_RESPONSE_HELP);
+
+ if (response == IUP_RESPONSE_1)
+ IupSetAttribute(ih, "BUTTONRESPONSE", "1");
+ else
+ IupSetAttribute(ih, "BUTTONRESPONSE", "2");
+
+ gtk_widget_destroy(dialog);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvMessageDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = gtkMessageDlgPopup;
+}
diff --git a/iup/src/gtk/iupgtk_open.c b/iup/src/gtk/iupgtk_open.c
new file mode 100755
index 0000000..66e46e8
--- /dev/null
+++ b/iup/src/gtk/iupgtk_open.c
@@ -0,0 +1,172 @@
+/** \file
+ * \brief GTK Driver Core
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include "iup.h"
+
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvinfo.h"
+#include "iup_object.h"
+#include "iup_globalattrib.h"
+
+#include "iupgtk_drv.h"
+
+
+#ifdef WIN32 /******************************** WIN32 ************************************/
+#include <gdk/gdkwin32.h>
+
+char* iupgtkGetNativeWindowHandle(Ihandle* ih)
+{
+ GdkWindow* window = ih->handle->window;
+ if (window)
+ return (char*)GDK_WINDOW_HWND(window);
+ else
+ return NULL;
+}
+
+void* iupgtkGetNativeGraphicsContext(GtkWidget* widget)
+{
+ return GetDC(GDK_WINDOW_HWND(widget->window));
+}
+
+void iupgtkReleaseNativeGraphicsContext(GtkWidget* widget, void* gc)
+{
+ ReleaseDC(GDK_WINDOW_HWND(widget->window), (HDC)gc);
+}
+
+void* iupdrvGetDisplay(void)
+{
+ return NULL;
+}
+
+void iupgtkPushVisualAndColormap(void* visual, void* colormap)
+{
+ (void)visual;
+ (void)colormap;
+}
+
+static void gtkSetDrvGlobalAttrib(void)
+{
+}
+
+#else /******************************** X11 ************************************/
+#include <gdk/gdkx.h>
+
+char* iupgtkGetNativeWindowHandle(Ihandle* ih)
+{
+ GdkWindow* window = ih->handle->window;
+ if (window)
+ return (char*)GDK_WINDOW_XID(window);
+ else
+ return NULL;
+}
+
+void* iupgtkGetNativeGraphicsContext(GtkWidget* widget)
+{
+ GdkDisplay* display = gdk_display_get_default();
+ return (void*)XCreateGC(GDK_DISPLAY_XDISPLAY(display), GDK_WINDOW_XID(widget->window), 0, NULL);
+}
+
+void iupgtkReleaseNativeGraphicsContext(GtkWidget* widget, void* gc)
+{
+ GdkDisplay* display = gdk_display_get_default();
+ XFreeGC(GDK_DISPLAY_XDISPLAY(display), (GC)gc);
+ (void)widget;
+}
+
+void* iupdrvGetDisplay(void)
+{
+ GdkDisplay* display = gdk_display_get_default();
+ return GDK_DISPLAY_XDISPLAY(display);
+}
+
+void iupgtkPushVisualAndColormap(void* visual, void* colormap)
+{
+ GdkColormap* gdk_colormap;
+ GdkVisual *gdk_visual = gdkx_visual_get(XVisualIDFromVisual((Visual*)visual));
+ if (colormap)
+ gdk_colormap = gdk_x11_colormap_foreign_new(gdk_visual, (Colormap)colormap);
+ else
+ gdk_colormap = gdk_colormap_new(gdk_visual, FALSE);
+
+ gtk_widget_push_colormap(gdk_colormap);
+
+ /* gtk_widget_push_visual is now deprecated */
+}
+
+static void gtkSetDrvGlobalAttrib(void)
+{
+ GdkDisplay* display = gdk_display_get_default();
+ Display* xdisplay = GDK_DISPLAY_XDISPLAY(display);
+ IupSetGlobal("XDISPLAY", (char*)xdisplay);
+ IupSetGlobal("XSCREEN", (char*)XDefaultScreen(xdisplay));
+ IupSetGlobal("XSERVERVENDOR", ServerVendor(xdisplay));
+ IupSetfAttribute(NULL, "XVENDORRELEASE", "%d", VendorRelease(xdisplay));
+}
+
+#endif
+
+static void gtkSetGlobalColorAttrib(const char* name, GdkColor *color)
+{
+ iupGlobalSetDefaultColorAttrib(name, (int)iupCOLOR16TO8(color->red),
+ (int)iupCOLOR16TO8(color->green),
+ (int)iupCOLOR16TO8(color->blue));
+}
+
+void iupgtkUpdateGlobalColors(GtkStyle* style)
+{
+ GdkColor color = style->bg[GTK_STATE_NORMAL];
+ gtkSetGlobalColorAttrib("DLGBGCOLOR", &color);
+
+ color = style->fg[GTK_STATE_NORMAL];
+ gtkSetGlobalColorAttrib("DLGFGCOLOR", &color);
+
+ color = style->base[GTK_STATE_NORMAL];
+ gtkSetGlobalColorAttrib("TXTBGCOLOR", &color);
+
+ color = style->text[GTK_STATE_NORMAL];
+ gtkSetGlobalColorAttrib("TXTFGCOLOR", &color);
+}
+
+int iupdrvOpen(int *argc, char ***argv)
+{
+ GtkStyle* style;
+
+ if (!gtk_init_check(argc, argv))
+ return IUP_ERROR;
+
+ IupSetGlobal("DRIVER", "GTK");
+
+ IupStoreGlobal("SYSTEMLANGUAGE", pango_language_to_string(gtk_get_default_language()));
+
+ /* driver system version */
+ IupSetfAttribute(NULL, "GTKVERSION", "%d.%d.%d", gtk_major_version,
+ gtk_minor_version,
+ gtk_micro_version);
+ IupSetfAttribute(NULL, "GTKDEVVERSION", "%d.%d.%d", GTK_MAJOR_VERSION,
+ GTK_MINOR_VERSION,
+ GTK_MICRO_VERSION);
+
+ gtkSetDrvGlobalAttrib();
+
+ style = gtk_style_new();
+ iupgtkUpdateGlobalColors(style);
+ IupSetGlobal("_IUP_RESET_GLOBALCOLORS", "YES"); /* will update the global colors when the first dialog is mapped */
+ g_object_unref(style);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvClose(void)
+{
+ iupgtkReleaseConvertUTF8();
+}
diff --git a/iup/src/gtk/iupgtk_progressbar.c b/iup/src/gtk/iupgtk_progressbar.c
new file mode 100755
index 0000000..7bc6cbb
--- /dev/null
+++ b/iup/src/gtk/iupgtk_progressbar.c
@@ -0,0 +1,131 @@
+/** \file
+* \brief Progress bar Control
+*
+* See Copyright Notice in "iup.h"
+*/
+
+#undef GTK_DISABLE_DEPRECATED
+#include <gtk/gtk.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_progressbar.h"
+#include "iup_drv.h"
+
+#include "iupgtk_drv.h"
+
+
+static int gtkProgressBarSetMarqueeAttrib(Ihandle* ih, const char* value)
+{
+ GtkProgress* progress = (GtkProgress*)ih->handle;
+
+ if (iupStrBoolean(value))
+ {
+ ih->data->marquee = 1;
+ gtk_progress_set_activity_mode(progress, TRUE);
+ }
+ else
+ {
+ gtk_progress_set_activity_mode(progress, FALSE);
+ ih->data->marquee = 0;
+ }
+
+ return 1;
+}
+
+static int gtkProgressBarSetValueAttrib(Ihandle* ih, const char* value)
+{
+ GtkProgressBar* pbar = (GtkProgressBar*)ih->handle;
+
+ if (!value)
+ ih->data->value = 0;
+ else
+ ih->data->value = atof(value);
+ iProgressBarCropValue(ih);
+
+ if (ih->data->marquee)
+ gtk_progress_bar_pulse(pbar);
+ else
+ gtk_progress_bar_set_fraction(pbar, (ih->data->value - ih->data->vmin) / (ih->data->vmax - ih->data->vmin));
+
+ return 0;
+}
+
+static int gtkProgressBarSetDashedAttrib(Ihandle* ih, const char* value)
+{
+ GtkProgressBar* pbar = (GtkProgressBar*)ih->handle;
+
+ /* gtk_progress_bar_set_bar_style is deprecated */
+ if (iupStrBoolean(value))
+ {
+ ih->data->dashed = 1;
+ gtk_progress_bar_set_bar_style(pbar, GTK_PROGRESS_DISCRETE);
+ }
+ else /* Default */
+ {
+ ih->data->dashed = 0;
+ gtk_progress_bar_set_bar_style(pbar, GTK_PROGRESS_CONTINUOUS);
+ }
+
+ return 0;
+}
+
+static int gtkProgressBarMapMethod(Ihandle* ih)
+{
+ ih->handle = gtk_progress_bar_new();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ /* add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ gtk_widget_realize(ih->handle);
+
+ if (iupStrEqualNoCase(iupAttribGetStr(ih, "ORIENTATION"), "VERTICAL"))
+ {
+ gtk_progress_bar_set_orientation((GtkProgressBar*)ih->handle, GTK_PROGRESS_BOTTOM_TO_TOP);
+
+ if (ih->currentheight < ih->currentwidth)
+ {
+ int tmp = ih->currentheight;
+ ih->currentheight = ih->currentwidth;
+ ih->currentwidth = tmp;
+ }
+ }
+ else
+ gtk_progress_bar_set_orientation((GtkProgressBar*)ih->handle, GTK_PROGRESS_LEFT_TO_RIGHT);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvProgressBarInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkProgressBarMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, NULL, NULL, IUPAF_DEFAULT);
+
+ /* IupProgressBar only */
+ iupClassRegisterAttribute(ic, "VALUE", iProgressBarGetValueAttrib, gtkProgressBarSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DASHED", iProgressBarGetDashedAttrib, gtkProgressBarSetDashedAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ORIENTATION", NULL, NULL, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MARQUEE", NULL, gtkProgressBarSetMarqueeAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DASHED", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/gtk/iupgtk_tabs.c b/iup/src/gtk/iupgtk_tabs.c
new file mode 100755
index 0000000..8029826
--- /dev/null
+++ b/iup/src/gtk/iupgtk_tabs.c
@@ -0,0 +1,444 @@
+/** \file
+* \brief Tabs Control
+*
+* See Copyright Notice in "iup.h"
+*/
+
+#include <gtk/gtk.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_image.h"
+#include "iup_tabs.h"
+
+#include "iupgtk_drv.h"
+
+
+int iupdrvTabsExtraDecor(Ihandle* ih)
+{
+ (void)ih;
+ return 0;
+}
+
+int iupdrvTabsGetLineCountAttrib(Ihandle* ih)
+{
+ (void)ih;
+ return 1;
+}
+
+void iupdrvTabsSetCurrentTab(Ihandle* ih, int pos)
+{
+ iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", "1");
+ gtk_notebook_set_current_page((GtkNotebook*)ih->handle, pos);
+ iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", NULL);
+}
+
+int iupdrvTabsGetCurrentTab(Ihandle* ih)
+{
+ return gtk_notebook_get_current_page((GtkNotebook*)ih->handle);
+}
+
+static void gtkTabsUpdatePageFont(Ihandle* ih)
+{
+ Ihandle* child;
+ PangoFontDescription* fontdesc = (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih);
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ GtkWidget* tab_label = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABLABEL");
+ if (tab_label)
+ {
+ gtk_widget_modify_font(tab_label, fontdesc);
+ iupgtkFontUpdatePangoLayout(ih, gtk_label_get_layout((GtkLabel*)tab_label));
+ }
+ }
+}
+
+static void gtkTabsUpdatePageBgColor(Ihandle* ih, unsigned char r, unsigned char g, unsigned char b)
+{
+ Ihandle* child;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ GtkWidget* tab_page = (GtkWidget*)iupAttribGet(child, "_IUPTAB_CONTAINER");
+ if (tab_page)
+ {
+ GtkWidget* tab_label = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABLABEL");
+ if (tab_label)
+ iupgtkBaseSetBgColor(tab_label, r, g, b);
+ iupgtkBaseSetBgColor(tab_page, r, g, b);
+ }
+ }
+}
+
+static void gtkTabsUpdatePageFgColor(Ihandle* ih, unsigned char r, unsigned char g, unsigned char b)
+{
+ Ihandle* child;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ GtkWidget* tab_label = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABLABEL");
+ if (tab_label)
+ iupgtkBaseSetFgColor(tab_label, r, g, b);
+ }
+}
+
+static void gtkTabsUpdatePagePadding(Ihandle* ih)
+{
+ Ihandle* child;
+
+ for (child = ih->firstchild; child; child = child->brother)
+ {
+ GtkWidget* tab_label = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABLABEL");
+ if (tab_label)
+ gtk_misc_set_padding((GtkMisc*)tab_label, ih->data->horiz_padding, ih->data->vert_padding);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+/* gtkTabs - Sets and Gets accessors */
+/* ------------------------------------------------------------------------- */
+
+
+static int gtkTabsSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x');
+
+ if (ih->handle)
+ gtkTabsUpdatePagePadding(ih);
+ return 0;
+}
+
+static void gtkTabsUpdateTabType(Ihandle* ih)
+{
+ GtkNotebook* tab_page = (GtkNotebook*)ih->handle;
+ int iup2gtk[4] = {GTK_POS_TOP, GTK_POS_BOTTOM, GTK_POS_LEFT, GTK_POS_RIGHT};
+ gtk_notebook_set_tab_pos(tab_page, iup2gtk[ih->data->type]);
+}
+
+static int gtkTabsSetTabTypeAttrib(Ihandle* ih, const char* value)
+{
+ if(iupStrEqualNoCase(value, "BOTTOM"))
+ ih->data->type = ITABS_BOTTOM;
+ else if(iupStrEqualNoCase(value, "LEFT"))
+ ih->data->type = ITABS_LEFT;
+ else if(iupStrEqualNoCase(value, "RIGHT"))
+ ih->data->type = ITABS_RIGHT;
+ else /* "TOP" */
+ ih->data->type = ITABS_TOP;
+
+ if (ih->handle)
+ gtkTabsUpdateTabType(ih);
+
+ return 0;
+}
+
+static int gtkTabsSetTabOrientationAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->handle) /* allow to set only before mapping */
+ return 0;
+
+ if(iupStrEqualNoCase(value, "VERTICAL"))
+ ih->data->orientation = ITABS_VERTICAL;
+ else /* HORIZONTAL */
+ ih->data->orientation = ITABS_HORIZONTAL;
+
+ return 0;
+}
+
+static int gtkTabsSetTabTitleAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ int pos;
+ if (value && iupStrToInt(name_id, &pos)==1)
+ {
+ Ihandle* child = IupGetChild(ih, pos);
+ GtkWidget* tab_label = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABLABEL");
+ if (tab_label)
+ {
+ GtkWidget* tab_page = (GtkWidget*)iupAttribGet(child, "_IUPTAB_CONTAINER");
+ gtk_label_set_text((GtkLabel*)tab_label, iupgtkStrConvertToUTF8(value));
+ gtk_notebook_set_menu_label_text((GtkNotebook*)ih->handle, tab_page, gtk_label_get_text((GtkLabel*)tab_label));
+ }
+ }
+ return 1;
+}
+
+static int gtkTabsSetTabImageAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ int pos;
+ if (value && iupStrToInt(name_id, &pos)==1)
+ {
+ Ihandle* child = IupGetChild(ih, pos);
+ GtkWidget* tab_image = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABIMAGE");
+ if (tab_image)
+ {
+ GdkPixbuf* pixbuf = iupImageGetImage(value, ih, 0);
+ if (pixbuf)
+ gtk_image_set_from_pixbuf((GtkImage*)tab_image, pixbuf);
+ }
+ }
+ return 1;
+}
+
+static int gtkTabsSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ iupdrvSetStandardFontAttrib(ih, value);
+ if (ih->handle)
+ gtkTabsUpdatePageFont(ih);
+ return 1;
+}
+
+static int gtkTabsSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgtkBaseSetFgColor(ih->handle, r, g, b);
+ gtkTabsUpdatePageFgColor(ih, r, g, b);
+
+ return 1;
+}
+
+static int gtkTabsSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgtkBaseSetBgColor(ih->handle, r, g, b);
+ gtkTabsUpdatePageBgColor(ih, r, g, b);
+
+ return 1;
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* gtkTabs - Callbacks */
+/* ------------------------------------------------------------------------- */
+
+void gtkTabSwitchPage(GtkNotebook* notebook, GtkNotebookPage *page, int pos, Ihandle* ih)
+{
+ IFnnn cb;
+ Ihandle* child = IupGetChild(ih, pos);
+ Ihandle* prev_child = IupGetChild(ih, iupdrvTabsGetCurrentTab(ih));
+ IupSetAttribute(child, "VISIBLE", "YES");
+ IupSetAttribute(prev_child, "VISIBLE", "NO");
+
+ if (iupAttribGet(ih, "_IUPGTK_IGNORE_CHANGE"))
+ return;
+
+ cb = (IFnnn)IupGetCallback(ih, "TABCHANGE_CB");
+ if (cb)
+ cb(ih, child, prev_child);
+
+ (void)notebook;
+ (void)page;
+}
+
+/* ------------------------------------------------------------------------- */
+/* gtkTabs - Methods and Init Class */
+/* ------------------------------------------------------------------------- */
+
+static void gtkTabsChildAddedMethod(Ihandle* ih, Ihandle* child)
+{
+ if (IupGetName(child) == NULL)
+ iupAttribSetHandleName(child);
+
+ if (ih->handle)
+ {
+ GtkWidget* tab_page;
+ GtkWidget *tab_label = NULL, *tab_image = NULL;
+ char *tabtitle, *tabimage;
+ int pos;
+ unsigned char r, g, b;
+
+ pos = IupGetChildPos(ih, child);
+
+ tab_page = gtk_fixed_new();
+ gtk_widget_show(tab_page);
+
+ tabtitle = iupAttribGet(child, "TABTITLE");
+ if (!tabtitle) tabtitle = iupTabsAttribGetStrId(ih, "TABTITLE", pos);
+ tabimage = iupAttribGet(child, "TABIMAGE");
+ if (!tabimage) tabimage = iupTabsAttribGetStrId(ih, "TABIMAGE", pos);
+ if (!tabtitle && !tabimage)
+ tabtitle = " ";
+
+ if (tabtitle)
+ {
+ tab_label = gtk_label_new(iupgtkStrConvertToUTF8(tabtitle));
+
+#if GTK_CHECK_VERSION(2, 6, 0)
+ if (ih->data->orientation == ITABS_VERTICAL)
+ gtk_label_set_angle((GtkLabel*)tab_label, 90);
+#endif
+ }
+
+ if (tabimage)
+ {
+ GdkPixbuf* pixbuf = iupImageGetImage(tabimage, ih, 0);
+
+ tab_image = gtk_image_new();
+
+ if (pixbuf)
+ gtk_image_set_from_pixbuf((GtkImage*)tab_image, pixbuf);
+ }
+
+ iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", "1");
+
+ if (tabimage && tabtitle)
+ {
+ GtkWidget* box;
+ if (ih->data->orientation == ITABS_VERTICAL)
+ box = gtk_vbox_new(FALSE, 2);
+ else
+ box = gtk_hbox_new(FALSE, 2);
+ gtk_widget_show(box);
+
+ gtk_container_add((GtkContainer*)box, tab_image);
+ gtk_container_add((GtkContainer*)box, tab_label);
+
+ gtk_notebook_insert_page((GtkNotebook*)ih->handle, tab_page, box, pos);
+ gtk_notebook_set_menu_label_text((GtkNotebook*)ih->handle, tab_page, gtk_label_get_text((GtkLabel*)tab_label));
+ }
+ else if (tabimage)
+ gtk_notebook_insert_page((GtkNotebook*)ih->handle, tab_page, tab_image, pos);
+ else
+ gtk_notebook_insert_page((GtkNotebook*)ih->handle, tab_page, tab_label, pos);
+
+ gtk_widget_realize(tab_page);
+
+ iupAttribSetStr(child, "_IUPGTK_TABIMAGE", (char*)tab_image); /* store it even if its NULL */
+ iupAttribSetStr(child, "_IUPGTK_TABLABEL", (char*)tab_label);
+ iupAttribSetStr(child, "_IUPTAB_CONTAINER", (char*)tab_page);
+ iupStrToRGB(IupGetAttribute(ih, "BGCOLOR"), &r, &g, &b);
+ iupgtkBaseSetBgColor(tab_page, r, g, b);
+
+ if (tabtitle)
+ {
+ PangoFontDescription* fontdesc = (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih);
+ gtk_widget_modify_font(tab_label, fontdesc);
+ iupgtkFontUpdatePangoLayout(ih, gtk_label_get_layout((GtkLabel*)tab_label));
+
+ iupgtkBaseSetBgColor(tab_label, r, g, b);
+
+ iupStrToRGB(IupGetAttribute(ih, "FGCOLOR"), &r, &g, &b);
+ iupgtkBaseSetFgColor(tab_label, r, g, b);
+
+ gtk_widget_show(tab_label);
+ gtk_widget_realize(tab_label);
+ }
+
+ if (tabimage)
+ {
+ gtk_widget_show(tab_image);
+ gtk_widget_realize(tab_image);
+ }
+
+ iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", NULL);
+
+ if (pos == iupdrvTabsGetCurrentTab(ih))
+ IupSetAttribute(child, "VISIBLE", "YES");
+ else
+ IupSetAttribute(child, "VISIBLE", "NO");
+ }
+}
+
+static void gtkTabsChildRemovedMethod(Ihandle* ih, Ihandle* child)
+{
+ if (ih->handle)
+ {
+ GtkWidget* tab_page = (GtkWidget*)iupAttribGet(child, "_IUPTAB_CONTAINER");
+ if (tab_page)
+ {
+ int pos = gtk_notebook_page_num((GtkNotebook*)ih->handle, tab_page);
+
+ iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", "1");
+ gtk_notebook_remove_page((GtkNotebook*)ih->handle, pos);
+ iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", NULL);
+
+ iupAttribSetStr(child, "_IUPGTK_TABIMAGE", NULL);
+ iupAttribSetStr(child, "_IUPGTK_TABLABEL", NULL);
+ iupAttribSetStr(child, "_IUPTAB_CONTAINER", NULL);
+ }
+ }
+}
+
+static int gtkTabsMapMethod(Ihandle* ih)
+{
+ ih->handle = gtk_notebook_new();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ gtk_notebook_set_scrollable((GtkNotebook*)ih->handle, TRUE);
+ gtk_notebook_popup_enable((GtkNotebook*)ih->handle);
+
+ gtkTabsUpdateTabType(ih);
+
+ /* add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ gtk_widget_add_events(ih->handle, GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK);
+
+ g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "switch-page", G_CALLBACK(gtkTabSwitchPage), ih);
+
+ gtk_widget_realize(ih->handle);
+
+ /* Create pages and tabs */
+ if (ih->firstchild)
+ {
+ Ihandle* child;
+ for (child = ih->firstchild; child; child = child->brother)
+ gtkTabsChildAddedMethod(ih, child);
+ }
+
+ return IUP_NOERROR;
+}
+
+void iupdrvTabsInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkTabsMapMethod;
+ ic->ChildAdded = gtkTabsChildAddedMethod;
+ ic->ChildRemoved = gtkTabsChildRemovedMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Common */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, gtkTabsSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED);
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkTabsSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, gtkTabsSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT);
+
+ /* IupTabs only */
+ iupClassRegisterAttribute(ic, "TABTYPE", iupTabsGetTabTypeAttrib, gtkTabsSetTabTypeAttrib, IUPAF_SAMEASSYSTEM, "TOP", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TABORIENTATION", iupTabsGetTabOrientationAttrib, gtkTabsSetTabOrientationAttrib, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "TABTITLE", NULL, gtkTabsSetTabTitleAttrib, IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "TABIMAGE", NULL, gtkTabsSetTabImageAttrib, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "PADDING", iupTabsGetPaddingAttrib, gtkTabsSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+}
diff --git a/iup/src/gtk/iupgtk_text.c b/iup/src/gtk/iupgtk_text.c
new file mode 100755
index 0000000..4c2906a
--- /dev/null
+++ b/iup/src/gtk/iupgtk_text.c
@@ -0,0 +1,1716 @@
+/** \file
+ * \brief Text Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_image.h"
+#include "iup_mask.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_image.h"
+#include "iup_key.h"
+#include "iup_array.h"
+#include "iup_text.h"
+
+#include "iupgtk_drv.h"
+
+#ifndef PANGO_WEIGHT_SEMIBOLD
+#define PANGO_WEIGHT_SEMIBOLD 600
+#endif
+
+void iupdrvTextAddSpin(int *w, int h)
+{
+ int spin_size = 16;
+ *w += spin_size;
+ (void)h;
+}
+
+void iupdrvTextAddBorders(int *x, int *y)
+{
+ int border_size = 2*5;
+ (*x) += border_size;
+ (*y) += border_size;
+}
+
+static void gtkTextParseParagraphFormat(Ihandle* formattag, GtkTextTag* tag)
+{
+ int val;
+ char* format;
+
+ format = iupAttribGet(formattag, "INDENT");
+ if (format && iupStrToInt(format, &val))
+ g_object_set(G_OBJECT(tag), "indent", val, NULL);
+
+ format = iupAttribGet(formattag, "ALIGNMENT");
+ if (format)
+ {
+ if (iupStrEqualNoCase(format, "JUSTIFY"))
+ val = GTK_JUSTIFY_FILL;
+ else if (iupStrEqualNoCase(format, "RIGHT"))
+ val = GTK_JUSTIFY_RIGHT;
+ else if (iupStrEqualNoCase(format, "CENTER"))
+ val = GTK_JUSTIFY_CENTER;
+ else /* "LEFT" */
+ val = GTK_JUSTIFY_LEFT;
+
+ g_object_set(G_OBJECT(tag), "justification", val, NULL);
+ }
+
+ format = iupAttribGet(formattag, "TABSARRAY");
+ {
+ PangoTabArray *tabs;
+ int pos, i = 0;
+ PangoTabAlign align;
+ char* str;
+
+ tabs = pango_tab_array_new(32, FALSE);
+
+ while (format)
+ {
+ str = iupStrCopyUntil((char**)&format, ' ');
+ if (!str) break;
+ pos = atoi(str);
+ free(str);
+
+ str = iupStrCopyUntil((char**)&format, ' ');
+ if (!str) break;
+
+/* if (iupStrEqualNoCase(str, "DECIMAL")) unsupported for now
+ align = PANGO_TAB_NUMERIC;
+ else if (iupStrEqualNoCase(str, "RIGHT"))
+ align = PANGO_TAB_RIGHT;
+ else if (iupStrEqualNoCase(str, "CENTER"))
+ align = PANGO_TAB_CENTER;
+ else */ /* "LEFT" */
+ align = PANGO_TAB_LEFT;
+ free(str);
+
+ pango_tab_array_set_tab(tabs, i, align, IUPGTK_PIXELS2PANGOUNITS(pos));
+ i++;
+ if (i == 32) break;
+ }
+
+ g_object_set(G_OBJECT(tag), "tabs", tabs, NULL);
+ pango_tab_array_free(tabs);
+ }
+
+ format = iupAttribGet(formattag, "SPACEBEFORE");
+ if (format && iupStrToInt(format, &val))
+ g_object_set(G_OBJECT(tag), "pixels-above-lines", val, NULL);
+
+ format = iupAttribGet(formattag, "SPACEAFTER");
+ if (format && iupStrToInt(format, &val))
+ g_object_set(G_OBJECT(tag), "pixels-below-lines", val, NULL);
+
+ format = iupAttribGet(formattag, "LINESPACING");
+ if (format && iupStrToInt(format, &val))
+ g_object_set(G_OBJECT(tag), "pixels-inside-wrap", val, NULL);
+}
+
+static void gtkTextParseCharacterFormat(Ihandle* formattag, GtkTextTag* tag)
+{
+ int val;
+ char* format;
+
+ format = iupAttribGet(formattag, "LANGUAGE");
+ if (format)
+ g_object_set(G_OBJECT(tag), "language", format, NULL);
+
+ format = iupAttribGet(formattag, "STRETCH");
+ if (format)
+ {
+ if (iupStrEqualNoCase(format, "EXTRA_CONDENSED"))
+ val = PANGO_STRETCH_EXTRA_CONDENSED;
+ else if (iupStrEqualNoCase(format, "CONDENSED"))
+ val = PANGO_STRETCH_CONDENSED;
+ else if (iupStrEqualNoCase(format, "SEMI_CONDENSED"))
+ val = PANGO_STRETCH_SEMI_CONDENSED;
+ else if (iupStrEqualNoCase(format, "SEMI_EXPANDED"))
+ val = PANGO_STRETCH_SEMI_EXPANDED;
+ else if (iupStrEqualNoCase(format, "EXPANDED"))
+ val = PANGO_STRETCH_EXPANDED;
+ else if (iupStrEqualNoCase(format, "EXTRA_EXPANDED"))
+ val = PANGO_STRETCH_EXTRA_EXPANDED;
+ else /* "NORMAL" */
+ val = PANGO_STRETCH_NORMAL;
+
+ g_object_set(G_OBJECT(tag), "stretch", val, NULL);
+ }
+
+ format = iupAttribGet(formattag, "RISE");
+ if (format)
+ {
+ val = 0;
+
+ if (iupStrEqualNoCase(format, "SUPERSCRIPT"))
+ {
+ g_object_set(G_OBJECT(tag), "scale", PANGO_SCALE_X_SMALL, NULL);
+ val = 10; /* 10 pixels up */
+ }
+ else if (iupStrEqualNoCase(format, "SUBSCRIPT"))
+ {
+ g_object_set(G_OBJECT(tag), "scale", PANGO_SCALE_X_SMALL, NULL);
+ val = -10; /* 10 pixels down */
+ }
+ else
+ iupStrToInt(format, &val);
+
+ val = IUPGTK_PIXELS2PANGOUNITS(val);
+ g_object_set(G_OBJECT(tag), "rise", val, NULL);
+ }
+
+ format = iupAttribGet(formattag, "SMALLCAPS");
+ if (format)
+ {
+ if (iupStrBoolean(format))
+ val = PANGO_VARIANT_SMALL_CAPS;
+ else
+ val = PANGO_VARIANT_NORMAL;
+ g_object_set(G_OBJECT(tag), "variant", val, NULL);
+ }
+
+ format = iupAttribGet(formattag, "ITALIC");
+ if (format)
+ {
+ if (iupStrBoolean(format))
+ val = PANGO_STYLE_ITALIC;
+ else
+ val = PANGO_STYLE_NORMAL;
+ g_object_set(G_OBJECT(tag), "style", val, NULL);
+ }
+
+ format = iupAttribGet(formattag, "STRIKEOUT");
+ if (format)
+ {
+ val = iupStrBoolean(format);
+ g_object_set(G_OBJECT(tag), "strikethrough", val, NULL);
+ }
+
+ format = iupAttribGet(formattag, "PROTECTED");
+ if (format)
+ {
+ val = iupStrBoolean(format);
+ g_object_set(G_OBJECT(tag), "editable", val, NULL);
+ }
+
+ format = iupAttribGet(formattag, "FONTSIZE");
+ if (format && iupStrToInt(format, &val))
+ {
+ if (val < 0) /* in pixels */
+ {
+ val = IUPGTK_PIXELS2PANGOUNITS(-val);
+ g_object_set(G_OBJECT(tag), "size", val, NULL);
+ }
+ else /* in points */
+ g_object_set(G_OBJECT(tag), "size-points", (double)val, NULL);
+ }
+
+ format = iupAttribGet(formattag, "FONTSCALE");
+ if (format)
+ {
+ float fval = 0;
+ if (iupStrEqualNoCase(format, "XX-SMALL"))
+ fval = (float)PANGO_SCALE_XX_SMALL;
+ else if (iupStrEqualNoCase(format, "X-SMALL"))
+ fval = (float)PANGO_SCALE_X_SMALL;
+ else if (iupStrEqualNoCase(format, "SMALL"))
+ fval = (float)PANGO_SCALE_SMALL;
+ else if (iupStrEqualNoCase(format, "MEDIUM"))
+ fval = (float)PANGO_SCALE_MEDIUM;
+ else if (iupStrEqualNoCase(format, "LARGE"))
+ fval = (float)PANGO_SCALE_LARGE;
+ else if (iupStrEqualNoCase(format, "X-LARGE"))
+ fval = (float)PANGO_SCALE_X_LARGE;
+ else if (iupStrEqualNoCase(format, "XX-LARGE"))
+ fval = (float)PANGO_SCALE_XX_LARGE;
+ else
+ iupStrToFloat(format, &fval);
+
+ if (fval > 0)
+ g_object_set(G_OBJECT(tag), "scale", (double)fval, NULL);
+ }
+
+ format = iupAttribGet(formattag, "FONTFACE");
+ if (format)
+ g_object_set(G_OBJECT(tag), "family", format, NULL);
+
+ format = iupAttribGet(formattag, "FGCOLOR");
+ if (format)
+ {
+ unsigned char r, g, b;
+ if (iupStrToRGB(format, &r, &g, &b))
+ {
+ GdkColor color;
+ iupgdkColorSet(&color, r, g, b);
+ g_object_set(G_OBJECT(tag), "foreground-gdk", &color, NULL);
+ }
+ }
+
+ format = iupAttribGet(formattag, "BGCOLOR");
+ if (format)
+ {
+ unsigned char r, g, b;
+ if (iupStrToRGB(format, &r, &g, &b))
+ {
+ GdkColor color;
+ iupgdkColorSet(&color, r, g, b);
+ g_object_set(G_OBJECT(tag), "background-gdk", &color, NULL);
+ }
+ }
+
+ format = iupAttribGet(formattag, "UNDERLINE");
+ if (format)
+ {
+ if (iupStrEqualNoCase(format, "SINGLE"))
+ val = PANGO_UNDERLINE_SINGLE;
+ else if (iupStrEqualNoCase(format, "DOUBLE"))
+ val = PANGO_UNDERLINE_DOUBLE;
+ else /* "NONE" */
+ val = PANGO_UNDERLINE_NONE;
+
+ g_object_set(G_OBJECT(tag), "underline", val, NULL);
+ }
+
+ format = iupAttribGet(formattag, "WEIGHT");
+ if (format)
+ {
+ if (iupStrEqualNoCase(format, "EXTRALIGHT"))
+ val = PANGO_WEIGHT_ULTRALIGHT;
+ else if (iupStrEqualNoCase(format, "LIGHT"))
+ val = PANGO_WEIGHT_LIGHT;
+ else if (iupStrEqualNoCase(format, "SEMIBOLD"))
+ val = PANGO_WEIGHT_SEMIBOLD;
+ else if (iupStrEqualNoCase(format, "BOLD"))
+ val = PANGO_WEIGHT_BOLD;
+ else if (iupStrEqualNoCase(format, "EXTRABOLD"))
+ val = PANGO_WEIGHT_ULTRABOLD;
+ else if (iupStrEqualNoCase(format, "HEAVY"))
+ val = PANGO_WEIGHT_HEAVY;
+ else /* "NORMAL" */
+ val = PANGO_WEIGHT_NORMAL;
+
+ g_object_set(G_OBJECT(tag), "weight", val, NULL);
+ }
+}
+
+static void gtkTextMoveIterToLinCol(GtkTextBuffer *buffer, GtkTextIter *iter, int lin, int col)
+{
+ int line_count, line_length;
+
+ lin--; /* IUP starts at 1 */
+ col--;
+
+ line_count = gtk_text_buffer_get_line_count(buffer);
+ if (lin < 0) lin = 0;
+ if (lin >= line_count)
+ lin = line_count-1;
+
+ gtk_text_buffer_get_iter_at_line(buffer, iter, lin);
+ line_length = gtk_text_iter_get_chars_in_line(iter);
+
+ if (col < 0) col = 0;
+ if (col > line_length)
+ col = line_length; /* after the last character */
+
+ gtk_text_iter_set_line_offset(iter, col);
+}
+
+static void gtkTextGetLinColFromPosition(const GtkTextIter *iter, int *lin, int *col)
+{
+ *lin = gtk_text_iter_get_line(iter);
+ *col = gtk_text_iter_get_line_offset(iter);
+
+ (*lin)++; /* IUP starts at 1 */
+ (*col)++;
+}
+
+static int gtkTextGetCharSize(Ihandle* ih)
+{
+ int charwidth;
+ PangoFontMetrics* metrics;
+ PangoContext* context;
+ PangoFontDescription* fontdesc = (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih);
+ if (!fontdesc)
+ return 0;
+
+ context = gdk_pango_context_get();
+ metrics = pango_context_get_metrics(context, fontdesc, pango_context_get_language(context));
+ charwidth = pango_font_metrics_get_approximate_char_width(metrics);
+ pango_font_metrics_unref(metrics);
+ return charwidth;
+}
+
+void iupdrvTextConvertLinColToPos(Ihandle* ih, int lin, int col, int *pos)
+{
+ GtkTextIter iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtkTextMoveIterToLinCol(buffer, &iter, lin, col);
+ *pos = gtk_text_iter_get_offset(&iter);
+}
+
+void iupdrvTextConvertPosToLinCol(Ihandle* ih, int pos, int *lin, int *col)
+{
+ GtkTextIter iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_iter_at_offset(buffer, &iter, pos);
+ gtkTextGetLinColFromPosition(&iter, lin, col);
+}
+
+static int gtkTextConvertXYToPos(Ihandle* ih, int x, int y)
+{
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter iter;
+ gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(ih->handle), GTK_TEXT_WINDOW_WIDGET, x, y, &x, &y);
+ gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(ih->handle), &iter, x, y);
+ return gtk_text_iter_get_offset(&iter);
+ }
+ else
+ {
+ int trailing, off_x, off_y, pos;
+
+ /* transform to Layout coordinates */
+ gtk_entry_get_layout_offsets(GTK_ENTRY(ih->handle), &off_x, &off_y);
+ x = IUPGTK_PIXELS2PANGOUNITS(x - off_x);
+ y = IUPGTK_PIXELS2PANGOUNITS(y - off_y);
+
+ pango_layout_xy_to_index(gtk_entry_get_layout(GTK_ENTRY(ih->handle)), x, y, &pos, &trailing);
+ return pos;
+ }
+}
+
+static void gtkTextScrollToVisible(Ihandle* ih)
+{
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ GtkTextMark* mark = gtk_text_buffer_get_insert(buffer);
+ gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(ih->handle), mark);
+}
+
+
+/*******************************************************************************************/
+
+
+static int gtkTextSetSelectionAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ return 0;
+
+ if (!value || iupStrEqualNoCase(value, "NONE"))
+ {
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter start_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_start_iter(buffer, &start_iter);
+ gtk_text_buffer_select_range(buffer, &start_iter, &start_iter);
+ }
+ else
+ gtk_editable_select_region(GTK_EDITABLE(ih->handle), 0, 0);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(value, "ALL"))
+ {
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter start_iter;
+ GtkTextIter end_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_start_iter(buffer, &start_iter);
+ gtk_text_buffer_get_end_iter(buffer, &end_iter);
+ gtk_text_buffer_select_range(buffer, &start_iter, &end_iter);
+ }
+ else
+ gtk_editable_select_region(GTK_EDITABLE(ih->handle), 0, -1);
+ return 0;
+ }
+
+ if (ih->data->is_multiline)
+ {
+ int lin_start=1, col_start=1, lin_end=1, col_end=1;
+ GtkTextIter start_iter, end_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+
+ if (sscanf(value, "%d,%d:%d,%d", &lin_start, &col_start, &lin_end, &col_end)!=4) return 0;
+ if (lin_start<1 || col_start<1 || lin_end<1 || col_end<1) return 0;
+
+ gtkTextMoveIterToLinCol(buffer, &start_iter, lin_start, col_start);
+ gtkTextMoveIterToLinCol(buffer, &end_iter, lin_end, col_end);
+
+ gtk_text_buffer_select_range(buffer, &start_iter, &end_iter);
+ }
+ else
+ {
+ int start=1, end=1;
+ if (iupStrToIntInt(value, &start, &end, ':')!=2)
+ return 0;
+
+ if(start<1 || end<1)
+ return 0;
+
+ start--; /* IUP starts at 1 */
+ end--;
+
+ gtk_editable_select_region(GTK_EDITABLE(ih->handle), start, end);
+ }
+
+ return 0;
+}
+
+static char* gtkTextGetSelectionAttrib(Ihandle* ih)
+{
+ char *str;
+
+ if (ih->data->is_multiline)
+ {
+ int start_col, start_lin, end_col, end_lin;
+
+ GtkTextIter start_iter, end_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ if (gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter))
+ {
+ gtkTextGetLinColFromPosition(&start_iter, &start_lin, &start_col);
+ gtkTextGetLinColFromPosition(&end_iter, &end_lin, &end_col);
+
+ str = iupStrGetMemory(100);
+ sprintf(str,"%d,%d:%d,%d", start_lin, start_col, end_lin, end_col);
+ return str;
+ }
+ }
+ else
+ {
+ int start, end;
+ if (gtk_editable_get_selection_bounds(GTK_EDITABLE(ih->handle), &start, &end))
+ {
+ start++; /* IUP starts at 1 */
+ end++;
+ str = iupStrGetMemory(100);
+ sprintf(str, "%d:%d", (int)start, (int)end);
+ return str;
+ }
+ }
+
+ return NULL;
+}
+
+static int gtkTextSetSelectionPosAttrib(Ihandle* ih, const char* value)
+{
+ int start=0, end=0;
+
+ if (!value)
+ return 0;
+
+ if (!value || iupStrEqualNoCase(value, "NONE"))
+ {
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter start_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_start_iter(buffer, &start_iter);
+ gtk_text_buffer_select_range(buffer, &start_iter, &start_iter);
+ }
+ else
+ gtk_editable_select_region(GTK_EDITABLE(ih->handle), 0, 0);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(value, "ALL"))
+ {
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter start_iter;
+ GtkTextIter end_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_start_iter(buffer, &start_iter);
+ gtk_text_buffer_get_end_iter(buffer, &end_iter);
+ gtk_text_buffer_select_range(buffer, &start_iter, &end_iter);
+ }
+ else
+ gtk_editable_select_region(GTK_EDITABLE(ih->handle), 0, -1);
+ return 0;
+ }
+
+ if (iupStrToIntInt(value, &start, &end, ':')!=2)
+ return 0;
+
+ if(start<0 || end<0)
+ return 0;
+
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter start_iter, end_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+
+ gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, start);
+ gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, end);
+
+ gtk_text_buffer_select_range(buffer, &start_iter, &end_iter);
+ }
+ else
+ gtk_editable_select_region(GTK_EDITABLE(ih->handle), start, end);
+
+ return 0;
+}
+
+static char* gtkTextGetSelectionPosAttrib(Ihandle* ih)
+{
+ int start, end;
+ char *str;
+
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter start_iter, end_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ if (gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter))
+ {
+ start = gtk_text_iter_get_offset(&start_iter);
+ end = gtk_text_iter_get_offset(&end_iter);
+
+ str = iupStrGetMemory(100);
+ sprintf(str, "%d:%d", (int)start, (int)end);
+ return str;
+ }
+ }
+ else
+ {
+ if (gtk_editable_get_selection_bounds(GTK_EDITABLE(ih->handle), &start, &end))
+ {
+ str = iupStrGetMemory(100);
+ sprintf(str, "%d:%d", (int)start, (int)end);
+ return str;
+ }
+ }
+
+ return NULL;
+}
+
+static int gtkTextSetSelectedTextAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ return 0;
+
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter start_iter, end_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ if (gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter))
+ {
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ gtk_text_buffer_delete(buffer, &start_iter, &end_iter);
+ gtk_text_buffer_insert(buffer, &start_iter, iupgtkStrConvertToUTF8(value), -1);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ }
+ }
+ else
+ {
+ int start, end;
+ if (gtk_editable_get_selection_bounds(GTK_EDITABLE(ih->handle), &start, &end))
+ {
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ gtk_editable_delete_selection(GTK_EDITABLE(ih->handle));
+ gtk_editable_insert_text(GTK_EDITABLE(ih->handle), iupgtkStrConvertToUTF8(value), -1, &start);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ }
+ }
+
+ return 0;
+}
+
+static char* gtkTextGetSelectedTextAttrib(Ihandle* ih)
+{
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter start_iter, end_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ if (gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter))
+ return iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_text_buffer_get_text(buffer, &start_iter, &end_iter, TRUE)));
+ }
+ else
+ {
+ int start, end;
+ if (gtk_editable_get_selection_bounds(GTK_EDITABLE(ih->handle), &start, &end))
+ {
+ char* selectedtext = gtk_editable_get_chars(GTK_EDITABLE(ih->handle), start, end);
+ char* str = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(selectedtext));
+ g_free(selectedtext);
+ return str;
+ }
+ }
+
+ return NULL;
+}
+
+static int gtkTextSetCaretAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 1;
+
+ if (!value)
+ return 0;
+
+ if (ih->data->is_multiline)
+ {
+ int lin = 1, col = 1;
+ GtkTextIter iter;
+
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+
+ iupStrToIntInt(value, &lin, &col, ',');
+
+ gtkTextMoveIterToLinCol(buffer, &iter, lin, col);
+
+ gtk_text_buffer_place_cursor(buffer, &iter);
+ gtkTextScrollToVisible(ih);
+ }
+ else
+ {
+ sscanf(value,"%i",&pos);
+ pos--; /* IUP starts at 1 */
+ if (pos < 0) pos = 0;
+
+ gtk_editable_set_position(GTK_EDITABLE(ih->handle), pos);
+ }
+
+ return 0;
+}
+
+static char* gtkTextGetCaretAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(50);
+
+ if (ih->data->is_multiline)
+ {
+ int col, lin;
+ GtkTextIter iter;
+
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_iter_at_mark(buffer, &iter, gtk_text_buffer_get_insert(buffer));
+ gtkTextGetLinColFromPosition(&iter, &lin, &col);
+
+ sprintf(str, "%d,%d", lin, col);
+ }
+ else
+ {
+ int pos = gtk_editable_get_position(GTK_EDITABLE(ih->handle));
+ pos++; /* IUP starts at 1 */
+ sprintf(str, "%d", (int)pos);
+ }
+
+ return str;
+}
+
+static int gtkTextSetCaretPosAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 0) pos = 0;
+
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_iter_at_offset(buffer, &iter, pos);
+ gtk_text_buffer_place_cursor(buffer, &iter);
+ gtkTextScrollToVisible(ih);
+ }
+ else
+ gtk_editable_set_position(GTK_EDITABLE(ih->handle), pos);
+
+ return 0;
+}
+
+static char* gtkTextGetCaretPosAttrib(Ihandle* ih)
+{
+ int pos;
+ char* str = iupStrGetMemory(50);
+
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_iter_at_mark(buffer, &iter, gtk_text_buffer_get_insert(buffer));
+ pos = gtk_text_iter_get_offset(&iter);
+ }
+ else
+ pos = gtk_editable_get_position(GTK_EDITABLE(ih->handle));
+
+ sprintf(str, "%d", (int)pos);
+ return str;
+}
+
+static int gtkTextSetScrollToAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ return 0;
+
+ if (ih->data->is_multiline)
+ {
+ int lin = 1, col = 1;
+ GtkTextIter iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+
+ iupStrToIntInt(value, &lin, &col, ',');
+ if (lin < 1) lin = 1;
+ if (col < 1) col = 1;
+
+ gtkTextMoveIterToLinCol(buffer, &iter, lin, col);
+ gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(ih->handle), &iter, 0, FALSE, 0, 0);
+ }
+ else
+ {
+ int pos = 1;
+ sscanf(value,"%i",&pos);
+ if (pos < 1) pos = 1;
+ pos--; /* return to GTK referece */
+ gtk_editable_set_position(GTK_EDITABLE(ih->handle), pos);
+ }
+
+ return 0;
+}
+
+static int gtkTextSetScrollToPosAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 0) pos = 0;
+
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_iter_at_offset(buffer, &iter, pos);
+ gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(ih->handle), &iter, 0, FALSE, 0, 0);
+ }
+ else
+ gtk_editable_set_position(GTK_EDITABLE(ih->handle), pos);
+
+ return 0;
+}
+
+static int gtkTextSetValueAttrib(Ihandle* ih, const char* value)
+{
+ if (!value) value = "";
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ if (ih->data->is_multiline)
+ {
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_set_text(buffer, iupgtkStrConvertToUTF8(value), -1);
+ }
+ else
+ gtk_entry_set_text(GTK_ENTRY(ih->handle), iupgtkStrConvertToUTF8(value));
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ return 0;
+}
+
+static char* gtkTextGetValueAttrib(Ihandle* ih)
+{
+ char* value;
+
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter start_iter;
+ GtkTextIter end_iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_start_iter(buffer, &start_iter);
+ gtk_text_buffer_get_end_iter(buffer, &end_iter);
+ value = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_text_buffer_get_text(buffer, &start_iter, &end_iter, TRUE)));
+ }
+ else
+ value = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_entry_get_text(GTK_ENTRY(ih->handle))));
+
+ if (!value) value = "";
+
+ return value;
+}
+
+static int gtkTextSetInsertAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ if (!value)
+ return 0;
+
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ if (ih->data->is_multiline)
+ {
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_insert_at_cursor(buffer, iupgtkStrConvertToUTF8(value), -1);
+ }
+ else
+ {
+ gint pos = gtk_editable_get_position(GTK_EDITABLE(ih->handle));
+ gtk_editable_insert_text(GTK_EDITABLE(ih->handle), iupgtkStrConvertToUTF8(value), -1, &pos);
+ }
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+
+ return 0;
+}
+
+static int gtkTextSetAppendAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter iter;
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_end_iter(buffer, &iter);
+ if (ih->data->append_newline)
+ gtk_text_buffer_insert(buffer, &iter, "\n", 1);
+ gtk_text_buffer_insert(buffer, &iter, iupgtkStrConvertToUTF8(value), -1);
+ }
+ else
+ {
+ gint pos = strlen(gtk_entry_get_text(GTK_ENTRY(ih->handle)))+1;
+ gtk_editable_insert_text(GTK_EDITABLE(ih->handle), iupgtkStrConvertToUTF8(value), -1, &pos);
+ }
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ return 0;
+}
+
+static int gtkTextSetAlignmentAttrib(Ihandle* ih, const char* value)
+{
+ float xalign;
+ GtkJustification justification;
+
+ if (iupStrEqualNoCase(value, "ARIGHT"))
+ {
+ xalign = 1.0f;
+ justification = GTK_JUSTIFY_RIGHT;
+ }
+ else if (iupStrEqualNoCase(value, "ACENTER"))
+ {
+ xalign = 0.5f;
+ justification = GTK_JUSTIFY_CENTER;
+ }
+ else /* "ALEFT" */
+ {
+ xalign = 0;
+ justification = GTK_JUSTIFY_LEFT;
+ }
+
+ if (ih->data->is_multiline)
+ gtk_text_view_set_justification(GTK_TEXT_VIEW(ih->handle), justification);
+ else
+ gtk_entry_set_alignment(GTK_ENTRY(ih->handle), xalign);
+
+ return 1;
+}
+
+static int gtkTextSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x');
+ if (ih->handle)
+ {
+ if (ih->data->is_multiline)
+ {
+ gtk_text_view_set_left_margin(GTK_TEXT_VIEW(ih->handle), ih->data->horiz_padding);
+ gtk_text_view_set_right_margin(GTK_TEXT_VIEW(ih->handle), ih->data->horiz_padding);
+ ih->data->vert_padding = 0;
+ }
+ else
+ {
+#if GTK_CHECK_VERSION(2, 10, 0)
+ GtkBorder border;
+ border.bottom = border.top = ih->data->vert_padding;
+ border.left = border.right = ih->data->horiz_padding;
+ gtk_entry_set_inner_border(GTK_ENTRY(ih->handle), &border);
+#endif
+ }
+ }
+ return 0;
+}
+
+static int gtkTextSetNCAttrib(Ihandle* ih, const char* value)
+{
+ if (!iupStrToInt(value, &ih->data->nc))
+ ih->data->nc = INT_MAX;
+
+ if (!ih->data->is_multiline && ih->handle)
+ gtk_entry_set_max_length(GTK_ENTRY(ih->handle), ih->data->nc);
+
+ return 0;
+}
+
+static int gtkTextSetClipboardAttrib(Ihandle *ih, const char *value)
+{
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ if (iupStrEqualNoCase(value, "COPY"))
+ {
+ if (ih->data->is_multiline)
+ {
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ GtkClipboard *clipboard = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE));
+ gtk_text_buffer_copy_clipboard(buffer, clipboard);
+ }
+ else
+ gtk_editable_copy_clipboard(GTK_EDITABLE(ih->handle));
+ }
+ else if (iupStrEqualNoCase(value, "CUT"))
+ {
+ if (ih->data->is_multiline)
+ {
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ GtkClipboard *clipboard = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE));
+ gtk_text_buffer_cut_clipboard(buffer, clipboard, TRUE);
+ }
+ else
+ gtk_editable_cut_clipboard(GTK_EDITABLE(ih->handle));
+ }
+ else if (iupStrEqualNoCase(value, "PASTE"))
+ {
+ if (ih->data->is_multiline)
+ {
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ GtkClipboard *clipboard = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE));
+ gtk_text_buffer_paste_clipboard(buffer, clipboard, NULL, TRUE);
+ }
+ else
+ gtk_editable_paste_clipboard(GTK_EDITABLE(ih->handle));
+ }
+ else if (iupStrEqualNoCase(value, "CLEAR"))
+ {
+ if (ih->data->is_multiline)
+ {
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_delete_selection(buffer, FALSE, TRUE);
+ }
+ else
+ gtk_editable_delete_selection(GTK_EDITABLE(ih->handle));
+ }
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ return 0;
+}
+
+static int gtkTextSetReadOnlyAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->is_multiline)
+ gtk_text_view_set_editable(GTK_TEXT_VIEW(ih->handle), !iupStrBoolean(value));
+ else
+ gtk_editable_set_editable(GTK_EDITABLE(ih->handle), !iupStrBoolean(value));
+ return 0;
+}
+
+static char* gtkTextGetReadOnlyAttrib(Ihandle* ih)
+{
+ int editable;
+ if (ih->data->is_multiline)
+ editable = gtk_text_view_get_editable(GTK_TEXT_VIEW(ih->handle));
+ else
+ editable = gtk_editable_get_editable(GTK_EDITABLE(ih->handle));
+ if (!editable)
+ return "YES";
+ else
+ return "NO";
+}
+
+static char* gtkTextGetPangoLayoutAttrib(Ihandle* ih)
+{
+ if (ih->data->is_multiline)
+ return NULL;
+ else
+ return (char*)gtk_entry_get_layout(GTK_ENTRY(ih->handle));
+}
+
+static int gtkTextSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->is_multiline)
+ {
+ GtkScrolledWindow* scrolled_window = (GtkScrolledWindow*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ unsigned char r, g, b;
+
+ /* ignore given value, must use only from parent for the scrollbars */
+ char* parent_value = iupBaseNativeParentGetBgColor(ih);
+
+ if (iupStrToRGB(parent_value, &r, &g, &b))
+ {
+ GtkWidget* sb;
+
+ iupgtkBaseSetBgColor((GtkWidget*)scrolled_window, r, g, b);
+
+#if GTK_CHECK_VERSION(2, 8, 0)
+ sb = gtk_scrolled_window_get_hscrollbar(scrolled_window);
+ if (sb) iupgtkBaseSetBgColor(sb, r, g, b);
+
+ sb = gtk_scrolled_window_get_vscrollbar(scrolled_window);
+ if (sb) iupgtkBaseSetBgColor(sb, r, g, b);
+#endif
+ }
+ }
+
+ return iupdrvBaseSetBgColorAttrib(ih, value);
+}
+
+static int gtkTextSetTabSizeAttrib(Ihandle* ih, const char* value)
+{
+ PangoTabArray *tabs;
+ int tabsize, charwidth;
+ if (!ih->data->is_multiline)
+ return 0;
+
+ iupStrToInt(value, &tabsize);
+ charwidth = gtkTextGetCharSize(ih);
+ tabsize *= charwidth;
+ tabs = pango_tab_array_new_with_positions(1, FALSE, PANGO_TAB_LEFT, tabsize);
+ gtk_text_view_set_tabs(GTK_TEXT_VIEW(ih->handle), tabs);
+ pango_tab_array_free(tabs);
+ return 1;
+}
+
+static int gtkTextSetOverwriteAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->is_multiline)
+ return 0;
+ gtk_text_view_set_overwrite(GTK_TEXT_VIEW(ih->handle), iupStrBoolean(value));
+ return 0;
+}
+
+static char* gtkTextGetOverwriteAttrib(Ihandle* ih)
+{
+ if (!ih->data->is_multiline)
+ return "NO";
+ if (gtk_text_view_get_overwrite(GTK_TEXT_VIEW(ih->handle)))
+ return "YES";
+ else
+ return "NO";
+}
+
+void iupdrvTextAddFormatTag(Ihandle* ih, Ihandle* formattag)
+{
+ GtkTextBuffer *buffer;
+ GtkTextIter start_iter, end_iter;
+ GtkTextTag* tag;
+ char *selection;
+
+ if (!ih->data->is_multiline)
+ return;
+
+ selection = iupAttribGet(formattag, "SELECTION");
+ if (selection)
+ {
+ /* simulate Windows behavior and change the current selection */
+ gtkTextSetSelectionAttrib(ih, selection);
+ iupAttribSetStr(ih, "SELECTION", NULL);
+ }
+ else
+ {
+ char* selectionpos = iupAttribGet(formattag, "SELECTIONPOS");
+ if (selectionpos)
+ {
+ /* simulate Windows behavior and change the current selection */
+ gtkTextSetSelectionPosAttrib(ih, selectionpos);
+ iupAttribSetStr(ih, "SELECTIONPOS", NULL);
+ }
+ }
+
+ buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ if (!gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter))
+ {
+ GtkTextMark* mark = gtk_text_buffer_get_insert(buffer);
+ gtk_text_buffer_get_iter_at_mark(buffer, &start_iter, mark);
+ gtk_text_buffer_get_iter_at_mark(buffer, &end_iter, mark);
+ }
+
+ tag = gtk_text_buffer_create_tag(buffer, NULL, NULL);
+ gtkTextParseParagraphFormat(formattag, tag);
+ gtkTextParseCharacterFormat(formattag, tag);
+ gtk_text_buffer_apply_tag(buffer, tag, &start_iter, &end_iter);
+
+ /* reset the selection */
+ gtkTextSetSelectionAttrib(ih, NULL);
+}
+
+static int gtkTextSetRemoveFormattingAttrib(Ihandle* ih, const char* value)
+{
+ GtkTextBuffer *buffer;
+ GtkTextIter start_iter, end_iter;
+
+ if (!ih->data->is_multiline)
+ return 0;
+
+ buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ if (gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter))
+ gtk_text_buffer_remove_all_tags(buffer, &start_iter, &end_iter);
+
+ (void)value;
+ return 0;
+}
+
+
+/************************************************************************************************/
+
+static gboolean gtkTextSpinOutput(GtkSpinButton *spin, Ihandle* ih)
+{
+ if (iupAttribGet(ih, "_IUPGTK_SPIN_NOAUTO"))
+ {
+ iupAttribSetInt(ih, "_IUPGTK_SPIN_VALUE", (int)spin->adjustment->value);
+ return TRUE; /* disable output update */
+ }
+ else
+ {
+ iupAttribSetStr(ih, "_IUPGTK_SPIN_OLDVALUE", gtk_entry_get_text(GTK_ENTRY(ih->handle)));
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ return FALSE;
+ }
+}
+
+static gint gtkTextSpinInput(GtkSpinButton *spin, gdouble *val, Ihandle* ih)
+{
+ (void)spin;
+ *val = (double)iupAttribGetInt(ih, "_IUPGTK_SPIN_VALUE");
+ /* called only when SPINAUTO=NO */
+ return TRUE; /* disable input update */
+}
+
+static void gtkTextSpinValueChanged(GtkSpinButton* spin, Ihandle* ih)
+{
+ IFni cb;
+
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+
+ cb = (IFni)IupGetCallback(ih, "SPIN_CB");
+ if (cb)
+ {
+ int pos, ret;
+ if (iupAttribGet(ih, "_IUPGTK_SPIN_NOAUTO"))
+ pos = iupAttribGetInt(ih, "_IUPGTK_SPIN_VALUE");
+ else
+ pos = gtk_spin_button_get_value_as_int((GtkSpinButton*)ih->handle);
+
+ ret = cb(ih, pos);
+ if (ret == IUP_IGNORE)
+ {
+ /* this is not working: g_signal_stop_emission_by_name(spin, "value_changed"); */
+ }
+ }
+
+ (void)spin;
+}
+
+static int gtkTextSetSpinMinAttrib(Ihandle* ih, const char* value)
+{
+ if (GTK_IS_SPIN_BUTTON(ih->handle))
+ {
+ int min;
+ if (iupStrToInt(value, &min))
+ {
+ int max = iupAttribGetInt(ih, "SPINMAX");
+
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih);
+
+ gtk_spin_button_set_range((GtkSpinButton*)ih->handle, (double)min, (double)max);
+
+ g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ }
+ }
+ return 1;
+}
+
+static int gtkTextSetSpinMaxAttrib(Ihandle* ih, const char* value)
+{
+ if (GTK_IS_SPIN_BUTTON(ih->handle))
+ {
+ int max;
+ if (iupStrToInt(value, &max))
+ {
+ int min = iupAttribGetInt(ih, "SPINMIN");
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih);
+
+ gtk_spin_button_set_range((GtkSpinButton*)ih->handle, (double)min, (double)max);
+
+ g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+ }
+ }
+ return 1;
+}
+
+static int gtkTextSetSpinIncAttrib(Ihandle* ih, const char* value)
+{
+ if (GTK_IS_SPIN_BUTTON(ih->handle))
+ {
+ int inc;
+ if (iupStrToInt(value, &inc))
+ gtk_spin_button_set_increments((GtkSpinButton*)ih->handle, (double)inc, (double)(inc*10));
+ }
+ return 1;
+}
+
+static int gtkTextSetSpinValueAttrib(Ihandle* ih, const char* value)
+{
+ if (GTK_IS_SPIN_BUTTON(ih->handle))
+ {
+ int pos;
+ if (iupStrToInt(value, &pos))
+ {
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih);
+
+ gtk_spin_button_set_value((GtkSpinButton*)ih->handle, (double)pos);
+
+ g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+
+ if (iupAttribGet(ih, "_IUPGTK_SPIN_NOAUTO"))
+ iupAttribSetInt(ih, "_IUPGTK_SPIN_VALUE", pos);
+ }
+ }
+ return 1;
+}
+
+static char* gtkTextGetSpinValueAttrib(Ihandle* ih)
+{
+ if (GTK_IS_SPIN_BUTTON(ih->handle))
+ {
+ int pos;
+ char *str = iupStrGetMemory(50);
+
+ if (iupAttribGet(ih, "_IUPGTK_SPIN_NOAUTO"))
+ pos = iupAttribGetInt(ih, "_IUPGTK_SPIN_VALUE");
+ else
+ pos = gtk_spin_button_get_value_as_int((GtkSpinButton*)ih->handle);
+
+ sprintf(str, "%d", pos);
+ return str;
+ }
+ return NULL;
+}
+
+
+/**********************************************************************************************************/
+
+
+static void gtkTextMoveCursor(GtkWidget *w, GtkMovementStep step, gint count, gboolean extend_selection, Ihandle* ih)
+{
+ int col, lin, pos;
+
+ IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB");
+ if (!cb) return;
+
+ if (ih->data->is_multiline)
+ {
+ GtkTextIter iter;
+
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ gtk_text_buffer_get_iter_at_mark(buffer, &iter, gtk_text_buffer_get_insert(buffer));
+ gtkTextGetLinColFromPosition(&iter, &lin, &col);
+ pos = gtk_text_iter_get_offset(&iter);
+ }
+ else
+ {
+ pos = gtk_editable_get_position(GTK_EDITABLE(ih->handle));
+ col = pos;
+ col++; /* IUP starts at 1 */
+ lin = 1;
+ }
+
+ if (pos != ih->data->last_caret_pos)
+ {
+ ih->data->last_caret_pos = pos;
+
+ cb(ih, lin, col, pos);
+ }
+
+ (void)w;
+ (void)step;
+ (void)count;
+ (void)extend_selection;
+}
+
+static gboolean gtkTextKeyReleaseEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
+{
+ gtkTextMoveCursor(NULL, 0, 0, 0, ih);
+ (void)widget;
+ (void)evt;
+ return FALSE;
+}
+
+static gboolean gtkTextButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih)
+{
+ gtkTextMoveCursor(NULL, 0, 0, 0, ih);
+ return iupgtkButtonEvent(widget, evt, ih);
+}
+
+static int gtkTextCallActionCb(Ihandle* ih, const char* insert_value, int len, int start, int end)
+{
+ char *new_value, *value;
+ int ret = -1, key = 0;
+
+ IFnis cb = (IFnis)IupGetCallback(ih, "ACTION");
+ if (!cb && !ih->data->mask)
+ return -1; /* continue */
+
+ value = gtkTextGetValueAttrib(ih); /* new_value is the internal buffer */
+
+ if (!insert_value)
+ {
+ new_value = iupStrDup(value);
+ if (end<0) end = strlen(value)+1;
+ iupStrRemove(new_value, start, end, 1);
+ }
+ else
+ {
+ if (value[0]==0)
+ new_value = iupStrDup(insert_value);
+ else
+ {
+ if (len < end-start)
+ {
+ new_value = iupStrDup(value);
+ new_value = iupStrInsert(new_value, insert_value, start, end);
+ }
+ else
+ new_value = iupStrInsert(value, insert_value, start, end);
+ }
+ }
+
+ if (insert_value && insert_value[0]!=0 && insert_value[1]==0)
+ key = insert_value[0];
+
+ if (!new_value)
+ return -1; /* continue */
+
+ if (ih->data->nc && (int)strlen(new_value) > ih->data->nc)
+ {
+ if (new_value != value) free(new_value);
+ return 0; /* abort */
+ }
+
+ if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0)
+ {
+ if (new_value != value) free(new_value);
+ return 0; /* abort */
+ }
+
+ if (cb)
+ {
+ int cb_ret = cb(ih, key, (char*)new_value);
+ if (cb_ret==IUP_IGNORE)
+ ret = 0; /* abort */
+ else if (cb_ret==IUP_CLOSE)
+ {
+ IupExitLoop();
+ ret = 0; /* abort */
+ }
+ else if (cb_ret!=0 && key!=0 &&
+ cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE)
+ ret = cb_ret; /* abort and replace */
+ }
+
+ if (new_value != value) free(new_value);
+ return ret; /* continue */
+}
+
+static void gtkTextEntryDeleteText(GtkEditable *editable, int start, int end, Ihandle* ih)
+{
+ if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB"))
+ return;
+
+ if (gtkTextCallActionCb(ih, NULL, 0, start, end)==0)
+ g_signal_stop_emission_by_name (editable, "delete_text");
+}
+
+static void gtkTextEntryInsertText(GtkEditable *editable, char *insert_value, int len, int *pos, Ihandle* ih)
+{
+ int ret;
+
+ if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB"))
+ return;
+
+ ret = gtkTextCallActionCb(ih, iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(insert_value)), len, *pos, *pos);
+ if (ret == 0)
+ g_signal_stop_emission_by_name(editable, "insert_text");
+ else if (ret != -1)
+ {
+ insert_value[0] = (char)ret; /* replace key */
+
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ gtk_editable_insert_text(editable, insert_value, 1, pos);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+
+ g_signal_stop_emission_by_name(editable, "insert_text");
+ }
+}
+
+static void gtkTextBufferDeleteRange(GtkTextBuffer *textbuffer, GtkTextIter *start_iter, GtkTextIter *end_iter, Ihandle* ih)
+{
+ int start, end;
+ if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB"))
+ return;
+
+ start = gtk_text_iter_get_offset(start_iter);
+ end = gtk_text_iter_get_offset(end_iter);
+
+ if (gtkTextCallActionCb(ih, NULL, 0, start, end)==0)
+ g_signal_stop_emission_by_name (textbuffer, "delete_range");
+}
+
+static void gtkTextBufferInsertText(GtkTextBuffer *textbuffer, GtkTextIter *pos_iter, gchar *insert_value, gint len, Ihandle* ih)
+{
+ int ret, pos;
+
+ if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB"))
+ return;
+
+ pos = gtk_text_iter_get_offset(pos_iter);
+
+ ret = gtkTextCallActionCb(ih, iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(insert_value)), len, pos, pos);
+ if (ret == 0)
+ g_signal_stop_emission_by_name(textbuffer, "insert_text");
+ else if (ret != -1)
+ {
+ insert_value[0] = (char)ret; /* replace key */
+
+ /* disable callbacks */
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1");
+ gtk_text_buffer_insert(textbuffer, pos_iter, insert_value, 1);
+ iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL);
+
+ g_signal_stop_emission_by_name(textbuffer, "insert_text");
+ }
+}
+
+static void gtkTextChanged(void* dummy, Ihandle* ih)
+{
+ if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB"))
+ return;
+
+ iupBaseCallValueChangedCb(ih);
+ (void)dummy;
+}
+
+/**********************************************************************************************************/
+
+
+static int gtkTextMapMethod(Ihandle* ih)
+{
+ GtkScrolledWindow* scrolled_window = NULL;
+
+ if (ih->data->is_multiline)
+ {
+ GtkPolicyType hscrollbar_policy, vscrollbar_policy;
+ int wordwrap = 0;
+
+ ih->handle = gtk_text_view_new();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ scrolled_window = (GtkScrolledWindow*)gtk_scrolled_window_new(NULL, NULL);
+ if (!scrolled_window)
+ return IUP_ERROR;
+
+ gtk_container_add((GtkContainer*)scrolled_window, ih->handle);
+ gtk_widget_show((GtkWidget*)scrolled_window);
+
+ iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)scrolled_window);
+
+ /* formatting is always supported when MULTILINE=YES */
+ ih->data->has_formatting = 1;
+
+ if (iupAttribGetBoolean(ih, "WORDWRAP"))
+ {
+ wordwrap = 1;
+ ih->data->sb &= ~IUP_SB_HORIZ; /* must remove the horizontal scroolbar */
+ }
+
+ if (iupAttribGetBoolean(ih, "BORDER"))
+ gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_IN);
+ else
+ gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_NONE);
+
+ if (ih->data->sb & IUP_SB_HORIZ)
+ {
+ if (iupAttribGetBoolean(ih, "AUTOHIDE"))
+ hscrollbar_policy = GTK_POLICY_AUTOMATIC;
+ else
+ hscrollbar_policy = GTK_POLICY_ALWAYS;
+ }
+ else
+ hscrollbar_policy = GTK_POLICY_NEVER;
+
+ if (ih->data->sb & IUP_SB_VERT)
+ {
+ if (iupAttribGetBoolean(ih, "AUTOHIDE"))
+ vscrollbar_policy = GTK_POLICY_AUTOMATIC;
+ else
+ vscrollbar_policy = GTK_POLICY_ALWAYS;
+ }
+ else
+ vscrollbar_policy = GTK_POLICY_NEVER;
+
+ gtk_scrolled_window_set_policy(scrolled_window, hscrollbar_policy, vscrollbar_policy);
+
+ if (wordwrap)
+ gtk_text_view_set_wrap_mode((GtkTextView*)ih->handle, GTK_WRAP_WORD);
+
+ gtk_widget_add_events(ih->handle, GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK);
+ }
+ else
+ {
+ if (iupAttribGetBoolean(ih, "SPIN"))
+ ih->handle = gtk_spin_button_new_with_range(0, 100, 1);
+ else
+ ih->handle = gtk_entry_new();
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ /* formatting is never supported when MULTILINE=NO */
+ ih->data->has_formatting = 0;
+
+ gtk_entry_set_has_frame((GtkEntry*)ih->handle, IupGetInt(ih, "BORDER"));
+
+ if (iupAttribGetBoolean(ih, "PASSWORD"))
+ gtk_entry_set_visibility((GtkEntry*)ih->handle, FALSE);
+
+ if (GTK_IS_SPIN_BUTTON(ih->handle))
+ {
+ gtk_spin_button_set_numeric((GtkSpinButton*)ih->handle, FALSE);
+ gtk_spin_button_set_digits((GtkSpinButton*)ih->handle, 0);
+
+ gtk_spin_button_set_wrap((GtkSpinButton*)ih->handle, iupAttribGetBoolean(ih, "SPINWRAP"));
+
+ g_signal_connect(G_OBJECT(ih->handle), "value-changed", G_CALLBACK(gtkTextSpinValueChanged), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "output", G_CALLBACK(gtkTextSpinOutput), ih);
+
+ if (!iupAttribGetBoolean(ih, "SPINAUTO"))
+ {
+ g_signal_connect(G_OBJECT(ih->handle), "input", G_CALLBACK(gtkTextSpinInput), ih);
+ iupAttribSetStr(ih, "_IUPGTK_SPIN_NOAUTO", "1");
+ }
+ }
+ }
+
+ /* add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ if (!iupAttribGetBoolean(ih, "CANFOCUS"))
+ GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS;
+
+ g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+
+ g_signal_connect_after(G_OBJECT(ih->handle), "move-cursor", G_CALLBACK(gtkTextMoveCursor), ih); /* only report some caret movements */
+ g_signal_connect_after(G_OBJECT(ih->handle), "key-release-event", G_CALLBACK(gtkTextKeyReleaseEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "button-press-event", G_CALLBACK(gtkTextButtonEvent), ih); /* if connected "after" then it is ignored */
+ g_signal_connect(G_OBJECT(ih->handle), "button-release-event",G_CALLBACK(gtkTextButtonEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "motion-notify-event",G_CALLBACK(iupgtkMotionNotifyEvent), ih);
+
+ if (ih->data->is_multiline)
+ {
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle));
+ g_signal_connect(G_OBJECT(buffer), "delete-range", G_CALLBACK(gtkTextBufferDeleteRange), ih);
+ g_signal_connect(G_OBJECT(buffer), "insert-text", G_CALLBACK(gtkTextBufferInsertText), ih);
+ g_signal_connect(G_OBJECT(buffer), "changed", G_CALLBACK(gtkTextChanged), ih);
+ }
+ else
+ {
+ g_signal_connect(G_OBJECT(ih->handle), "delete-text", G_CALLBACK(gtkTextEntryDeleteText), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "insert-text", G_CALLBACK(gtkTextEntryInsertText), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "changed", G_CALLBACK(gtkTextChanged), ih);
+ }
+
+ if (scrolled_window)
+ gtk_widget_realize((GtkWidget*)scrolled_window);
+ gtk_widget_realize(ih->handle);
+
+ /* configure for DRAG&DROP */
+ if (IupGetCallback(ih, "DROPFILES_CB"))
+ iupAttribSetStr(ih, "DRAGDROP", "YES");
+
+ /* update a mnemonic in a label if necessary */
+ iupgtkUpdateMnemonic(ih);
+
+ if (ih->data->formattags)
+ iupTextUpdateFormatTags(ih);
+
+ IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)gtkTextConvertXYToPos);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvTextInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkTextMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Common GTK only (when text is in a secondary element) */
+ iupClassRegisterAttribute(ic, "PANGOLAYOUT", gtkTextGetPangoLayoutAttrib, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkTextSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iupdrvBaseSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT);
+
+ /* IupText only */
+ iupClassRegisterAttribute(ic, "PADDING", iupTextGetPaddingAttrib, gtkTextSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "VALUE", gtkTextGetValueAttrib, gtkTextSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTEDTEXT", gtkTextGetSelectedTextAttrib, gtkTextSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTION", gtkTextGetSelectionAttrib, gtkTextSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTIONPOS", gtkTextGetSelectionPosAttrib, gtkTextSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CARET", gtkTextGetCaretAttrib, gtkTextSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CARETPOS", gtkTextGetCaretPosAttrib, gtkTextSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "INSERT", NULL, gtkTextSetInsertAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "APPEND", NULL, gtkTextSetAppendAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "READONLY", gtkTextGetReadOnlyAttrib, gtkTextSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "NC", iupTextGetNCAttrib, gtkTextSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, gtkTextSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SCROLLTO", NULL, gtkTextSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, gtkTextSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPINMIN", NULL, gtkTextSetSpinMinAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPINMAX", NULL, gtkTextSetSpinMaxAttrib, IUPAF_SAMEASSYSTEM, "100", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPININC", NULL, gtkTextSetSpinIncAttrib, IUPAF_SAMEASSYSTEM, "1", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPINVALUE", gtkTextGetSpinValueAttrib, gtkTextSetSpinValueAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT);
+
+ /* IupText Windows and GTK only */
+ iupClassRegisterAttribute(ic, "ADDFORMATTAG", NULL, iupTextSetAddFormatTagAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ADDFORMATTAG_HANDLE", NULL, iupTextSetAddFormatTagHandleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, gtkTextSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "ALEFT", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupgtkSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FORMATTING", iupTextGetFormattingAttrib, iupTextSetFormattingAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "OVERWRITE", gtkTextGetOverwriteAttrib, gtkTextSetOverwriteAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "REMOVEFORMATTING", NULL, gtkTextSetRemoveFormattingAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TABSIZE", NULL, gtkTextSetTabSizeAttrib, "8", NULL, IUPAF_DEFAULT); /* force new default value */
+ iupClassRegisterAttribute(ic, "PASSWORD", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/gtk/iupgtk_timer.c b/iup/src/gtk/iupgtk_timer.c
new file mode 100755
index 0000000..ecbefa3
--- /dev/null
+++ b/iup/src/gtk/iupgtk_timer.c
@@ -0,0 +1,61 @@
+/** \file
+ * \brief Timer for the GTK Driver.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <gtk/gtk.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_assert.h"
+#include "iup_timer.h"
+
+
+static gboolean gtkTimerProc(gpointer data)
+{
+ Ihandle *ih = (Ihandle*)data;
+ Icallback cb;
+
+ if (!iupObjectCheck(ih)) /* control could be destroyed before timer callback */
+ return FALSE;
+
+ cb = IupGetCallback(ih, "ACTION_CB");
+ if (cb && cb(ih)==IUP_CLOSE)
+ IupExitLoop();
+
+ return TRUE;
+}
+
+void iupdrvTimerRun(Ihandle *ih)
+{
+ unsigned int time_ms;
+
+ if (ih->serial > 0) /* timer already started */
+ return;
+
+ time_ms = iupAttribGetInt(ih, "TIME");
+ if (time_ms > 0)
+ ih->serial = g_timeout_add(time_ms, gtkTimerProc, (gpointer)ih);
+}
+
+void iupdrvTimerStop(Ihandle* ih)
+{
+ if (ih->serial > 0)
+ {
+ g_source_remove(ih->serial);
+ ih->serial = -1;
+ }
+}
+
+void iupdrvTimerInitClass(Iclass* ic)
+{
+ (void)ic;
+}
diff --git a/iup/src/gtk/iupgtk_tips.c b/iup/src/gtk/iupgtk_tips.c
new file mode 100755
index 0000000..6289d70
--- /dev/null
+++ b/iup/src/gtk/iupgtk_tips.c
@@ -0,0 +1,100 @@
+/** \file
+ * \brief Windows Driver TIPS management
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+
+#include <gtk/gtk.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_str.h"
+#include "iup_attrib.h"
+#include "iup_image.h"
+
+#include "iupgtk_drv.h"
+
+#if GTK_CHECK_VERSION(2, 12, 0)
+#else
+static GtkTooltips* gtk_tips = NULL; /* old TIPS */
+#endif
+
+#if GTK_CHECK_VERSION(2, 12, 0)
+static gboolean gtkQueryTooltip(GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, Ihandle* ih)
+{
+ char* value = iupAttribGet(ih, "TIPRECT");
+ if (value && !keyboard_mode)
+ {
+ GdkRectangle rect;
+ int x1, x2, y1, y2;
+ sscanf(value, "%d %d %d %d", &x1, &y1, &x2, &y2);
+ rect.x = x1;
+ rect.y = y1;
+ rect.width = x2-x1+1;
+ rect.height = y2-y1+1;
+ gtk_tooltip_set_tip_area(tooltip, &rect);
+ }
+ else
+ gtk_tooltip_set_tip_area(tooltip, NULL);
+
+ value = iupAttribGet(ih, "TIPICON");
+ if (!value)
+ gtk_tooltip_set_icon(tooltip, NULL);
+ else
+ {
+ GdkPixbuf* icon = (GdkPixbuf*)iupImageGetIcon(value);
+ if (icon)
+ gtk_tooltip_set_icon(tooltip, icon);
+ }
+
+ (void)y;
+ (void)x;
+ (void)widget;
+ return FALSE;
+}
+#endif
+
+int iupdrvBaseSetTipAttrib(Ihandle* ih, const char* value)
+{
+ GtkWidget* widget = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (!widget)
+ widget = ih->handle;
+
+#if GTK_CHECK_VERSION(2, 12, 0)
+ if (iupAttribGetBoolean(ih, "TIPMARKUP"))
+ gtk_widget_set_tooltip_markup(widget, iupgtkStrConvertToUTF8(value));
+ else
+ gtk_widget_set_tooltip_text(widget, iupgtkStrConvertToUTF8(value));
+
+ g_signal_connect(widget, "query-tooltip", G_CALLBACK(gtkQueryTooltip), ih);
+#else
+ if (gtk_tips == NULL)
+ gtk_tips = gtk_tooltips_new();
+
+ gtk_tooltips_set_tip(gtk_tips, widget, iupgtkStrConvertToUTF8(value), NULL);
+#endif
+
+ return 1;
+}
+
+int iupdrvBaseSetTipVisibleAttrib(Ihandle* ih, const char* value)
+{
+ GtkWidget* widget = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (!widget)
+ widget = ih->handle;
+ (void)value;
+
+ /* must use IupGetAttribute to use inheritance */
+ if (!IupGetAttribute(ih, "TIP"))
+ return 0;
+
+#if GTK_CHECK_VERSION(2, 12, 0)
+ gtk_widget_trigger_tooltip_query(widget);
+#endif
+
+ return 0;
+}
+
diff --git a/iup/src/gtk/iupgtk_toggle.c b/iup/src/gtk/iupgtk_toggle.c
new file mode 100755
index 0000000..8ff7df5
--- /dev/null
+++ b/iup/src/gtk/iupgtk_toggle.c
@@ -0,0 +1,519 @@
+/** \file
+ * \brief Toggle Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_image.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_image.h"
+#include "iup_key.h"
+#include "iup_toggle.h"
+
+#include "iupgtk_drv.h"
+
+
+#if !GTK_CHECK_VERSION(2, 6, 0)
+static void gtk_button_set_image(GtkButton *button, GtkWidget *image)
+{
+}
+static GtkWidget* gtk_button_get_image(GtkButton *button)
+{
+ return NULL;
+}
+#endif
+
+void iupdrvToggleAddCheckBox(int *x, int *y)
+{
+#ifdef HILDON
+ (*x) += 30+4;
+ if ((*y) < 30) (*y) = 30; /* minimum height */
+#else
+ (*x) += 16+4;
+ if ((*y) < 16) (*y) = 16; /* minimum height */
+#endif
+ (*y) += 4;
+}
+
+static int gtkToggleGetCheck(Ihandle* ih)
+{
+ if (gtk_toggle_button_get_inconsistent((GtkToggleButton*)ih->handle))
+ return -1;
+ if (gtk_toggle_button_get_active((GtkToggleButton*)ih->handle))
+ return 1;
+ else
+ return 0;
+}
+
+static void gtkToggleSetPixbuf(Ihandle* ih, const char* name, int make_inactive)
+{
+ GtkButton* button = (GtkButton*)ih->handle;
+ GtkImage* image = (GtkImage*)gtk_button_get_image(button);
+
+ if (name)
+ {
+ GdkPixbuf* pixbuf = iupImageGetImage(name, ih, make_inactive);
+ GdkPixbuf* old_pixbuf = gtk_image_get_pixbuf(image);
+ if (pixbuf != old_pixbuf)
+ gtk_image_set_from_pixbuf(image, pixbuf);
+ return;
+ }
+
+ /* if not defined */
+#if GTK_CHECK_VERSION(2, 8, 0)
+ gtk_image_clear(image);
+#endif
+}
+
+static void gtkToggleUpdateImage(Ihandle* ih, int active, int check)
+{
+ char* name;
+
+ if (!active)
+ {
+ name = iupAttribGet(ih, "IMINACTIVE");
+ if (name)
+ gtkToggleSetPixbuf(ih, name, 0);
+ else
+ {
+ /* if not defined then automaticaly create one based on IMAGE */
+ name = iupAttribGet(ih, "IMAGE");
+ gtkToggleSetPixbuf(ih, name, 1); /* make_inactive */
+ }
+ }
+ else
+ {
+ /* must restore the normal image */
+ if (check)
+ {
+ name = iupAttribGet(ih, "IMPRESS");
+ if (name)
+ gtkToggleSetPixbuf(ih, name, 0);
+ else
+ {
+ /* if not defined then automaticaly create one based on IMAGE */
+ name = iupAttribGet(ih, "IMAGE");
+ gtkToggleSetPixbuf(ih, name, 0);
+ }
+ }
+ else
+ {
+ name = iupAttribGet(ih, "IMAGE");
+ if (name)
+ gtkToggleSetPixbuf(ih, name, 0);
+ }
+ }
+}
+
+
+/*************************************************************************/
+
+
+static int gtkToggleSetValueAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrEqualNoCase(value,"NOTDEF"))
+ gtk_toggle_button_set_inconsistent((GtkToggleButton*)ih->handle, TRUE);
+ else
+ {
+ gtk_toggle_button_set_inconsistent((GtkToggleButton*)ih->handle, FALSE);
+
+ /* This action causes the toggled signal to be emitted. */
+ iupAttribSetStr(ih, "_IUPGTK_IGNORE_TOGGLE", "1");
+
+ if (iupStrBoolean(value))
+ gtk_toggle_button_set_active((GtkToggleButton*)ih->handle, TRUE);
+ else
+ gtk_toggle_button_set_active((GtkToggleButton*)ih->handle, FALSE);
+
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ gtkToggleUpdateImage(ih, iupdrvIsActive(ih), gtkToggleGetCheck(ih));
+
+ iupAttribSetStr(ih, "_IUPGTK_IGNORE_TOGGLE", NULL);
+ }
+
+ return 0;
+}
+
+static char* gtkToggleGetValueAttrib(Ihandle* ih)
+{
+ int check = gtkToggleGetCheck(ih);
+ if (check == -1)
+ return "NOTDEF";
+ else if (check == 1)
+ return "ON";
+ else
+ return "OFF";
+}
+
+static int gtkToggleSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_TEXT)
+ {
+ GtkButton* button = (GtkButton*)ih->handle;
+ GtkLabel* label = (GtkLabel*)gtk_button_get_image(button);
+ iupgtkSetMnemonicTitle(ih, label, value);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int gtkToggleSetAlignmentAttrib(Ihandle* ih, const char* value)
+{
+ GtkButton* button = (GtkButton*)ih->handle;
+ float xalign, yalign;
+ char value1[30]="", value2[30]="";
+
+ if (ih->data->type == IUP_TOGGLE_TEXT)
+ return 0;
+
+ iupStrToStrStr(value, value1, value2, ':');
+
+ if (iupStrEqualNoCase(value1, "ARIGHT"))
+ xalign = 1.0f;
+ else if (iupStrEqualNoCase(value1, "ACENTER"))
+ xalign = 0.5f;
+ else /* "ALEFT" */
+ xalign = 0;
+
+ if (iupStrEqualNoCase(value2, "ABOTTOM"))
+ yalign = 1.0f;
+ else if (iupStrEqualNoCase(value2, "ATOP"))
+ yalign = 0;
+ else /* ACENTER (default) */
+ yalign = 0.5f;
+
+ gtk_button_set_alignment(button, xalign, yalign);
+
+ return 1;
+}
+
+static int gtkToggleSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x');
+ if (ih->handle && ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ GtkButton* button = (GtkButton*)ih->handle;
+ GtkMisc* misc = (GtkMisc*)gtk_button_get_image(button);
+ gtk_misc_set_padding(misc, ih->data->horiz_padding, ih->data->vert_padding);
+ }
+ return 0;
+}
+
+static int gtkToggleSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ GtkWidget* label = (GtkWidget*)gtk_button_get_image((GtkButton*)ih->handle);
+ if (!label) return 0;
+
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgtkBaseSetFgColor(label, r, g, b);
+
+ return 1;
+}
+
+static int gtkToggleSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ iupdrvSetStandardFontAttrib(ih, value);
+
+ if (ih->handle)
+ {
+ GtkWidget* label = gtk_button_get_image((GtkButton*)ih->handle);
+ if (!label) return 1;
+
+ gtk_widget_modify_font(label, (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih));
+
+ if (ih->data->type == IUP_TOGGLE_TEXT)
+ iupgtkFontUpdatePangoLayout(ih, gtk_label_get_layout((GtkLabel*)label));
+ }
+ return 1;
+}
+
+static int gtkToggleSetImageAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ if (value != iupAttribGet(ih, "IMAGE"))
+ iupAttribSetStr(ih, "IMAGE", (char*)value);
+ gtkToggleUpdateImage(ih, iupdrvIsActive(ih), gtkToggleGetCheck(ih));
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkToggleSetImInactiveAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ if (value != iupAttribGet(ih, "IMINACTIVE"))
+ iupAttribSetStr(ih, "IMINACTIVE", (char*)value);
+ gtkToggleUpdateImage(ih, iupdrvIsActive(ih), gtkToggleGetCheck(ih));
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkToggleSetImPressAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ if (value != iupAttribGet(ih, "IMPRESS"))
+ iupAttribSetStr(ih, "IMPRESS", (char*)value);
+ gtkToggleUpdateImage(ih, iupdrvIsActive(ih), gtkToggleGetCheck(ih));
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int gtkToggleSetActiveAttrib(Ihandle* ih, const char* value)
+{
+ /* update the inactive image if necessary */
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ gtkToggleUpdateImage(ih, iupStrBoolean(value), gtkToggleGetCheck(ih));
+
+ return iupBaseSetActiveAttrib(ih, value);
+}
+
+/****************************************************************************************************/
+
+static void gtkToggleToggled(GtkToggleButton *widget, Ihandle* ih)
+{
+ IFni cb;
+ int check;
+
+ if (iupAttribGet(ih, "_IUPGTK_IGNORE_TOGGLE"))
+ return;
+
+ check = gtkToggleGetCheck(ih);
+
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ gtkToggleUpdateImage(ih, iupdrvIsActive(ih), check);
+
+ cb = (IFni)IupGetCallback(ih, "ACTION");
+ if (cb && cb(ih, check) == IUP_CLOSE)
+ IupExitLoop();
+
+ iupBaseCallValueChangedCb(ih);
+
+ (void)widget;
+}
+
+static int gtkToggleUpdate3StateCheck(Ihandle *ih, int keyb)
+{
+ int check = gtkToggleGetCheck(ih);
+ if (check == 1) /* GOTO check == -1 */
+ {
+ gtk_toggle_button_set_inconsistent((GtkToggleButton*)ih->handle, TRUE);
+ gtkToggleToggled((GtkToggleButton*)ih->handle, ih);
+ return TRUE; /* ignore message to avoid change toggle state */
+ }
+ else if (check == -1) /* GOTO check == 0 */
+ {
+ gtk_toggle_button_set_inconsistent((GtkToggleButton*)ih->handle, FALSE);
+ if (keyb)
+ {
+ gtk_toggle_button_set_active((GtkToggleButton*)ih->handle, FALSE);
+ return TRUE; /* ignore message to avoid change toggle state */
+ }
+ }
+ else /* (check == 0) GOTO check == 1 */
+ {
+ gtk_toggle_button_set_inconsistent((GtkToggleButton*)ih->handle, FALSE);
+ if (keyb)
+ {
+ gtk_toggle_button_set_active((GtkToggleButton*)ih->handle, TRUE);
+ return TRUE; /* ignore message to avoid change toggle state */
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean gtkToggleButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih)
+{
+ if (iupAttribGet(ih, "_IUPGTK_IGNORE_TOGGLE"))
+ return FALSE;
+
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ char* name = iupAttribGet(ih, "IMPRESS");
+ if (name)
+ {
+ if (evt->type == GDK_BUTTON_PRESS)
+ gtkToggleUpdateImage(ih, iupdrvIsActive(ih), 1);
+ else
+ gtkToggleUpdateImage(ih, iupdrvIsActive(ih), 0);
+ }
+ }
+ else
+ {
+ if (evt->type == GDK_BUTTON_RELEASE)
+ {
+ if (gtkToggleUpdate3StateCheck(ih, 0))
+ return TRUE; /* ignore message to avoid change toggle state */
+ }
+ }
+
+ (void)widget;
+ return FALSE;
+}
+
+static gboolean gtkToggleKeyEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
+{
+ if (evt->type == GDK_KEY_PRESS)
+ {
+ if (evt->keyval == GDK_space || evt->keyval == GDK_Return)
+ return TRUE; /* ignore message to avoid change toggle state */
+ }
+ else
+ {
+ if (evt->keyval == GDK_space || evt->keyval == GDK_Return)
+ {
+ if (gtkToggleUpdate3StateCheck(ih, 1))
+ return TRUE; /* ignore message to avoid change toggle state */
+ }
+ }
+
+ (void)widget;
+ return FALSE;
+}
+
+static int gtkToggleMapMethod(Ihandle* ih)
+{
+ Ihandle* radio = iupRadioFindToggleParent(ih);
+ char *value;
+ int is3state = 0;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ if (radio)
+ ih->data->radio = 1;
+
+ value = iupAttribGet(ih, "IMAGE");
+ if (value)
+ ih->data->type = IUP_TOGGLE_IMAGE;
+ else
+ ih->data->type = IUP_TOGGLE_TEXT;
+
+ if (radio)
+ {
+ GtkRadioButton* last_tg = (GtkRadioButton*)iupAttribGet(radio, "_IUPGTK_LASTRADIOBUTTON");
+ if (last_tg)
+ ih->handle = gtk_radio_button_new_from_widget(last_tg);
+ else
+ ih->handle = gtk_radio_button_new(NULL);
+ iupAttribSetStr(radio, "_IUPGTK_LASTRADIOBUTTON", (char*)ih->handle);
+ }
+ else
+ {
+ if (ih->data->type == IUP_TOGGLE_TEXT)
+ {
+ ih->handle = gtk_check_button_new();
+
+ if (iupAttribGetBoolean(ih, "3STATE"))
+ is3state = 1;
+ }
+ else
+ ih->handle = gtk_toggle_button_new();
+ }
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ if (ih->data->type == IUP_TOGGLE_TEXT)
+ {
+ gtk_button_set_image((GtkButton*)ih->handle, gtk_label_new(NULL));
+ gtk_toggle_button_set_mode((GtkToggleButton*)ih->handle, TRUE);
+ }
+ else
+ {
+ gtk_button_set_image((GtkButton*)ih->handle, gtk_image_new());
+ gtk_toggle_button_set_mode((GtkToggleButton*)ih->handle, FALSE);
+ }
+
+ /* add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ if (!iupAttribGetBoolean(ih, "CANFOCUS"))
+ GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS;
+
+ g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "toggled", G_CALLBACK(gtkToggleToggled), ih);
+
+ if (ih->data->type == IUP_TOGGLE_IMAGE || is3state)
+ {
+ g_signal_connect(G_OBJECT(ih->handle), "button-press-event", G_CALLBACK(gtkToggleButtonEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "button-release-event",G_CALLBACK(gtkToggleButtonEvent), ih);
+ }
+
+ if (is3state)
+ {
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(gtkToggleKeyEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-release-event", G_CALLBACK(gtkToggleKeyEvent), ih);
+ }
+
+ gtk_widget_realize(ih->handle);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvToggleInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkToggleMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Overwrite Common */
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, gtkToggleSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED);
+
+ /* Overwrite Visual */
+ iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, gtkToggleSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, gtkToggleSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT); /* black */
+ iupClassRegisterAttribute(ic, "TITLE", NULL, gtkToggleSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupToggle only */
+ iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, gtkToggleSetAlignmentAttrib, "ACENTER:ACENTER", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, gtkToggleSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, gtkToggleSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMPRESS", NULL, gtkToggleSetImPressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "VALUE", gtkToggleGetValueAttrib, gtkToggleSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "PADDING", iupToggleGetPaddingAttrib, gtkToggleSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "MARKUP", NULL, NULL, NULL, NULL, IUPAF_DEFAULT);
+}
diff --git a/iup/src/gtk/iupgtk_tree.c b/iup/src/gtk/iupgtk_tree.c
new file mode 100755
index 0000000..d408f27
--- /dev/null
+++ b/iup/src/gtk/iupgtk_tree.c
@@ -0,0 +1,2369 @@
+/** \file
+ * \brief Tree Control
+ *
+ * See Copyright Notice in iup.h
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_stdcontrols.h"
+#include "iup_key.h"
+#include "iup_image.h"
+#include "iup_array.h"
+#include "iup_tree.h"
+
+#include "iup_drvinfo.h"
+#include "iupgtk_drv.h"
+
+enum
+{
+ IUPGTK_TREE_IMAGE,
+ IUPGTK_TREE_HAS_IMAGE,
+ IUPGTK_TREE_IMAGE_EXPANDED,
+ IUPGTK_TREE_HAS_IMAGE_EXPANDED,
+ IUPGTK_TREE_TITLE,
+ IUPGTK_TREE_KIND,
+ IUPGTK_TREE_COLOR,
+ IUPGTK_TREE_FONT,
+ IUPGTK_TREE_USERDATA
+};
+
+static GtkTreeIter gtkTreeInvalidIter = {0,0,0,0};
+
+/*****************************************************************************/
+/* COPYING ITEMS (Branches and its children) */
+/*****************************************************************************/
+/* Insert the copied item in a new location. Returns the new item. */
+static void gtkTreeCopyItem(GtkTreeModel* model, GtkTreeIter* iterItem, GtkTreeIter* iterParent, int position, GtkTreeIter *iterNewItem, int full_copy)
+{
+ GtkTreeStore* store = GTK_TREE_STORE(model);
+ int kind;
+ char* title;
+ gboolean has_image, has_image_expanded;
+ PangoFontDescription* font;
+ void* userdata;
+ GdkColor *color;
+ GdkPixbuf* image, *image_expanded;
+
+ gtk_tree_model_get(GTK_TREE_MODEL(store), iterItem, IUPGTK_TREE_IMAGE, &image,
+ IUPGTK_TREE_HAS_IMAGE, &has_image,
+ IUPGTK_TREE_IMAGE_EXPANDED, &image_expanded,
+ IUPGTK_TREE_HAS_IMAGE_EXPANDED, &has_image_expanded,
+ IUPGTK_TREE_TITLE, &title,
+ IUPGTK_TREE_KIND, &kind,
+ IUPGTK_TREE_COLOR, &color,
+ IUPGTK_TREE_FONT, &font,
+ IUPGTK_TREE_USERDATA, &userdata,
+ -1);
+
+ if (position == 2)
+ gtk_tree_store_append(store, iterNewItem, iterParent);
+ else if (position == 1) /* copy as first child of expanded branch */
+ gtk_tree_store_insert(store, iterNewItem, iterParent, 0); /* iterParent is parent of the new item (firstchild of it) */
+ else /* copy as next brother of item or collapsed branch */
+ gtk_tree_store_insert_after(store, iterNewItem, NULL, iterParent); /* iterParent is sibling of the new item */
+
+ if (full_copy) /* during a full copy the userdata reference is not copied */
+ userdata = NULL;
+
+ gtk_tree_store_set(store, iterNewItem, IUPGTK_TREE_IMAGE, image,
+ IUPGTK_TREE_HAS_IMAGE, has_image,
+ IUPGTK_TREE_IMAGE_EXPANDED, image_expanded,
+ IUPGTK_TREE_HAS_IMAGE_EXPANDED, has_image_expanded,
+ IUPGTK_TREE_TITLE, title,
+ IUPGTK_TREE_KIND, kind,
+ IUPGTK_TREE_COLOR, color,
+ IUPGTK_TREE_FONT, font,
+ IUPGTK_TREE_USERDATA, userdata,
+ -1);
+}
+
+static void gtkTreeCopyChildren(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItemSrc, GtkTreeIter *iterItemDst, int full_copy)
+{
+ GtkTreeIter iterChildSrc;
+ int hasItem = gtk_tree_model_iter_children(model, &iterChildSrc, iterItemSrc); /* get the firstchild */
+ while(hasItem)
+ {
+ GtkTreeIter iterNewItem;
+ gtkTreeCopyItem(model, &iterChildSrc, iterItemDst, 2, &iterNewItem, full_copy); /* append always */
+
+ /* Recursively transfer all the items */
+ gtkTreeCopyChildren(ih, model, &iterChildSrc, &iterNewItem, full_copy);
+
+ /* Go to next sibling item */
+ hasItem = gtk_tree_model_iter_next(model, &iterChildSrc);
+ }
+}
+
+/* Copies all items in a branch to a new location. Returns the new branch node. */
+static void gtkTreeCopyNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItemSrc, GtkTreeIter *iterItemDst, GtkTreeIter* iterNewItem, int full_copy)
+{
+ int kind, position = 0; /* insert after iterItemDst */
+ gtk_tree_model_get(model, iterItemDst, IUPGTK_TREE_KIND, &kind, -1);
+
+ if (kind == ITREE_BRANCH)
+ {
+ GtkTreePath* path = gtk_tree_model_get_path(model, iterItemDst);
+ if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path))
+ position = 1; /* insert as first child of iterItemDst */
+ gtk_tree_path_free(path);
+ }
+
+ gtkTreeCopyItem(model, iterItemSrc, iterItemDst, position, iterNewItem, full_copy);
+
+ gtkTreeCopyChildren(ih, model, iterItemSrc, iterNewItem, full_copy);
+}
+
+/*****************************************************************************/
+/* FINDING ITEMS */
+/*****************************************************************************/
+
+static void gtkTreeInvertAllNodeMarking(Ihandle* ih, GtkTreeModel* model, GtkTreeSelection* selection, GtkTreeIter* iterItem)
+{
+ GtkTreeIter iterChild;
+ int hasItem = TRUE;
+
+ while(hasItem)
+ {
+ if(gtk_tree_selection_iter_is_selected(selection, iterItem))
+ gtk_tree_selection_unselect_iter(selection, iterItem);
+ else
+ gtk_tree_selection_select_iter(selection, iterItem);
+
+ /* Check whether we have child items */
+ if(gtk_tree_model_iter_has_child(model, iterItem))
+ {
+ gtk_tree_model_iter_children(model, &iterChild, iterItem); /* get the firstchild */
+ gtkTreeInvertAllNodeMarking(ih, model, selection, &iterChild);
+ }
+
+ /* Go to next sibling item */
+ hasItem = gtk_tree_model_iter_next(model, iterItem);
+ }
+}
+
+static GtkTreeIter gtkTreeFindVisibleNodeId(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, GtkTreeIter iterNode)
+{
+ GtkTreeIter iterChild;
+ GtkTreePath* path;
+ int hasItem = TRUE;
+
+ while(hasItem)
+ {
+ /* ID control to traverse items */
+ ih->data->id_control++; /* not the real id since it counts only the visible ones */
+
+ /* StateID founded! */
+ if(iterItem.user_data == iterNode.user_data)
+ return iterItem;
+
+ path = gtk_tree_model_get_path(model, &iterItem);
+
+ /* Check whether we have child items and it is expanded (visible) */
+ if (gtk_tree_model_iter_has_child(model, &iterItem) && gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path))
+ {
+ gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */
+ iterChild = gtkTreeFindVisibleNodeId(ih, model, iterChild, iterNode);
+
+ /* StateID founded! */
+ if(iterChild.user_data)
+ {
+ gtk_tree_path_free(path);
+ return iterChild;
+ }
+ }
+
+ gtk_tree_path_free(path);
+ /* Go to next sibling item */
+ hasItem = gtk_tree_model_iter_next(model, &iterItem);
+ }
+
+ return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */
+}
+
+static GtkTreeIter gtkTreeFindVisibleNodeFromId(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem)
+{
+ GtkTreeIter iterChild;
+ GtkTreePath* path;
+ int hasItem = TRUE;
+
+ while(hasItem)
+ {
+ /* ID control to traverse items */
+ ih->data->id_control--; /* not the real id since it counts only the visible ones */
+
+ /* StateID founded! */
+ if(ih->data->id_control < 0)
+ return iterItem;
+
+ path = gtk_tree_model_get_path(model, &iterItem);
+
+ /* Check whether we have child items and it is expanded (visible) */
+ if(gtk_tree_model_iter_has_child(model, &iterItem) && gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path))
+ {
+ gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */
+ iterChild = gtkTreeFindVisibleNodeFromId(ih, model, iterChild);
+
+ /* StateID founded! */
+ if(ih->data->id_control < 0)
+ {
+ gtk_tree_path_free(path);
+ return iterChild;
+ }
+ }
+
+ gtk_tree_path_free(path);
+ /* Go to next sibling item */
+ hasItem = gtk_tree_model_iter_next(model, &iterItem);
+ }
+
+ return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */
+}
+
+static GtkTreeIter gtkTreeGetLastVisibleNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem)
+{
+ GtkTreeIter iterChild, iterPrev = gtkTreeInvalidIter;
+ GtkTreePath* path = gtk_tree_model_get_path(model, &iterItem);
+
+ /* Check whether we have child items and it is expanded (visible) */
+ if(gtk_tree_model_iter_has_child(model, &iterItem) && gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path))
+ {
+ int hasItem = TRUE;
+ gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */
+
+ while(hasItem)
+ {
+ iterPrev = iterChild;
+
+ /* Go to next sibling item */
+ hasItem = gtk_tree_model_iter_next(model, &iterChild);
+ }
+
+ iterItem = gtkTreeGetLastVisibleNode(ih, model, iterPrev);
+ }
+ gtk_tree_path_free(path);
+
+ return iterItem;
+}
+
+static GtkTreeIter gtkTreeFindNodeID(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, GtkTreeIter iterNode)
+{
+ GtkTreeIter iterChild;
+ int hasItem = TRUE;
+
+ while(hasItem)
+ {
+ /* ID control to traverse items */
+ ih->data->id_control++;
+
+ /* StateID founded! */
+ if (iterItem.user_data == iterNode.user_data)
+ return iterItem;
+
+ /* Check whether we have child items */
+ if (gtk_tree_model_iter_has_child(model, &iterItem))
+ {
+ gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */
+ iterChild = gtkTreeFindNodeID(ih, model, iterChild, iterNode);
+
+ /* StateID founded! */
+ if(iterChild.user_data)
+ return iterChild;
+ }
+
+ /* Go to next sibling item */
+ hasItem = gtk_tree_model_iter_next(model, &iterItem);
+ }
+
+ return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */
+}
+
+static int gtkTreeGetNodeId(Ihandle* ih, GtkTreeIter iterItem)
+{
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterRoot;
+ gtk_tree_model_get_iter_first(model, &iterRoot);
+
+ ih->data->id_control = -1;
+ iterItem = gtkTreeFindNodeID(ih, model, iterRoot, iterItem);
+ if (iterItem.user_data)
+ return ih->data->id_control;
+ else
+ return -1;
+}
+
+static GtkTreeIter gtkTreeFindUserData(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, void* userdata)
+{
+ GtkTreeIter iterChild;
+ int hasItem = TRUE;
+ void* node_userdata;
+
+ while(hasItem)
+ {
+ /* ID control to traverse items */
+ ih->data->id_control++;
+
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_USERDATA, &node_userdata, -1);
+
+ /* userdata founded! */
+ if (node_userdata == userdata)
+ return iterItem;
+
+ /* Check whether we have child items */
+ if (gtk_tree_model_iter_has_child(model, &iterItem))
+ {
+ gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */
+ iterChild = gtkTreeFindUserData(ih, model, iterChild, userdata);
+
+ /* userdata founded! */
+ if (iterChild.user_data)
+ return iterChild;
+ }
+
+ /* Go to next sibling item */
+ hasItem = gtk_tree_model_iter_next(model, &iterItem);
+ }
+
+ return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */
+}
+
+static int gtkTreeGetUserDataId(Ihandle* ih, GtkTreeModel* model, void* userdata)
+{
+ GtkTreeIter iterRoot, iterItem;
+ gtk_tree_model_get_iter_first(model, &iterRoot);
+
+ ih->data->id_control = -1;
+ iterItem = gtkTreeFindUserData(ih, model, iterRoot, userdata);
+ if (iterItem.user_data)
+ return ih->data->id_control;
+ else
+ return -1;
+}
+
+static void gtkTreeCallNodeRemovedRec(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, IFnis cb)
+{
+ GtkTreeIter iterChild;
+ int hasItem = TRUE;
+ void* node_userdata;
+
+ while(hasItem)
+ {
+ /* ID control to traverse items */
+ ih->data->id_control++;
+
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_USERDATA, &node_userdata, -1);
+
+ cb(ih, ih->data->id_control, (char*)node_userdata);
+
+ /* Check whether we have child items */
+ if (gtk_tree_model_iter_has_child(model, &iterItem))
+ {
+ gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */
+ gtkTreeCallNodeRemovedRec(ih, model, iterChild, cb);
+ }
+
+ /* Go to next sibling item */
+ hasItem = gtk_tree_model_iter_next(model, &iterItem);
+ }
+}
+
+static void gtkTreeCallNodeRemoved(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItem)
+{
+ IFnis cb = (IFnis)IupGetCallback(ih, "NODEREMOVED_CB");
+ if (cb)
+ {
+ ih->data->id_control = gtkTreeGetNodeId(ih, *iterItem)-1;
+ gtkTreeCallNodeRemovedRec(ih, model, *iterItem, cb);
+ }
+}
+
+static gboolean gtkTreeFindNodeFromID(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItem, int *id)
+{
+ GtkTreeIter iterChild;
+ int hasItem = TRUE;
+
+ while(hasItem)
+ {
+ /* ID control to traverse items */
+ (*id)--;
+
+ /* StateID founded! */
+ if (*id < 0)
+ return TRUE;
+
+ /* Check whether we have child items */
+ if (gtk_tree_model_iter_has_child(model, iterItem))
+ {
+ gtk_tree_model_iter_children(model, &iterChild, iterItem); /* get the firstchild */
+
+ if (gtkTreeFindNodeFromID(ih, model, &iterChild, id))
+ {
+ *iterItem = iterChild;
+ return TRUE;
+ }
+ }
+
+ /* Go to next sibling item */
+ hasItem = gtk_tree_model_iter_next(model, iterItem);
+ }
+
+ return FALSE;
+}
+
+static gboolean gtkTreeFindNodeFromString(Ihandle* ih, GtkTreeModel* model, const char* name_id, GtkTreeIter *iterItem)
+{
+ if (name_id[0])
+ {
+ int id;
+ if (iupStrToInt(name_id, &id))
+ {
+ gtk_tree_model_get_iter_first(model, iterItem);
+ return gtkTreeFindNodeFromID(ih, model, iterItem, &id);
+ }
+ }
+ else
+ {
+ GtkTreePath* path = NULL;
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, NULL);
+ if (path)
+ {
+ gtk_tree_model_get_iter(model, iterItem, path);
+ gtk_tree_path_free(path);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*****************************************************************************/
+/* MANIPULATING IMAGES */
+/*****************************************************************************/
+static void gtkTreeUpdateImages(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, int mode)
+{
+ GtkTreeIter iterChild;
+ int hasItem = TRUE;
+ int kind;
+
+ while(hasItem)
+ {
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1);
+
+ if (kind == ITREE_BRANCH)
+ {
+ if (mode == ITREE_UPDATEIMAGE_EXPANDED)
+ {
+ gboolean has_image_expanded = FALSE;
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_HAS_IMAGE_EXPANDED, &has_image_expanded, -1);
+ if (!has_image_expanded)
+ gtk_tree_store_set(GTK_TREE_STORE(model), &iterItem, IUPGTK_TREE_IMAGE_EXPANDED, ih->data->def_image_expanded, -1);
+ }
+ else if(mode == ITREE_UPDATEIMAGE_COLLAPSED)
+ {
+ gboolean has_image = FALSE;
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_HAS_IMAGE, &has_image, -1);
+ if (!has_image)
+ gtk_tree_store_set(GTK_TREE_STORE(model), &iterItem, IUPGTK_TREE_IMAGE, ih->data->def_image_collapsed, -1);
+ }
+
+ if (gtk_tree_model_iter_has_child(model, &iterItem))
+ {
+
+ /* Recursively traverse child items */
+ gtk_tree_model_iter_children(model, &iterChild, &iterItem);
+ gtkTreeUpdateImages(ih, model, iterChild, mode);
+ }
+ }
+ else
+ {
+ if (mode == ITREE_UPDATEIMAGE_LEAF)
+ {
+ gboolean has_image = FALSE;
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_HAS_IMAGE, &has_image, -1);
+ if (!has_image)
+ gtk_tree_store_set(GTK_TREE_STORE(model), &iterItem, IUPGTK_TREE_IMAGE, ih->data->def_image_leaf, -1);
+ }
+ }
+
+ /* Go to next sibling item */
+ hasItem = gtk_tree_model_iter_next(model, &iterItem);
+ }
+}
+
+static void gtkTreeExpandItem(Ihandle* ih, GtkTreePath* path, int expand)
+{
+ if (expand == -1)
+ expand = !gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path); /* toggle */
+
+ if (expand)
+ gtk_tree_view_expand_row(GTK_TREE_VIEW(ih->handle), path, FALSE);
+ else
+ gtk_tree_view_collapse_row(GTK_TREE_VIEW(ih->handle), path);
+}
+
+int iupgtkGetColor(const char* value, GdkColor *color)
+{
+ unsigned char r, g, b;
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ iupgdkColorSet(color, r, g, b);
+ return 1;
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+/* ADDING ITEMS */
+/*****************************************************************************/
+void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* title, int add)
+{
+ GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)));
+ GtkTreeIter iterPrev, iterNewItem, iterParent;
+ GtkTreePath* path;
+ GdkColor color = {0L,0,0,0};
+ int kindPrev;
+
+ if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterPrev))
+ return;
+
+ gtk_tree_model_get(GTK_TREE_MODEL(store), &iterPrev, IUPGTK_TREE_KIND, &kindPrev, -1);
+
+ if (kindPrev == ITREE_BRANCH && add)
+ gtk_tree_store_insert(store, &iterNewItem, &iterPrev, 0); /* iterPrev is parent of the new item (firstchild of it) */
+ else
+ gtk_tree_store_insert_after(store, &iterNewItem, NULL, &iterPrev); /* iterPrev is sibling of the new item */
+
+ iupgtkGetColor(iupAttribGetStr(ih, "FGCOLOR"), &color);
+
+ /* set the attributes of the new node */
+ gtk_tree_store_set(store, &iterNewItem, IUPGTK_TREE_HAS_IMAGE, FALSE,
+ IUPGTK_TREE_HAS_IMAGE_EXPANDED, FALSE,
+ IUPGTK_TREE_TITLE, iupgtkStrConvertToUTF8(title),
+ IUPGTK_TREE_KIND, kind,
+ IUPGTK_TREE_COLOR, &color, -1);
+
+ if (kind == ITREE_LEAF)
+ gtk_tree_store_set(store, &iterNewItem, IUPGTK_TREE_IMAGE, ih->data->def_image_leaf, -1);
+ else
+ gtk_tree_store_set(store, &iterNewItem, IUPGTK_TREE_IMAGE, ih->data->def_image_collapsed,
+ IUPGTK_TREE_IMAGE_EXPANDED, ih->data->def_image_expanded, -1);
+
+ if (kindPrev == ITREE_BRANCH && add)
+ iterParent = iterPrev;
+ else
+ gtk_tree_model_iter_parent(GTK_TREE_MODEL(store), &iterParent, &iterNewItem);
+
+ /* If this is the first child of the parent, then handle the ADDEXPANDED attribute */
+ if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), &iterParent) == 1)
+ {
+ int depth;
+ path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iterParent);
+ depth = gtk_tree_path_get_depth(path)-1;
+ if (ih->data->add_expanded || depth==0) /* if this is the first child of the root, expand always */
+ {
+ iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCHOPEN_CB", "1");
+ gtk_tree_view_expand_row(GTK_TREE_VIEW(ih->handle), path, FALSE);
+ }
+ else
+ gtk_tree_view_collapse_row(GTK_TREE_VIEW(ih->handle), path);
+ gtk_tree_path_free(path);
+ }
+}
+
+static void gtkTreeAddRootNode(Ihandle* ih)
+{
+ GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)));
+ GtkTreePath* path;
+ GtkTreeIter iterRoot;
+ GdkColor color = {0L,0,0,0};
+
+ iupgtkGetColor(iupAttribGetStr(ih, "FGCOLOR"), &color);
+
+ gtk_tree_store_append(store, &iterRoot, NULL); /* root node */
+ gtk_tree_store_set(store, &iterRoot, IUPGTK_TREE_IMAGE, ih->data->def_image_collapsed,
+ IUPGTK_TREE_HAS_IMAGE, FALSE,
+ IUPGTK_TREE_IMAGE_EXPANDED, ih->data->def_image_expanded,
+ IUPGTK_TREE_HAS_IMAGE_EXPANDED, FALSE,
+ IUPGTK_TREE_KIND, ITREE_BRANCH,
+ IUPGTK_TREE_COLOR, &color, -1);
+
+ path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iterRoot);
+ /* MarkStart node */
+ iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)path);
+
+ /* Set the default VALUE */
+ gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE);
+}
+
+/*****************************************************************************/
+/* AUXILIAR FUNCTIONS */
+/*****************************************************************************/
+static void gtkTreeOpenCloseEvent(Ihandle* ih)
+{
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+ GtkTreePath* path;
+ int kind;
+
+ if (!gtkTreeFindNodeFromString(ih, model, "", &iterItem))
+ return;
+
+ path = gtk_tree_model_get_path(model, &iterItem);
+ if (path)
+ {
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1);
+
+ if (kind == ITREE_LEAF) /* leafs */
+ gtk_tree_view_row_activated(GTK_TREE_VIEW(ih->handle), path, (GtkTreeViewColumn*)iupAttribGet(ih, "_IUPGTK_COLUMN"));
+ else /* branches */
+ gtkTreeExpandItem(ih, path, -1); /* toggle */
+
+ gtk_tree_path_free(path);
+ }
+}
+
+static gboolean gtkTreeSelected_Foreach_Func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GList **rowref_list)
+{
+ GtkTreeRowReference *rowref;
+
+ rowref = gtk_tree_row_reference_new(model, path);
+ *rowref_list = g_list_append(*rowref_list, rowref);
+
+ (void)iter;
+ return FALSE; /* do not stop walking the store, call us with next row */
+}
+
+static gboolean gtkTreeSelected_Iter_Func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GList **rowref_list)
+{
+ GtkTreeRowReference *rowref;
+ GtkTreeIter iterParent;
+ if (!gtk_tree_model_iter_parent(model, &iterParent, iter)) /* the root node can't be deleted */
+ return FALSE; /* do not stop walking the store, call us with next row */
+
+ rowref = gtk_tree_row_reference_new(model, path);
+ *rowref_list = g_list_append(*rowref_list, rowref);
+
+ return FALSE; /* do not stop walking the store, call us with next row */
+}
+
+/*****************************************************************************/
+/* CALLBACKS */
+/*****************************************************************************/
+static void gtkTreeCallMultiSelectionCb(Ihandle* ih)
+{
+ IFnIi cbMulti = (IFnIi)IupGetCallback(ih, "MULTISELECTION_CB");
+ IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB");
+ if (cbMulti || cbSelec)
+ {
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterRoot;
+ GList *rr_list = NULL;
+ GList *node;
+ int* id_rowItem;
+ int count_selected_rows, i = 0;
+
+ gtk_tree_model_get_iter_first(model, &iterRoot);
+
+ gtk_tree_selection_selected_foreach(selection, (GtkTreeSelectionForeachFunc)gtkTreeSelected_Foreach_Func, &rr_list);
+ count_selected_rows = g_list_length(rr_list);
+ id_rowItem = malloc(sizeof(int) * count_selected_rows);
+
+ for(node = rr_list; node != NULL; node = node->next)
+ {
+ GtkTreePath* path = gtk_tree_row_reference_get_path(node->data);
+ if (path)
+ {
+ GtkTreeIter iterItem;
+ gtk_tree_model_get_iter(model, &iterItem, path);
+
+ id_rowItem[i] = gtkTreeGetNodeId(ih, iterItem);
+ i++;
+
+ gtk_tree_path_free(path);
+ }
+ }
+
+ g_list_foreach(rr_list, (GFunc) gtk_tree_row_reference_free, NULL);
+ g_list_free(rr_list);
+
+ if (cbMulti)
+ cbMulti(ih, id_rowItem, count_selected_rows);
+ else
+ {
+ for (i=0; i<count_selected_rows; i++)
+ cbSelec(ih, id_rowItem[i], 1);
+ }
+
+ free(id_rowItem);
+ }
+}
+
+
+/*****************************************************************************/
+/* GET AND SET ATTRIBUTES */
+/*****************************************************************************/
+
+
+static char* gtkTreeGetIndentationAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(255);
+#if GTK_CHECK_VERSION(2, 12, 0)
+ int indent = gtk_tree_view_get_level_indentation(GTK_TREE_VIEW(ih->handle));
+#else
+ int indent = 0;
+#endif
+ sprintf(str, "%d", indent);
+ return str;
+}
+
+static int gtkTreeSetIndentationAttrib(Ihandle* ih, const char* value)
+{
+#if GTK_CHECK_VERSION(2, 12, 0)
+ int indent;
+ if (iupStrToInt(value, &indent))
+ gtk_tree_view_set_level_indentation(GTK_TREE_VIEW(ih->handle), indent);
+#endif
+ return 0;
+}
+
+static int gtkTreeSetTopItemAttrib(Ihandle* ih, const char* value)
+{
+ GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)));
+ GtkTreeIter iterItem;
+ GtkTreePath* path;
+
+ if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), value, &iterItem))
+ return 0;
+
+ path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iterItem);
+
+ if (!gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path))
+ gtk_tree_view_expand_to_path(GTK_TREE_VIEW(ih->handle), path);
+
+ gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE, 0, 0); /* scroll to visible */
+
+ gtk_tree_path_free(path);
+
+ return 0;
+}
+
+static int gtkTreeSetSpacingAttrib(Ihandle* ih, const char* value)
+{
+ if(!iupStrToInt(value, &ih->data->spacing))
+ ih->data->spacing = 1;
+
+ if(ih->data->spacing < 1)
+ ih->data->spacing = 1;
+
+ if (ih->handle)
+ {
+ GtkCellRenderer *renderer_img = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER_IMG");
+ GtkCellRenderer *renderer_txt = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER_TEXT");
+ g_object_set(G_OBJECT(renderer_img), "ypad", ih->data->spacing, NULL);
+ g_object_set(G_OBJECT(renderer_txt), "ypad", ih->data->spacing, NULL);
+ return 0;
+ }
+ else
+ return 1; /* store until not mapped, when mapped will be set again */
+}
+
+static int gtkTreeSetExpandAllAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value))
+ gtk_tree_view_expand_all(GTK_TREE_VIEW(ih->handle));
+ else
+ {
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterRoot;
+ GtkTreePath* pathRoot;
+
+ gtk_tree_view_collapse_all(GTK_TREE_VIEW(ih->handle));
+
+ /* The root node is always expanded */
+ gtk_tree_model_get_iter_first(model, &iterRoot);
+ pathRoot = gtk_tree_model_get_path(model, &iterRoot);
+ gtk_tree_view_expand_row(GTK_TREE_VIEW(ih->handle), pathRoot, FALSE);
+ gtk_tree_path_free(pathRoot);
+ }
+
+ return 0;
+}
+
+static char* gtkTreeGetDepthAttrib(Ihandle* ih, const char* name_id)
+{
+ char* depth;
+ GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)));
+ GtkTreeIter iterItem;
+ if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem))
+ return NULL;
+
+ depth = iupStrGetMemory(10);
+ sprintf(depth, "%d", gtk_tree_store_iter_depth(store, &iterItem));
+ return depth;
+}
+
+static int gtkTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ GtkTreeModel* model;
+ GtkTreeIter iterItemSrc, iterItemDst, iterNewItem;
+ GtkTreeIter iterParent, iterNextParent;
+
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+
+ model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItemSrc))
+ return 0;
+
+ if (!gtkTreeFindNodeFromString(ih, model, value, &iterItemDst))
+ return 0;
+
+ /* If Drag item is an ancestor of Drop item then return */
+ iterParent = iterItemDst;
+ while(gtk_tree_model_iter_parent(model, &iterNextParent, &iterParent))
+ {
+ if (iterNextParent.user_data == iterItemSrc.user_data)
+ return 0;
+ iterParent = iterNextParent;
+ }
+
+ /* Copying the node and its children to the new position */
+ gtkTreeCopyNode(ih, model, &iterItemSrc, &iterItemDst, &iterNewItem, 0); /* not a full copy, preserve user data */
+
+ /* Deleting the node of its old position */
+ /* do not delete the user data, we copy the references in CopyNode */
+ gtk_tree_store_remove(GTK_TREE_STORE(model), &iterItemSrc);
+
+ return 0;
+}
+
+static int gtkTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ GtkTreeModel* model;
+ GtkTreeIter iterItemSrc, iterItemDst, iterNewItem;
+ GtkTreeIter iterParent, iterNextParent;
+
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+
+ model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItemSrc))
+ return 0;
+
+ if (!gtkTreeFindNodeFromString(ih, model, value, &iterItemDst))
+ return 0;
+
+ /* If Drag item is an ancestor of Drop item then return */
+ iterParent = iterItemDst;
+ while(gtk_tree_model_iter_parent(model, &iterNextParent, &iterParent))
+ {
+ if (iterNextParent.user_data == iterItemSrc.user_data)
+ return 0;
+ iterParent = iterNextParent;
+ }
+
+ /* Copying the node and its children to the new position */
+ gtkTreeCopyNode(ih, model, &iterItemSrc, &iterItemDst, &iterNewItem, 1);
+
+ return 0;
+}
+
+static char* gtkTreeGetColorAttrib(Ihandle* ih, const char* name_id)
+{
+ char* str;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+ GdkColor *color;
+
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem))
+ return NULL;
+
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_COLOR, &color, -1);
+ if (!color)
+ return NULL;
+
+ str = iupStrGetMemory(20);
+ sprintf(str, "%d %d %d", iupCOLOR16TO8(color->red),
+ iupCOLOR16TO8(color->green),
+ iupCOLOR16TO8(color->blue));
+ return str;
+}
+
+static int gtkTreeSetColorAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)));
+ GtkTreeIter iterItem;
+ GdkColor color;
+ unsigned char r, g, b;
+
+ if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem))
+ return 0;
+
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgdkColorSet(&color, r, g, b);
+ gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_COLOR, &color, -1);
+
+ return 0;
+}
+
+static char* gtkTreeGetParentAttrib(Ihandle* ih, const char* name_id)
+{
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+ GtkTreeIter iterParent;
+ char* str;
+
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem))
+ return NULL;
+
+ if (!gtk_tree_model_iter_parent(model, &iterParent, &iterItem))
+ return NULL;
+
+ str = iupStrGetMemory(10);
+ sprintf(str, "%d", gtkTreeGetNodeId(ih, iterParent));
+ return str;
+}
+
+static char* gtkTreeGetChildCountAttrib(Ihandle* ih, const char* name_id)
+{
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+ char* str;
+
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem))
+ return NULL;
+
+ str = iupStrGetMemory(10);
+ sprintf(str, "%d", gtk_tree_model_iter_n_children(model, &iterItem));
+ return str;
+}
+
+static int gtkTreeCount(GtkTreeModel* model, GtkTreeIter iterBranch)
+{
+ GtkTreeIter iterChild;
+ int count = 0;
+ int hasItem = gtk_tree_model_iter_children(model, &iterChild, &iterBranch); /* get the firstchild */
+ count++;
+ while(hasItem)
+ {
+ count += gtkTreeCount(model, iterChild);
+
+ /* Go to next sibling item */
+ hasItem = gtk_tree_model_iter_next(model, &iterChild);
+ }
+
+ return count;
+}
+
+static char* gtkTreeGetCountAttrib(Ihandle* ih)
+{
+ GtkTreeIter iterRoot;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ char* str = iupStrGetMemory(10);
+ gtk_tree_model_get_iter_first(model, &iterRoot);
+ sprintf(str, "%d", gtkTreeCount(model, iterRoot));
+ return str;
+}
+
+static char* gtkTreeGetKindAttrib(Ihandle* ih, const char* name_id)
+{
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+ int kind;
+
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem))
+ return NULL;
+
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1);
+
+ if(!kind)
+ return "BRANCH";
+ else
+ return "LEAF";
+}
+
+static char* gtkTreeGetStateAttrib(Ihandle* ih, const char* name_id)
+{
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem))
+ return NULL;
+
+ if (gtk_tree_model_iter_has_child(model, &iterItem))
+ {
+ GtkTreePath* path = gtk_tree_model_get_path(model, &iterItem);
+ int expanded = gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path);
+ gtk_tree_path_free(path);
+
+ if (expanded)
+ return "EXPANDED";
+ else
+ return "COLLAPSED";
+ }
+
+ return NULL;
+}
+
+static int gtkTreeSetStateAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+ GtkTreePath* path;
+
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem))
+ return 0;
+
+ path = gtk_tree_model_get_path(model, &iterItem);
+ gtkTreeExpandItem(ih, path, iupStrEqualNoCase(value, "EXPANDED"));
+ gtk_tree_path_free(path);
+
+ return 0;
+}
+
+static char* gtkTreeGetTitle(GtkTreeModel* model, GtkTreeIter iterItem)
+{
+ char* title;
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_TITLE, &title, -1);
+ return iupgtkStrConvertFromUTF8(title);
+}
+
+static char* gtkTreeGetTitleAttrib(Ihandle* ih, const char* name_id)
+{
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem))
+ return NULL;
+ return gtkTreeGetTitle(model, iterItem);
+}
+
+static int gtkTreeSetTitleAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)));
+ GtkTreeIter iterItem;
+ if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem))
+ return 0;
+ gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_TITLE, iupgtkStrConvertToUTF8(value), -1);
+ return 0;
+}
+
+static int gtkTreeSetTitleFontAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ PangoFontDescription* fontdesc = NULL;
+ GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)));
+ GtkTreeIter iterItem;
+ if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem))
+ return 0;
+ if (value)
+ fontdesc = iupgtkGetPangoFontDesc(value);
+ gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_FONT, fontdesc, -1);
+ return 0;
+}
+
+static char* gtkTreeGetTitleFontAttrib(Ihandle* ih, const char* name_id)
+{
+ PangoFontDescription* fontdesc;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem))
+ return NULL;
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_FONT, &fontdesc, -1);
+ return pango_font_description_to_string(fontdesc);
+}
+
+static char* gtkTreeGetFindUserDataAttrib(Ihandle* ih, const char* name_id)
+{
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ int id;
+ char* str = (char*)(name_id+1); /* skip ':' */
+ void* userdata = NULL;
+ if (sscanf(str, "%p", &userdata)!=1)
+ return NULL;
+ id = gtkTreeGetUserDataId(ih, model, userdata);
+ if (id == -1)
+ return NULL;
+ str = iupStrGetMemory(16);
+ sprintf(str, "%d", id);
+ return str;
+}
+
+static char* gtkTreeGetUserDataAttrib(Ihandle* ih, const char* name_id)
+{
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+ char* userdata;
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem))
+ return NULL;
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_USERDATA, &userdata, -1);
+ return userdata;
+}
+
+static int gtkTreeSetUserDataAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)));
+ GtkTreeIter iterItem;
+ if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem))
+ return 0;
+ gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_USERDATA, value, -1);
+ return 0;
+}
+
+static char* gtkTreeGetValueAttrib(Ihandle* ih)
+{
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreePath* path = NULL;
+ char* str;
+
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, NULL);
+ if (path)
+ {
+ GtkTreeIter iterItem;
+ gtk_tree_model_get_iter(model, &iterItem, path);
+ gtk_tree_path_free(path);
+
+ str = iupStrGetMemory(16);
+ sprintf(str, "%d", gtkTreeGetNodeId(ih, iterItem));
+ return str;
+ }
+
+ return "0"; /* default VALUE is root */
+}
+
+static int gtkTreeSetMarkAttrib(Ihandle* ih, const char* value)
+{
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterRoot;
+
+ if (ih->data->mark_mode==ITREE_MARK_SINGLE)
+ return 0;
+
+ gtk_tree_model_get_iter_first(model, &iterRoot);
+
+ if(iupStrEqualNoCase(value, "BLOCK"))
+ {
+ GtkTreePath* pathFocus;
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL);
+ gtk_tree_selection_select_range(selection, (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE"), pathFocus);
+ gtk_tree_path_free(pathFocus);
+ }
+ else if(iupStrEqualNoCase(value, "CLEARALL"))
+ gtk_tree_selection_unselect_all(selection);
+ else if(iupStrEqualNoCase(value, "MARKALL"))
+ gtk_tree_selection_select_all(selection);
+ else if(iupStrEqualNoCase(value, "INVERTALL")) /* INVERTALL *MUST* appear before INVERT, or else INVERTALL will never be called. */
+ gtkTreeInvertAllNodeMarking(ih, model, selection, &iterRoot);
+ else if(iupStrEqualPartial(value, "INVERT"))
+ {
+ /* iupStrEqualPartial allows the use of "INVERTid" form */
+ GtkTreeIter iterItem;
+ if (!gtkTreeFindNodeFromString(ih, model, &value[strlen("INVERT")], &iterItem))
+ return 0;
+
+ if(gtk_tree_selection_iter_is_selected(selection, &iterItem))
+ gtk_tree_selection_unselect_iter(selection, &iterItem);
+ else
+ gtk_tree_selection_select_iter(selection, &iterItem);
+ }
+ else
+ {
+ GtkTreePath *path1, *path2;
+ GtkTreeIter iterItem1, iterItem2;
+ char str1[50], str2[50];
+ if (iupStrToStrStr(value, str1, str2, '-')!=2)
+ return 0;
+
+ if (!gtkTreeFindNodeFromString(ih, model, str1, &iterItem1))
+ return 0;
+ if (!gtkTreeFindNodeFromString(ih, model, str2, &iterItem2))
+ return 0;
+
+ path1 = gtk_tree_model_get_path(model, &iterItem1);
+ path2 = gtk_tree_model_get_path(model, &iterItem2);
+ gtk_tree_selection_select_range(selection, path1, path2);
+ gtk_tree_path_free(path1);
+ gtk_tree_path_free(path2);
+ }
+
+ return 1;
+}
+
+static int gtkTreeSetValueAttrib(Ihandle* ih, const char* value)
+{
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterRoot, iterItem;
+ GtkTreePath* path;
+
+ if (gtkTreeSetMarkAttrib(ih, value))
+ return 0;
+
+ gtk_tree_model_get_iter_first(model, &iterRoot);
+
+ if (iupStrEqualNoCase(value, "ROOT"))
+ iterItem = iterRoot;
+ else if(iupStrEqualNoCase(value, "LAST"))
+ iterItem = gtkTreeGetLastVisibleNode(ih, model, iterRoot);
+ else if(iupStrEqualNoCase(value, "PGUP"))
+ {
+ GtkTreeIter iterPrev;
+
+ GtkTreePath* pathFocus;
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL);
+ gtk_tree_model_get_iter(model, &iterPrev, pathFocus);
+ gtk_tree_path_free(pathFocus);
+
+ ih->data->id_control = -1;
+ gtkTreeFindVisibleNodeId(ih, model, iterRoot, iterPrev);
+ ih->data->id_control -= 10; /* less 10 visible nodes */
+
+ if(ih->data->id_control < 0)
+ ih->data->id_control = 0; /* Begin of tree = Root id */
+
+ iterItem = gtkTreeFindVisibleNodeFromId(ih, model, iterRoot);
+ }
+ else if(iupStrEqualNoCase(value, "PGDN"))
+ {
+ GtkTreeIter iterNext;
+
+ GtkTreePath* pathFocus;
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL);
+ gtk_tree_model_get_iter(model, &iterNext, pathFocus);
+ gtk_tree_path_free(pathFocus);
+
+ ih->data->id_control = -1;
+ gtkTreeFindVisibleNodeId(ih, model, iterRoot, iterNext);
+ ih->data->id_control += 10; /* more 10 visible nodes */
+
+ iterNext = gtkTreeFindVisibleNodeFromId(ih, model, iterRoot);
+
+ if (ih->data->id_control >= 0)
+ iterNext = gtkTreeGetLastVisibleNode(ih, model, iterRoot);
+
+ iterItem = iterNext;
+ }
+ else if(iupStrEqualNoCase(value, "NEXT"))
+ {
+ GtkTreeIter iterNext;
+
+ GtkTreePath* pathFocus;
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL);
+ gtk_tree_model_get_iter(model, &iterNext, pathFocus);
+ gtk_tree_path_free(pathFocus);
+
+ ih->data->id_control = -1;
+ gtkTreeFindVisibleNodeId(ih, model, iterRoot, iterNext);
+ ih->data->id_control++; /* more 1 visible node */
+
+ iterNext = gtkTreeFindVisibleNodeFromId(ih, model, iterRoot);
+
+ if (ih->data->id_control >= 0)
+ iterNext = gtkTreeGetLastVisibleNode(ih, model, iterRoot);
+
+ iterItem = iterNext;
+ }
+ else if(iupStrEqualNoCase(value, "PREVIOUS"))
+ {
+ GtkTreeIter iterPrev;
+
+ GtkTreePath* pathFocus;
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL);
+ gtk_tree_model_get_iter(model, &iterPrev, pathFocus);
+ gtk_tree_path_free(pathFocus);
+
+ ih->data->id_control = -1;
+ gtkTreeFindVisibleNodeId(ih, model, iterRoot, iterPrev);
+ ih->data->id_control--; /* less 1 visible node */
+
+ if (ih->data->id_control < 0)
+ ih->data->id_control = 0;
+
+ iterItem = gtkTreeFindVisibleNodeFromId(ih, model, iterRoot);
+ if (!iterItem.user_data)
+ return 0;
+ }
+ else
+ {
+ if (!gtkTreeFindNodeFromString(ih, model, value, &iterItem))
+ return 0;
+ }
+
+ /* select */
+ if (ih->data->mark_mode==ITREE_MARK_SINGLE)
+ {
+ iupAttribSetStr(ih, "_IUP_IGNORE_SELECTION", "1");
+ gtk_tree_selection_select_iter(selection, &iterItem);
+ }
+
+ path = gtk_tree_model_get_path(model, &iterItem);
+ gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE, 0, 0); /* scroll to visible */
+ gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE); /* set focus */
+ gtk_tree_path_free(path);
+
+ iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", gtkTreeGetNodeId(ih, iterItem));
+
+ return 0;
+}
+
+static int gtkTreeSetMarkStartAttrib(Ihandle* ih, const char* name_id)
+{
+ GtkTreePath *pathMarkStart, *pathMarkStartPrev;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem))
+ return 0;
+
+ pathMarkStart = gtk_tree_model_get_path(model, &iterItem);
+
+ pathMarkStartPrev = (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE");
+ if (pathMarkStartPrev)
+ gtk_tree_path_free(pathMarkStartPrev);
+
+ iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)pathMarkStart);
+
+ return 1;
+}
+
+static char* gtkTreeGetMarkedAttrib(Ihandle* ih, const char* name_id)
+{
+ GtkTreeSelection* selection;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem))
+ return 0;
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+ if (gtk_tree_selection_iter_is_selected(selection, &iterItem))
+ return "YES";
+ else
+ return "NO";
+}
+
+static int gtkTreeSetMarkedAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ GtkTreeSelection* selection;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem))
+ return 0;
+
+ iupAttribSetStr(ih, "_IUP_IGNORE_SELECTION", "1");
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+ if (iupStrBoolean(value))
+ gtk_tree_selection_select_iter(selection, &iterItem);
+ else
+ gtk_tree_selection_unselect_iter(selection, &iterItem);
+
+ return 0;
+}
+
+static int gtkTreeSetDelNodeAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ if (iupStrEqualNoCase(value, "SELECTED")) /* selected here means the specified one */
+ {
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem;
+ GtkTreeIter iterParent;
+
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem))
+ return 0;
+
+ if (!gtk_tree_model_iter_parent(model, &iterParent, &iterItem)) /* the root node can't be deleted */
+ return 0;
+
+ gtkTreeCallNodeRemoved(ih, model, &iterItem);
+
+ /* deleting the specified node (and it's children) */
+ gtk_tree_store_remove(GTK_TREE_STORE(model), &iterItem);
+ }
+ else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the specified one */
+ {
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeIter iterItem, iterChild;
+ int hasChildren;
+
+ if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem))
+ return 0;
+
+ hasChildren = gtk_tree_model_iter_children(model, &iterChild, &iterItem);
+
+ /* deleting the selected node's children */
+ while(hasChildren)
+ {
+ gtkTreeCallNodeRemoved(ih, model, &iterChild);
+ hasChildren = gtk_tree_store_remove(GTK_TREE_STORE(model), &iterChild);
+ }
+ }
+ else if(iupStrEqualNoCase(value, "MARKED")) /* Delete the array of marked nodes */
+ {
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+ GList *rr_list = NULL;
+ GList *node;
+
+ gtk_tree_selection_selected_foreach(selection, (GtkTreeSelectionForeachFunc)gtkTreeSelected_Iter_Func, &rr_list);
+
+ for(node = rr_list; node != NULL; node = node->next)
+ {
+ GtkTreePath* path = gtk_tree_row_reference_get_path(node->data);
+ if (path)
+ {
+ GtkTreeIter iterItem;
+ if (gtk_tree_model_get_iter(model, &iterItem, path))
+ {
+ gtkTreeCallNodeRemoved(ih, model, &iterItem);
+ gtk_tree_store_remove(GTK_TREE_STORE(model), &iterItem);
+ }
+ gtk_tree_path_free(path);
+ }
+ gtk_tree_row_reference_free(node->data);
+ }
+ g_list_free(rr_list);
+ }
+
+ return 0;
+}
+
+static int gtkTreeSetRenameAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->show_rename)
+ {
+ GtkTreePath* path;
+ IFni cbShowRename = (IFni)IupGetCallback(ih, "SHOWRENAME_CB");
+ GtkTreeViewColumn *focus_column;
+
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, &focus_column);
+
+ if (cbShowRename)
+ {
+ GtkTreeIter iterItem;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ gtk_tree_model_get_iter(model, &iterItem, path);
+ cbShowRename(ih, gtkTreeGetNodeId(ih, iterItem));
+ }
+
+ gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), path, focus_column, TRUE);
+ gtk_tree_path_free(path);
+ }
+ else
+ {
+ IFnis cbRenameNode = (IFnis)IupGetCallback(ih, "RENAMENODE_CB");
+ if (cbRenameNode)
+ {
+ GtkTreePath* path;
+ GtkTreeIter iterItem;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, NULL);
+ gtk_tree_model_get_iter(model, &iterItem, path);
+ gtk_tree_path_free(path);
+ cbRenameNode(ih, gtkTreeGetNodeId(ih, iterItem), gtkTreeGetTitle(model, iterItem));
+ }
+ }
+
+ (void)value;
+ return 0;
+}
+
+static int gtkTreeSetImageExpandedAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ int kind;
+ GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)));
+ GdkPixbuf* pixExpand = iupImageGetImage(value, ih, 0);
+ GtkTreeIter iterItem;
+ if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem))
+ return 0;
+
+ gtk_tree_model_get(GTK_TREE_MODEL(store), &iterItem, IUPGTK_TREE_KIND, &kind, -1);
+
+ if (kind == ITREE_BRANCH)
+ {
+ if (pixExpand)
+ gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_IMAGE_EXPANDED, pixExpand,
+ IUPGTK_TREE_HAS_IMAGE_EXPANDED, TRUE, -1);
+ else
+ gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_IMAGE_EXPANDED, ih->data->def_image_expanded,
+ IUPGTK_TREE_HAS_IMAGE_EXPANDED, FALSE, -1);
+ }
+
+ return 1;
+}
+
+static int gtkTreeSetImageAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)));
+ GdkPixbuf* pixImage = iupImageGetImage(value, ih, 0);
+ GtkTreeIter iterItem;
+ if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem))
+ return 0;
+
+ if (pixImage)
+ {
+ gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_IMAGE, pixImage,
+ IUPGTK_TREE_HAS_IMAGE, TRUE, -1);
+ }
+ else
+ {
+ int kind;
+ gtk_tree_model_get(GTK_TREE_MODEL(store), &iterItem, IUPGTK_TREE_KIND, &kind, -1);
+ if (kind == ITREE_BRANCH)
+ gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_IMAGE, ih->data->def_image_collapsed,
+ IUPGTK_TREE_HAS_IMAGE, FALSE, -1);
+ else
+ gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_IMAGE, ih->data->def_image_leaf,
+ IUPGTK_TREE_HAS_IMAGE, FALSE, -1);
+ }
+
+ return 1;
+}
+
+static int gtkTreeSetImageBranchExpandedAttrib(Ihandle* ih, const char* value)
+{
+ GtkTreeIter iterRoot;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ ih->data->def_image_expanded = iupImageGetImage(value, ih, 0);
+
+ gtk_tree_model_get_iter_first(model, &iterRoot);
+
+ /* Update all images, starting at root node */
+ gtkTreeUpdateImages(ih, model, iterRoot, ITREE_UPDATEIMAGE_EXPANDED);
+
+ return 1;
+}
+
+static int gtkTreeSetImageBranchCollapsedAttrib(Ihandle* ih, const char* value)
+{
+ GtkTreeIter iterRoot;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ ih->data->def_image_collapsed = iupImageGetImage(value, ih, 0);
+
+ gtk_tree_model_get_iter_first(model, &iterRoot);
+
+ /* Update all images, starting at root node */
+ gtkTreeUpdateImages(ih, model, iterRoot, ITREE_UPDATEIMAGE_COLLAPSED);
+
+ return 1;
+}
+
+static int gtkTreeSetImageLeafAttrib(Ihandle* ih, const char* value)
+{
+ GtkTreeIter iterRoot;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ ih->data->def_image_leaf = iupImageGetImage(value, ih, 0);
+
+ gtk_tree_model_get_iter_first(model, &iterRoot);
+
+ /* Update all images, starting at root node */
+ gtkTreeUpdateImages(ih, model, iterRoot, ITREE_UPDATEIMAGE_LEAF);
+
+ return 1;
+}
+
+static int gtkTreeSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+
+ GtkScrolledWindow* scrolled_window = (GtkScrolledWindow*)iupAttribGet(ih, "_IUP_EXTRAPARENT");
+ if (scrolled_window)
+ {
+ /* ignore given value, must use only from parent for the scrollbars */
+ char* parent_value = iupBaseNativeParentGetBgColor(ih);
+
+ if (iupStrToRGB(parent_value, &r, &g, &b))
+ {
+ GtkWidget* sb;
+
+ if (!GTK_IS_SCROLLED_WINDOW(scrolled_window))
+ scrolled_window = (GtkScrolledWindow*)iupAttribGet(ih, "_IUPGTK_SCROLLED_WINDOW");
+
+ iupgtkBaseSetBgColor((GtkWidget*)scrolled_window, r, g, b);
+
+#if GTK_CHECK_VERSION(2, 8, 0)
+ sb = gtk_scrolled_window_get_hscrollbar(scrolled_window);
+ if (sb) iupgtkBaseSetBgColor(sb, r, g, b);
+
+ sb = gtk_scrolled_window_get_vscrollbar(scrolled_window);
+ if (sb) iupgtkBaseSetBgColor(sb, r, g, b);
+#endif
+ }
+ }
+
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ {
+ GtkCellRenderer* renderer_txt = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER_TEXT");
+ GtkCellRenderer* renderer_img = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER_IMG");
+ GdkColor color;
+ iupgdkColorSet(&color, r, g, b);
+ g_object_set(G_OBJECT(renderer_txt), "cell-background-gdk", &color, NULL);
+ g_object_set(G_OBJECT(renderer_img), "cell-background-gdk", &color, NULL);
+ }
+
+ iupdrvBaseSetBgColorAttrib(ih, value); /* use given value for contents */
+
+ /* no need to update internal image cache in GTK */
+
+ return 1;
+}
+
+static int gtkTreeSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ if (!iupStrToRGB(value, &r, &g, &b))
+ return 0;
+
+ iupgtkBaseSetFgColor(ih->handle, r, g, b);
+
+ {
+ GtkCellRenderer* renderer_txt = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER_TEXT");
+ GdkColor color;
+ iupgdkColorSet(&color, r, g, b);
+ g_object_set(G_OBJECT(renderer_txt), "foreground-gdk", &color, NULL);
+ g_object_get(G_OBJECT(renderer_txt), "foreground-gdk", &color, NULL);
+ color.blue = 0;
+ }
+
+ return 1;
+}
+
+void iupdrvTreeUpdateMarkMode(Ihandle *ih)
+{
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+ gtk_tree_selection_set_mode(selection, (ih->data->mark_mode==ITREE_MARK_SINGLE)? GTK_SELECTION_SINGLE: GTK_SELECTION_MULTIPLE);
+
+ if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && !ih->data->show_dragdrop)
+ {
+#if GTK_CHECK_VERSION(2, 10, 0)
+ gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(ih->handle), TRUE);
+#endif
+ }
+}
+
+
+/***********************************************************************************************/
+
+
+static void gtkTreeSetRenameCaretPos(GtkCellEditable *editable, const char* value)
+{
+ int pos = 1;
+
+ if (iupStrToInt(value, &pos))
+ {
+ if (pos < 1) pos = 1;
+ pos--; /* IUP starts at 1 */
+
+ gtk_editable_set_position(GTK_EDITABLE(editable), pos);
+ }
+}
+
+static void gtkTreeSetRenameSelectionPos(GtkCellEditable *editable, const char* value)
+{
+ int start = 1, end = 1;
+
+ if (iupStrToIntInt(value, &start, &end, ':') != 2)
+ return;
+
+ if(start < 1 || end < 1)
+ return;
+
+ start--; /* IUP starts at 1 */
+ end--;
+
+ gtk_editable_select_region(GTK_EDITABLE(editable), start, end);
+}
+
+/*****************************************************************************/
+/* SIGNALS */
+/*****************************************************************************/
+
+static void gtkTreeCellTextEditingStarted(GtkCellRenderer *cell, GtkCellEditable *editable, const gchar *path_string, Ihandle *ih)
+{
+ char* value;
+ GtkTreeIter iterItem;
+ PangoFontDescription* fontdesc = NULL;
+ GdkColor *color = NULL;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+
+ value = iupAttribGetStr(ih, "RENAMECARET");
+ if (value)
+ gtkTreeSetRenameCaretPos(editable, value);
+
+ value = iupAttribGetStr(ih, "RENAMESELECTION");
+ if (value)
+ gtkTreeSetRenameSelectionPos(editable, value);
+
+ gtk_tree_model_get_iter_from_string(model, &iterItem, path_string);
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_FONT, &fontdesc, -1);
+ if (fontdesc)
+ gtk_widget_modify_font(GTK_WIDGET(editable), fontdesc);
+
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_COLOR, &color, -1);
+ if (color)
+ iupgtkBaseSetFgGdkColor(GTK_WIDGET(editable), color);
+
+ (void)cell;
+}
+
+static void gtkTreeCellTextEdited(GtkCellRendererText *cell, gchar *path_string, gchar *new_text, Ihandle* ih)
+{
+ GtkTreeModel* model;
+ GtkTreeIter iterItem;
+ IFnis cbRename;
+
+ if (!new_text)
+ return;
+
+ model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ if (!gtk_tree_model_get_iter_from_string(model, &iterItem, path_string))
+ return;
+
+ cbRename = (IFnis)IupGetCallback(ih, "RENAME_CB");
+ if (cbRename)
+ {
+ if (cbRename(ih, gtkTreeGetNodeId(ih, iterItem), iupgtkStrConvertFromUTF8(new_text)) == IUP_IGNORE)
+ return;
+ }
+
+ /* It is the responsibility of the application to update the model and store new_text at the position indicated by path. */
+ gtk_tree_store_set(GTK_TREE_STORE(model), &iterItem, IUPGTK_TREE_TITLE, new_text, -1);
+
+ (void)cell;
+}
+
+static int gtkTreeCallDragDropCb(Ihandle* ih, GtkTreeIter *iterDrag, GtkTreeIter *iterDrop, int *is_ctrl)
+{
+ IFniiii cbDragDrop = (IFniiii)IupGetCallback(ih, "DRAGDROP_CB");
+ int is_shift = 0;
+ char key[5];
+ iupdrvGetKeyState(key);
+ if (key[0] == 'S')
+ is_shift = 1;
+ if (key[1] == 'C')
+ *is_ctrl = 1;
+ else
+ *is_ctrl = 0;
+
+ if (cbDragDrop)
+ {
+ int drag_id = gtkTreeGetNodeId(ih, *iterDrag);
+ int drop_id = gtkTreeGetNodeId(ih, *iterDrop);
+ return cbDragDrop(ih, drag_id, drop_id, is_shift, *is_ctrl);
+ }
+
+ return IUP_CONTINUE; /* allow to move by default if callback not defined */
+}
+
+static void gtkTreeDragDataReceived(GtkWidget *widget, GdkDragContext *context, gint x, gint y,
+ GtkSelectionData *selection_data, guint info, guint time, Ihandle* ih)
+{
+ GtkTreePath* pathDrag = (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_DRAGITEM");
+ GtkTreePath* pathDrop = (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_DROPITEM");
+ int accepted = FALSE;
+ int is_ctrl;
+
+ if (pathDrag && pathDrop)
+ {
+ GtkTreeIter iterDrag, iterDrop, iterParent, iterNextParent;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+
+ gtk_tree_model_get_iter(model, &iterDrag, pathDrag);
+ gtk_tree_model_get_iter(model, &iterDrop, pathDrop);
+
+ iterParent = iterDrop;
+ while(gtk_tree_model_iter_parent(model, &iterNextParent, &iterParent))
+ {
+ if (iterNextParent.user_data == iterDrag.user_data)
+ goto gtkTreeDragDataReceived_FINISH;
+ iterParent = iterNextParent;
+ }
+
+ accepted = TRUE;
+
+ if (gtkTreeCallDragDropCb(ih, &iterDrag, &iterDrop, &is_ctrl) == IUP_CONTINUE)
+ {
+ GtkTreeIter iterNewItem;
+
+ /* Copy the dragged item to the new position. */
+ gtkTreeCopyNode(ih, model, &iterDrag, &iterDrop, &iterNewItem, is_ctrl);
+
+ if (!is_ctrl)
+ {
+ /* do not delete the user data, we copy the references in CopyNode */
+ gtk_tree_store_remove(GTK_TREE_STORE(model), &iterDrag);
+ }
+
+ /* set focus and selection */
+ {
+ GtkTreePath *pathNew;
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+
+ pathNew = gtk_tree_model_get_path(model, &iterNewItem);
+ gtk_tree_selection_select_path(selection, pathNew);
+
+ gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(ih->handle), pathNew, NULL, FALSE, 0, 0);
+ gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), pathNew, NULL, FALSE);
+
+ gtk_tree_path_free(pathNew);
+ }
+ }
+ }
+
+gtkTreeDragDataReceived_FINISH:
+ if (pathDrag) gtk_tree_path_free(pathDrag);
+ if (pathDrop) gtk_tree_path_free(pathDrop);
+
+ iupAttribSetStr(ih, "_IUPTREE_DRAGITEM", NULL);
+ iupAttribSetStr(ih, "_IUPTREE_DROPITEM", NULL);
+
+ gtk_drag_finish(context, accepted, (context->action == GDK_ACTION_MOVE), time);
+
+ (void)widget;
+ (void)info;
+ (void)x;
+ (void)y;
+ (void)selection_data;
+}
+
+static gboolean gtkTreeDragDrop(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, Ihandle* ih)
+{
+ GtkTreePath* path;
+ GtkTreeViewDropPosition pos;
+ GdkAtom target = GDK_NONE;
+
+ /* unset any highlight row */
+ gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW(widget), NULL, GTK_TREE_VIEW_DROP_BEFORE);
+
+ if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(ih->handle), x, y, &path, &pos))
+ {
+ if ((pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE || pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER) &&
+ (gtk_tree_path_compare(path, (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_DRAGITEM")) != 0))
+ {
+ target = gtk_drag_dest_find_target(widget, context, gtk_drag_dest_get_target_list(widget));
+ if (target != GDK_NONE)
+ {
+ iupAttribSetStr(ih, "_IUPTREE_DROPITEM", (char*)path);
+ gtk_drag_get_data(widget, context, target, time);
+ return TRUE;
+ }
+ }
+ }
+
+ (void)widget;
+ return FALSE;
+}
+
+static void gtkTreeDragLeave(GtkWidget *widget, GdkDragContext *context, guint time)
+{
+ /* unset any highlight row */
+ gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(widget), NULL, GTK_TREE_VIEW_DROP_BEFORE);
+ (void)context;
+ (void)time;
+}
+
+static gboolean gtkTreeDragMotion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, Ihandle* ih)
+{
+ GtkTreePath* path;
+ GtkTreeViewDropPosition pos;
+ GtkTreePath* pathDrag = (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_DRAGITEM");
+ if (pathDrag && gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(ih->handle), x, y, &path, &pos))
+ {
+ if ((pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE || pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER) &&
+ (gtk_tree_path_compare(path, pathDrag) != 0))
+ {
+ gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(widget), path, pos);
+ gdk_drag_status(context, context->actions, time);
+ return TRUE;
+ }
+
+ gtk_tree_path_free(path);
+ }
+
+ (void)widget;
+ return FALSE;
+}
+
+static void gtkTreeDragBegin(GtkWidget *widget, GdkDragContext *context, Ihandle* ih)
+{
+ int x = iupAttribGetInt(ih, "_IUPTREE_DRAG_X");
+ int y = iupAttribGetInt(ih, "_IUPTREE_DRAG_Y");
+ GtkTreePath* path;
+ GtkTreeViewDropPosition pos;
+ if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(ih->handle), x, y, &path, &pos))
+ {
+ if ((pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE || pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER))
+ {
+ GdkPixmap* pixmap;
+ iupAttribSetStr(ih, "_IUPTREE_DRAGITEM", (char*)path);
+
+ pixmap = gtk_tree_view_create_row_drag_icon(GTK_TREE_VIEW(ih->handle), path);
+ gtk_drag_source_set_icon(widget, gtk_widget_get_colormap(widget), pixmap, NULL);
+ g_object_unref(pixmap);
+ return;
+ }
+ }
+
+ (void)context;
+ (void)widget;
+}
+
+static void gtkTreeSelectionChanged(GtkTreeSelection* selection, Ihandle* ih)
+{
+ IFnii cbSelec;
+ int is_ctrl = 0;
+
+ if (ih->data->mark_mode == ITREE_MARK_MULTIPLE)
+ {
+ char key[5];
+ iupdrvGetKeyState(key);
+ if (key[0] == 'S')
+ return;
+ else if (key[1] == 'C')
+ is_ctrl = 1;
+
+ if (iupAttribGetInt(ih, "_IUPTREE_EXTENDSELECT")==2 && !is_ctrl)
+ {
+ iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", NULL);
+ gtkTreeCallMultiSelectionCb(ih);
+ return;
+ }
+ }
+
+ cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB");
+ if (cbSelec)
+ {
+ int curpos = -1, is_selected = 0;
+
+ if (iupAttribGet(ih, "_IUP_IGNORE_SELECTION"))
+ {
+ iupAttribSetStr(ih, "_IUP_IGNORE_SELECTION", NULL);
+ return;
+ }
+
+ {
+ GtkTreeIter iterFocus;
+ GtkTreePath* pathFocus;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL);
+ if (pathFocus)
+ {
+ gtk_tree_model_get_iter(model, &iterFocus, pathFocus);
+ gtk_tree_path_free(pathFocus);
+ curpos = gtkTreeGetNodeId(ih, iterFocus);
+ is_selected = gtk_tree_selection_iter_is_selected(selection, &iterFocus);
+ }
+ }
+
+ if (curpos == -1)
+ return;
+
+ if (is_ctrl)
+ cbSelec(ih, curpos, is_selected);
+ else
+ {
+ int oldpos = iupAttribGetInt(ih, "_IUPTREE_OLDVALUE");
+ if(oldpos != curpos)
+ {
+ cbSelec(ih, oldpos, 0); /* unselected */
+ cbSelec(ih, curpos, 1); /* selected */
+
+ iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", curpos);
+ }
+ }
+ }
+}
+
+static gboolean gtkTreeTestExpandRow(GtkTreeView* tree_view, GtkTreeIter *iterItem, GtkTreePath *path, Ihandle* ih)
+{
+ IFni cbBranchOpen = (IFni)IupGetCallback(ih, "BRANCHOPEN_CB");
+ if (cbBranchOpen)
+ {
+ if (iupAttribGet(ih, "_IUPTREE_IGNORE_BRANCHOPEN_CB"))
+ {
+ iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCHOPEN_CB", NULL);
+ return FALSE;
+ }
+
+ if (cbBranchOpen(ih, gtkTreeGetNodeId(ih, *iterItem)) == IUP_IGNORE)
+ return TRUE; /* prevent the change */
+ }
+
+ (void)path;
+ (void)tree_view;
+ return FALSE;
+}
+
+static gboolean gtkTreeTestCollapseRow(GtkTreeView* tree_view, GtkTreeIter *iterItem, GtkTreePath *path, Ihandle* ih)
+{
+ IFni cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB");
+ if (cbBranchClose)
+ {
+ if (cbBranchClose(ih, gtkTreeGetNodeId(ih, *iterItem)) == IUP_IGNORE)
+ return TRUE;
+ }
+
+ (void)path;
+ (void)tree_view;
+ return FALSE;
+}
+
+static void gtkTreeRowActived(GtkTreeView* tree_view, GtkTreePath *path, GtkTreeViewColumn *column, Ihandle* ih)
+{
+ GtkTreeIter iterItem;
+ GtkTreeModel* model;
+ int kind; /* used for nodes defined as branches, but do not have children */
+ IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB");
+ if (!cbExecuteLeaf)
+ return;
+
+ model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ gtk_tree_model_get_iter(model, &iterItem, path);
+ gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1);
+
+ /* just to leaf nodes */
+ if(gtk_tree_model_iter_has_child(model, &iterItem) == 0 && kind == ITREE_LEAF)
+ cbExecuteLeaf(ih, gtkTreeGetNodeId(ih, iterItem));
+
+ (void)column;
+ (void)tree_view;
+}
+
+static int gtkTreeConvertXYToPos(Ihandle* ih, int x, int y)
+{
+ GtkTreePath* path;
+ if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(ih->handle), x, y, &path, NULL))
+ {
+ GtkTreeIter iterItem;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ gtk_tree_model_get_iter(model, &iterItem, path);
+ gtk_tree_path_free (path);
+ return gtkTreeGetNodeId(ih, iterItem);
+ }
+ return -1;
+}
+
+static gboolean gtkTreeButtonEvent(GtkWidget *treeview, GdkEventButton *evt, Ihandle* ih)
+{
+ if (iupgtkButtonEvent(treeview, evt, ih) == TRUE)
+ return TRUE;
+
+ if (evt->type == GDK_BUTTON_PRESS && evt->button == 3) /* right single click */
+ {
+ IFni cbRightClick = (IFni)IupGetCallback(ih, "RIGHTCLICK_CB");
+ if (cbRightClick)
+ {
+ int id = gtkTreeConvertXYToPos(ih, (int)evt->x, (int)evt->y);
+ if (id != -1)
+ cbRightClick(ih, id);
+ return TRUE;
+ }
+ }
+ else if (evt->type == GDK_2BUTTON_PRESS && evt->button == 1) /* left double click */
+ {
+ GtkTreePath *path;
+
+ if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview), (gint) evt->x, (gint) evt->y, &path, NULL, NULL, NULL))
+ {
+ GtkTreeIter iter;
+ GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle));
+ int kind; /* used for nodes defined as branches, but do not have children */
+
+ gtk_tree_model_get_iter(model, &iter, path);
+ gtk_tree_model_get(model, &iter, IUPGTK_TREE_KIND, &kind, -1);
+
+ if (kind == ITREE_BRANCH)
+ gtkTreeExpandItem(ih, path, -1); /* toggle */
+
+ gtk_tree_path_free(path);
+ }
+ }
+ else if (evt->type == GDK_BUTTON_RELEASE && evt->button == 1) /* left single release */
+ {
+ if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && (evt->state & GDK_SHIFT_MASK))
+ gtkTreeCallMultiSelectionCb(ih); /* Multi Selection Callback */
+
+ if (ih->data->mark_mode==ITREE_MARK_MULTIPLE &&
+ !(evt->state & GDK_SHIFT_MASK) && !(evt->state & GDK_CONTROL_MASK))
+ {
+ if (iupAttribGet(ih, "_IUPTREE_EXTENDSELECT"))
+ iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", "2");
+ }
+ }
+ else if (evt->type == GDK_BUTTON_PRESS && evt->button == 1) /* left single press */
+ {
+ iupAttribSetInt(ih, "_IUPTREE_DRAG_X", (int)evt->x);
+ iupAttribSetInt(ih, "_IUPTREE_DRAG_Y", (int)evt->y);
+
+ if (ih->data->mark_mode==ITREE_MARK_MULTIPLE &&
+ !(evt->state & GDK_SHIFT_MASK) && !(evt->state & GDK_CONTROL_MASK))
+ iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", "1");
+ }
+
+ return FALSE;
+}
+
+static gboolean gtkTreeKeyReleaseEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
+{
+ if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && (evt->state & GDK_SHIFT_MASK))
+ {
+ if (evt->keyval == GDK_Up || evt->keyval == GDK_Down || evt->keyval == GDK_Home || evt->keyval == GDK_End)
+ gtkTreeCallMultiSelectionCb(ih); /* Multi Selection Callback */
+ }
+
+ (void)widget;
+ return TRUE;
+}
+
+static gboolean gtkTreeKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
+{
+ if (iupgtkKeyPressEvent(widget, evt, ih) == TRUE)
+ return TRUE;
+
+ if (evt->keyval == GDK_F2)
+ {
+ gtkTreeSetRenameAttrib(ih, NULL);
+ return TRUE;
+ }
+ else if (evt->keyval == GDK_Return || evt->keyval == GDK_KP_Enter)
+ {
+ gtkTreeOpenCloseEvent(ih);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void gtkTreeEnableDragDrop(Ihandle* ih)
+{
+ const GtkTargetEntry row_targets[] = {
+ { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
+ };
+
+ if (iupAttribGetBoolean(ih, "AUTODRAGDROP"))
+ {
+ gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW(ih->handle),
+ GDK_BUTTON1_MASK,
+ row_targets,
+ G_N_ELEMENTS(row_targets),
+ GDK_ACTION_MOVE|GDK_ACTION_COPY);
+ gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW(ih->handle),
+ row_targets,
+ G_N_ELEMENTS(row_targets),
+ GDK_ACTION_MOVE|GDK_ACTION_COPY);
+ }
+ else
+ {
+ gtk_drag_source_set(ih->handle, GDK_BUTTON1_MASK, row_targets, G_N_ELEMENTS(row_targets), GDK_ACTION_MOVE|GDK_ACTION_COPY);
+ gtk_drag_dest_set(ih->handle, GDK_BUTTON1_MASK, row_targets, G_N_ELEMENTS(row_targets), GDK_ACTION_MOVE|GDK_ACTION_COPY);
+
+ g_signal_connect(G_OBJECT(ih->handle), "drag-begin", G_CALLBACK(gtkTreeDragBegin), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "drag-motion", G_CALLBACK(gtkTreeDragMotion), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "drag-leave", G_CALLBACK(gtkTreeDragLeave), NULL);
+ g_signal_connect(G_OBJECT(ih->handle), "drag-drop", G_CALLBACK(gtkTreeDragDrop), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "drag-data-received", G_CALLBACK(gtkTreeDragDataReceived), ih);
+ }
+}
+
+/*****************************************************************************/
+
+static int gtkTreeMapMethod(Ihandle* ih)
+{
+ GtkScrolledWindow* scrolled_window = NULL;
+ GtkTreeStore *store;
+ GtkCellRenderer *renderer_img, *renderer_txt;
+ GtkTreeSelection* selection;
+ GtkTreeViewColumn *column;
+
+ store = gtk_tree_store_new(9, GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN,
+ G_TYPE_STRING, G_TYPE_INT, GDK_TYPE_COLOR, PANGO_TYPE_FONT_DESCRIPTION, G_TYPE_POINTER);
+
+ ih->handle = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
+
+ g_object_unref(store);
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ scrolled_window = (GtkScrolledWindow*)gtk_scrolled_window_new(NULL, NULL);
+ iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)scrolled_window);
+
+ /* Column and renderers */
+ column = gtk_tree_view_column_new();
+ iupAttribSetStr(ih, "_IUPGTK_COLUMN", (char*)column);
+
+ renderer_img = gtk_cell_renderer_pixbuf_new();
+ gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(column), renderer_img, FALSE);
+ gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(column), renderer_img, "pixbuf", IUPGTK_TREE_IMAGE,
+ "pixbuf-expander-open", IUPGTK_TREE_IMAGE_EXPANDED,
+ "pixbuf-expander-closed", IUPGTK_TREE_IMAGE,
+ NULL);
+ iupAttribSetStr(ih, "_IUPGTK_RENDERER_IMG", (char*)renderer_img);
+
+ renderer_txt = gtk_cell_renderer_text_new();
+ gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(column), renderer_txt, TRUE);
+ gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(column), renderer_txt, "text", IUPGTK_TREE_TITLE,
+ "is-expander", IUPGTK_TREE_KIND,
+ "font-desc", IUPGTK_TREE_FONT,
+ "foreground-gdk", IUPGTK_TREE_COLOR,
+ NULL);
+ iupAttribSetStr(ih, "_IUPGTK_RENDERER_TEXT", (char*)renderer_txt);
+
+ if (ih->data->show_rename)
+ g_object_set(G_OBJECT(renderer_txt), "editable", TRUE, NULL);
+
+ g_object_set(G_OBJECT(renderer_txt), "xpad", 0, NULL);
+ g_object_set(G_OBJECT(renderer_txt), "ypad", 0, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(ih->handle), column);
+
+ gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(ih->handle), FALSE);
+ gtk_tree_view_set_enable_search(GTK_TREE_VIEW(ih->handle), FALSE);
+
+#if GTK_CHECK_VERSION(2, 10, 0)
+ if (iupAttribGetBoolean(ih, "HIDELINES"))
+ gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(ih->handle), FALSE);
+ else
+ gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(ih->handle), TRUE);
+#endif
+
+#if GTK_CHECK_VERSION(2, 12, 0)
+ if (iupAttribGetBoolean(ih, "HIDEBUTTONS"))
+ gtk_tree_view_set_show_expanders(GTK_TREE_VIEW(ih->handle), FALSE);
+ else
+ gtk_tree_view_set_show_expanders(GTK_TREE_VIEW(ih->handle), TRUE);
+#endif
+
+ if (ih->data->show_dragdrop)
+ gtkTreeEnableDragDrop(ih);
+
+ gtk_container_add((GtkContainer*)scrolled_window, ih->handle);
+ gtk_widget_show((GtkWidget*)scrolled_window);
+ gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_IN);
+
+ gtk_scrolled_window_set_policy(scrolled_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle));
+
+ gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
+ gtk_tree_view_set_reorderable(GTK_TREE_VIEW(ih->handle), FALSE);
+
+ /* callbacks */
+ g_signal_connect(selection, "changed", G_CALLBACK(gtkTreeSelectionChanged), ih);
+
+ g_signal_connect(renderer_txt, "editing-started", G_CALLBACK(gtkTreeCellTextEditingStarted), ih);
+ g_signal_connect(renderer_txt, "edited", G_CALLBACK(gtkTreeCellTextEdited), ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "motion-notify-event",G_CALLBACK(iupgtkMotionNotifyEvent), ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "test-expand-row", G_CALLBACK(gtkTreeTestExpandRow), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "test-collapse-row", G_CALLBACK(gtkTreeTestCollapseRow), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "row-activated", G_CALLBACK(gtkTreeRowActived), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(gtkTreeKeyPressEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "key-release-event", G_CALLBACK(gtkTreeKeyReleaseEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "button-press-event", G_CALLBACK(gtkTreeButtonEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "button-release-event",G_CALLBACK(gtkTreeButtonEvent), ih);
+
+ /* add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ if (!iupAttribGetBoolean(ih, "CANFOCUS"))
+ GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS;
+
+ gtk_widget_realize((GtkWidget*)scrolled_window);
+ gtk_widget_realize(ih->handle);
+
+ /* Initialize the default images */
+ ih->data->def_image_leaf = iupImageGetImage("IMGLEAF", ih, 0);
+ ih->data->def_image_collapsed = iupImageGetImage("IMGCOLLAPSED", ih, 0);
+ ih->data->def_image_expanded = iupImageGetImage("IMGEXPANDED", ih, 0);
+
+ gtkTreeAddRootNode(ih);
+
+ /* configure for DRAG&DROP of files */
+ if (IupGetCallback(ih, "DROPFILES_CB"))
+ iupAttribSetStr(ih, "DRAGDROP", "YES");
+
+ IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)gtkTreeConvertXYToPos);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvTreeInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkTreeMapMethod;
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkTreeSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, gtkTreeSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT);
+
+ /* IupTree Attributes - GENERAL */
+ iupClassRegisterAttribute(ic, "EXPANDALL", NULL, gtkTreeSetExpandAllAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "INDENTATION", gtkTreeGetIndentationAttrib, gtkTreeSetIndentationAttrib, NULL, NULL, IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "COUNT", gtkTreeGetCountAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupgtkSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPACING", iupTreeGetSpacingAttrib, gtkTreeSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "TOPITEM", NULL, gtkTreeSetTopItemAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+
+ /* IupTree Attributes - IMAGES */
+ iupClassRegisterAttributeId(ic, "IMAGE", NULL, gtkTreeSetImageAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "IMAGEEXPANDED", NULL, gtkTreeSetImageExpandedAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "IMAGELEAF", NULL, gtkTreeSetImageLeafAttrib, IUPAF_SAMEASSYSTEM, "IMGLEAF", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGEBRANCHCOLLAPSED", NULL, gtkTreeSetImageBranchCollapsedAttrib, IUPAF_SAMEASSYSTEM, "IMGCOLLAPSED", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGEBRANCHEXPANDED", NULL, gtkTreeSetImageBranchExpandedAttrib, IUPAF_SAMEASSYSTEM, "IMGEXPANDED", IUPAF_NO_INHERIT);
+
+ /* IupTree Attributes - NODES */
+ iupClassRegisterAttributeId(ic, "STATE", gtkTreeGetStateAttrib, gtkTreeSetStateAttrib, IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "DEPTH", gtkTreeGetDepthAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "KIND", gtkTreeGetKindAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "PARENT", gtkTreeGetParentAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "COLOR", gtkTreeGetColorAttrib, gtkTreeSetColorAttrib, IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "NAME", gtkTreeGetTitleAttrib, gtkTreeSetTitleAttrib, IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "TITLE", gtkTreeGetTitleAttrib, gtkTreeSetTitleAttrib, IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "USERDATA", gtkTreeGetUserDataAttrib, gtkTreeSetUserDataAttrib, IUPAF_NO_STRING|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttributeId(ic, "CHILDCOUNT", gtkTreeGetChildCountAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "TITLEFONT", gtkTreeGetTitleFontAttrib, gtkTreeSetTitleFontAttrib, IUPAF_NO_INHERIT);
+
+ /* IupTree Attributes - MARKS */
+ iupClassRegisterAttributeId(ic, "MARKED", gtkTreeGetMarkedAttrib, gtkTreeSetMarkedAttrib, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute (ic, "MARK", NULL, gtkTreeSetMarkAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute (ic, "STARTING", NULL, gtkTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute (ic, "MARKSTART", NULL, gtkTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute (ic, "VALUE", gtkTreeGetValueAttrib, gtkTreeSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupTree Attributes - ACTION */
+ iupClassRegisterAttributeId(ic, "DELNODE", NULL, gtkTreeSetDelNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "RENAME", NULL, gtkTreeSetRenameAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "MOVENODE", NULL, gtkTreeSetMoveNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "COPYNODE", NULL, gtkTreeSetCopyNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "FINDUSERDATA", gtkTreeGetFindUserDataAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute (ic, "AUTODRAGDROP", NULL, NULL, NULL, NULL, IUPAF_DEFAULT);
+}
diff --git a/iup/src/gtk/iupgtk_val.c b/iup/src/gtk/iupgtk_val.c
new file mode 100755
index 0000000..018af83
--- /dev/null
+++ b/iup/src/gtk/iupgtk_val.c
@@ -0,0 +1,208 @@
+/** \file
+ * \brief Valuator Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_val.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_key.h"
+
+#include "iupgtk_drv.h"
+
+
+void iupdrvValGetMinSize(Ihandle* ih, int *w, int *h)
+{
+ if (ih->data->type == IVAL_HORIZONTAL)
+ {
+ *w = 20;
+ *h = 35;
+ }
+ else
+ {
+ *w = 35;
+ *h = 20;
+ }
+}
+
+static int gtkValSetStepAttrib(Ihandle* ih, const char* value)
+{
+ ih->data->step = atof(value);
+ gtk_range_set_increments(GTK_RANGE(ih->handle), ih->data->step, ih->data->pagestep);
+ return 0; /* do not store value in hash table */
+}
+
+static int gtkValSetPageStepAttrib(Ihandle* ih, const char* value)
+{
+ ih->data->pagestep = atof(value);
+ gtk_range_set_increments(GTK_RANGE(ih->handle), ih->data->step, ih->data->pagestep);
+ return 0; /* do not store value in hash table */
+}
+
+static int gtkValSetValueAttrib(Ihandle* ih, const char* value)
+{
+ double fval;
+ ih->data->val = atof(value);
+ fval = (ih->data->val-ih->data->vmin)/(ih->data->vmax - ih->data->vmin);
+ gtk_range_set_value(GTK_RANGE(ih->handle), fval);
+ return 0; /* do not store value in hash table */
+}
+
+
+/*********************************************************************************************/
+
+
+static gboolean gtkValChangeValue(GtkRange *range, GtkScrollType scroll, double fval, Ihandle *ih)
+{
+ double old_val = ih->data->val;
+ IFn cb;
+
+ if (fval < 0.0)
+ gtk_range_set_value(GTK_RANGE(ih->handle), 0.0);
+ if (fval > 1.0)
+ gtk_range_set_value(GTK_RANGE(ih->handle), 1.0);
+
+ ih->data->val = fval*(ih->data->vmax - ih->data->vmin) + ih->data->vmin;
+ iupValCropValue(ih);
+
+ cb = (IFn)IupGetCallback(ih, "VALUECHANGED_CB");
+ if (cb)
+ {
+ if (ih->data->val == old_val)
+ return FALSE;
+
+ cb(ih);
+ }
+ else
+ {
+ IFnd cb_old;
+ if (scroll == GTK_SCROLL_JUMP) /* scroll == 1 */
+ cb_old = (IFnd)IupGetCallback(ih, "MOUSEMOVE_CB");
+ else if((scroll >= GTK_SCROLL_STEP_BACKWARD) && (scroll <= GTK_SCROLL_END))
+ cb_old = (IFnd)IupGetCallback(ih, "BUTTON_PRESS_CB");
+ else
+ cb_old = (IFnd)IupGetCallback(ih, "BUTTON_RELEASE_CB");
+ if (cb_old)
+ cb_old(ih, ih->data->val);
+ }
+
+ if (fval < 0.0 || fval > 1.0)
+ return TRUE;
+
+ (void)range;
+ return FALSE;
+}
+
+static gboolean gtkValKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
+{
+ if (iupgtkKeyPressEvent(widget, evt, ih) == TRUE)
+ return TRUE;
+
+ /* change Home and End default behaviour */
+ if (ih->data->inverted)
+ {
+ if (evt->keyval==GDK_Home || evt->keyval==GDK_KP_Home)
+ {
+ /* set to maximum */
+ gtk_range_set_value(GTK_RANGE(ih->handle), 1.0);
+ gtkValChangeValue(GTK_RANGE(ih->handle), GTK_SCROLL_START, 1.0, ih);
+ return TRUE;
+ }
+ if (evt->keyval==GDK_End || evt->keyval==GDK_KP_End)
+ {
+ /* set to minimum */
+ gtk_range_set_value(GTK_RANGE(ih->handle), 0.0);
+ gtkValChangeValue(GTK_RANGE(ih->handle), GTK_SCROLL_END, 0.0, ih);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*********************************************************************************************/
+
+
+static int gtkValMapMethod(Ihandle* ih)
+{
+ GtkObject *adjustment;
+
+ /* value, lower, upper, step_increment, page_increment, page_size */
+ /* page_size value only makes a difference for scrollbar widgets */
+ adjustment = gtk_adjustment_new (0, 0, 1.0, 0.01, 0.1, 0);
+ if (!adjustment)
+ return IUP_ERROR;
+
+ if (ih->data->type == IVAL_HORIZONTAL)
+ ih->handle = gtk_hscale_new(GTK_ADJUSTMENT(adjustment));
+ else
+ ih->handle = gtk_vscale_new(GTK_ADJUSTMENT(adjustment));
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ /* add to the parent, all GTK controls must call this. */
+ iupgtkBaseAddToParent(ih);
+
+ if (!iupAttribGetBoolean(ih, "CANFOCUS"))
+ GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS;
+
+ g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih);
+
+ g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(gtkValKeyPressEvent), ih);
+ g_signal_connect(G_OBJECT(ih->handle), "change-value", G_CALLBACK(gtkValChangeValue), ih);
+
+ /* configure the scale */
+ gtk_scale_set_draw_value(GTK_SCALE(ih->handle), FALSE);
+ gtk_range_set_range(GTK_RANGE(ih->handle), 0.0, 1.0);
+
+ if (ih->data->inverted)
+ gtk_range_set_inverted(GTK_RANGE(ih->handle), TRUE);
+
+ gtk_widget_realize(ih->handle);
+
+ /* update a mnemonic in a label if necessary */
+ iupgtkUpdateMnemonic(ih);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvValInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = gtkValMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+
+ /* IupVal only */
+ iupClassRegisterAttribute(ic, "VALUE", iupValGetValueAttrib, gtkValSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "PAGESTEP", iupValGetPageStepAttrib, gtkValSetPageStepAttrib, IUPAF_SAMEASSYSTEM, "0.1", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "STEP", iupValGetStepAttrib, gtkValSetStepAttrib, IUPAF_SAMEASSYSTEM, "0.01", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SHOWTICKS", NULL, NULL, NULL, NULL, IUPAF_WRITEONLY|IUPAF_READONLY); /* showticks is not supported in GTK */
+}