diff --git a/data/rc.xml b/data/rc.xml
index 3e5554bad..c06d38396 100644
--- a/data/rc.xml
+++ b/data/rc.xml
@@ -732,6 +732,13 @@
yes
# make the window in fullscreen mode when it appears
+ process
+ # stop the application when it hides in order to minimize CPU usage
+ # and power consumption
+ # 'no' - do not stop application when it hides (default value)
+ # 'process' - stop just the process the window belongs to
+ # 'group' - stop whole process group the application belongs to
+
true
# 'Horizontal', 'Vertical' or boolean (yes/no)
diff --git a/data/rc.xsd b/data/rc.xsd
index c8f5638bc..a7c23bd47 100644
--- a/data/rc.xsd
+++ b/data/rc.xsd
@@ -254,6 +254,7 @@
+
@@ -485,6 +486,13 @@
+
+
+
+
+
+
+
diff --git a/doc/rc-mouse-focus.xml b/doc/rc-mouse-focus.xml
index dc7f2e987..3e29f73bc 100644
--- a/doc/rc-mouse-focus.xml
+++ b/doc/rc-mouse-focus.xml
@@ -625,6 +625,13 @@
yes
# make the window in fullscreen mode when it appears
+ process
+ # stop the application when it hides in order to minimize CPU usage
+ # and power consumption
+ # 'no' - do not stop application when it hides (default value)
+ # 'process' - stop just the process the window belongs to
+ # 'group' - stop whole process group the application belongs to
+
true
# 'Horizontal', 'Vertical' or boolean (yes/no)
diff --git a/openbox/client.c b/openbox/client.c
index 3ff278ae6..04b66c089 100644
--- a/openbox/client.c
+++ b/openbox/client.c
@@ -625,6 +625,9 @@ void client_unmanage(ObClient *self)
prompt_unref(self->kill_prompt);
self->kill_prompt = NULL;
+ /* if client was stopped, continue executing */
+ client_continue_hidden(self);
+
client_list = g_list_remove(client_list, self);
stacking_remove(self);
window_remove(self->window);
@@ -968,6 +971,8 @@ static ObAppSettings *client_get_settings_state(ObClient *self)
self->skip_pager = !!settings->skip_pager;
if (settings->skip_taskbar != -1)
self->skip_taskbar = !!settings->skip_taskbar;
+ if (settings->stop_hidden != OB_CLIENT_STOP_MODE_NONE)
+ self->stop_hidden = settings->stop_hidden;
if (settings->max_vert != -1)
self->max_vert = !!settings->max_vert;
@@ -1043,6 +1048,7 @@ static void client_restore_session_state(ObClient *self)
self->max_horz = self->session->max_horz;
self->max_vert = self->session->max_vert;
self->undecorated = self->session->undecorated;
+ self->stop_hidden = self->session->stop_hidden;
}
static gboolean client_restore_session_stacking(ObClient *self)
@@ -2510,8 +2516,11 @@ static void client_change_wm_state(ObClient *self)
(self->desktop != DESKTOP_ALL && self->desktop != screen_desktop))
{
self->wmstate = IconicState;
- } else
+ client_stop_hidden(self);
+ } else {
self->wmstate = NormalState;
+ client_continue_hidden(self);
+ }
if (old != self->wmstate) {
OBT_PROP_MSG(ob_screen, self->window, KDE_WM_CHANGE_STATE,
@@ -2608,6 +2617,24 @@ ObClient *client_search_focus_group_full(ObClient *self)
return NULL;
}
+gboolean client_is_hidden(ObClient *self)
+{
+ return (self->wmstate == IconicState);
+}
+
+gboolean client_is_group_hidden(ObClient *self)
+{
+ GSList *it;
+
+ if (self->group) {
+ for (it = self->group->members; it; it = g_slist_next(it)) {
+ ObClient *c = it->data;
+ if (!client_is_hidden(c)) return FALSE;
+ }
+ }
+ return TRUE;
+}
+
gboolean client_has_parent(ObClient *self)
{
return self->parents != NULL;
@@ -3706,6 +3733,68 @@ void client_kill(ObClient *self)
}
}
+void client_stop_hidden(ObClient *self)
+{
+ if (self->stop_hidden == OB_CLIENT_STOP_MODE_NONE)
+ return;
+
+ if (client_on_localhost(self) && self->pid) {
+ /* running on the local host */
+
+ if (!client_is_group_hidden(self)) {
+ return;
+ }
+
+ if (self->stop_hidden == OB_CLIENT_STOP_MODE_PROCESS) {
+ ob_debug("client_stop_hidden is stopping process with pid %lu",
+ self->pid);
+ kill(self->pid, SIGSTOP);
+ } else if (self->stop_hidden == OB_CLIENT_STOP_MODE_GROUP) {
+ ob_debug("client_stop_hidden is stopping group with pid %lu",
+ self->pid);
+ pid_t pgid = getpgid(self->pid);
+ if (pgid != -1) {
+ killpg(self->pid, SIGSTOP);
+ }
+ } else {
+ ob_debug("client_stop_hidden: unknown value of stop_hidden");
+ return;
+ }
+ }
+ else {
+ /* do nothing, running on a remote host */
+ }
+}
+
+void client_continue_hidden(ObClient *self)
+{
+ if (self->stop_hidden == OB_CLIENT_STOP_MODE_NONE)
+ return;
+
+ if (client_on_localhost(self) && self->pid) {
+ /* running on the local host */
+ if (self->stop_hidden == OB_CLIENT_STOP_MODE_PROCESS) {
+ ob_debug("client_continue_hidden is continuing process with pid %lu",
+ self->pid);
+ kill(self->pid, SIGCONT);
+ } else if (self->stop_hidden == OB_CLIENT_STOP_MODE_GROUP) {
+ ob_debug("client_continue_hidden is continuing group with pid %lu",
+ self->pid);
+ pid_t pgid = getpgid(self->pid);
+ if (pgid != -1) {
+ killpg(self->pid, SIGCONT);
+ }
+ } else {
+ ob_debug("client_continue_hidden: unknown value"
+ " of stop_hidden");
+ return;
+ }
+ }
+ else {
+ /* do nothing, running on a remote host */
+ }
+}
+
void client_hilite(ObClient *self, gboolean hilite)
{
if (self->demands_attention == hilite)
diff --git a/openbox/client.h b/openbox/client.h
index 11a014000..d574740a6 100644
--- a/openbox/client.h
+++ b/openbox/client.h
@@ -69,6 +69,14 @@ typedef enum
OB_CLIENT_FUNC_UNDECORATE = 1 << 9 /*!< Allow to be undecorated */
} ObFunctions;
+/*! The way to stop client when it hides */
+typedef enum
+{
+ OB_CLIENT_STOP_MODE_NONE, /*!< Do not stop client */
+ OB_CLIENT_STOP_MODE_PROCESS, /*!< Stop the client process only */
+ OB_CLIENT_STOP_MODE_GROUP, /*!< Stop process group the client belongs to */
+} ObClientStopMode;
+
struct _ObClient
{
ObWindow obwin;
@@ -272,6 +280,8 @@ struct _ObClient
gboolean skip_pager;
/*! The window should not be displayed by taskbars */
gboolean skip_taskbar;
+ /*! How to stop the process when it hides or iconifies */
+ ObClientStopMode stop_hidden;
/*! The window is a 'fullscreen' window, and should be on top of all
others */
gboolean fullscreen;
@@ -548,6 +558,12 @@ void client_close(ObClient *self);
/*! Kill the client off violently */
void client_kill(ObClient *self);
+/*! Stop the client process when all its windows are hidded */
+void client_stop_hidden(ObClient *self);
+
+/*! Continue executing the client process when one of its windows appears */
+void client_continue_hidden(ObClient *self);
+
/*! Sends the window to the specified desktop
@param donthide If TRUE, the window will not be shown/hidden after its
desktop has been changed. Generally this should be FALSE.
diff --git a/openbox/config.c b/openbox/config.c
index dad5d1bf9..4310906bc 100644
--- a/openbox/config.c
+++ b/openbox/config.c
@@ -123,6 +123,7 @@ ObAppSettings* config_create_app_settings(void)
settings->fullscreen = -1;
settings->max_horz = -1;
settings->max_vert = -1;
+ settings->stop_hidden = OB_CLIENT_STOP_MODE_NONE;
return settings;
}
@@ -148,6 +149,7 @@ void config_app_settings_copy_non_defaults(const ObAppSettings *src,
copy_if(fullscreen, -1);
copy_if(max_horz, -1);
copy_if(max_vert, -1);
+ copy_if(stop_hidden, OB_CLIENT_STOP_MODE_NONE);
if (src->pos_given) {
dst->pos_given = TRUE;
@@ -328,6 +330,18 @@ static void parse_single_per_app_settings(xmlNodePtr app,
if (!obt_xml_node_contains(n, "default"))
settings->fullscreen = obt_xml_node_bool(n);
+ if ((n = obt_xml_find_node(app->children, "stop_hidden")))
+ if (!obt_xml_node_contains(n, "default")) {
+ gchar *s = obt_xml_node_string(n);
+ if (!g_ascii_strcasecmp(s, "no"))
+ settings->stop_hidden = OB_CLIENT_STOP_MODE_NONE;
+ else if (!g_ascii_strcasecmp(s, "process"))
+ settings->stop_hidden = OB_CLIENT_STOP_MODE_PROCESS;
+ else if (!g_ascii_strcasecmp(s, "group"))
+ settings->stop_hidden = OB_CLIENT_STOP_MODE_GROUP;
+ g_free(s);
+ }
+
if ((n = obt_xml_find_node(app->children, "maximized"))) {
if (!obt_xml_node_contains(n, "default")) {
gchar *s = obt_xml_node_string(n);
diff --git a/openbox/config.h b/openbox/config.h
index 96a66cf1e..567e88e68 100644
--- a/openbox/config.h
+++ b/openbox/config.h
@@ -42,6 +42,7 @@ struct _ObAppSettings
GPatternSpec *group_name;
GPatternSpec *title;
ObClientType type;
+ ObClientStopMode stop_hidden;
GravityPoint position;
gboolean pos_given;
diff --git a/openbox/session.c b/openbox/session.c
index d6c6f7670..96fa066fb 100644
--- a/openbox/session.c
+++ b/openbox/session.c
@@ -603,6 +603,8 @@ static gboolean session_save_to_file(const ObSMSaveData *savedata)
fprintf(f, "\t\n");
if (c->undecorated)
fprintf(f, "\t\n");
+ if (c->stop_hidden)
+ fprintf(f, "\t\n");
if (savedata->focus_client == c)
fprintf(f, "\t\n");
fprintf(f, "\n\n");
@@ -784,6 +786,8 @@ static void session_load_file(const gchar *path)
obt_xml_find_node(node->children, "max_vert") != NULL;
state->undecorated =
obt_xml_find_node(node->children, "undecorated") != NULL;
+ state->stop_hidden =
+ obt_xml_find_node(node->children, "stop_hidden") != NULL;
state->focused =
obt_xml_find_node(node->children, "focused") != NULL;
diff --git a/openbox/session.h b/openbox/session.h
index f37e21117..a65f83974 100644
--- a/openbox/session.h
+++ b/openbox/session.h
@@ -34,7 +34,7 @@ struct _ObSessionState {
gboolean shaded, iconic, skip_pager, skip_taskbar, fullscreen;
gboolean above, below, max_horz, max_vert, undecorated;
gboolean focused;
-
+ ObClientStopMode stop_hidden;
gboolean matched;
};