/* The TdeGtk Theming Engine for Gtk+.
 * Copyright (C) 2012 Timothy Pearson <kb9vqf@pearsoncomputing.net>
 *
 * This  library is free  software; you can  redistribute it and/or
 * modify it  under  the terms  of the  GNU Lesser  General  Public
 * License  as published  by the Free  Software  Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed  in the hope that it will be useful,
 * but  WITHOUT ANY WARRANTY; without even  the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License  along  with  this library;  if not,  write to  the Free
 * Software Foundation, Inc., 51  Franklin St, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 *
 */

// NOTE
// GTK contains a number of bugs that will interfere with your overall visual experience
// Those that I have reported can be accessed with this link:
// https://bugzilla.gnome.org/buglist.cgi?type0-0-4=substring&emailcc1=1&emailreporter1=1&emaillongdesc1=1&field0-0-0=product&type0-0-1=substring&field0-0-1=component&field0-0-4=longdesc&emailtype1=substring&type0-0-3=substring&query_format=advanced&emailassigned_to1=1&field0-0-3=status_whiteboard&emailqa_contact1=1&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_status=NEEDINFO&bug_status=RESOLVED&bug_status=VERIFIED&field0-0-2=short_desc&email1=kb9vqf%40pearsoncomputing.net&type0-0-0=substring&value0-0-0=gtk%2B&type0-0-2=substring

// FIXME
// This style should use the TDE open/save dialogs instead of the stock Gnome GtkFileChooserDialog
// This is not currently possible in GTK
// See upstream GTK bug #687173

#define TDEGTK_THEME_THEME_DIRECTORY_NAME	"tdegtk"
#define TDEGTK_THEME_CONTROL_FILE_NAME		"tdegtk.css"
#define RC_CACHE_VERSION			TQString("1")
#define DEBUG_PRINT(x)				if (gtk3TQtDebug) printf(x"\n");
#define DEBUG_PRINT_ARGS(x,y)			if (gtk3TQtDebug) printf(x"\n",y);

bool gtk3TQtEnable = false;
int gtk3TQtDebug = false;
bool tde_showIconsOnPushButtons = false;

void initTDESettings();
void writeGtkThemeControlFile(int forceRecreate);

int m_scrollBarSubLineWidth = -1;
bool m_scrollbarBack1 = false;
bool m_scrollbarForward1 = false;
bool m_scrollbarBack2 = false;
bool m_scrollbarForward2 = false;

#include <gmodule.h>
#include <tdemacros.h>

extern "C" {
	#include <gtk/gtk.h>
	
	#include "tdegtk-engine.h"
	
	TDE_EXPORT void theme_init(GTypeModule *module);
	
	TDE_EXPORT void theme_exit(void);
	
	TDE_EXPORT GtkThemingEngine* create_engine(void);
	
	TDE_EXPORT void theme_init(GTypeModule *module) {
		tdegtk_engine_register_types(module);
	}
	
	TDE_EXPORT void theme_exit(void) {
		//
	}
}

#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <utility>
#include <vector>
#include <fstream>
#include <sstream>

#include <tqpainter.h>
#include <tqapplication.h>
#include <tqdir.h>
#include <tqfile.h>
#include <tqstyle.h>
#include <tqslider.h>
#include <tqscrollbar.h>
#include <tqregexp.h>
#include <tqfont.h>
#include <tqpopupmenu.h>
#include <tqeventloop.h>

#include <tdeapplication.h>
#include <tdecmdlineargs.h>
#include <kiconloader.h>
#include <tdeaboutdata.h>
#include <kicontheme.h>
#include <tdelocale.h>
#include <tdeconfig.h>
#include <tdeglobal.h>
#include <tdeglobalsettings.h>

#include <gdk/gdkx.h>

#include "tdegtk-widgetlookup.h"

extern WidgetLookup m_widgetLookup;

typedef std::pair<std::string, unsigned int> SizePair;
typedef std::vector<SizePair> SizeMap;
SizeMap icon_sizes;

G_MODULE_EXPORT GtkThemingEngine* create_engine(void) {
	gtk3TQtEnable = true;

	gtk3TQtDebug = (getenv("GTK3_TQT_ENGINE_DEBUG") != NULL) ? 1 : 0;
	DEBUG_PRINT("Creating TDEApplication")

	int argc = 1;
	char** argv;
	// Supply it with fake data to keep TDEApplication happy
	argv = (char**) malloc(sizeof(char*));
	argv[0] = (char*) malloc(sizeof(char) * 21);
	strncpy(argv[0], "gtk3-tqt-application", 21);

	TDEAboutData aboutData("gtk3-tqt-engine", I18N_NOOP("gtk3-tqt-engine"), "v0.1",
		"GTK3 TQt theme engine", TDEAboutData::License_GPL,
		"(c) 2012, Timothy Pearson",
		"", 0 /* TODO: Website */, "kb9vqf@pearsoncomputing.net");
	TDECmdLineArgs::init(argc, const_cast<char**>(argv), &aboutData);

	TDEApplication::disableAutoDcopRegistration();
	new TDEApplication(gdk_x11_get_default_xdisplay(), true, 0, 0, true);

	// Propagate glib events to GTK as needed
	if (tqApp) {
		TQEventLoop* loop = tqApp->eventLoop();
		if (loop) {
			loop->setSingleToolkitEventHandling(false);
		}
	}

	initTDESettings();

        // initialize icon sizes
        icon_sizes.push_back(std::make_pair("panel-menu", 16));
        icon_sizes.push_back(std::make_pair("panel", 32));
        icon_sizes.push_back(std::make_pair("gtk-small-toolbar", IconSize(TDEIcon::Toolbar)));
        icon_sizes.push_back(std::make_pair("gtk-large-toolbar", IconSize(TDEIcon::MainToolbar)));
        icon_sizes.push_back(std::make_pair("gtk-dnd", IconSize(TDEIcon::Small)));
        icon_sizes.push_back(std::make_pair("gtk-button", IconSize(TDEIcon::Small)));
        icon_sizes.push_back(std::make_pair("gtk-menu", IconSize(TDEIcon::Small)));
        icon_sizes.push_back(std::make_pair("gtk-dialog", IconSize(TDEIcon::Small)));
        icon_sizes.push_back(std::make_pair("", IconSize(TDEIcon::Small)));

	if (gtk3TQtDebug) {
		writeGtkThemeControlFile(true);
	}
	else {
		writeGtkThemeControlFile(false);
	}

	// Initialize hooks
	m_widgetLookup.initializeHooks();

	return GTK_THEMING_ENGINE (g_object_new (TDEGTK_TYPE_ENGINE, "name", "tdegtk", NULL));
}

// =========================================================================================================
//
// TQt3/GTK Theme Control Functions
//
// =========================================================================================================

TQStringList tdeSearchPaths;
TQString iconTheme;
TQStringList iconThemeDirs;
TQColor alternateBackgroundColour;
int showIconsOnButtons;
int toolbarStyle;

TQString tdeConfigValue(const TQString& section, const TQString& name, const TQString& def) {
	TDEConfig currentConfig;
	currentConfig.setGroup(section);
	return currentConfig.readEntry(name, def);
}

bool tdeBoolConfigValue(const TQString& section, const TQString& name, bool def) {
	TDEConfig currentConfig;
	currentConfig.setGroup(section);
	return currentConfig.readBoolEntry(name, def);
}

TQString tdeFindDir(const TQString& suffix, const TQString& file1, const TQString& file2) {
	for ( TQStringList::Iterator it = tdeSearchPaths.begin(); it != tdeSearchPaths.end(); ++it )
	{
		if ((TQFile::exists((*it) + suffix + file1)) || (TQFile::exists((*it) + suffix + file2)))
			return (*it) + suffix;
	}
	return TQString();
}

TQString runCommand(const TQString& command) {
	FILE* p = popen(command.local8Bit(), "r");
	if (p == NULL) {
		return TQString();
	}
	
	TQString ret;
	while (!feof(p))
	{
		char buffer[256];
		int n = fread(buffer, 1, 255, p);
		buffer[n] = '\0';
		ret += buffer;
	}
	pclose(p);
	
	return ret.stripWhiteSpace();
}

void initTDESettings() {
	tdeSearchPaths.clear();
	
	TQString tdeHome = getenv("TDEHOME");
	TQString tdeDirs = getenv("TDEDIRS");
	TQString tdeDir = getenv("TDEDIR");
	
	if (!tdeHome.isEmpty()) {
		tdeSearchPaths.append(tdeHome);
	}
	tdeSearchPaths.append(runCommand("tde-config --localprefix"));
	
	if (!tdeDirs.isEmpty()) {
		tdeSearchPaths += TQStringList::split(':', tdeDirs);
	}
	if (!tdeDir.isEmpty()) {
		tdeSearchPaths.append(tdeDir);
	}
	tdeSearchPaths.append(runCommand("tde-config --prefix"));
	
	iconTheme = tdeConfigValue("Icons", "Theme", "crystalsvg");
	tde_showIconsOnPushButtons = tdeBoolConfigValue("KDE", "ShowIconsOnPushButtons", false);

	TQStringList back = TQStringList::split(',', tdeConfigValue("General", "alternateBackground", "238,246,255"));
	alternateBackgroundColour.setRgb(back[0].toInt(), back[1].toInt(), back[2].toInt());

	showIconsOnButtons = (tdeConfigValue("KDE", "ShowIconsOnPushButtons", "true").lower() == "true");

	TQString tmp = tdeConfigValue("Toolbar style", "IconText", "true").lower();
	if (tmp == "icononly") {
		toolbarStyle = 0;
	}
	else if (tmp == "icontextright") {
		toolbarStyle = 3;
	}
	else if (tmp == "textonly") {
		toolbarStyle = 1;
	}
	else if (tmp == "icontextbottom") {
		toolbarStyle = 2;
	}
	else {
		// Should never happen, but just in case we fallback to TDE's default "icononly"
		toolbarStyle = 0;
	}
}

void gtk3_tqt_load_resource_string(const char* css_string) {
	GtkCssProvider *provider;

	provider = gtk_css_provider_new();
	gtk_css_provider_load_from_data(provider, css_string, -1, NULL);
	GdkDisplay *display = gdk_display_get_default();
	GdkScreen *screen = gdk_display_get_default_screen(display);
	gtk_style_context_add_provider_for_screen(screen, GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); 
	g_object_unref(provider);

	DEBUG_PRINT_ARGS("gtk3_tqt_load_resource_string(%s)", css_string)
}

void gtk3_tqt_reload_theme_definition_file(const char* filename) {
	GtkCssProvider *provider;
	GError *error = NULL;

	provider = gtk_css_provider_new();
	GdkDisplay *display = gdk_display_get_default();
	GdkScreen *screen = gdk_display_get_default_screen(display);
	gtk_style_context_add_provider_for_screen(screen, GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
	if (!gtk_css_provider_load_from_path(provider, filename, &error)) {
		if (error) {
			g_printerr("[ERROR] %s: error parsing %s: %s\n", G_STRFUNC, filename, error->message);
			g_clear_error(&error);
		}
		else {
			g_printerr("[ERROR] %s: unknown failure parsing %s\n", G_STRFUNC, filename); fflush(stdout);
		}
	}

	g_object_unref(provider);
}

TQString tdeFontToGTKFontString(TQFont font) {
	TQString fontDescriptor = "font: ";
	fontDescriptor.append(font.family());
	if (font.bold()) {
		fontDescriptor.append(" bold");
	}
	if (font.italic()) {
		fontDescriptor.append(" italic");
	}
	if (font.pointSizeFloat() != -1) {
		fontDescriptor.append(TQString(" %1").arg(font.pointSizeFloat()));
	}
	else {
		fontDescriptor.append(TQString(" %1px").arg(font.pixelSize()));
	}

	return fontDescriptor;
}

// Thanks Martin Dvorak of metatheme
TQString parse_rc_string(const TQString& defs, const TQString& pattern, bool widgetClass = true) {
	static int dynamic_counter = 0;
	++dynamic_counter;

	return pattern + " {\n\t" + defs + ";\n}\n\n";
}

GtkIconSet* generateIconSet(const std::string& gtkIconName, const std::string& tdeIconName, TQStringList pathList) {
	if (tdeIconName == "NONE") {
		return 0L;
	}
	
	bool empty = true;
	
	// create iconSet
	GtkIconSet* iconSet = gtk_icon_set_new();

	// loop over iconSizes
	for (SizeMap::const_iterator sizeIter = icon_sizes.begin(); sizeIter != icon_sizes.end(); ++sizeIter) {
		// generate full icon name
		std::ostringstream iconFileStream;
		iconFileStream << sizeIter->second << "x" << sizeIter->second << "/" << tdeIconName;

		// loop over provided path to see if at least one icon is found
		for (TQStringList::const_iterator pathIter = pathList.begin(); pathIter != pathList.end(); ++pathIter) {
			std::string filename((*pathIter + '/' + iconFileStream.str().c_str()).local8Bit());
			if (!std::ifstream(filename.c_str())) {
				continue;
			}

			empty = false;
			GtkIconSource* iconSource(gtk_icon_source_new());
		
			// set name
			gtk_icon_source_set_filename(iconSource, filename.c_str());

			// set direction and state wildcarded
			gtk_icon_source_set_direction_wildcarded(iconSource, TRUE);
			gtk_icon_source_set_state_wildcarded(iconSource, TRUE);

			// set size
			if (sizeIter->first.empty()) {
				gtk_icon_source_set_size_wildcarded(iconSource, TRUE);
			}
			else {
				GtkIconSize size = gtk_icon_size_from_name(sizeIter->first.c_str());
				if (size != GTK_ICON_SIZE_INVALID) {
					gtk_icon_source_set_size_wildcarded(iconSource, FALSE);
					gtk_icon_source_set_size(iconSource, size);
				}
			}

			// add source to iconSet
			gtk_icon_set_add_source(iconSet, iconSource);
			break;
		}
	}

	// if nothing found, return;
	if (empty) {
		gtk_icon_set_unref(iconSet);
		return 0L;
	}
	else {
		return iconSet;
	}

}

void doIconMapping(const char* gtkName, const char * tdeName, GtkIconFactory* factory, TQStringList tdeIconThemeDirs) {
	GtkIconSet* iconSet = generateIconSet(gtkName, tdeName, tdeIconThemeDirs);
	if (iconSet) {
		gtk_icon_factory_add(factory, gtkName, iconSet);
		gtk_icon_set_unref(iconSet);
	}
}

TQString colorString(TQColor color) {
	TQString ret = "rgb(";
	ret += TQString::number(color.red()) + ", ";
	ret += TQString::number(color.green()) + ", ";
	ret += TQString::number(color.blue()) + ")";
	
	return ret;
}

void setColour(TQString name, TQString state, TQColor color, TQString widgetTypes = TQString("*")) {
	state = ":" + state;
	if (state == ":normal") {
		state = "";
	}
	gtk3_tqt_load_resource_string(parse_rc_string(name + ": " + colorString(color), widgetTypes + state).local8Bit());
}

static TQStringList iconInheritsDirs(const TQString& icondir) {
	TQFile index;
	index.setName(icondir + "index.theme");
	if( !index.open( IO_ReadOnly )) {
		index.setName(icondir + "index.desktop");
		if( !index.open( IO_ReadOnly ))
			return TQStringList();
	}
	char buf[1024];
	TQRegExp reg( "^\\s*Inherits=([^\\n]*)" );
	for(;;) {
		if( index.readLine(buf, 1023) <= 0 ) {
			break;
		}
		if( reg.search(buf, 0) >= 0 ) {
			return TQStringList::split(",", reg.cap(1));
		}
	}
	return TQStringList();
}

void addIconThemeDir(const TQString& theme) {
	// Try to find this theme's directory
	TQString icondir = tdeFindDir("/share/icons/" + theme + "/", "index.theme", "index.desktop");
	if(icondir.isEmpty()) {
		return;
	}
	if (iconThemeDirs.contains(icondir)) {
		return;
	}

	// Add this theme to the list
	iconThemeDirs.append(icondir);

	// Do it again for any parent themes
	TQStringList parents = iconInheritsDirs(icondir);
	for ( TQStringList::Iterator it=parents.begin() ; it!=parents.end(); ++it) {
		addIconThemeDir((*it).stripWhiteSpace());
	}
}

void writeGtkThemeControlFile(int forceRecreate) {
	if (!gtk3TQtEnable) {
		return;
	}
	
	DEBUG_PRINT("writeGtkThemeControlFile()")
	
	// Set colors
	// Normal
	setColour("color",            "normal",     tqApp->palette().active().text());
	setColour("background-color", "normal",     tqApp->palette().active().background());
// 	setColour("text",             "normal",     tqApp->palette().active().text());
// 	setColour("base",             "normal",     tqApp->palette().active().base());

	// Active (on)
	setColour("color",            "active",     tqApp->palette().active().text());
	setColour("background-color", "active",     tqApp->palette().active().background());
// 	setColour("text",             "active",     tqApp->palette().active().text());
// 	setColour("base",             "active",     tqApp->palette().active().base());

	// Mouseover
	setColour("color",            "prelight",   tqApp->palette().active().text()); // menu items - change?
	setColour("background-color", "prelight",   tqApp->palette().active().highlight());
// 	setColour("text",             "prelight",   tqApp->palette().active().text());
// 	setColour("base",             "prelight",   tqApp->palette().active().base());

	// Selected
	setColour("color",            "selected",   tqApp->palette().active().highlightedText());
	setColour("background-color", "selected",   tqApp->palette().active().highlight());
// 	setColour("text",             "selected",   tqApp->palette().active().highlightedText());
// 	setColour("base",             "selected",   tqApp->palette().active().highlight());

	// Disabled
	setColour("color",             "insensitive",    tqApp->palette().disabled().text());
	setColour("background-color",  "insensitive",    tqApp->palette().disabled().background());
// 	setColour("text",              "insensitive",    tqApp->palette().disabled().text());
// 	setColour("base",              "insensitive",    tqApp->palette().disabled().background());

	// Menu items
	{
		TQStringList objectTypes;
		objectTypes.append("TQPopupMenu");
		TQPalette objectPalette = tqApp->palette(objectTypes);
		setColour("color", "hover:insensitive", objectPalette.color(TQPalette::Disabled, TQColorGroup::Text), "GtkMenu>GtkMenuItem");
// 		setColour("color", "hover:normal", objectPalette.color(TQPalette::Active, TQColorGroup::HighlightedText), "GtkMenu>GtkMenuItem");
		setColour("color", "hover:active", objectPalette.color(TQPalette::Active, TQColorGroup::HighlightedText), "GtkMenu>GtkMenuItem");
		setColour("color", "hover", objectPalette.color(TQPalette::Active, TQColorGroup::HighlightedText), "GtkMenu>GtkMenuItem *");
	}

	TQString iconSettingsString;
	iconSettingsString.append(TQString("gtk-menu=%1,%2").arg(IconSize(TDEIcon::Small)).arg(IconSize(TDEIcon::Small)));
	iconSettingsString.append(TQString(":gtk-button=%1,%2").arg(IconSize(TDEIcon::Small)).arg(IconSize(TDEIcon::Small)));
	iconSettingsString.append(TQString(":gtk-small-toolbar=%1,%2").arg(IconSize(TDEIcon::Toolbar)).arg(IconSize(TDEIcon::Toolbar)));
	iconSettingsString.append(TQString(":gtk-large-toolbar=%1,%2").arg(IconSize(TDEIcon::MainToolbar)).arg(IconSize(TDEIcon::MainToolbar)));
	iconSettingsString.append(TQString(":gtk-dnd=%1,%2").arg(IconSize(TDEIcon::Small)).arg(IconSize(TDEIcon::Small)));
	iconSettingsString.append(TQString(":gtk-dialog=%1,%2").arg(IconSize(TDEIcon::Small)).arg(IconSize(TDEIcon::Small)));

	// Set up global application settings
	GtkSettings* gtksettings = gtk_settings_get_default();
	GtkSettingsValue svalue;
	if (gtksettings) {
		g_object_set(gtksettings, "gtk-alternative-button-order", TRUE, NULL);
		g_object_set(gtksettings, "gtk-primary-button-warps-slider", FALSE, NULL);
		g_object_set(gtksettings, "gtk-button-images", tde_showIconsOnPushButtons, NULL);
		g_object_set(gtksettings, "gtk-menu-popup-delay", tqApp->style().styleHint(TQStyle::SH_PopupMenu_SubMenuPopupDelay), NULL);
		g_object_set(gtksettings, "gtk-icon-sizes", iconSettingsString.ascii(), NULL);
		// Handle toolbar text display
		if (toolbarStyle == 3) {
			// This is broken by GTK bug #68700
			g_object_set(gtksettings, "gtk-toolbar-style", GTK_TOOLBAR_BOTH_HORIZ, NULL);
		}
		else if (toolbarStyle == 2) {
			g_object_set(gtksettings, "gtk-toolbar-style", GTK_TOOLBAR_BOTH, NULL);
		}
		else if (toolbarStyle == 1) {
			g_object_set(gtksettings, "gtk-toolbar-style", GTK_TOOLBAR_TEXT, NULL);
		}
		else {
			g_object_set(gtksettings, "gtk-toolbar-style", GTK_TOOLBAR_ICONS, NULL);
		}
	}

	// Set up icons
	// Build the list of icon theme directories.
	// This function is recursive - it gets the directories of all the inherited themes as well
	addIconThemeDir(iconTheme);

	if (!iconThemeDirs.isEmpty()) {
		// Create symbolic links from the active icon theme directories to the TDE GTK icon theme names
		TQString fullThemePath;
		for (TQStringList::Iterator it=iconThemeDirs.begin(); it!=iconThemeDirs.end(); ++it) {
			TQString currentDir = (*it);
			if (currentDir.endsWith("/")) {
				currentDir.truncate(currentDir.length()-1);
			}
			if (currentDir.endsWith(iconTheme)) {
				fullThemePath = (*it);
			}
		}
		if (fullThemePath != "") {
			// Create symbolic link...
			TQDir curDir;
			TQString iconThemePath = TQDir::homeDirPath();
			curDir.setPath(iconThemePath);
			if (!curDir.exists()) {
				curDir.mkdir(iconThemePath);
			}
			iconThemePath = iconThemePath + "/.icons/";
			curDir.setPath(iconThemePath);
			if (!curDir.exists()) {
				curDir.mkdir(iconThemePath);
			}
			iconThemePath = iconThemePath + "tdegtk-icon-theme";
			unlink(iconThemePath.ascii());
			symlink(fullThemePath.ascii(), iconThemePath.ascii());
		}
		// FIXME
		// Handle fallback icon theme (tdegtk-fallback-icon-theme)
	}

	if (!iconThemeDirs.isEmpty()) {
		GtkIconFactory* factory;
		factory = gtk_icon_factory_new();
	
		doIconMapping("gtk-about", "actions/about_kde.png", factory, iconThemeDirs);
		doIconMapping("gtk-add", "actions/add.png", factory, iconThemeDirs);
		doIconMapping("gtk-apply", "actions/apply.png", factory, iconThemeDirs);
		doIconMapping("gtk-bold", "actions/text_bold.png", factory, iconThemeDirs);
		doIconMapping("gtk-cancel", "actions/button_cancel.png", factory, iconThemeDirs);
		doIconMapping("gtk-cdrom", "devices/cdrom_unmount.png", factory, iconThemeDirs);
		doIconMapping("gtk-clear", "actions/editclear.png", factory, iconThemeDirs);
		doIconMapping("gtk-close", "actions/fileclose.png", factory, iconThemeDirs);
		doIconMapping("gtk-color-picker", "actions/colorpicker.png", factory, iconThemeDirs);
		doIconMapping("gtk-copy", "actions/editcopy.png", factory, iconThemeDirs);
		doIconMapping("gtk-convert", "actions/gtk-convert.png", factory, iconThemeDirs);
		doIconMapping("gtk-connect", "actions/connect_creating.png", factory, iconThemeDirs);
		doIconMapping("gtk-cut", "actions/editcut.png", factory, iconThemeDirs);
		doIconMapping("gtk-delete", "actions/editdelete.png", factory, iconThemeDirs);
		doIconMapping("gtk-dialog-authentication", "status/gtk-dialog-authentication", factory, iconThemeDirs);
		doIconMapping("gtk-dialog-error", "actions/messagebox_critical.png", factory, iconThemeDirs);
		doIconMapping("gtk-dialog-info", "actions/messagebox_info.png", factory, iconThemeDirs);
		doIconMapping("gtk-dialog-question", "actions/help.png", factory, iconThemeDirs);
		doIconMapping("gtk-dialog-warning", "actions/messagebox_warning.png", factory, iconThemeDirs);
		doIconMapping("gtk-directory", "filesystems/folder.png", factory, iconThemeDirs);
		doIconMapping("gtk-disconnect", "actions/connect_no.png", factory, iconThemeDirs);
		doIconMapping("gtk-dnd", "mimetypes/empty.png", factory, iconThemeDirs);
		doIconMapping("gtk-dnd-multiple", "mimetypes/tdemultiple.png", factory, iconThemeDirs);
		doIconMapping("gtk-edit", "actions/edit.png", factory, iconThemeDirs);  //2.6 
		doIconMapping("gtk-execute", "actions/exec.png", factory, iconThemeDirs);
		doIconMapping("gtk-file", "mimetypes/empty.png", factory, iconThemeDirs);
		doIconMapping("gtk-find", "actions/find.png", factory, iconThemeDirs);
		doIconMapping("gtk-find-and-replace", "actions/find.png", factory, iconThemeDirs);	// Is there a TDE "find and replace" icon? FIXME
		doIconMapping("gtk-floppy", "devices/3floppy_unmount.png", factory, iconThemeDirs);
		doIconMapping("gtk-fullscreen", "actions/window-fullscreen.png", factory, iconThemeDirs);
		doIconMapping("gtk-goto-bottom", "actions/bottom.png", factory, iconThemeDirs);
		doIconMapping("gtk-goto-first", "actions/start.png", factory, iconThemeDirs);
		doIconMapping("gtk-goto-last", "actions/finish.png", factory, iconThemeDirs);
		doIconMapping("gtk-goto-top", "actions/top.png", factory, iconThemeDirs);
		doIconMapping("gtk-go-back", "actions/back.png", factory, iconThemeDirs);
		doIconMapping("gtk-go-down", "actions/down.png", factory, iconThemeDirs);
		doIconMapping("gtk-go-forward", "actions/forward.png", factory, iconThemeDirs);
		doIconMapping("gtk-go-up", "actions/up.png", factory, iconThemeDirs);
		doIconMapping("gtk-harddisk", "devices/hdd_unmount.png", factory, iconThemeDirs);
		doIconMapping("gtk-help", "apps/khelpcenter.png", factory, iconThemeDirs);
		doIconMapping("gtk-home", "filesystems/folder_home.png", factory, iconThemeDirs);
		doIconMapping("gtk-indent", "actions/indent.png", factory, iconThemeDirs);
		doIconMapping("gtk-index", "actions/contents.png", factory, iconThemeDirs);
		doIconMapping("gtk-info", "actions/messagebox_info.png", factory, iconThemeDirs);
		doIconMapping("gtk-italic", "actions/text_italic.png", factory, iconThemeDirs);
		doIconMapping("gtk-jump-to", "actions/goto.png", factory, iconThemeDirs);
		doIconMapping("gtk-justify-center", "actions/text_center.png", factory, iconThemeDirs);
		doIconMapping("gtk-justify-fill", "actions/text_block.png", factory, iconThemeDirs);
		doIconMapping("gtk-justify-left", "actions/text_left.png", factory, iconThemeDirs);
		doIconMapping("gtk-justify-right", "actions/text_right.png", factory, iconThemeDirs);
		doIconMapping("gtk-leave-fullscreen", "actions/window-nofullscreen.png", factory, iconThemeDirs);
		doIconMapping("gtk-media-forward", "player-fwd.png", factory, iconThemeDirs);
		doIconMapping("gtk-media-next", "actions/player-end.png", factory, iconThemeDirs);
		doIconMapping("gtk-media-pause", "actions/player-pause.png", factory, iconThemeDirs);
		doIconMapping("gtk-media-previous", "actions/player-start.png", factory, iconThemeDirs);
		doIconMapping("gtk-media-record", "actions/gtk-media-record.png", factory, iconThemeDirs);	// FIXME
		doIconMapping("gtk-media-rewind", "actions/player-rew.png", factory, iconThemeDirs);
		doIconMapping("gtk-media-stop", "actions/player-stop.png", factory, iconThemeDirs);
		doIconMapping("gtk-missing-image", "mimetypes/unknown.png", factory, iconThemeDirs);
		doIconMapping("gtk-network", "filesystems/network.png", factory, iconThemeDirs);
		doIconMapping("gtk-new", "actions/filenew.png", factory, iconThemeDirs);
		doIconMapping("gtk-no", "actions/gtk-no.png", factory, iconThemeDirs);
		doIconMapping("gtk-ok", "actions/button_ok.png", factory, iconThemeDirs);
		doIconMapping("gtk-open", "actions/fileopen.png", factory, iconThemeDirs);
		//doIconMapping("gtk-orientation-landscape", factory, iconThemeDirs);			// FIXME
		//doIconMapping("gtk-orientation-portrait", factory, iconThemeDirs);			// FIXME
		//doIconMapping("gtk-orientation-reverse-landscape", factory, iconThemeDirs);		// FIXME
		//doIconMapping("gtk-orientation-reverse-portrait"", factory, iconThemeDirs);		// FIXME
		doIconMapping("gtk-paste", "actions/editpaste.png", factory, iconThemeDirs);
		doIconMapping("gtk-preferences", "actions/configure.png", factory, iconThemeDirs);
		doIconMapping("gtk-print", "actions/fileprint.png", factory, iconThemeDirs);
		doIconMapping("gtk-print-preview", "actions/filequickprint.png", factory, iconThemeDirs);
		doIconMapping("gtk-properties", "actions/configure.png", factory, iconThemeDirs);
		doIconMapping("gtk-quit", "actions/exit.png", factory, iconThemeDirs);
		doIconMapping("gtk-redo", "actions/redo.png", factory, iconThemeDirs);
		doIconMapping("gtk-refresh", "actions/reload.png", factory, iconThemeDirs);
		doIconMapping("gtk-remove", "actions/remove.png", factory, iconThemeDirs);
		doIconMapping("gtk-revert-to-saved", "actions/revert.png", factory, iconThemeDirs);
		doIconMapping("gtk-save", "actions/filesave.png", factory, iconThemeDirs);
		doIconMapping("gtk-save-as", "actions/filesaveas.png", factory, iconThemeDirs);
		doIconMapping("gtk-select-all", "actions/gtk-select-all.png", factory, iconThemeDirs);	// FIXME
		doIconMapping("gtk-select-color", "actions/colorize.png", factory, iconThemeDirs);
		doIconMapping("gtk-select-font", "mimetypes/font.png", factory, iconThemeDirs);
		//doIconMapping("gtk-sort-ascending", "??", factory, iconThemeDirs);				// FIXME
		//doIconMapping("gtk-sort-descending", "??", factory, iconThemeDirs);				// FIXME
		doIconMapping("gtk-spell-check", "actions/spellcheck.png", factory, iconThemeDirs);
		doIconMapping("gtk-stop", "actions/stop.png", factory, iconThemeDirs);
		doIconMapping("gtk-strikethrough", "actions/text_strike.png", factory, iconThemeDirs);
		doIconMapping("gtk-undelete", "actions/gtk-undelete.png", factory, iconThemeDirs);		// FIXME
		doIconMapping("gtk-underline", "actions/text_under.png", factory, iconThemeDirs);
		doIconMapping("gtk-undo", "actions/undo.png", factory, iconThemeDirs);
		doIconMapping("gtk-unindent", "actions/unindent.png", factory, iconThemeDirs);
		doIconMapping("gtk-yes", "actions/button_ok.png", factory, iconThemeDirs);			// Verify mapping here
		doIconMapping("gtk-zoom-100", "actions/viewmag1.png", factory, iconThemeDirs);
		doIconMapping("gtk-zoom-fit", "actions/viewmagfit.png", factory, iconThemeDirs);
		doIconMapping("gtk-zoom-in", "actions/viewmag+.png", factory, iconThemeDirs);
		doIconMapping("gtk-zoom-out", "actions/viewmag-.png", factory, iconThemeDirs);
	
		// Other icons that really should have Trinity equivalents in tdelibs
		doIconMapping("list-add", "actions/add.png", factory, iconThemeDirs);
		doIconMapping("list-remove", "actions/remove.png", factory, iconThemeDirs);
		doIconMapping("list-add-symbolic", "actions/add.png", factory, iconThemeDirs);
		doIconMapping("list-remove-symbolic", "actions/remove.png", factory, iconThemeDirs);
	
		gtk_icon_factory_add_default(factory);
	}

	TQScrollBar sbar(NULL);
	sbar.setOrientation(TQt::Horizontal);
	sbar.setValue(1);
	sbar.resize(200,25);
	
	// The following code determines how many buttons are on a scrollbar
	// It works by looking at each pixel of the scrollbar's area not taken up by the groove,
	// and asking the style which subcontrol is at that location.
	TQRect rect = tqApp->style().querySubControlMetrics(TQStyle::CC_ScrollBar, &sbar, TQStyle::SC_ScrollBarGroove);
	
	TQStyle::SubControl sc = TQStyle::SC_None;
	for (TQPoint pos(0,7) ; pos.x()<rect.x() ; pos.setX(pos.x()+1))
	{
		TQStyle::SubControl sc2 = tqApp->style().querySubControl(TQStyle::CC_ScrollBar, &sbar, pos);
		if (sc != sc2)
		{
			if (sc2 == TQStyle::SC_ScrollBarAddLine) m_scrollbarForward1 = true;
			if (sc2 == TQStyle::SC_ScrollBarSubLine) m_scrollbarBack1 = true;
			sc = sc2;
		}
	}
	sc = TQStyle::SC_None;
	for (TQPoint pos(rect.x()+rect.width(),7) ; pos.x()<200 ; pos.setX(pos.x()+1))
	{
		TQStyle::SubControl sc2 = tqApp->style().querySubControl(TQStyle::CC_ScrollBar, &sbar, pos);
		if (sc != sc2)
		{
			if (sc2 == TQStyle::SC_ScrollBarAddLine) m_scrollbarForward2 = true;
			if (sc2 == TQStyle::SC_ScrollBarSubLine) m_scrollbarBack2 = true;
			sc = sc2;
		}
	}

	// This function takes quite a long time to execute, and is run at the start of every app.
	// In order to speed it up, we can store the results in a file, along with the name of icon
	// theme and style.  This file can then be regenerated when the icon theme or style change.

	TQDir curDir;
	TQString themeFilePath = TQDir::homeDirPath();
	curDir.setPath(themeFilePath);
	if (!curDir.exists()) {
		curDir.mkdir(themeFilePath);
	}
	themeFilePath = themeFilePath + "/.themes/";
	curDir.setPath(themeFilePath);
	if (!curDir.exists()) {
		curDir.mkdir(themeFilePath);
	}
	themeFilePath = themeFilePath + TQString(TDEGTK_THEME_THEME_DIRECTORY_NAME) + "/";
	curDir.setPath(themeFilePath);
	if (!curDir.exists()) {
		curDir.mkdir(themeFilePath);
	}
	themeFilePath = themeFilePath + "gtk-3.0/";
	curDir.setPath(themeFilePath);
	if (!curDir.exists()) {
		curDir.mkdir(themeFilePath);
	}

	themeFilePath = themeFilePath + TDEGTK_THEME_CONTROL_FILE_NAME;
	TQFile themeFile(themeFilePath);
	TQTextStream stream;
	
	if (!forceRecreate && themeFile.exists()) {
		themeFile.open(IO_ReadOnly);
		stream.setDevice(&themeFile);
		
		if (stream.readLine() == "/* " + iconTheme + ", " + tqApp->style().name() + ", " + RC_CACHE_VERSION + ", " + __DATE__ + ", " + __TIME__  + " */") {
			// This cache matches the current icon theme and style
			themeFile.close();

			gtk3_tqt_reload_theme_definition_file(themeFilePath.local8Bit());
			return;
		}
		
		stream.unsetDevice();
		themeFile.close();
	}

	if (gtk3TQtDebug) {
		// Load possibly modified theme control file before writing a new one
		gtk3_tqt_reload_theme_definition_file(themeFilePath.local8Bit());
	}
	
	themeFile.open(IO_WriteOnly | IO_Truncate);
	stream.setDevice(&themeFile);

	stream << "/* " << iconTheme << ", " << tqApp->style().name() << ", " << RC_CACHE_VERSION << ", " << __DATE__ << ", " << __TIME__ << " */\n\n";
	stream << "/* This file was generated by the Gtk TQt Theme Engine */\n";
	stream << "/* It will be recreated when you change your TDE icon theme or widget style */\n\n";

	// FIXME
	// The items in a GTK3 combobox cannot be styled, either to draw them in a custom manner or to change their height
	// A bug report should be filed on this issue...
	bool combobox_appears_as_list = (!(tqApp->style().styleHint(TQStyle::SH_ComboBox_Popup) || tqApp->style().styleHint(TQStyle::SH_GUIStyle) == TQt::MotifStyle));
	stream << parse_rc_string(TQString("-GtkComboBox-appears-as-list: %1px").arg(combobox_appears_as_list), "*");

	// FIXME
	// Partially work around problems detailed in upstream GTK bug #687677
	// These issues will likely have a more permanent and complete resolution in GTK 3.8, and the following two lines should be removed at that point
	stream << parse_rc_string(TQString("-GtkComboBox-shadow-type: in"), "*");
	stream << parse_rc_string(TQString("background-color: transparent"), "GtkComboBox");

	stream << parse_rc_string(TQString("-GtkScrolledWindow-scrollbars-within-bevel: 1"), "*");
	stream << parse_rc_string(TQString("-GtkScrolledWindow-scrollbar-spacing: 0px"), "*");
	stream << parse_rc_string(TQString("border-style: inset"), "GtkScrolledWindow");
	stream << parse_rc_string("border-width: " + TQString::number(2) + "px " + TQString::number(2) + "px " + TQString::number(2) + "px " + TQString::number(2) + "px", "GtkScrolledWindow");
	stream << parse_rc_string("padding: " + TQString::number(0) + "px " + TQString::number(0) + "px " + TQString::number(0) + "px " + TQString::number(0) + "px", "GtkScrolledWindow");

	stream << parse_rc_string("-GtkComboBox-arrow-size: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_ArrowSize)), "*");
	stream << parse_rc_string("-GtkComboBox-arrow-scaling: 0", "*");

	stream << parse_rc_string(TQString("-GtkScrollbar-has-backward-stepper: ") + (m_scrollbarBack1 ? "1" : "0"), "*");
	stream << parse_rc_string(TQString("-GtkScrollbar-has-forward-stepper: ") + (m_scrollbarForward2 ? "1" : "0"), "*");
	stream << parse_rc_string(TQString("-GtkScrollbar-has-secondary-forward-stepper: ") + (m_scrollbarForward1 ? "1" : "0"), "*");
	stream << parse_rc_string(TQString("-GtkScrollbar-has-secondary-backward-stepper: ") + (m_scrollbarBack2 ? "1" : "0"), "*");

	m_scrollBarSubLineWidth = tqApp->style().querySubControlMetrics(TQStyle::CC_ScrollBar, &sbar, TQStyle::SC_ScrollBarSubLine).width();

	stream << parse_rc_string("-GtkRange-stepper-size: " + TQString::number(m_scrollBarSubLineWidth), "GtkScrollbar");
	stream << parse_rc_string("-GtkRange-slider-width: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_ScrollBarExtent)), "GtkScrollbar");
	stream << parse_rc_string("-GtkRange-trough-border: 0", "GtkScrollbar");
	stream << parse_rc_string("-GtkRange-trough-under-steppers: 1", "GtkScrollbar");
	stream << parse_rc_string("-GtkScrollbar-min-slider-length: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_ScrollBarSliderMin)), "*");

	// FIXME
	// This is currently set to the scrollbar stepper button size, as TQt3 does not have the concept of a stepper for a TQSlider
	stream << parse_rc_string("-GtkRange-stepper-size: " + TQString::number(m_scrollBarSubLineWidth), "GtkScale");

	TQSlider slider(NULL); // To keep BlueCurve happy
	stream << parse_rc_string("-GtkRange-slider-width: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_SliderThickness, &slider)), "GtkScale");
	stream << parse_rc_string("-GtkScale-slider-length: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_SliderLength, &slider)), "*");

	stream << parse_rc_string("-GtkButton-child-displacement-x: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_ButtonShiftHorizontal)), "*");
	stream << parse_rc_string("-GtkButton-child-displacement-y: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_ButtonShiftVertical)), "*");
	stream << parse_rc_string("-GtkRange-arrow-displacement-x: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_ButtonShiftHorizontal)), "*");
	stream << parse_rc_string("-GtkRange-arrow-displacement-y: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_ButtonShiftVertical)), "*");
	stream << parse_rc_string("-GtkRange-arrow-displacement-x: " + TQString::number(0), "GtkScrollbar");
	stream << parse_rc_string("-GtkRange-arrow-displacement-y: " + TQString::number(0), "GtkScrollbar");
	stream << parse_rc_string("-GtkButton-default-border: 0 0 0 0", "*");
	stream << parse_rc_string("-GtkButton-default-outside-border: 0 0 0 0", "*");
#ifdef USE_NATIVE_GTK_BUTTON_DRAWING
	stream << parse_rc_string("-GtkButton-inner-border: 2 2 2 2", "*");
#else
	if (tde_showIconsOnPushButtons) {
		stream << parse_rc_string("-GtkButton-inner-border: 10 10 2 2", "*");	// Allow space for the icon on either side of the text
	}
	else {
		stream << parse_rc_string("-GtkButton-inner-border: 2 2 2 2", "*");
	}
#endif

	stream << parse_rc_string("-GtkButtonBox-child_min_height: 0", "*");
	stream << parse_rc_string("-GtkButtonBox-child_internal_pad_x: 0", "*");
	stream << parse_rc_string("-GtkButtonBox-child_internal_pad_y: 0", "*");

	stream << parse_rc_string("-GtkRange-arrow-scaling: 1.0", "GtkScrollbar");

	stream << parse_rc_string("-xthickness: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_DefaultFrameWidth)), "*.GtkMenu");
	stream << parse_rc_string("-ythickness: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_DefaultFrameWidth)), "*.GtkMenu");
	stream << parse_rc_string("-xthickness: 5", "*.GtkMenu.Gtk*MenuItem");
	stream << parse_rc_string("-xthickness: 3", "*.GtkNotebook");
	stream << parse_rc_string("-ythickness: 3", "*.GtkNotebook");
	stream << parse_rc_string("-ythickness: 1", "*.GtkButton");
	stream << parse_rc_string("-color: " + colorString(TQColor(0,0,0)), "gtk-tooltips.GtkLabel", false);

	stream << parse_rc_string("-xthickness: 1", "*.GtkButton.*");
	stream << parse_rc_string("-ythickness: 1", "*.GtkButton.*");

//	stream << parse_rc_string("GtkTreeView::allow-rules = 0", "*");
//	stream << parse_rc_string("GtkTreeView::tree-line-width = 1", "*");
//	stream << parse_rc_string("GtkTreeView::vertical-separator = 30", "*");
//	//stream << parse_rc_string("GtkTreeView::odd-row-color = { 0.0, 0.0, 0.0 }", "*");

	stream << parse_rc_string("-GtkButton-inner-border: 0 0 0 0", "*GtkToolbar*GtkButton*");
	stream << parse_rc_string("-GtkButton-inner-border: 0 0 0 0", "*GtkToolbar*GtkToggleButton*");
	stream << parse_rc_string("-GtkButton-inner-border: 0 0 0 0", "*GtkNotebook*GtkButton*");
	stream << parse_rc_string("-GtkButton-inner-border: 0 0 0 0", "*GtkNotebook*GtkToggleButton*");

	// TQt calls them tab boxes, GTK calls them notebooks (!??!?)  Either way they are a pain...
	//stream << parse_rc_string("-GtkNotebook-tab-overlap: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_TabBarTabOverlap)), "*");
	stream << parse_rc_string("-GtkNotebook-tab-overlap: 0", "*");	// Overlap is handled in the style engine itself
	stream << parse_rc_string("-GtkNotebook-tab-curvature: 0", "*");
	stream << parse_rc_string("-GtkNotebook-initial-gap: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_TabBarTabOverlap)), "*");

	// This sets both the radio button and check box sizes
	stream << parse_rc_string("-GtkCheckButton-indicator-size: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_IndicatorHeight)), "*");
	stream << parse_rc_string("-GtkCheckMenuItem-indicator-size: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_IndicatorHeight)), "*");

	// FIXME
	// GtkCellRendererToggle indicator-size must be set as follows, however GTK3 does not provide any means to change the default size!
	// See upstream GTK bug #687076
	//stream << parse_rc_string("-GtkCellRendererToggle-indicator-size: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_IndicatorHeight)), "*");

	// FIXME
	// GtkSpinButton widgets use ugly unthemed horizontal buttons
	// When GTK provides an option to switch to vertical buttons, implement theming support for them
	// See upstream GTK bug #687172

	// FIXME
	// GtkSwitch slider height must be set to the TQt3 scrollbar slider width
	// When GTK provides an option to set the GtkSwitch height, implement theming support for this
	// See upstream GTK bug #688675

	// FIXME
	// There must be a way to set the selected tab offset (shift)
	// If not, it may be neccessary to override the GTK text drawing routines for notebooks to insert the proper shift
	//stream << parse_rc_string("-????: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_TabBarTabShiftHorizontal)), "*");

	// Expand widget padding so as to keep the prelighting out of the active widget area
	// FIXME
	// Where do these 3px values actually come from?
	stream << parse_rc_string("padding: " + TQString::number(3) + "px " + TQString::number(3) + "px", "GtkButton");
	stream << parse_rc_string("padding: " + TQString::number(3) + "px " + TQString::number(3) + "px", "GtkNotebook");
	stream << parse_rc_string("padding: " + TQString::number(3) + "px " + TQString::number(3) + "px", "GtkEntry");

	TQRect probeRect;
	TQRect comboBoxArrowRect;
	TQRect comboBoxEditFieldRect;
	{
		probeRect = TQRect(0, 0, 100, 100);

		TQStringList objectTypes;
		objectTypes.append("TQComboBox");
		TQPalette objectPalette = tqApp->palette(objectTypes);

		TQStyleControlElementData ceData;
		TQStyle::ControlElementFlags elementFlags = TQStyle::CEF_None;
		ceData.widgetObjectTypes = objectTypes;
		ceData.orientation = TQt::Horizontal;
		ceData.rect = probeRect;
		elementFlags = elementFlags | TQStyle::CEF_IsEditable;

		comboBoxArrowRect = tqApp->style().querySubControlMetrics(TQStyle::CC_ComboBox, ceData, elementFlags, TQStyle::SC_ComboBoxArrow);
		comboBoxEditFieldRect = tqApp->style().querySubControlMetrics(TQStyle::CC_ComboBox, ceData, elementFlags, TQStyle::SC_ComboBoxEditField);
	}

	// The padding is specified in a highly unusual format:
	// top_width, right_width, bottom_width, left_width
	// Compare that to the more typical format of:
	// left, top, right, bottom
	stream << parse_rc_string("padding: " + TQString::number(comboBoxEditFieldRect.y()-probeRect.y()) + "px " + TQString::number(probeRect.right()-comboBoxEditFieldRect.right()-comboBoxArrowRect.width()) + "px " + TQString::number(probeRect.bottom()-comboBoxEditFieldRect.bottom()) + "px " + TQString::number(comboBoxEditFieldRect.x()-probeRect.x()) + "px", "GtkComboBox>GtkEntry");

	// Set header sizes
	stream << parse_rc_string("padding: " + TQString::number(0) + "px " + TQString::number(0) + "px", "GtkTreeView>*>GtkButton");
	stream << parse_rc_string("border-width: " + TQString::number(0) + "px " + TQString::number(0) + "px", "GtkTreeView>*>GtkButton");
	stream << parse_rc_string("padding: " + TQString::number(0) + "px " + TQString::number(0) + "px", "GtkList>*>GtkButton");
	stream << parse_rc_string("border-width: " + TQString::number(0) + "px " + TQString::number(0) + "px", "GtkList>*>GtkButton");

	// Ensure group boxes are not cut off by their labels
	// FIXME
	// Where do these 2px values actually come from?
	stream << parse_rc_string("padding: " + TQString::number(2) + "px " + TQString::number(2) + "px", "GtkFrame");

	// Separators appear to be hardcoded to 1px high in TQt3
	// Anything else will cause a silent drawing failure!
	stream << parse_rc_string("-GtkWidget-separator-height: " + TQString::number(1), "*");
	stream << parse_rc_string("-GtkWidget-separator-width: " + TQString::number(1), "*");
	stream << parse_rc_string("-GtkWidget-wide-separators: 1", "*");

	// Set treeview cell size
	stream << parse_rc_string("-GtkTreeView-vertical-separator: 0", "*");

	// FIXME
	// GTK3 does not currently support drawing GtkTextView backgrounds through the style engine
	// Therefore, the best we can currently do is to set the background to the correct TQt3 color, which is obviously suboptimal as the TQt3 background drawing methods are never called!
	// Even the recommended CSS style properties do not appear to work!
	// See upstream GTK bug #687363
	{
		TQStringList objectTypes;
		objectTypes.append("TQTextEdit");
		TQPalette objectPalette = tqApp->palette(objectTypes);
// 		stream << parse_rc_string("background-color: " + colorString(objectPalette.color(TQPalette::Active, TQColorGroup::Base)), "GtkTextView");
// 		stream << parse_rc_string("background-color: " + colorString(objectPalette.color(TQPalette::Disabled, TQColorGroup::Base)), "GtkTextView:insensitive");

		setColour("color", "normal",                 objectPalette.color(TQPalette::Active, TQColorGroup::Foreground),   "GtkTextView");
		setColour("color", "insensitive",            objectPalette.color(TQPalette::Disabled, TQColorGroup::Foreground), "GtkTextView");
		setColour("background-color", "normal",      objectPalette.color(TQPalette::Active, TQColorGroup::Base),         "GtkTextView");
		setColour("background-color", "insensitive", objectPalette.color(TQPalette::Disabled, TQColorGroup::Base),       "GtkTextView");
	}

	// Handle menu metrics
	int tdeStandardMenuItemHeight;
	int tdeSeparatorMenuItemHeight;
	int tdeMenuFrameWidth;
	{
		TQStringList objectTypes;
		objectTypes.append("TQPopupMenu");
		TQPalette objectPalette = tqApp->palette(objectTypes);

		TQStyleControlElementData ceData;
		TQStyle::ControlElementFlags elementFlags = TQStyle::CEF_None;
		ceData.widgetObjectTypes = objectTypes;
		ceData.orientation = TQt::Horizontal;

		TQSize sz;
		TQMenuItem tqt3MenuItem;

		tqt3MenuItem.setSeparator(false);
		tdeStandardMenuItemHeight = TQPopupMenu::menuItemHeight(&tqt3MenuItem, tqApp->fontMetrics());
		ceData.rect = TQRect(0, 0, 0, tdeStandardMenuItemHeight);
		sz = tqApp->style().sizeFromContents(TQStyle::CT_PopupMenuItem, ceData, elementFlags, TQSize(0, tdeStandardMenuItemHeight), TQStyleOption(&tqt3MenuItem));
		sz = sz.expandedTo(TQSize(0, sz.height()));
		tdeStandardMenuItemHeight = sz.height();

		tqt3MenuItem.setSeparator(true);
		tdeSeparatorMenuItemHeight = TQPopupMenu::menuItemHeight(&tqt3MenuItem, tqApp->fontMetrics());
		ceData.rect = TQRect(0, 0, 0, tdeSeparatorMenuItemHeight);
		sz = tqApp->style().sizeFromContents(TQStyle::CT_PopupMenuItem, ceData, elementFlags, TQSize(0, tdeSeparatorMenuItemHeight), TQStyleOption(&tqt3MenuItem));
		sz = sz.expandedTo(TQSize(0, sz.height()));
		tdeSeparatorMenuItemHeight = sz.height();

		tdeMenuFrameWidth = tqApp->style().pixelMetric(TQStyle::PM_DefaultFrameWidth, ceData, elementFlags);
	}

	stream << parse_rc_string("-GtkWidget-separator-height: " + TQString::number(tdeSeparatorMenuItemHeight), "GtkMenuItem");
	stream << parse_rc_string("-GtkWidget-separator-width: " + TQString::number(tdeSeparatorMenuItemHeight), "GtkMenuItem");
	stream << parse_rc_string("-GtkWidget-wide-separators: 1", "GtkMenuItem");
	stream << parse_rc_string("padding: " + TQString::number(tdeMenuFrameWidth) + "px " + TQString::number(tdeMenuFrameWidth) + "px " + TQString::number(tdeMenuFrameWidth) + "px " + TQString::number(tdeMenuFrameWidth) + "px", "GtkMenu");

	// FIXME
	// GTK does not seem to support inserting actual space between the items in a menu bar; instead it insists on expanding the size of the menu items themselves (GtkMenuBar>GtkMenuItem padding:)
	// This is rather jarring visually; if a way is found to work around this GTK bug the menu bar item spacing should be fixed ASAP!

// 	stream << parse_rc_string("padding: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_)), "GtkMenuBar");
	stream << parse_rc_string("padding: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_MenuBarFrameWidth)) + "px " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_MenuBarItemSpacing)*0.75) + "px", "GtkMenuBar>GtkMenuItem");
	stream << parse_rc_string("padding: " + TQString::number(((tdeStandardMenuItemHeight-tqApp->style().pixelMetric(TQStyle::PM_IndicatorHeight))/2)*0.75) + "px " + TQString::number(0) + "px", "GtkMenu>GtkMenuItem");
	stream << parse_rc_string("padding: " + TQString::number(0) + "px " + TQString::number(0) + "px", "GtkMenu>GtkMenuSpacerItem");
// 	stream << parse_rc_string("padding: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_)), "GtkMenu>GtkSeparatorMenuItem");

	// Set up fonts
	TQFont generalFont = TDEGlobalSettings::generalFont();
	TQFont toolBarFont = TDEGlobalSettings::toolBarFont();
	TQFont menuFont = TDEGlobalSettings::menuFont();
	// TQFont windowTitleFont = TDEGlobalSettings::windowTitleFont();
	// TQFont taskbarFont = TDEGlobalSettings::taskbarFont();
 
	stream << parse_rc_string(tdeFontToGTKFontString(generalFont), "*");
	stream << parse_rc_string(tdeFontToGTKFontString(toolBarFont), "*GtkToolbar*GtkButton*");
	stream << parse_rc_string(tdeFontToGTKFontString(menuFont), "*.GtkMenu");
	
	themeFile.close();

	if (!gtk3TQtDebug) {
		gtk3_tqt_reload_theme_definition_file(themeFilePath.local8Bit());
	}
}
// =========================================================================================================
