You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gtk-qt-engine/kcm_gtk/kcmgtk.cpp

628 lines
19 KiB

/***************************************************************************
* Copyright (C) 2004 by David Sansome *
* david@dave-linux *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#if defined( HAVE_CONFIG_H )
# include "config.h"
#endif
#include <tqlayout.h>
#include <tdelocale.h>
#include <tdeglobal.h>
#include <tdefontdialog.h>
#include <kiconloader.h>
#include <tqfile.h>
#include <tqtextstream.h>
#include <tqregexp.h>
#include <tqdir.h>
#include <tqcombobox.h>
#include <tqmap.h>
#include <tqbuttongroup.h>
#include <tqpushbutton.h>
#include <tqradiobutton.h>
#include <tqlabel.h>
#include <kurllabel.h>
#include <tdeapplication.h>
#include <tdefontcombo.h>
#include <tqspinbox.h>
#include <ksqueezedtextlabel.h>
#include <stdlib.h>
#include <tdemessagebox.h>
#include <tdeconfig.h>
#include <tqstyle.h>
#include <tqheader.h>
#include <tdelistview.h>
#include <tqmessagebox.h>
#include <tqcheckbox.h>
#include <tdeglobal.h>
#include <kstandarddirs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "kcmgtk.h"
#include "mozillaprofile.h"
const TQString KcmGtk::GTK_RC_FILE(".gtkrc-2.0-kde-kde4");
const TQString KcmGtk::KDE_RC_DIR(TDEGlobal::dirs()->localtdedir() + "/env/");
const TQString KcmGtk::GTK_TQT_RC_FILE("gtk-qt-engine.rc.sh");
const TQString KcmGtk::GTK3_INI_DIR(TQDir::homeDirPath() + "/.config/gtk-3.0/");
const TQString KcmGtk::GTK3_INI_FILE("settings.ini");
/*typedef KGenericFactory<KcmGtk, TQWidget> KcmGtkFactory;
K_EXPORT_COMPONENT_FACTORY( kcm_gtk, KcmGtkFactory("gtk"))*/
extern "C"
{
KDE_EXPORT TDECModule *create_kcmgtk( TQWidget * parent, const char * name )
{
TDEGlobal::locale()->insertCatalogue( "gtk-qt-engine" );
return new KcmGtk( parent, "kcmgtk" );
}
}
GtkRcParser::GtkRcParser()
: emacs(false)
{
}
void GtkRcParser::parse(TQString fileName)
{
TQFile file(fileName);
file.open(IO_ReadOnly);
TQTextStream stream(&file);
TQRegExp includeRe("include\\s*\"([^\"]*)\"");
TQRegExp fontRe("font_name\\s*=\\s*\"([^\"]*)\"");
TQRegExp keyThemeRe("gtk-key-theme-name\\s*=\\s*\"([^\"]*)\"");
TQStringList includes;
while (1)
{
TQString line = stream.readLine();
if (line.isNull())
break;
if (line.startsWith("#"))
continue;
line = line.stripWhiteSpace();
if (line.startsWith("include"))
{
if (includeRe.search(line) == -1)
continue;
TQString themePath = includeRe.cap(1);
if (themePath.endsWith("/gtk-2.0/gtkrc") && !themePath.startsWith("/etc"))
style = includeRe.cap(1);
}
if (line.startsWith("font_name"))
{
if (fontRe.search(line) == -1)
continue;
// Assume there will only be one font line
font = parseFont(fontRe.cap(1));
}
if (line.startsWith("gtk-key-theme-name"))
{
if (keyThemeRe.search(line) == -1)
continue;
if (TQString(keyThemeRe.cap(1)).lower() == "emacs")
emacs = true;
}
}
file.close();
}
TQFont GtkRcParser::parseFont(TQString fontString)
{
TQFont ret;
while (true)
{
int lastSpacePos = fontString.findRev(' ');
if (lastSpacePos == -1)
break;
TQString lastWord = fontString.right(fontString.length() - lastSpacePos).stripWhiteSpace();
if (lastWord.lower() == "bold")
ret.setBold(true);
else if (lastWord.lower() == "italic")
ret.setItalic(true);
else
{
bool ok;
int fontSize = lastWord.toInt(&ok);
if (!ok)
break;
ret.setPointSize(fontSize);
}
fontString = fontString.left(lastSpacePos);
}
ret.setFamily(fontString);
return ret;
}
KcmGtk::KcmGtk(TQWidget *parent, const char *name, const TQStringList&)
: TDECModule(parent, name),
myAboutData(0),
emacsDetailsDialog(NULL),
searchPathsDialog(NULL)
{
TDEGlobal::locale()->insertCatalogue("gtk-qt-engine");
config = new TDEConfig("kcmgtkrc");
TQStringList gtkSearchPathsDefault;
gtkSearchPathsDefault.append("/usr");
gtkSearchPathsDefault.append("/usr/local");
gtkSearchPathsDefault.append("/opt/gnome");
gtkSearchPathsDefault.append(TQDir::homeDirPath() + "/.local");
gtkSearchPaths = config->readListEntry("gtkSearchPaths", gtkSearchPathsDefault);
// Add the widget to our layout
TQBoxLayout* l = new TQVBoxLayout(this);
widget = new KcmGtkWidget(this);
l->addWidget(widget);
// Load the icons
TDEIconLoader iconLoader;
widget->styleIcon->setPixmap(iconLoader.loadIcon("style", TDEIcon::Desktop));
widget->styleIcon3->setPixmap(iconLoader.loadIcon("style", TDEIcon::Desktop));
widget->fontIcon->setPixmap(iconLoader.loadIcon("fonts", TDEIcon::Desktop));
widget->keyboardIcon->setPixmap(iconLoader.loadIcon("input-keyboard", TDEIcon::Desktop));
getInstalledThemes();
load();
// Connect some signals
connect(widget->warning2, TQT_SIGNAL(leftClickedURL(const TQString&)), TDEApplication::kApplication(), TQT_SLOT(invokeBrowser(const TQString&)));
connect(widget->styleGroup, TQT_SIGNAL(clicked(int)), TQT_SLOT(itemChanged()));
connect(widget->warning5, TQT_SIGNAL(leftClickedURL(const TQString&)), TDEApplication::kApplication(), TQT_SLOT(invokeBrowser(const TQString&)));
connect(widget->styleGroup3, TQT_SIGNAL(clicked(int)), TQT_SLOT(itemChanged()));
connect(widget->fontGroup, TQT_SIGNAL(clicked(int)), TQT_SLOT(itemChanged()));
connect(widget->styleBox, TQT_SIGNAL(activated(int)), TQT_SLOT(itemChanged()));
connect(widget->styleBox, TQT_SIGNAL(activated(int)), TQT_SLOT(styleChanged()));
connect(widget->styleBox3, TQT_SIGNAL(activated(int)), TQT_SLOT(itemChanged()));
connect(widget->styleBox3, TQT_SIGNAL(activated(int)), TQT_SLOT(styleChanged()));
connect(widget->emacsBox, TQT_SIGNAL(toggled(bool)), TQT_SLOT(itemChanged()));
connect(widget->fontChange, TQT_SIGNAL(clicked()), TQT_SLOT(fontChangeClicked()));
connect(widget->emacsDetails, TQT_SIGNAL(clicked()), TQT_SLOT(emacsDetailsClicked()));
connect(widget->warning3, TQT_SIGNAL(clicked()), TQT_SLOT(searchPathsClicked()));
connect(widget->warning6, TQT_SIGNAL(clicked()), TQT_SLOT(searchPathsClicked()));
}
void KcmGtk::getInstalledThemes()
{
themes.clear();
for ( TQStringList::Iterator it = gtkSearchPaths.begin(); it != gtkSearchPaths.end(); ++it )
{
TQString path = (*it) + "/share/themes/";
TQDir dir(path);
TQStringList entryList = dir.entryList(TQDir::Dirs, TQDir::Unsorted);
for ( TQStringList::Iterator it2 = entryList.begin(); it2 != entryList.end(); ++it2 )
{
if ((*it2).startsWith("."))
continue;
if (themes.find(*it2) != themes.end())
continue;
if (!TQFile::exists(path + (*it2) + "/gtk-2.0/gtkrc"))
continue;
themes.insert((*it2), path + (*it2) + "/gtk-2.0/gtkrc");
}
}
bool installed = false;
widget->styleBox->clear();
if(!themes.empty()) {
TQStringList otherStyles = themes.keys();
if(otherStyles.find("Qt")!=otherStyles.end()) {
otherStyles.remove(otherStyles.find("Qt"));
}
installed = !otherStyles.empty();
if(installed) {
widget->styleBox->insertStringList(otherStyles);
}
}
widget->styleKde->setEnabled(installed);
widget->styleBox->setEnabled(installed);
widget->styleOther->setEnabled(installed);
widget->warning1->setHidden(installed);
widget->warning2->setHidden(installed);
widget->warning3->setHidden(installed);
gtk3Themes.clear();
for ( TQStringList::Iterator it = gtkSearchPaths.begin(); it != gtkSearchPaths.end(); ++it )
{
TQString path = (*it) + "/share/themes/";
TQDir dir(path);
TQStringList entryList = dir.entryList(TQDir::Dirs, TQDir::Unsorted);
for ( TQStringList::Iterator it2 = entryList.begin(); it2 != entryList.end(); ++it2 )
{
if ((*it2).startsWith("."))
continue;
if (gtk3Themes.find(*it2) != gtk3Themes.end())
continue;
if (!TQFile::exists(path + (*it2) + "/gtk-3.0/gtk.css"))
continue;
gtk3Themes.insert((*it2), path + (*it2) + "/gtk-3.0/gtk.css");
}
}
bool gtk3installed = !gtk3Themes.empty();
widget->styleBox3->clear();
if(gtk3installed) {
TQStringList otherGtk3Styles = gtk3Themes.keys();
if(otherGtk3Styles.find("tdegtk")!=otherGtk3Styles.end()) {
otherGtk3Styles.remove(otherGtk3Styles.find("tdegtk"));
}
if(otherGtk3Styles.find("Default")==otherGtk3Styles.end()) {
otherGtk3Styles.prepend("Default");
}
widget->styleBox3->insertStringList(otherGtk3Styles);
}
widget->styleKde3->setEnabled(gtk3installed);
widget->styleBox3->setEnabled(gtk3installed);
widget->styleOther3->setEnabled(gtk3installed);
widget->warning4->setHidden(gtk3installed);
widget->warning5->setHidden(gtk3installed);
widget->warning6->setHidden(gtk3installed);
}
void KcmGtk::itemChanged()
{
// In KDE < 3.3 there is no changed() slot - only a signal.
emit changed(true);
}
void KcmGtk::fontChangeClicked()
{
if ( TDEFontDialog::getFont( font ) == TDEFontDialog::Accepted )
{
updateFontPreview();
widget->fontGroup->setButton(widget->fontGroup->id(widget->fontOther));
itemChanged();
}
}
void KcmGtk::styleChanged()
{
widget->styleGroup->setButton(widget->styleGroup->id(widget->styleOther));
itemChanged();
}
TQString KcmGtk::env(TQString key)
{
char* value = getenv(key.latin1());
if (value == NULL)
return TQString();
else
return TQString(value);
}
void KcmGtk::updateFontPreview()
{
widget->fontPreview->setFont(font);
widget->fontPreview->setText(
i18n("%1 (size %2)").arg(font.family()).arg(TQString::number(font.pointSize())));
widget->fontPreview2->setFont(font);
}
KcmGtk::~KcmGtk()
{
delete config;
}
void KcmGtk::load()
{
parser.parse(TQDir::homeDirPath() + "/" + GTK_RC_FILE);
bool usingQtEngine = false;
if (!parser.style.isEmpty())
{
for ( TQMapIterator<TQString, TQString> it = themes.begin(); it != themes.end(); ++it )
{
if (it.data() != parser.style)
continue;
if (it.key() == "Qt")
usingQtEngine = true;
for (int i=0 ; i<widget->styleBox->count() ; ++i)
{
if (widget->styleBox->text(i) == it.key())
{
widget->styleBox->setCurrentItem(i);
break;
}
}
break;
}
if (usingQtEngine) {
widget->styleGroup->setButton(widget->styleGroup->id(widget->styleKde));
}
else {
widget->styleGroup->setButton(widget->styleGroup->id(widget->styleOther));
}
}
font = parser.font;
if (TQApplication::font().family() == font.family() &&
TQApplication::font().pointSize() == font.pointSize() &&
TQApplication::font().bold() == font.bold() &&
TQApplication::font().italic() == font.italic())
widget->fontGroup->setButton(widget->fontGroup->id(widget->fontKde));
else
widget->fontGroup->setButton(widget->fontGroup->id(widget->fontOther));
widget->emacsBox->setChecked(parser.emacs);
updateFontPreview();
bool usingGtk3TQtEngine = false;
if (TQFile::exists(GTK3_INI_DIR + GTK3_INI_FILE)) {
TQString activeGtk3Style;
TDEConfig gtk3Config(GTK3_INI_DIR + GTK3_INI_FILE);
gtk3Config.setGroup("Settings");
activeGtk3Style = gtk3Config.readEntry("gtk-theme-name");
if (activeGtk3Style == "tdegtk") {
usingGtk3TQtEngine = true;
}
if (usingGtk3TQtEngine) {
widget->styleGroup3->setButton(widget->styleGroup3->id(widget->styleKde3));
}
else {
widget->styleGroup3->setButton(widget->styleGroup3->id(widget->styleOther3));
for (int i=0; i<widget->styleBox3->count(); ++i) {
if (widget->styleBox3->text(i) == activeGtk3Style) {
widget->styleBox3->setCurrentItem(i);
break;
}
}
}
}
}
void KcmGtk::save()
{
// First write out the gtkrc file
TQFile file(TQDir::homeDirPath() + "/" + GTK_RC_FILE);
file.open(IO_WriteOnly);
TQTextStream stream(&file);
stream.setEncoding(TQTextStream::Locale);
TQFont selectedFont(widget->fontKde->isChecked() ? TQApplication::font() : font);
TQString fontName = selectedFont.family() + " " +
TQString(selectedFont.bold() ? "Bold " : "") +
TQString(selectedFont.italic() ? "Italic " : "") +
TQString::number(selectedFont.pointSize());
TQString themeName = widget->styleKde->isChecked() ? themes["Qt"] : themes[widget->styleBox->currentText()];
TQString themeNameShort = widget->styleKde->isChecked() ? TQString("Qt") : widget->styleBox->currentText();
TQString themeName3 = widget->styleKde3->isChecked() ? gtk3Themes["tdegtk"] : gtk3Themes[widget->styleBox3->currentText()];
TQString themeNameShort3 = widget->styleKde3->isChecked() ? TQString("tdegtk") : widget->styleBox3->currentText();
stream << "# This file was written by TDE\n";
stream << "# You can edit it in the TDE control center, under \"GTK Styles and Fonts\"\n";
stream << "\n";
stream << "include \"" << themeName << "\"\n";
if (TQFile::exists("/etc/gtk-2.0/gtkrc"))
stream << "include \"/etc/gtk-2.0/gtkrc\"\n";
stream << "\n";
stream << "style \"user-font\"\n";
stream << "{\n";
stream << "\tfont_name=\"" << fontName << "\"\n";
stream << "}\n";
stream << "widget_class \"*\" style \"user-font\"\n";
stream << "\n";
stream << "gtk-theme-name=\"" << themeNameShort << "\"\n";
stream << "gtk-font-name=\"" << fontName << "\"\n";
if (widget->emacsBox->isChecked())
stream << "gtk-key-theme-name=\"Emacs\"\n";
file.close();
// Now we check if that file is actually being loaded.
TQDir kdeRcDir;
if (!kdeRcDir.exists(KDE_RC_DIR))
{
// Make sure KDE's rc dir exists
kdeRcDir.mkdir(KDE_RC_DIR);
}
file.setName(KDE_RC_DIR + "/" + GTK_TQT_RC_FILE);
bool envFileDidNotExist = (!file.exists());
file.open(IO_ReadWrite);
stream.setDevice(TQT_TQIODEVICE(&file));
bool found = false;
for (;;)
{
TQString line = stream.readLine();
if (line.isNull())
break;
if (line.stripWhiteSpace().startsWith("export GTK2_RC_FILES=$HOME/" + GTK_RC_FILE))
{
found = true;
break;
}
}
if (!found)
{
stream << "#!/bin/bash\n\n";
stream << "# Make sure our customised gtkrc file is loaded.\n";
stream << "export GTK2_RC_FILES=$HOME/" + GTK_RC_FILE + "\n";
}
file.close();
// Make it executable
if (!found)
chmod(file.name().utf8(), 0755);
// Tell the user to restart KDE if the environment file was created this time
if (envFileDidNotExist)
TQMessageBox::information(this, "Restart TDE", "Your changes have been saved, but you will have to restart TDE for them to take effect.", TQMessageBox::Ok);
// Older versions of the Gtk-Qt theme engine wrote directly into ~/.gtkrc-2.0
// If the user has upgraded, that file needs to be deleted so the old settings
// won't override the new ones set now.
file.setName(TQDir::homeDirPath() + "/.gtkrc-2.0");
if (file.exists())
{
file.open(IO_ReadOnly);
TQString firstLine;
file.readLine(firstLine, 50);
file.close();
if (firstLine == "# This file was written by TDE")
file.remove();
}
// Simarly, remove the line we added to ~/.bashrc to tell GTK to load ~/.gtkrc-2.0
file.setName(TQDir::homeDirPath() + "/.bashrc");
if (file.exists())
{
file.open(IO_ReadOnly);
stream.setDevice(TQT_TQIODEVICE(&file));
TQString fileDataString = stream.read();
file.close();
TQString rcLine = "export GTK2_RC_FILES=$HOME/.gtkrc-2.0";
fileDataString.replace("\n" + rcLine, "\n# (This is no longer needed from version 0.8 of the theme engine)\n# " + rcLine);
file.open(IO_WriteOnly);
stream.setDevice(TQT_TQIODEVICE(&file));
stream << fileDataString;
file.close();
}
TQDir gtk3IniDir;
if (!gtk3IniDir.exists(GTK3_INI_DIR))
{
// Make sure the GTK INI dir exists
gtk3IniDir.mkdir(GTK3_INI_DIR);
}
TQFile gtk3IniFile(GTK3_INI_DIR + GTK3_INI_FILE);
gtk3IniFile.open(IO_WriteOnly);
TQTextStream gtk3IniStream(&gtk3IniFile);
gtk3IniStream << "# This file was written by TDE\n";
gtk3IniStream << "# You can edit it in the TDE control center, under \"GTK Styles and Fonts\"\n";
gtk3IniStream << "\n";
gtk3IniStream << "[Settings]\n";
gtk3IniStream << "gtk-theme-name = " << themeNameShort3 << "\n";
gtk3IniStream << "gtk-icon-theme-name = tdegtk-icon-theme\n";
gtk3IniStream << "gtk-fallback-icon-theme = tdegtk-fallback-icon-theme\n";
gtk3IniFile.close();
emit changed(true);
}
int KcmGtk::buttons()
{
return TDECModule::Apply;
}
TQString KcmGtk::quickHelp() const
{
return "";
}
void KcmGtk::emacsDetailsClicked()
{
if (emacsDetailsDialog == NULL)
{
emacsDetailsDialog = new EmacsDetails(this);
emacsDetailsDialog->list->header()->setStretchEnabled(true, 1);
}
emacsDetailsDialog->show();
}
void KcmGtk::searchPathsClicked()
{
if (searchPathsDialog == NULL)
{
searchPathsDialog = new SearchPaths(this);
connect(searchPathsDialog->okButton, TQT_SIGNAL(clicked()), TQT_SLOT(searchPathsOk()));
connect(searchPathsDialog->pathBox, TQT_SIGNAL(textChanged(const TQString&)), TQT_SLOT(searchPathsTextChanged(const TQString&)));
connect(searchPathsDialog->pathList, TQT_SIGNAL(currentChanged(TQListBoxItem*)), TQT_SLOT(searchPathsCurrentChanged(TQListBoxItem*)));
connect(searchPathsDialog->addButton, TQT_SIGNAL(clicked()), TQT_SLOT(searchPathsAddClicked()));
connect(searchPathsDialog->removeButton, TQT_SIGNAL(clicked()), TQT_SLOT(searchPathsRemoveClicked()));
}
searchPathsDialog->pathList->clear();
for (TQStringList::Iterator it = gtkSearchPaths.begin(); it != gtkSearchPaths.end(); ++it )
new TQListBoxText(searchPathsDialog->pathList, *it);
searchPathsDialog->show();
}
void KcmGtk::searchPathsOk()
{
gtkSearchPaths.clear();
int i=0;
TQListBoxItem* item = 0;
while ((item = searchPathsDialog->pathList->item(i++)))
gtkSearchPaths.append(item->text());
config->writeEntry("gtkSearchPaths", gtkSearchPaths);
getInstalledThemes();
}
void KcmGtk::searchPathsTextChanged(const TQString& text)
{
searchPathsDialog->addButton->setDisabled(text.isEmpty());
}
void KcmGtk::searchPathsCurrentChanged(TQListBoxItem* item)
{
searchPathsDialog->removeButton->setEnabled(item != NULL);
}
void KcmGtk::searchPathsAddClicked()
{
new TQListBoxText(searchPathsDialog->pathList, searchPathsDialog->pathBox->text());
searchPathsDialog->pathBox->clear();
}
void KcmGtk::searchPathsRemoveClicked()
{
searchPathsDialog->pathList->removeItem(searchPathsDialog->pathList->currentItem());
}
#include "kcmgtk.moc"