/* * common.cpp - contains all the common variables and functions for Psi * Copyright (C) 2001-2003 Justin Karneges * * 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "common.h" #include "profiles.h" #include "rtparse.h" #include "psievent.h" #include "psiiconset.h" #include "applicationinfo.h" #include "psioptions.h" #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_WS_X11 #include #include #include #include #endif #ifdef Q_WS_WIN #include #endif #ifdef Q_WS_MAC #include #include #include // for HIToolbox/InternetConfig #include #endif Qt::WFlags psi_dialog_flags = (Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint); // used to be part of the global options struct. // FIXME find it a new home! int common_smallFontSize=0; bool useSound; QString CAP(const QString &str) { return QString("%1: %2").arg(ApplicationInfo::name()).arg(str); } // clips plain text QString clipStatus(const QString &str, int width, int height) { QString out = ""; int at = 0; int len = str.length(); if(len == 0) return out; // only take the first "height" lines for(int n2 = 0; n2 < height; ++n2) { // only take the first "width" chars QString line; bool hasNewline = false; for(int n = 0; at < len; ++n, ++at) { if(str.at(at) == '\n') { hasNewline = true; break; } line += str.at(at); } ++at; if((int)line.length() > width) { line.truncate(width-3); line += "..."; } out += line; if(hasNewline) out += '\n'; if(at >= len) break; } return out; } QString encodePassword(const QString &pass, const QString &key) { QString result; int n1, n2; if(key.length() == 0) return pass; for(n1 = 0, n2 = 0; n1 < pass.length(); ++n1) { ushort x = pass.at(n1).unicode() ^ key.at(n2++).unicode(); QString hex; hex.sprintf("%04x", x); result += hex; if(n2 >= key.length()) n2 = 0; } return result; } QString decodePassword(const QString &pass, const QString &key) { QString result; int n1, n2; if(key.length() == 0) return pass; for(n1 = 0, n2 = 0; n1 < pass.length(); n1 += 4) { ushort x = 0; if(n1 + 4 > pass.length()) break; x += QString(pass.at(n1)).toInt(NULL,16)*4096; x += QString(pass.at(n1+1)).toInt(NULL,16)*256; x += QString(pass.at(n1+2)).toInt(NULL,16)*16; x += QString(pass.at(n1+3)).toInt(NULL,16); QChar c(x ^ key.at(n2++).unicode()); result += c; if(n2 >= key.length()) n2 = 0; } return result; } QString status2txt(int status) { switch(status) { case STATUS_OFFLINE: return QObject::tr("Offline"); case STATUS_AWAY: return QObject::tr("Away"); case STATUS_XA: return QObject::tr("Not Available"); case STATUS_DND: return QObject::tr("Do not Disturb"); case STATUS_CHAT: return QObject::tr("Free for Chat"); case STATUS_INVISIBLE: return QObject::tr("Invisible"); case STATUS_ONLINE: default: return QObject::tr("Online"); } } QString logencode(QString str) { str.replace(QRegExp("\\\\"), "\\\\"); // backslash to double-backslash str.replace(QRegExp("\\|"), "\\p"); // pipe to \p str.replace(QRegExp("\n"), "\\n"); // newline to \n return str; } QString logdecode(const QString &str) { QString ret; for(int n = 0; n < str.length(); ++n) { if(str.at(n) == '\\') { ++n; if(n >= str.length()) break; if(str.at(n) == 'n') ret.append('\n'); if(str.at(n) == 'p') ret.append('|'); if(str.at(n) == '\\') ret.append('\\'); } else { ret.append(str.at(n)); } } return ret; } bool fileCopy(const QString &src, const QString &dest) { QFile in(src); QFile out(dest); if(!in.open(QIODevice::ReadOnly)) return FALSE; if(!out.open(QIODevice::WriteOnly)) return FALSE; char *dat = new char[16384]; int n = 0; while(!in.atEnd()) { n = in.readBlock(dat, 16384); if(n == -1) { delete dat; return FALSE; } out.writeBlock(dat, n); } delete dat; out.close(); in.close(); return TRUE; } /** Detect default player helper on unix like systems */ QString soundDetectPlayer() { // prefer ALSA on linux if (QFile("/proc/asound").exists()) { return "aplay"; } // fallback to "play" return "play"; } void soundPlay(const QString &s) { QString str = s; if(str == "!beep") { QApplication::beep(); return; } if (QDir::isRelativePath(str)) { str = ApplicationInfo::resourcesDir() + "/" + str; } if(!QFile::exists(str)) return; #if defined(Q_WS_WIN) || defined(Q_WS_MAC) QSound::play(str); #else QString player = PsiOptions::instance()->getOption("options.ui.notifications.sounds.unix-sound-player").toString(); if (player == "") player = soundDetectPlayer(); QStringList args; args = QStringList::split(' ', player); args += str; QString prog = args.takeFirst(); QProcess::startDetached(prog, args); #endif } XMPP::Status makeStatus(int x, const QString &str, int priority) { XMPP::Status s = makeStatus(x,str); if (priority > 127) s.setPriority(127); else if (priority < -128) s.setPriority(-128); else s.setPriority(priority); return s; } XMPP::Status makeStatus(int x, const QString &str) { return XMPP::Status(static_cast(x), str); } XMPP::Status::Type makeSTATUS(const XMPP::Status &s) { return s.type(); } #include QLayout *rw_recurseFindLayout(QLayout *lo, QWidget *w) { //printf("scanning layout: %p\n", lo); QLayoutIterator it = lo->iterator(); for(QLayoutItem *i; (i = it.current()); ++it) { //printf("found: %p,%p\n", i->layout(), i->widget()); QLayout *slo = i->layout(); if(slo) { QLayout *tlo = rw_recurseFindLayout(slo, w); if(tlo) return tlo; } else if(i->widget() == w) return lo; } return 0; } QLayout *rw_findLayoutOf(QWidget *w) { return rw_recurseFindLayout(w->parentWidget()->layout(), w); } void replaceWidget(QWidget *a, QWidget *b) { if(!a) return; QLayout *lo = rw_findLayoutOf(a); if(!lo) return; //printf("decided on this: %p\n", lo); if(lo->inherits("QBoxLayout")) { QBoxLayout *bo = (QBoxLayout *)lo; int n = bo->findWidget(a); bo->insertWidget(n+1, b); delete a; } } void closeDialogs(QWidget *w) { // close qmessagebox? QList dialogs; QObjectList list = w->children(); for(QObjectList::Iterator it = list.begin() ; it != list.end(); ++it) { if((*it)->inherits("QDialog")) dialogs.append((QDialog *)(*it)); } for(QList::Iterator w = dialogs.begin(); w != dialogs.end(); ++w) { (*w)->close(); } } #ifdef Q_WS_X11 #include #include // needed for WM_CLASS hinting void x11wmClass(Display *dsp, WId wid, QString resName) { char app_name[] = "psi"; //Display *dsp = x11Display(); // get the display //WId win = winId(); // get the window XClassHint classhint; // class hints classhint.res_name = (char *)resName.latin1(); // res_name classhint.res_class = app_name; // res_class XSetClassHint(dsp, wid, &classhint); // set the class hints } //>>>-- Nathaniel Gray -- Caltech Computer Science ------> //>>>-- Mojave Project -- http://mojave.cs.caltech.edu --> // Copied from http://www.nedit.org/archives/discuss/2002-Aug/0386.html // Helper function bool getCardinal32Prop(Display *display, Window win, char *propName, long *value) { Atom nameAtom, typeAtom, actual_type_return; int actual_format_return, result; unsigned long nitems_return, bytes_after_return; long *result_array=NULL; nameAtom = XInternAtom(display, propName, False); typeAtom = XInternAtom(display, "CARDINAL", False); if (nameAtom == None || typeAtom == None) { //qDebug("Atoms not interned!"); return false; } // Try to get the property result = XGetWindowProperty(display, win, nameAtom, 0, 1, False, typeAtom, &actual_type_return, &actual_format_return, &nitems_return, &bytes_after_return, (unsigned char **)&result_array); if( result != Success ) { //qDebug("not Success"); return false; } if( actual_type_return == None || actual_format_return == 0 ) { //qDebug("Prop not found"); return false; } if( actual_type_return != typeAtom ) { //qDebug("Wrong type atom"); } *value = result_array[0]; XFree(result_array); return true; } // Get the desktop number that a window is on bool desktopOfWindow(Window *window, long *desktop) { Display *display = QX11Info::display(); bool result = getCardinal32Prop(display, *window, (char *)"_NET_WM_DESKTOP", desktop); //if( result ) // qDebug("Desktop: " + QString::number(*desktop)); return result; } // Get the current desktop the WM is displaying bool currentDesktop(long *desktop) { Window rootWin; Display *display = QX11Info::display(); bool result; rootWin = RootWindow(QX11Info::display(), XDefaultScreen(QX11Info::display())); result = getCardinal32Prop(display, rootWin, (char *)"_NET_CURRENT_DESKTOP", desktop); //if( result ) // qDebug("Current Desktop: " + QString::number(*desktop)); return result; } #endif void bringToFront(QWidget *widget, bool) { Q_ASSERT(widget); QWidget* w = widget->window(); #ifdef Q_WS_X11 // If we're not on the current desktop, do the hide/show trick long dsk, curr_dsk; Window win = w->winId(); if(desktopOfWindow(&win, &dsk) && currentDesktop(&curr_dsk)) { //qDebug() << "bringToFront current desktop=" << curr_dsk << " windowDesktop=" << dsk; if((dsk != curr_dsk) && (dsk != -1)) { // second condition for sticky windows w->hide(); } } // FIXME: multi-desktop hacks for Win and Mac required #endif if(w->isMaximized()) w->showMaximized(); else w->showNormal(); //if(grabFocus) // w->setActiveWindow(); w->raise(); w->setActiveWindow(); } bool operator!=(const QMap &m1, const QMap &m2) { if ( m1.size() != m2.size() ) return true; QMap::ConstIterator it = m1.begin(), it2; for ( ; it != m1.end(); ++it) { it2 = m2.find( it.key() ); if ( it2 == m2.end() ) return true; if ( it.data() != it2.data() ) return true; } return false; } //---------------------------------------------------------------------------- // ToolbarPrefs //---------------------------------------------------------------------------- ToolbarPrefs::ToolbarPrefs() : dock(Qt::DockTop) // , dirty(true) , on(false) , locked(false) // , stretchable(false) // , index(0) , nl(true) // , extraOffset(0) { id = QUuid::createUuid().toString(); } bool ToolbarPrefs::operator==(const ToolbarPrefs& other) { return id == other.id && name == other.name && keys == other.keys && dock == other.dock && // dirty == other.dirty && on == other.on && locked == other.locked && // stretchable == other.stretchable && // index == other.index && nl == other.nl; // extraOffset == other.extraOffset; } int versionStringToInt(const char* version) { QString str = QString::fromLatin1(version); QStringList parts = str.split('.', QString::KeepEmptyParts); if (parts.count() != 3) { return 0; } int versionInt = 0; for (int n = 0; n < 3; ++n) { bool ok; int x = parts[n].toInt(&ok); if (ok && x >= 0 && x <= 0xff) { versionInt <<= 8; versionInt += x; } else { return 0; } } return versionInt; } int qVersionInt() { static int out = -1; if (out == -1) { out = versionStringToInt(qVersion()); } return out; }