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; };