diff --git a/activation.cpp b/activation.cpp
index 4f426f02d6..44e5b004e7 100644
--- a/activation.cpp
+++ b/activation.cpp
@@ -23,6 +23,8 @@ License. See the file "COPYING" for the exact licensing terms.
#include
#include
#include
+#include
+#include
#include "notifications.h"
#include "atoms.h"
@@ -658,10 +660,44 @@ void Client::demandAttention( bool set )
{
if( isActive())
set = false;
- info->setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention );
+ if( demands_attention == set )
+ return;
+ demands_attention = set;
+ if( demands_attention )
+ {
+ // Demand attention flag is often set right from manage(), when focus stealing prevention
+ // steps in. At that time the window has no taskbar entry yet, so KNotify cannot place
+ // e.g. the passive popup next to it. So wait up to 1 second for the icon geometry
+ // to be set.
+ // Delayed call to KNotify also solves the problem of having X server grab in manage(),
+ // which may deadlock when KNotify (or KLauncher when launching KNotify) need to access X.
+ Notify::Event e = isOnCurrentDesktop() ? Notify::DemandAttentionCurrent : Notify::DemandAttentionOther;
+ // Setting the demands attention state needs to be done directly in KWin, because
+ // KNotify would try to set it, resulting in a call to KNotify again, etc.
+ if( Notify::makeDemandAttention( e ))
+ info->setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention );
+
+ if( demandAttentionKNotifyTimer == NULL )
+ {
+ demandAttentionKNotifyTimer = new QTimer( this );
+ connect( demandAttentionKNotifyTimer, SIGNAL( timeout()), SLOT( demandAttentionKNotify()));
+ }
+ demandAttentionKNotifyTimer->start( 1000, true );
+ }
+ else
+ info->setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention );
workspace()->clientAttentionChanged( this, set );
}
+void Client::demandAttentionKNotify()
+ {
+ Notify::Event e = isOnCurrentDesktop() ? Notify::DemandAttentionCurrent : Notify::DemandAttentionOther;
+ Notify::raise( e, i18n( "Window '%1' demands attention." ).arg( KStringHandler::csqueeze(caption())), this );
+ demandAttentionKNotifyTimer->stop();
+ demandAttentionKNotifyTimer->deleteLater();
+ demandAttentionKNotifyTimer = NULL;
+ }
+
// TODO I probably shouldn't be lazy here and do it without the macro, so that people can read it
KWIN_COMPARE_PREDICATE( SameApplicationActiveHackPredicate, const Client*,
// ignore already existing splashes, toolbars, utilities, menus and topmenus,
diff --git a/client.cpp b/client.cpp
index f91cdd6fd6..fa82c59aee 100644
--- a/client.cpp
+++ b/client.cpp
@@ -91,7 +91,8 @@ Client::Client( Workspace *ws )
border_left( 0 ),
border_right( 0 ),
border_top( 0 ),
- border_bottom( 0 )
+ border_bottom( 0 ),
+ demandAttentionKNotifyTimer( NULL )
// SELI do all as initialization
{
autoRaiseTimer = 0;
@@ -128,6 +129,7 @@ Client::Client( Workspace *ws )
not_obscured = false;
urgency = false;
ignore_focus_stealing = false;
+ demands_attention = false;
check_active_modal = false;
Pdeletewindow = 0;
diff --git a/client.h b/client.h
index d4f15d26a5..a4a3ae0c43 100644
--- a/client.h
+++ b/client.h
@@ -341,6 +341,7 @@ class Client : public QObject, public KDecorationDefines
private slots:
void pingTimeout();
void processKillerExited();
+ void demandAttentionKNotify();
private:
// ICCCM 4.1.3.1, 4.1.4 , NETWM 2.5.1
@@ -481,6 +482,7 @@ class Client : public QObject, public KDecorationDefines
uint not_obscured : 1;
uint urgency : 1; // XWMHints, UrgencyHint
uint ignore_focus_stealing : 1; // don't apply focus stealing prevention to this client
+ uint demands_attention : 1;
WindowRules client_rules;
void getWMHints();
void readIcons();
@@ -534,7 +536,7 @@ class Client : public QObject, public KDecorationDefines
uint rule_opacity_inactive; //dto.
//int shadeOriginalHeight;
bool isBMP_;
-
+ QTimer* demandAttentionKNotifyTimer;
};
// NET WM Protocol handler class
diff --git a/events.cpp b/events.cpp
index b8eb51e35c..b52e8dc580 100644
--- a/events.cpp
+++ b/events.cpp
@@ -543,6 +543,11 @@ bool Client::windowEvent( XEvent* e )
}
if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 )
startupIdChanged();
+ if( dirty[ WinInfo::PROTOCOLS ] & NET::WMIconGeometry )
+ {
+ if( demandAttentionKNotifyTimer != NULL )
+ demandAttentionKNotify();
+ }
}
// TODO move all focus handling stuff to separate file?
diff --git a/eventsrc b/eventsrc
index f8506e8b56..923bd0a271 100644
--- a/eventsrc
+++ b/eventsrc
@@ -3530,3 +3530,13 @@ Comment[uz]=Ойнанинг ўлчами ўзгариб бўлди
Comment[wa]=On purnea a fini d' candjî s' grandeu
Comment[xx]=xxA window has finished resizingxx
default_presentation=0
+
+[demandsattentioncurrent]
+Name=Window On Current Desktop Demands Attention
+Comment=A window on the current virtual desktop demands attention
+default_presentation=64
+
+[demandsattentionother]
+Name=Window On Other Desktop Demands Attention
+Comment=A window on an inactive virtual desktop demands attention
+default_presentation=64
diff --git a/kcmkwin/kwinoptions/windows.cpp b/kcmkwin/kwinoptions/windows.cpp
index 8ebd63b7f4..0735c2c58e 100644
--- a/kcmkwin/kwinoptions/windows.cpp
+++ b/kcmkwin/kwinoptions/windows.cpp
@@ -591,7 +591,7 @@ KAdvancedConfig::KAdvancedConfig (bool _standAlone, KConfig *_config, QWidget *p
focusStealingLabel->setBuddy( focusStealing );
focusStealingLayout->addWidget( focusStealingLabel );
focusStealingLayout->addWidget( focusStealing, AlignLeft );
- wtstr = i18n( "This option specifies how much KWin will try to prevent unwanted focus stealing "
+ wtstr = i18n( "This option specifies how much KWin will try to prevent unwanted focus stealing "
"caused by unexpected activation of new windows. (Note: This feature does not "
"work with the Focus Under Mouse or Focus Strictly Under Mouse focus policies.)"
"
"
@@ -606,7 +606,10 @@ KAdvancedConfig::KAdvancedConfig (bool _standAlone, KConfig *_config, QWidget *p
"or if they belong to the currently active application. This setting is probably "
"not really usable when not using mouse focus policy."
"- Extreme: All windows must be explicitly activated by the user.
"
- "
" );
+ "
"
+ "Windows that are prevented from stealing focus are marked as demanding attention, "
+ "which by default means their taskbar entry will be highlighted. This can be changed "
+ "in the Notifications control module.
" );
QWhatsThis::add( focusStealing, wtstr );
QWhatsThis::add( focusStealingLabel, wtstr );
connect(focusStealing, SIGNAL(activated(int)), SLOT(changed()));
diff --git a/notifications.cpp b/notifications.cpp
index ce1ea7e9d2..53a804c3ef 100644
--- a/notifications.cpp
+++ b/notifications.cpp
@@ -12,15 +12,13 @@ License. See the file "COPYING" for the exact licensing terms.
#include "notifications.h"
#include
+#include "client.h"
+
namespace KWinInternal
{
-void Notify::raise( Event e )
+QString Notify::eventToName( Event e )
{
- static bool forgetIt = FALSE;
- if ( forgetIt )
- return; // no connection was possible, don't try each time
-
QString event;
switch ( e )
{
@@ -78,6 +76,12 @@ void Notify::raise( Event e )
case ResizeEnd:
event = "resizeend";
break;
+ case DemandAttentionCurrent:
+ event = "demandsattentioncurrent";
+ break;
+ case DemandAttentionOther:
+ event = "demandsattentionother";
+ break;
default:
if ((e > DesktopChange) && (e <= DesktopChange+20))
{
@@ -85,11 +89,33 @@ void Notify::raise( Event e )
}
break;
}
+ return event;
+ }
+bool Notify::raise( Event e, const QString& message, Client* c )
+ {
+ static bool forgetIt = FALSE;
+ if ( forgetIt )
+ return false; // no connection was possible, don't try each time
+
+ QString event = eventToName( e );
if ( !event )
- return;
+ return false;
- forgetIt= !KNotifyClient::event( 0, event, event );
+ forgetIt= !KNotifyClient::event( c ? c->window() : 0, event, message );
+
+ return !forgetIt;
+ }
+
+bool Notify::makeDemandAttention( Event e )
+ {
+ QString event = eventToName( e );
+ if( !event )
+ return false;
+ int rep = KNotifyClient::getPresentation( event );
+ if( rep == -1 )
+ rep = KNotifyClient::getDefaultPresentation( event );
+ return rep != -1 && ( rep & KNotifyClient::Taskbar );
}
} // namespace
diff --git a/notifications.h b/notifications.h
index b8fe4c7335..478d15a6a4 100644
--- a/notifications.h
+++ b/notifications.h
@@ -12,9 +12,14 @@ License. See the file "COPYING" for the exact licensing terms.
#ifndef KWIN_NOTIFICATIONS_H
#define KWIN_NOTIFICATIONS_H
+#include
+#include
+
namespace KWinInternal
{
+class Client;
+
class Notify
{
public:
@@ -39,10 +44,15 @@ class Notify
MoveEnd,
ResizeStart,
ResizeEnd,
+ DemandAttentionCurrent,
+ DemandAttentionOther,
DesktopChange = 100
};
- static void raise( Event );
+ static bool raise( Event, const QString& message = QString::null, Client* c = NULL );
+ static bool makeDemandAttention( Event );
+ private:
+ static QString eventToName( Event );
};
} // namespace