Use KNotify for notifications about windows demanding attention.
People who use hidden Kicker, have their taskbar configured to show only windows on the current desktop or similar now may configure it so that windows that didn't get focus because of focus stealing prevention now can not only have their taskbar entry marked but there can be e.g. also a passive popup. svn path=/trunk/KDE/kdebase/kwin/; revision=419727
This commit is contained in:
parent
2e71a5d3cd
commit
96e1fdab6c
8 changed files with 107 additions and 13 deletions
|
@ -23,6 +23,8 @@ License. See the file "COPYING" for the exact licensing terms.
|
|||
#include <qpopupmenu.h>
|
||||
#include <kxerrorhandler.h>
|
||||
#include <kstartupinfo.h>
|
||||
#include <kstringhandler.h>
|
||||
#include <klocale.h>
|
||||
|
||||
#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,
|
||||
|
|
|
@ -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;
|
||||
|
|
4
client.h
4
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
|
||||
|
|
|
@ -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?
|
||||
|
|
10
eventsrc
10
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
|
||||
|
|
|
@ -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( "<p>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.)"
|
||||
"<ul>"
|
||||
|
@ -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.</li>"
|
||||
"<li><em>Extreme:</em> All windows must be explicitly activated by the user.</li>"
|
||||
"</ul>" );
|
||||
"</ul></p>"
|
||||
"<p>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.</p>" );
|
||||
QWhatsThis::add( focusStealing, wtstr );
|
||||
QWhatsThis::add( focusStealingLabel, wtstr );
|
||||
connect(focusStealing, SIGNAL(activated(int)), SLOT(changed()));
|
||||
|
|
|
@ -12,15 +12,13 @@ License. See the file "COPYING" for the exact licensing terms.
|
|||
#include "notifications.h"
|
||||
#include <knotifyclient.h>
|
||||
|
||||
#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
|
||||
|
|
|
@ -12,9 +12,14 @@ License. See the file "COPYING" for the exact licensing terms.
|
|||
#ifndef KWIN_NOTIFICATIONS_H
|
||||
#define KWIN_NOTIFICATIONS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <qstring.h>
|
||||
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue