begin of upt-gui: processes tree view
Stefan Schuermans

Stefan Schuermans commited on 2020-05-23 20:45:22
Showing 5 changed files, with 261 additions and 0 deletions.

... ...
@@ -1 +1,3 @@
1 1
 /build/
2
+*~
3
+.*.swp
... ...
@@ -24,6 +24,7 @@ add_custom_target(
24 24
 add_subdirectory(libuptev)
25 25
 add_subdirectory(libuptpl)
26 26
 add_subdirectory(python3)
27
+add_subdirectory(upt-gui)
27 28
 add_subdirectory(upt-tool)
28 29
 add_subdirectory(upt-trace)
29 30
 add_subdirectory(tests)
... ...
@@ -0,0 +1,27 @@
1
+add_custom_command(
2
+  OUTPUT
3
+  ${CMAKE_CURRENT_BINARY_DIR}/upt-gui.glade
4
+  DEPENDS
5
+  ${CMAKE_CURRENT_SOURCE_DIR}/upt-gui.glade
6
+  COMMAND
7
+  cp -a ${CMAKE_CURRENT_SOURCE_DIR}/upt-gui.glade
8
+        ${CMAKE_CURRENT_BINARY_DIR}/upt-gui.glade
9
+)
10
+
11
+add_custom_command(
12
+  OUTPUT
13
+  ${CMAKE_CURRENT_BINARY_DIR}/upt-gui.py
14
+  DEPENDS
15
+  ${CMAKE_CURRENT_SOURCE_DIR}/upt-gui.py
16
+  COMMAND
17
+  cp -a ${CMAKE_CURRENT_SOURCE_DIR}/upt-gui.py
18
+        ${CMAKE_CURRENT_BINARY_DIR}/upt-gui.py
19
+)
20
+
21
+add_custom_target(
22
+  upt-gui
23
+  ALL
24
+  DEPENDS
25
+  ${CMAKE_CURRENT_BINARY_DIR}/upt-gui.glade
26
+  ${CMAKE_CURRENT_BINARY_DIR}/upt-gui.py
27
+)
... ...
@@ -0,0 +1,126 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!-- Generated with glade 3.22.1 -->
3
+<interface>
4
+  <requires lib="gtk+" version="3.20"/>
5
+  <object class="GtkTreeStore" id="ProcessesTree">
6
+    <columns>
7
+      <!-- column-name proc_id -->
8
+      <column type="gint"/>
9
+      <!-- column-name begin_timestamp -->
10
+      <column type="gchararray"/>
11
+      <!-- column-name end_timestamp -->
12
+      <column type="gchararray"/>
13
+      <!-- column-name cmdline -->
14
+      <column type="gchararray"/>
15
+    </columns>
16
+  </object>
17
+  <object class="GtkWindow" id="Application">
18
+    <property name="visible">True</property>
19
+    <property name="can_focus">False</property>
20
+    <signal name="destroy" handler="onDestroy" swapped="no"/>
21
+    <child>
22
+      <placeholder/>
23
+    </child>
24
+    <child>
25
+      <object class="GtkBox" id="TopVBox">
26
+        <property name="visible">True</property>
27
+        <property name="can_focus">False</property>
28
+        <property name="orientation">vertical</property>
29
+        <child>
30
+          <object class="GtkBox" id="TopHBox">
31
+            <property name="visible">True</property>
32
+            <property name="can_focus">False</property>
33
+            <child>
34
+              <object class="GtkScrolledWindow" id="ProcessesScoll">
35
+                <property name="width_request">256</property>
36
+                <property name="height_request">256</property>
37
+                <property name="visible">True</property>
38
+                <property name="can_focus">True</property>
39
+                <property name="shadow_type">in</property>
40
+                <child>
41
+                  <object class="GtkTreeView" id="ProcessesView">
42
+                    <property name="visible">True</property>
43
+                    <property name="can_focus">True</property>
44
+                    <property name="model">ProcessesTree</property>
45
+                    <property name="reorderable">True</property>
46
+                    <property name="rules_hint">True</property>
47
+                    <property name="search_column">0</property>
48
+                    <property name="fixed_height_mode">True</property>
49
+                    <property name="enable_tree_lines">True</property>
50
+                    <child internal-child="selection">
51
+                      <object class="GtkTreeSelection"/>
52
+                    </child>
53
+                    <child>
54
+                      <object class="GtkTreeViewColumn" id="Begin">
55
+                        <property name="resizable">True</property>
56
+                        <property name="sizing">fixed</property>
57
+                        <property name="title" translatable="yes">Begin</property>
58
+                        <property name="clickable">True</property>
59
+                        <property name="reorderable">True</property>
60
+                        <property name="sort_indicator">True</property>
61
+                        <property name="sort_column_id">0</property>
62
+                        <child>
63
+                          <object class="GtkCellRendererText" id="BeginText"/>
64
+                          <attributes>
65
+                            <attribute name="text">1</attribute>
66
+                          </attributes>
67
+                        </child>
68
+                      </object>
69
+                    </child>
70
+                    <child>
71
+                      <object class="GtkTreeViewColumn" id="End">
72
+                        <property name="resizable">True</property>
73
+                        <property name="sizing">fixed</property>
74
+                        <property name="title" translatable="yes">End</property>
75
+                        <property name="clickable">True</property>
76
+                        <property name="reorderable">True</property>
77
+                        <property name="sort_indicator">True</property>
78
+                        <property name="sort_column_id">1</property>
79
+                        <child>
80
+                          <object class="GtkCellRendererText" id="EndText"/>
81
+                          <attributes>
82
+                            <attribute name="text">2</attribute>
83
+                          </attributes>
84
+                        </child>
85
+                      </object>
86
+                    </child>
87
+                    <child>
88
+                      <object class="GtkTreeViewColumn" id="Command">
89
+                        <property name="resizable">True</property>
90
+                        <property name="sizing">fixed</property>
91
+                        <property name="title" translatable="yes">Command</property>
92
+                        <property name="clickable">True</property>
93
+                        <property name="reorderable">True</property>
94
+                        <property name="sort_indicator">True</property>
95
+                        <property name="sort_column_id">2</property>
96
+                        <child>
97
+                          <object class="GtkCellRendererText" id="CommandText"/>
98
+                          <attributes>
99
+                            <attribute name="text">3</attribute>
100
+                          </attributes>
101
+                        </child>
102
+                      </object>
103
+                    </child>
104
+                  </object>
105
+                </child>
106
+              </object>
107
+              <packing>
108
+                <property name="expand">True</property>
109
+                <property name="fill">True</property>
110
+                <property name="position">0</property>
111
+              </packing>
112
+            </child>
113
+            <child>
114
+              <placeholder/>
115
+            </child>
116
+          </object>
117
+          <packing>
118
+            <property name="expand">True</property>
119
+            <property name="fill">True</property>
120
+            <property name="position">0</property>
121
+          </packing>
122
+        </child>
123
+      </object>
124
+    </child>
125
+  </object>
126
+</interface>
... ...
@@ -0,0 +1,105 @@
1
+#! /usr/bin/env python3
2
+
3
+import cairo
4
+import datetime
5
+import gi
6
+import os
7
+import shlex
8
+import sys
9
+import time
10
+gi.require_version('Gdk', '3.0')
11
+gi.require_version('Gtk', '3.0')
12
+from gi.repository import Gdk
13
+from gi.repository import GLib
14
+from gi.repository import Gtk
15
+
16
+import uproctrace.processes
17
+
18
+
19
+def cmdline2str(cmdline: list) -> str:
20
+    """
21
+    Convert command line to string.
22
+    """
23
+    if cmdline is None:
24
+        return "???"
25
+    return ' '.join([shlex.quote(s) for s in cmdline])
26
+
27
+def timestamp2str(timestamp: float) -> str:
28
+    """
29
+    Convert a timestamp to a human-reable time string."
30
+    """
31
+    if timestamp is None:
32
+        return "???"
33
+    sec = int(timestamp)
34
+    nsec = int((timestamp - sec) * 1e9)
35
+    time_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(sec))
36
+    return time_str + f'.{nsec:09d}'
37
+
38
+
39
+class UptGui:
40
+    def __init__(self, proto_filename):
41
+        """
42
+        Construct the GUI.
43
+        """
44
+        self.builder = Gtk.Builder()
45
+        script_dir = os.path.dirname(os.path.abspath(__file__))
46
+        self.builder.add_from_file(os.path.join(script_dir, 'upt-gui.glade'))
47
+        self.widProcessesTree = self.builder.get_object('ProcessesTree')
48
+        self.widProcessesView = self.builder.get_object('ProcessesView')
49
+        handlers = {'onDestroy': self.onDestroy}
50
+        self.builder.connect_signals(handlers)
51
+        # open trace file
52
+        self.openTrace(proto_filename)
53
+
54
+    def onDestroy(self, widget):
55
+        """
56
+        Window will be destroyed.
57
+        """
58
+        Gtk.main_quit()
59
+
60
+    def openTrace(self, proto_filename: str):
61
+        """
62
+        Open a trace file.
63
+        """
64
+        # forget old data
65
+        self.widProcessesTree.clear()
66
+        # lead new data
67
+        with open(proto_filename, 'rb') as proto_file:
68
+            self._processes = uproctrace.processes.Processes(proto_file)
69
+        # add processes to processes tree store
70
+        to_be_output = [(self._processes.toplevel, None)]
71
+        while to_be_output:
72
+            procs, parent_iter = to_be_output[-1]
73
+            if not procs:
74
+                del to_be_output[-1]
75
+                continue
76
+            proc = procs[0]
77
+            del procs[0]
78
+            proc_iter = self.widProcessesTree.append(parent_iter)
79
+            self.widProcessesTree.set_value(proc_iter, 0, proc.proc_id)
80
+            self.widProcessesTree.set_value(proc_iter, 1, timestamp2str(proc.begin_timestamp))
81
+            self.widProcessesTree.set_value(proc_iter, 2, timestamp2str(proc.end_timestamp))
82
+            self.widProcessesTree.set_value(proc_iter, 3, cmdline2str(proc.cmdline))
83
+            to_be_output.append((proc.children, proc_iter))
84
+        # show all processes
85
+        self.widProcessesView.expand_all()
86
+
87
+
88
+def main(argv):
89
+    """
90
+    Main program.
91
+    """
92
+    if len(argv) < 2:
93
+        print('usage: ' + argv[0] + ' <trace.proto>', file=sys.stderr)
94
+        return 2
95
+    proto_filename = argv[1]
96
+    app = UptGui(proto_filename)
97
+    try:
98
+        Gtk.main()
99
+    except KeyboardInterrupt:
100
+        pass
101
+    return 0
102
+
103
+
104
+if __name__ == '__main__':
105
+    sys.exit(main(sys.argv))
0 106