summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-09-07 19:42:15 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-09-07 19:42:15 +0000
commit9cc1e2c1aa2629d499e7555acd4906d6cc989cf9 (patch)
tree2a737f47bb029688c2f5ebef76869903cf4b4eec
parenteaa51fec106463800192924168eaf9f03f188655 (diff)
downloadtdebase-9cc1e2c1.tar.gz
tdebase-9cc1e2c1.zip
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
-rw-r--r--kcontrol/info/memory.cpp55
-rw-r--r--kcontrol/info/memory.h7
-rw-r--r--kdesktop/krootwm.cc29
-rw-r--r--kdesktop/krootwm.h1
-rw-r--r--kmenuedit/kcontroleditui.rc1
-rw-r--r--kmenuedit/kmenuedit.cpp8
-rw-r--r--kmenuedit/kmenuedit.h1
-rw-r--r--kmenuedit/kmenueditui.rc1
-rw-r--r--kmenuedit/pixmaps/cr22-action-filesave_and_close.pngbin0 -> 3263 bytes
-rw-r--r--konsole/konsole/TEmulation.cpp5
-rw-r--r--konsole/konsole/TEmulation.h1
-rw-r--r--konsole/konsole/konsole.cpp37
-rw-r--r--konsole/konsole/konsole.h7
-rw-r--r--ksmserver/legacy.cpp2
-rw-r--r--ksysguard/ksysguardd/Linux/netdev.c193
-rw-r--r--kwin/KWinInterface.h3
-rw-r--r--kwin/activation.cpp49
-rw-r--r--kwin/client.cpp637
-rw-r--r--kwin/client.h52
-rw-r--r--kwin/events.cpp211
-rw-r--r--kwin/geometry.cpp15
-rw-r--r--kwin/kcmkwin/kwindecoration/kwindecoration.cpp227
-rw-r--r--kwin/kcmkwin/kwindecoration/kwindecoration.h13
-rw-r--r--kwin/layers.cpp59
-rw-r--r--kwin/lib/kdecoration.h15
-rw-r--r--kwin/manage.cpp1
-rw-r--r--kwin/options.cpp84
-rw-r--r--kwin/options.h54
-rw-r--r--kwin/sm.cpp2
-rw-r--r--kwin/sm.h1
-rw-r--r--kwin/useractions.cpp8
-rw-r--r--kwin/workspace.cpp19
-rw-r--r--kwin/workspace.h13
33 files changed, 1728 insertions, 83 deletions
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 "
- "<b>total sum of physical and virtual memory</b> "
- "in your system.");
+ "usage of <b>all available memory</b> (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 <b>usage of physical memory</b> in your system."
+ "the usage of <b>physical memory</b> in your system."
"<p>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. "
- "<p>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. "
+ "<p>This means that if you are seeing a small amount "
"of <b>Free Physical Memory</b> and a large amount of "
- "<b>Disk Cache Memory</b>, your system is well "
- "configured.");
+ "<b>Disk Cache</b>, your system is well configured.");
break;
case MEM_HDD:
title = i18n("Swap Space");
- hint = i18n("The swap space is the <b>virtual memory</b> "
+ hint = i18n("Swap space is the <b>virtual memory</b> "
"available to the system. "
- "<p>It will be used on demand and is provided "
+ "<p>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 @@
<Action name="newsubmenu" />
<Separator/>
<Action name="file_save"/>
+ <Action name="file_save_and_quit"/>
<Separator/>
<Action name="file_quit"/>
</Menu>
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 @@
<Action name="newsep" />
<Separator/>
<Action name="file_save"/>
+ <Action name="file_save_and_quit"/>
<Separator/>
<Action name="file_quit"/>
</Menu>
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
--- /dev/null
+++ b/kmenuedit/pixmaps/cr22-action-filesave_and_close.png
Binary files 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 <knotifydialog.h>
#include <kprinter.h>
#include <kaccelmanager.h>
+#include <kurifilter.h>
#include <kaction.h>
#include <kshell.h>
@@ -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 <math.h>
+
#include <tqapplication.h>
#include <tqpainter.h>
#include <tqdatetime.h>
+#include <tqimage.h>
#include <kprocess.h>
#include <unistd.h>
#include <kstandarddirs.h>
@@ -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<ShadowRegion> 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<Client> reshadowClients;
+ TQValueList<Client *> reshadowClients;
+ TQValueListIterator<ShadowRegion> it;
+ TQValueListIterator<Client *> 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<Client *> reshadowClients;
+ ClientList stacking_order;
+ ClientList::ConstIterator it;
+ TQValueListIterator<ShadowRegion> it2;
+ TQValueListIterator<Client *> 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<QRgb> 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<TQRect> exposedRects;
+ TQMemArray<TQRect>::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<ShadowRegion>::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<TQRect> occludedRects;
+ TQMemArray<TQRect>::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<TQRect>::Iterator it, itEnd;
+ TQMemArray<TQRect> 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<TQRect>::Iterator it, itEnd;
+ TQMemArray<TQRect> 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<double> activeOpacityCache;
+ TQMemArray<double> inactiveOpacityCache;
+ TQMemArray<double>* 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 <assert.h>
+#include <math.h>
+
#include <tqdir.h>
#include <tqfileinfo.h>
#include <tqlayout.h>
@@ -39,8 +41,10 @@
#include <tqlabel.h>
#include <tqfile.h>
#include <tqslider.h>
+#include <tqspinbox.h>
#include <kapplication.h>
+#include <kcolorbutton.h>
#include <kcombobox.h>
#include <kdebug.h>
#include <kdesktopfile.h>
@@ -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