From 9cc1e2c1aa2629d499e7555acd4906d6cc989cf9 Mon Sep 17 00:00:00 2001 From: tpearson Date: Tue, 7 Sep 2010 19:42:15 +0000 Subject: Merged in remaining kdebase bugfixes from the Chakra project git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1172677 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- kcontrol/info/memory.cpp | 55 +- kcontrol/info/memory.h | 7 +- kdesktop/krootwm.cc | 29 + kdesktop/krootwm.h | 1 + kmenuedit/kcontroleditui.rc | 1 + kmenuedit/kmenuedit.cpp | 8 + kmenuedit/kmenuedit.h | 1 + kmenuedit/kmenueditui.rc | 1 + .../pixmaps/cr22-action-filesave_and_close.png | Bin 0 -> 3263 bytes konsole/konsole/TEmulation.cpp | 5 + konsole/konsole/TEmulation.h | 1 + konsole/konsole/konsole.cpp | 37 ++ konsole/konsole/konsole.h | 7 + ksmserver/legacy.cpp | 2 +- ksysguard/ksysguardd/Linux/netdev.c | 193 +++++-- kwin/KWinInterface.h | 3 + kwin/activation.cpp | 49 ++ kwin/client.cpp | 637 ++++++++++++++++++++- kwin/client.h | 52 ++ kwin/events.cpp | 211 +++++++ kwin/geometry.cpp | 15 + kwin/kcmkwin/kwindecoration/kwindecoration.cpp | 227 ++++++++ kwin/kcmkwin/kwindecoration/kwindecoration.h | 13 + kwin/layers.cpp | 59 +- kwin/lib/kdecoration.h | 15 +- kwin/manage.cpp | 1 + kwin/options.cpp | 84 ++- kwin/options.h | 54 ++ kwin/sm.cpp | 2 + kwin/sm.h | 1 + kwin/useractions.cpp | 8 + kwin/workspace.cpp | 19 + kwin/workspace.h | 13 +- 33 files changed, 1728 insertions(+), 83 deletions(-) create mode 100644 kmenuedit/pixmaps/cr22-action-filesave_and_close.png diff --git a/kcontrol/info/memory.cpp b/kcontrol/info/memory.cpp index df7bcc6fa..7bfe52948 100644 --- a/kcontrol/info/memory.cpp +++ b/kcontrol/info/memory.cpp @@ -153,10 +153,10 @@ KMemoryWidget::KMemoryWidget(TQWidget * parent, const char *name) break; case SWAP_MEM: vbox->addSpacing(SPACING); - title = i18n("Total swap memory:"); + title = i18n("Total swap space:"); break; case FREESWAP_MEM: - title = i18n("Free swap memory:"); + title = i18n("Free swap space:"); break; default: title = ""; @@ -197,27 +197,26 @@ KMemoryWidget::KMemoryWidget(TQWidget * parent, const char *name) case MEM_RAM_AND_HDD: title = i18n("Total Memory"); hint = i18n("This graph gives you an overview of the " - "total sum of physical and virtual memory " - "in your system."); + "usage of all available memory (the sum of " + "physical memory and swap space) in your system."); break; case MEM_RAM: title = i18n("Physical Memory"); hint = i18n("This graph gives you an overview of " - "the usage of physical memory in your system." + "the usage of physical memory in your system." "

Most operating systems (including Linux) " "will use as much of the available physical " - "memory as possible as disk cache, " - "to speed up the system performance. " - "

This means that if you have a small amount " + "memory as possible for a disk cache, " + "to speed up the reading and writing of files. " + "

This means that if you are seeing a small amount " "of Free Physical Memory and a large amount of " - "Disk Cache Memory, your system is well " - "configured."); + "Disk Cache, your system is well configured."); break; case MEM_HDD: title = i18n("Swap Space"); - hint = i18n("The swap space is the virtual memory " + hint = i18n("Swap space is the virtual memory " "available to the system. " - "

It will be used on demand and is provided " + "

It will be used when needed, and is provided " "through one or more swap partitions and/or swap files."); break; default: @@ -312,10 +311,10 @@ bool KMemoryWidget::Display_Graph(int widgetindex, last_used = *used; #ifdef HAVE_LONG_LONG - percent = (((long long)last_used) * 100) / total; + percent = (((long long)last_used) * 1000 + 5) / (total * 10); #else /* prevent integer overflow with usage of double type */ - percent = (int) ((((double)last_used) * 100) / total); + percent = (int) ((((double)last_used) * 1000 + 5) / (total * 10)); #endif if (count) @@ -400,11 +399,11 @@ void KMemoryWidget::update_Values() if (!ram_colors_initialized) { ram_colors_initialized = true; ram_text[0] = i18n("Application Data"); - ram_colors[0] = COLOR_USED_MEMORY; /* used+shared */ + ram_colors[0] = COLOR_USED_DATA; /* used+shared */ ram_text[1] = i18n("Disk Buffers"); - ram_colors[1] = TQColor(24,131,5); /* buffer */ + ram_colors[1] = COLOR_USED_BUFFER; /* buffers */ ram_text[2] = i18n("Disk Cache"); - ram_colors[2] = TQColor(33,180,7); /* cached */ + ram_colors[2] = COLOR_USED_CACHE; /* cached */ ram_text[3] = i18n("Free Physical Memory"); ram_colors[3] = COLOR_FREE_MEMORY; /* free */ } @@ -425,24 +424,20 @@ void KMemoryWidget::update_Values() used, swap_colors, swap_text); /* RAM + SWAP usage: */ - if (Memory_Info[SWAP_MEM] == NO_MEMORY_INFO || - Memory_Info[FREESWAP_MEM] == NO_MEMORY_INFO) - Memory_Info[SWAP_MEM] = Memory_Info[FREESWAP_MEM] = 0; - - used[1] = Memory_Info[SWAP_MEM] - Memory_Info[FREESWAP_MEM]; - used[2] = Memory_Info[FREE_MEM] + Memory_Info[FREESWAP_MEM]; - used[0] = (Memory_Info[TOTAL_MEM]+Memory_Info[SWAP_MEM])-used[1]-used[2]; + /* used[0] already contains the amount of used swap */ + used[2] = Memory_Info[FREE_MEM] + ZERO_IF_NO_INFO(Memory_Info[FREESWAP_MEM]); + used[1] = Memory_Info[TOTAL_MEM] - Memory_Info[FREE_MEM]; if (!all_colors_initialized) { all_colors_initialized = true; - all_text[0] = i18n("Used Physical Memory"); - all_colors[0] = COLOR_USED_MEMORY; /* used ram */ - all_text[1] = i18n("Used Swap"); - all_colors[1] = COLOR_USED_SWAP; /* used swap */ - all_text[2] = i18n("Total Free Memory"); + all_text[0] = i18n("Used Memory (swap part)"); + all_colors[0] = COLOR_USED_SWAP; /* used swap */ + all_text[1] = i18n("Used Memory (physical part)"); + all_colors[1] = COLOR_USED_RAM; /* used ram */ + all_text[2] = i18n("Free Memory (total)"); all_colors[2] = COLOR_FREE_MEMORY; /* free ram+swap*/ } Display_Graph(MEM_RAM_AND_HDD, 3, - ok1 ? Memory_Info[TOTAL_MEM] + Memory_Info[SWAP_MEM] + ok1 ? Memory_Info[TOTAL_MEM] + ZERO_IF_NO_INFO(Memory_Info[SWAP_MEM]) : NO_MEMORY_INFO, used, all_colors, all_text); } diff --git a/kcontrol/info/memory.h b/kcontrol/info/memory.h index 975b851f5..1387f5ac3 100644 --- a/kcontrol/info/memory.h +++ b/kcontrol/info/memory.h @@ -20,8 +20,11 @@ typedef unsigned long long t_memsize; typedef unsigned long t_memsize; #endif -#define COLOR_USED_MEMORY TQColor(255,0,0) -#define COLOR_USED_SWAP TQColor(255,134,64) +#define COLOR_USED_SWAP TQColor(255,0,0) +#define COLOR_USED_DATA TQColor(255,180,88) +#define COLOR_USED_BUFFER TQColor(184,200,0) +#define COLOR_USED_CACHE TQColor(156,192,0) +#define COLOR_USED_RAM TQColor(220,200,88) #define COLOR_FREE_MEMORY TQColor(127,255,212) class KMemoryWidget:public KCModule { diff --git a/kdesktop/krootwm.cc b/kdesktop/krootwm.cc index 58eb78a9f..a423471bb 100644 --- a/kdesktop/krootwm.cc +++ b/kdesktop/krootwm.cc @@ -131,7 +131,10 @@ KRootWm::KRootWm(KDesktop* _desktop) : TQObject(_desktop) if (kapp->authorize("run_command")) { new KAction(i18n("Run Command..."), "run", 0, m_pDesktop, TQT_SLOT( slotExecuteCommand() ), m_actionCollection, "exec" ); + new KAction(i18n("Konsole ..." ), "terminal", CTRL+Key_T, this, TQT_SLOT( slotOpenTerminal() ), + m_actionCollection, "open_terminal" ); } + if (!KGlobal::config()->isImmutable()) { new KAction(i18n("Configure Desktop..."), "configure", 0, this, TQT_SLOT( slotConfigureDesktop() ), @@ -322,6 +325,12 @@ void KRootWm::buildMenus() file->insertSeparator(); } + action = m_actionCollection->action("open_terminal"); + if (action) + { + action->plug( file ); + } + action = m_actionCollection->action("lock"); if (action) action->plug( file ); @@ -396,6 +405,10 @@ void KRootWm::buildMenus() needSeparator = true; } + action = m_actionCollection->action("open_terminal"); + if (action) + action->plug( desktopMenu ); + if (needSeparator) { desktopMenu->insertSeparator(); @@ -723,6 +736,22 @@ TQStringList KRootWm::configModules() { return args; } +void KRootWm::slotOpenTerminal() +{ + // kdDebug() << "KRootWm::slotOpenTerminal" << endl; + KProcess* p = new KProcess; + Q_CHECK_PTR(p); + + KConfigGroupSaver gs(KGlobal::config(), "General"); + TQString terminal = KGlobal::config()->readPathEntry("TerminalApplication", "konsole"); + + *p << terminal; + + p->start(KProcess::DontCare); + + delete p; +} + void KRootWm::slotConfigureDesktop() { if (!m_configDialog) { diff --git a/kdesktop/krootwm.h b/kdesktop/krootwm.h index 960d0e53c..007da9bf3 100644 --- a/kdesktop/krootwm.h +++ b/kdesktop/krootwm.h @@ -119,6 +119,7 @@ public slots: void slotPopulateSessions(); void slotSessionActivated( int ); void slotNewSession(); + void slotOpenTerminal(); void slotLockNNewSession(); private: diff --git a/kmenuedit/kcontroleditui.rc b/kmenuedit/kcontroleditui.rc index 18bc04fcb..8e621a98a 100644 --- a/kmenuedit/kcontroleditui.rc +++ b/kmenuedit/kcontroleditui.rc @@ -8,6 +8,7 @@ + diff --git a/kmenuedit/kmenuedit.cpp b/kmenuedit/kmenuedit.cpp index 9474d85eb..37ab13676 100644 --- a/kmenuedit/kmenuedit.cpp +++ b/kmenuedit/kmenuedit.cpp @@ -67,6 +67,8 @@ void KMenuEdit::setupActions() if (!m_controlCenter) (void)new KAction(i18n("New S&eparator"), "menu_new_sep", 0, actionCollection(), "newsep"); + (void)new KAction(i18n("Save && Quit"), "filesave_and_close", 0, this, TQT_SLOT( slotSave_and_close()), actionCollection(), "file_save_and_quit"); + m_actionDelete = 0; KStdAction::save(this, TQT_SLOT( slotSave() ), actionCollection()); @@ -141,6 +143,12 @@ void KMenuEdit::slotSave() m_tree->save(); } +void KMenuEdit::slotSave_and_close() +{ + if (m_tree->save()) + close(); +} + bool KMenuEdit::queryClose() { if (!m_tree->dirty()) return true; diff --git a/kmenuedit/kmenuedit.h b/kmenuedit/kmenuedit.h index 08c89a6be..bc9bd13c1 100644 --- a/kmenuedit/kmenuedit.h +++ b/kmenuedit/kmenuedit.h @@ -46,6 +46,7 @@ protected: protected slots: void slotSave(); + void slotSave_and_close(); void slotChangeView(); void slotConfigureToolbars(); protected: diff --git a/kmenuedit/kmenueditui.rc b/kmenuedit/kmenueditui.rc index 66330e740..eb8c3ae00 100644 --- a/kmenuedit/kmenueditui.rc +++ b/kmenuedit/kmenueditui.rc @@ -9,6 +9,7 @@ + diff --git a/kmenuedit/pixmaps/cr22-action-filesave_and_close.png b/kmenuedit/pixmaps/cr22-action-filesave_and_close.png new file mode 100644 index 000000000..7d4b6f365 Binary files /dev/null and b/kmenuedit/pixmaps/cr22-action-filesave_and_close.png differ diff --git a/konsole/konsole/TEmulation.cpp b/konsole/konsole/TEmulation.cpp index 8dd6da437..39aeab542 100644 --- a/konsole/konsole/TEmulation.cpp +++ b/konsole/konsole/TEmulation.cpp @@ -395,6 +395,11 @@ void TEmulation::copySelection() { TQApplication::clipboard()->setText(t); } +TQString TEmulation::getSelection() { + if (connected) return scr->getSelText(true); + return TQString::null; +} + void TEmulation::streamHistory(TQTextStream* stream) { scr->streamHistory(stream); } diff --git a/konsole/konsole/TEmulation.h b/konsole/konsole/TEmulation.h index 7d3ba65d6..a5f432175 100644 --- a/konsole/konsole/TEmulation.h +++ b/konsole/konsole/TEmulation.h @@ -59,6 +59,7 @@ public slots: // signals incoming from TEWidget virtual void clearSelection(); virtual void copySelection(); + virtual TQString getSelection(); virtual void onSelectionBegin(const int x, const int y, const bool columnmode); virtual void onSelectionExtend(const int x, const int y); virtual void setSelection(const bool preserve_line_breaks); diff --git a/konsole/konsole/konsole.cpp b/konsole/konsole/konsole.cpp index 9c292daa2..e8dacbe5e 100644 --- a/konsole/konsole/konsole.cpp +++ b/konsole/konsole/konsole.cpp @@ -114,6 +114,7 @@ Time to start a requirement list. #include #include #include +#include #include #include @@ -268,6 +269,7 @@ Konsole::Konsole(const char* name, int histon, bool menubaron, bool tabbaron, bo ,sessionNumberMapper(0) ,sl_sessionShortCuts(0) ,s_workDir(workdir) +,m_filterData(0) { isRestored = b_inRestore; connect( &m_closeTimeout, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotCouldNotClose())); @@ -346,6 +348,8 @@ Konsole::Konsole(const char* name, int histon, bool menubaron, bool tabbaron, bo Konsole::~Konsole() { + delete m_filterData; + sessions.first(); while(sessions.current()) { @@ -718,6 +722,11 @@ void Konsole::makeGUI() m_copyClipboard->plug(m_rightButton); m_pasteClipboard->plug(m_rightButton); + + m_openSelection = new KPopupMenu(this); + m_rightButton->insertItem( i18n("&Open.."), m_openSelection ); + connect(m_openSelection, TQT_SIGNAL(aboutToShow()), TQT_SLOT(slotOpenSelection())); + if (m_signals) m_rightButton->insertItem(i18n("&Send Signal"), m_signals); @@ -3950,6 +3959,34 @@ void Konsole::slotFindHistory() m_finddialog->result(); } +void Konsole::slotOpenSelection() +{ + delete m_filterData; + + m_openSelection->clear(); + disconnect(m_openSelection, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotOpenURI(int))); + + TQString selection = se->getEmulation()->getSelection(); + TQString curdir = baseURL().path(); + + if ( TQFile::exists( curdir + selection ) ) { + selectedURL = TQString(curdir + selection); + } else { + selectedURL = TQString(selection); + } + + m_filterData = new KURIFilterData( selectedURL ); + KURIFilter::self()->filterURI( *(m_filterData) ); + m_openSelection->insertItem( SmallIconSet( m_filterData->iconName() ),i18n( "%1" ).arg(m_filterData->uri().url()), 1 ); + + connect(m_openSelection, TQT_SIGNAL(activated(int)), TQT_SLOT(slotOpenURI(int))); +} + +void Konsole::slotOpenURI(int) +{ + (void) new KRun( m_filterData->uri() ); +} + void Konsole::slotFindNext() { if( !m_finddialog ) { diff --git a/konsole/konsole/konsole.h b/konsole/konsole/konsole.h index 5b6702412..4ca704a9b 100644 --- a/konsole/konsole/konsole.h +++ b/konsole/konsole/konsole.h @@ -61,6 +61,7 @@ class KSelectAction; class KRadioAction; class KTabWidget; class TQToolButton; +class KURIFilterData; // Defined in main.C const char *konsole_shell(TQStrList &args); @@ -200,6 +201,9 @@ private slots: void loadScreenSessions(); void updateFullScreen(bool on); + void slotOpenSelection(); + void slotOpenURI(int n); + void slotSaveSettings(); void slotSaveSessionsProfile(); void slotConfigureNotifications(); @@ -362,6 +366,7 @@ private: KAction *m_print; KAction *m_quit; KAction *m_tabDetachSession; + KPopupMenu *m_openSelection; KActionCollection *m_shortcuts; @@ -372,6 +377,7 @@ private: bool m_find_first; bool m_find_found; TQString m_find_pattern; + TQString selectedURL; int cmd_serial; int cmd_first_screen; @@ -435,6 +441,7 @@ private: TQString s_workDir; TQColor m_tabColor; + KURIFilterData* m_filterData; }; class TQSpinBox; diff --git a/ksmserver/legacy.cpp b/ksmserver/legacy.cpp index a8f439745..773cd514d 100644 --- a/ksmserver/legacy.cpp +++ b/ksmserver/legacy.cpp @@ -220,7 +220,7 @@ void KSMServer::storeLegacySession( KConfig* config ) for (WindowMap::ConstIterator it = legacyWindows.begin(); it != legacyWindows.end(); ++it) { if ( (*it).type != SM_ERROR) { if( excludeApps.contains( (*it).wmclass1.lower()) - || excludeApps.contains( (*it).wmclass2.lower())) + || excludeApps.contains( (*it).wmclass2.lower()) || (*it).wmCommand[0] == "compiz" || (*it).wmCommand[0] == "beryl" || (*it).wmCommand[0] == "aquamarine" || (*it).wmCommand[0] == "beryl-manager" || (*it).wmCommand[0] == "beryl-settings" || (*it).wmCommand[0] == "kde-window-decorator" || (*it).wmCommand[0] == "emerald") continue; if ( !(*it).wmCommand.isEmpty() && !(*it).wmClientMachine.isEmpty() ) { count++; diff --git a/ksysguard/ksysguardd/Linux/netdev.c b/ksysguard/ksysguardd/Linux/netdev.c index 867678642..bba927e19 100644 --- a/ksysguard/ksysguardd/Linux/netdev.c +++ b/ksysguard/ksysguardd/Linux/netdev.c @@ -35,65 +35,85 @@ #define MON_SIZE 128 -#define CALC( a, b, c, d, e ) \ +#define CALC( a, b, c, d, e, f ) \ { \ - NetDevs[ i ].a = a - NetDevs[ i ].Old##a; \ - NetDevs[ i ].Old##a = a; \ + if (f){ \ + NetDevs[ i ].a = a - NetDevs[ i ].Old##a; \ + NetDevs[ i ].Old##a = a; \ + } \ + else{ \ + NetDevs[ i ].a = a; \ + } \ } -#define REGISTERSENSOR( a, b, c, d, e ) \ +#define REGISTERSENSOR( a, b, c, d, e, f ) \ { \ snprintf( mon, MON_SIZE, "network/interfaces/%s/%s", tag, b ); \ registerMonitor( mon, "integer", printNetDev##a, printNetDev##a##Info, NetDevSM ); \ } -#define UNREGISTERSENSOR( a, b, c, d, e ) \ +#define UNREGISTERSENSOR( a, b, c, d, e, f ) \ { \ snprintf( mon, MON_SIZE, "network/interfaces/%s/%s", NetDevs[ i ].name, b ); \ removeMonitor( mon ); \ } -#define DEFMEMBERS( a, b, c, d, e ) \ -unsigned long long Old##a; \ -unsigned long long a; \ -unsigned long a##Scale; +#define DEFMEMBERS( a, b, c, d, e, f ) \ +signed long long Old##a; \ +signed long long a; \ +signed long a##Scale; -#define DEFVARS( a, b, c, d, e ) \ -unsigned long long a; +#define DEFVARS( a, b, c, d, e, f ) \ +signed long long a; + +/*The sixth variable is 1 if the quantity variation must be provided, 0 if the absolute value must be provided */ #define FORALL( a ) \ - a( recBytes, "receiver/data", "Received Data", "kBytes/s", 1024 ) \ - a( recPacks, "receiver/packets", "Received Packets", "1/s", 1 ) \ - a( recErrs, "receiver/errors", "Receiver Errors", "1/s", 1 ) \ - a( recDrop, "receiver/drops", "Receiver Drops", "1/s", 1 ) \ - a( recFifo, "receiver/fifo", "Receiver FIFO Overruns", "1/s", 1 ) \ - a( recFrame, "receiver/frame", "Receiver Frame Errors", "1/s", 1 ) \ - a( recCompressed, "receiver/compressed", "Received Compressed Packets", "1/s", 1 ) \ - a( recMulticast, "receiver/multicast", "Received Multicast Packets", "1/s", 1 ) \ - a( sentBytes, "transmitter/data", "Sent Data", "kBytes/s", 1024 ) \ - a( sentPacks, "transmitter/packets", "Sent Packets", "1/s", 1 ) \ - a( sentErrs, "transmitter/errors", "Transmitter Errors", "1/s", 1 ) \ - a( sentDrop, "transmitter/drops", "Transmitter Drops", "1/s", 1 ) \ - a( sentFifo, "transmitter/fifo", "Transmitter FIFO overruns", "1/s", 1 ) \ - a( sentColls, "transmitter/collisions", "Transmitter Collisions", "1/s", 1 ) \ - a( sentCarrier, "transmitter/carrier", "Transmitter Carrier losses", "1/s", 1 ) \ - a( sentCompressed, "transmitter/compressed", "Transmitter Compressed Packets", "1/s", 1 ) - -#define SETZERO( a, b, c, d, e ) \ + a( recBytes, "receiver/data", "Received Data", "kBytes/s", 1024, 1) \ + a( recPacks, "receiver/packets", "Received Packets", "1/s", 1, 1 ) \ + a( recErrs, "receiver/errors", "Receiver Errors", "1/s", 1, 1 ) \ + a( recDrop, "receiver/drops", "Receiver Drops", "1/s", 1, 1 ) \ + a( recFifo, "receiver/fifo", "Receiver FIFO Overruns", "1/s", 1, 1 ) \ + a( recFrame, "receiver/frame", "Receiver Frame Errors", "1/s", 1, 1 ) \ + a( recCompressed, "receiver/compressed", "Received Compressed Packets", "1/s", 1, 1 ) \ + a( recMulticast, "receiver/multicast", "Received Multicast Packets", "1/s", 1, 1 ) \ + a( sentBytes, "transmitter/data", "Sent Data", "kBytes/s", 1024, 1 ) \ + a( sentPacks, "transmitter/packets", "Sent Packets", "1/s", 1, 1 ) \ + a( sentErrs, "transmitter/errors", "Transmitter Errors", "1/s", 1, 1 ) \ + a( sentDrop, "transmitter/drops", "Transmitter Drops", "1/s", 1, 1 ) \ + a( sentFifo, "transmitter/fifo", "Transmitter FIFO overruns", "1/s", 1, 1 ) \ + a( sentColls, "transmitter/collisions", "Transmitter Collisions", "1/s", 1, 1 ) \ + a( sentCarrier, "transmitter/carrier", "Transmitter Carrier losses", "1/s", 1, 1 ) \ + a( sentCompressed, "transmitter/compressed", "Transmitter Compressed Packets", "1/s", 1, 1 ) + +#define FORALLWIFI( a ) \ + a( linkQuality, "wifi/quality", "Link Quality", "", 1, 0) \ + a( signalLevel, "wifi/signal", "Signal Level", "dBm", 1, 0) \ + a( noiseLevel, "wifi/noise", "Noise Level", "dBm", 1, 0) \ + a( nwid, "wifi/nwid", "Rx Invalid Nwid Packets", "1/s", 1, 1) \ + a( RxCrypt, "wifi/crypt", "Rx Invalid Crypt Packets", "1/s", 1, 1) \ + a( frag, "wifi/frag", "Rx Invalid Frag Packets", "1/s", 1, 1) \ + a( retry, "wifi/retry", "Tx Excessive Retries Packets", "1/s", 1, 1) \ + a( misc, "wifi/misc", "Invalid Misc Packets", "1/s", 1, 1) \ + a( beacon, "wifi/beacon", "Missed Beacon", "1/s", 1, 1) + +#define SETZERO( a, b, c, d, e, f ) \ a = 0; -#define SETMEMBERZERO( a, b, c, d, e ) \ +#define SETMEMBERZERO( a, b, c, d, e, f ) \ NetDevs[ i ].a = 0; \ NetDevs[ i ].a##Scale = e; -#define DECLAREFUNC( a, b, c, d, e ) \ +#define DECLAREFUNC( a, b, c, d, e, f ) \ void printNetDev##a( const char* cmd ); \ void printNetDev##a##Info( const char* cmd ); typedef struct { FORALL( DEFMEMBERS ) + FORALLWIFI( DEFMEMBERS ) char name[ 32 ]; + int wifi; } NetDevInfo; /* We have observed deviations of up to 5% in the accuracy of the timer @@ -106,6 +126,7 @@ static struct SensorModul* NetDevSM; #define NETDEVBUFSIZE 4096 static char NetDevBuf[ NETDEVBUFSIZE ]; +static char NetDevWifiBuf[ NETDEVBUFSIZE ]; static int NetDevCnt = 0; static int Dirty = 0; static int NetDevOk = 0; @@ -117,15 +138,17 @@ static NetDevInfo NetDevs[ MAXNETDEVS ]; void processNetDev( void ); FORALL( DECLAREFUNC ) +FORALLWIFI( DECLAREFUNC ) static int processNetDev_( void ) { - int i; + int i,j; char format[ 32 ]; char devFormat[ 16 ]; char buf[ 1024 ]; char tag[ 64 ]; char* netDevBufP = NetDevBuf; + char* netDevWifiBufP = NetDevWifiBuf; sprintf( format, "%%%d[^\n]\n", (int)sizeof( buf ) - 1 ); sprintf( devFormat, "%%%ds", (int)sizeof( tag ) - 1 ); @@ -147,8 +170,8 @@ static int processNetDev_( void ) FORALL( DEFVARS ); *pos = '\0'; FORALL( SETZERO ); - sscanf( buf + 7, "%llu %llu %llu %llu %llu %llu %llu %llu " - "%llu %llu %llu %llu %llu %llu %llu %llu", + sscanf( buf + 7, "%lli %lli %lli %lli %lli %lli %lli %lli " + "%lli %lli %lli %lli %lli %lli %lli %lli", &recBytes, &recPacks, &recErrs, &recDrop, &recFifo, &recFrame, &recCompressed, &recMulticast, &sentBytes, &sentPacks, &sentErrs, &sentDrop, @@ -168,6 +191,44 @@ static int processNetDev_( void ) if ( i != NetDevCnt ) return -1; + /*Update the values for the wifi interfaces*/ + if ( *netDevWifiBufP=='\0') /*there is no /proc/net/wireless file*/ + return 0; + + /* skip 2 first lines */ + for ( i = 0; i < 2; i++ ) { + sscanf( netDevWifiBufP, format, buf ); + buf[ sizeof( buf ) - 1 ] = '\0'; + netDevWifiBufP += strlen( buf ) + 1; /* move netDevWifiBufP to next line */ + } + + for ( j = 0; sscanf( netDevWifiBufP, format, buf ) == 1; ++j ) { + buf[ sizeof( buf ) - 1 ] = '\0'; + netDevWifiBufP += strlen( buf ) + 1; /* move netDevWifiBufP to next line */ + + if ( sscanf( buf, devFormat, tag ) ) { + char* pos = strchr( tag, ':' ); + if ( pos ) { + FORALLWIFI( DEFVARS ); + *pos = '\0'; + + for (i = 0 ; i < NetDevCnt ; ++i){ /*find the corresponding interface*/ + if ( strcmp(tag,NetDevs[ i ].name)==0){ + break; + } + } + sscanf( buf + 12, " %lli. %lli. %lli. %lli %lli %lli %lli %lli %lli", + &linkQuality, &signalLevel, &noiseLevel, &nwid, + &RxCrypt, &frag, &retry, &misc, &beacon ); + signalLevel -= 256; /*the units are dBm*/ + noiseLevel -= 256; + FORALLWIFI( CALC ); + } + } + } + + + /* save exact time inverval between this and the last read of * /proc/net/dev */ timeInterval = currSampling.tv_sec - lastSampling.tv_sec + @@ -200,12 +261,13 @@ void processNetDev( void ) void initNetDev( struct SensorModul* sm ) { - int i; + int i,j; char format[ 32 ]; char devFormat[ 16 ]; char buf[ 1024 ]; char tag[ 64 ]; char* netDevBufP = NetDevBuf; + char* netDevWifiBufP = NetDevWifiBuf; NetDevSM = sm; @@ -233,8 +295,8 @@ void initNetDev( struct SensorModul* sm ) *pos = '\0'; strlcpy( NetDevs[ i ].name, tag, sizeof( NetDevs[ i ].name ) ); FORALL( REGISTERSENSOR ); - sscanf( pos + 1, "%llu %llu %llu %llu %llu %llu %llu %llu" - "%llu %llu %llu %llu %llu %llu %llu %llu", + sscanf( pos + 1, "%lli %lli %lli %lli %lli %lli %lli %lli" + "%lli %lli %lli %lli %lli %lli %lli %lli", &NetDevs[ i ].recBytes, &NetDevs[ i ].recPacks, &NetDevs[ i ].recErrs, &NetDevs[ i ].recDrop, &NetDevs[ i ].recFifo, &NetDevs[ i ].recFrame, @@ -247,6 +309,39 @@ void initNetDev( struct SensorModul* sm ) } FORALL( SETMEMBERZERO ); } + + } + + /* detect the wifi interfaces*/ + /* skip 2 first lines */ + for ( i = 0; i < 2; i++ ) { + sscanf( netDevWifiBufP, format, buf ); + buf[ sizeof( buf ) - 1 ] = '\0'; + netDevWifiBufP += strlen( buf ) + 1; /* move netDevWifiBufP to next line */ + } + + for ( j = 0; sscanf( netDevWifiBufP, format, buf ) == 1; ++j ) { + buf[ sizeof( buf ) - 1 ] = '\0'; + netDevWifiBufP += strlen( buf ) + 1; /* move netDevWifiBufP to next line */ + + if ( sscanf( buf, devFormat, tag ) ) { + char * pos = strchr( tag, ':' ); + if ( pos ) { + char mon[ MON_SIZE ]; + *pos = '\0'; + /*find and tag the corresponding NetDev as wifi enabled. + At the end of the loop, i is the index of the device. + This variable i is used in some macro */ + for (i = 0 ; i < NetDevCnt ; ++i){ + if ( strcmp(tag,NetDevs[ i ].name)==0){ + NetDevs[ i ].wifi = 1; + break; + } + } + FORALLWIFI( REGISTERSENSOR ); + } + FORALLWIFI( SETMEMBERZERO ); /* the variable i must point to the corrrect NetDevs[i]*/ + } } /* Call processNetDev to elimitate initial peek values. */ @@ -260,6 +355,8 @@ void exitNetDev( void ) for ( i = 0; i < NetDevCnt; ++i ) { char mon[ MON_SIZE ]; FORALL( UNREGISTERSENSOR ); + if (NetDevs[ i ].wifi) + FORALLWIFI( UNREGISTERSENSOR ); } NetDevCnt = 0; } @@ -320,6 +417,20 @@ int updateNetDev( void ) Dirty = 1; + /* We read the informations about the wifi from /proc/net/wireless and store it into NetDevWifiBuf */ + if ( ( fd = open( "/proc/net/wireless", O_RDONLY ) ) < 0 ) { + /* /proc/net/wireless may not exist on some machines. */ + NetDevWifiBuf[0]='\0'; + } + + if ( ( n = read( fd, NetDevWifiBuf, NETDEVBUFSIZE - 1 ) ) == NETDEVBUFSIZE - 1 ) { + log_error( "Internal buffer too small to read \'/proc/net/wireless\'" ); + close( fd ); + return -1; + } + close( fd ); + NetDevWifiBuf[ n ] = '\0'; + return 0; } @@ -331,7 +442,7 @@ void checkNetDev( void ) initNetDev( NetDevSM ); } -#define PRINTFUNC( a, b, c, d, e ) \ +#define PRINTFUNC( a, b, c, d, e, f ) \ void printNetDev##a( const char* cmd ) \ { \ int i; \ @@ -350,8 +461,11 @@ void printNetDev##a( const char* cmd ) \ \ for ( i = 0; i < MAXNETDEVS; ++i ) \ if ( strcmp( NetDevs[ i ].name, dev ) == 0) { \ - fprintf( CurrentClient, "%lu\n", (unsigned long) \ + if (f) \ + fprintf( CurrentClient, "%li\n", (long) \ ( NetDevs[ i ].a / ( NetDevs[ i ].a##Scale * timeInterval ) ) ); \ + else \ + fprintf( CurrentClient, "%li\n", (long) NetDevs[ i ].a ); \ return; \ } \ \ @@ -365,3 +479,4 @@ void printNetDev##a##Info( const char* cmd ) \ } FORALL( PRINTFUNC ) +FORALLWIFI( PRINTFUNC ) diff --git a/kwin/KWinInterface.h b/kwin/KWinInterface.h index eff3a88f2..2af0d03ff 100644 --- a/kwin/KWinInterface.h +++ b/kwin/KWinInterface.h @@ -23,6 +23,9 @@ class KWinInterface : virtual public DCOPObject virtual void nextDesktop() = 0; virtual void previousDesktop() = 0; virtual void circulateDesktopApplications() = 0; + virtual void updateOverlappingShadows(unsigned long window) = 0; + virtual void setShadowed(unsigned long window, bool shadowed) = 0; + // kompmgr stuff virtual void startKompmgr() = 0; virtual void stopKompmgr() = 0; diff --git a/kwin/activation.cpp b/kwin/activation.cpp index f80a00f9a..c0f578634 100644 --- a/kwin/activation.cpp +++ b/kwin/activation.cpp @@ -227,6 +227,13 @@ void Workspace::setActiveClient( Client* c, allowed_t ) active_client->setActive( false, !c || !c->isModal() || c != active_client->transientFor() ); } active_client = c; + if (set_active_client_recursion == 1) + { + // Only unset next_active_client if activateClient() wasn't called by + // Client::setActive() to set the active window to null before + // activating another window. + next_active_client = NULL; + } Q_ASSERT( c == NULL || c->isActive()); if( active_client != NULL ) last_active_client = active_client; @@ -324,6 +331,7 @@ void Workspace::takeActivity( Client* c, int flags, bool handled ) Client* modal = c->findModal(); if( modal != NULL && modal != c ) { + next_active_client = modal; if( !modal->isOnDesktop( c->desktop())) { modal->setDesktop( c->desktop()); @@ -351,11 +359,14 @@ void Workspace::takeActivity( Client* c, int flags, bool handled ) c->setActive( true ); focusToNull(); } + if( c->wantsInput()) + next_active_client = c; flags &= ~ActivityFocus; handled = false; // no point, can't get clicks } if( !c->isShown( true )) // shouldn't happen, call activateClient() if needed { + next_active_client = c; kdWarning( 1212 ) << "takeActivity: not shown" << endl; return; } @@ -856,7 +867,45 @@ void Client::setActive( bool act, bool updateOpacity_) updateShadowSize(); if ( active ) + { Notify::raise( Notify::Activate ); + if (options->shadowEnabled(true)) + { + if (options->shadowEnabled(false)) + { + // Wait for inactive shadow to expose occluded windows and give + // them a chance to redraw before painting the active shadow + removeShadow(); + drawDelayedShadow(); + if (!isDesktop() && + this != workspace()->topClientOnDesktop(desktop())) + // If the newly activated window's isn't the desktop, wait + // for its shadow to draw, then redraw any shadows + // overlapping it. + drawOverlappingShadows(true); + } + else + drawShadow(); + } + } + else + { + removeShadow(); + + if (options->shadowEnabled(false)) + if (this == workspace()->topClientOnDesktop(desktop())) + { + /* If the newly deactivated window is the top client on the + * desktop, then the newly activated window is below it; ensure + * that the deactivated window's shadow draws after the + * activated window's shadow. + */ + if ((shadowAfterClient = workspace()->activeClient())) + drawShadowAfter(shadowAfterClient); + } + else + drawDelayedShadow(); + } if( !active ) cancelAutoRaise(); diff --git a/kwin/client.cpp b/kwin/client.cpp index 5f281f2ab..0d2c5cfbf 100644 --- a/kwin/client.cpp +++ b/kwin/client.cpp @@ -11,9 +11,12 @@ License. See the file "COPYING" for the exact licensing terms. #include "client.h" +#include + #include #include #include +#include #include #include #include @@ -39,9 +42,25 @@ extern Time qt_x_time; extern Atom qt_window_role; extern Atom qt_sm_client_id; +// wait 200 ms before drawing shadow after move/resize +static const int SHADOW_DELAY = 200; + namespace KWinInternal { +/* TODO: Remove this once X has real translucency. + * + * A list of the regions covered by all shadows and the Clients to which they + * belong. Used to redraw shadows when a window overlapping or underlying a + * shadow is moved, resized, or hidden. + */ +struct ShadowRegion + { + TQRegion region; + Client *client; + }; +static TQValueList shadowRegions; + /* Creating a client: @@ -100,6 +119,13 @@ Client::Client( Workspace *ws ) autoRaiseTimer = 0; shadeHoverTimer = 0; + shadowDelayTimer = new TQTimer(this); + opacityCache = &activeOpacityCache; + shadowAfterClient = NULL; + shadowWidget = NULL; + shadowMe = true; + connect(shadowDelayTimer, TQT_SIGNAL(timeout()), TQT_SLOT(drawShadow())); + // set the initial mapping state mapping_state = WithdrawnState; desk = 0; // no desktop yet @@ -145,7 +171,7 @@ Client::Client( Workspace *ws ) maxmode_restore = MaximizeRestore; cmap = None; - + frame_geometry = TQRect( 0, 0, 100, 100 ); // so that decorations don't start with size being (0,0) client_size = TQSize( 100, 100 ); custom_opacity = false; @@ -188,6 +214,8 @@ void Client::releaseWindow( bool on_shutdown ) if (!custom_opacity) setOpacity(FALSE); if (moveResizeMode) leaveMoveResize(); + removeShadow(); + drawIntersectingShadows(); finishWindowRules(); ++postpone_geometry_updates; // grab X during the release to make removing of properties, setting to withdrawn state @@ -248,6 +276,8 @@ void Client::destroyClient() StackingUpdatesBlocker blocker( workspace()); if (moveResizeMode) leaveMoveResize(); + removeShadow(); + drawIntersectingShadows(); finishWindowRules(); ++postpone_geometry_updates; setModal( false ); @@ -304,6 +334,7 @@ void Client::updateDecoration( bool check_workspace_pos, bool force ) if( do_show ) decoration->widget()->show(); updateFrameExtents(); + updateOpacityCache(); } void Client::destroyDecoration() @@ -434,6 +465,12 @@ void Client::resizeDecoration( const TQSize& s ) TQResizeEvent e( s, oldsize ); TQApplication::sendEvent( decoration->widget(), &e ); } + if (!moveResizeMode && options->shadowEnabled(isActive())) + { + // If the user is manually resizing, let Client::leaveMoveResize() + // decide when to redraw the shadow + updateOpacityCache(); + } } bool Client::noBorder() const @@ -471,6 +508,7 @@ void Client::updateShape() noborder = true; updateDecoration( true ); } + updateOpacityCache(); if ( shape() ) { XShapeCombineShape(qt_xdisplay(), frameId(), ShapeBounding, @@ -862,6 +900,16 @@ void Client::setShade( ShadeMode mode ) XMapWindow( qt_xdisplay(), wrapperId()); XMapWindow( qt_xdisplay(), window()); XDeleteProperty (qt_xdisplay(), client, atoms->net_wm_window_shade); + if (options->shadowEnabled(false)) + { + for (ClientList::ConstIterator it = transients().begin(); + it != transients().end(); ++it) + { + (*it)->removeShadow(); + (*it)->drawDelayedShadow(); + } + } + if ( isActive() ) workspace()->requestFocus( this ); } @@ -946,6 +994,589 @@ void Client::updateVisibility() } } +void Client::setShadowed(bool shadowed) +{ + bool wasShadowed; + + wasShadowed = isShadowed(); + shadowMe = options->shadowEnabled(isActive()) ? shadowed : false; + + if (shadowMe) { + if (!wasShadowed) + drawShadow(); + } + else { + if (wasShadowed) { + removeShadow(); + + if (!activeOpacityCache.isNull()) + activeOpacityCache.resize(0); + if (!inactiveOpacityCache.isNull()) + inactiveOpacityCache.resize(0); + } + } +} + +void Client::updateOpacityCache() +{ + if (!activeOpacityCache.isNull()) + activeOpacityCache.resize(0); + if (!inactiveOpacityCache.isNull()) + inactiveOpacityCache.resize(0); + + if (!moveResizeMode) { + // If the user is manually resizing, let Client::finishMoveResize() + // decide when to redraw the shadow + removeShadow(); + drawIntersectingShadows(); + if (options->shadowEnabled(isActive())) + drawDelayedShadow(); + } +} + +/*! + Redraw shadows that were previously occluding or occluded by this window, + to avoid visual glitches. + */ +void Client::drawIntersectingShadows() { + //Client *reshadowClient; + TQRegion region; + //TQPtrList reshadowClients; + TQValueList reshadowClients; + TQValueListIterator it; + TQValueListIterator it2; + + if (!options->shadowEnabled(false)) + // No point in redrawing overlapping/overlapped shadows if only the + // active window has a shadow. + return; + + region = shapeBoundingRegion; + + // Generate list of Clients whose shadows need to be redrawn. That is, + // those that are currently intersecting or intersected by other windows or + // shadows. + for (it = shadowRegions.begin(); it != shadowRegions.end(); ++it) + if ((isOnAllDesktops() || (*it).client->isOnCurrentDesktop()) && + !(*it).region.intersect(region).isEmpty()) + reshadowClients.append((*it).client); + + // Redraw shadows for each of the Clients in the list generated above + for (it2 = reshadowClients.begin(); it2 != reshadowClients.end(); + ++it2) { + (*it2)->removeShadow(); + (*it2)->drawDelayedShadow(); + } +} + +/*! + Redraw shadows that are above the current window in the stacking order. + Furthermore, redraw them in the same order as they come in the stacking order + from bottom to top. + */ +void Client::drawOverlappingShadows(bool waitForMe) +{ + Client *aClient; + TQRegion region; + TQValueList reshadowClients; + ClientList stacking_order; + ClientList::ConstIterator it; + TQValueListIterator it2; + TQValueListIterator it3; + + if (!options->shadowEnabled(false)) + // No point in redrawing overlapping/overlapped shadows if only the + // active window has a shadow. + return; + + region = shapeBoundingRegion; + + stacking_order = workspace()->stackingOrder(); + for (it = stacking_order.fromLast(); it != stacking_order.end(); --it) { + // Find the position of this window in the stacking order. + if ((*it) == this) + break; + } + ++it; + while (it != stacking_order.end()) { + if ((*it)->windowType() == NET::Dock) { + // This function is only interested in windows whose shadows don't + // have weird stacking rules. + ++it; + continue; + } + + // Generate list of Clients whose shadows need to be redrawn. That is, + // those that are currently overlapping or overlapped by other windows + // or shadows. The list should be in order from bottom to top in the + // stacking order. + for (it2 = shadowRegions.begin(); it2 != shadowRegions.end(); ++it2) { + if ((*it2).client == (*it)) { + if ((isOnAllDesktops() || (*it2).client->isOnCurrentDesktop()) + && !(*it2).region.intersect(region).isEmpty()) + reshadowClients.append((*it2).client); + } + } + ++it; + } + + // Redraw shadows for each of the Clients in the list generated above + for (it3 = reshadowClients.begin(); it3 != reshadowClients.end(); ++it3) { + (*it3)->removeShadow(); + if (it3 == reshadowClients.begin()) { + if (waitForMe) + (*it3)->drawShadowAfter(this); + else + (*it3)->drawDelayedShadow(); + } + else { + --it3; + aClient = (*it3); + ++it3; + (*it3)->drawShadowAfter(aClient); + } + } +} + +/*! + Draw shadow after some time has elapsed, to give recently exposed windows a + chance to repaint before a shadow gradient is drawn over them. + */ +void Client::drawDelayedShadow() +{ + shadowDelayTimer->stop(); + shadowDelayTimer->start(SHADOW_DELAY, true); +} + +/*! + Draw shadow immediately after the specified Client's shadow finishes drawing. + */ +void Client::drawShadowAfter(Client *after) +{ + shadowAfterClient = after; + connect(after, TQT_SIGNAL(shadowDrawn()), TQT_SLOT(drawShadow())); +} + +/*! + Draw a shadow under this window and XShape the shadow accordingly. + */ +void Client::drawShadow() +{ + Window shadows[2]; + XRectangle *shapes; + int i, count, ordering; + + // If we are waiting for another Client's shadow to be drawn, stop waiting now + if (shadowAfterClient != NULL) { + disconnect(shadowAfterClient, TQT_SIGNAL(shadowDrawn()), this, TQT_SLOT(drawShadow())); + shadowAfterClient = NULL; + } + + if (!isOnCurrentDesktop()) + return; + + /* Store this window's ShapeBoundingRegion even if shadows aren't drawn for + * this type of window. Otherwise, drawIntersectingShadows() won't update + * properly when this window is moved/resized/hidden/closed. + */ + shapes = XShapeGetRectangles(qt_xdisplay(), frameId(), ShapeBounding, + &count, &ordering); + if (!shapes) + // XShape extension not supported + shapeBoundingRegion = TQRegion(x(), y(), width(), height()); + else { + shapeBoundingRegion = TQRegion(); + for (i = 0; i < count; i++) { + // Translate XShaped window into a TQRegion + TQRegion shapeRectangle(shapes[i].x, shapes[i].y, shapes[i].width, + shapes[i].height); + shapeBoundingRegion += shapeRectangle; + } + if (isShade()) + // Since XResize() doesn't change a window's XShape regions, ensure that + // shapeBoundingRegion is not taller than the window's shaded height, + // or the bottom shadow will appear to be missing + shapeBoundingRegion &= TQRegion(0, 0, width(), height()); + shapeBoundingRegion.translate(x(), y()); + } + + if (!isShadowed() || hidden || isMinimized() || + maximizeMode() == MaximizeFull || + !options->shadowWindowType(windowType())) { + XFree(shapes); + + // Tell whatever Clients are listening that this Client's shadow has been drawn. + // It hasn't, but there's no sense waiting for something that won't happen. + emit shadowDrawn(); + + return; + } + + removeShadow(); + + TQMemArray pixelData; + TQPixmap shadowPixmap; + TQRect shadow; + TQRegion exposedRegion; + ShadowRegion shadowRegion; + int thickness, xOffset, yOffset; + + thickness = options->shadowThickness(isActive()); + xOffset = options->shadowXOffset(isActive()); + yOffset = options->shadowYOffset(isActive()); + opacityCache = active? &activeOpacityCache : &inactiveOpacityCache; + + shadow.setRect(x() - thickness + xOffset, y() - thickness + yOffset, + width() + thickness * 2, height() + thickness * 2); + shadowPixmap.resize(shadow.size()); + + // Create a fake drop-down shadow effect via blended Xwindows + shadowWidget = new TQWidget(0, 0, WStyle_Customize | WX11BypassWM); + shadowWidget->setGeometry(shadow); + XSelectInput(qt_xdisplay(), shadowWidget->winId(), + ButtonPressMask | ButtonReleaseMask | StructureNotifyMask); + shadowWidget->installEventFilter(this); + + if (!shapes) { + // XShape extension not supported + exposedRegion = getExposedRegion(shapeBoundingRegion, shadow.x(), + shadow.y(), shadow.width(), shadow.height(), thickness, + xOffset, yOffset); + shadowRegion.region = exposedRegion; + shadowRegion.client = this; + shadowRegions.append(shadowRegion); + + if (opacityCache->isNull()) + imposeRegionShadow(shadowPixmap, shapeBoundingRegion, + exposedRegion, thickness, + options->shadowOpacity(isActive())); + else + imposeCachedShadow(shadowPixmap, exposedRegion); + } + else { + TQMemArray exposedRects; + TQMemArray::Iterator it, itEnd; + XRectangle *shadowShapes; + + exposedRegion = getExposedRegion(shapeBoundingRegion, shadow.x(), + shadow.y(), shadow.width(), shadow.height(), thickness, + xOffset, yOffset); + shadowRegion.region = exposedRegion; + shadowRegion.client = this; + shadowRegions.append(shadowRegion); + + // XShape the shadow + exposedRects = exposedRegion.rects(); + i = 0; + itEnd = exposedRects.end(); + shadowShapes = new XRectangle[exposedRects.count()]; + for (it = exposedRects.begin(); it != itEnd; ++it) { + shadowShapes[i].x = (*it).x(); + shadowShapes[i].y = (*it).y(); + shadowShapes[i].width = (*it).width(); + shadowShapes[i].height = (*it).height(); + i++; + } + XShapeCombineRectangles(qt_xdisplay(), shadowWidget->winId(), + ShapeBounding, -x() + thickness - xOffset, + -y() + thickness - yOffset, shadowShapes, i, ShapeSet, + Unsorted); + delete [] shadowShapes; + + if (opacityCache->isNull()) + imposeRegionShadow(shadowPixmap, shapeBoundingRegion, + exposedRegion, thickness, + options->shadowOpacity(isActive())); + else + imposeCachedShadow(shadowPixmap, exposedRegion); + } + + XFree(shapes); + + // Set the background pixmap + //shadowPixmap.convertFromImage(shadowImage); + shadowWidget->setErasePixmap(shadowPixmap); + + // Restack shadows under this window so that shadows drawn for a newly + // focused (but not raised) window don't overlap any windows above it. + if (isDock()) { + ClientList stacking_order = workspace()->stackingOrder(); + for (ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it) + if ((*it)->isDesktop()) + { + ++it; + shadows[0] = (*it)->frameId(); + shadows[1] = shadowWidget->winId(); + } + } + else { + shadows[0] = frameId(); + if (shadowWidget != NULL) + shadows[1] = shadowWidget->winId(); + } + + XRestackWindows(qt_xdisplay(), shadows, 2); + + // Don't use TQWidget::show() so we don't confuse QEffects, thus causing + // broken focus. + XMapWindow(qt_xdisplay(), shadowWidget->winId()); + + // Tell whatever Clients are listening that this Client's shadow has been drawn. + emit shadowDrawn(); +} + +/*! + Remove shadow under this window. + */ +void Client::removeShadow() +{ + TQValueList::Iterator it; + + shadowDelayTimer->stop(); + + if (shadowWidget != NULL) { + for (it = shadowRegions.begin(); it != shadowRegions.end(); ++it) + if ((*it).client == this) { + shadowRegions.remove(it); + break; + } + delete shadowWidget; + shadowWidget = NULL; + } +} + +/*! + Calculate regions in which the shadow will be visible given the window's + origin, height and width and the shadow's thickness, and X- and Y-offsets. + */ +TQRegion Client::getExposedRegion(TQRegion occludedRegion, int x, int y, int w, + int h, int thickness, int xOffset, int yOffset) +{ + TQRegion exposedRegion; + + exposedRegion = TQRegion(x, y, w, h); + exposedRegion -= occludedRegion; + + if (thickness > 0) { + // Limit exposedRegion to include only where a shadow of the specified + // thickness will be drawn + TQMemArray occludedRects; + TQMemArray::Iterator it, itEnd; + TQRegion shadowRegion; + + occludedRects = occludedRegion.rects(); + itEnd = occludedRects.end(); + for (it = occludedRects.begin(); it != itEnd; ++it) { + // Expand each of the occluded region's shape rectangles to contain + // where a shadow of the specified thickness will be drawn. Create + // a new TQRegion that contains the expanded occluded region + it->setTop(it->top() - thickness + yOffset); + it->setLeft(it->left() - thickness + xOffset); + it->setRight(it->right() + thickness + xOffset); + it->setBottom(it->bottom() + thickness + yOffset); + shadowRegion += TQRegion(*it); + } + exposedRegion -= exposedRegion - shadowRegion; + } + + return exposedRegion; +} + +/*! + Draw shadow gradient around this window using cached opacity values. + */ +void Client::imposeCachedShadow(TQPixmap &pixmap, TQRegion exposed) +{ + QRgb pixel; + double opacity; + int red, green, blue, pixelRed, pixelGreen, pixelBlue; + int subW, subH, w, h, x, y, zeroX, zeroY; + TQImage image; + TQMemArray::Iterator it, itEnd; + TQMemArray rectangles; + TQPixmap subPixmap; + Window rootWindow; + int thickness, windowX, windowY, xOffset, yOffset; + + rectangles = exposed.rects(); + rootWindow = qt_xrootwin(); + thickness = options->shadowThickness(isActive()); + windowX = this->x(); + windowY = this->y(); + xOffset = options->shadowXOffset(isActive()); + yOffset = options->shadowYOffset(isActive()); + options->shadowColour(isActive()).rgb(&red, &green, &blue); + w = pixmap.width(); + h = pixmap.height(); + + itEnd = rectangles.end(); + for (it = rectangles.begin(); it != itEnd; ++it) { + subW = (*it).width(); + subH = (*it).height(); + subPixmap = TQPixmap::grabWindow(rootWindow, (*it).x(), (*it).y(), + subW, subH); + zeroX = (*it).x() - windowX + thickness - xOffset; + zeroY = (*it).y() - windowY + thickness - yOffset; + image = subPixmap.convertToImage(); + + for (x = 0; x < subW; x++) { + for (y = 0; y < subH; y++) { + opacity = (*(opacityCache))[(zeroY + y) * w + zeroX + x]; + pixel = image.pixel(x, y); + pixelRed = qRed(pixel); + pixelGreen = qGreen(pixel); + pixelBlue = qBlue(pixel); + image.setPixel(x, y, + qRgb((int)(pixelRed + (red - pixelRed) * opacity), + (int)(pixelGreen + (green - pixelGreen) * opacity), + (int)(pixelBlue + (blue - pixelBlue) * opacity))); + } + } + + subPixmap.convertFromImage(image); + bitBlt(&pixmap, zeroX, zeroY, &subPixmap); + } +} + +/*! + Draw shadow around this window using calculated opacity values. + */ +void Client::imposeRegionShadow(TQPixmap &pixmap, TQRegion occluded, + TQRegion exposed, int thickness, double maxOpacity) +{ + register int distance, intersectCount, i, j, x, y; + QRgb pixel; + double decay, factor, opacity; + int red, green, blue, pixelRed, pixelGreen, pixelBlue; + int halfMaxIntersects, lineIntersects, maxIntersects, maxY; + int irBottom, irLeft, irRight, irTop, yIncrement; + int subW, subH, w, h, zeroX, zeroY; + TQImage image; + TQMemArray::Iterator it, itEnd; + TQMemArray rectangles; + TQPixmap subPixmap; + Window rootWindow; + int windowX, windowY, xOffset, yOffset; + + rectangles = exposed.rects(); + rootWindow = qt_xrootwin(); + windowX = this->x(); + windowY = this->y(); + xOffset = options->shadowXOffset(isActive()); + yOffset = options->shadowYOffset(isActive()); + options->shadowColour(isActive()).rgb(&red, &green, &blue); + maxIntersects = thickness * thickness * 4 + (thickness * 4) + 1; + halfMaxIntersects = maxIntersects / 2; + lineIntersects = thickness * 2 + 1; + factor = maxIntersects / maxOpacity; + decay = (lineIntersects / 0.0125 - factor) / pow((double)maxIntersects, 3.0); + w = pixmap.width(); + h = pixmap.height(); + xOffset = options->shadowXOffset(isActive()); + yOffset = options->shadowYOffset(isActive()); + + opacityCache->resize(0); + opacityCache->resize(w * h); + occluded.translate(-windowX + thickness, -windowY + thickness); + + itEnd = rectangles.end(); + for (it = rectangles.begin(); it != itEnd; ++it) { + subW = (*it).width(); + subH = (*it).height(); + subPixmap = TQPixmap::grabWindow(rootWindow, (*it).x(), (*it).y(), + subW, subH); + maxY = subH; + zeroX = (*it).x() - windowX + thickness - xOffset; + zeroY = (*it).y() - windowY + thickness - yOffset; + image = subPixmap.convertToImage(); + + intersectCount = 0; + opacity = -1; + y = 0; + yIncrement = 1; + for (x = 0; x < subW; x++) { + irLeft = zeroX + x - thickness; + irRight = zeroX + x + thickness; + + while (y != maxY) { + // horizontal row about to leave the intersect region, not + // necessarily the top row + irTop = zeroY + y - thickness * yIncrement; + // horizontal row that just came into the intersect region, + // not necessarily the bottom row + irBottom = zeroY + y + thickness * yIncrement; + + if (opacity == -1) { + // If occluded pixels caused an intersect count to be + // skipped, recount it + intersectCount = 0; + + for (j = irTop; j != irBottom; j += yIncrement) { + // irTop is not necessarily larger than irBottom and + // yIncrement isn't necessarily positive + for (i = irLeft; i <= irRight; i++) { + if (occluded.contains(TQPoint(i, j))) + intersectCount++; + } + } + } + else { + if (intersectCount < 0) + intersectCount = 0; + + for (i = irLeft; i <= irRight; i++) { + if (occluded.contains(TQPoint(i, irBottom))) + intersectCount++; + } + } + + distance = maxIntersects - intersectCount; + opacity = intersectCount / (factor + pow((double)distance, 3.0) * decay); + + (*(opacityCache))[(zeroY + y) * w + zeroX + x] = opacity; + pixel = image.pixel(x, y); + pixelRed = qRed(pixel); + pixelGreen = qGreen(pixel); + pixelBlue = qBlue(pixel); + image.setPixel(x, y, + qRgb((int)(pixelRed + (red - pixelRed) * opacity), + (int)(pixelGreen + (green - pixelGreen) * opacity), + (int)(pixelBlue + (blue - pixelBlue) * opacity))); + + for (i = irLeft; i <= irRight; i++) { + if (occluded.contains(TQPoint(i, irTop))) + intersectCount--; + } + + y += yIncrement; + } + y -= yIncrement; + + irTop += yIncrement; + for (j = irTop; j != irBottom; j += yIncrement) { + if (occluded.contains(TQPoint(irLeft, j))) + intersectCount--; + } + irRight++; + for (j = irTop; j != irBottom; j += yIncrement) { + if (occluded.contains(TQPoint(irRight, j))) + intersectCount++; + } + + yIncrement *= -1; + if (yIncrement < 0) + // Scan Y-axis bottom-up for next X-coordinate iteration + maxY = -1; + else + // Scan Y-axis top-down for next X-coordinate iteration + maxY = subH; + } + + subPixmap.convertFromImage(image); + bitBlt(&pixmap, zeroX, zeroY, &subPixmap); + } +} + /*! Sets the client window's mapping state. Possible values are WithdrawnState, IconicState, NormalState. @@ -989,6 +1620,8 @@ void Client::rawShow() XMapWindow( qt_xdisplay(), wrapper ); XMapWindow( qt_xdisplay(), client ); } + if (options->shadowEnabled(isActive())) + drawDelayedShadow(); } /*! @@ -1004,6 +1637,8 @@ void Client::rawHide() // which won't be missed, so this shouldn't be a problem. The chance the real UnmapNotify // will be missed is also very minimal, so I don't think it's needed to grab the server // here. + removeShadow(); + drawIntersectingShadows(); XSelectInput( qt_xdisplay(), wrapper, ClientWinMask ); // avoid getting UnmapNotify XUnmapWindow( qt_xdisplay(), frame ); XUnmapWindow( qt_xdisplay(), wrapper ); diff --git a/kwin/client.h b/kwin/client.h index 306873a1e..1c4d45f51 100644 --- a/kwin/client.h +++ b/kwin/client.h @@ -200,6 +200,19 @@ class Client : public TQObject, public KDecorationDefines void updateDecoration( bool check_workspace_pos, bool force = false ); void checkBorderSizes(); + // drop shadow + bool isShadowed() const; + void setShadowed(bool shadowed); + Window shadowId() const; + // Aieee, a friend function! Unpleasant, yes, but it's needed by + // raiseClient() to redraw a window's shadow when it is active prior to + // being raised. + friend void Workspace::raiseClient(Client *); + // Wouldn't you know it, friend functions breed. This one's needed to + // enable a DCOP function that causes all shadows obscuring a changed + // window to be redrawn. + friend void Workspace::updateOverlappingShadows(WId); + // shape extensions bool shape() const; void updateShape(); @@ -312,6 +325,8 @@ class Client : public TQObject, public KDecorationDefines void autoRaise(); void shadeHover(); void shortcutActivated(); + void updateOpacityCache(); + private: friend class Bridge; // FRAME @@ -348,12 +363,29 @@ class Client : public TQObject, public KDecorationDefines bool buttonReleaseEvent( Window w, int button, int state, int x, int y, int x_root, int y_root ); bool motionNotifyEvent( Window w, int state, int x, int y, int x_root, int y_root ); + // drop shadows + void drawIntersectingShadows(); + void drawOverlappingShadows(bool waitForMe); + TQRegion getExposedRegion(TQRegion occludedRegion, int x, int y, + int w, int h, int thickness, int xOffset, int yOffset); + void imposeCachedShadow(TQPixmap &pixmap, TQRegion exposed); + void imposeRegionShadow(TQPixmap &pixmap, TQRegion occluded, + TQRegion exposed, int thickness, double maxOpacity = 0.75); + void processDecorationButtonPress( int button, int state, int x, int y, int x_root, int y_root ); private slots: void pingTimeout(); void processKillerExited(); void demandAttentionKNotify(); + void drawShadow(); + void drawShadowAfter(Client *after); + void drawDelayedShadow(); + void removeShadow(); + + signals: + void shadowDrawn(); + private: // ICCCM 4.1.3.1, 4.1.4 , NETWM 2.5.1 @@ -531,6 +563,16 @@ class Client : public TQObject, public KDecorationDefines bool pending_geometry_update; bool shade_geometry_change; int border_left, border_right, border_top, border_bottom; + + Client* shadowAfterClient; + TQWidget* shadowWidget; + TQMemArray activeOpacityCache; + TQMemArray inactiveOpacityCache; + TQMemArray* opacityCache; + TQRegion shapeBoundingRegion; + TQTimer* shadowDelayTimer; + bool shadowMe; + TQRegion _mask; static bool check_active_modal; // see Client::checkActiveModal() KShortcut _shortcut; @@ -880,6 +922,16 @@ inline void Client::plainResize( const TQSize& s, ForceGeometry_t force ) plainResize( s.width(), s.height(), force ); } +inline bool Client::isShadowed() const + { + return shadowMe; + } + +inline Window Client::shadowId() const + { + return shadowWidget != NULL ? shadowWidget->winId() : None; + } + inline void Client::resizeWithChecks( const TQSize& s, ForceGeometry_t force ) { resizeWithChecks( s.width(), s.height(), force ); diff --git a/kwin/events.cpp b/kwin/events.cpp index ba6321a7c..a30e915e1 100644 --- a/kwin/events.cpp +++ b/kwin/events.cpp @@ -1078,6 +1078,217 @@ int qtToX11State( Qt::ButtonState state ) // for the decoration window cannot be (easily) intercepted as X11 events bool Client::eventFilter( TQObject* o, TQEvent* e ) { + if (o == shadowWidget) + { + if (e->type() == TQEvent::MouseButtonRelease) + { + int buttonMask, buttonPressed, x, y, x_root, y_root; + unsigned int mask; + TQMouseEvent *qe = (TQMouseEvent *)e; + Window inner_window, parent_window, pointer_window, root_window; + XButtonEvent xe; + + removeShadow(); + switch (qe->button()) + { + case Qt::MidButton: + buttonMask = Button2Mask; + buttonPressed = Button2; + break; + case Qt::RightButton: + buttonMask = Button3Mask; + buttonPressed = Button3; + break; + default: + buttonMask = Button1Mask; + buttonPressed = Button1; + break; + } + + // find the window under the cursor that should receive the + // simulated events + root_window = qt_xrootwin(); + XQueryPointer(qt_xdisplay(), root_window, &root_window, + &pointer_window, &x_root, &y_root, &x, &y, &mask); + + if (pointer_window != None) + { + // Save the child window immediately under the window + // decoration, if any. This is so that we can send an event to + // the immediate descendant of a window's window decoration, + // which causes KWin to refocus windows properly + parent_window = pointer_window; + XQueryPointer(qt_xdisplay(), parent_window, &root_window, + &pointer_window, &x_root, &y_root, &x, &y, &mask); + inner_window = pointer_window; + + while (pointer_window != None) + { + // Recursively query for the child window under the pointer, + // using the returned child window as the parent window for + // the subsequent query. When no child window is left, we've + // found the child that will receive the simulated event + parent_window = pointer_window; + XQueryPointer(qt_xdisplay(), parent_window, &root_window, + &pointer_window, &x_root, &y_root, &x, &y, &mask); + } + pointer_window = parent_window; + } + else + inner_window = None; + + // simulate a mouse button press + xe.type = ButtonPress; + xe.display = qt_xdisplay(); + xe.root = qt_xrootwin(); + xe.subwindow = None; + xe.time = CurrentTime; + xe.x = x; + xe.y = y; + xe.x_root = x_root; + xe.y_root = y_root; + xe.state = 0; + xe.button = buttonPressed; + xe.same_screen = True; + if (inner_window != None && inner_window != pointer_window) + { + xe.window = inner_window; + XSendEvent(qt_xdisplay(), inner_window, True, ButtonPressMask, + (XEvent *)&xe); + } + xe.window = pointer_window; + XSendEvent(qt_xdisplay(), pointer_window, True, ButtonPressMask, + (XEvent *)&xe); + + // simulate a mouse button release + xe.type = ButtonRelease; + xe.display = qt_xdisplay(); + xe.root = qt_xrootwin(); + xe.subwindow = None; + xe.time = CurrentTime; + xe.x = x; + xe.y = y; + xe.x_root = x_root; + xe.y_root = y_root; + xe.state = buttonMask; + xe.button = buttonPressed; + xe.same_screen = True; + if (inner_window != None && inner_window != pointer_window) + { + xe.window = inner_window; + XSendEvent(qt_xdisplay(), inner_window, True, ButtonReleaseMask, + (XEvent *)&xe); + } + xe.window = pointer_window; + XSendEvent(qt_xdisplay(), pointer_window, True, ButtonReleaseMask, + (XEvent *)&xe); + + drawDelayedShadow(); + + return true; + } + else if (e->type() == TQEvent::Wheel) + { + int x, y, x_root, y_root; + unsigned int buttonMask, buttonPressed, mask; + TQWheelEvent *wheelEvent = (TQWheelEvent *)e; + Window inner_window, parent_window, pointer_window, + root_window; + XButtonEvent xe; + + removeShadow(); + + // state and button parameters passed to XSendEvent depend on the + // direction in which the mouse wheel was rolled + buttonMask = wheelEvent->delta() > 0 ? Button4Mask : Button5Mask; + buttonPressed = wheelEvent->delta() > 0 ? Button4 : Button5; + + // find the window under the cursor that should receive the + // simulated events + root_window = qt_xrootwin(); + XQueryPointer(qt_xdisplay(), root_window, &root_window, + &pointer_window, &x_root, &y_root, &x, &y, &mask); + + if (pointer_window != None) + { + // Save the child window immediately under the window + // decoration, if any. This is so that we can send an event to + // the immediate descendant of a window's window decoration, + // which causes KWin to refocus windows properly + parent_window = pointer_window; + XQueryPointer(qt_xdisplay(), parent_window, &root_window, + &pointer_window, &x_root, &y_root, &x, &y, &mask); + inner_window = pointer_window; + + while (pointer_window != None) + { + // Recursively query for the child window under the pointer, + // using the returned child window as the parent window for + // the subsequent query. When no child window is left, we've + // found the child that will receive the simulated event + parent_window = pointer_window; + XQueryPointer(qt_xdisplay(), parent_window, &root_window, + &pointer_window, &x_root, &y_root, &x, &y, &mask); + } + pointer_window = parent_window; + } + else + inner_window = None; + + // simulate a mouse button press + xe.type = ButtonPress; + xe.display = qt_xdisplay(); + xe.root = qt_xrootwin(); + xe.subwindow = None; + xe.time = CurrentTime; + xe.x = x; + xe.y = y; + xe.x_root = x_root; + xe.y_root = y_root; + xe.state = 0; + xe.same_screen = True; + if (inner_window != None && inner_window != pointer_window) + { + xe.button = buttonPressed; + xe.window = inner_window; + XSendEvent(qt_xdisplay(), inner_window, True, ButtonPressMask, + (XEvent *)&xe); + } + xe.button = buttonPressed; + xe.window = pointer_window; + XSendEvent(qt_xdisplay(), pointer_window, True, ButtonPressMask, + (XEvent *)&xe); + + // simulate a mouse button release + xe.type = ButtonRelease; + xe.display = qt_xdisplay(); + xe.root = qt_xrootwin(); + xe.subwindow = None; + xe.time = CurrentTime; + xe.x = x; + xe.y = y; + xe.x_root = x_root; + xe.y_root = y_root; + xe.same_screen = True; + if (inner_window != None && inner_window != pointer_window) + { + xe.window = inner_window; + xe.state = buttonMask; + xe.button = buttonPressed; + XSendEvent(qt_xdisplay(), inner_window, True, ButtonReleaseMask, + (XEvent *)&xe); + } + xe.state = buttonMask; + xe.button = buttonPressed; + xe.window = pointer_window; + XSendEvent(qt_xdisplay(), pointer_window, True, ButtonReleaseMask, + (XEvent *)&xe); + + drawDelayedShadow(); + + return true; + } + } if( decoration == NULL || o != decoration->widget()) return false; diff --git a/kwin/geometry.cpp b/kwin/geometry.cpp index f531bdfb8..3fd278360 100644 --- a/kwin/geometry.cpp +++ b/kwin/geometry.cpp @@ -1063,6 +1063,15 @@ void Client::checkDirection( int new_diff, int old_diff, TQRect& rect, const TQR rect.moveLeft( area.right() - 5 ); } } + if (!moveResizeMode && options->shadowEnabled(isActive())) + { + // If the user is manually resizing, let Client::leaveMoveResize() + // decide when to redraw the shadow + removeShadow(); + drawIntersectingShadows(); + if (options->shadowEnabled(isActive())) + drawDelayedShadow(); + } } /*! @@ -2322,6 +2331,7 @@ bool Client::startMoveResize() } if ( maximizeMode() != MaximizeRestore ) resetMaximize(); + removeShadow(); moveResizeMode = true; workspace()->setClientIsMoving(this); initialMoveResizeGeom = moveResizeGeom = geometry(); @@ -2390,6 +2400,11 @@ void Client::leaveMoveResize() moveResizeMode = false; delete eater; eater = 0; + if (options->shadowEnabled(isActive())) + { + drawIntersectingShadows(); + updateOpacityCache(); + } } // This function checks if it actually makes sense to perform a restricted move/resize. diff --git a/kwin/kcmkwin/kwindecoration/kwindecoration.cpp b/kwin/kcmkwin/kwindecoration/kwindecoration.cpp index 68aec85ff..193450086 100644 --- a/kwin/kcmkwin/kwindecoration/kwindecoration.cpp +++ b/kwin/kcmkwin/kwindecoration/kwindecoration.cpp @@ -28,6 +28,8 @@ */ #include +#include + #include #include #include @@ -39,8 +41,10 @@ #include #include #include +#include #include +#include #include #include #include @@ -153,6 +157,164 @@ KWinDecorationModule::KWinDecorationModule(TQWidget* parent, const char* name, c preview->setSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Expanding); tabWidget->setSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Maximum); + // Page 3 (Window Shadows) + TQHBox *inactiveShadowColourHBox, *shadowColourHBox; + TQHBox *inactiveShadowOpacityHBox, *shadowOpacityHBox; + TQHBox *inactiveShadowXOffsetHBox, *shadowXOffsetHBox; + TQHBox *inactiveShadowYOffsetHBox, *shadowYOffsetHBox; + TQHBox *inactiveShadowThicknessHBox, *shadowThicknessHBox; + TQLabel *inactiveShadowColourLabel, *shadowColourLabel; + TQLabel *inactiveShadowOpacityLabel, *shadowOpacityLabel; + TQLabel *inactiveShadowXOffsetLabel, *shadowXOffsetLabel; + TQLabel *inactiveShadowYOffsetLabel, *shadowYOffsetLabel; + TQLabel *inactiveShadowThicknessLabel, *shadowThicknessLabel; + + shadowPage = new TQVBox(tabWidget); + shadowPage->setSpacing(KDialog::spacingHint()); + shadowPage->setMargin(KDialog::marginHint()); + + cbWindowShadow = new TQCheckBox( + i18n("&Draw a drop shadow under windows"), shadowPage); + TQWhatsThis::add(cbWindowShadow, + i18n("Enabling this checkbox will allow you to choose a kind of " + "drop shadow to draw under each window.")); + + activeShadowSettings = new TQGroupBox(1, Qt::Horizontal, + i18n("Active Window Shadow"), shadowPage); + inactiveShadowSettings = new TQGroupBox(1, Qt::Horizontal, + i18n("Inactive Window Shadows"), shadowPage); + whichShadowSettings = new TQGroupBox(3, Qt::Horizontal, + i18n("Draw Shadow Under Normal Windows And..."), shadowPage); + + cbShadowDocks = new TQCheckBox(i18n("Docks and &panels"), + whichShadowSettings); + connect(cbShadowDocks, TQT_SIGNAL(toggled(bool)), + TQT_SLOT(slotSelectionChanged())); + cbShadowOverrides = new TQCheckBox(i18n("O&verride windows"), + whichShadowSettings); + connect(cbShadowOverrides, TQT_SIGNAL(toggled(bool)), + TQT_SLOT(slotSelectionChanged())); + cbShadowTopMenus = new TQCheckBox(i18n("&Top menu"), + whichShadowSettings); + connect(cbShadowTopMenus, TQT_SIGNAL(toggled(bool)), + TQT_SLOT(slotSelectionChanged())); + cbInactiveShadow = new TQCheckBox( + i18n("Draw shadow under &inactive windows"), inactiveShadowSettings); + connect(cbInactiveShadow, TQT_SIGNAL(toggled(bool)), + TQT_SLOT(slotSelectionChanged())); + + shadowColourHBox = new TQHBox(activeShadowSettings); + shadowColourHBox->setSpacing(KDialog::spacingHint()); + shadowColourLabel = new TQLabel(i18n("Colour:"), shadowColourHBox); + shadowColourButton = new KColorButton(shadowColourHBox); + connect(shadowColourButton, TQT_SIGNAL(changed(const TQColor &)), TQT_SLOT(slotSelectionChanged())); + + inactiveShadowColourHBox = new TQHBox(inactiveShadowSettings); + inactiveShadowColourHBox->setSpacing(KDialog::spacingHint()); + inactiveShadowColourLabel = new TQLabel(i18n("Colour:"), inactiveShadowColourHBox); + inactiveShadowColourButton = new KColorButton(inactiveShadowColourHBox); + connect(inactiveShadowColourButton, TQT_SIGNAL(changed(const TQColor &)), TQT_SLOT(slotSelectionChanged())); + + shadowOpacityHBox = new TQHBox(activeShadowSettings); + shadowOpacityHBox->setSpacing(KDialog::spacingHint()); + shadowOpacityLabel = new TQLabel(i18n("Maximum opacity:"), shadowOpacityHBox); + shadowOpacitySlider = new TQSlider(1, 100, 10, 50, Qt::Horizontal, + shadowOpacityHBox); + shadowOpacitySlider->setTickmarks(TQSlider::Below); + shadowOpacitySlider->setTickInterval(10); + shadowOpacitySpinBox = new TQSpinBox(1, 100, 1, shadowOpacityHBox); + shadowOpacitySpinBox->setSuffix(" %"); + connect(shadowOpacitySlider, TQT_SIGNAL(valueChanged(int)), shadowOpacitySpinBox, + TQT_SLOT(setValue(int))); + connect(shadowOpacitySpinBox, TQT_SIGNAL(valueChanged(int)), shadowOpacitySlider, + TQT_SLOT(setValue(int))); + connect(shadowOpacitySlider, TQT_SIGNAL(valueChanged(int)), + TQT_SLOT(slotSelectionChanged())); + + inactiveShadowOpacityHBox = new TQHBox(inactiveShadowSettings); + inactiveShadowOpacityHBox->setSpacing(KDialog::spacingHint()); + inactiveShadowOpacityLabel = new TQLabel(i18n("Maximum opacity:"), + inactiveShadowOpacityHBox); + inactiveShadowOpacitySlider = new TQSlider(1, 100, 10, 50, Qt::Horizontal, + inactiveShadowOpacityHBox); + inactiveShadowOpacitySlider->setTickmarks(TQSlider::Below); + inactiveShadowOpacitySlider->setTickInterval(10); + inactiveShadowOpacitySpinBox = new TQSpinBox(1, 100, 1, + inactiveShadowOpacityHBox); + inactiveShadowOpacitySpinBox->setSuffix(" %"); + connect(inactiveShadowOpacitySlider, TQT_SIGNAL(valueChanged(int)), + inactiveShadowOpacitySpinBox, + TQT_SLOT(setValue(int))); + connect(inactiveShadowOpacitySpinBox, TQT_SIGNAL(valueChanged(int)), + inactiveShadowOpacitySlider, + TQT_SLOT(setValue(int))); + connect(inactiveShadowOpacitySlider, TQT_SIGNAL(valueChanged(int)), + TQT_SLOT(slotSelectionChanged())); + + shadowXOffsetHBox = new TQHBox(activeShadowSettings); + shadowXOffsetHBox->setSpacing(KDialog::spacingHint()); + shadowXOffsetLabel = new TQLabel( + i18n("Offset rightward (may be negative):"), + shadowXOffsetHBox); + shadowXOffsetSpinBox = new TQSpinBox(-1024, 1024, 1, shadowXOffsetHBox); + shadowXOffsetSpinBox->setSuffix(i18n(" pixels")); + connect(shadowXOffsetSpinBox, TQT_SIGNAL(valueChanged(int)), + TQT_SLOT(slotSelectionChanged())); + + inactiveShadowXOffsetHBox = new TQHBox(inactiveShadowSettings); + inactiveShadowXOffsetHBox->setSpacing(KDialog::spacingHint()); + inactiveShadowXOffsetLabel = new TQLabel( + i18n("Offset rightward (may be negative):"), + inactiveShadowXOffsetHBox); + inactiveShadowXOffsetSpinBox = new TQSpinBox(-1024, 1024, 1, + inactiveShadowXOffsetHBox); + inactiveShadowXOffsetSpinBox->setSuffix(i18n(" pixels")); + connect(inactiveShadowXOffsetSpinBox, TQT_SIGNAL(valueChanged(int)), + TQT_SLOT(slotSelectionChanged())); + + shadowYOffsetHBox = new TQHBox(activeShadowSettings); + shadowYOffsetHBox->setSpacing(KDialog::spacingHint()); + shadowYOffsetLabel = new TQLabel( + i18n("Offset downward (may be negative):"), + shadowYOffsetHBox); + shadowYOffsetSpinBox = new TQSpinBox(-1024, 1024, 1, shadowYOffsetHBox); + shadowYOffsetSpinBox->setSuffix(i18n(" pixels")); + connect(shadowYOffsetSpinBox, TQT_SIGNAL(valueChanged(int)), + TQT_SLOT(slotSelectionChanged())); + + inactiveShadowYOffsetHBox = new TQHBox(inactiveShadowSettings); + inactiveShadowYOffsetHBox->setSpacing(KDialog::spacingHint()); + inactiveShadowYOffsetLabel = new TQLabel( + i18n("Offset downward (may be negative):"), + inactiveShadowYOffsetHBox); + inactiveShadowYOffsetSpinBox = new TQSpinBox(-1024, 1024, 1, + inactiveShadowYOffsetHBox); + inactiveShadowYOffsetSpinBox->setSuffix(i18n(" pixels")); + connect(inactiveShadowYOffsetSpinBox, TQT_SIGNAL(valueChanged(int)), + TQT_SLOT(slotSelectionChanged())); + + shadowThicknessHBox = new TQHBox(activeShadowSettings); + shadowThicknessHBox->setSpacing(KDialog::spacingHint()); + shadowThicknessLabel = new TQLabel( + i18n("Thickness to either side of window:"), + shadowThicknessHBox); + shadowThicknessSpinBox = new TQSpinBox(1, 100, 1, + shadowThicknessHBox); + shadowThicknessSpinBox->setSuffix(i18n(" pixels")); + connect(shadowThicknessSpinBox, TQT_SIGNAL(valueChanged(int)), + TQT_SLOT(slotSelectionChanged())); + + inactiveShadowThicknessHBox = new TQHBox(inactiveShadowSettings); + inactiveShadowThicknessHBox->setSpacing(KDialog::spacingHint()); + inactiveShadowThicknessLabel = new TQLabel( + i18n("Thickness to either side of window:"), + inactiveShadowThicknessHBox); + inactiveShadowThicknessSpinBox = new TQSpinBox(1, 100, 1, + inactiveShadowThicknessHBox); + inactiveShadowThicknessSpinBox->setSuffix(i18n(" pixels")); + connect(inactiveShadowThicknessSpinBox, TQT_SIGNAL(valueChanged(int)), + TQT_SLOT(slotSelectionChanged())); + // Load all installed decorations into memory // Set up the decoration lists and other UI settings findDecorations(); @@ -162,6 +324,7 @@ KWinDecorationModule::KWinDecorationModule(TQWidget* parent, const char* name, c tabWidget->insertTab( pluginPage, i18n("&Window Decoration") ); tabWidget->insertTab( buttonPage, i18n("&Buttons") ); + tabWidget->insertTab( shadowPage, i18n("&Shadows") ); connect( buttonPositionWidget, TQT_SIGNAL(changed()), this, TQT_SLOT(slotButtonsChanged()) ); // update preview etc. connect( buttonPositionWidget, TQT_SIGNAL(changed()), this, TQT_SLOT(slotSelectionChanged()) ); // emit changed()... @@ -171,7 +334,12 @@ KWinDecorationModule::KWinDecorationModule(TQWidget* parent, const char* name, c connect( cbUseCustomButtonPositions, TQT_SIGNAL(clicked()), TQT_SLOT(slotSelectionChanged()) ); connect(cbUseCustomButtonPositions, TQT_SIGNAL(toggled(bool)), buttonPositionWidget, TQT_SLOT(setEnabled(bool))); connect(cbUseCustomButtonPositions, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotButtonsChanged()) ); + connect(cbWindowShadow, TQT_SIGNAL(toggled(bool)), activeShadowSettings, TQT_SLOT(setEnabled(bool))); + connect(cbWindowShadow, TQT_SIGNAL(toggled(bool)), inactiveShadowSettings, TQT_SLOT(setEnabled(bool))); + connect(cbWindowShadow, TQT_SIGNAL(toggled(bool)), whichShadowSettings, TQT_SLOT(setEnabled(bool))); + connect( cbShowToolTips, TQT_SIGNAL(clicked()), TQT_SLOT(slotSelectionChanged()) ); + connect( cbWindowShadow, TQT_SIGNAL(clicked()), TQT_SLOT(slotSelectionChanged()) ); connect( cBorder, TQT_SIGNAL( activated( int )), TQT_SLOT( slotBorderChanged( int ))); // connect( cbUseMiniWindows, TQT_SIGNAL(clicked()), TQT_SLOT(slotSelectionChanged()) ); @@ -465,6 +633,28 @@ void KWinDecorationModule::readConfig( KConfig* conf ) border_size = BorderNormal; checkSupportedBorderSizes(); + // Shadows tab + // =========== + bool shadowEnabled = conf->readBoolEntry("ShadowEnabled", false); + cbWindowShadow->setChecked(shadowEnabled); + activeShadowSettings->setEnabled(shadowEnabled); + inactiveShadowSettings->setEnabled(shadowEnabled); + whichShadowSettings->setEnabled(shadowEnabled); + shadowColourButton->setColor(conf->readColorEntry("ShadowColour", &Qt::black)); + shadowOpacitySlider->setValue((int)ceil(conf->readDoubleNumEntry("ShadowOpacity", 0.70) * 100)); + shadowXOffsetSpinBox->setValue(conf->readNumEntry("ShadowXOffset", 0)); + shadowYOffsetSpinBox->setValue(conf->readNumEntry("ShadowYOffset", 10)); + cbShadowDocks->setChecked(conf->readBoolEntry("ShadowDocks", false)); + cbShadowOverrides->setChecked(conf->readBoolEntry("ShadowOverrides", false)); + cbShadowTopMenus->setChecked(conf->readBoolEntry("ShadowTopMenus", false)); + shadowThicknessSpinBox->setValue(conf->readNumEntry("ShadowThickness", 10)); + cbInactiveShadow->setChecked(conf->readBoolEntry("InactiveShadowEnabled", false)); + inactiveShadowColourButton->setColor(conf->readColorEntry("InactiveShadowColour", &Qt::black)); + inactiveShadowOpacitySlider->setValue((int)ceil(conf->readDoubleNumEntry("InactiveShadowOpacity", 0.70) * 100)); + inactiveShadowXOffsetSpinBox->setValue(conf->readNumEntry("InactiveShadowXOffset", 0)); + inactiveShadowYOffsetSpinBox->setValue(conf->readNumEntry("InactiveShadowYOffset", 5)); + inactiveShadowThicknessSpinBox->setValue(conf->readNumEntry("InactiveShadowThickness", 5)); + emit KCModule::changed(false); } @@ -489,6 +679,27 @@ void KWinDecorationModule::writeConfig( KConfig* conf ) conf->writeEntry("ButtonsOnRight", buttonPositionWidget->buttonsRight() ); conf->writeEntry("BorderSize", border_size ); + // Shadow settings + conf->writeEntry("ShadowEnabled", cbWindowShadow->isChecked()); + conf->writeEntry("ShadowColour", shadowColourButton->color()); + conf->writeEntry("ShadowOpacity", shadowOpacitySlider->value() / 100.0); + conf->writeEntry("ShadowXOffset", shadowXOffsetSpinBox->value()); + conf->writeEntry("ShadowYOffset", shadowYOffsetSpinBox->value()); + conf->writeEntry("ShadowThickness", shadowThicknessSpinBox->value()); + conf->writeEntry("ShadowDocks", cbShadowDocks->isChecked()); + conf->writeEntry("ShadowOverrides", cbShadowOverrides->isChecked()); + conf->writeEntry("ShadowTopMenus", cbShadowTopMenus->isChecked()); + conf->writeEntry("InactiveShadowEnabled", cbInactiveShadow->isChecked()); + conf->writeEntry("InactiveShadowColour", inactiveShadowColourButton->color()); + conf->writeEntry("InactiveShadowOpacity", + inactiveShadowOpacitySlider->value() / 100.0); + conf->writeEntry("InactiveShadowXOffset", + inactiveShadowXOffsetSpinBox->value()); + conf->writeEntry("InactiveShadowYOffset", + inactiveShadowYOffsetSpinBox->value()); + conf->writeEntry("InactiveShadowThickness", + inactiveShadowThicknessSpinBox->value()); + oldLibraryName = currentLibraryName; currentLibraryName = libName; @@ -541,6 +752,7 @@ void KWinDecorationModule::defaults() cbUseCustomButtonPositions->setChecked( false ); buttonPositionWidget->setEnabled( false ); cbShowToolTips->setChecked( true ); + cbWindowShadow->setChecked( false ); // cbUseMiniWindows->setChecked( false); // Don't set default for now // decorationList->setSelected( @@ -552,6 +764,21 @@ void KWinDecorationModule::defaults() border_size = BorderNormal; checkSupportedBorderSizes(); + shadowColourButton->setColor(Qt::black); + shadowOpacitySlider->setValue(70); + shadowXOffsetSpinBox->setValue(0); + shadowYOffsetSpinBox->setValue(10); + shadowThicknessSpinBox->setValue(10); + cbShadowDocks->setChecked(false); + cbShadowOverrides->setChecked(false); + cbShadowTopMenus->setChecked(false); + cbInactiveShadow->setChecked(false); + inactiveShadowColourButton->setColor(Qt::black); + inactiveShadowOpacitySlider->setValue(70); + inactiveShadowXOffsetSpinBox->setValue(0); + inactiveShadowYOffsetSpinBox->setValue(5); + inactiveShadowThicknessSpinBox->setValue(5); + // Set plugin defaults emit pluginDefaults(); } diff --git a/kwin/kcmkwin/kwindecoration/kwindecoration.h b/kwin/kcmkwin/kwindecoration/kwindecoration.h index c4a123352..53b3ed6ae 100644 --- a/kwin/kcmkwin/kwindecoration/kwindecoration.h +++ b/kwin/kcmkwin/kwindecoration/kwindecoration.h @@ -127,6 +127,19 @@ class KWinDecorationModule : public KCModule, virtual public KWinDecorationIface // Page 2 ButtonPositionWidget *buttonPositionWidget; TQVBox* buttonPage; + + // Page 3 + TQVBox *shadowPage; + KColorButton *inactiveShadowColourButton, *shadowColourButton; + TQCheckBox *cbShadowDocks, *cbShadowOverrides, *cbShadowTopMenus; + TQCheckBox *cbInactiveShadow, *cbWindowShadow; + TQGroupBox *activeShadowSettings, *inactiveShadowSettings; + TQGroupBox *whichShadowSettings; + TQSlider *inactiveShadowOpacitySlider, *shadowOpacitySlider; + TQSpinBox *inactiveShadowOpacitySpinBox, *shadowOpacitySpinBox; + TQSpinBox *inactiveShadowXOffsetSpinBox, *shadowXOffsetSpinBox; + TQSpinBox *inactiveShadowYOffsetSpinBox, *shadowYOffsetSpinBox; + TQSpinBox *inactiveShadowThicknessSpinBox, *shadowThicknessSpinBox; }; diff --git a/kwin/layers.cpp b/kwin/layers.cpp index 40a7583a4..8d942c731 100644 --- a/kwin/layers.cpp +++ b/kwin/layers.cpp @@ -134,37 +134,89 @@ void Workspace::propagateClients( bool propagate_new_clients ) // when passig pointers around. // restack the windows according to the stacking order +#if 0 Window* new_stack = new Window[ stacking_order.count() + 2 ]; int pos = 0; +#endif + NET::WindowType t; + Window shadow; + Window *dock_shadow_stack, *window_stack; + int i, numDocks, pos, topmenu_space_pos; + + dock_shadow_stack = new Window[ stacking_order.count() * 2 ]; + window_stack = new Window[ stacking_order.count() * 2 + 2 ]; + i = 0; + pos = 0; + topmenu_space_pos = 1; // not 0, that's supportWindow !!! + // Stack all windows under the support window. The support window is // not used for anything (besides the NETWM property), and it's not shown, // but it was lowered after kwin startup. Stacking all clients below // it ensures that no client will be ever shown above override-redirect // windows (e.g. popups). +#if 0 new_stack[ pos++ ] = supportWindow->winId(); int topmenu_space_pos = 1; // not 0, that's supportWindow !!! +#endif + window_stack[pos++] = supportWindow->winId(); for( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it ) { +#if 0 new_stack[ pos++ ] = (*it)->frameId(); if( (*it)->belongsToLayer() >= DockLayer ) topmenu_space_pos = pos; - } +#endif + t = (*it)->windowType(); + switch (t) + { + case NET::Dock: + window_stack[pos++] = (*it)->frameId(); + if ((shadow = (*it)->shadowId()) != None) + dock_shadow_stack[i++] = shadow; + break; + case NET::Desktop: + numDocks = i; + for (i = 0; i < numDocks; i++) + // Shadows for dock windows go just above the desktop + window_stack[pos++] = dock_shadow_stack[i]; + window_stack[pos++] = (*it)->frameId(); + break; + case NET::TopMenu: + topmenu_space_pos = pos; + // fall through + default: + window_stack[pos++] = (*it)->frameId(); + if ((shadow = (*it)->shadowId()) != None) + // If the current window also has a shadow, place it + // immediately under the current window + window_stack[pos++] = shadow; + } + } if( topmenu_space != NULL ) { // make sure the topmenu space is below all topmenus, fullscreens, etc. for( int i = pos; i > topmenu_space_pos; --i ) +#if 0 new_stack[ i ] = new_stack[ i - 1 ]; new_stack[ topmenu_space_pos ] = topmenu_space->winId(); +#endif + window_stack[ i ] = window_stack[ i - 1 ]; + window_stack[ topmenu_space_pos ] = topmenu_space->winId(); ++pos; } // TODO isn't it too inefficient to restart always all clients? // TODO don't restack not visible windows? assert( new_stack[ 0 ] = supportWindow->winId()); +#if 0 XRestackWindows(qt_xdisplay(), new_stack, pos); delete [] new_stack; +#endif + XRestackWindows(qt_xdisplay(), window_stack, pos); + delete [] dock_shadow_stack; + delete [] window_stack; if ( propagate_new_clients ) { @@ -342,6 +394,11 @@ void Workspace::raiseClient( Client* c ) unconstrained_stacking_order.remove( c ); unconstrained_stacking_order.append( c ); + if (options->shadowEnabled(c->isActive())) + { + c->removeShadow(); + c->drawDelayedShadow(); + } if( !c->isSpecialWindow()) { diff --git a/kwin/lib/kdecoration.h b/kwin/lib/kdecoration.h index b4f62d6f8..f41f19041 100644 --- a/kwin/lib/kdecoration.h +++ b/kwin/lib/kdecoration.h @@ -97,6 +97,7 @@ public: LowerOp, FullScreenOp, NoBorderOp, + ShadowOp, NoOp, SetupWindowShortcutOp, ApplicationRulesOp ///< @since 3.5 @@ -116,7 +117,7 @@ public: ColorHandle, ///< The color for the resize handle NUM_COLORS }; - + /** * These flags specify which settings changed when rereading settings. * Each setting in class KDecorationOptions specifies its matching flag. @@ -130,7 +131,7 @@ public: SettingTooltips = 1 << 4, ///< The tooltip setting was changed SettingBorder = 1 << 5 ///< The border size setting was changed }; - + /** * Border size. KDecorationOptions::preferredBorderSize() returns * one of these values. @@ -261,7 +262,7 @@ public: * The changed flags for this setting is SettingTooltips. */ bool showTooltips() const; - + /** * The preferred border size selected by the user, e.g. for accessibility * reasons, or when using high resolution displays. It's up to the decoration @@ -322,9 +323,9 @@ class KWIN_EXPORT KDecoration * Destroys the KDecoration. */ virtual ~KDecoration(); - + // requests from decoration - + /** * Returns the KDecorationOptions object, which is used to access * configuration settings for the decoration. @@ -417,7 +418,7 @@ class KWIN_EXPORT KDecoration * to support older code). For a description of all window types, * see the definition of the NET::WindowType type. Note that * some window types never have decorated windows. - * + * * An example of usage: * @code * const unsigned long supported_types = NET::NormalMask | NET::DesktopMask @@ -671,7 +672,7 @@ class KWIN_EXPORT KDecoration /** * This function is called to reset the decoration on settings changes. * It is usually invoked by calling KDecorationFactory::resetDecorations(). - * + * * @param changed Specifies which settings were changed, given by the SettingXXX masks */ virtual void reset( unsigned long changed ); diff --git a/kwin/manage.cpp b/kwin/manage.cpp index e56a877b4..df385867a 100644 --- a/kwin/manage.cpp +++ b/kwin/manage.cpp @@ -372,6 +372,7 @@ bool Client::manage( Window w, bool isMapped ) setSkipTaskbar( session->skipTaskbar, true ); setSkipPager( session->skipPager ); setShade( session->shaded ? ShadeNormal : ShadeNone ); + setShadowed( session->shadowed ); if( session->maximized != MaximizeRestore ) { maximize( (MaximizeMode) session->maximized ); diff --git a/kwin/options.cpp b/kwin/options.cpp index 5f0190347..cab703051 100644 --- a/kwin/options.cpp +++ b/kwin/options.cpp @@ -193,7 +193,24 @@ unsigned long Options::updateSettings() if (resetKompmgr) config->writeEntry("ResetKompmgr",FALSE); - + // window drop shadows + config->setGroup("Style"); + shadow_colour = config->readColorEntry("ShadowColour", &Qt::black); + shadow_docks = config->readBoolEntry("ShadowDocks", false); + shadow_overrides = config->readBoolEntry("ShadowOverrides", false); + shadow_topMenus = config->readBoolEntry("ShadowTopMenus", false); + shadow_inactive_colour = config->readColorEntry("InactiveShadowColour", &Qt::black); + shadow_inactive_enabled = config->readBoolEntry("InactiveShadowEnabled", false); + shadow_inactive_opacity = config->readDoubleNumEntry("InactiveShadowOpacity", 0.70); + shadow_inactive_thickness = config->readNumEntry("InactiveShadowThickness", 5); + shadow_inactive_x_offset = config->readNumEntry("InactiveShadowXOffset", 0); + shadow_inactive_y_offset = config->readNumEntry("InactiveShadowYOffset", 5); + shadow_enabled = config->readBoolEntry("ShadowEnabled", false); + shadow_opacity = config->readDoubleNumEntry("ShadowOpacity", 0.70); + shadow_thickness = config->readNumEntry("ShadowThickness", 10); + shadow_x_offset = config->readNumEntry("ShadowXOffset", 0); + shadow_y_offset = config->readNumEntry("ShadowYOffset", 10); + // Read button tooltip animation effect from kdeglobals // Since we want to allow users to enable window decoration tooltips @@ -243,6 +260,8 @@ Options::WindowOperation Options::windowOperation(const TQString &name, bool res return HMaximizeOp; else if (name == "Lower") return LowerOp; + else if (name == "Shadow") + return ShadowOp; return NoOp; } @@ -285,6 +304,69 @@ bool Options::showGeometryTip() return show_geometry_tip; } +TQColor &Options::shadowColour(bool active) + { + return active ? shadow_colour : shadow_inactive_colour; + } + +bool Options::shadowWindowType(NET::WindowType t) + { + bool retval; + + switch (t) + { + case NET::Dialog: + case NET::Normal: + retval = true; + break; + case NET::Desktop: + case NET::Menu: + case NET::Toolbar: + retval = false; + break; + case NET::Dock: + retval = shadow_docks; + break; + case NET::Override: + retval = shadow_overrides; + break; + case NET::TopMenu: + retval = shadow_topMenus; + break; + default: + retval = false; + break; + } + + return retval; + } + +bool Options::shadowEnabled(bool active) + { + return active ? shadow_enabled : + (shadow_enabled && shadow_inactive_enabled); + } + +double Options::shadowOpacity(bool active) + { + return active ? shadow_opacity : shadow_inactive_opacity; + } + +int Options::shadowThickness(bool active) + { + return active ? shadow_thickness : shadow_inactive_thickness; + } + +int Options::shadowXOffset(bool active) + { + return active ? shadow_x_offset : shadow_inactive_x_offset; + } + +int Options::shadowYOffset(bool active) + { + return active ? shadow_y_offset : shadow_inactive_y_offset; + } + int Options::electricBorders() { return electric_borders; diff --git a/kwin/options.h b/kwin/options.h index 82dc6cdc1..dbaa8855f 100644 --- a/kwin/options.h +++ b/kwin/options.h @@ -268,6 +268,45 @@ class Options : public KDecorationOptions */ bool showGeometryTip(); + /** + * @returns A TQColor representing the colour that window drop shadows should + * be. + */ + TQColor &shadowColour(bool active=true); + + /** + * @returns true if shadows should be drawn around windows of the + * specified type + */ + bool shadowWindowType(NET::WindowType t); + + /** + * @returns true if window shadows should be drawn + */ + bool shadowEnabled(bool active=true); + + /** + * @returns Window shadow's opacity between 0.01 and 1.00. + */ + double shadowOpacity(bool active=true); + + /** + * @returns How thick a shadow should be to either side of of a window. + */ + int shadowThickness(bool active=true); + + /** + * @returns Number of pixels along the X-axis by which to offset window + * shadows. + */ + int shadowXOffset(bool active=true); + + /** + * @returns Number of pixels along the Y-axis by which to offset window + * shadows. + */ + int shadowYOffset(bool active=true); + enum { ElectricDisabled = 0, ElectricMoveOnly = 1, ElectricAlways = 2 }; /** * @returns true if electric borders are enabled. With electric borders @@ -336,6 +375,21 @@ class Options : public KDecorationOptions bool show_geometry_tip; bool topmenus; bool desktop_topmenu; + TQColor shadow_colour; + TQColor shadow_inactive_colour; + bool shadow_docks; + bool shadow_overrides; + bool shadow_topMenus; + bool shadow_inactive_enabled; + bool shadow_enabled; + double shadow_inactive_opacity; + double shadow_opacity; + int shadow_inactive_thickness; + int shadow_thickness; + int shadow_inactive_x_offset; + int shadow_x_offset; + int shadow_inactive_y_offset; + int shadow_y_offset; // List of window classes for which not to use focus stealing prevention TQStringList ignoreFocusStealingClasses; diff --git a/kwin/sm.cpp b/kwin/sm.cpp index d13c6b18b..31cada7e0 100644 --- a/kwin/sm.cpp +++ b/kwin/sm.cpp @@ -106,6 +106,7 @@ void Workspace::storeSession( KConfig* config, SMSavePhase phase ) // the config entry is called "sticky" for back. comp. reasons config->writeEntry( TQString("sticky")+n, c->isOnAllDesktops() ); config->writeEntry( TQString("shaded")+n, c->isShade() ); + config->writeEntry( TQString("shadowed")+n, c->isShadowed() ); // the config entry is called "staysOnTop" for back. comp. reasons config->writeEntry( TQString("staysOnTop")+n, c->keepAbove() ); config->writeEntry( TQString("keepBelow")+n, c->keepBelow() ); @@ -172,6 +173,7 @@ void Workspace::loadSessionInfo() info->minimized = config->readBoolEntry( TQString("iconified")+n, FALSE ); info->onAllDesktops = config->readBoolEntry( TQString("sticky")+n, FALSE ); info->shaded = config->readBoolEntry( TQString("shaded")+n, FALSE ); + info->shadowed = config->readBoolEntry( TQString("shadowed")+n, TRUE ); info->keepAbove = config->readBoolEntry( TQString("staysOnTop")+n, FALSE ); info->keepBelow = config->readBoolEntry( TQString("keepBelow")+n, FALSE ); info->skipTaskbar = config->readBoolEntry( TQString("skipTaskbar")+n, FALSE ); diff --git a/kwin/sm.h b/kwin/sm.h index 9321b3745..065ce621d 100644 --- a/kwin/sm.h +++ b/kwin/sm.h @@ -39,6 +39,7 @@ struct SessionInfo bool minimized; bool onAllDesktops; bool shaded; + bool shadowed; bool keepAbove; bool keepBelow; bool skipTaskbar; diff --git a/kwin/useractions.cpp b/kwin/useractions.cpp index 88bfaf035..e825ac846 100644 --- a/kwin/useractions.cpp +++ b/kwin/useractions.cpp @@ -65,6 +65,7 @@ TQPopupMenu* Workspace::clientPopup() advanced_popup->insertItem( SmallIconSet( "window_fullscreen" ), i18n("&Fullscreen")+'\t'+keys->shortcut("Window Fullscreen").seq(0).toString(), Options::FullScreenOp ); advanced_popup->insertItem( i18n("&No Border")+'\t'+keys->shortcut("Window No Border").seq(0).toString(), Options::NoBorderOp ); + advanced_popup->insertItem( i18n("Shad&ow"), Options::ShadowOp ); advanced_popup->insertItem( SmallIconSet("key_bindings"), i18n("Window &Shortcut...")+'\t'+keys->shortcut("Setup Window Shortcut").seq(0).toString(), Options::SetupWindowShortcutOp ); advanced_popup->insertItem( SmallIconSet( "wizard" ), i18n("&Special Window Settings..."), Options::WindowRulesOp ); @@ -172,6 +173,10 @@ void Workspace::clientPopupAboutToShow() advanced_popup->setItemEnabled( Options::FullScreenOp, active_popup_client->userCanSetFullScreen() ); advanced_popup->setItemChecked( Options::NoBorderOp, active_popup_client->noBorder() ); advanced_popup->setItemEnabled( Options::NoBorderOp, active_popup_client->userCanSetNoBorder() ); + + advanced_popup->setItemEnabled( Options::ShadowOp, (options->shadowWindowType(active_popup_client->windowType()) && options->shadowEnabled(active_popup_client->isActive())) ); + advanced_popup->setItemChecked( Options::ShadowOp, active_popup_client->isShadowed() ); + popup->setItemEnabled( Options::MinimizeOp, active_popup_client->isMinimizable() ); popup->setItemEnabled( Options::CloseOp, active_popup_client->isCloseable() ); if (options->useTranslucency) @@ -398,6 +403,9 @@ void Workspace::performWindowOperation( Client* c, Options::WindowOperation op ) case Options::ShadeOp: c->performMouseCommand( Options::MouseShade, TQCursor::pos()); break; + case Options::ShadowOp: + c->setShadowed( !c->isShadowed() ); + break; case Options::OnAllDesktopsOp: c->setOnAllDesktops( !c->isOnAllDesktops() ); break; diff --git a/kwin/workspace.cpp b/kwin/workspace.cpp index bc8914f5b..fe8ad8faa 100644 --- a/kwin/workspace.cpp +++ b/kwin/workspace.cpp @@ -90,6 +90,7 @@ Workspace::Workspace( bool restore ) rules_updates_disabled( false ), active_client (0), last_active_client (0), + next_active_client (0), most_recently_raised (0), movingClient(0), pending_take_activity ( NULL ), @@ -699,6 +700,24 @@ void Workspace::updateFocusChains( Client* c, FocusChainChange change ) } } +void Workspace::updateOverlappingShadows(unsigned long window) + { + Client *client; + + if ((client = findClient(WindowMatchPredicate((WId)window)))) + // Redraw overlapping shadows without waiting for the specified window + // to redraw its own shadow + client->drawOverlappingShadows(false); + } + +void Workspace::setShadowed(unsigned long window, bool shadowed) + { + Client *client; + + if ((client = findClient(WindowMatchPredicate((WId)window)))) + client->setShadowed(shadowed); + } + void Workspace::updateCurrentTopMenu() { if( !managingTopMenus()) diff --git a/kwin/workspace.h b/kwin/workspace.h index d369497da..55043276e 100644 --- a/kwin/workspace.h +++ b/kwin/workspace.h @@ -231,6 +231,8 @@ class Workspace : public TQObject, public KWinInterface, public KDecorationDefin void unclutterDesktop(); void doNotManage(TQString); bool setCurrentDesktop( int new_desktop ); + void updateOverlappingShadows(WId window); + void setShadowed(WId window, bool shadowed); void nextDesktop(); void previousDesktop(); void circulateDesktopApplications(); @@ -518,6 +520,7 @@ class Workspace : public TQObject, public KWinInterface, public KDecorationDefin Client* active_client; Client* last_active_client; + Client* next_active_client; // will be active after active_client deactivates Client* most_recently_raised; // used _only_ by raiseOrLowerClient() Client* movingClient; Client* pending_take_activity; @@ -704,7 +707,15 @@ inline bool Workspace::initializing() const inline Client* Workspace::activeClient() const { - return active_client; + // next_active_client is a kludge for drop shadows. If a window that is + // activated is not also raised (i.e. when focus follows mouse), then the + // newly activated window and its shadow won't cover visual artifacts that + // might exist in the inactive window's shadow. We work around this by + // (re)drawing the inactive window's shadow after the active window's shadow + // is drawn, but to do that the inactive window needs to know which window + // will become active next. next_active_client is a Client pointer for that + // purpose. + return next_active_client != NULL ? next_active_client : active_client; } inline Client* Workspace::mostRecentlyActivatedClient() const -- cgit v1.2.3