/************************************************************************** kpager.cpp - KPager's main window Copyright (C) 2000 Antonio Larrosa Jimenez Matthias Ettrich Matthias Elter 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. Send comments and bug fixes to larrosa@kde.org ***************************************************************************/ /* * There is a features that is only configurable by manually editing the * config file due to the translation freeze . The key is * windowTransparentMode and the values are : * 0 = Never * 1 = Only maximized windows are painted transparent * 2 = Every window is painted transparent (default) * */ #include "config.h" #include "kpager.h" #include <tqintdict.h> #include <tqptrlist.h> #include <tqlayout.h> #include <tqtooltip.h> #include <tqtimer.h> #include <kapplication.h> #include <kglobalsettings.h> #include <kaction.h> #include <kstdaction.h> #include <kglobal.h> #include <kconfig.h> #include <kdebug.h> #include <klocale.h> #include <twin.h> #include <twinmodule.h> #include <netwm.h> #include "desktop.h" #include <tqpopupmenu.h> #include <kpopupmenu.h> #include <kiconloader.h> #include <assert.h> KPagerMainWindow::KPagerMainWindow(TQWidget *parent, const char *name) : DCOPObject("KPagerIface"), KMainWindow(parent, name) { m_reallyClose=false; m_pPager = new KPager(this, 0); setCentralWidget(m_pPager); KConfig *cfg = kapp->config(); cfg->setGroup("KPager"); // Update the last used geometry int w = cfg->readNumEntry(m_pPager->lWidth(),-1); int h = cfg->readNumEntry(m_pPager->lHeight(),-1); if (w > 0 && h > 0) resize(w,h); else resize(m_pPager->sizeHint()); // resize(cfg->readNumEntry(lWidth(),200),cfg->readNumEntry(lHeight(),90)); int xpos=cfg->readNumEntry("xPos",-1); int ypos=cfg->readNumEntry("yPos",-1); if (xpos > 0 && ypos > 0) move(xpos,ypos); else { // NETRootInfo ri( tqt_xdisplay(), NET::WorkArea ); // NETRect rect=ri.workArea(1); // move(rect.pos.x+rect.size.width-m_pPager->width(), // rect.pos.y+rect.size.height-m_pPager->height()); // antonio:The above lines don't work. I should look at them when I have // more time move(kapp->desktop()->width()-m_pPager->sizeHint().width()-5,kapp->desktop()->height()-m_pPager->sizeHint().height()-25); } // Set the wm flags to this window KWin::setState( winId(), NET::StaysOnTop | NET::SkipTaskbar | NET::Sticky | NET::SkipPager ); KWin::setOnAllDesktops( winId(), true); if ( KWin::windowInfo( winId(), NET::WMWindowType, 0 ).windowType(NET::Normal) == NET::Normal ) { KWin::setType( winId(), NET::Utility ); } XWMHints *hints = XGetWMHints(x11Display(), winId()); if( hints == NULL ) hints = XAllocWMHints(); hints->input = false; hints->flags |= InputHint; XSetWMHints(x11Display(), winId(), hints); XFree(reinterpret_cast<char *>(hints)); timeout=new TQTimer(this,"timeoutToQuit"); connect(timeout,TQT_SIGNAL(timeout()),this, TQT_SLOT(reallyClose())); } KPagerMainWindow::~KPagerMainWindow() { } extern bool closed_by_sm; bool KPagerMainWindow::queryClose() { KConfig *cfg=KGlobal::config(); cfg->setGroup("KPager"); cfg->writeEntry("layoutType", static_cast<int>(m_pPager->m_layoutType)); cfg->writeEntry(m_pPager->lWidth(),width()); cfg->writeEntry(m_pPager->lHeight(),height()); cfg->writeEntry("xPos",x()); cfg->writeEntry("yPos",y()); cfg->sync(); kdDebug() << "queryCLose " << m_reallyClose << " " << closed_by_sm << endl; if (m_reallyClose || closed_by_sm) return true; hide(); timeout->start(10 /*minutes*/ *60000, true); return false; } void KPagerMainWindow::showEvent( TQShowEvent *ev ) { timeout->stop(); KMainWindow::showEvent(ev); } void KPagerMainWindow::reallyClose() { m_reallyClose=true; close(); } void KPagerMainWindow::showAt(int x, int y) { // Just in case we lost the sticky bit... (as when a window is hidden) KWin::setOnAllDesktops( winId(), true); if (x>kapp->desktop()->width()/2) // Right x-=m_pPager->width()+5; if (y>kapp->desktop()->height()/2) // Bottom y-=m_pPager->height()+25; move(x,y); show(); } void KPagerMainWindow::toggleShow(int x, int y) { if (isVisible()) { hide(); timeout->start(10 /*minutes*/ *60000, true); } else showAt(x,y); } KPager::KPager(KPagerMainWindow *parent, const char *name) : TQFrame (parent, name, (WFlags)(WStyle_Customize | WStyle_NoBorder | WStyle_Tool)) , m_layout(0) , m_mnu(0) , m_smnu(0) , m_dmnu(0) { m_windows.setAutoDelete(true); // delete windows info after removal setBackgroundColor( black ); m_winmodule=new KWinModule(TQT_TQOBJECT(this)); m_currentDesktop=m_winmodule->currentDesktop(); m_grabWinTimer=new TQTimer(this,"grabWinTimer"); connect(m_grabWinTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotGrabWindows())); KPagerConfigDialog::initConfiguration(); KConfig *cfg = kapp->config(); cfg->setGroup("KPager"); m_showStickyOption=cfg->readBoolEntry("ShowStickyOption",false); int numberOfDesktops=m_winmodule->numberOfDesktops(); for (int i=0;i<numberOfDesktops;i++) { Desktop *dsk=new Desktop(i+1,m_winmodule->desktopName(i),this); m_desktops.append(dsk); } m_layoutType=static_cast<enum KPager::LayoutTypes>( KPagerConfigDialog::m_layoutType ); connect( m_winmodule, TQT_SIGNAL( activeWindowChanged(WId)), TQT_SLOT(slotActiveWindowChanged(WId))); connect( m_winmodule, TQT_SIGNAL( windowAdded(WId) ), TQT_SLOT( slotWindowAdded(WId) ) ); connect( m_winmodule, TQT_SIGNAL( windowRemoved(WId) ), TQT_SLOT( slotWindowRemoved(WId) ) ); connect( m_winmodule, TQT_SIGNAL( windowChanged(WId,unsigned int) ), TQT_SLOT( slotWindowChanged(WId,unsigned int) ) ); connect( m_winmodule, TQT_SIGNAL( stackingOrderChanged() ), TQT_SLOT( slotStackingOrderChanged() ) ); connect( m_winmodule, TQT_SIGNAL( desktopNamesChanged() ), TQT_SLOT( slotDesktopNamesChanged() ) ); connect( m_winmodule, TQT_SIGNAL( numberOfDesktopsChanged(int) ), TQT_SLOT( slotNumberOfDesktopsChanged(int) ) ); connect( m_winmodule, TQT_SIGNAL( currentDesktopChanged(int)), TQT_SLOT( slotCurrentDesktopChanged(int) ) ); connect(kapp, TQT_SIGNAL(backgroundChanged(int)), TQT_SLOT(slotBackgroundChanged(int))); TQFont defFont(KGlobalSettings::generalFont().family(), 10, TQFont::Bold); defFont = cfg->readFontEntry("Font", &defFont); setFont(defFont); m_prefs_action = KStdAction::preferences(TQT_TQOBJECT(this), TQT_SLOT(configureDialog()), parent->actionCollection()); m_quit_action = KStdAction::quit(TQT_TQOBJECT(kapp), TQT_SLOT(quit()), parent->actionCollection()); updateLayout(); } KPager::~KPager() { } const TQString KPager::lWidth() { switch (m_layoutType) { case (Classical) : return "layoutClassicalWidth";break; case (Horizontal) : return "layoutHorizontalWidth";break; case (Vertical) : return "layoutVerticalWidth";break; }; return "Width"; } const TQString KPager::lHeight() { switch (m_layoutType) { case (Classical) : return "layoutClassicalHeight";break; case (Horizontal) : return "layoutHorizontalHeight";break; case (Vertical) : return "layoutVerticalHeight";break; }; return "Height"; } void KPager::updateLayout() { int w=m_desktops[0]->width(); int h=m_desktops[0]->height(); delete m_layout; switch (m_layoutType) { case (Classical) : m_layout=new TQGridLayout(this, 2, 0); break; case (Horizontal) : m_layout=new TQGridLayout(this, 0, 1); break; case (Vertical) : m_layout=new TQGridLayout(this, 1, 0); break; }; TQValueList <Desktop *>::Iterator it; int i,j; i=j=0; int ndesks=0; int halfdesks = (m_desktops.count() + 1) / 2; for( it = m_desktops.begin(); it != m_desktops.end(); ++it ) { m_layout->addWidget(*it,i,j); ndesks++; switch (m_layoutType) { case (Classical) : i= ndesks / halfdesks; j = ndesks % halfdesks; break; case (Horizontal) : j++; break; case (Vertical) : i++; break; }; } m_layout->activate(); updateGeometry(); switch (m_layoutType) { case (Classical) : resize(w*(ndesks/2+(ndesks%2)),h*2);break; case (Horizontal) : resize(w*ndesks,h);break; case (Vertical) : resize(w, h*ndesks);break; }; } void KPager::showPopupMenu( WId wid, TQPoint pos) { if (wid <= 0) { if(!m_smnu) { m_smnu = new TQPopupMenu(this); m_prefs_action->plug(m_smnu); m_quit_action->plug(m_smnu); } m_smnu->popup(pos); } else { m_winfo = KWin::windowInfo(wid); if (!m_mnu) { m_mnu = new KPopupMenu(this); m_mnu->insertTitle( TQString::fromUtf8("KPager"), 1); m_mnu->setCheckable(true); connect(m_mnu, TQT_SIGNAL(aboutToShow()), TQT_SLOT(clientPopupAboutToShow())); connect(m_mnu, TQT_SIGNAL(activated(int)), TQT_SLOT(clientPopupActivated(int))); m_dmnu = new TQPopupMenu(m_mnu); m_dmnu->setCheckable(true); connect(m_dmnu, TQT_SIGNAL(aboutToShow()), TQT_SLOT(desktopPopupAboutToShow())); connect(m_dmnu, TQT_SIGNAL(activated(int)), TQT_SLOT(sendToDesktop(int))); m_mnu->insertItem( i18n("Mi&nimize"), IconifyOp ); m_mnu->insertItem( i18n("Ma&ximize"), MaximizeOp ); if (m_showStickyOption) m_mnu->insertItem( TQString("&Sticky"), StickyOp ); // Add translation m_mnu->insertSeparator(); m_mnu->insertItem(i18n("&To Desktop"), m_dmnu ); m_mnu->insertSeparator(); m_mnu->insertItem(SmallIcon("fileclose"),i18n("&Close"), CloseOp); m_mnu->insertSeparator(); m_prefs_action->plug(m_mnu); m_quit_action->plug(m_mnu); } m_mnu->popup(pos); } } void KPager::configureDialog() { KPagerConfigDialog *dialog= new KPagerConfigDialog(this); if (dialog->exec()) { m_layoutType=static_cast<enum KPager::LayoutTypes>(KPagerConfigDialog::m_layoutType); KConfig *cfg=KGlobal::config(); int nWd = (parent() ? ((TQWidget *)parent())->width() : width()); int nHg = (parent() ? ((TQWidget *)parent())->width() : width()); cfg->setGroup("KPager"); cfg->writeEntry(lWidth(),nWd); cfg->writeEntry(lHeight(),nHg); cfg->writeEntry("windowDrawMode",KPagerConfigDialog::m_windowDrawMode); cfg->writeEntry("layoutType",KPagerConfigDialog::m_layoutType); cfg->writeEntry("showNumber",KPagerConfigDialog::m_showNumber); cfg->writeEntry("showName",KPagerConfigDialog::m_showName); cfg->writeEntry("showWindows",KPagerConfigDialog::m_showWindows); cfg->writeEntry("showBackground",KPagerConfigDialog::m_showBackground); cfg->writeEntry("windowDragging",KPagerConfigDialog::m_windowDragging); updateLayout(); for( TQValueList <Desktop *>::Iterator it = m_desktops.begin(); it != m_desktops.end(); ++it ) (*it)->repaint(); } } KWin::WindowInfo* KPager::info( WId win ) { KWin::WindowInfo* info = m_windows[win]; if (!info ) { info = new KWin::WindowInfo( KWin::windowInfo( win ) ); if( !info->valid() || info->desktop() == 0 ) { delete info; return NULL; // window no longer valid } m_windows.insert( (long) win, info ); } return info; } void KPager::slotActiveWindowChanged( WId win ) { KWin::WindowInfo* inf1 = info( m_activeWin ); KWin::WindowInfo* inf2 = info( win ); m_activeWin = win; // update window pixmap // in case of active desktop change it will be updated anyway by timer // if (!m_grabWinTimer->isActive()) // Desktop::removeCachedPixmap(win); for ( int i=1; i <= (int) m_desktops.count(); ++i) { if ( (inf1 && inf1->isOnDesktop(i)) || (inf2 && inf2->isOnDesktop(i) ) ) m_desktops[i-1]->repaint(false); } } void KPager::slotWindowAdded( WId win) { KWin::WindowInfo* inf = info( win ); if (!inf) return; // never should be here for ( int i=1; i <= (int) m_desktops.count(); ++i) { if ( inf->isOnDesktop( i )) m_desktops[i-1]->repaint(false); } } void KPager::slotWindowRemoved( WId win ) { KWin::WindowInfo* inf = m_windows[win]; if (inf) { bool onAllDesktops = inf->onAllDesktops(); int desktop = inf->desktop(); m_windows.remove( (long)win ); Desktop::removeCachedPixmap(win); for (int i = 1; i <= (int) m_desktops.count(); ++i) { if (onAllDesktops || desktop == i) m_desktops[i-1]->repaint(false); } } } void KPager::slotWindowChanged( WId win , unsigned int prop) { bool repaint=false; KWin::WindowInfo* inf = m_windows[win]; if (!inf) { inf=info(win); prop=0; // info already calls KWin::info, so there's no need // to update anything else. repaint=true; }; bool onAllDesktops = inf ? inf->onAllDesktops() : false; int desktop = inf ? inf->desktop() : 0; if (prop) { m_windows.remove( (long) win ); inf = info( win ); } if((prop & ~( NET::WMName | NET::WMVisibleName )) != 0 ) repaint = true; if (repaint) for ( int i=1; i <= (int) m_desktops.count(); ++i) { if ((inf && (inf->isOnDesktop(i))) || onAllDesktops || desktop == i ) { m_desktops[i-1]->repaint(false); } } // redrawDesktops(); } void KPager::slotStackingOrderChanged() { m_desktops[m_currentDesktop-1]->m_grabWindows=true; for ( int i=1; i <= (int) m_desktops.count(); ++i) { m_desktops[i-1]->repaint(false); } // repaint(true); } void KPager::slotDesktopNamesChanged() { for ( int i=1; i <= (int) m_desktops.count(); ++i) { TQToolTip::remove(m_desktops[i-1]); TQToolTip::add(m_desktops[i-1], twin()->desktopName(i)); } update(); emit updateLayout(); } void KPager::slotNumberOfDesktopsChanged(int ndesktops) { unsigned int nDesktops=static_cast<unsigned int>(ndesktops); if (nDesktops<m_desktops.count()) { TQValueList <Desktop *>::Iterator it; for ( int i=m_desktops.count()-nDesktops; i > 0; i--) { it = m_desktops.fromLast(); delete (*it); m_desktops.remove(it); } emit updateLayout(); } else if (nDesktops>m_desktops.count()) { int i,j; i=j=m_desktops.count(); switch (m_layoutType) { case (Classical) : i%=2;j/=2; break; case (Horizontal) : i=0; break; case (Vertical) : j=0; break; } for (unsigned int d=m_desktops.count()+1;d<=nDesktops; d++) { Desktop *dsk=new Desktop(d,twin()->desktopName(d-1),this); m_desktops.append(dsk); dsk->show(); } emit updateLayout(); } } void KPager::slotCurrentDesktopChanged(int desk) { if (m_currentDesktop==desk) return; m_desktops[m_currentDesktop-1]->paintFrame( false ); m_desktops[m_currentDesktop-1]->update(); m_desktops[desk-1]->paintFrame( true ); m_desktops[desk-1]->update(); // m_desktops[m_currentDesktop-1]->repaint(); // m_desktops[desk-1]->repaint(); m_currentDesktop=desk; if (m_grabWinTimer->isActive()) m_grabWinTimer->stop(); if ( static_cast<Desktop::WindowDrawMode>( KPagerConfigDialog::m_windowDrawMode ) == Desktop::Pixmap ) m_grabWinTimer->start(1000,true); } void KPager::slotBackgroundChanged(int desk) { m_desktops[desk-1]->loadBgPixmap(); } void KPager::sendToDesktop(int desk) { if (desk == 0) KWin::setOnAllDesktops(m_winfo.win(), true); else { KWin::setOnDesktop(m_winfo.win(), desk); } } void KPager::clientPopupAboutToShow() { if (!m_mnu) return; m_mnu->changeTitle(1,KWin::icon(m_winfo.win(),16,16,true), m_winfo.name()); m_mnu->setItemChecked(IconifyOp, m_winfo.isMinimized()); m_mnu->setItemChecked(MaximizeOp, m_winfo.state() & NET::Max); if (m_showStickyOption) // Add translation m_mnu->changeItem(StickyOp, (m_winfo.onAllDesktops()) ? TQString("Un&sticky"):TQString("&Sticky")); } void KPager::desktopPopupAboutToShow() { if (!m_dmnu) return; m_dmnu->clear(); m_dmnu->insertItem( i18n("&All Desktops"), 0 ); m_dmnu->insertSeparator(); if (m_winfo.onAllDesktops()) m_dmnu->setItemChecked( 0, true ); int id; for ( int i = 1; i <= m_winmodule->numberOfDesktops(); i++ ) { id = m_dmnu->insertItem( TQString("&")+TQString::number(i )+TQString(" ") + m_winmodule->desktopName(i), i ); if ( m_winfo.desktop() == i ) m_dmnu->setItemChecked( id, TRUE ); } } void KPager::clientPopupActivated( int id ) { switch ( id ) { case MaximizeOp: if ( (m_winfo.state() & NET::Max) == 0 ) { NETWinInfo ni( tqt_xdisplay(), m_winfo.win(), tqt_xrootwin(), 0); ni.setState( NET::Max, NET::Max ); } else { NETWinInfo ni( tqt_xdisplay(), m_winfo.win(), tqt_xrootwin(), 0); ni.setState( 0, NET::Max ); } break; case IconifyOp: if ( !m_winfo.isMinimized() ) { KWin::iconifyWindow( m_winfo.win()); } else { KWin::forceActiveWindow( m_winfo.win() ); } break; case StickyOp: if ( m_winfo.onAllDesktops() ) { KWin::setOnAllDesktops(m_winfo.win(), false); } else { KWin::setOnAllDesktops(m_winfo.win(), true); } break; case CloseOp: { NETRootInfo ri( tqt_xdisplay(), 0 ); ri.closeWindowRequest( m_winfo.win() ); } break; default: break; } } void KPager::redrawDesktops() { TQValueList <Desktop *>::Iterator it; for( it = m_desktops.begin(); it != m_desktops.end(); ++it ) (*it)->repaint(); } void KPager::slotGrabWindows() { m_desktops[m_currentDesktop-1]->m_grabWindows=true; m_desktops[m_currentDesktop-1]->repaint(); } TQSize KPager::sizeHint() const { int n=m_desktops.count(); int w=-1,h=-1; TQSize size=m_desktops[0]->sizeHint(); int wDsk=size.width(); int hDsk=size.height(); switch (m_layoutType) { case (Classical) : w=wDsk*(n/2+(n%2)); h=hDsk*2;break; case (Horizontal) : w=wDsk*n; h=hDsk;break; case (Vertical) : w=wDsk; h=hDsk*n;break; }; return TQSize(w,h); } const KPager::LayoutTypes KPager::c_defLayout=KPager::Horizontal; #include "kpager.moc"