Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
apt install -y libgala-dev libgee-0.8-dev libglib2.0-dev libgranite-7-dev libgtk-4-dev libadwaita-1-dev \
libdbus-glib-1-dev libgtop2-dev libwingpanel-9-dev libudisks2-dev \
libxnvctrl0 libxnvctrl-dev libcurl4-gnutls-dev libflatpak-dev libjson-glib-dev \
liblivechart-2-dev libpci-dev \
liblivechart-2-dev libsystemd-dev libpci-dev \
meson valac sassc git
- name: Build
run: |
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@
If you plan to install WITH a wingpanel-indicator

```bash
sudo apt install sassc valac libgtk-4-dev libgee-0.8-dev libgranite-7-dev libgtop2-dev libadwaita-1-dev libudisks2-dev libjson-glib-dev libflatpak-dev libxnvctrl-dev liblivechart-2-dev libpci-dev libwingpanel-9-dev meson
sudo apt install sassc valac libgtk-4-dev libgee-0.8-dev libgranite-7-dev libgtop2-dev libadwaita-1-dev libudisks2-dev libjson-glib-dev libflatpak-dev libsystemd-dev libxnvctrl-dev liblivechart-2-dev libpci-dev libwingpanel-9-dev meson
```

Alternatively, if you plan to install WITHOUT a wingpanel-indicator

```bash
sudo apt install sassc valac libgtk-4-dev libgee-0.8-dev libgranite-7-dev libgtop2-dev libadwaita-1-dev libudisks2-dev libjson-glib-dev libflatpak-dev libxnvctrl-dev liblivechart-2-dev libpci-dev meson
sudo apt install sassc valac libgtk-4-dev libgee-0.8-dev libgranite-7-dev libgtop2-dev libadwaita-1-dev libudisks2-dev libjson-glib-dev libflatpak-dev libsystemd-dev libxnvctrl-dev liblivechart-2-dev libpci-dev meson
```


Expand Down
10 changes: 10 additions & 0 deletions data/stylesheet/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,13 @@ header.small-label {
}
}
}

columnview {
cell {
padding: 0.5em;
}

row:nth-child(odd) {
background: #{'@bg_color'};
}
}
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ app_dependencies = [
dependency('gobject-2.0'),
dependency('libgtop-2.0'),
dependency('libadwaita-1', version: '>=1.0.0'),
dependency('libsystemd'),
dependency('gtk4-x11'),
dependency('udisks2'),
dependency('json-glib-1.0'),
Expand Down
4 changes: 4 additions & 0 deletions po/POTFILES
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ src/MainWindow.vala
src/Utils.vala
src/Indicator/Widgets/IndicatorWidgetFrequency.vala
src/Indicator/Widgets/PopoverWidget.vala
src/views/LogView/LogCell.vala
src/views/LogView/LogView.vala
src/views/LogView/SystemdLogEntry.vala
src/views/LogView/SystemdLogModel.vala
src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala
src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala
src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala
Expand Down
7 changes: 5 additions & 2 deletions src/MainWindow.vala
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ public class Monitor.MainWindow : Gtk.ApplicationWindow {
var resources = new Resources ();

process_view = new ProcessView ();
var log_view = new LogView ();
var system_view = new SystemView (resources);

var stack = new Gtk.Stack () {
transition_type = SLIDE_LEFT_RIGHT
};
stack.add_titled (process_view, "process_view", _("Processes"));
stack.add_titled (log_view, "log_view", _("Logs"));
stack.add_titled (system_view, "system_view", _("System"));

var stack_switcher = new Gtk.StackSwitcher () {
Expand Down Expand Up @@ -90,10 +92,10 @@ public class Monitor.MainWindow : Gtk.ApplicationWindow {

var dbusserver = DBusServer.get_default ();

search_revealer.reveal_child = stack.visible_child == process_view;
search_revealer.reveal_child = stack.visible_child != system_view;
stack.notify["visible-child"].connect (() => {
toolbox.reveal_bottom_bars = stack.visible_child == process_view;
search_revealer.reveal_child = stack.visible_child == process_view;
search_revealer.reveal_child = stack.visible_child != system_view;
});

new Thread<void> ("upd", () => {
Expand All @@ -118,6 +120,7 @@ public class Monitor.MainWindow : Gtk.ApplicationWindow {

search_entry.search_changed.connect (() => {
process_view.treeview_model.filtered.needle = search_entry.text;
log_view.on_search_changed (search_entry.text);
search_entry.grab_focus ();
});

Expand Down
47 changes: 47 additions & 0 deletions src/Views/LogView/LogCell.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* SPDX-License-Identifier: GPL-3.0-or-later
* SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
*/

public class Monitor.LogCell : Granite.Bin {
public enum CellType {
ORIGIN,
MESSAGE
}

public CellType cell_type { get; construct; }

private Gtk.Label label;

public LogCell (CellType cell_type) {
Object (cell_type: cell_type);
}

construct {
label = new Gtk.Label (null);

switch (cell_type) {
case ORIGIN:
label.add_css_class (Granite.CssClass.DIM);
label.width_chars = 15;
label.xalign = 1;
break;
case MESSAGE:
label.halign = START;
break;
}

child = label;
}

public void bind (SystemdLogEntry entry) {
switch (cell_type) {
case ORIGIN:
label.label = entry.origin;
break;
case MESSAGE:
label.label = entry.message;
break;
}
}
}
125 changes: 125 additions & 0 deletions src/Views/LogView/LogView.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* SPDX-License-Identifier: GPL-3.0-or-later
* SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
*/

public class Monitor.LogView : Granite.Bin {
private SystemdLogModel model;
private Gtk.ProgressBar refresh_progress;
private Gtk.Revealer refresh_revealer;
private uint refresh_timeout = -1;

construct {
refresh_progress = new Gtk.ProgressBar ();

refresh_revealer = new Gtk.Revealer () {
child = refresh_progress
};

model = new SystemdLogModel ();

var selection_model = new Gtk.NoSelection (model);

var header_factory = new Gtk.SignalListItemFactory ();
header_factory.setup.connect (setup_header);
header_factory.bind.connect (bind_header);

var origin_factory = new Gtk.SignalListItemFactory ();
origin_factory.setup.connect (setup_origin);
origin_factory.bind.connect (bind);

var origin_column = new Gtk.ColumnViewColumn (_("Sender"), origin_factory);

var message_factory = new Gtk.SignalListItemFactory ();
message_factory.setup.connect (setup_message);
message_factory.bind.connect (bind);

var message_column = new Gtk.ColumnViewColumn (_("Message"), message_factory) {
expand = true
};

var column_view = new Gtk.ColumnView (selection_model) {
header_factory = header_factory,
reorderable = false,
vexpand = true
};
column_view.append_column (origin_column);
column_view.append_column (message_column);

var scrolled = new Gtk.ScrolledWindow () {
child = column_view
};

var box = new Granite.Box (VERTICAL, NONE);
box.append (refresh_revealer);
box.append (scrolled);

child = box;

scrolled.edge_reached.connect (on_edge_reached);
scrolled.edge_overshot.connect (on_edge_overshot);
}

private void setup_header (Object obj) {
var item = (Gtk.ListHeader) obj;
item.child = new Granite.HeaderLabel ("");
}

private void bind_header (Object obj) {
var item = (Gtk.ListHeader) obj;
var entry = (SystemdLogEntry) item.item;
var label = (Granite.HeaderLabel) item.child;
label.label = entry.relative_time;
}

private void setup_origin (Object obj) {
var item = (Gtk.ListItem) obj;
item.child = new LogCell (ORIGIN);
}

private void setup_message (Object obj) {
var item = (Gtk.ListItem) obj;
item.child = new LogCell (MESSAGE);
}

private void bind (Object obj) {
var item = (Gtk.ListItem) obj;
var entry = (SystemdLogEntry) item.item;
var cell = (LogCell) item.child;
cell.bind (entry);
}

public void on_search_changed (string needle) {
model.search (needle);
}

private void on_edge_reached (Gtk.PositionType pos) {
if (pos == BOTTOM) {
model.load_chunk ();
}
}

private void on_edge_overshot (Gtk.PositionType pos) {
if (pos == TOP) {
if (refresh_timeout == -1) {
refresh_timeout = Timeout.add_once (200, () => {
reset_refresh_progress ();
});
}

refresh_revealer.reveal_child = true;
refresh_progress.fraction += 0.25;

if (refresh_progress.fraction >= 1) {
model.refresh ();
reset_refresh_progress ();
}
}
}

private void reset_refresh_progress () {
refresh_revealer.reveal_child = false;
refresh_progress.fraction = 0;
refresh_timeout = -1;
}
}
46 changes: 46 additions & 0 deletions src/Views/LogView/SystemdLogEntry.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* SPDX-License-Identifier: GPL-3.0-or-later
* SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
*/

public class Monitor.SystemdLogEntry : GLib.Object {
public string origin { get; construct; }
public string message { get; construct; }
public DateTime dt { get; construct; }
public string relative_time { get; construct; }

public uint section_start { get; set; }

public SystemdLogEntry (string origin, string message, DateTime time) {
Object (
origin: origin, message: message, dt: time,
relative_time: format_time (time)
);
}

public bool matches (string term) {
return origin.contains (term) || message.contains (term);
}

private static string format_time (DateTime time) {
var diff = SystemdLogModel.get_stable_now ().difference (time);
if (diff < TimeSpan.SECOND) {
return _("Now");
} else if (diff < TimeSpan.MINUTE) {
var seconds = diff / TimeSpan.SECOND;
return dngettext (GETTEXT_PACKAGE, "%ds ago", "%ds ago", (ulong) seconds).printf ((int) seconds);
} else if (diff < TimeSpan.HOUR) {
var minutes = diff / TimeSpan.MINUTE;
var seconds = (diff - minutes * TimeSpan.MINUTE) / TimeSpan.SECOND;

if (seconds == 0) {
return dngettext (GETTEXT_PACKAGE, "%dm ago", "%dm ago", (ulong) minutes).printf ((int) minutes);
}

// I think the plural form is according to the last one??
return dngettext (GETTEXT_PACKAGE, "%dm %ds ago", "%dm %ds ago", (ulong) seconds).printf ((int) minutes, (int) seconds);
}

return time.format (Granite.DateTime.get_default_time_format ());
}
}
Loading
Loading