Commit 67d9ec08 authored by Zander Brown's avatar Zander Brown Committed by Zander Brown
Browse files

prompt when command still running

parent 0802f09b
......@@ -35,6 +35,11 @@
<xi:include href="xml/kgx-terminal.xml"/>
<xi:include href="xml/kgx-process.xml"/>
<xi:include href="xml/kgx-search-box.xml"/>
<chapter>
<title>Confirm Close Dialog</title>
<xi:include href="xml/kgx-close-dialog.xml"/>
<xi:include href="xml/kgx-close-dialog-row.xml"/>
</chapter>
</part>
<part id="util-api">
......@@ -53,6 +58,16 @@
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
</index>
<index id="index-0.1.0">
<title>API added in 0.1.0</title>
<xi:include href="xml/api-index-0.1.0.xml"><xi:fallback /></xi:include>
</index>
<index id="index-0.2.0">
<title>API added in 0.2.0</title>
<xi:include href="xml/api-index-0.2.0.xml"><xi:fallback /></xi:include>
</index>
<index id="deprecated-api-index" role="deprecated">
<title>Index of deprecated API</title>
<xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
......
......@@ -8,7 +8,9 @@ i18n = import('i18n')
config_h = configuration_data()
config_h.set_quoted('PACKAGE_VERSION', meson.project_version())
config_h.set_quoted('GETTEXT_PACKAGE', 'kgx')
config_h.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir')))
config_h.set_quoted('LOCALEDIR',
join_paths(get_option('prefix'), get_option('localedir')))
config_h.set_quoted('RES_PATH', '/org/gnome/zbrown/KingsCross/')
config_h.set('BINDIR', join_paths(get_option('prefix'), get_option('bindir')))
if get_option('gtop')
config_h.set('HAS_GTOP', 1)
......
......@@ -175,7 +175,6 @@ watch (gpointer data)
{
KgxApplication *self = KGX_APPLICATION (data);
g_autoptr (GPtrArray) plist = NULL;
const char *exec;
plist = kgx_process_get_list ();
......@@ -185,32 +184,22 @@ watch (gpointer data)
for (int j = 0; j < plist->len; j++) {
g_autoptr (KgxProcess) parent = NULL;
KgxProcess *curr = g_ptr_array_index (plist, j);
GPid pid;
parent = kgx_process_get_parent (curr);
pid = kgx_process_get_pid (curr);
if (kgx_process_get_pid (parent) == kgx_process_get_pid (watch->process)) {
exec = kgx_process_get_exec (curr);
if (!g_ptr_array_find_with_equal_func (self->children, curr, (GEqualFunc) watch_is_for_process, NULL)) {
struct ProcessWatch *child_watch = g_new(struct ProcessWatch, 1);
child_watch->process = g_rc_box_acquire (curr);
child_watch->window = g_object_ref (watch->window);
g_debug ("Hello %s!", exec);
// g_debug ("Hello %s!", exec);
g_ptr_array_add (self->children, child_watch);
}
if (g_strcmp0 (exec, "ssh") == 0) {
kgx_window_push_remote (watch->window, pid);
}
if (kgx_process_get_is_root (curr)) {
kgx_window_push_root (watch->window, pid);
}
kgx_window_push_child (watch->window, curr);
}
}
}
......@@ -220,10 +209,7 @@ watch (gpointer data)
if (!g_ptr_array_find_with_equal_func (plist, child_watch, (GEqualFunc) process_is_watched_by, NULL)) {
g_debug ("Bye %s!", kgx_process_get_exec (child_watch->process));
kgx_window_pop_remote (child_watch->window,
kgx_process_get_pid (child_watch->process));
kgx_window_pop_root (child_watch->window,
kgx_process_get_pid (child_watch->process));
kgx_window_pop_child (child_watch->window, child_watch->process);
g_ptr_array_remove_index (self->children, i);
i--;
}
......@@ -293,7 +279,7 @@ kgx_application_startup (GApplication *app)
g_settings_bind (settings, "font-scale", app, "font-scale", G_SETTINGS_BIND_DEFAULT);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider, "/org/gnome/zbrown/KingsCross/styles.css");
gtk_css_provider_load_from_resource (provider, RES_PATH "styles.css");
gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
GTK_STYLE_PROVIDER (provider),
/* Is this stupid? Yes
......@@ -358,7 +344,7 @@ print_logo (short width)
int i = 0;
int half_screen = width / 2;
logo = g_file_new_for_uri ("resource://org/gnome/zbrown/KingsCross/logo.txt");
logo = g_file_new_for_uri ("resource:/" RES_PATH "logo.txt");
g_file_load_contents (logo, NULL, &logo_text, NULL, NULL, &error);
......
/* kgx-close-dialog-row.c
*
* Copyright 2019 Zander Brown
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* SECTION:kgx-close-dialog-row
* @title: KgxCloseDialogRow
* @short_description: A row in a #KgxCloseDialog
*
* A simple row with a #GtkLabel to represent a running process
*
* Since: 0.2.0
*/
#include <glib/gi18n.h>
#include "kgx-config.h"
#include "kgx-close-dialog-row.h"
G_DEFINE_TYPE (KgxCloseDialogRow, kgx_close_dialog_row, GTK_TYPE_LIST_BOX_ROW)
enum {
PROP_0,
PROP_COMMAND,
PROP_ICON,
LAST_PROP
};
static GParamSpec *pspecs[LAST_PROP] = { NULL, };
static void
kgx_close_dialog_row_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
KgxCloseDialogRow *self = KGX_CLOSE_DIALOG_ROW (object);
switch (property_id) {
case PROP_COMMAND:
g_clear_pointer (&self->command, g_free);
self->command = g_value_dup_string (value);
break;
case PROP_ICON:
g_clear_object (&self->icon);
self->icon = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
kgx_close_dialog_row_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
KgxCloseDialogRow *self = KGX_CLOSE_DIALOG_ROW (object);
switch (property_id) {
case PROP_COMMAND:
g_value_set_string (value, self->command);
break;
case PROP_ICON:
g_value_set_object (value, self->icon);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
kgx_close_dialog_row_finalize (GObject *object)
{
KgxCloseDialogRow *self = KGX_CLOSE_DIALOG_ROW (object);
g_clear_pointer (&self->command, g_free);
g_clear_object (&self->icon);
G_OBJECT_CLASS (kgx_close_dialog_row_parent_class)->finalize (object);
}
static void
kgx_close_dialog_row_class_init (KgxCloseDialogRowClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->set_property = kgx_close_dialog_row_set_property;
object_class->get_property = kgx_close_dialog_row_get_property;
object_class->finalize = kgx_close_dialog_row_finalize;
/**
* KgxCloseDialogRow:command:
*
* The command this row is supposed to represent, see kgx_process_get_exec()
*
* Stability: Private
*
* Since: 0.2.0
*/
pspecs[PROP_COMMAND] =
g_param_spec_string ("command", "Command", "Command row represents",
NULL,
G_PARAM_READWRITE);
/**
* KgxCloseDialogRow:icon:
*
* A #GIcon to represent the command, most of the time this will just be
* a placeholder but occasionally we might get lucky
*
* Stability: Private
*
* Since: 0.2.0
*/
pspecs[PROP_ICON] =
g_param_spec_object ("icon", "Icon", "Command app icon",
G_TYPE_ICON,
G_PARAM_READWRITE);
g_object_class_install_properties (object_class, LAST_PROP, pspecs);
gtk_widget_class_set_template_from_resource (widget_class,
RES_PATH "kgx-close-dialog-row.ui");
}
static void
kgx_close_dialog_row_init (KgxCloseDialogRow *self)
{
self->icon = g_themed_icon_new ("application-x-executable-symbolic");
gtk_widget_init_template (GTK_WIDGET (self));
}
/* kgx-close-dialog-row.h
*
* Copyright 2019 Zander Brown
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <gtk/gtk.h>
#include <vte/vte.h>
G_BEGIN_DECLS
#define KGX_TYPE_CLOSE_DIALOG_ROW (kgx_close_dialog_row_get_type())
/**
* KgxCloseDialogRow:
* @command: the kgx_process_get_exec() of the pid being represented
* @icon: the #GIcon to represent this process
*
* Stability: Private
*/
struct _KgxCloseDialogRow
{
/*< private >*/
GtkListBoxRow parent_instance;
/*< public >*/
char *command;
GIcon *icon;
};
G_DECLARE_FINAL_TYPE (KgxCloseDialogRow, kgx_close_dialog_row, KGX, CLOSE_DIALOG_ROW, GtkListBoxRow)
G_END_DECLS
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="3.20"/>
<template class="KgxCloseDialogRow" parent="GtkListBoxRow">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="activatable">False</property>
<property name="selectable">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="margin">6</property>
<property name="spacing">6</property>
<property name="valign">center</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="gicon" bind-source="KgxCloseDialogRow" bind-property="icon" bind-flags="sync-create">base-icon</property>
<property name="pixel-size">16</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" bind-source="KgxCloseDialogRow" bind-property="command" bind-flags="sync-create"/>
<property name="ellipsize">start</property>
<property name="single_line_mode">True</property>
<property name="xalign">0</property>
</object>
</child>
</object>
</child>
</template>
<object class="GThemedIcon" id="base-icon">
<property name="name">application-x-executable-symbolic</property>
</object>
</interface>
/* kgx-close-dialog.c
*
* Copyright 2019 Zander Brown
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* SECTION:kgx-close-dialog
* @title: KgxCloseDialog
* @short_description: Confirmation dialog to close a terminal with children
*
* The "are you sure?" dialog when a terminal is closed whilst commands are
* still running within it
*
* Since: 0.2.0
*/
#include <glib/gi18n.h>
#include "kgx-config.h"
#include "kgx-close-dialog.h"
#include "kgx-close-dialog-row.h"
G_DEFINE_TYPE (KgxCloseDialog, kgx_close_dialog, GTK_TYPE_DIALOG)
static void
kgx_close_dialog_class_init (KgxCloseDialogClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
gtk_widget_class_set_template_from_resource (widget_class,
RES_PATH "kgx-close-dialog.ui");
gtk_widget_class_bind_template_child (widget_class, KgxCloseDialog, list);
}
static void
separator_header (GtkListBoxRow *row,
GtkListBoxRow *before,
gpointer data)
{
GtkWidget *header;
g_return_if_fail (GTK_IS_LIST_BOX_ROW (row));
if (before == NULL) {
gtk_list_box_row_set_header (row, NULL);
return;
} else if (gtk_list_box_row_get_header (row) != NULL) {
return;
}
header = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
gtk_widget_show (header);
gtk_list_box_row_set_header (row, header);
}
static void
kgx_close_dialog_init (KgxCloseDialog *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
gtk_list_box_set_header_func (GTK_LIST_BOX (self->list),
separator_header,
NULL,
NULL);
}
/**
* kgx_close_dialog_add_command:
* @self: the #KgxCloseDialog
* @command: the command the row is for
*
* Adds a row to the #GtkListBox
*
* Since: 0.2.0
*/
void
kgx_close_dialog_add_command (KgxCloseDialog *self,
const char *command)
{
GtkWidget *row;
g_return_if_fail (KGX_IS_CLOSE_DIALOG (self));
row = g_object_new (KGX_TYPE_CLOSE_DIALOG_ROW,
"command", command,
NULL);
gtk_container_add (GTK_CONTAINER (self->list), row);
}
/* kgx-close-dialog.h
*
* Copyright 2019 Zander Brown
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <gtk/gtk.h>
#include <vte/vte.h>
G_BEGIN_DECLS
#define KGX_TYPE_CLOSE_DIALOG (kgx_close_dialog_get_type())
/**
* KgxCloseDialog:
* @list: the #GtkListBox that #KgxCloseDialogRow s are added to
*
* Stability: Private
*/
struct _KgxCloseDialog
{
/*< private >*/
GtkDialog parent_instance;
/*< public >*/
GtkWidget *list;
};
G_DECLARE_FINAL_TYPE (KgxCloseDialog, kgx_close_dialog, KGX, CLOSE_DIALOG, GtkDialog)
void kgx_close_dialog_add_command (KgxCloseDialog *self,
const char *command);
G_END_DECLS
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="3.20"/>
<template class="KgxCloseDialog" parent="GtkDialog">
<property name="border-width">0</property>
<property name="title" translatable="yes">Close Terminal</property>
<property name="modal">True</property>
<property name="use-header-bar">1</property>
<property name="type-hint">dialog</property>
<property name="default-width">400</property>
<child internal-child="vbox">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="width-request">300</property>
<property name="visible">True</property>
<property name="halign">center</property>
<property name="margin">12</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Some commands are still running, cosing this terminal will kill them and may lead to unexpected outcomes</property>
<property name="wrap">True</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkListBox" id="list">
<property name="visible">True</property>
<property name="selection-mode">none</property>
<property name="activate-on-single-click">False</property>
<style>
<class name="frame"/>
</style>
<child type="placeholder">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">No children</property>
<property name="margin">12</property>
<property name="xalign">0</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child type="action">
<object class="GtkButton" id="button-cancel">
<property name="label" translatable="yes">_Cancel</property>
<property name="visible">True</property>
<property name="can-default">True</property>
<property name="use-underline">True</property>
</object>
</child>
<child type="action">
<object class="GtkButton" id="button-ok">
<property name="label" translatable="yes">_Okay</property>
<property name="visible">True</property>
<property name="use-underline">True</property>
<style>
<class name="destructive-action"/>
</style>
</object>
</child>
<action-widgets>
<action-widget response="cancel" default="true">button-cancel</action-widget>
<action-widget response="ok">button-ok</action-widget>
</action-widgets>
</template>
</interface>
......@@ -53,6 +53,10 @@ clear_process (KgxProcess *self)
* Reduce the refrence count of @self, possibly freeing @self
*
* See g_rc_box_acquire() and g_rc_box_release_full()
*
* Since: 0.1.0
*
* Stability: Private
*/
void
kgx_process_unref (KgxProcess *self)
......@@ -69,8 +73,12 @@ G_DEFINE_BOXED_TYPE (KgxProcess, kgx_process, g_rc_box_acquire, kgx_process_unre
* @pid: The #GPid to get info about
*
* Populate a new #KgxProcess with details about the process @pid
*
* Since: 0.1.0
*
* Stability: Private
*/
KgxProcess *
inline KgxProcess *
kgx_process_new (GPid pid)
{
glibtop_proc_uid info;
......@@ -99,8 +107,12 @@ kgx_process_new (GPid pid)
* @self: the #KgxProcess
*
* Returns: The process id
*
* Since: 0.1.0
*
* Stability: Private
*/
GPid
inline GPid
kgx_process_get_pid (KgxProcess *self)
{
g_return_val_if_fail (self != NULL, 0);
......@@ -113,8 +125,12 @@ kgx_process_get_pid (KgxProcess *self)
* @self: the #KgxProcess
*
* Returns: The user id of the process
*
* Since: 0.1.0
*
* Stability: Private