--- /dev/null
+
+// see google codesearch for MOZ_GTK_SUCCESS and ensure_checkbox_widget
+
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <glib/gprintf.h>
+
+#include <tk.h>
+
+/* Are we part of tile, or Tk... */
+#ifdef BUILD_tile
+#include "tkTheme.h"
+#define TTK_VERSION PACKAGE_VERSION
+#else
+#include "ttkTheme.h"
+#endif
+
+#include <string.h>
+
+typedef enum WIDGET_TYPE {
+ WIDGET_GTK_WINDOW,
+ WIDGET_GTK_BUTTON,
+ WIDGET_GTK_CHECKBUTTON,
+ WIDGET_GTK_RADIOBUTTON,
+} WIDGET_TYPE;
+
+typedef struct ThemeData {
+ GtkWidget *widget[4];
+ GtkWidget *container[4];
+} ThemeData;
+
+static Ttk_StateTable button_statemap[] =
+{
+ { GTK_STATE_INSENSITIVE, TTK_STATE_DISABLED, 0 },
+ { GTK_STATE_ACTIVE, TTK_STATE_PRESSED, 0 },
+ //{ GTK_STATE_SELECTED, TTK_STATE_FOCUS, 0 },
+ { GTK_STATE_PRELIGHT, TTK_STATE_ACTIVE, 0 },
+ { GTK_STATE_NORMAL, 0, 0 }
+};
+
+static Ttk_StateTable button_shadowmap[] = {
+ { GTK_SHADOW_IN, TTK_STATE_PRESSED, 0 },
+ { GTK_SHADOW_OUT, 0, 0 }
+};
+
+/* ---------------------------------------------------------------------- */
+/* From some mozilla code */
+
+static gint
+TSOffsetStyleGCArray(GdkGC** gcs, gint xorigin, gint yorigin)
+{
+ int i;
+ /* there are 5 gc's in each array, for each of the widget states */
+ for (i = 0; i < 5; ++i)
+ gdk_gc_set_ts_origin(gcs[i], xorigin, yorigin);
+ return 0;
+}
+
+static gint
+TSOffsetStyleGCs(GtkStyle* style, gint xorigin, gint yorigin)
+{
+ TSOffsetStyleGCArray(style->fg_gc, xorigin, yorigin);
+ TSOffsetStyleGCArray(style->bg_gc, xorigin, yorigin);
+ TSOffsetStyleGCArray(style->light_gc, xorigin, yorigin);
+ TSOffsetStyleGCArray(style->dark_gc, xorigin, yorigin);
+ TSOffsetStyleGCArray(style->mid_gc, xorigin, yorigin);
+ TSOffsetStyleGCArray(style->text_gc, xorigin, yorigin);
+ TSOffsetStyleGCArray(style->base_gc, xorigin, yorigin);
+ gdk_gc_set_ts_origin(style->black_gc, xorigin, yorigin);
+ gdk_gc_set_ts_origin(style->white_gc, xorigin, yorigin);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------
+ * Gtk+ element
+ *
+ */
+
+typedef struct ElementInfo {
+ const char *elementName;
+ //GtkWidget*(*createWidget)();
+ int id;
+ Ttk_ElementSpec *elementSpec;
+} ElementInfo;
+
+typedef struct ElementData {
+ GtkWidget *widget;
+ GtkStyle *style;
+ ElementInfo *info;
+} ElementData;
+
+static ElementData *
+NewElementData(ElementInfo *infoPtr, ThemeData *themeData)
+{
+ ElementData *elementData = (ElementData *)ckalloc(sizeof(ElementData));
+ elementData->info = infoPtr;
+ elementData->widget = themeData->widget[infoPtr->id];
+#if 1
+ if (infoPtr->id == WIDGET_GTK_WINDOW) {
+ gtk_widget_realize(elementData->widget);
+ themeData->container[infoPtr->id] = NULL;
+ } else {
+ GtkWidget *w = gtk_window_new(GTK_WINDOW_POPUP);
+ themeData->container[infoPtr->id] = w;
+ gtk_widget_realize(w);
+ gtk_container_add(GTK_CONTAINER(w), elementData->widget);
+ gtk_widget_realize(elementData->widget);
+ elementData->style = w->style;
+ }
+#else
+ gtk_widget_ensure_style(elementData->widget);
+ elementData->style = gtk_rc_get_style(elementData->widget);
+#endif
+ return elementData;
+}
+
+static void
+DestroyElementData(void *clientData)
+{
+ ElementData *elementData = clientData;
+ gtk_widget_destroy(elementData->widget);
+ g_object_unref(G_OBJECT(elementData->style));
+ ckfree(clientData);
+}
+
+static void
+GenericElementGeometry(void *clientData, void *elementRecord, Tk_Window tkwin,
+ int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
+{
+ ElementData *elementData = clientData;
+ gint size = 0, space = 0;
+
+ switch (elementData->info->id) {
+ case WIDGET_GTK_CHECKBUTTON:
+ case WIDGET_GTK_RADIOBUTTON: {
+ gtk_widget_style_get(elementData->widget,
+ "indicator_size", &size,
+ "indicator_spacing", &space, NULL);
+ *widthPtr = size ; *heightPtr = size;
+ break;
+ }
+ }
+}
+
+static void
+GenericElementDraw(void *clientData, void *elementRecord, Tk_Window tkwin,
+ Drawable d, Ttk_Box b, unsigned int state)
+{
+ ElementData *elementData = clientData;
+ GdkDisplay *gdkdisplay = 0;
+ GdkWindow *gdkdrawable = 0;
+ GtkStyle *style = 0;
+
+ gdkdisplay = gdk_x11_lookup_xdisplay(Tk_Display(tkwin));
+ if (gdkdisplay == NULL) {
+ gdkdisplay = gdk_display_get_default();
+ }
+ if (gdkdisplay == NULL) {
+ g_printf("GenericDrawElement: failed to get display\n");
+ }
+ gdkdrawable = gdk_window_foreign_new_for_display(gdkdisplay, Tk_WindowId(tkwin));
+ style = gtk_style_attach(elementData->style, gdkdrawable);
+ TSOffsetStyleGCs(style, b.x, b.y);
+ switch (elementData->info->id) {
+ case WIDGET_GTK_CHECKBUTTON: {
+ GtkShadowType gshadow = (GtkShadowType)Ttk_StateTableLookup(button_shadowmap, state);
+ //GtkShadowType gshadow = (state & TTK_STATE_SELECTED)?GTK_SHADOW_IN:GTK_SHADOW_OUT;
+ GtkStateType gstate = (GtkStateType)Ttk_StateTableLookup(button_statemap, state);
+ GTK_TOGGLE_BUTTON(elementData->widget)->active = (state & TTK_STATE_SELECTED);
+ if (state & TTK_STATE_FOCUS) {
+ GTK_WIDGET_SET_FLAGS(elementData->widget, GTK_HAS_FOCUS);
+ } else {
+ GTK_WIDGET_UNSET_FLAGS(elementData->widget, GTK_HAS_FOCUS);
+ }
+ gtk_paint_check(style, gdkdrawable, gstate, gshadow,
+ NULL, elementData->widget, "cellcheck",
+ b.x, b.y, b.width, b.height);
+ break;
+ }
+ case WIDGET_GTK_RADIOBUTTON: {
+ GtkShadowType gshadow = (GtkShadowType)Ttk_StateTableLookup(button_shadowmap, state);
+ //GtkShadowType gshadow = (state & TTK_STATE_SELECTED)?GTK_SHADOW_IN:GTK_SHADOW_OUT;
+ GtkStateType gstate = (GtkStateType)Ttk_StateTableLookup(button_statemap, state);
+ GTK_TOGGLE_BUTTON(elementData->widget)->active = (state & TTK_STATE_SELECTED);
+ if (state & TTK_STATE_FOCUS) {
+ GTK_WIDGET_SET_FLAGS(elementData->widget, GTK_HAS_FOCUS);
+ } else {
+ GTK_WIDGET_UNSET_FLAGS(elementData->widget, GTK_HAS_FOCUS);
+ }
+ gtk_paint_option(style, gdkdrawable, gstate, gshadow,
+ 0, elementData->widget, "radiobutton",
+ b.x, b.y, b.width, b.height);
+ break;
+ }
+ case WIDGET_GTK_BUTTON: {
+ Ttk_Padding p = {-2, -2, -2, -2};
+ //GtkShadowType gshadow = (state & TTK_STATE_PRESSED)
+ // ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
+ GtkShadowType gshadow = (GtkShadowType)Ttk_StateTableLookup(button_shadowmap, state);
+ GtkStateType gstate = (GtkStateType)Ttk_StateTableLookup(button_statemap, state);
+ if (state & TTK_STATE_FOCUS) {
+ GTK_WIDGET_SET_FLAGS(elementData->widget, GTK_HAS_FOCUS);
+ } else {
+ GTK_WIDGET_UNSET_FLAGS(elementData->widget, GTK_HAS_FOCUS);
+ }
+
+ gdk_window_set_back_pixmap(gdkdrawable, NULL, TRUE);
+ gdk_window_clear_area(gdkdrawable, b.x, b.y, b.width, b.height);
+ gtk_widget_set_state(elementData->widget, gstate);
+ gtk_paint_box(style, gdkdrawable, gstate, gshadow,
+ 0, elementData->widget, "button",
+ b.x, b.y, b.width, b.height);
+ Ttk_ExpandBox(b, p);
+ gtk_paint_focus(style, gdkdrawable, gstate,
+ 0, elementData->widget, "button", b.x, b.y, b.width, b.height);
+ break;
+ }
+ }
+ gtk_style_detach(style);
+}
+
+static Ttk_ElementSpec GtkElementSpec =
+{
+ TK_STYLE_VERSION_2,
+ sizeof(NullElement),
+ TtkNullElementOptions,
+ GenericElementGeometry,
+ GenericElementDraw
+};
+
+/* ----------------------------------------------------------------------
+ * Create a Glib event source to link the Tk and Glib event loops
+ */
+
+static int
+EventProc(Tcl_Event *evPtr, int flags)
+{
+ if (!(flags & TCL_WINDOW_EVENTS)) {
+ return 0;
+ }
+ while (gtk_events_pending()) {
+ gtk_main_iteration();
+ }
+ return 1;
+}
+
+static void
+SetupProc(ClientData clientData, int flags) {
+ Tcl_Time block_time = {0, 0};
+ if (!(flags & TCL_WINDOW_EVENTS)) {
+ return;
+ }
+ if (!gtk_events_pending()) {
+ block_time.usec = 10000;
+ }
+ Tcl_SetMaxBlockTime(&block_time);
+ return;
+}
+
+static void
+CheckProc(ClientData clientData, int flags) {
+ if (!(flags & TCL_WINDOW_EVENTS)) {
+ return;
+ }
+ if (gtk_events_pending()) {
+ Tcl_Event *event = (Tcl_Event *)ckalloc(sizeof(Tcl_Event));
+ event->proc = EventProc;
+ Tcl_QueueEvent(event, TCL_QUEUE_TAIL);
+ }
+ return;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void
+DeleteThemeData(void *clientData)
+{
+ /* ThemeData *themeData = clientData; */
+ ckfree(clientData);
+}
+static ElementInfo ElementInfoTable[] = {
+ { "Button.button", WIDGET_GTK_BUTTON, &GtkElementSpec },
+ { "Checkbutton.indicator", WIDGET_GTK_CHECKBUTTON, &GtkElementSpec },
+ { "Radiobutton.indicator", WIDGET_GTK_RADIOBUTTON, &GtkElementSpec },
+ { 0, 0, 0 }
+};
+
+MODULE_SCOPE int
+TtkGtkTheme_Init(Tcl_Interp *interp)
+{
+ ThemeData *themeData;
+ ElementInfo *infoPtr = NULL;
+ Ttk_Theme theme = NULL, parent = NULL;
+
+ parent = Ttk_GetTheme(interp, "clam");
+ theme = Ttk_CreateTheme(interp, "gtk", parent);
+
+ if (!theme) {
+ printf("failed to create gtk theme\n");
+ return TCL_ERROR;
+ }
+
+ // LoadGtkThemeProcs();
+ themeData = (ThemeData *)ckalloc(sizeof(ThemeData));
+ Ttk_RegisterCleanup(interp, themeData, DeleteThemeData);
+
+ /*
+ * Initialize the Gtk+ library
+ */
+
+ gtk_init_check(0, NULL);
+
+ //themeData->widget[WIDGET_GTK_WINDOW] = gtk_invisible_new();
+ themeData->widget[WIDGET_GTK_WINDOW] = gtk_window_new(GTK_WINDOW_POPUP);
+ themeData->widget[WIDGET_GTK_BUTTON] = gtk_button_new_with_label("b");
+ themeData->widget[WIDGET_GTK_CHECKBUTTON] = gtk_check_button_new_with_label("c");
+ themeData->widget[WIDGET_GTK_RADIOBUTTON] = gtk_radio_button_new_with_label(NULL, "r");
+
+ /*
+ * Register elements
+ */
+
+ for (infoPtr = ElementInfoTable; infoPtr->elementName != 0; ++infoPtr) {
+ ClientData clientData = NewElementData(infoPtr, themeData);
+ Ttk_RegisterElementSpec(theme, infoPtr->elementName,
+ infoPtr->elementSpec, clientData);
+ Ttk_RegisterCleanup(interp, clientData, DestroyElementData);
+ }
+
+ /*
+ * Create an event source to service Gtk+ events as part of the Tk event system
+ */
+
+ Tcl_CreateEventSource(SetupProc, CheckProc, NULL);
+
+ /*
+ * Register layouts
+ */
+
+
+ Tcl_PkgProvide(interp, "ttk::theme::gtk", TTK_VERSION);
+ return TCL_OK;
+}