mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-23 18:32:49 +00:00
1184 lines
36 KiB
C++
1184 lines
36 KiB
C++
/* This file is part of the KDE libraries
|
|
Copyright
|
|
(C) 2000 Reginald Stadlbauer (reggie@kde.org)
|
|
(C) 1997 Stephan Kulow (coolo@kde.org)
|
|
(C) 1997-2000 Sven Radej (radej@kde.org)
|
|
(C) 1997-2000 Matthias Ettrich (ettrich@kde.org)
|
|
(C) 1999 Chris Schlaeger (cs@kde.org)
|
|
(C) 2002 Joseph Wenninger (jowenn@kde.org)
|
|
(C) 2005-2006 Hamish Rodda (rodda@kde.org)
|
|
(C) 2000-2008 David Faure (faure@kde.org)
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License version 2 as published by the Free Software Foundation.
|
|
|
|
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
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "kmainwindow.h"
|
|
#include "kmainwindow_p.h"
|
|
#include "kmainwindowiface_p.h"
|
|
#include "ktoolbarhandler_p.h"
|
|
#include "kcmdlineargs.h"
|
|
#include "ktoggleaction.h"
|
|
#include "ksessionmanager.h"
|
|
#include "kstandardaction.h"
|
|
|
|
#include <QtCore/QList>
|
|
#include <QtCore/QObject>
|
|
#include <QtCore/QTimer>
|
|
#include <QtGui/QCloseEvent>
|
|
#include <QtGui/QDesktopWidget>
|
|
#include <QtGui/QDockWidget>
|
|
#include <QtGui/QLayout>
|
|
#include <QtGui/QSessionManager>
|
|
#include <QtGui/QStyle>
|
|
#include <QtGui/QWidget>
|
|
|
|
#include <kaction.h>
|
|
#include <kapplication.h>
|
|
#include <kauthorized.h>
|
|
#include <kconfig.h>
|
|
#include <kdebug.h>
|
|
#include <kdialog.h>
|
|
#include <khelpmenu.h>
|
|
#include <klocale.h>
|
|
#include <kmenubar.h>
|
|
#include <kstandarddirs.h>
|
|
#include <kstatusbar.h>
|
|
#include <ktoolbar.h>
|
|
#include <kwindowsystem.h>
|
|
#include <kconfiggroup.h>
|
|
#include <kglobalsettings.h>
|
|
|
|
#if defined Q_WS_X11
|
|
#include <qx11info_x11.h>
|
|
#include <netwm.h>
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <assert.h>
|
|
|
|
#include <config.h>
|
|
|
|
static bool no_query_exit = false;
|
|
|
|
static KMenuBar *internalMenuBar(KMainWindow *mw)
|
|
{
|
|
return KGlobal::findDirectChild<KMenuBar *>(mw);
|
|
}
|
|
|
|
static KStatusBar *internalStatusBar(KMainWindow *mw)
|
|
{
|
|
// Don't use qFindChild here, it's recursive!
|
|
// (== slow, but also finds konqueror's per-view statusbars)
|
|
return KGlobal::findDirectChild<KStatusBar *>(mw);
|
|
}
|
|
|
|
/**
|
|
* Listens to resize events from QDockWidgets. The KMainWindow
|
|
* settings are set as dirty, as soon as at least one resize
|
|
* event occurred. The listener is attached to the dock widgets
|
|
* by dock->installEventFilter(dockResizeListener) inside
|
|
* KMainWindow::event().
|
|
*/
|
|
class DockResizeListener : public QObject
|
|
{
|
|
public:
|
|
DockResizeListener(KMainWindow *win);
|
|
virtual ~DockResizeListener();
|
|
virtual bool eventFilter(QObject *watched, QEvent *event);
|
|
|
|
private:
|
|
KMainWindow *m_win;
|
|
};
|
|
|
|
DockResizeListener::DockResizeListener(KMainWindow *win) :
|
|
QObject(win),
|
|
m_win(win)
|
|
{
|
|
}
|
|
|
|
DockResizeListener::~DockResizeListener()
|
|
{
|
|
}
|
|
|
|
bool DockResizeListener::eventFilter(QObject *watched, QEvent *event)
|
|
{
|
|
switch( event->type() ) {
|
|
case QEvent::Resize:
|
|
case QEvent::Move:
|
|
case QEvent::Hide:
|
|
m_win->k_ptr->setSettingsDirty(KMainWindowPrivate::CompressCalls);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return QObject::eventFilter(watched, event);
|
|
}
|
|
|
|
class KMWSessionManager : public KSessionManager
|
|
{
|
|
public:
|
|
KMWSessionManager()
|
|
{
|
|
}
|
|
~KMWSessionManager()
|
|
{
|
|
}
|
|
bool dummyInit() { return true; }
|
|
bool saveState( QSessionManager& )
|
|
{
|
|
KConfig* config = KApplication::kApplication()->sessionConfig();
|
|
if ( KMainWindow::memberList().count() ){
|
|
// According to Jochen Wilhelmy <digisnap@cs.tu-berlin.de>, this
|
|
// hook is useful for better document orientation
|
|
KMainWindow::memberList().first()->saveGlobalProperties(config);
|
|
}
|
|
|
|
int n = 0;
|
|
foreach (KMainWindow* mw, KMainWindow::memberList()) {
|
|
n++;
|
|
mw->savePropertiesInternal(config, n);
|
|
}
|
|
|
|
KConfigGroup group( config, "Number" );
|
|
group.writeEntry("NumberOfWindows", n );
|
|
return true;
|
|
}
|
|
|
|
bool commitData( QSessionManager& sm )
|
|
{
|
|
// not really a fast method but the only compatible one
|
|
if ( sm.allowsInteraction() ) {
|
|
bool canceled = false;
|
|
::no_query_exit = true;
|
|
|
|
foreach (KMainWindow *window, KMainWindow::memberList()) {
|
|
if ( !window->testAttribute( Qt::WA_WState_Hidden ) ) {
|
|
QCloseEvent e;
|
|
QApplication::sendEvent( window, &e );
|
|
canceled = !e.isAccepted();
|
|
if (canceled)
|
|
break;
|
|
/* Don't even think_about deleting widgets with
|
|
Qt::WDestructiveClose flag set at this point. We
|
|
are faking a close event, but we are *not*_
|
|
closing the window. The purpose of the faked
|
|
close event is to prepare the application so it
|
|
can safely be quit without the user losing data
|
|
(possibly showing a message box "do you want to
|
|
save this or that?"). It is possible that the
|
|
session manager quits the application later
|
|
(emitting QApplication::aboutToQuit() when this
|
|
happens), but it is also possible that the user
|
|
cancels the shutdown, so the application will
|
|
continue to run.
|
|
*/
|
|
}
|
|
}
|
|
::no_query_exit = false;
|
|
if (canceled)
|
|
return false;
|
|
|
|
KMainWindow* last = 0;
|
|
foreach (KMainWindow *window, KMainWindow::memberList()) {
|
|
if ( !window->testAttribute( Qt::WA_WState_Hidden ) ) {
|
|
last = window;
|
|
}
|
|
}
|
|
if ( last )
|
|
return last->queryExit();
|
|
// else
|
|
return true;
|
|
}
|
|
|
|
// the user wants it, the user gets it
|
|
return true;
|
|
}
|
|
};
|
|
|
|
K_GLOBAL_STATIC(KMWSessionManager, ksm)
|
|
K_GLOBAL_STATIC(QList<KMainWindow*>, sMemberList)
|
|
static bool being_first = true;
|
|
|
|
KMainWindow::KMainWindow( QWidget* parent, Qt::WindowFlags f )
|
|
: QMainWindow(parent, f), k_ptr(new KMainWindowPrivate)
|
|
{
|
|
k_ptr->init(this);
|
|
}
|
|
|
|
KMainWindow::KMainWindow(KMainWindowPrivate &dd, QWidget *parent, Qt::WindowFlags f)
|
|
: QMainWindow(parent, f), k_ptr(&dd)
|
|
{
|
|
k_ptr->init(this);
|
|
}
|
|
|
|
void KMainWindowPrivate::init(KMainWindow *_q)
|
|
{
|
|
KGlobal::ref();
|
|
|
|
// We set allow quit to true when the first mainwindow is created, so that when the refcounting
|
|
// reaches 0 the application can quit. We don't want this to happen before the first mainwindow
|
|
// is created, otherwise running a job in main would exit the app too early.
|
|
KGlobal::setAllowQuit(true);
|
|
|
|
q = _q;
|
|
|
|
q->setAnimated(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects);
|
|
|
|
q->setAttribute( Qt::WA_DeleteOnClose );
|
|
|
|
// We handle this functionality (quitting the app) ourselves, with KGlobal::ref/deref.
|
|
// This makes apps stay alive even if they only have a systray icon visible, or
|
|
// a progress widget with "keep open" checked, for instance.
|
|
// So don't let the default Qt mechanism allow any toplevel widget to just quit the app on us.
|
|
// Setting WA_QuitOnClose to false for all KMainWindows is not enough, any progress widget
|
|
// or dialog box would still quit the app...
|
|
if (qApp)
|
|
qApp->setQuitOnLastWindowClosed(false);
|
|
|
|
helpMenu = 0;
|
|
|
|
//actionCollection()->setWidget( this );
|
|
QObject::connect(qApp, SIGNAL(aboutToQuit()), q, SLOT(_k_shuttingDown()));
|
|
QObject::connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)),
|
|
q, SLOT(_k_slotSettingsChanged(int)));
|
|
|
|
// force KMWSessionManager creation - someone a better idea?
|
|
ksm->dummyInit();
|
|
|
|
sMemberList->append( q );
|
|
|
|
settingsDirty = false;
|
|
autoSaveSettings = false;
|
|
autoSaveWindowSize = true; // for compatibility
|
|
//d->kaccel = actionCollection()->kaccel();
|
|
settingsTimer = 0;
|
|
sizeTimer = 0;
|
|
shuttingDown = false;
|
|
if ((care_about_geometry = being_first)) {
|
|
being_first = false;
|
|
|
|
QString geometry;
|
|
KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde");
|
|
if (args && args->isSet("geometry"))
|
|
geometry = args->getOption("geometry");
|
|
|
|
if ( geometry.isNull() ) // if there is no geometry, it doesn't matter
|
|
care_about_geometry = false;
|
|
else
|
|
q->parseGeometry(false);
|
|
}
|
|
|
|
q->setWindowTitle( KGlobal::caption() );
|
|
|
|
dockResizeListener = new DockResizeListener(_q);
|
|
letDirtySettings = true;
|
|
|
|
sizeApplied = false;
|
|
}
|
|
|
|
static bool endsWithHashNumber( const QString& s )
|
|
{
|
|
for( int i = s.length() - 1;
|
|
i > 0;
|
|
--i )
|
|
{
|
|
if( s[ i ] == '#' && i != s.length() - 1 )
|
|
return true; // ok
|
|
if( !s[ i ].isDigit())
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static inline bool isValidDBusObjectPathCharacter(const QChar &c)
|
|
{
|
|
register ushort u = c.unicode();
|
|
return (u >= 'a' && u <= 'z')
|
|
|| (u >= 'A' && u <= 'Z')
|
|
|| (u >= '0' && u <= '9')
|
|
|| (u == '_') || (u == '/');
|
|
}
|
|
|
|
void KMainWindowPrivate::polish(KMainWindow *q)
|
|
{
|
|
// Set a unique object name. Required by session management, window management, and for the dbus interface.
|
|
QString objname;
|
|
QString s;
|
|
int unusedNumber = 1;
|
|
const QString name = q->objectName();
|
|
bool startNumberingImmediately = true;
|
|
bool tryReuse = false;
|
|
if ( name.isEmpty() )
|
|
{ // no name given
|
|
objname = "MainWindow#";
|
|
}
|
|
else if( name.endsWith( QLatin1Char( '#' ) ) )
|
|
{ // trailing # - always add a number - KWin uses this for better grouping
|
|
objname = name;
|
|
}
|
|
else if( endsWithHashNumber( name ))
|
|
{ // trailing # with a number - like above, try to use the given number first
|
|
objname = name;
|
|
tryReuse = true;
|
|
startNumberingImmediately = false;
|
|
}
|
|
else
|
|
{
|
|
objname = name;
|
|
startNumberingImmediately = false;
|
|
}
|
|
|
|
s = objname;
|
|
if ( startNumberingImmediately )
|
|
s += '1';
|
|
|
|
for(;;) {
|
|
const QList<QWidget*> list = qApp->topLevelWidgets();
|
|
bool found = false;
|
|
foreach ( QWidget* w, list ) {
|
|
if( w != q && w->objectName() == s )
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if( !found )
|
|
break;
|
|
if( tryReuse ) {
|
|
objname = name.left( name.length() - 1 ); // lose the hash
|
|
unusedNumber = 0; // start from 1 below
|
|
tryReuse = false;
|
|
}
|
|
s.setNum( ++unusedNumber );
|
|
s = objname + s;
|
|
}
|
|
q->setObjectName( s );
|
|
q->winId(); // workaround for setWindowRole() crashing, and set also window role, just in case TT
|
|
q->setWindowRole( s ); // will keep insisting that object name suddenly should not be used for window role
|
|
|
|
dbusName = '/' + qApp->applicationName() + '/' + q->objectName().replace(QLatin1Char('/'), QLatin1Char('_'));
|
|
// Clean up for dbus usage: any non-alphanumeric char should be turned into '_'
|
|
const int len = dbusName.length();
|
|
for ( int i = 0; i < len; ++i ) {
|
|
if ( !isValidDBusObjectPathCharacter( dbusName[i] ) )
|
|
dbusName[i] = QLatin1Char('_');
|
|
}
|
|
|
|
QDBusConnection::sessionBus().registerObject(dbusName, q, QDBusConnection::ExportScriptableSlots |
|
|
QDBusConnection::ExportScriptableProperties |
|
|
QDBusConnection::ExportNonScriptableSlots |
|
|
QDBusConnection::ExportNonScriptableProperties |
|
|
QDBusConnection::ExportAdaptors);
|
|
}
|
|
|
|
void KMainWindowPrivate::setSettingsDirty(CallCompression callCompression)
|
|
{
|
|
if (!letDirtySettings) {
|
|
return;
|
|
}
|
|
|
|
settingsDirty = true;
|
|
if (autoSaveSettings) {
|
|
if (callCompression == CompressCalls) {
|
|
if (!settingsTimer) {
|
|
settingsTimer = new QTimer(q);
|
|
settingsTimer->setInterval(500);
|
|
settingsTimer->setSingleShot(true);
|
|
QObject::connect(settingsTimer, SIGNAL(timeout()), q, SLOT(saveAutoSaveSettings()));
|
|
}
|
|
settingsTimer->start();
|
|
} else {
|
|
q->saveAutoSaveSettings();
|
|
}
|
|
}
|
|
}
|
|
|
|
void KMainWindowPrivate::setSizeDirty()
|
|
{
|
|
if (autoSaveWindowSize) {
|
|
if (!sizeTimer) {
|
|
sizeTimer = new QTimer(q);
|
|
sizeTimer->setInterval(500);
|
|
sizeTimer->setSingleShot(true);
|
|
QObject::connect(sizeTimer, SIGNAL(timeout()), q, SLOT(_k_slotSaveAutoSaveSize()));
|
|
}
|
|
sizeTimer->start();
|
|
}
|
|
}
|
|
|
|
void KMainWindow::parseGeometry(bool parsewidth)
|
|
{
|
|
K_D(KMainWindow);
|
|
QString cmdlineGeometry;
|
|
KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde");
|
|
if (args->isSet("geometry"))
|
|
cmdlineGeometry = args->getOption("geometry");
|
|
|
|
assert ( !cmdlineGeometry.isNull() );
|
|
assert ( d->care_about_geometry );
|
|
Q_UNUSED(d); // fix compiler warning in release mode
|
|
|
|
#if defined Q_WS_X11
|
|
int x, y;
|
|
int w, h;
|
|
int m = XParseGeometry( cmdlineGeometry.toLatin1(), &x, &y, (unsigned int*)&w, (unsigned int*)&h);
|
|
if (parsewidth) {
|
|
const QSize minSize = minimumSize();
|
|
const QSize maxSize = maximumSize();
|
|
if ( !(m & WidthValue) )
|
|
w = width();
|
|
if ( !(m & HeightValue) )
|
|
h = height();
|
|
w = qMin(w,maxSize.width());
|
|
h = qMin(h,maxSize.height());
|
|
w = qMax(w,minSize.width());
|
|
h = qMax(h,minSize.height());
|
|
resize(w, h);
|
|
} else {
|
|
if ( (m & XNegative) )
|
|
x = KApplication::desktop()->width() + x - w;
|
|
else if ( !(m & XValue) )
|
|
x = geometry().x();
|
|
if ( (m & YNegative) )
|
|
y = KApplication::desktop()->height() + y - h;
|
|
else if ( !(m & YValue) )
|
|
y = geometry().y();
|
|
|
|
move(x, y);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
KMainWindow::~KMainWindow()
|
|
{
|
|
sMemberList->removeAll( this );
|
|
delete static_cast<QObject *>(k_ptr->dockResizeListener); //so we don't get anymore events after k_ptr is destroyed
|
|
delete k_ptr;
|
|
KGlobal::deref();
|
|
}
|
|
|
|
KMenu* KMainWindow::helpMenu( const QString &aboutAppText, bool showWhatsThis )
|
|
{
|
|
K_D(KMainWindow);
|
|
if(!d->helpMenu) {
|
|
if ( aboutAppText.isEmpty() )
|
|
d->helpMenu = new KHelpMenu( this, KGlobal::mainComponent().aboutData(), showWhatsThis);
|
|
else
|
|
d->helpMenu = new KHelpMenu( this, aboutAppText, showWhatsThis );
|
|
|
|
if (!d->helpMenu)
|
|
return 0;
|
|
}
|
|
|
|
return d->helpMenu->menu();
|
|
}
|
|
|
|
KMenu* KMainWindow::customHelpMenu( bool showWhatsThis )
|
|
{
|
|
K_D(KMainWindow);
|
|
if (!d->helpMenu) {
|
|
d->helpMenu = new KHelpMenu( this, QString(), showWhatsThis );
|
|
connect(d->helpMenu, SIGNAL(showAboutApplication()),
|
|
this, SLOT(showAboutApplication()));
|
|
}
|
|
|
|
return d->helpMenu->menu();
|
|
}
|
|
|
|
bool KMainWindow::canBeRestored( int number )
|
|
{
|
|
if ( !qApp->isSessionRestored() )
|
|
return false;
|
|
KConfig *config = kapp->sessionConfig();
|
|
if ( !config )
|
|
return false;
|
|
|
|
KConfigGroup group( config, "Number" );
|
|
const int n = group.readEntry( "NumberOfWindows", 1 );
|
|
return number >= 1 && number <= n;
|
|
}
|
|
|
|
const QString KMainWindow::classNameOfToplevel( int number )
|
|
{
|
|
if ( !qApp->isSessionRestored() )
|
|
return QString();
|
|
KConfig *config = kapp->sessionConfig();
|
|
if ( !config )
|
|
return QString();
|
|
QString s;
|
|
s.setNum( number );
|
|
s.prepend( QLatin1String("WindowProperties") );
|
|
|
|
KConfigGroup group( config, s );
|
|
if ( !group.hasKey( "ClassName" ) )
|
|
return QString();
|
|
else
|
|
return group.readEntry( "ClassName" );
|
|
}
|
|
|
|
bool KMainWindow::restore( int number, bool show )
|
|
{
|
|
if ( !canBeRestored( number ) )
|
|
return false;
|
|
KConfig *config = kapp->sessionConfig();
|
|
if ( readPropertiesInternal( config, number ) ){
|
|
if ( show )
|
|
KMainWindow::show();
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void KMainWindow::setCaption( const QString &caption )
|
|
{
|
|
setPlainCaption( KDialog::makeStandardCaption( caption, this ) );
|
|
}
|
|
|
|
void KMainWindow::setCaption( const QString &caption, bool modified )
|
|
{
|
|
KDialog::CaptionFlags flags = KDialog::HIGCompliantCaption;
|
|
|
|
if ( modified )
|
|
{
|
|
flags |= KDialog::ModifiedCaption;
|
|
}
|
|
|
|
setPlainCaption( KDialog::makeStandardCaption(caption, this, flags) );
|
|
}
|
|
|
|
void KMainWindow::setPlainCaption( const QString &caption )
|
|
{
|
|
setWindowTitle(caption);
|
|
}
|
|
|
|
void KMainWindow::appHelpActivated( void )
|
|
{
|
|
K_D(KMainWindow);
|
|
if( !d->helpMenu ) {
|
|
d->helpMenu = new KHelpMenu( this );
|
|
if ( !d->helpMenu )
|
|
return;
|
|
}
|
|
d->helpMenu->appHelpActivated();
|
|
}
|
|
|
|
void KMainWindow::closeEvent ( QCloseEvent *e )
|
|
{
|
|
K_D(KMainWindow);
|
|
|
|
// Save settings if auto-save is enabled, and settings have changed
|
|
if (d->settingsTimer && d->settingsTimer->isActive()) {
|
|
d->settingsTimer->stop();
|
|
saveAutoSaveSettings();
|
|
}
|
|
if (d->sizeTimer && d->sizeTimer->isActive()) {
|
|
d->sizeTimer->stop();
|
|
d->_k_slotSaveAutoSaveSize();
|
|
}
|
|
|
|
if (queryClose()) {
|
|
e->accept();
|
|
|
|
int not_withdrawn = 0;
|
|
foreach (KMainWindow* mw, KMainWindow::memberList()) {
|
|
if ( !mw->isHidden() && mw->isTopLevel() && mw != this )
|
|
not_withdrawn++;
|
|
}
|
|
|
|
if ( !no_query_exit && not_withdrawn <= 0 ) { // last window close accepted?
|
|
if (!( queryExit() && ( !kapp || !kapp->sessionSaving() ) && !d->shuttingDown )) {
|
|
// cancel closing, it's stupid to end up with no windows at all....
|
|
e->ignore();
|
|
}
|
|
}
|
|
} else e->ignore(); //if the window should not be closed, don't close it
|
|
}
|
|
|
|
bool KMainWindow::queryExit()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool KMainWindow::queryClose()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void KMainWindow::saveGlobalProperties( KConfig* )
|
|
{
|
|
}
|
|
|
|
void KMainWindow::readGlobalProperties( KConfig* )
|
|
{
|
|
}
|
|
|
|
void KMainWindow::showAboutApplication()
|
|
{
|
|
}
|
|
|
|
void KMainWindow::savePropertiesInternal( KConfig *config, int number )
|
|
{
|
|
K_D(KMainWindow);
|
|
const bool oldASWS = d->autoSaveWindowSize;
|
|
d->autoSaveWindowSize = true; // make saveMainWindowSettings save the window size
|
|
|
|
QString s;
|
|
s.setNum(number);
|
|
s.prepend(QLatin1String("WindowProperties"));
|
|
KConfigGroup cg(config, s);
|
|
|
|
// store objectName, className, Width and Height for later restoring
|
|
// (Only useful for session management)
|
|
cg.writeEntry(QLatin1String("ObjectName"), objectName());
|
|
cg.writeEntry(QLatin1String("ClassName"), metaObject()->className());
|
|
|
|
saveMainWindowSettings(cg); // Menubar, statusbar and Toolbar settings.
|
|
|
|
s.setNum(number);
|
|
cg = KConfigGroup(config, s);
|
|
saveProperties(cg);
|
|
|
|
d->autoSaveWindowSize = oldASWS;
|
|
}
|
|
|
|
void KMainWindow::saveMainWindowSettings(const KConfigGroup &_cg)
|
|
{
|
|
K_D(KMainWindow);
|
|
//kDebug(200) << "KMainWindow::saveMainWindowSettings " << _cg.name();
|
|
|
|
// Called by session management - or if we want to save the window size anyway
|
|
if ( d->autoSaveWindowSize )
|
|
saveWindowSize( _cg );
|
|
|
|
KConfigGroup cg(_cg); // for saving
|
|
|
|
// One day will need to save the version number, but for now, assume 0
|
|
// Utilise the QMainWindow::saveState() functionality.
|
|
const QByteArray state = saveState();
|
|
cg.writeEntry(QString("State"), state.toBase64());
|
|
|
|
QStatusBar* sb = internalStatusBar(this);
|
|
if (sb) {
|
|
if(!cg.hasDefault("StatusBar") && !sb->isHidden() )
|
|
cg.revertToDefault("StatusBar");
|
|
else
|
|
cg.writeEntry("StatusBar", sb->isHidden() ? "Disabled" : "Enabled");
|
|
}
|
|
|
|
QMenuBar* mb = internalMenuBar(this);
|
|
if (mb) {
|
|
const QString MenuBar = QLatin1String("MenuBar");
|
|
if(!cg.hasDefault("MenuBar") && !mb->isHidden() )
|
|
cg.revertToDefault("MenuBar");
|
|
else
|
|
cg.writeEntry("MenuBar", mb->isHidden() ? "Disabled" : "Enabled");
|
|
}
|
|
|
|
if ( !autoSaveSettings() || cg.name() == autoSaveGroup() ) { // TODO should be cg == d->autoSaveGroup, to compare both kconfig and group name
|
|
if(!cg.hasDefault("ToolBarsMovable") && !KToolBar::toolBarsLocked())
|
|
cg.revertToDefault("ToolBarsMovable");
|
|
else
|
|
cg.writeEntry("ToolBarsMovable", KToolBar::toolBarsLocked() ? "Disabled" : "Enabled");
|
|
}
|
|
|
|
int n = 1; // Toolbar counter. toolbars are counted from 1,
|
|
foreach (KToolBar* toolbar, toolBars()) {
|
|
QString group("Toolbar");
|
|
// Give a number to the toolbar, but prefer a name if there is one,
|
|
// because there's no real guarantee on the ordering of toolbars
|
|
group += (toolbar->objectName().isEmpty() ? QString::number(n) : QString(" ")+toolbar->objectName());
|
|
|
|
KConfigGroup toolbarGroup(&cg, group);
|
|
toolbar->saveSettings(toolbarGroup);
|
|
n++;
|
|
}
|
|
}
|
|
|
|
bool KMainWindow::readPropertiesInternal( KConfig *config, int number )
|
|
{
|
|
K_D(KMainWindow);
|
|
|
|
const bool oldLetDirtySettings = d->letDirtySettings;
|
|
d->letDirtySettings = false;
|
|
|
|
if ( number == 1 )
|
|
readGlobalProperties( config );
|
|
|
|
// in order they are in toolbar list
|
|
QString s;
|
|
s.setNum(number);
|
|
s.prepend(QLatin1String("WindowProperties"));
|
|
|
|
KConfigGroup cg(config, s);
|
|
|
|
// restore the object name (window role)
|
|
if ( cg.hasKey(QLatin1String("ObjectName" )) )
|
|
setObjectName( cg.readEntry("ObjectName").toLatin1()); // latin1 is right here
|
|
|
|
d->sizeApplied = false; // since we are changing config file, reload the size of the window
|
|
// if necessary. Do it before the call to applyMainWindowSettings.
|
|
applyMainWindowSettings(cg); // Menubar, statusbar and toolbar settings.
|
|
|
|
s.setNum(number);
|
|
KConfigGroup grp(config, s);
|
|
readProperties(grp);
|
|
|
|
d->letDirtySettings = oldLetDirtySettings;
|
|
|
|
return true;
|
|
}
|
|
|
|
void KMainWindow::applyMainWindowSettings(const KConfigGroup &cg, bool force)
|
|
{
|
|
K_D(KMainWindow);
|
|
kDebug(200) << "KMainWindow::applyMainWindowSettings " << cg.name();
|
|
|
|
QWidget *focusedWidget = QApplication::focusWidget();
|
|
|
|
const bool oldLetDirtySettings = d->letDirtySettings;
|
|
d->letDirtySettings = false;
|
|
|
|
if (!d->sizeApplied) {
|
|
restoreWindowSize(cg);
|
|
d->sizeApplied = true;
|
|
}
|
|
|
|
QStatusBar* sb = internalStatusBar(this);
|
|
if (sb) {
|
|
QString entry = cg.readEntry("StatusBar", "Enabled");
|
|
if ( entry == "Disabled" )
|
|
sb->hide();
|
|
else
|
|
sb->show();
|
|
}
|
|
|
|
QMenuBar* mb = internalMenuBar(this);
|
|
if (mb) {
|
|
QString entry = cg.readEntry ("MenuBar", "Enabled");
|
|
if ( entry == "Disabled" )
|
|
mb->hide();
|
|
else
|
|
mb->show();
|
|
}
|
|
|
|
if ( !autoSaveSettings() || cg.name() == autoSaveGroup() ) { // TODO should be cg == d->autoSaveGroup, to compare both kconfig and group name
|
|
QString entry = cg.readEntry ("ToolBarsMovable", "Disabled");
|
|
if ( entry == "Disabled" )
|
|
KToolBar::setToolBarsLocked(true);
|
|
else
|
|
KToolBar::setToolBarsLocked(false);
|
|
}
|
|
|
|
int n = 1; // Toolbar counter. toolbars are counted from 1,
|
|
foreach (KToolBar* toolbar, toolBars()) {
|
|
QString group("Toolbar");
|
|
// Give a number to the toolbar, but prefer a name if there is one,
|
|
// because there's no real guarantee on the ordering of toolbars
|
|
group += (toolbar->objectName().isEmpty() ? QString::number(n) : QString(" ")+toolbar->objectName());
|
|
|
|
KConfigGroup toolbarGroup(&cg, group);
|
|
toolbar->applySettings(toolbarGroup, force);
|
|
n++;
|
|
}
|
|
|
|
QByteArray state;
|
|
if (cg.hasKey("State")) {
|
|
state = cg.readEntry("State", state);
|
|
state = QByteArray::fromBase64(state);
|
|
// One day will need to load the version number, but for now, assume 0
|
|
restoreState(state);
|
|
}
|
|
|
|
if (focusedWidget) {
|
|
focusedWidget->setFocus();
|
|
}
|
|
|
|
d->settingsDirty = false;
|
|
d->letDirtySettings = oldLetDirtySettings;
|
|
}
|
|
|
|
#ifdef Q_WS_WIN
|
|
|
|
/*
|
|
The win32 implementation for restoring/savin windows size differs
|
|
from the unix/max implementation in three topics:
|
|
|
|
1. storing and restoring the position, which may not work on x11
|
|
see http://doc.trolltech.com/4.3/geometry.html#x11-peculiarities
|
|
2. using QWidget::saveGeometry() and QWidget::restoreGeometry()
|
|
this would probably be usable on x11 and/or on mac, but I'm unable to
|
|
check this on unix/mac, so I leave this fix to the x11/mac experts.
|
|
3. store geometry separately for each resolution -> on unix/max the size
|
|
and with of the window are already saved separately on non windows
|
|
system although not using ...Geometry functions -> could also be
|
|
fixed by x11/mac experts.
|
|
*/
|
|
void KMainWindow::restoreWindowSize( const KConfigGroup & _cg )
|
|
{
|
|
K_D(KMainWindow);
|
|
|
|
int scnum = QApplication::desktop()->screenNumber(window());
|
|
QRect desk = QApplication::desktop()->screenGeometry(scnum);
|
|
|
|
QString geometryKey = QString::fromLatin1("geometry-%1-%2").arg(desk.width()).arg(desk.height());
|
|
QByteArray geometry = _cg.readEntry( geometryKey, QByteArray() );
|
|
// if first time run, center window
|
|
if (!restoreGeometry( QByteArray::fromBase64(geometry) ))
|
|
move( (desk.width()-width())/2, (desk.height()-height())/2 );
|
|
}
|
|
|
|
void KMainWindow::saveWindowSize( const KConfigGroup & _cg ) const
|
|
{
|
|
K_D(const KMainWindow);
|
|
int scnum = QApplication::desktop()->screenNumber(window());
|
|
QRect desk = QApplication::desktop()->screenGeometry(scnum);
|
|
|
|
// geometry is saved separately for each resolution
|
|
QString geometryKey = QString::fromLatin1("geometry-%1-%2").arg(desk.width()).arg(desk.height());
|
|
QByteArray geometry = saveGeometry();
|
|
KConfigGroup cg(_cg);
|
|
cg.writeEntry( geometryKey, geometry.toBase64() );
|
|
}
|
|
#else
|
|
void KMainWindow::saveWindowSize( const KConfigGroup & _cg ) const
|
|
{
|
|
K_D(const KMainWindow);
|
|
int scnum = QApplication::desktop()->screenNumber(window());
|
|
QRect desk = QApplication::desktop()->screenGeometry(scnum);
|
|
|
|
int w, h;
|
|
#if defined Q_WS_X11
|
|
// save maximalization as desktop size + 1 in that direction
|
|
KWindowInfo info = KWindowSystem::windowInfo( winId(), NET::WMState );
|
|
w = info.state() & NET::MaxHoriz ? desk.width() + 1 : width();
|
|
h = info.state() & NET::MaxVert ? desk.height() + 1 : height();
|
|
#else
|
|
if (isMaximized()) {
|
|
w = desk.width() + 1;
|
|
h = desk.height() + 1;
|
|
} else {
|
|
w = width();
|
|
h = height();
|
|
}
|
|
//TODO: add "Maximized" property instead "+1" hack
|
|
#endif
|
|
KConfigGroup cg(_cg);
|
|
|
|
QRect size( desk.width(), w, desk.height(), h );
|
|
bool defaultSize = (size == d->defaultWindowSize);
|
|
QString widthString = QString::fromLatin1("Width %1").arg(desk.width());
|
|
QString heightString = QString::fromLatin1("Height %1").arg(desk.height());
|
|
if (!cg.hasDefault(widthString) && defaultSize)
|
|
cg.revertToDefault(widthString);
|
|
else
|
|
cg.writeEntry(widthString, w );
|
|
|
|
if (!cg.hasDefault(heightString) && defaultSize)
|
|
cg.revertToDefault(heightString);
|
|
else
|
|
cg.writeEntry(heightString, h );
|
|
}
|
|
|
|
void KMainWindow::restoreWindowSize( const KConfigGroup & config )
|
|
{
|
|
K_D(KMainWindow);
|
|
if (d->care_about_geometry) {
|
|
parseGeometry(true);
|
|
} else {
|
|
// restore the size
|
|
const int scnum = QApplication::desktop()->screenNumber(window());
|
|
QRect desk = QApplication::desktop()->screenGeometry(scnum);
|
|
|
|
if ( d->defaultWindowSize.isNull() ) // only once
|
|
d->defaultWindowSize = QRect(desk.width(), width(), desk.height(), height()); // store default values
|
|
const QSize size( config.readEntry( QString::fromLatin1("Width %1").arg(desk.width()), 0 ),
|
|
config.readEntry( QString::fromLatin1("Height %1").arg(desk.height()), 0 ) );
|
|
if ( !size.isEmpty() ) {
|
|
#ifdef Q_WS_X11
|
|
int state = ( size.width() > desk.width() ? NET::MaxHoriz : 0 )
|
|
| ( size.height() > desk.height() ? NET::MaxVert : 0 );
|
|
if(( state & NET::Max ) == NET::Max )
|
|
resize( desk.width(), desk.height() ); // WORKAROUND: this should not be needed. KWindowSystem::setState
|
|
// should be enough for maximizing. (ereslibre)
|
|
else if(( state & NET::MaxHoriz ) == NET::MaxHoriz )
|
|
resize( desk.width(), size.height() );
|
|
else if(( state & NET::MaxVert ) == NET::MaxVert )
|
|
resize( size.width(), desk.height() );
|
|
else
|
|
resize( size );
|
|
// QWidget::showMaximized() is both insufficient and broken
|
|
KWindowSystem::setState( winId(), state );
|
|
#else
|
|
if (size.width() > desk.width() || size.height() > desk.height())
|
|
setWindowState( Qt::WindowMaximized );
|
|
else
|
|
resize( size );
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
bool KMainWindow::initialGeometrySet() const
|
|
{
|
|
K_D(const KMainWindow);
|
|
return d->care_about_geometry;
|
|
}
|
|
|
|
void KMainWindow::ignoreInitialGeometry()
|
|
{
|
|
K_D(KMainWindow);
|
|
d->care_about_geometry = false;
|
|
}
|
|
|
|
void KMainWindow::setSettingsDirty()
|
|
{
|
|
K_D(KMainWindow);
|
|
d->setSettingsDirty();
|
|
}
|
|
|
|
bool KMainWindow::settingsDirty() const
|
|
{
|
|
K_D(const KMainWindow);
|
|
return d->settingsDirty;
|
|
}
|
|
|
|
void KMainWindow::setAutoSaveSettings( const QString & groupName, bool saveWindowSize )
|
|
{
|
|
setAutoSaveSettings(KConfigGroup(KGlobal::config(), groupName), saveWindowSize);
|
|
}
|
|
|
|
void KMainWindow::setAutoSaveSettings( const KConfigGroup & group,
|
|
bool saveWindowSize )
|
|
{
|
|
K_D(KMainWindow);
|
|
d->autoSaveSettings = true;
|
|
d->autoSaveGroup = group;
|
|
d->autoSaveWindowSize = saveWindowSize;
|
|
|
|
if (!saveWindowSize && d->sizeTimer) {
|
|
d->sizeTimer->stop();
|
|
}
|
|
|
|
// Now read the previously saved settings
|
|
applyMainWindowSettings(d->autoSaveGroup);
|
|
}
|
|
|
|
void KMainWindow::resetAutoSaveSettings()
|
|
{
|
|
K_D(KMainWindow);
|
|
d->autoSaveSettings = false;
|
|
if (d->settingsTimer) {
|
|
d->settingsTimer->stop();
|
|
}
|
|
}
|
|
|
|
bool KMainWindow::autoSaveSettings() const
|
|
{
|
|
K_D(const KMainWindow);
|
|
return d->autoSaveSettings;
|
|
}
|
|
|
|
QString KMainWindow::autoSaveGroup() const
|
|
{
|
|
K_D(const KMainWindow);
|
|
return d->autoSaveSettings ? d->autoSaveGroup.name() : QString();
|
|
}
|
|
|
|
KConfigGroup KMainWindow::autoSaveConfigGroup() const
|
|
{
|
|
K_D(const KMainWindow);
|
|
return d->autoSaveSettings ? d->autoSaveGroup : KConfigGroup();
|
|
}
|
|
|
|
void KMainWindow::saveAutoSaveSettings()
|
|
{
|
|
K_D(KMainWindow);
|
|
Q_ASSERT( d->autoSaveSettings );
|
|
//kDebug(200) << "KMainWindow::saveAutoSaveSettings -> saving settings";
|
|
saveMainWindowSettings(d->autoSaveGroup);
|
|
d->autoSaveGroup.sync();
|
|
d->settingsDirty = false;
|
|
}
|
|
|
|
bool KMainWindow::event( QEvent* ev )
|
|
{
|
|
K_D(KMainWindow);
|
|
switch( ev->type() ) {
|
|
#ifdef Q_WS_WIN
|
|
case QEvent::Move:
|
|
#endif
|
|
case QEvent::Resize:
|
|
d->setSizeDirty();
|
|
break;
|
|
case QEvent::Polish:
|
|
d->polish(this);
|
|
break;
|
|
case QEvent::ChildPolished:
|
|
{
|
|
QChildEvent *event = static_cast<QChildEvent*>(ev);
|
|
QDockWidget *dock = qobject_cast<QDockWidget*>(event->child());
|
|
KToolBar *toolbar = qobject_cast<KToolBar*>(event->child());
|
|
QMenuBar *menubar = qobject_cast<QMenuBar*>(event->child());
|
|
if (dock) {
|
|
connect(dock, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)),
|
|
this, SLOT(setSettingsDirty()));
|
|
connect(dock, SIGNAL(visibilityChanged(bool)),
|
|
this, SLOT(setSettingsDirty()), Qt::QueuedConnection);
|
|
connect(dock, SIGNAL(topLevelChanged(bool)),
|
|
this, SLOT(setSettingsDirty()));
|
|
|
|
// there is no signal emitted if the size of the dock changes,
|
|
// hence install an event filter instead
|
|
dock->installEventFilter(k_ptr->dockResizeListener);
|
|
} else if (toolbar) {
|
|
// there is no signal emitted if the size of the toolbar changes,
|
|
// hence install an event filter instead
|
|
toolbar->installEventFilter(k_ptr->dockResizeListener);
|
|
} else if (menubar) {
|
|
// there is no signal emitted if the size of the menubar changes,
|
|
// hence install an event filter instead
|
|
menubar->installEventFilter(k_ptr->dockResizeListener);
|
|
}
|
|
}
|
|
break;
|
|
case QEvent::ChildRemoved:
|
|
{
|
|
QChildEvent *event = static_cast<QChildEvent*>(ev);
|
|
QDockWidget *dock = qobject_cast<QDockWidget*>(event->child());
|
|
KToolBar *toolbar = qobject_cast<KToolBar*>(event->child());
|
|
QMenuBar *menubar = qobject_cast<QMenuBar*>(event->child());
|
|
if (dock) {
|
|
disconnect(dock, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)),
|
|
this, SLOT(setSettingsDirty()));
|
|
disconnect(dock, SIGNAL(visibilityChanged(bool)),
|
|
this, SLOT(setSettingsDirty()));
|
|
disconnect(dock, SIGNAL(topLevelChanged(bool)),
|
|
this, SLOT(setSettingsDirty()));
|
|
dock->removeEventFilter(k_ptr->dockResizeListener);
|
|
} else if (toolbar) {
|
|
toolbar->removeEventFilter(k_ptr->dockResizeListener);
|
|
} else if (menubar) {
|
|
menubar->removeEventFilter(k_ptr->dockResizeListener);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return QMainWindow::event( ev );
|
|
}
|
|
|
|
bool KMainWindow::hasMenuBar()
|
|
{
|
|
return internalMenuBar(this);
|
|
}
|
|
|
|
KMenuBar *KMainWindow::menuBar()
|
|
{
|
|
KMenuBar * mb = internalMenuBar(this);
|
|
if ( !mb ) {
|
|
mb = new KMenuBar( this );
|
|
// trigger a re-layout and trigger a call to the private
|
|
// setMenuBar method.
|
|
setMenuBar(mb);
|
|
}
|
|
return mb;
|
|
}
|
|
|
|
KStatusBar *KMainWindow::statusBar()
|
|
{
|
|
KStatusBar * sb = internalStatusBar(this);
|
|
if ( !sb ) {
|
|
sb = new KStatusBar( this );
|
|
// trigger a re-layout and trigger a call to the private
|
|
// setStatusBar method.
|
|
setStatusBar(sb);
|
|
}
|
|
return sb;
|
|
}
|
|
|
|
void KMainWindowPrivate::_k_shuttingDown()
|
|
{
|
|
// Needed for Qt <= 3.0.3 at least to prevent reentrancy
|
|
// when queryExit() shows a dialog. Check before removing!
|
|
static bool reentrancy_protection = false;
|
|
if (!reentrancy_protection)
|
|
{
|
|
reentrancy_protection = true;
|
|
shuttingDown = true;
|
|
// call the virtual queryExit
|
|
q->queryExit();
|
|
reentrancy_protection = false;
|
|
}
|
|
}
|
|
|
|
void KMainWindowPrivate::_k_slotSettingsChanged(int category)
|
|
{
|
|
Q_UNUSED(category);
|
|
|
|
// This slot will be called when the style KCM changes settings that need
|
|
// to be set on the already running applications.
|
|
|
|
// At this level (KMainWindow) the only thing we need to restore is the
|
|
// animations setting (whether the user wants builtin animations or not).
|
|
|
|
q->setAnimated(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects);
|
|
}
|
|
|
|
void KMainWindowPrivate::_k_slotSaveAutoSaveSize()
|
|
{
|
|
if (autoSaveGroup.isValid()) {
|
|
q->saveWindowSize(autoSaveGroup);
|
|
}
|
|
}
|
|
|
|
KToolBar *KMainWindow::toolBar( const QString& name )
|
|
{
|
|
QString childName = name;
|
|
if (childName.isEmpty())
|
|
childName = "mainToolBar";
|
|
|
|
KToolBar *tb = findChild<KToolBar*>(childName);
|
|
if ( tb )
|
|
return tb;
|
|
|
|
KToolBar* toolbar = new KToolBar(childName, this); // non-XMLGUI toolbar
|
|
return toolbar;
|
|
}
|
|
|
|
QList<KToolBar*> KMainWindow::toolBars() const
|
|
{
|
|
QList<KToolBar*> ret;
|
|
|
|
foreach (QObject* child, children())
|
|
if (KToolBar* toolBar = qobject_cast<KToolBar*>(child))
|
|
ret.append(toolBar);
|
|
|
|
return ret;
|
|
}
|
|
|
|
QList<KMainWindow*> KMainWindow::memberList() { return *sMemberList; }
|
|
|
|
QString KMainWindow::dbusName() const
|
|
{
|
|
return k_func()->dbusName;
|
|
}
|
|
|
|
#include "kmainwindow.moc"
|
|
|