Index: trunk/kdebase/kdesktop/desktop.cc =================================================================== --- trunk/kdebase/kdesktop/desktop.cc (revision 256732) +++ trunk/kdebase/kdesktop/desktop.cc (revision 256733) @@ -1,810 +1,809 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library 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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "desktop.h" #include "krootwm.h" #include "bgmanager.h" #include "bgsettings.h" #include "startupid.h" #include "kdiconview.h" #include "minicli.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Create the equivalent of KAccelBase::connectItem // and then remove this include and fix reconnects in initRoot() -- ellis //#include // root window hack #include #include #include #include // ---- class KRootWidget : public QObject { public: KRootWidget() : QObject() { kapp->desktop()->installEventFilter(this); } bool eventFilter ( QObject *, QEvent * e ) { if (e->type() == QEvent::MouseButtonPress) { QMouseEvent *me = (QMouseEvent *) e; KRootWm::self()->mousePressed( me->globalPos(), me->button() ); return true; } return false; // Don't filter. } }; // ----------------------------------------------------------------------------- #define DEFAULT_DELETEACTION 1 // for multihead - from main.cc extern int kdesktop_screen_number; KDesktop::KDesktop( bool x_root_hack, bool auto_start, bool wait_for_kded ) : DCOPObject( "KDesktopIface" ), QWidget( 0L, "desktop", WResizeNoErase | ( x_root_hack ? (WStyle_Customize | WStyle_NoBorder) : 0) ), // those two WStyle_ break kdesktop when the root-hack isn't used (no Dnd) startup_id( NULL ) { m_bAutoStart = auto_start; m_bWaitForKded = wait_for_kded; m_miniCli = 0; // created on demand m_show_iconview = false; keys = 0; // created later KGlobal::locale()->insertCatalogue("kdesktop"); KGlobal::locale()->insertCatalogue("libkonq"); // needed for apps using libkonq setCaption( "KDE Desktop"); KWin::setType( winId(), NET::Desktop ); KWin::setState( winId(), NET::SkipPager ); KWin::setOnAllDesktops( winId(), true ); setAcceptDrops(true); // WStyle_Customize seems to disable that m_pKwinmodule = new KWinModule( this ); updateWorkAreaTimer = new QTimer( this ); connect( updateWorkAreaTimer, SIGNAL( timeout() ), this, SLOT( updateWorkArea() ) ); connect( m_pKwinmodule, SIGNAL( workAreaChanged() ), this, SLOT( workAreaChanged() ) ); // Dont repaint on configuration changes during construction m_bInit = true; // It's the child widget that gets the focus, not us setFocusPolicy( NoFocus ); if ( x_root_hack ) { // this is a ugly hack to make Dnd work // Matthias told me that it won't be necessary with kwin // actually my first try with ICCCM (Dirk) :-) unsigned long data[2]; data[0] = (unsigned long) 1; data[1] = (unsigned long) 0; // None; (Werner) Atom wm_state = XInternAtom(qt_xdisplay(), "WM_STATE", False); XChangeProperty(qt_xdisplay(), winId(), wm_state, wm_state, 32, PropModeReplace, (unsigned char *)data, 2); } setGeometry( QApplication::desktop()->geometry() ); lower(); connect( kapp, SIGNAL( shutDown() ), this, SLOT( slotShutdown() ) ); connect(kapp, SIGNAL(settingsChanged(int)), this, SLOT(slotSettingsChanged(int))); kapp->addKipcEventMask(KIPC::SettingsChanged); kapp->addKipcEventMask(KIPC::IconChanged); connect(kapp, SIGNAL(iconChanged(int)), this, SLOT(slotIconChanged(int))); connect(KSycoca::self(), SIGNAL(databaseChanged()), this, SLOT(slotDatabaseChanged())); m_pIconView = 0; m_pRootWidget = 0; bgMgr = 0; initRoot(); QTimer::singleShot(0, this, SLOT( slotStart() )); #if (QT_VERSION-0 >= 0x030200) // XRANDR support connect( kapp->desktop(), SIGNAL( resized( int )), SLOT( desktopResized())); #endif } void KDesktop::initRoot() { Display *dpy = qt_xdisplay(); Window root = RootWindow(dpy, kdesktop_screen_number); XDefineCursor(dpy, root, cursor().handle()); KConfigGroup configGroup(KGlobal::config(), "General"); m_bDesktopEnabled = configGroup.readBoolEntry("Enabled", true); if (!m_bDesktopEnabled && !m_pRootWidget) { hide(); delete bgMgr; bgMgr = 0; if ( m_pIconView ) m_pIconView->slotSaveIconPositions(); delete m_pIconView; m_pIconView = 0; XWindowAttributes attrs; XGetWindowAttributes(dpy, root, &attrs); XSelectInput(dpy, root, attrs.your_event_mask | ButtonPressMask); m_pRootWidget = new KRootWidget; // Geert Jansen: backgroundmanager belongs here // TODO tell KBackgroundManager if we change widget() bgMgr = new KBackgroundManager( m_pIconView, m_pKwinmodule ); connect( bgMgr, SIGNAL( initDone()), SLOT( backgroundInitDone())); if (!m_bInit) { delete KRootWm::self(); KRootWm* krootwm = new KRootWm( this ); // handler for root menu (used by kdesktop on RMB click) keys->setSlot("Lock Screen", krootwm, SLOT(slotLock())); keys->updateConnections(); } } else if (m_bDesktopEnabled && !m_pIconView) { delete bgMgr; bgMgr = 0; delete m_pRootWidget; m_pRootWidget = 0; m_pIconView = new KDIconView( this, 0 ); connect( m_pIconView, SIGNAL( imageDropEvent( QDropEvent * ) ), this, SLOT( handleImageDropEvent( QDropEvent * ) ) ); connect( m_pIconView, SIGNAL( colorDropEvent( QDropEvent * ) ), this, SLOT( handleColorDropEvent( QDropEvent * ) ) ); connect( m_pIconView, SIGNAL( newWallpaper( const KURL & ) ), this, SLOT( slotNewWallpaper( const KURL & ) ) ); // All the QScrollView/QWidget-specific stuff should go here, so that we can use // another qscrollview/widget instead of the iconview and use the same code m_pIconView->setVScrollBarMode( QScrollView::AlwaysOff ); m_pIconView->setHScrollBarMode( QScrollView::AlwaysOff ); m_pIconView->setDragAutoScroll( false ); m_pIconView->setFrameStyle( QFrame::NoFrame ); m_pIconView->viewport()->setBackgroundMode( X11ParentRelative ); m_pIconView->setFocusPolicy( StrongFocus ); m_pIconView->viewport()->setFocusPolicy( StrongFocus ); m_pIconView->setGeometry( geometry() ); if (m_show_iconview && !m_bInit) m_pIconView->show(); // Geert Jansen: backgroundmanager belongs here // TODO tell KBackgroundManager if we change widget() bgMgr = new KBackgroundManager( m_pIconView, m_pKwinmodule ); connect( bgMgr, SIGNAL( initDone()), SLOT( backgroundInitDone())); //kdDebug(1204) << "KDesktop constructor -> workAreaChanged" << endl; workAreaChanged(); if (!m_bInit) { m_pIconView->initConfig( m_bInit ); m_pIconView->start(); delete KRootWm::self(); KRootWm* krootwm = new KRootWm( this ); // handler for root menu (used by kdesktop on RMB click) keys->setSlot("Lock Screen", krootwm, SLOT(slotLock())); keys->updateConnections(); } } } void KDesktop::backgroundInitDone() { //kdDebug(1204) << "KDesktop::backgroundInitDone" << endl; // avoid flicker if (m_bDesktopEnabled) { const QPixmap *bg = QApplication::desktop()->screen()->backgroundPixmap(); if ( bg ) m_pIconView->setErasePixmap( *bg ); show(); } } void KDesktop::slotStart() { //kdDebug(1204) << "KDesktop::slotStart" << endl; if (!m_bInit) return; kapp->dcopClient()->send( "ksplash", "", "upAndRunning(QString)", QString("kdesktop")); // In case we started without database KImageIO::registerFormats(); initConfig(); // if (m_bDesktopEnabled) // { // // We need to be visible in order to insert icons, even if the background isn't ready yet... // show(); // } // Now we may react to configuration changes m_bInit = false; if (m_pIconView) m_pIconView->start(); // Global keys keys = new KGlobalAccel( this ); (void) new KRootWm( this ); #include "kdesktopbindings.cpp" keys->readSettings(); keys->updateConnections(); if ( m_bAutoStart ) { // now let's execute all the stuff in the autostart folder. // the stuff will actually be really executed when the event loop is // entered, since KRun internally uses a QTimer QDir dir( KGlobalSettings::autostartPath() ); QStringList entries = dir.entryList( QDir::Files ); QStringList::Iterator it = entries.begin(); QStringList::Iterator end = entries.end(); for (; it != end; ++it ) { // Don't execute backup files if ( (*it).right(1) != "~" && (*it).right(4) != ".bak" && ( (*it)[0] != '%' || (*it).right(1) != "%" ) && ( (*it)[0] != '#' || (*it).right(1) != "#" ) ) { KURL url; url.setPath( dir.absPath() + '/' + (*it) ); (void) new KRun( url, 0, true ); } } } connect(kapp, SIGNAL(appearanceChanged()), SLOT(slotConfigure())); QTimer::singleShot(300, this, SLOT( slotUpAndRunning() )); } // ----------------------------------------------------------------------------- KDesktop::~KDesktop() { delete m_miniCli; delete bgMgr; delete startup_id; } // ----------------------------------------------------------------------------- void KDesktop::initConfig() { if (m_pIconView) m_pIconView->initConfig( m_bInit ); if ( keys ) { keys->readSettings(); keys->updateConnections(); } KConfig c( "klaunchrc", true ); c.setGroup( "FeedbackStyle" ); if( !c.readBoolEntry( "BusyCursor", true )) { delete startup_id; startup_id = NULL; } else { if( startup_id == NULL ) startup_id = new StartupId; startup_id->configure(); } KConfig * config = KGlobal::config(); config->setGroup( "General" ); set_vroot = config->readBoolEntry( "SetVRoot", false ); slotSetVRoot(); // start timer } // ----------------------------------------------------------------------------- void KDesktop::slotExecuteCommand() { // this function needs to be duplicated since it appears that one // cannot have a 'slot' be a DCOP method. if this changes in the // future, then 'slotExecuteCommand' and 'popupExecuteCommand' can // merge into one slot. popupExecuteCommand(); } /* Shows minicli */ void KDesktop::popupExecuteCommand() { if (m_bInit) return; if (!kapp->authorize("run_command")) return; // Created on demand if ( !m_miniCli ) { m_miniCli = new Minicli; m_miniCli->adjustSize(); // for the centering below } // Move minicli to the current desktop NETWinInfo info( qt_xdisplay(), m_miniCli->winId(), qt_xrootwin(), NET::WMDesktop ); int currentDesktop = kwinModule()->currentDesktop(); if ( info.desktop() != currentDesktop ) info.setDesktop( currentDesktop ); // Update the user timestamp. Minicli can be shown either by a keyboard shortcut, // or by a DCOP call. In the case of the DCOP call, this is necessary, otherwise // kwin's focus stealing prevention could refuse to make minicli the active window. // This means the DCOP call is only for user scripting. In the case of keyboard // shortcut, the shortcut itself is user action, so this doesn't really matter, // it only makes sure minicli will be active even if kdesktop will be slow to react. // (kdebase/kwin/README, section on focus stealing prevention) kapp->updateUserTimestamp(); if ( m_miniCli->isVisible() ) { KWin::setActiveWindow( m_miniCli->winId() ); } else { QRect rect = KGlobalSettings::desktopGeometry(QCursor::pos()); m_miniCli->move(rect.x() + (rect.width() - m_miniCli->width())/2, rect.y() + (rect.height() - m_miniCli->height())/4); m_miniCli->exec(); } } void KDesktop::slotShowWindowList() { - KWin::setActiveWindow( winId() ); KRootWm::self()->slotWindowList(); } void KDesktop::slotShowTaskManager() { kdDebug(1204) << "Launching KSysGuard..." << endl; KProcess* p = new KProcess; Q_CHECK_PTR(p); *p << "ksysguard"; *p << "--showprocesses"; p->start(KProcess::DontCare); delete p; } // ----------------------------------------------------------------------------- void KDesktop::rearrangeIcons() { if (m_pIconView) m_pIconView->rearrangeIcons(); } void KDesktop::lineupIcons() { if (m_pIconView) m_pIconView->lineupIcons(); } void KDesktop::selectAll() { if (m_pIconView) m_pIconView->selectAll( true ); } void KDesktop::unselectAll() { if (m_pIconView) m_pIconView->selectAll( false ); } QStringList KDesktop::selectedURLs() { if (m_pIconView) return m_pIconView->selectedURLs(); return QStringList(); } void KDesktop::refreshIcons() { if (m_pIconView) m_pIconView->refreshIcons(); } KActionCollection * KDesktop::actionCollection() { if (!m_pIconView) return 0; return m_pIconView->actionCollection(); } KURL KDesktop::url() const { if (m_pIconView) return m_pIconView->url(); return KURL(); } // ----------------------------------------------------------------------------- void KDesktop::slotConfigure() { configure(); } void KDesktop::configure() { // re-read configuration and apply it KGlobal::config()->reparseConfiguration(); // If we have done start() already, then re-configure. // Otherwise, start() will call initConfig anyway if (!m_bInit) { initRoot(); initConfig(); KRootWm::self()->initConfig(); } keys->readSettings(); keys->updateConnections(); } void KDesktop::slotSettingsChanged(int category) { //kdDebug(1204) << "KDesktop::slotSettingsChanged" << endl; if (category == KApplication::SETTINGS_PATHS) { kdDebug(1204) << "KDesktop::slotSettingsChanged SETTINGS_PATHS" << endl; if (m_pIconView) m_pIconView->recheckDesktopURL(); } else if (category == KApplication::SETTINGS_SHORTCUTS) { kdDebug(1204) << "KDesktop::slotSettingsChanged SETTINGS_SHORTCUTS" << endl; keys->readSettings(); keys->updateConnections(); } } void KDesktop::slotIconChanged(int group) { if ( group == KIcon::Desktop ) { kdDebug(1204) << "KDesktop::slotIconChanged" << endl; refreshIcons(); refresh(); } } void KDesktop::slotDatabaseChanged() { //kdDebug(1204) << "KDesktop::slotDatabaseChanged" << endl; if (m_bInit) // kded is done, now we can "start" for real slotStart(); if (m_pIconView && KSycoca::isChanged("mimetypes")) m_pIconView->refreshMimeTypes(); } void KDesktop::refresh() { // George Staikos 3/14/01 // This bit will just refresh the desktop and icons. Now I have code // in KWin to do a complete refresh so this isn't really needed. // I'll leave it in here incase the plan is changed again #if 0 m_bNeedRepaint |= 1; updateWorkArea(); refreshIcons(); #endif kapp->dcopClient()->send( "kwin", "", "refresh()", ""); } // ----------------------------------------------------------------------------- void KDesktop::slotSetVRoot() { if (!m_pIconView) return; if (KWin::windowInfo(winId()).mappingState() == NET::Withdrawn) { QTimer::singleShot(100, this, SLOT(slotSetVRoot())); return; } unsigned long rw = RootWindowOfScreen(ScreenOfDisplay(qt_xdisplay(), qt_xscreen())); unsigned long vroot_data[1] = { m_pIconView->viewport()->winId() }; static Atom vroot = XInternAtom(qt_xdisplay(), "__SWM_VROOT", False); Window rootReturn, parentReturn, *children; unsigned int numChildren; Window top = winId(); while (1) { /*int ret = */XQueryTree(qt_xdisplay(), top , &rootReturn, &parentReturn, &children, &numChildren); if (children) XFree((char *)children); if (parentReturn == rw) { break; } else top = parentReturn; } if ( set_vroot ) XChangeProperty(qt_xdisplay(), top, vroot, XA_WINDOW, 32, PropModeReplace, (unsigned char *)vroot_data, 1); else XDeleteProperty (qt_xdisplay(), top, vroot); } // ----------------------------------------------------------------------------- void KDesktop::slotShutdown() { if ( m_pIconView ) m_pIconView->slotSaveIconPositions(); if ( m_miniCli ) m_miniCli->saveConfig(); } // don't hide when someone presses Alt-F4 on us void KDesktop::closeEvent(QCloseEvent *e) { e->ignore(); } void KDesktop::workAreaChanged() { //kdDebug(1204) << "KDesktop::workAreaChanged() -> starting timer" << endl; updateWorkAreaTimer->stop(); updateWorkAreaTimer->start( 100, TRUE ); } void KDesktop::updateWorkArea() { if (m_pIconView) { QRect wr( kwinModule()->workArea( kwinModule()->currentDesktop() ) ); m_pIconView->updateWorkArea( wr ); } } void KDesktop::handleColorDropEvent(QDropEvent * e) { KPopupMenu popup; popup.insertItem(SmallIconSet("colors"),i18n("Set as Primary Background Color"), 1); popup.insertItem(SmallIconSet("colors"),i18n("Set as Secondary Background Color"), 2); int result = popup.exec(e->pos()); QColor c; KColorDrag::decode(e, c); switch (result) { case 1: bgMgr->setColor(c, true); break; case 2: bgMgr->setColor(c, false); break; default: break; } bgMgr->setWallpaper(0,0); } void KDesktop::handleImageDropEvent(QDropEvent * e) { KPopupMenu popup; popup.insertItem(SmallIconSet("filesave"),i18n("&Save to Desktop..."), 1); popup.insertItem(SmallIconSet("background"),i18n("Set as &Wallpaper"), 2); popup.insertSeparator(); popup.insertItem(SmallIconSet("cancel"), i18n("&Cancel")); int result = popup.exec(e->pos()); if (result == 1) { bool ok = true; QString filename = KInputDialog::getText(QString::null, i18n("Enter a name for the image below:"), QString::null, &ok, m_pIconView); if (!ok) { return; } if (filename.isEmpty()) { filename = i18n("image.png"); } else if (filename.right(4).lower() != ".png") { filename += ".png"; } QImage i; QImageDrag::decode(e, i); KTempFile tmpFile(QString::null, filename); i.save(tmpFile.name(), "PNG"); KIO::NetAccess::copy(tmpFile.name(), KGlobalSettings::desktopPath() + "/" + filename); tmpFile.unlink(); } else if (result == 2) { QImage i; QImageDrag::decode(e, i); KTempFile tmpFile(KGlobal::dirs()->saveLocation("wallpaper"), ".png"); i.save(tmpFile.name(), "PNG"); kdDebug(1204) << "KDesktop::contentsDropEvent " << tmpFile.name() << endl; bgMgr->setWallpaper(tmpFile.name()); } } void KDesktop::slotNewWallpaper(const KURL &url) { // This is called when a file containing an image is dropped // (called by KonqOperations) QString tmpFile; KIO::NetAccess::download( url, tmpFile ); bgMgr->setWallpaper(tmpFile); } // for dcop interface backward compatibility void KDesktop::logout() { logout( KApplication::ShutdownConfirmDefault, KApplication::ShutdownTypeNone ); } void KDesktop::logout( KApplication::ShutdownConfirm confirm, KApplication::ShutdownType sdtype ) { if( !kapp->requestShutDown( confirm, sdtype ) ) // this i18n string is also in kicker/applets/run/runapplet KMessageBox::error( this, i18n("Could not logout properly.\nThe session manager cannot " "be contacted. You can try to force a shutdown by pressing " "Ctrl+Alt+Backspace. Note, however, that your current session " "will not be saved with a forced shutdown." ) ); } void KDesktop::slotLogout() { logout( KApplication::ShutdownConfirmDefault, KApplication::ShutdownTypeDefault ); } void KDesktop::slotLogoutNoCnf() { logout( KApplication::ShutdownConfirmNo, KApplication::ShutdownTypeNone ); } void KDesktop::slotHaltNoCnf() { logout( KApplication::ShutdownConfirmNo, KApplication::ShutdownTypeHalt ); } void KDesktop::slotRebootNoCnf() { logout( KApplication::ShutdownConfirmNo, KApplication::ShutdownTypeReboot ); } void KDesktop::setVRoot( bool enable ) { if ( enable == set_vroot ) return; set_vroot = enable; kdDebug(1204) << "setVRoot " << enable << endl; KConfig * config = KGlobal::config(); KConfigGroupSaver gs( config, "General" ); config->writeEntry( "SetVRoot", set_vroot ); config->sync(); slotSetVRoot(); } void KDesktop::clearCommandHistory() { if ( m_miniCli ) m_miniCli->clearHistory(); } void KDesktop::setIconsEnabled( bool enable ) { if ( enable == m_bDesktopEnabled ) return; m_bDesktopEnabled = enable; kdDebug(1204) << "setIcons " << enable << endl; KConfig * config = KGlobal::config(); KConfigGroupSaver gs( config, "General" ); config->writeEntry( "Enabled", m_bDesktopEnabled ); config->sync(); if (!enable) { delete m_pIconView; m_pIconView = 0; m_show_iconview = false; } else m_show_iconview = true; configure(); } void KDesktop::desktopResized() { resize( kapp->desktop()->size()); } bool KDesktop::event(QEvent * e) { if ( e->type() == QEvent::WindowDeactivate) { if (m_pIconView) m_pIconView->clearSelection(); } return QWidget::event(e); } #include "desktop.moc"