From d160a6fc0101dd094195f8d0782e8aefcf94d376 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Mon, 20 Feb 2012 02:24:32 -0600 Subject: Update twin with initial framework for application suspend/resume This needs some additional work before it can be enabled --- twin/KWinInterface.h | 2 + twin/client.cpp | 118 +++++++++++++++++++++++++++++++++++++++++++++++++ twin/client.h | 5 +++ twin/lib/kdecoration.h | 4 +- twin/useractions.cpp | 28 ++++++++++++ twin/workspace.cpp | 54 ++++++++++++++++++++++ twin/workspace.h | 6 +++ 7 files changed, 216 insertions(+), 1 deletion(-) (limited to 'twin') 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; @@ -991,6 +1003,22 @@ void Workspace::slotKillWindow() kill.start(); } +/*! + 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 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(); -- cgit v1.2.3