summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--twin/KWinInterface.h2
-rw-r--r--twin/client.cpp118
-rw-r--r--twin/client.h5
-rw-r--r--twin/lib/kdecoration.h4
-rw-r--r--twin/useractions.cpp28
-rw-r--r--twin/workspace.cpp54
-rw-r--r--twin/workspace.h6
7 files changed, 216 insertions, 1 deletions
diff --git a/twin/KWinInterface.h b/twin/KWinInterface.h
index 2af0d03ff..5a270d9f3 100644
--- a/twin/KWinInterface.h
+++ b/twin/KWinInterface.h
@@ -13,6 +13,8 @@ class KWinInterface : virtual public DCOPObject
virtual ASYNC unclutterDesktop() = 0;
virtual ASYNC reconfigure() = 0;
virtual ASYNC killWindow() = 0;
+ virtual ASYNC suspendWindow() = 0;
+ virtual ASYNC resumeWindow() = 0;
virtual void refresh() = 0;
virtual void doNotManage(TQString)= 0;
virtual void showWindowMenuAt(unsigned long winId, int x, int y)= 0;
diff --git a/twin/client.cpp b/twin/client.cpp
index c09df53fa..ff890404e 100644
--- a/twin/client.cpp
+++ b/twin/client.cpp
@@ -1834,6 +1834,124 @@ void Client::killProcess( bool ask, Time timestamp )
}
}
+bool Client::isSuspendable() const
+ {
+ TQCString machine = wmClientMachine( true );
+ pid_t pid = info->pid();
+ if( pid <= 0 || machine.isEmpty()) // needed properties missing
+ return false;
+ kdDebug( 1212 ) << "Suspend process:" << pid << "(" << machine << ")" << endl;
+ if( machine != "localhost" )
+ {
+ return false;
+ }
+ else
+ {
+ FILE *procfile;
+ if(chdir(TQString("/proc/%1").arg(pid).ascii()) == 0)
+ {
+ procfile = fopen("stat", "r");
+ }
+ if(!procfile)
+ {
+ return false;
+ }
+ else
+ {
+ long long int procpid;
+ char tcomm[PATH_MAX];
+ char state;
+ fscanf(procfile, "%lld ", &procpid);
+ fscanf(procfile, "%s ", tcomm);
+ fscanf(procfile, "%c ", &state);
+ if( state != 'T' )
+ {
+ fclose(procfile);
+ return true;
+ }
+ else
+ {
+ fclose(procfile);
+ return false;
+ }
+ }
+ }
+ }
+
+bool Client::isResumeable() const
+ {
+ TQCString machine = wmClientMachine( true );
+ pid_t pid = info->pid();
+ if( pid <= 0 || machine.isEmpty()) // needed properties missing
+ return false;
+ kdDebug( 1212 ) << "Suspend process:" << pid << "(" << machine << ")" << endl;
+ if( machine != "localhost" )
+ {
+ return false;
+ }
+ else
+ {
+ FILE *procfile;
+ if(chdir(TQString("/proc/%1").arg(pid).ascii()) == 0)
+ {
+ procfile = fopen("stat", "r");
+ }
+ if(!procfile)
+ {
+ return false;
+ }
+ else
+ {
+ long long int procpid;
+ char tcomm[PATH_MAX];
+ char state;
+ fscanf(procfile, "%lld ", &procpid);
+ fscanf(procfile, "%s ", tcomm);
+ fscanf(procfile, "%c ", &state);
+ if( state == 'T' )
+ {
+ fclose(procfile);
+ return true;
+ }
+ else
+ {
+ fclose(procfile);
+ return false;
+ }
+ }
+ }
+ }
+
+void Client::suspendWindow()
+ {
+ TQCString machine = wmClientMachine( true );
+ pid_t pid = info->pid();
+ if( pid <= 0 || machine.isEmpty()) // needed properties missing
+ return;
+ kdDebug( 1212 ) << "Suspend process:" << pid << "(" << machine << ")" << endl;
+ if( machine != "localhost" )
+ {
+ return;
+ }
+ else
+ ::kill( pid, SIGSTOP );
+ }
+
+void Client::resumeWindow()
+ {
+ TQCString machine = wmClientMachine( true );
+ pid_t pid = info->pid();
+ if( pid <= 0 || machine.isEmpty()) // needed properties missing
+ return;
+ kdDebug( 1212 ) << "Resume process:" << pid << "(" << machine << ")" << endl;
+ if( machine != "localhost" )
+ {
+ return;
+ }
+ else
+ ::kill( pid, SIGCONT );
+ }
+
void Client::processKillerExited()
{
kdDebug( 1212 ) << "Killer exited" << endl;
diff --git a/twin/client.h b/twin/client.h
index 21c40afa9..813431065 100644
--- a/twin/client.h
+++ b/twin/client.h
@@ -113,6 +113,9 @@ class Client : public TQObject, public KDecorationDefines
bool isActive() const;
void setActive( bool, bool updateOpacity = true );
+ bool isSuspendable() const;
+ bool isResumeable() const;
+
int desktop() const;
void setDesktop( int );
bool isOnDesktop( int d ) const;
@@ -297,6 +300,8 @@ class Client : public TQObject, public KDecorationDefines
void unminimize( bool avoid_animation = false );
void closeWindow();
void killWindow();
+ void suspendWindow();
+ void resumeWindow();
void maximize( MaximizeMode );
void toggleShade();
void showContextHelp();
diff --git a/twin/lib/kdecoration.h b/twin/lib/kdecoration.h
index f18f970e2..693007a03 100644
--- a/twin/lib/kdecoration.h
+++ b/twin/lib/kdecoration.h
@@ -100,7 +100,9 @@ public:
NoOp,
SetupWindowShortcutOp,
ApplicationRulesOp, ///< @since 3.5
- ShadowOp ///< @since 3.5.12
+ ShadowOp, ///< @since 3.5.12
+ SuspendWindowOp, ///< @since R14.0
+ ResumeWindowOp ///< @since R14.0
};
/**
* Basic color types that should be recognized by all decoration styles.
diff --git a/twin/useractions.cpp b/twin/useractions.cpp
index a265a1784..6542cdb99 100644
--- a/twin/useractions.cpp
+++ b/twin/useractions.cpp
@@ -68,6 +68,10 @@ TQPopupMenu* Workspace::clientPopup()
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 );
+// FIXME
+// Uncomment these actions when twin can handle suspended applications in a user friendly manner
+// advanced_popup->insertItem( SmallIconSet( "suspend" ), i18n("&Suspend Application"), Options::SuspendWindowOp );
+// advanced_popup->insertItem( SmallIconSet( "exec" ), i18n("&Resume Application"), Options::ResumeWindowOp );
advanced_popup->insertItem( SmallIconSet( "wizard" ), i18n("&Special Window Settings..."), Options::WindowRulesOp );
advanced_popup->insertItem( SmallIconSet( "wizard" ), i18n("&Special Application Settings..."), Options::ApplicationRulesOp );
@@ -171,6 +175,8 @@ void Workspace::clientPopupAboutToShow()
advanced_popup->setItemChecked( Options::KeepBelowOp, active_popup_client->keepBelow() );
advanced_popup->setItemChecked( Options::FullScreenOp, active_popup_client->isFullScreen() );
advanced_popup->setItemEnabled( Options::FullScreenOp, active_popup_client->userCanSetFullScreen() );
+ advanced_popup->setItemEnabled( Options::SuspendWindowOp, active_popup_client->isSuspendable() );
+ advanced_popup->setItemEnabled( Options::ResumeWindowOp, active_popup_client->isResumeable() );
advanced_popup->setItemChecked( Options::NoBorderOp, active_popup_client->noBorder() );
advanced_popup->setItemEnabled( Options::NoBorderOp, active_popup_client->userCanSetNoBorder() );
@@ -436,6 +442,12 @@ void Workspace::performWindowOperation( Client* c, Options::WindowOperation op )
case Options::OperationsOp:
c->performMouseCommand( Options::MouseShade, TQCursor::pos());
break;
+ case Options::SuspendWindowOp:
+ c->suspendWindow();
+ break;
+ case Options::ResumeWindowOp:
+ c->resumeWindow();
+ break;
case Options::WindowRulesOp:
editWindowRules( c, false );
break;
@@ -992,6 +1004,22 @@ void Workspace::slotKillWindow()
}
/*!
+ Suspend Window feature
+ */
+void Workspace::slotSuspendWindow()
+ {
+ active_popup_client->suspendWindow();
+ }
+
+/*!
+ Resume Window feature
+ */
+void Workspace::slotResumeWindow()
+ {
+ active_popup_client->resumeWindow();
+ }
+
+/*!
Sends the popup client to desktop \a desk
Internal slot for the window operation menu
diff --git a/twin/workspace.cpp b/twin/workspace.cpp
index 5b9f58305..e6e18e1aa 100644
--- a/twin/workspace.cpp
+++ b/twin/workspace.cpp
@@ -1909,6 +1909,60 @@ void Workspace::killWindowId( Window window_to_kill )
XKillClient( qt_xdisplay(), window_to_kill );
}
+void Workspace::suspendWindowId( Window window_to_suspend )
+ {
+ if( window_to_suspend == None )
+ return;
+ Window window = window_to_suspend;
+ Client* client = NULL;
+ for(;;)
+ {
+ client = findClient( FrameIdMatchPredicate( window ));
+ if( client != NULL ) // found the client
+ break;
+ Window parent, root;
+ Window* children;
+ unsigned int children_count;
+ XQueryTree( qt_xdisplay(), window, &root, &parent, &children, &children_count );
+ if( children != NULL )
+ XFree( children );
+ if( window == root ) // we didn't find the client, probably an override-redirect window
+ break;
+ window = parent; // go up
+ }
+ if( client != NULL )
+ client->suspendWindow();
+ else
+ return;
+ }
+
+void Workspace::resumeWindowId( Window window_to_resume )
+ {
+ if( window_to_resume == None )
+ return;
+ Window window = window_to_resume;
+ Client* client = NULL;
+ for(;;)
+ {
+ client = findClient( FrameIdMatchPredicate( window ));
+ if( client != NULL ) // found the client
+ break;
+ Window parent, root;
+ Window* children;
+ unsigned int children_count;
+ XQueryTree( qt_xdisplay(), window, &root, &parent, &children, &children_count );
+ if( children != NULL )
+ XFree( children );
+ if( window == root ) // we didn't find the client, probably an override-redirect window
+ break;
+ window = parent; // go up
+ }
+ if( client != NULL )
+ client->resumeWindow();
+ else
+ return;
+ }
+
void Workspace::sendPingToWindow( Window window, Time timestamp )
{
diff --git a/twin/workspace.h b/twin/workspace.h
index a4aa6d27f..6a161c52e 100644
--- a/twin/workspace.h
+++ b/twin/workspace.h
@@ -97,8 +97,12 @@ class Workspace : public TQObject, public KWinInterface, public KDecorationDefin
* @internal
*/
void killWindowId( Window window);
+ void suspendWindowId( Window window);
+ void resumeWindowId( Window window);
void killWindow() { slotKillWindow(); }
+ void suspendWindow() { slotSuspendWindow(); }
+ void resumeWindow() { slotResumeWindow(); }
WId rootWin() const;
@@ -369,6 +373,8 @@ class Workspace : public TQObject, public KWinInterface, public KDecorationDefin
void slotReconfigure();
void slotKillWindow();
+ void slotSuspendWindow();
+ void slotResumeWindow();
void slotGrabWindow();
void slotGrabDesktop();