├── .editorconfig ├── .github └── workflows │ ├── ci.yml │ ├── gettext.yml │ └── release.yml ├── .gitignore ├── .valalintignore ├── AUTHORS ├── LICENSE ├── README.md ├── data ├── css.gresource.xml ├── database │ ├── README.md │ ├── cpu_bugs.csv │ └── cpu_features.csv ├── icons │ ├── 16 │ │ └── io.elementary.monitor.svg │ ├── 24 │ │ └── io.elementary.monitor.svg │ ├── 32 │ │ └── io.elementary.monitor.svg │ ├── 48 │ │ └── io.elementary.monitor.svg │ ├── 64 │ │ └── io.elementary.monitor.svg │ ├── 128 │ │ └── io.elementary.monitor.svg │ ├── cpu-symbolic.svg │ ├── extra │ │ ├── 16 │ │ │ ├── bash.svg │ │ │ └── docker.svg │ │ ├── 48 │ │ │ ├── bash.svg │ │ │ └── docker.svg │ │ └── 64 │ │ │ ├── bash.svg │ │ │ └── docker.svg │ ├── file-deleted-symbolic.svg │ ├── gpu-symbolic.svg │ ├── gpu-vram-symbolic.svg │ ├── icons.indicator.gresource.xml │ ├── ram-symbolic.svg │ ├── swap-symbolic.svg │ ├── temperature-gpu-symbolic.svg │ └── temperature-sensor-symbolic.svg ├── io.elementary.monitor.appdata.xml.in ├── io.elementary.monitor.gschema.xml ├── meson.build ├── monitor.desktop.in ├── screenshots │ ├── monitor-containers.png │ ├── monitor-processes.png │ └── monitor-system.png └── stylesheet │ ├── _index.scss │ ├── _palette.scss │ ├── monitor-dark.scss │ ├── monitor-light.scss │ └── monitor-retrofit.scss ├── design ├── GfknBzs.jpg ├── application_manager_by_nicekiwi-d698q3a.png ├── brainstorm ├── task_manager_by_mashnoon33-d7x4s3f.png └── tasku.png ├── meson.build ├── meson ├── bump_version.py ├── get_cpu_features_and_bugs.py ├── list-app-src.sh └── post_install.py ├── meson_options.txt ├── po ├── LINGUAS ├── POTFILES ├── aa.po ├── ab.po ├── ace.po ├── ae.po ├── af.po ├── ak.po ├── am.po ├── an.po ├── ar.po ├── as.po ├── ast.po ├── av.po ├── ay.po ├── az.po ├── ba.po ├── be.po ├── bg.po ├── bh.po ├── bi.po ├── bm.po ├── bn.po ├── bo.po ├── br.po ├── bs.po ├── ca.po ├── ca@valencia.po ├── ce.po ├── ch.po ├── ckb.po ├── co.po ├── cr.po ├── cs.po ├── cu.po ├── cv.po ├── cy.po ├── da.po ├── de.po ├── dv.po ├── dz.po ├── ee.po ├── el.po ├── en_AU.po ├── en_CA.po ├── en_GB.po ├── en_ZA.po ├── eo.po ├── es.po ├── et.po ├── eu.po ├── extra │ ├── LINGUAS │ ├── POTFILES │ ├── aa.po │ ├── ab.po │ ├── ace.po │ ├── ae.po │ ├── af.po │ ├── ak.po │ ├── am.po │ ├── an.po │ ├── ar.po │ ├── as.po │ ├── ast.po │ ├── av.po │ ├── ay.po │ ├── az.po │ ├── ba.po │ ├── be.po │ ├── bg.po │ ├── bh.po │ ├── bi.po │ ├── bm.po │ ├── bn.po │ ├── bo.po │ ├── br.po │ ├── bs.po │ ├── ca.po │ ├── ca@valencia.po │ ├── ce.po │ ├── ch.po │ ├── ckb.po │ ├── co.po │ ├── cr.po │ ├── cs.po │ ├── cu.po │ ├── cv.po │ ├── cy.po │ ├── da.po │ ├── de.po │ ├── dv.po │ ├── dz.po │ ├── ee.po │ ├── el.po │ ├── en_AU.po │ ├── en_CA.po │ ├── en_GB.po │ ├── en_ZA.po │ ├── eo.po │ ├── es.po │ ├── et.po │ ├── eu.po │ ├── extra.pot │ ├── fa.po │ ├── ff.po │ ├── fi.po │ ├── fil.po │ ├── fj.po │ ├── fo.po │ ├── fr.po │ ├── fr_CA.po │ ├── frp.po │ ├── fy.po │ ├── ga.po │ ├── gd.po │ ├── gl.po │ ├── gn.po │ ├── gu.po │ ├── gv.po │ ├── ha.po │ ├── he.po │ ├── hi.po │ ├── ho.po │ ├── hr.po │ ├── ht.po │ ├── hu.po │ ├── hy.po │ ├── hz.po │ ├── ia.po │ ├── id.po │ ├── id_ID.po │ ├── ie.po │ ├── ig.po │ ├── ii.po │ ├── ik.po │ ├── io.po │ ├── is.po │ ├── it.po │ ├── iu.po │ ├── ja.po │ ├── jv.po │ ├── ka.po │ ├── kg.po │ ├── ki.po │ ├── kj.po │ ├── kk.po │ ├── kl.po │ ├── km.po │ ├── kn.po │ ├── ko.po │ ├── kr.po │ ├── ks.po │ ├── ku.po │ ├── kv.po │ ├── kw.po │ ├── ky.po │ ├── la.po │ ├── lb.po │ ├── lg.po │ ├── li.po │ ├── ln.po │ ├── lo.po │ ├── lt.po │ ├── lu.po │ ├── lv.po │ ├── meson.build │ ├── mg.po │ ├── mh.po │ ├── mi.po │ ├── mk.po │ ├── ml.po │ ├── mn.po │ ├── mo.po │ ├── mr.po │ ├── ms.po │ ├── mt.po │ ├── my.po │ ├── na.po │ ├── nb.po │ ├── nd.po │ ├── ne.po │ ├── ng.po │ ├── nl.po │ ├── nn.po │ ├── no.po │ ├── nr.po │ ├── nv.po │ ├── ny.po │ ├── oc.po │ ├── oj.po │ ├── om.po │ ├── or.po │ ├── os.po │ ├── pa.po │ ├── pap.po │ ├── pi.po │ ├── pl.po │ ├── ps.po │ ├── pt.po │ ├── pt_BR.po │ ├── qu.po │ ├── rm.po │ ├── rn.po │ ├── ro.po │ ├── ru.po │ ├── rue.po │ ├── rw.po │ ├── sa.po │ ├── sc.po │ ├── sco.po │ ├── sd.po │ ├── se.po │ ├── sg.po │ ├── si.po │ ├── sk.po │ ├── sl.po │ ├── sm.po │ ├── sma.po │ ├── sn.po │ ├── so.po │ ├── sq.po │ ├── sr.po │ ├── sr@latin.po │ ├── ss.po │ ├── st.po │ ├── su.po │ ├── sv.po │ ├── sw.po │ ├── szl.po │ ├── ta.po │ ├── te.po │ ├── tg.po │ ├── th.po │ ├── ti.po │ ├── tk.po │ ├── tl.po │ ├── tn.po │ ├── to.po │ ├── tr.po │ ├── ts.po │ ├── tt.po │ ├── tw.po │ ├── ty.po │ ├── ug.po │ ├── uk.po │ ├── ur.po │ ├── uz.po │ ├── ve.po │ ├── vi.po │ ├── vo.po │ ├── wa.po │ ├── wo.po │ ├── xh.po │ ├── yi.po │ ├── yo.po │ ├── za.po │ ├── zh.po │ ├── zh_HK.po │ ├── zh_Hans.po │ ├── zh_Hant.po │ └── zu.po ├── fa.po ├── ff.po ├── fi.po ├── fil.po ├── fj.po ├── fo.po ├── fr.po ├── fr_CA.po ├── frp.po ├── fy.po ├── ga.po ├── gd.po ├── gl.po ├── gn.po ├── gu.po ├── gv.po ├── ha.po ├── he.po ├── hi.po ├── ho.po ├── hr.po ├── ht.po ├── hu.po ├── hy.po ├── hz.po ├── ia.po ├── id.po ├── id_ID.po ├── ie.po ├── ig.po ├── ii.po ├── ik.po ├── io.elementary.monitor.pot ├── io.po ├── is.po ├── it.po ├── iu.po ├── ja.po ├── jv.po ├── ka.po ├── kg.po ├── ki.po ├── kj.po ├── kk.po ├── kl.po ├── km.po ├── kn.po ├── ko.po ├── kr.po ├── ks.po ├── ku.po ├── kv.po ├── kw.po ├── ky.po ├── la.po ├── lb.po ├── lg.po ├── li.po ├── ln.po ├── lo.po ├── lt.po ├── lu.po ├── lv.po ├── meson.build ├── mg.po ├── mh.po ├── mi.po ├── mk.po ├── ml.po ├── mn.po ├── mo.po ├── mr.po ├── ms.po ├── mt.po ├── my.po ├── na.po ├── nb.po ├── nd.po ├── ne.po ├── ng.po ├── nl.po ├── nn.po ├── no.po ├── nr.po ├── nv.po ├── ny.po ├── oc.po ├── oj.po ├── om.po ├── or.po ├── os.po ├── pa.po ├── pap.po ├── pi.po ├── pl.po ├── ps.po ├── pt.po ├── pt_BR.po ├── qu.po ├── rm.po ├── rn.po ├── ro.po ├── ru.po ├── rue.po ├── rw.po ├── sa.po ├── sc.po ├── sco.po ├── sd.po ├── se.po ├── sg.po ├── si.po ├── sk.po ├── sl.po ├── sm.po ├── sma.po ├── sn.po ├── so.po ├── sq.po ├── sr.po ├── sr@latin.po ├── ss.po ├── st.po ├── su.po ├── sv.po ├── sw.po ├── szl.po ├── ta.po ├── te.po ├── tg.po ├── th.po ├── ti.po ├── tk.po ├── tl.po ├── tn.po ├── to.po ├── tr.po ├── ts.po ├── tt.po ├── tw.po ├── ty.po ├── ug.po ├── uk.po ├── ur.po ├── uz.po ├── ve.po ├── vi.po ├── vo.po ├── wa.po ├── wo.po ├── xh.po ├── yi.po ├── yo.po ├── za.po ├── zh.po ├── zh_HK.po ├── zh_Hans.po ├── zh_Hant.po └── zu.po ├── src ├── Conf.vala.in ├── Indicator │ ├── Indicator.vala │ ├── Services │ │ └── DBusClient.vala │ ├── Widgets │ │ ├── DisplayWidget.vala │ │ ├── IndicatorWidget.vala │ │ └── PopoverWidget.vala │ └── meson.build ├── MainWindow.vala ├── Managers │ ├── AppManager.vala │ ├── Process.vala │ ├── ProcessManager.vala │ ├── ProcessStructs.vala │ └── ProcessUtils.vala ├── Models │ ├── OpenFilesTreeViewModel.vala │ └── TreeViewModel.vala ├── Monitor.vala ├── PCIUtils.vala ├── Resources │ ├── CPU.vala │ ├── CPUCache.vala │ ├── Cgroup │ │ ├── Cgroup.vala │ │ └── CgroupStructs.vala │ ├── Core.vala │ ├── Drive.vala │ ├── GPU │ │ ├── GPUAmd.vala │ │ ├── GPUIntel.vala │ │ ├── GPUNvidia.vala │ │ └── IGPU.vala │ ├── Hwmon │ │ ├── HwmonFan.vala │ │ ├── HwmonFrequency.vala │ │ ├── HwmonPWM.vala │ │ ├── HwmonPathsParser.vala │ │ ├── HwmonPathsParserCPU.vala │ │ ├── HwmonPathsParserGPU.vala │ │ ├── HwmonPathsParserIwlwifi.vala │ │ ├── HwmonPathsParserNVMe.vala │ │ ├── HwmonPower.vala │ │ ├── HwmonTemperature.vala │ │ ├── HwmonVoltage.vala │ │ └── IHwmonPathsParserInterface.vala │ ├── Memory.vala │ ├── Network.vala │ ├── Resources.vala │ ├── ResourcesSerialized.vala │ ├── Storage │ │ ├── Disk.vala │ │ ├── Storage.vala │ │ ├── StorageBlock.vala │ │ ├── StorageParser.vala │ │ └── Volume.vala │ └── Swap.vala ├── Services │ ├── Appearance.vala │ └── DBusServer.vala ├── Utils.vala ├── Views │ ├── PreferencesView.vala │ ├── ProcessView │ │ ├── ProcessInfoView │ │ │ ├── OpenFilesTreeView.vala │ │ │ ├── Preventor.vala │ │ │ ├── ProcessInfoCPURAM.vala │ │ │ ├── ProcessInfoHeader.vala │ │ │ ├── ProcessInfoIOStats.vala │ │ │ └── ProcessInfoView.vala │ │ ├── ProcessTreeView │ │ │ └── CPUProcessTreeView.vala │ │ └── ProcessView.vala │ └── SystemView │ │ ├── SystemCPUInfoPopover.vala │ │ ├── SystemCPUView.vala │ │ ├── SystemGPUView.vala │ │ ├── SystemMemoryView.vala │ │ ├── SystemNetworkView.vala │ │ ├── SystemStorageView.vala │ │ └── SystemView.vala ├── Widgets │ ├── Chart │ │ └── Chart.vala │ ├── Headerbar │ │ └── Search.vala │ ├── Labels │ │ ├── LabelRoundy.vala │ │ └── LabelVertical.vala │ ├── Statusbar │ │ └── Statusbar.vala │ └── WidgetResource │ │ └── WidgetResource.vala └── meson.build ├── subprojects └── live-chart.wrap ├── tests ├── list-src.sh ├── meson.build ├── runner.vala └── test_statusbar.vala ├── uncrustify.cfg └── vapi ├── flatpak.vapi ├── libgtop-2.0.vapi ├── libxnvctrl.vapi └── pci.vapi /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig 2 | root = true 3 | 4 | # elementary defaults 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | indent_size = tab 9 | indent_style = space 10 | insert_final_newline = true 11 | max_line_length = 80 12 | tab_width = 4 13 | 14 | # Markup files 15 | [{*.html,*.xml,*.xml.in,*.yml}] 16 | tab_width = 2 17 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - reopened 8 | - synchronize 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | version: [stable, unstable, development-target] 18 | container: 19 | image: ghcr.io/elementary/docker:${{ matrix.version }} 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | with: 24 | submodules: true 25 | 26 | - name: Install Dependencies 27 | run: | 28 | apt update 29 | apt install -y libgala-dev libgee-0.8-dev libglib2.0-dev libgranite-dev libgtk-3-dev libhandy-1-dev \ 30 | libdbus-glib-1-dev libwnck-3-dev libgtop2-dev libwingpanel-3.0-dev libudisks2-dev \ 31 | libxnvctrl0 libxnvctrl-dev libcurl4-gnutls-dev libflatpak-dev libjson-glib-dev \ 32 | liblivechart-1-dev libpci-dev \ 33 | meson valac sassc git 34 | - name: Build 35 | run: | 36 | meson setup -Dindicator-wingpanel=enabled build 37 | meson compile -C build 38 | # Tests disabled since it starts to test live-chart and some tests fail there 39 | # meson test -C build --print-errorlogs 40 | meson install -C build 41 | 42 | lint: 43 | runs-on: ubuntu-latest 44 | 45 | container: 46 | image: valalang/lint 47 | 48 | steps: 49 | - uses: actions/checkout@v4 50 | - name: Lint 51 | run: io.elementary.vala-lint -d . 52 | -------------------------------------------------------------------------------- /.github/workflows/gettext.yml: -------------------------------------------------------------------------------- 1 | name: Gettext Updates 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-22.04 10 | container: 11 | image: ghcr.io/elementary/docker:next-unstable 12 | 13 | steps: 14 | - name: Clone repository 15 | uses: actions/checkout@v4 16 | with: 17 | token: ${{ secrets.GIT_USER_TOKEN }} 18 | submodules: true 19 | - name: Update Translation Files 20 | uses: elementary/actions/gettext-template@main 21 | env: 22 | GIT_USER_TOKEN: ${{ secrets.GIT_USER_TOKEN }} 23 | GIT_USER_NAME: "elementaryBot" 24 | GIT_USER_EMAIL: "builds@elementary.io" 25 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | pull_request: 4 | branches: [main] 5 | types: closed 6 | jobs: 7 | release: 8 | runs-on: ubuntu-latest 9 | if: github.event.pull_request.merged == true && true == contains(join(github.event.pull_request.labels.*.name), 'Release') 10 | steps: 11 | - uses: actions/checkout@v4 12 | with: 13 | submodules: true 14 | - uses: elementary/actions/release@main 15 | env: 16 | GIT_USER_TOKEN: "${{ secrets.GIT_USER_TOKEN }}" 17 | GIT_USER_NAME: "elementaryBot" 18 | GIT_USER_EMAIL: "builds@elementary.io" 19 | with: 20 | release_branch: 'noble' 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | builddir 3 | .atom-dbg.cson 4 | .vscode 5 | *~ 6 | .goutputstream-* 7 | *.css 8 | obj-*-linux-gnu 9 | *.debhelper.log 10 | *.substvars 11 | *.debhelper 12 | debian/io.elementary.monitor 13 | debian/files 14 | # subprojects/*/ 15 | .flatpak-builder 16 | *.tar.gz 17 | *.rpm 18 | -------------------------------------------------------------------------------- /.valalintignore: -------------------------------------------------------------------------------- 1 | build 2 | builddir 3 | data 4 | subprojects 5 | po -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Michael Starkweather 2 | Stanisław Dac 3 | 4 | Icons: 5 | Paulo Galardi 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

Monitor

4 |

5 | 6 |

Manage processes and monitor system resources

7 | 8 | [![](https://img.shields.io/github/release/elementary/monitor.svg)]() 9 | [![Github Workflow Status](https://github.com/elementary/monitor/actions/workflows/ci.yml/badge.svg)]() 10 | [![Translation status](https://l10n.elementary.io/widget/desktop/monitor/svg-badge.svg)](https://l10n.elementary.io/engage/desktop/) 11 | 12 | ![Monitor Screenshot](https://github.com/elementary/monitor/raw/main/data/screenshots/monitor-processes.png) 13 | ![Monitor Screenshot](https://github.com/elementary/monitor/raw/main/data/screenshots/monitor-system.png) 14 | 15 | ## Install 16 | 17 | ### elementary OS 7 Horus 18 | 19 | If you have never added a PPA on your system before, you might need to run this command first: 20 | 21 | ```bash 22 | sudo apt install -y software-properties-common 23 | ``` 24 | 25 | Add the PPA of Monitor and then install it: 26 | 27 | ```bash 28 | sudo add-apt-repository ppa:stsdc/monitor 29 | sudo apt install com.github.stsdc.monitor 30 | ``` 31 | 32 | Monitor will be available from the Applications menu. 33 | 34 | ## Development 35 | 36 | ### Install dependencies 37 | 38 | If you plan to install WITH a wingpanel-indicator 39 | 40 | ```bash 41 | sudo apt install build-essential cmake sassc valac libgtk-3-dev libgee-0.8-dev libgranite-dev libgtop2-dev libwnck-3-dev libhandy-1-dev libudisks2-dev libjson-glib-dev libflatpak-dev libxnvctrl-dev liblivechart-1-dev libpci-dev libwingpanel-dev 42 | ``` 43 | 44 | Alternatively, if you plan to install WITHOUT a wingpanel-indicator 45 | 46 | ```bash 47 | sudo apt install build-essential cmake sassc valac libgtk-3-dev libgee-0.8-dev libgranite-dev libgtop2-dev libwnck-3-dev libhandy-1-dev libudisks2-dev libjson-glib-dev libflatpak-dev libxnvctrl-dev liblivechart-1-dev libpci-dev 48 | ``` 49 | 50 | 51 | ### Clone, Build & Install 52 | 53 | 1. Clone: 54 | ```bash 55 | git clone https://github.com/elementary/monitor 56 | cd monitor 57 | ``` 58 | 59 | 2. To build with the wingpanel indicator: 60 | ```bash 61 | meson setup -Dindicator-wingpanel=enabled build 62 | ``` 63 | Alternatively, to build without the wingpanel indicator: 64 | ```bash 65 | meson setup build 66 | ``` 67 | 68 | 3. Install: 69 | ```bash 70 | cd builddir 71 | sudo ninja install 72 | ``` 73 | 74 | ### Debug logging 75 | 76 | ```bash 77 | G_MESSAGES_DEBUG=all GTK_DEBUG=interactive io.elementary.monitor 78 | ``` 79 | -------------------------------------------------------------------------------- /data/css.gresource.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | monitor-light.css 5 | monitor-dark.css 6 | 7 | -------------------------------------------------------------------------------- /data/database/README.md: -------------------------------------------------------------------------------- 1 | # The CPU features and bugs database 2 | 3 | The database contains information about the CPU features and bugs that were generated by script located in `meson/get_cpu_features_and_bugs.py`. 4 | -------------------------------------------------------------------------------- /data/database/cpu_bugs.csv: -------------------------------------------------------------------------------- 1 | f00f,Intel F00F 2 | fdiv,FPU FDIV 3 | coma,Cyrix 6x86 coma 4 | amd_tlb_mmatch,tlb_mmatch AMD Erratum 383 5 | amd_apic_c1e,apic_c1e AMD Erratum 400 6 | 11ap,Bad local APIC aka 11AP 7 | fxsave_leak,FXSAVE leaks FOP/FIP/FOP 8 | clflush_monitor,"AAI65, CLFLUSH required before MONITOR" 9 | sysret_ss_attrs,SYSRET doesn't fix up SS attrs 10 | espfix.,ESPFIX. Make the define conditional 11 | espfix,IRET to 16-bit SS corrupts ESP/RSP high bits 12 | null_seg,Nulling a selector preserves the base 13 | swapgs_fence,SWAPGS without input dep on GS 14 | monitor,IPI required to wake up remote CPU 15 | amd_e400,CPU is among the affected by Erratum 400 16 | cpu_meltdown,CPU is affected by meltdown attack and needs kernel page table isolation 17 | spectre_v1,CPU is affected by Spectre variant 1 attack with conditional branches 18 | spectre_v2,CPU is affected by Spectre variant 2 attack with indirect branches 19 | spec_store_bypass,CPU is affected by speculative store bypass attack 20 | l1tf,CPU is affected by L1 Terminal Fault 21 | mds,CPU is affected by Microarchitectural data sampling 22 | msbds_only,CPU is only affected by the MSDBS variant of BUG_MDS 23 | swapgs,CPU is affected by speculation through SWAPGS 24 | taa,CPU is affected by TSX Async Abort(TAA) 25 | itlb_multihit,CPU may incur MCE during certain page attribute changes 26 | srbds,CPU may leak RNG bits if not mitigated 27 | -------------------------------------------------------------------------------- /data/icons/file-deleted-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 16 | 18 | 19 | 21 | image/svg+xml 22 | 24 | 25 | 26 | 27 | 29 | 52 | 55 | 56 | 60 | 66 | 67 | 71 | 75 | 78 | 86 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /data/icons/gpu-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml 158 | -------------------------------------------------------------------------------- /data/icons/icons.indicator.gresource.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | cpu-symbolic.svg 5 | gpu-symbolic.svg 6 | ram-symbolic.svg 7 | gpu-vram-symbolic.svg 8 | swap-symbolic.svg 9 | file-deleted-symbolic.svg 10 | temperature-sensor-symbolic.svg 11 | temperature-gpu-symbolic.svg 12 | extra/16/bash.svg 13 | extra/48/bash.svg 14 | extra/64/bash.svg 15 | extra/16/docker.svg 16 | extra/48/docker.svg 17 | extra/64/docker.svg 18 | 19 | 20 | -------------------------------------------------------------------------------- /data/icons/ram-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 12 | 14 | 15 | 17 | image/svg+xml 18 | 20 | 21 | 22 | 23 | 24 | 26 | 30 | 37 | 44 | 51 | 58 | 59 | -------------------------------------------------------------------------------- /data/icons/swap-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 16 | 39 | 42 | 43 | 45 | 46 | 48 | image/svg+xml 49 | 51 | 52 | 53 | 54 | 55 | 57 | 60 | 65 | 72 | 79 | 86 | 89 | 92 | 95 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /data/icons/temperature-gpu-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml 50 | -------------------------------------------------------------------------------- /data/icons/temperature-sensor-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 16 | 18 | 19 | 21 | image/svg+xml 22 | 24 | 25 | 26 | 27 | 29 | 49 | 52 | 53 | 58 | 59 | -------------------------------------------------------------------------------- /data/io.elementary.monitor.gschema.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | false 10 | Is window maximized or not 11 | Is window maximized or not 12 | 13 | 14 | 800 15 | Window width 16 | Window width 17 | 18 | 19 | 640 20 | Window height 21 | Window height 22 | 23 | 24 | false 25 | To show Monitor Indicator or not 26 | To show Monitor Indicator or not 27 | 28 | 29 | false 30 | To start Monitor in background or not 31 | To start Monitor in background or not 32 | 33 | 34 | true 35 | To show CPU usage in Monitor Indicator or not 36 | To show CPU usage in Monitor Indicator or not 37 | 38 | 39 | false 40 | To show CPU frequency in Monitor Indicator or not 41 | To show CPU frequency in Monitor Indicator or not 42 | 43 | 44 | true 45 | To show CPU temperature value in Monitor Indicator or not 46 | To show CPU temperature value in Monitor Indicator or not 47 | 48 | 49 | true 50 | To show memory usage in Monitor Indicator or not 51 | To show memory usage in Monitor Indicator or not 52 | 53 | 54 | false 55 | To show network up bandwidth data in Monitor Indicator or not 56 | To show network up bandwidth in Monitor Indicator or not 57 | 58 | 59 | false 60 | To show network down bandwidth in Monitor Indicator or not 61 | To show network down bandwidth in Monitor Indicator or not 62 | 63 | 64 | false 65 | To show GPU used percentage in Monitor Indicator or not 66 | To show GPU used percentage in Monitor Indicator or not 67 | 68 | 69 | false 70 | To show GPU memory usage in Monitor Indicator or not 71 | To show GPU memory usage in Monitor Indicator or not 72 | 73 | 74 | false 75 | To show GPU temperature in Monitor Indicator or not 76 | To show GPU temperature in Monitor Indicator or not 77 | 78 | 79 | true 80 | To enable smooth lines in charts 81 | To enable smooth lines in charts or not 82 | 83 | 84 | 'process_view' 85 | Opened view 86 | The last opened view 87 | 88 | 89 | 2 90 | Update time 91 | This value sets update time for updating data and charts. 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /data/meson.build: -------------------------------------------------------------------------------- 1 | icon_sizes = ['16', '24', '32', '48', '64', '128'] 2 | 3 | foreach i : icon_sizes 4 | install_data( 5 | join_paths('icons', i, meson.project_name() + '.svg'), 6 | install_dir: join_paths(icondir, i + 'x' + i, 'apps') 7 | ) 8 | install_data( 9 | join_paths('icons', i, meson.project_name() + '.svg'), 10 | install_dir: join_paths(icondir, i + 'x' + i + '@2', 'apps') 11 | ) 12 | endforeach 13 | 14 | dbdir = join_paths(datadir, meson.project_name(), 'database') 15 | config_data.set('DBDIR', dbdir) 16 | 17 | install_data( 18 | join_paths('database', 'cpu_bugs.csv'), 19 | install_dir: dbdir 20 | ) 21 | 22 | install_data( 23 | join_paths('database', 'cpu_features.csv'), 24 | install_dir: dbdir 25 | ) 26 | 27 | install_data( 28 | meson.project_name() + '.gschema.xml', 29 | install_dir: join_paths(datadir, 'glib-2.0', 'schemas') 30 | ) 31 | 32 | i18n.merge_file( 33 | input: 'monitor.desktop.in', 34 | output: meson.project_name() + '.desktop', 35 | po_dir: meson.source_root() / 'po' / 'extra', 36 | type: 'desktop', 37 | install: true, 38 | install_dir: datadir / 'applications' 39 | ) 40 | 41 | i18n.merge_file( 42 | input: meson.project_name() + '.appdata.xml.in', 43 | output: meson.project_name() + '.appdata.xml', 44 | po_dir: join_paths(meson.source_root(), 'po', 'extra'), 45 | install: true, 46 | install_dir: join_paths(datadir, 'metainfo') 47 | ) 48 | 49 | 50 | icons_gresource = gnome.compile_resources( 51 | 'gresource_icons', 'icons/icons.indicator.gresource.xml', 52 | source_dir: 'icons', 53 | c_name: 'as1' 54 | ) 55 | 56 | sass_command = [ 57 | sass, 58 | '@INPUT@', 59 | '@OUTPUT@' 60 | ] 61 | 62 | stylesheet_light = custom_target( 63 | 'theme-monitor-light', 64 | input : './stylesheet/monitor-light.scss', 65 | output : 'monitor-light.css', 66 | command : sass_command, 67 | build_by_default: true 68 | ) 69 | 70 | stylesheet_dark = custom_target( 71 | 'theme-monitor-dark', 72 | input : './stylesheet/monitor-dark.scss', 73 | output : 'monitor-dark.css', 74 | command : sass_command, 75 | build_by_default: true 76 | ) 77 | 78 | css_gresource = gnome.compile_resources( 79 | 'gresource_css', 80 | 'css.gresource.xml', 81 | source_dir: 'stylesheet', 82 | c_name: 'as2', 83 | dependencies: [stylesheet_dark, stylesheet_light], 84 | 85 | ) 86 | -------------------------------------------------------------------------------- /data/monitor.desktop.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.5 3 | Type=Application 4 | 5 | Name=Monitor 6 | Comment=Manage processes and monitor resource usage of the system 7 | Categories=System;Utility; 8 | Keywords=System monitor;System usage;Task manager; 9 | 10 | Icon=io.elementary.monitor 11 | Exec=io.elementary.monitor %U 12 | SingleMainWindow=true 13 | StartupNotify=true 14 | Terminal=false 15 | 16 | X-GNOME-UsesNotifications=false 17 | -------------------------------------------------------------------------------- /data/screenshots/monitor-containers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elementary/monitor/cce725f44e32e6474ba0580fa58aa2ac91c4a4f7/data/screenshots/monitor-containers.png -------------------------------------------------------------------------------- /data/screenshots/monitor-processes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elementary/monitor/cce725f44e32e6474ba0580fa58aa2ac91c4a4f7/data/screenshots/monitor-processes.png -------------------------------------------------------------------------------- /data/screenshots/monitor-system.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elementary/monitor/cce725f44e32e6474ba0580fa58aa2ac91c4a4f7/data/screenshots/monitor-system.png -------------------------------------------------------------------------------- /data/stylesheet/_palette.scss: -------------------------------------------------------------------------------- 1 | //@TODO: Could be removed, if Granite will provide palette 2 | 3 | // Internal Palette 4 | $STRAWBERRY_100: #ff8c82; 5 | $STRAWBERRY_300: #ed5353; 6 | $STRAWBERRY_500: #c6262e; 7 | $STRAWBERRY_700: #a10705; 8 | $STRAWBERRY_900: #7a0000; 9 | 10 | $ORANGE_100: #ffc27d; 11 | $ORANGE_300: #ffa154; 12 | $ORANGE_500: #f37329; 13 | $ORANGE_700: #cc3b02; 14 | $ORANGE_900: #a62100; 15 | 16 | $BANANA_100: #fff394; 17 | $BANANA_300: #ffe16b; 18 | $BANANA_500: #f9c440; 19 | $BANANA_700: #d48e15; 20 | $BANANA_900: #ad5f00; 21 | 22 | $LIME_100: #d1ff82; 23 | $LIME_300: #9bdb4d; 24 | $LIME_500: #68b723; 25 | $LIME_700: #3a9104; 26 | $LIME_900: #206b00; 27 | 28 | $MINT_100: #89ffdd; 29 | $MINT_300: #43d6b5; 30 | $MINT_500: #28bca3; 31 | $MINT_700: #0e9a83; 32 | $MINT_900: #007367; 33 | 34 | $BLUEBERRY_100: #8cd5ff; 35 | $BLUEBERRY_300: #64baff; 36 | $BLUEBERRY_500: #3689e6; 37 | $BLUEBERRY_700: #0d52bf; 38 | $BLUEBERRY_900: #002e99; 39 | 40 | $BUBBLEGUM_100: #fe9ab8; 41 | $BUBBLEGUM_300: #f4679d; 42 | $BUBBLEGUM_500: #de3e80; 43 | $BUBBLEGUM_700: #bc245d; 44 | $BUBBLEGUM_900: #910e38; 45 | 46 | $GRAPE_100: #e4c6fa; 47 | $GRAPE_300: #cd9ef7; 48 | $GRAPE_500: #a56de2; 49 | $GRAPE_700: #7239b3; 50 | $GRAPE_900: #452981; 51 | 52 | $COCOA_100: #a3907c; 53 | $COCOA_300: #8a715e; 54 | $COCOA_500: #715344; 55 | $COCOA_700: #57392d; 56 | $COCOA_900: #3d211b; 57 | 58 | $SILVER_100: #fafafa; 59 | $SILVER_300: #d4d4d4; 60 | $SILVER_500: #abacae; 61 | $SILVER_700: #7e8087; 62 | $SILVER_900: #555761; 63 | 64 | $SLATE_100: #95a3ab; 65 | $SLATE_300: #667885; 66 | $SLATE_500: #485a6c; 67 | $SLATE_700: #273445; 68 | $SLATE_900: #0e141f; 69 | 70 | $BLACK_100: #666; 71 | $BLACK_300: #4d4d4d; 72 | $BLACK_500: #333; 73 | $BLACK_700: #1a1a1a; 74 | $BLACK_900: #000; 75 | 76 | // Exported 77 | @define-color STRAWBERRY_100 #{$STRAWBERRY_100}; 78 | @define-color STRAWBERRY_300 #{$STRAWBERRY_300}; 79 | @define-color STRAWBERRY_500 #{$STRAWBERRY_500}; 80 | @define-color STRAWBERRY_700 #{$STRAWBERRY_700}; 81 | @define-color STRAWBERRY_900 #{$STRAWBERRY_900}; 82 | 83 | @define-color ORANGE_100 #{$ORANGE_100}; 84 | @define-color ORANGE_300 #{$ORANGE_300}; 85 | @define-color ORANGE_500 #{$ORANGE_500}; 86 | @define-color ORANGE_700 #{$ORANGE_700}; 87 | @define-color ORANGE_900 #{$ORANGE_900}; 88 | 89 | @define-color BANANA_100 #{$BANANA_100}; 90 | @define-color BANANA_300 #{$BANANA_300}; 91 | @define-color BANANA_500 #{$BANANA_500}; 92 | @define-color BANANA_700 #{$BANANA_700}; 93 | @define-color BANANA_900 #{$BANANA_900}; 94 | 95 | @define-color LIME_100 #{$LIME_100}; 96 | @define-color LIME_300 #{$LIME_300}; 97 | @define-color LIME_500 #{$LIME_500}; 98 | @define-color LIME_700 #{$LIME_700}; 99 | @define-color LIME_900 #{$LIME_900}; 100 | 101 | @define-color MINT_100 #{$MINT_100}; 102 | @define-color MINT_300 #{$MINT_300}; 103 | @define-color MINT_500 #{$MINT_500}; 104 | @define-color MINT_700 #{$MINT_700}; 105 | @define-color MINT_900 #{$MINT_900}; 106 | 107 | @define-color BLUEBERRY_100 #{$BLUEBERRY_100}; 108 | @define-color BLUEBERRY_300 #{$BLUEBERRY_300}; 109 | @define-color BLUEBERRY_500 #{$BLUEBERRY_500}; 110 | @define-color BLUEBERRY_700 #{$BLUEBERRY_700}; 111 | @define-color BLUEBERRY_900 #{$BLUEBERRY_900}; 112 | 113 | @define-color BUBBLEGUM_100 #{$BUBBLEGUM_100}; 114 | @define-color BUBBLEGUM_300 #{$BUBBLEGUM_300}; 115 | @define-color BUBBLEGUM_500 #{$BUBBLEGUM_500}; 116 | @define-color BUBBLEGUM_700 #{$BUBBLEGUM_700}; 117 | @define-color BUBBLEGUM_900 #{$BUBBLEGUM_900}; 118 | 119 | @define-color GRAPE_100 #{$GRAPE_100}; 120 | @define-color GRAPE_300 #{$GRAPE_300}; 121 | @define-color GRAPE_500 #{$GRAPE_500}; 122 | @define-color GRAPE_700 #{$GRAPE_700}; 123 | @define-color GRAPE_900 #{$GRAPE_900}; 124 | 125 | @define-color COCOA_100 #{$COCOA_100}; 126 | @define-color COCOA_300 #{$COCOA_300}; 127 | @define-color COCOA_500 #{$COCOA_500}; 128 | @define-color COCOA_700 #{$COCOA_700}; 129 | @define-color COCOA_900 #{$COCOA_900}; 130 | 131 | @define-color SILVER_100 #{$SILVER_100}; 132 | @define-color SILVER_300 #{$SILVER_300}; 133 | @define-color SILVER_500 #{$SILVER_500}; 134 | @define-color SILVER_700 #{$SILVER_700}; 135 | @define-color SILVER_900 #{$SILVER_900}; 136 | 137 | @define-color SLATE_100 #{$SLATE_100}; 138 | @define-color SLATE_300 #{$SLATE_300}; 139 | @define-color SLATE_500 #{$SLATE_500}; 140 | @define-color SLATE_700 #{$SLATE_700}; 141 | @define-color SLATE_900 #{$SLATE_900}; 142 | 143 | @define-color BLACK_100 #{$BLACK_100}; 144 | @define-color BLACK_300 #{$BLACK_300}; 145 | @define-color BLACK_500 #{$BLACK_500}; 146 | @define-color BLACK_700 #{$BLACK_700}; 147 | @define-color BLACK_900 #{"" + $BLACK_900}; 148 | -------------------------------------------------------------------------------- /data/stylesheet/monitor-dark.scss: -------------------------------------------------------------------------------- 1 | $color-scheme: "dark"; 2 | 3 | @import './index.scss'; -------------------------------------------------------------------------------- /data/stylesheet/monitor-light.scss: -------------------------------------------------------------------------------- 1 | $color-scheme: "light"; 2 | 3 | @import './index.scss'; -------------------------------------------------------------------------------- /data/stylesheet/monitor-retrofit.scss: -------------------------------------------------------------------------------- 1 | @import "../../subprojects/stylesheet/src/gtk-3.0/palette"; 2 | 3 | @define-color selected_bg_color @BLUEBERRY_500; -------------------------------------------------------------------------------- /design/GfknBzs.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elementary/monitor/cce725f44e32e6474ba0580fa58aa2ac91c4a4f7/design/GfknBzs.jpg -------------------------------------------------------------------------------- /design/application_manager_by_nicekiwi-d698q3a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elementary/monitor/cce725f44e32e6474ba0580fa58aa2ac91c4a4f7/design/application_manager_by_nicekiwi-d698q3a.png -------------------------------------------------------------------------------- /design/brainstorm: -------------------------------------------------------------------------------- 1 | ----------- 2 | 3 | Have three different concepts: 4 | 5 | Applications (by which I mean graphical applications) 6 | Windows 7 | Processes 8 | 9 | An application is a group of windows and associated processes. We can use libbamf 10 | to enumerate applications (and their windows) as well as monitor for changes; we 11 | can also use libbamf's get_pid () function to grab associated Window->PIDs and 12 | group the related process trees (there may be several) underneath the application. 13 | 14 | ----------- 15 | 16 | Listed in the main window, we will enumerate all applications under which we 17 | will list the windows and process trees (which we got using get_pid () on each 18 | window) 19 | 20 | Application 21 | Window1 22 | Window2 23 | Processes 24 | Process1 25 | Process2 26 | Process3 27 | Process4 28 | Process5 29 | Process6 30 | 31 | 32 | Process trees that are not grabbed by an application will be enumerated in a 33 | special category ("Background Processes", "Other", ?) located at the bottom of 34 | the application list. It may be that some processes are parents of other processes 35 | that have been moved up into an Application. In this case, the child process 36 | 'owned' by an Application will not be displayed as a child process -- in effect, 37 | the process will have been 'moved' up into the application. 38 | 39 | ----------- 40 | 41 | We could also monitor network and disk resource usage. This may be out of scope. 42 | 43 | ----------- 44 | 45 | Perhaps we should have a couple different view modes, because grouping processes 46 | into Applications is a touchy business (as sometimes windows can't be tied to a 47 | PID, and thus, Applications can't be tied to processes). View modes could include: 48 | 49 | Group by Application (default behavior) 50 | Group by Process Tree (shows only processes) 51 | No grouping (shows only processes) 52 | 53 | ----------- 54 | 55 | What kind of data do we need to fetch and maintain? 56 | 57 | All running Bamf.Applications 58 | their Bamf.Windows 59 | 60 | All running processes 61 | their CPU load 62 | their memory load 63 | 64 | ----------- -------------------------------------------------------------------------------- /design/task_manager_by_mashnoon33-d7x4s3f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elementary/monitor/cce725f44e32e6474ba0580fa58aa2ac91c4a4f7/design/task_manager_by_mashnoon33-d7x4s3f.png -------------------------------------------------------------------------------- /design/tasku.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elementary/monitor/cce725f44e32e6474ba0580fa58aa2ac91c4a4f7/design/tasku.png -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('io.elementary.monitor', 'vala', 'c', version: '0.17.2') 2 | 3 | # these are Meson modules 4 | gnome = import('gnome') 5 | i18n = import('i18n') 6 | sass = find_program('sassc') 7 | 8 | # common dirs 9 | prefix = get_option('prefix') 10 | datadir = join_paths(prefix, get_option('datadir')) 11 | libdir = join_paths(prefix, get_option('libdir')) 12 | icondir = join_paths(datadir, 'icons', 'hicolor') 13 | vapidir = meson.current_source_dir() / 'vapi/' 14 | 15 | add_global_arguments('-DGETTEXT_PACKAGE="@0@"'.format(meson.project_name()), language: 'c') 16 | 17 | add_project_arguments(['--vapidir', vapidir], language: 'vala') 18 | add_project_arguments(['-DWNCK_I_KNOW_THIS_IS_UNSTABLE', '-w'], language: 'c') 19 | 20 | # subprojects should be skipped: https://mesonbuild.com/Release-notes-for-0-58-0.html#skip-subprojects-installation 21 | # needs meson 0.58.0 22 | # elementary_stylesheet = subproject('stylesheet') 23 | 24 | app_dependencies = [ 25 | dependency('granite', version: '>= 5.2.0'), 26 | dependency('glib-2.0'), 27 | dependency('gtk+-3.0'), 28 | dependency('gee-0.8'), 29 | dependency('gio-2.0'), 30 | dependency('gobject-2.0'), 31 | dependency('libgtop-2.0'), 32 | dependency('libwnck-3.0'), 33 | dependency('libhandy-1', version: '>=0.90.0'), 34 | dependency('gdk-x11-3.0'), 35 | dependency('x11'), 36 | dependency('udisks2'), 37 | dependency('json-glib-1.0'), 38 | dependency('flatpak'), 39 | 40 | # FIXME Bump required version to >= 1.10.0 when GTK 4 porting 41 | dependency( 42 | 'livechart', 43 | version: '< 1.10.0', 44 | fallback: ['live-chart', 'livechart_dep'], 45 | ), 46 | 47 | meson.get_compiler('c').find_library('m', required: false), 48 | meson.get_compiler('vala').find_library('posix'), 49 | meson.get_compiler('c').find_library('X11'), 50 | 51 | # PCI needs lower version limit '>= 3.8.0' 52 | meson.get_compiler('c').find_library('pci'), 53 | meson.get_compiler('vala').find_library('pci', dirs: vapidir), 54 | 55 | meson.get_compiler('c').find_library('XNVCtrl'), 56 | meson.get_compiler('vala').find_library('libxnvctrl', dirs: vapidir), 57 | ] 58 | 59 | config_data = configuration_data() 60 | config_data.set('GETTEXT_PACKAGE', meson.project_name()) 61 | 62 | subdir('data') 63 | 64 | config_data.set('VCS_TAG', '@VCS_TAG@') 65 | project_config = vcs_tag( 66 | input: configure_file( 67 | input: 'src/Conf.vala.in', 68 | output: 'Conf.vala.in', 69 | configuration: config_data, 70 | ), 71 | output: 'Conf.vala', 72 | command: ['git', 'describe', '--tags', '--dirty'], 73 | ) 74 | 75 | subdir('src') 76 | 77 | # Add in a post install script 78 | meson.add_install_script('meson/post_install.py') 79 | 80 | subdir('po') 81 | # subdir('tests') 82 | -------------------------------------------------------------------------------- /meson/bump_version.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ''' 4 | Bump all the versionsss!!! 5 | ''' 6 | 7 | import sys 8 | import datetime 9 | 10 | print ('Bumping everything to: ' + sys.argv[1]) 11 | 12 | def bump_spec(): 13 | SPEC_FILENAME = "../io.elementary.monitor.spec" 14 | spec_content = '' 15 | with open(SPEC_FILENAME, 'r') as f_spec: 16 | print('Reading spec file: ' + SPEC_FILENAME) 17 | for line in f_spec.readlines(): 18 | if 'Version:' in line: 19 | line = 'Version: ' + sys.argv[1] + '\n' 20 | spec_content += line 21 | 22 | with open(SPEC_FILENAME, 'w') as f_spec: 23 | print('Writing spec file: ' + SPEC_FILENAME) 24 | f_spec.write(spec_content) 25 | 26 | def bump_meson(): 27 | MESON_FILENAME = "../meson.build" 28 | meson_content = '' 29 | with open(MESON_FILENAME, 'r') as f_meson: 30 | print('Reading meson file: ' + MESON_FILENAME) 31 | for line in f_meson.readlines(): 32 | if 'version: ' in line and 'project' in line: 33 | # line = 'version: "' + sys.argv[1] + '"\n' 34 | splitted = line.split('version: ') 35 | line = splitted[0] + "version: '" + sys.argv[1] + "')\n" 36 | 37 | meson_content += line 38 | 39 | with open(MESON_FILENAME, 'w') as f_meson: 40 | print('Writing meson file: ' + MESON_FILENAME) 41 | f_meson.write(meson_content) 42 | 43 | def bump_deb_changelog(): 44 | DEB_CHANGELOG_FILENAME = "../debian/changelog" 45 | now = datetime.datetime.now() 46 | deb_changelog_content = f"""io.elementary.monitor ({sys.argv[1]}) jammy; urgency=low\n 47 | * \n -- Stanisław Dac {now.strftime("%a, %d %b %Y %H:%M:%S %z")} +0000\n\n""" 48 | 49 | with open(DEB_CHANGELOG_FILENAME, 'r+') as f_deb_changelog: 50 | content = f_deb_changelog.read() 51 | f_deb_changelog.seek(0) 52 | print('Writing deb changelog file: ' + DEB_CHANGELOG_FILENAME) 53 | f_deb_changelog.write(deb_changelog_content + content) 54 | 55 | bump_spec() 56 | bump_meson() 57 | bump_deb_changelog() -------------------------------------------------------------------------------- /meson/get_cpu_features_and_bugs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ''' 4 | This script is used to generate the list of available CPU features by parsing Linux sources. 5 | ''' 6 | 7 | import urllib.request 8 | import csv 9 | 10 | cpu_features = list() 11 | cpu_bugs = list() 12 | 13 | with urllib.request.urlopen('https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/plain/arch/x86/include/asm/cpufeatures.h') as f: 14 | html = f.read().decode('utf-8') 15 | 16 | for line in html.split('\n'): 17 | if 'X86_FEATURE_' in line and not line.startswith('/*'): 18 | flag_name = line.split('X86_FEATURE_')[1].split('\t')[0].split(' ')[0] 19 | flag_description = line.split('X86_FEATURE_')[1].split('\t')[-1].split('/*')[-1].strip('*/').replace('""', '').strip().replace('"', '') 20 | print(flag_name, flag_description) 21 | cpu_features.append([flag_name.lower(), flag_description]) 22 | 23 | if 'X86_BUG_' in line and not line.startswith('/*'): 24 | flag_name = line.split('X86_BUG_')[1].split('\t')[0].split(' ')[0] 25 | flag_description = line.split('X86_BUG_')[1].split('\t')[-1].split('/*')[-1].strip('*/').replace('""', '').strip().replace('"', '') 26 | print(flag_name, flag_description) 27 | cpu_bugs.append([flag_name.lower(), flag_description]) 28 | 29 | with open('cpu_features.csv', 'w') as f: 30 | # create the csv writer 31 | writer = csv.writer(f) 32 | writer.writerows(cpu_features) 33 | 34 | with open('cpu_bugs.csv', 'w') as f: 35 | # create the csv writer 36 | writer = csv.writer(f) 37 | writer.writerows(cpu_bugs) -------------------------------------------------------------------------------- /meson/list-app-src.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | find . -name "*.vala" -------------------------------------------------------------------------------- /meson/post_install.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import subprocess 5 | 6 | schema_dir = os.path.join(os.environ['MESON_INSTALL_PREFIX'], 'share', 'glib-2.0', 'schemas') 7 | icon_cache_dir = os.path.join(os.environ['MESON_INSTALL_PREFIX'], 'share', 'icons', 'hicolor') 8 | 9 | if not os.environ.get('DESTDIR'): 10 | print('Compiling gsettings schemas…') 11 | subprocess.call(['glib-compile-schemas', schema_dir]) 12 | 13 | print('Updating desktop icon cache…') 14 | subprocess.call(['gtk-update-icon-cache', '-qtf', icon_cache_dir]) 15 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option('indicator-wingpanel', type : 'feature', value : 'disabled', description : 'Enables the Indicator for Wingpanel.') -------------------------------------------------------------------------------- /po/LINGUAS: -------------------------------------------------------------------------------- 1 | aa ab ace ae af ak am an ar as ast av ay az ba be bg bh bi bm bn bo br bs ca ca@valencia ce ch ckb co cr cs cu cv cy da de dv dz ee el en_AU en_CA en_GB en_ZA eo es et eu fa ff fi fil fj fo fr fr_CA frp fy ga gd gl gn gu gv ha he hi ho hr ht hu hy hz ia id id_ID ie ig ii ik io is it iu ja jv ka kg ki kj kk kl km kn ko kr ks ku kv kw ky la lb lg li ln lo lt lu lv mg mh mi mk ml mn mo mr ms mt my na nb nd ne ng nl nn no nr nv ny oc oj om or os pa pap pi pl ps pt pt_BR qu rm rn ro ru rue rw sa sc sco sd se sg si sk sl sm sma sn so sq sr sr@latin ss st su sv sw szl ta te tg th ti tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa wo xh yi yo za zh zh_HK zh_Hans zh_Hant zu 2 | -------------------------------------------------------------------------------- /po/POTFILES: -------------------------------------------------------------------------------- 1 | src/Monitor.vala 2 | src/MainWindow.vala 3 | src/Utils.vala 4 | src/Indicator/Widgets/PopoverWidget.vala 5 | src/Views/ProcessView/ProcessInfoView/Preventor.vala 6 | src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala 7 | src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala 8 | src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala 9 | src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala 10 | src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala 11 | src/Views/PreferencesView.vala 12 | src/Views/SystemView/SystemCPUView.vala 13 | src/Views/SystemView/SystemCPUInfoPopover.vala 14 | src/Views/SystemView/SystemMemoryView.vala 15 | src/Views/SystemView/SystemNetworkView.vala 16 | src/Views/SystemView/SystemStorageView.vala 17 | src/Views/SystemView/SystemGPUView.vala 18 | src/Widgets/Headerbar/Search.vala 19 | src/Widgets/Statusbar/Statusbar.vala 20 | src/Widgets/WidgetResource/WidgetResource.vala 21 | -------------------------------------------------------------------------------- /po/extra/LINGUAS: -------------------------------------------------------------------------------- 1 | aa ab ace ae af ak am an ar as ast av ay az ba be bg bh bi bm bn bo br bs ca ca@valencia ce ch ckb co cr cs cu cv cy da de dv dz ee el en_AU en_CA en_GB en_ZA eo es et eu fa ff fi fil fj fo fr fr_CA frp fy ga gd gl gn gu gv ha he hi ho hr ht hu hy hz ia id id_ID ie ig ii ik io is it iu ja jv ka kg ki kj kk kl km kn ko kr ks ku kv kw ky la lb lg li ln lo lt lu lv mg mh mi mk ml mn mo mr ms mt my na nb nd ne ng nl nn no nr nv ny oc oj om or os pa pap pi pl ps pt pt_BR qu rm rn ro ru rue rw sa sc sco sd se sg si sk sl sm sma sn so sq sr sr@latin ss st su sv sw szl ta te tg th ti tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa wo xh yi yo za zh zh_HK zh_Hans zh_Hant zu 2 | -------------------------------------------------------------------------------- /po/extra/POTFILES: -------------------------------------------------------------------------------- 1 | data/io.elementary.monitor.appdata.xml.in 2 | data/monitor.desktop.in 3 | -------------------------------------------------------------------------------- /po/extra/meson.build: -------------------------------------------------------------------------------- 1 | i18n.gettext('extra', preset: 'glib', install: false) 2 | -------------------------------------------------------------------------------- /po/meson.build: -------------------------------------------------------------------------------- 1 | i18n.gettext(meson.project_name(), preset: 'glib') 2 | 3 | subdir ('extra') 4 | -------------------------------------------------------------------------------- /src/Conf.vala.in: -------------------------------------------------------------------------------- 1 | namespace Monitor { 2 | public const string DBDIR = "@DBDIR@"; 3 | public const string GETTEXT_PACKAGE = "@GETTEXT_PACKAGE@"; 4 | public const string VCS_TAG = "@VCS_TAG@"; 5 | } -------------------------------------------------------------------------------- /src/Indicator/Services/DBusClient.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | [DBus (name = "io.elementary.monitor")] 7 | public interface Monitor.DBusClientInterface : Object { 8 | public abstract void quit_monitor () throws Error; 9 | public abstract void show_monitor () throws Error; 10 | public signal void update (ResourcesSerialized data); 11 | public signal void indicator_state (bool state); 12 | public signal void indicator_cpu_state (bool state); 13 | public signal void indicator_cpu_frequency_state (bool state); 14 | public signal void indicator_cpu_temperature_state (bool state); 15 | public signal void indicator_memory_state (bool state); 16 | public signal void indicator_network_up_state (bool state); 17 | public signal void indicator_network_down_state (bool state); 18 | public signal void indicator_gpu_state (bool state); 19 | public signal void indicator_gpu_memory_state (bool state); 20 | public signal void indicator_gpu_temperature_state (bool state); 21 | 22 | } 23 | 24 | public class Monitor.DBusClient : Object { 25 | public DBusClientInterface ? interface = null; 26 | 27 | private static GLib.Once instance; 28 | public static unowned DBusClient get_default () { 29 | return instance.once (() => { return new DBusClient (); }); 30 | } 31 | 32 | public signal void monitor_vanished (); 33 | public signal void monitor_appeared (); 34 | 35 | construct { 36 | try { 37 | interface = Bus.get_proxy_sync ( 38 | BusType.SESSION, 39 | "io.elementary.monitor", 40 | "/io/elementary/monitor" 41 | ); 42 | 43 | Bus.watch_name ( 44 | BusType.SESSION, 45 | "io.elementary.monitor", 46 | BusNameWatcherFlags.NONE, 47 | () => monitor_appeared (), 48 | () => monitor_vanished () 49 | ); 50 | } catch (IOError e) { 51 | error ("Monitor Indicator DBus: %s\n", e.message); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Indicator/Widgets/DisplayWidget.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Monitor.Widgets.DisplayWidget : Gtk.Grid { 7 | public IndicatorWidget cpu_widget = new IndicatorWidget ("cpu-symbolic"); 8 | public IndicatorWidget cpu_frequency_widget = new IndicatorWidget ("cpu-symbolic"); 9 | public IndicatorWidget cpu_temperature_widget = new IndicatorWidget ("temperature-sensor-symbolic"); 10 | 11 | public IndicatorWidget memory_widget = new IndicatorWidget ("ram-symbolic"); 12 | 13 | public IndicatorWidget network_up_widget = new IndicatorWidget ("go-up-symbolic"); 14 | public IndicatorWidget network_down_widget = new IndicatorWidget ("go-down-symbolic"); 15 | 16 | public IndicatorWidget gpu_widget = new IndicatorWidget ("gpu-symbolic"); 17 | public IndicatorWidget gpu_memory_widget = new IndicatorWidget ("gpu-vram-symbolic"); 18 | public IndicatorWidget gpu_temperature_widget = new IndicatorWidget ("temperature-gpu-symbolic"); 19 | 20 | construct { 21 | valign = Gtk.Align.CENTER; 22 | 23 | add (cpu_widget); 24 | add (cpu_frequency_widget); 25 | add (cpu_temperature_widget); 26 | add (memory_widget); 27 | add (gpu_widget); 28 | add (gpu_memory_widget); 29 | add (gpu_temperature_widget); 30 | add (network_up_widget); 31 | add (network_down_widget); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Indicator/Widgets/IndicatorWidget.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Monitor.IndicatorWidget : Gtk.Box { 7 | 8 | public string icon_name { get; construct; } 9 | 10 | public uint state_percentage { 11 | set { 12 | label.label = "%u%%".printf (value); 13 | label.get_style_context ().remove_class ("monitor-indicator-label-warning"); 14 | label.get_style_context ().remove_class ("monitor-indicator-label-critical"); 15 | 16 | if (value > 80) { 17 | label.get_style_context ().add_class ("monitor-indicator-label-warning"); 18 | } 19 | if (value > 90) { 20 | label.get_style_context ().add_class ("monitor-indicator-label-critical"); 21 | } 22 | } 23 | } 24 | 25 | public int state_temperature { 26 | set { 27 | label.label = "%i℃".printf (value); 28 | } 29 | } 30 | 31 | public double state_frequency { 32 | set { 33 | label.label = ("%.2f %s").printf (value, _("GHz")); 34 | } 35 | } 36 | 37 | public uint64 state_bandwidth { 38 | set { 39 | label.label = format_size (value); 40 | } 41 | } 42 | 43 | private Gtk.Label label = new Gtk.Label (Utils.NOT_AVAILABLE); 44 | 45 | public IndicatorWidget (string icon_name) { 46 | Object ( 47 | orientation: Gtk.Orientation.HORIZONTAL, 48 | icon_name: icon_name, 49 | visible: false 50 | ); 51 | } 52 | 53 | construct { 54 | var icon = new Gtk.Image.from_icon_name (icon_name, Gtk.IconSize.SMALL_TOOLBAR); 55 | label.margin = 2; 56 | label.width_chars = 4; 57 | pack_start (icon); 58 | pack_start (label); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Indicator/Widgets/PopoverWidget.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Monitor.Widgets.PopoverWidget : Gtk.Grid { 7 | /* Button to hide the indicator */ 8 | private Gtk.ModelButton show_monitor_button; 9 | private Gtk.ModelButton quit_monitor_button; 10 | 11 | public signal void quit_monitor (); 12 | public signal void show_monitor (); 13 | 14 | construct { 15 | orientation = Gtk.Orientation.VERTICAL; 16 | 17 | show_monitor_button = new Gtk.ModelButton (); 18 | show_monitor_button.text = _("Show Monitor"); 19 | show_monitor_button.hexpand = true; 20 | quit_monitor_button = new Gtk.ModelButton (); 21 | quit_monitor_button.text = _("Quit Monitor"); 22 | quit_monitor_button.hexpand = true; 23 | show_monitor_button.clicked.connect (() => show_monitor ()); 24 | quit_monitor_button.clicked.connect (() => quit_monitor ()); 25 | 26 | add (show_monitor_button); 27 | add (new Gtk.Separator (Gtk.Orientation.HORIZONTAL)); 28 | add (quit_monitor_button); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Indicator/meson.build: -------------------------------------------------------------------------------- 1 | source_indicator_files = [ 2 | 'Indicator.vala', 3 | 'Services/DBusClient.vala', 4 | 'Widgets/DisplayWidget.vala', 5 | 'Widgets/IndicatorWidget.vala', 6 | 'Widgets/PopoverWidget.vala', 7 | 8 | meson.project_source_root() / 'src' / 'Resources/ResourcesSerialized.vala', 9 | meson.project_source_root() / 'src' / 'Utils.vala', 10 | ] 11 | 12 | wingpanel_dep = dependency('wingpanel', version: '>=2.1.0') 13 | 14 | indicator_dependencies = [ 15 | wingpanel_dep 16 | ] 17 | 18 | shared_module( 19 | 'monitor', 20 | source_indicator_files, 21 | icons_gresource, 22 | dependencies: indicator_dependencies, 23 | install: true, 24 | install_dir : wingpanel_dep.get_pkgconfig_variable('indicatorsdir', define_variable: ['libdir', libdir]), 25 | ) 26 | -------------------------------------------------------------------------------- /src/MainWindow.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Monitor.MainWindow : Hdy.ApplicationWindow { 7 | private Resources resources; 8 | 9 | // Widgets 10 | public Search search { get; private set; } 11 | 12 | public ProcessView process_view; 13 | public SystemView system_view; 14 | private Gtk.Stack stack; 15 | 16 | private Statusbar statusbar; 17 | 18 | public DBusServer dbusserver; 19 | 20 | 21 | // Constructs a main window 22 | public MainWindow (MonitorApp app) { 23 | this.set_application (app); 24 | 25 | setup_window_state (); 26 | 27 | title = _("Monitor"); 28 | 29 | get_style_context ().add_class ("rounded"); 30 | 31 | resources = new Resources (); 32 | 33 | process_view = new ProcessView (); 34 | system_view = new SystemView (resources); 35 | 36 | stack = new Gtk.Stack (); 37 | stack.set_transition_type (Gtk.StackTransitionType.SLIDE_LEFT_RIGHT); 38 | stack.add_titled (process_view, "process_view", _("Processes")); 39 | stack.add_titled (system_view, "system_view", _("System")); 40 | 41 | 42 | Gtk.StackSwitcher stack_switcher = new Gtk.StackSwitcher (); 43 | stack_switcher.valign = Gtk.Align.CENTER; 44 | stack_switcher.set_stack (stack); 45 | 46 | var sv = new PreferencesView (); 47 | sv.show_all (); 48 | 49 | var preferences_popover = new Gtk.Popover (null) { 50 | child = sv 51 | }; 52 | 53 | var preferences_button = new Gtk.MenuButton () { 54 | image = new Gtk.Image.from_icon_name ("open-menu", Gtk.IconSize.LARGE_TOOLBAR), 55 | popover = preferences_popover, 56 | tooltip_text = (_("Settings")) 57 | }; 58 | 59 | search = new Search (this) { 60 | valign = CENTER 61 | }; 62 | 63 | var search_revealer = new Gtk.Revealer () { 64 | child = search, 65 | transition_type = SLIDE_LEFT 66 | }; 67 | 68 | var headerbar = new Hdy.HeaderBar () { 69 | has_subtitle = false, 70 | show_close_button = true, 71 | title = _("Monitor") 72 | }; 73 | headerbar.pack_start (search_revealer); 74 | headerbar.set_custom_title (stack_switcher); 75 | headerbar.pack_end (preferences_button); 76 | 77 | statusbar = new Statusbar (); 78 | 79 | var grid = new Gtk.Grid () { 80 | orientation = Gtk.Orientation.VERTICAL 81 | }; 82 | 83 | grid.add (headerbar); 84 | grid.add (stack); 85 | grid.add (statusbar); 86 | 87 | add (grid); 88 | 89 | show_all (); 90 | 91 | dbusserver = DBusServer.get_default (); 92 | 93 | search_revealer.set_reveal_child (stack.visible_child_name == "process_view"); 94 | stack.notify["visible-child-name"].connect (() => { 95 | search_revealer.set_reveal_child (stack.visible_child_name == "process_view"); 96 | }); 97 | 98 | new Thread ("upd", () => { 99 | Timeout.add_seconds (MonitorApp.settings.get_int ("update-time"), () => { 100 | process_view.update (); 101 | 102 | Idle.add (() => { 103 | system_view.update (); 104 | dbusserver.indicator_state (MonitorApp.settings.get_boolean ("indicator-state")); 105 | var res = resources.serialize (); 106 | statusbar.update (res); 107 | dbusserver.update (res); 108 | return false; 109 | }); 110 | return true; 111 | }); 112 | }); 113 | 114 | 115 | dbusserver.quit.connect (() => app.quit ()); 116 | dbusserver.show.connect (() => { 117 | this.deiconify (); 118 | this.present (); 119 | setup_window_state (); 120 | this.show_all (); 121 | }); 122 | 123 | key_press_event.connect (search.handle_event); 124 | 125 | this.delete_event.connect (() => { 126 | int window_width, window_height; 127 | get_size (out window_width, out window_height); 128 | MonitorApp.settings.set_int ("window-width", window_width); 129 | MonitorApp.settings.set_int ("window-height", window_height); 130 | MonitorApp.settings.set_boolean ("is-maximized", this.is_maximized); 131 | 132 | MonitorApp.settings.set_string ("opened-view", stack.visible_child_name); 133 | 134 | if (MonitorApp.settings.get_boolean ("indicator-state")) { 135 | this.hide_on_delete (); 136 | } else { 137 | dbusserver.indicator_state (false); 138 | app.quit (); 139 | } 140 | 141 | return true; 142 | }); 143 | 144 | dbusserver.indicator_state (MonitorApp.settings.get_boolean ("indicator-state")); 145 | stack.visible_child_name = MonitorApp.settings.get_string ("opened-view"); 146 | 147 | var search_action = new GLib.SimpleAction ("search", null); 148 | search_action.activate.connect (() => search.activate_entry ()); 149 | 150 | add_action (search_action); 151 | } 152 | 153 | private void setup_window_state () { 154 | int window_width = MonitorApp.settings.get_int ("window-width"); 155 | int window_height = MonitorApp.settings.get_int ("window-height"); 156 | this.set_default_size (window_width, window_height); 157 | 158 | if (MonitorApp.settings.get_boolean ("is-maximized")) { 159 | this.maximize (); 160 | } 161 | } 162 | 163 | } 164 | -------------------------------------------------------------------------------- /src/Managers/ProcessStructs.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | // For more info look at: http://man7.org/linux/man-pages/man5/proc.5.html 7 | 8 | public struct Monitor.ProcessIO { 9 | // characters read 10 | public uint64 rchar; 11 | 12 | // characters written 13 | public uint64 wchar; 14 | 15 | // read syscalls 16 | public uint64 syscr; 17 | 18 | // write syscalls 19 | public uint64 syscw; 20 | 21 | // Attempt to count the number of bytes which this process 22 | // really did cause to be fetched from the storage layer 23 | public uint64 read_bytes; 24 | 25 | // Attempt to count the number of bytes which this process 26 | // caused to be sent to the storage layer. 27 | public uint64 write_bytes; 28 | 29 | public uint64 cancelled_write_bytes; 30 | } 31 | 32 | public struct Monitor.ProcessStatusMemory { 33 | // total program size (pages) (same as VmSize in status) 34 | public uint64 size; 35 | 36 | // size of memory portions (pages) (same as VmRSS in status) 37 | public uint64 resident; 38 | 39 | // number of pages that are shared 40 | // (i.e. backed by a file, same as RssFile+RssShmem in status) 41 | public uint64 shared; 42 | 43 | // number of pages that are 'code' (not including libs; broken, 44 | // includes data segment) 45 | public uint64 trs; 46 | 47 | // number of pages of library (always 0 on 2.6) 48 | public uint64 lrs; 49 | 50 | // number of pages of data/stack (including libs; broken, 51 | // includes library text) 52 | public uint64 drs; 53 | 54 | // number of dirty pages (always 0 on 2.6) 55 | public uint64 dt; 56 | } 57 | 58 | public struct Monitor.ProcessStatus { 59 | // process ID 60 | public int pid; 61 | 62 | // The filename of the executable, in parentheses. 63 | // This is visible whether or not the executable is 64 | // swapped out. 65 | public string comm; 66 | 67 | // Should contain one of the following value: 68 | // D uninterruptible sleep (usually IO) 69 | // I Idle kernel thread 70 | // R running or runnable (on run queue) 71 | // S interruptible sleep (waiting for an event to complete) 72 | // T stopped by job control signal 73 | // t stopped by debugger during the tracing 74 | // W paging (not valid since the 2.6.xx kernel) 75 | // X dead (should never be seen) 76 | // Z defunct ("zombie") process, terminated but not reaped by its parent 77 | public string state; 78 | 79 | // The PID of the parent of this process. 80 | public int ppid; 81 | 82 | // The process group ID of the process. 83 | public int pgrp; 84 | 85 | // The session ID of the process. 86 | public uint session; 87 | 88 | // The controlling terminal of the process. 89 | // (The minor device number is contained in 90 | // the combination of bits 31 to 20 and 7 to 0; 91 | // the major device number is in bits 15 to 8.) 92 | public uint tty_nr; 93 | 94 | // The ID of the foreground process group of the con‐ 95 | // trolling terminal of the process. 96 | public uint tpgid; 97 | 98 | // The nice value, a value in the 99 | // range 19 (low priority) to -20 (high priority). 100 | public int nice; 101 | 102 | public int priority; 103 | 104 | // Number of threads in this process 105 | public int num_threads; 106 | 107 | // The time the process started after system boot. 108 | public uint64 starttime; 109 | } 110 | -------------------------------------------------------------------------------- /src/Managers/ProcessUtils.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Monitor.ProcessUtils { 7 | // checks if it is run by shell 8 | public static bool is_shell (string chunk) { 9 | return "sh" == chunk || "bash" == chunk || "zsh" == chunk; 10 | } 11 | 12 | public static bool is_python (string chunk) { 13 | return chunk.contains ("python"); 14 | } 15 | 16 | public static string sanitize_commandline (string ? commandline) { 17 | if (commandline == null) return ""; 18 | 19 | // splitting command; might include many options 20 | var splitted_commandline = commandline.split (" "); 21 | 22 | // check if started by any shell 23 | if (is_shell (splitted_commandline[0]) || is_python (splitted_commandline[0]) ) { 24 | return commandline; 25 | } 26 | 27 | // if (!splitted_commandline[0].contains ("/")) { 28 | // return commandline; 29 | // } 30 | 31 | return splitted_commandline[0]; 32 | } 33 | 34 | public static string ? read_file (string path) { 35 | var file = File.new_for_path (path); 36 | 37 | /* make sure that it exists, not an error if it doesn't */ 38 | if (!file.query_exists ()) { 39 | return null; 40 | } 41 | var text = new StringBuilder (); 42 | try { 43 | var dis = new DataInputStream (file.read ()); 44 | 45 | // Doing this because of cmdline file. 46 | // cmdline is a single line file with each arg separated by a null character ('\0') 47 | string line = dis.read_upto ("\0", 1, null); 48 | while (line != null) { 49 | text.append (line); 50 | text.append (" "); 51 | dis.skip (1); 52 | line = dis.read_upto ("\0", 1, null); 53 | } 54 | 55 | return text.str; 56 | } catch (Error e) { 57 | warning ("Error reading cmdline file '%s': %s\n", file.get_path (), e.message); 58 | return null; 59 | } 60 | } 61 | 62 | public static Icon ? get_default_icon () { 63 | try { 64 | return Icon.new_for_string ("application-x-executable"); 65 | } catch (Error e) { 66 | warning (e.message); 67 | return null; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Models/OpenFilesTreeViewModel.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Monitor.OpenFilesTreeViewModel : Gtk.TreeStore { 7 | private Gee.Map open_files_paths = new Gee.HashMap (); 8 | 9 | private Process _process; 10 | 11 | public Process ? process { 12 | get { 13 | return _process; 14 | } 15 | set { 16 | _process = value; 17 | 18 | // repopulating 19 | open_files_paths.clear (); 20 | clear (); 21 | add_paths (); 22 | } 23 | } 24 | 25 | construct { 26 | set_column_types (new Type[] { 27 | typeof (string), 28 | typeof (string), 29 | }); 30 | 31 | } 32 | 33 | public void add_paths () { 34 | foreach (var path in process.open_files_paths) { 35 | add_path (path); 36 | } 37 | } 38 | 39 | private bool add_path (string path) { 40 | if (path.substring (0, 1) == "/") { 41 | Gtk.TreeIter iter; 42 | append (out iter, null); 43 | 44 | set (iter, 45 | Column.NAME, path, 46 | -1); 47 | 48 | // open_files_paths.set (path, iter); 49 | return true; 50 | } 51 | return false; 52 | } 53 | 54 | public void update_model (Process process) { 55 | if (process.open_files_paths.size > 0) { 56 | foreach (var path in process.open_files_paths) { 57 | 58 | // print("sdsd"); 59 | // Gtk.TreeIter iter = open_files_paths[path]; 60 | print (path); 61 | //// display only real paths 62 | //// probably should be done in process class 63 | // if (path.substring (0, 1) == "/") { 64 | // set (iter, 65 | // Column.NAME, path, 66 | // -1); 67 | // } 68 | } 69 | } 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/Models/TreeViewModel.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public enum Monitor.Column { 7 | ICON, 8 | NAME, 9 | CPU, 10 | MEMORY, 11 | PID, 12 | CMD 13 | } 14 | 15 | public class Monitor.TreeViewModel : Gtk.TreeStore { 16 | public ProcessManager process_manager; 17 | private Gee.Map process_rows; 18 | public signal void added_first_row (); 19 | 20 | construct { 21 | process_rows = new Gee.HashMap (); 22 | 23 | set_column_types (new Type[] { 24 | typeof (string), 25 | typeof (string), 26 | typeof (double), 27 | typeof (int64), 28 | typeof (int), 29 | typeof (string), 30 | }); 31 | 32 | process_manager = ProcessManager.get_default (); 33 | process_manager.process_added.connect ((process) => add_process (process)); 34 | process_manager.process_removed.connect ((pid) => remove_process (pid)); 35 | process_manager.updated.connect (update_model); 36 | 37 | Idle.add (() => { add_running_processes (); return false; }); 38 | } 39 | 40 | private void add_running_processes () { 41 | debug ("add_running_processes"); 42 | var running_processes = process_manager.get_process_list (); 43 | foreach (var process in running_processes.values) { 44 | add_process (process); 45 | } 46 | } 47 | 48 | private bool add_process (Process process) { 49 | if (process != null && !process_rows.has_key (process.stat.pid)) { 50 | debug ("Add process %d Parent PID: %d", process.stat.pid, process.stat.ppid); 51 | // add the process to the model 52 | Gtk.TreeIter iter; 53 | append (out iter, null); // null means top-level 54 | 55 | // donno what is going on, but maybe just use a string instead of Icon ?? 56 | // coz it lagz 57 | // string icon_name = process.icon.to_string (); 58 | 59 | set (iter, 60 | Column.NAME, process.application_name, 61 | Column.ICON, process.icon.to_string (), 62 | Column.PID, process.stat.pid, 63 | Column.CMD, process.command, 64 | -1); 65 | if (process_rows.size < 1) { 66 | added_first_row (); 67 | } 68 | // add the process to our cache of process_rows 69 | process_rows.set (process.stat.pid, iter); 70 | return true; 71 | } 72 | return false; 73 | } 74 | 75 | private void update_model () { 76 | foreach (int pid in process_rows.keys) { 77 | Process process = process_manager.get_process (pid); 78 | Gtk.TreeIter iter = process_rows[pid]; 79 | set (iter, 80 | Column.CPU, process.cpu_percentage, 81 | Column.MEMORY, process.mem_usage, 82 | -1); 83 | } 84 | } 85 | 86 | private void remove_process (int pid) { 87 | debug ("remove process %d from model".printf (pid)); 88 | // if process rows has pid 89 | if (process_rows.has_key (pid)) { 90 | var cached_iter = process_rows.get (pid); 91 | remove (ref cached_iter); 92 | process_rows.unset (pid); 93 | } 94 | } 95 | 96 | public void kill_process (int pid) { 97 | if (pid > 0) { 98 | var process = process_manager.get_process (pid); 99 | process.kill (); 100 | info ("Kill:%d", process.stat.pid); 101 | } 102 | } 103 | 104 | public void end_process (int pid) { 105 | if (pid > 0) { 106 | var process = process_manager.get_process (pid); 107 | process.end (); 108 | info ("End:%d", process.stat.pid); 109 | } 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /src/Monitor.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | namespace Monitor { 7 | public class MonitorApp : Gtk.Application { 8 | public static Settings settings; 9 | private MainWindow window = null; 10 | public string[] args; 11 | 12 | private static bool start_in_background = false; 13 | private static bool status_background = false; 14 | private const GLib.OptionEntry[] CMD_OPTIONS = { 15 | // --start-in-background 16 | { "start-in-background", 'b', 0, OptionArg.NONE, ref start_in_background, "Start in background with wingpanel indicator", null }, 17 | // list terminator 18 | { null } 19 | }; 20 | 21 | // constructor replacement, flags added 22 | public MonitorApp (bool status_indicator) { 23 | Object ( 24 | application_id: "io.elementary.monitor", 25 | flags : ApplicationFlags.FLAGS_NONE 26 | ); 27 | status_background = status_indicator; 28 | } 29 | 30 | static construct { 31 | settings = new Settings ("io.elementary.monitor.settings"); 32 | } 33 | 34 | public override void startup () { 35 | base.startup (); 36 | 37 | Hdy.init (); 38 | 39 | Appearance.set_prefered_style (); 40 | 41 | // Controls the direction of the sort indicators 42 | Gtk.Settings.get_default ().set ("gtk-alternative-sort-arrows", true, null); 43 | 44 | var quit_action = new SimpleAction ("quit", null); 45 | add_action (quit_action); 46 | quit_action.activate.connect (() => { 47 | if (window != null) { 48 | window.destroy (); 49 | } 50 | }); 51 | 52 | set_accels_for_action ("app.quit", { "q" }); 53 | set_accels_for_action ("win.search", { "f" }); 54 | set_accels_for_action ("process.end", { "e" }); 55 | set_accels_for_action ("process.kill", { "k" }); 56 | } 57 | 58 | public override void activate () { 59 | // only have one window 60 | if (get_windows () != null) { 61 | window.show_all (); 62 | window.present (); 63 | return; 64 | } 65 | 66 | window = new MainWindow (this); 67 | 68 | // start in background with indicator 69 | if (status_background || MonitorApp.settings.get_boolean ("background-state")) { 70 | if (!MonitorApp.settings.get_boolean ("indicator-state")) { 71 | MonitorApp.settings.set_boolean ("indicator-state", true); 72 | } 73 | // if (!MonitorApp.settings.get_boolean ("indicator-cpu-state")) { 74 | // MonitorApp.settings.set_boolean ("indicator-cpu-state", true); 75 | // } 76 | // if (!MonitorApp.settings.get_boolean ("indicator-memory-state")) { 77 | // MonitorApp.settings.set_boolean ("indicator-memory-state", true); 78 | // } 79 | // if (!MonitorApp.settings.get_boolean ("indicator-temperature-state")) { 80 | // MonitorApp.settings.set_boolean ("indicator-temperature-state", true); 81 | // } 82 | // if (!MonitorApp.settings.get_boolean ("indicator-network-upload-state")) { 83 | // MonitorApp.settings.set_boolean ("indicator-network-upload-state", false); 84 | // } 85 | // if (!MonitorApp.settings.get_boolean ("indicator-network-download-state")) { 86 | // MonitorApp.settings.set_boolean ("indicator-network-download-state", false); 87 | // } 88 | 89 | window.hide (); 90 | MonitorApp.settings.set_boolean ("background-state", true); 91 | } else { 92 | window.show_all (); 93 | } 94 | 95 | window.process_view.process_tree_view.focus_on_first_row (); 96 | } 97 | 98 | public static int main (string[] args) { 99 | Intl.setlocale (); 100 | print ("\n"); 101 | print (" Monitor %s \n", VCS_TAG); 102 | print ("\n"); 103 | 104 | print ( 105 | "LibPCI ver: %d.%d.%d \n", 106 | PCIUtils.LIBPCI_MAJOR_VER, 107 | PCIUtils.LIBPCI_MINOR_VER, 108 | PCIUtils.LIBPCI_PATCH_VER 109 | ); 110 | 111 | // add command line options 112 | try { 113 | var opt_context = new OptionContext (""); 114 | opt_context.set_help_enabled (true); 115 | opt_context.add_main_entries (CMD_OPTIONS, null); 116 | opt_context.parse (ref args); 117 | } catch (OptionError e) { 118 | print ("Error: %s\n", e.message); 119 | print ("Run '%s --help' to see a full list of available command line options.\n\n", args[0]); 120 | return 0; 121 | } 122 | 123 | var app = new MonitorApp (start_in_background); 124 | 125 | return app.run (args); 126 | } 127 | 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/PCIUtils.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | namespace Monitor.PCIUtils { 7 | const int LIBPCI_MAJOR_VER = (Pci.LIB_VERSION & 0xFF0000) >> 16; 8 | const int LIBPCI_MINOR_VER = (Pci.LIB_VERSION & 0x00FF00) >> 8; 9 | const int LIBPCI_PATCH_VER = (Pci.LIB_VERSION & 0x0000FF) >> 0; 10 | } 11 | -------------------------------------------------------------------------------- /src/Resources/CPUCache.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | // This struct holds paths to cpu cache data 7 | // Learn more: https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-devices-system-cpu 8 | [Compact] 9 | public class Monitor.CPUCache : Object { 10 | // 11 | // allocation_policy: 12 | // - WriteAllocate: 13 | // allocate a memory location to a cache line 14 | // on a cache miss because of a write 15 | // - ReadAllocate: 16 | // allocate a memory location to a cache line 17 | // on a cache miss because of a read 18 | // - ReadWriteAllocate: 19 | // both writeallocate and readallocate 20 | public string allocation_policy; 21 | 22 | // LEGACY used only on IA64 and is same as write_policy 23 | public string attributes; 24 | 25 | // the minimum amount of data in bytes that gets 26 | // transferred from memory to cache 27 | public string coherency_line_size; 28 | 29 | // the cache hierarchy in the multi-level cache configuration 30 | public string level; 31 | 32 | // Etotal number of sets in the cache, a set is a 33 | // collection of cache lines with the same cache index 34 | public string number_of_sets; 35 | 36 | // number of physical cache line per cache tag 37 | public string physical_line_partition; 38 | 39 | // the list of logical cpus sharing the cache 40 | public string shared_cpu_list; 41 | 42 | // logical cpu mask containing the list of cpus sharing 43 | // the cache 44 | public string shared_cpu_map; 45 | 46 | // the total cache size in kB 47 | public string size; 48 | 49 | // - Instruction: cache that only holds instructions 50 | // - Data: cache that only caches data 51 | // - Unified: cache that holds both data and instructions 52 | public string type; 53 | 54 | // degree of freedom in placing a particular block 55 | // of memory in the cache 56 | public string ways_of_associativity; 57 | 58 | // - WriteThrough: 59 | // data is written to both the cache line 60 | // and to the block in the lower-level memory 61 | // - WriteBack: 62 | // data is written only to the cache line and 63 | // the modified cache line is written to main 64 | // memory only when it is replaced 65 | public string write_policy; 66 | } 67 | -------------------------------------------------------------------------------- /src/Resources/Cgroup/Cgroup.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Monitor.Cgroup : GLib.Object { 7 | /** 8 | * This class only parses necessary values from cgroup files. 9 | * @TODO: Properly parse all values in files. 10 | */ 11 | public string id; 12 | public string memory_usage_by_bytes { 13 | owned get { 14 | return open_file ("/sys/fs/cgroup/memory/docker/%s/memory.usage_in_bytes".printf (id), read_memory_usage_in_bytes) ?? "0"; 15 | } private set { 16 | } 17 | } 18 | 19 | public string memory_stat_total_inactive_file { 20 | owned get { 21 | return open_file ("/sys/fs/cgroup/memory/docker/%s/memory.stat".printf (id), read_memory_stat_total_inactive_file) ?? "0"; 22 | } private set { 23 | } 24 | } 25 | 26 | public string cpuaact_usage_sys { 27 | owned get { 28 | return open_file ("/sys/fs/cgroup/cpuacct/docker/%s/memory.usage_in_bytes".printf (id), read_cpuacct_usage_sys) ?? "0"; 29 | } private set { 30 | } 31 | } 32 | 33 | // public CgroupMemoryStat memory_stat; 34 | public Cgroup (string _id) { 35 | id = _id; 36 | } 37 | 38 | delegate string DelegateReadFileFunc (File file); 39 | 40 | private string open_file (string path, DelegateReadFileFunc read_file) { 41 | File file = File.new_for_path (path); 42 | 43 | /* make sure that it exists, not an error if it doesn't */ 44 | if (!file.query_exists ()) { 45 | warning ("File doesn't exist ???"); 46 | return ""; 47 | } 48 | return read_file (file); 49 | } 50 | 51 | private string read_memory_usage_in_bytes (File file) { 52 | try { 53 | var dis = new DataInputStream (file.read ()); 54 | return dis.read_line (); 55 | } catch (Error e) { 56 | warning ("Error reading file '%s': %s\n", file.get_path (), e.message); 57 | return ""; 58 | } 59 | } 60 | 61 | // Reads very specific value from a file. Should basically read whole file 62 | // but am too lazy 63 | private string read_memory_stat_total_inactive_file (File file) { 64 | try { 65 | var dis = new DataInputStream (file.read ()); 66 | string ? line; 67 | while ((line = dis.read_line ()) != null) { 68 | var splitted_line = line.split (":"); 69 | if (splitted_line[0] == "total_inactive_file") { 70 | return splitted_line[1]; 71 | } 72 | } 73 | return ""; 74 | } catch (Error e) { 75 | warning ("Error reading file '%s': %s\n", file.get_path (), e.message); 76 | return ""; 77 | } 78 | } 79 | 80 | private string read_cpuacct_usage_sys (File file) { 81 | try { 82 | var dis = new DataInputStream (file.read ()); 83 | return dis.read_line (); 84 | } catch (Error e) { 85 | warning ("Error reading file '%s': %s\n", file.get_path (), e.message); 86 | return ""; 87 | } 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/Resources/Cgroup/CgroupStructs.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | // Read more: https://docs.docker.com/config/containers/runmetrics/ 7 | 8 | public struct Monitor.CgroupMemoryStat { 9 | public uint64 cache; 10 | public uint64 rss; 11 | public uint64 rss_huge; 12 | public uint64 shmem; 13 | public uint64 mapped_file; 14 | public uint64 dirty; 15 | public uint64 writeback; 16 | public uint64 swap; 17 | public uint64 pgpgin; 18 | public uint64 pgpgout; 19 | public uint64 pgfault; 20 | public uint64 pgmajfault; 21 | public uint64 inactive_anon; 22 | public uint64 active_anon; 23 | public uint64 inactive_file; 24 | public uint64 active_file; 25 | public uint64 unevictable; 26 | public uint64 hierarchical_memory_limit; 27 | public uint64 hierarchical_memsw_limit; 28 | public uint64 total_cache; 29 | public uint64 total_rss; 30 | public uint64 total_rss_huge; 31 | public uint64 total_shmem; 32 | public uint64 total_mapped_file; 33 | public uint64 total_dirty; 34 | public uint64 total_writeback; 35 | public uint64 total_swap; 36 | public uint64 total_pgpgin; 37 | public uint64 total_pgpgout; 38 | public uint64 total_pgfault; 39 | public uint64 total_pgmajfault; 40 | public uint64 total_inactive_anon; 41 | public uint64 total_active_anon; 42 | public uint64 total_inactive_file; 43 | public uint64 total_active_file; 44 | public uint64 total_unevictable; 45 | } 46 | -------------------------------------------------------------------------------- /src/Resources/Drive.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2020 Dirli 4 | * 2021 stsdc 5 | */ 6 | 7 | public struct Monitor.DriveSmart { 8 | public bool enabled; 9 | public uint64 updated; 10 | public bool failing; 11 | public uint64 power_seconds; 12 | public uint64 power_counts; 13 | public string selftest_status; 14 | public uint life_left; 15 | } 16 | 17 | public struct Monitor.DriveVolume { 18 | public string device; 19 | public string label; 20 | public string type; 21 | public string uuid; 22 | public string mount_point; 23 | public uint64 size; 24 | public uint64 free; 25 | public uint64 offset; 26 | } 27 | 28 | public class Monitor.DiskDrive : GLib.Object { 29 | public string model; 30 | public uint64 size; 31 | public uint64 free; 32 | public string revision; 33 | public string id; 34 | public string device; 35 | public string partition; 36 | public GLib.Icon drive_icon; 37 | 38 | 39 | 40 | private Gee.ArrayList volumes; 41 | 42 | private DriveSmart? smart = null; 43 | public bool has_smart { 44 | get { 45 | return smart != null; 46 | } 47 | } 48 | 49 | public DiskDrive () { 50 | free = 0; 51 | volumes = new Gee.ArrayList (); 52 | } 53 | 54 | public DriveSmart? get_smart () { 55 | return smart; 56 | } 57 | 58 | public void add_smart (DriveSmart _smart) { 59 | smart = _smart; 60 | } 61 | 62 | public void add_volume (DriveVolume vol) { 63 | volumes.add (vol); 64 | free = free + vol.free; 65 | } 66 | 67 | public Gee.ArrayList get_volumes () { 68 | var volumes_arr = new Gee.ArrayList (); 69 | 70 | volumes.foreach ((vol) => { 71 | 72 | volumes_arr.add (vol); 73 | 74 | return true; 75 | }); 76 | 77 | volumes_arr.sort (compare_volumes); 78 | 79 | return volumes_arr; 80 | } 81 | 82 | private int compare_volumes (DriveVolume? vol1, DriveVolume? vol2) { 83 | if (vol1 == null) { 84 | return (vol2 == null) ? 0 : -1; 85 | } 86 | 87 | if (vol2 == null) { 88 | return 1; 89 | } 90 | 91 | return GLib.strcmp (vol1.device, vol2.device); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Resources/GPU/GPUAmd.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Monitor.GPUAmd : IGPU, Object { 7 | 8 | public Gee.HashMap hwmon_temperatures { get; set; } 9 | 10 | public string hwmon_module_name { get; set; } 11 | 12 | public string name { get; set; } 13 | 14 | public int percentage { get; protected set; } 15 | 16 | public int memory_percentage { get; protected set; } 17 | 18 | public double memory_vram_used { get; protected set; } 19 | 20 | public double memory_vram_total { get; set; } 21 | 22 | public double temperature { get; protected set; } 23 | 24 | protected string sysfs_path { get; set; } 25 | 26 | public GPUAmd (Pci.Access pci_access, Pci.Dev pci_device) { 27 | name = pci_parse_name (pci_access, pci_device); 28 | name = "AMD® " + name; 29 | 30 | sysfs_path = pci_parse_sysfs_path (pci_access, pci_device); 31 | } 32 | 33 | private void update_temperature () { 34 | temperature = double.parse (hwmon_temperatures.get ("edge").input) / 1000; 35 | } 36 | 37 | private void update_memory_vram_used () { 38 | memory_vram_used = double.parse (get_sysfs_value (sysfs_path + "/mem_info_vram_used")); 39 | } 40 | 41 | private void update_memory_vram_total () { 42 | memory_vram_total = double.parse (get_sysfs_value (sysfs_path + "/mem_info_vram_total")); 43 | } 44 | 45 | private void update_memory_percentage () { 46 | memory_percentage = (int) (Math.round ((memory_vram_used / memory_vram_total) * 100)); 47 | } 48 | 49 | private void update_percentage () { 50 | percentage = int.parse (get_sysfs_value (sysfs_path + "/gpu_busy_percent")); 51 | } 52 | 53 | public void update () { 54 | update_temperature (); 55 | update_memory_vram_used (); 56 | update_memory_vram_total (); 57 | update_memory_percentage (); 58 | update_percentage (); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/Resources/GPU/GPUIntel.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Monitor.GPUIntel : IGPU, Object { 7 | 8 | public Gee.HashMap hwmon_temperatures { get; set; } 9 | 10 | public string hwmon_module_name { get; set; } 11 | 12 | public string name { get; set; } 13 | 14 | public int percentage { get; protected set; } 15 | 16 | public int memory_percentage { get; protected set; } 17 | 18 | public double memory_vram_used { get; protected set; } 19 | 20 | public double memory_vram_total { get; set; } 21 | 22 | public double temperature { get; protected set; } 23 | 24 | protected string sysfs_path { get; set; } 25 | 26 | public GPUIntel (Pci.Access pci_access, Pci.Dev pci_device) { 27 | name = pci_parse_name (pci_access, pci_device); 28 | name = "Intel® " + name; 29 | 30 | sysfs_path = pci_parse_sysfs_path (pci_access, pci_device); 31 | } 32 | 33 | private void update_temperature () { 34 | // @TODO: Intel GPU temperature retrieval needs implementation. 35 | temperature = 0; 36 | } 37 | 38 | private void update_memory_vram_used () { 39 | // @TODO: Intel GPU used VRAM retrieval needs implementation. 40 | memory_vram_used = 0; 41 | } 42 | 43 | private void update_memory_vram_total () { 44 | // @TODO: Intel GPU total VRAM retrieval needs implementation. 45 | memory_vram_total = 0; 46 | } 47 | 48 | private void update_memory_percentage () { 49 | // @TODO: Intel GPU memory percentage needs implementation. 50 | memory_percentage = 0; 51 | } 52 | 53 | private void update_percentage () { 54 | // @TODO: Intel GPU usage percentage needs implementation. 55 | percentage = 0; 56 | } 57 | 58 | public void update () { 59 | update_temperature (); 60 | update_memory_vram_used (); 61 | update_memory_vram_total (); 62 | update_memory_percentage (); 63 | update_percentage (); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/Resources/GPU/GPUNvidia.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Monitor.GPUNvidia : IGPU, Object { 7 | 8 | public Gee.HashMap hwmon_temperatures { get; set; } 9 | 10 | public string hwmon_module_name { get; set; } 11 | 12 | public string name { get; set; } 13 | 14 | public int percentage { get; protected set; } 15 | 16 | public int memory_percentage { get; protected set; } 17 | 18 | public int fb_percentage { get; protected set; } 19 | 20 | public double memory_vram_used { get; protected set; } 21 | 22 | public double memory_vram_total { get; set; } 23 | 24 | public double temperature { get; protected set; } 25 | 26 | protected string sysfs_path { get; set; } 27 | 28 | public int nvidia_temperature = 0; 29 | 30 | public int nvidia_memory_vram_used = 0; 31 | 32 | public int nvidia_memory_vram_total = 0; 33 | 34 | public int nvidia_memory_percentage = 0; 35 | 36 | public int nvidia_fb_percentage = 0; 37 | 38 | public int nvidia_percentage = 0; 39 | 40 | public char * nvidia_used = ""; 41 | 42 | public bool nvidia_resources_temperature; 43 | 44 | public bool nvidia_resources_vram_used; 45 | 46 | public bool nvidia_resources_vram_total; 47 | 48 | public bool nvidia_resources_used; 49 | 50 | public X.Display nvidia_display; 51 | 52 | public GPUNvidia (Pci.Access pci_access, Pci.Dev pci_device) { 53 | name = pci_parse_name (pci_access, pci_device); 54 | name = "nVidia® " + name; 55 | 56 | sysfs_path = pci_parse_sysfs_path (pci_access, pci_device); 57 | } 58 | 59 | construct { 60 | nvidia_display = new X.Display (); 61 | } 62 | 63 | private void update_nv_resources () { 64 | nvidia_resources_temperature = NVCtrl.XNVCTRLQueryAttribute ( 65 | nvidia_display, 66 | 0, 67 | 0, 68 | NV_CTRL_GPU_CORE_TEMPERATURE, 69 | &nvidia_temperature 70 | ); 71 | 72 | if (!nvidia_resources_temperature) { 73 | warning ("Could not query NV_CTRL_GPU_CORE_TEMPERATURE attribute!\n"); 74 | return; 75 | } 76 | 77 | nvidia_resources_vram_used = NVCtrl.XNVCTRLQueryTargetAttribute ( 78 | nvidia_display, 79 | NV_CTRL_TARGET_TYPE_GPU, 80 | 0, 81 | 0, 82 | NV_CTRL_USED_DEDICATED_GPU_MEMORY, 83 | &nvidia_memory_vram_used 84 | ); 85 | 86 | if (!nvidia_resources_vram_used) { 87 | warning ("Could not query NV_CTRL_USED_DEDICATED_GPU_MEMORY attribute!\n"); 88 | return; 89 | } 90 | 91 | nvidia_resources_vram_total = NVCtrl.XNVCTRLQueryTargetAttribute ( 92 | nvidia_display, 93 | NV_CTRL_TARGET_TYPE_GPU, 94 | 0, 95 | 0, 96 | NV_CTRL_TOTAL_DEDICATED_GPU_MEMORY, 97 | &nvidia_memory_vram_total 98 | ); 99 | 100 | if (!nvidia_resources_vram_total) { 101 | warning ("Could not query NV_CTRL_TOTAL_DEDICATED_GPU_MEMORY attribute!\n"); 102 | return; 103 | } 104 | 105 | nvidia_resources_used = NVCtrl.XNVCTRLQueryTargetStringAttribute ( 106 | nvidia_display, 107 | NV_CTRL_TARGET_TYPE_GPU, 108 | 0, 109 | 0, 110 | NV_CTRL_STRING_GPU_UTILIZATION, 111 | &nvidia_used 112 | ); 113 | 114 | // var str_used = (string)nvidia_used; 115 | nvidia_percentage = int.parse (((string) nvidia_used).split_set ("=,")[1]); 116 | nvidia_fb_percentage = int.parse (((string) nvidia_used).split_set ("=,")[3]); 117 | debug ("USED_GRAPHICS: %d%\n", nvidia_percentage); 118 | debug ("USED_FB_MEMORY: %d%\n", nvidia_fb_percentage); 119 | 120 | if (!nvidia_resources_used) { 121 | warning ("Could not query NV_CTRL_STRING_GPU_UTILIZATION attribute!\n"); 122 | return; 123 | } 124 | 125 | } 126 | 127 | private void update_temperature () { 128 | temperature = nvidia_temperature; 129 | } 130 | 131 | private void update_memory_vram_used () { 132 | memory_vram_used = (double) nvidia_memory_vram_used * 1000000.0; 133 | } 134 | 135 | private void update_memory_vram_total () { 136 | memory_vram_total = (double) nvidia_memory_vram_total * 1000000.0; 137 | } 138 | 139 | private void update_memory_percentage () { 140 | memory_percentage = (int) (Math.round ((memory_vram_used / memory_vram_total) * 100)); 141 | } 142 | 143 | private void update_fb_percentage () { 144 | fb_percentage = nvidia_fb_percentage; 145 | } 146 | 147 | private void update_percentage () { 148 | percentage = nvidia_percentage; 149 | } 150 | 151 | public void update () { 152 | update_nv_resources (); 153 | update_temperature (); 154 | update_memory_vram_used (); 155 | update_memory_vram_total (); 156 | update_memory_percentage (); 157 | update_percentage (); 158 | } 159 | 160 | } 161 | -------------------------------------------------------------------------------- /src/Resources/GPU/IGPU.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public interface Monitor.IGPU : Object { 7 | 8 | public abstract Gee.HashMap hwmon_temperatures { get; set; } 9 | 10 | public abstract string hwmon_module_name { get; protected set; } 11 | 12 | public abstract string name { get; protected set; } 13 | 14 | public abstract int percentage { get; protected set; } 15 | 16 | public abstract int memory_percentage { get; protected set; } 17 | 18 | public abstract double memory_vram_used { get; protected set; } 19 | 20 | public abstract double memory_vram_total { get; protected set; } 21 | 22 | public abstract double temperature { get; protected set; } 23 | 24 | protected abstract string sysfs_path { get; protected set; } 25 | 26 | public abstract void update_temperature (); 27 | 28 | public abstract void update_memory_vram_used (); 29 | 30 | public abstract void update_memory_vram_total (); 31 | 32 | public abstract void update_memory_percentage (); 33 | 34 | public abstract void update_percentage (); 35 | 36 | public abstract void update (); 37 | 38 | protected virtual string pci_parse_name (Pci.Access pci_access, Pci.Dev pci_device) { 39 | char namebuf[256]; 40 | return pci_access.lookup_name (namebuf, Pci.LookupMode.DEVICE, pci_device.vendor_id, pci_device.device_id); 41 | } 42 | 43 | protected virtual string pci_parse_sysfs_path (Pci.Access pci_access, Pci.Dev pci_device) { 44 | string pci_path_domain_bus = "%04x:%02x".printf (pci_device.domain_16, pci_device.bus); 45 | string pci_path_dev_func = "%02x.%d".printf (pci_device.dev, pci_device.func); 46 | string path = "/sys/class/pci_bus/%s/device/%s:%s".printf (pci_path_domain_bus, pci_path_domain_bus, pci_path_dev_func); 47 | debug ("GPU path: %s", path); 48 | 49 | return path; 50 | } 51 | 52 | public virtual string get_sysfs_value (string path) { 53 | string content; 54 | try { 55 | FileUtils.get_contents (path, out content); 56 | } catch (Error e) { 57 | warning (e.message); 58 | content = "0"; 59 | } 60 | return content; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/Resources/Hwmon/HwmonFan.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | // This struct holds paths to temperature data 7 | // Learn more: https://www.kernel.org/doc/html/v5.11/gpu/amdgpu.html#hwmon-interfaces 8 | 9 | [Compact] 10 | public class Monitor.HwmonFan : Object { 11 | // fan speed in RPM 12 | public string input; 13 | 14 | // an minimum value Unit: revolution/min (RPM) 15 | public string min; 16 | 17 | // an maximum value Unit: revolution/min (RPM) 18 | public string max; 19 | 20 | // Desired fan speed Unit: revolution/min (RPM) 21 | public string target; 22 | 23 | // Enable or disable the sensors.1: Enable 0: Disable 24 | public string enable; 25 | } 26 | -------------------------------------------------------------------------------- /src/Resources/Hwmon/HwmonFrequency.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | // This struct holds paths to temperature data 7 | // Learn more: https://www.kernel.org/doc/html/v5.11/gpu/amdgpu.html#hwmon-interfaces 8 | 9 | [Compact] 10 | public class Monitor.HwmonFrequency : Object { 11 | // freq channel label 12 | public string label; 13 | 14 | // freq1_input: the gfx/compute clock in hertz 15 | // freq2_input: the memory clock in hertz 16 | public string input; 17 | } 18 | -------------------------------------------------------------------------------- /src/Resources/Hwmon/HwmonPWM.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | // This struct holds paths to temperature data 7 | // Learn more: https://www.kernel.org/doc/html/v5.11/gpu/amdgpu.html#hwmon-interfaces 8 | 9 | [Compact] 10 | public class Monitor.HwmonPWM : Object { 11 | // pulse width modulation fan level (0-255) 12 | public string pwm; 13 | 14 | // pulse width modulation fan control minimum level (0) 15 | public string min; 16 | 17 | // pulse width modulation fan control maximum level (255) 18 | public string max; 19 | 20 | // pulse width modulation fan control method 21 | // 0: no fan speed control, 22 | // 1: manual fan speed control using pwm interface, 23 | // 2: automatic fan speed control 24 | public string enable; 25 | } 26 | -------------------------------------------------------------------------------- /src/Resources/Hwmon/HwmonPathsParser.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | class Monitor.HwmonPathParser : Object { 7 | private const string HWMON_PATH = "/sys/class/hwmon"; 8 | 9 | public HwmonPathsParserGPU gpu_paths_parser = new HwmonPathsParserGPU (); 10 | public HwmonPathsParserNVMe nvme_paths_parser = new HwmonPathsParserNVMe (); 11 | public HwmonPathsParserIwlwifi iwlwifi_paths_parser = new HwmonPathsParserIwlwifi (); 12 | public HwmonPathsParserCPU cpu_paths_parser = new HwmonPathsParserCPU (); 13 | 14 | // public double cpu { 15 | // get { 16 | // double total_temperature = 0; 17 | // // this should handle null 18 | // foreach (var path in cpu_temp_paths) { 19 | // total_temperature += double.parse (open_file (path)); 20 | // } 21 | // return total_temperature / cpu_temp_paths.size; 22 | // } 23 | // } 24 | 25 | construct { 26 | // cpu_temp_paths = new Gee.ArrayList (); 27 | detect_sensors (); 28 | } 29 | 30 | private void detect_sensors () { 31 | try { 32 | Dir hwmon_dir = Dir.open (HWMON_PATH, 0); 33 | 34 | string ? hwmonx = null; 35 | while ((hwmonx = hwmon_dir.read_name ()) != null) { 36 | string hwmonx_name = Path.build_filename (HWMON_PATH, hwmonx, "name"); 37 | 38 | string interface_name = open_file (hwmonx_name); 39 | 40 | // thank u, next 41 | if (interface_name == "") continue; 42 | 43 | if (interface_name == "coretemp" || 44 | interface_name == "k10temp" || 45 | interface_name == "cpu_thermal" 46 | ) { 47 | debug ("Found HWMON CPU Interface: %s in: %s", interface_name, hwmonx_name); 48 | this.parse (cpu_paths_parser, hwmonx); 49 | 50 | } else if (interface_name == "amdgpu") { 51 | debug ("Found HWMON GPU Interface: %s", interface_name); 52 | this.parse (gpu_paths_parser, hwmonx); 53 | 54 | } else if (interface_name == "nvme") { 55 | debug ("Found HWMON NVMe Interface: %s", interface_name); 56 | this.parse (nvme_paths_parser, hwmonx); 57 | 58 | } else if (interface_name == "iwlwifi_1") { 59 | debug ("Found HWMON iwlwifi Interface: %s", interface_name); 60 | this.parse (iwlwifi_paths_parser, hwmonx); 61 | 62 | } else { 63 | debug ("Found unknown HWMON Interface: %s", interface_name); 64 | } 65 | } 66 | } catch (FileError e) { 67 | warning ("Could not open dir: %s", e.message); 68 | } 69 | } 70 | 71 | private void parse (IHwmonPathsParserInterface parser, string hwmonx) { 72 | try { 73 | string ? hwmonx_prop = null; 74 | Dir hwmonx_dir = Dir.open (Path.build_filename (HWMON_PATH, hwmonx), 0); 75 | 76 | while (( hwmonx_prop = hwmonx_dir.read_name ()) != null) { 77 | parser.add_path (Path.build_filename (HWMON_PATH, hwmonx, hwmonx_prop)); 78 | } 79 | parser.parse (); 80 | 81 | } catch (FileError e) { 82 | warning ("Could not open dir: %s", e.message); 83 | } 84 | 85 | } 86 | 87 | private string open_file (string filename) { 88 | try { 89 | string read; 90 | if (!FileUtils.test (filename, FileTest.IS_REGULAR)) return ""; 91 | FileUtils.get_contents (filename, out read); 92 | return read.replace ("\n", ""); 93 | } catch (FileError e) { 94 | warning ("%s", e.message); 95 | return ""; 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/Resources/Hwmon/HwmonPathsParserCPU.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Monitor.HwmonPathsParserCPU : Object, IHwmonPathsParserInterface { 7 | 8 | public string name { get; protected set; } 9 | 10 | private Gee.HashMap _temperatures = new Gee.HashMap (); 11 | public Gee.HashMap temperatures = new Gee.HashMap (); 12 | 13 | protected Gee.HashSet all_paths { get; protected set; } 14 | 15 | construct { 16 | all_paths = new Gee.HashSet (); 17 | } 18 | 19 | public void parse () { 20 | foreach (var path in all_paths) { 21 | var basename = Path.get_basename (path); 22 | if (basename.contains ("name")) { 23 | this.name = open_file (path); 24 | } else if (basename.contains ("temp")) { 25 | debug ("Found HWMON CPU temperature interface path: %s", basename); 26 | if (!_temperatures.has_key (basename[4])) { 27 | _temperatures.set (basename[4], new HwmonTemperature ()); 28 | } 29 | 30 | if (basename.contains ("label")) { 31 | _temperatures.get (basename[4]).label = open_file (path); 32 | } else if (basename.contains ("input")) { 33 | _temperatures.get (basename[4]).input = path; 34 | } else if (basename.contains ("crit")) { 35 | _temperatures.get (basename[4]).crit = path; 36 | } else if (basename.contains ("crit_hyst")) { 37 | _temperatures.get (basename[4]).crit_hyst = path; 38 | } else if (basename.contains ("emergency")) { 39 | _temperatures.get (basename[4]).emergency = path; 40 | } else if (basename.contains ("max")) { 41 | _temperatures.get (basename[4]).max = path; 42 | } else if (basename.contains ("min")) { 43 | _temperatures.get (basename[4]).min = path; 44 | } 45 | } 46 | } 47 | 48 | foreach (var holder in _temperatures.values) { 49 | if (holder.label != null) { 50 | this.temperatures.set (holder.label, holder); 51 | debug ("🌡️ Parsed HWMON CPU temperature interface: %s", holder.label); 52 | } else { 53 | 54 | temperatures.set (this.name, holder); 55 | debug ("🌡️ Parsed HWMON CPU temperature interface %s", this.name); 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Resources/Hwmon/HwmonPathsParserIwlwifi.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Monitor.HwmonPathsParserIwlwifi : Object, IHwmonPathsParserInterface { 7 | 8 | public string name { get; protected set; } 9 | 10 | private Gee.HashMap _temperatures = new Gee.HashMap (); 11 | public Gee.HashMap temperatures = new Gee.HashMap (); 12 | 13 | protected Gee.HashSet all_paths { get; protected set; } 14 | 15 | construct { 16 | all_paths = new Gee.HashSet (); 17 | } 18 | 19 | public void parse () { 20 | foreach (var path in all_paths) { 21 | var basename = Path.get_basename (path); 22 | if (basename.contains ("name")) { 23 | this.name = open_file (path); 24 | } else if (basename.contains ("temp")) { 25 | debug ("Found HWMON iwlwifi temperature interface path: %s", basename); 26 | if (!_temperatures.has_key (basename[4])) { 27 | _temperatures.set (basename[4], new HwmonTemperature ()); 28 | } 29 | 30 | if (basename.contains ("label")) { 31 | _temperatures.get (basename[4]).label = open_file (path); 32 | } else if (basename.contains ("input")) { 33 | _temperatures.get (basename[4]).input = path; 34 | } else if (basename.contains ("crit")) { 35 | _temperatures.get (basename[4]).crit = path; 36 | } else if (basename.contains ("crit_hyst")) { 37 | _temperatures.get (basename[4]).crit_hyst = path; 38 | } else if (basename.contains ("emergency")) { 39 | _temperatures.get (basename[4]).emergency = path; 40 | } else if (basename.contains ("max")) { 41 | _temperatures.get (basename[4]).max = path; 42 | } else if (basename.contains ("min")) { 43 | _temperatures.get (basename[4]).min = path; 44 | } 45 | } 46 | } 47 | 48 | foreach (var paths_holder in _temperatures.values) { 49 | if (paths_holder.label != null) { 50 | this.temperatures.set (paths_holder.label, paths_holder); 51 | debug ("🌡️ Parsed HWMON iwlwifi temperature interface: %s", paths_holder.label); 52 | 53 | } else { 54 | // let's just hope that there is always one temp_input per iwlwifi 55 | temperatures.set (this.name, paths_holder); 56 | debug ("🌡️ Parsed HWMON iwlwifi temperature interface: %s", this.name); 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Resources/Hwmon/HwmonPathsParserNVMe.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Monitor.HwmonPathsParserNVMe : Object, IHwmonPathsParserInterface { 7 | 8 | public string name { get; protected set; } 9 | 10 | private Gee.HashMap _temperatures = new Gee.HashMap (); 11 | public Gee.HashMap temperatures = new Gee.HashMap (); 12 | 13 | protected Gee.HashSet all_paths { get; protected set; } 14 | 15 | construct { 16 | all_paths = new Gee.HashSet (); 17 | } 18 | 19 | public void parse () { 20 | foreach (var path in all_paths) { 21 | var basename = Path.get_basename (path); 22 | if (basename.contains ("name")) { 23 | this.name = basename; 24 | } else if (basename.contains ("temp")) { 25 | debug ("Found HWMON NVMe temperature interface path: %s", basename); 26 | if (!_temperatures.has_key (basename[4])) { 27 | _temperatures.set (basename[4], new HwmonTemperature ()); 28 | } 29 | 30 | if (basename.contains ("label")) { 31 | _temperatures.get (basename[4]).label = open_file (path); 32 | } else if (basename.contains ("input")) { 33 | _temperatures.get (basename[4]).input = path; 34 | } else if (basename.contains ("crit")) { 35 | _temperatures.get (basename[4]).crit = path; 36 | } else if (basename.contains ("crit_hyst")) { 37 | _temperatures.get (basename[4]).crit_hyst = path; 38 | } else if (basename.contains ("emergency")) { 39 | _temperatures.get (basename[4]).emergency = path; 40 | } else if (basename.contains ("max")) { 41 | _temperatures.get (basename[4]).max = path; 42 | } else if (basename.contains ("min")) { 43 | _temperatures.get (basename[4]).min = path; 44 | } 45 | } 46 | } 47 | 48 | foreach (var paths_holder in _temperatures.values) { 49 | temperatures.set (paths_holder.label, paths_holder); 50 | debug ("🌡️ Parsed HWMON NVMe temperature interface: %s", paths_holder.label); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Resources/Hwmon/HwmonPower.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | // This struct holds paths to temperature data 7 | // Learn more: https://www.kernel.org/doc/html/v5.11/gpu/amdgpu.html#hwmon-interfaces 8 | 9 | [Compact] 10 | public class Monitor.HwmonPower : Object { 11 | // average power used by the GPU in microWatts 12 | public string average; 13 | 14 | // average power used by the GPU in microWatts 15 | public string cap_min; 16 | 17 | // maximum cap supported in microWatts 18 | public string cap_max; 19 | 20 | // selected power cap in microWatts 21 | public string cap; 22 | } 23 | -------------------------------------------------------------------------------- /src/Resources/Hwmon/HwmonTemperature.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | // This class holds paths to temperature data 7 | // returns contents of the file as a string 8 | // Learn more: https://www.kernel.org/doc/html/v5.11/gpu/amdgpu.html#hwmon-interfaces 9 | 10 | [Compact] 11 | public class Monitor.HwmonTemperature : Object { 12 | // temperature channel label 13 | // temp2_label and temp3_label are supported on SOC15 dGPUs only 14 | public string _label; 15 | public string label { 16 | get { 17 | if (_label == null) return ""; 18 | return _label; 19 | } 20 | set { 21 | _label = value; 22 | } 23 | } 24 | // the on die temperature in millidegrees Celsius 25 | // temp2_input and temp3_input are supported on SOC15 dGPUs only 26 | private string _input; 27 | public string input { 28 | owned get { 29 | return open_file (_input); 30 | } 31 | set { 32 | _input = value; 33 | } 34 | } 35 | 36 | // temperature critical max value in millidegrees Celsius 37 | // temp2_crit and temp3_crit are supported on SOC15 dGPUs only 38 | public string ? crit; 39 | 40 | // temperature hysteresis for critical limit in millidegrees Celsius 41 | // temp2_crit_hyst and temp3_crit_hyst are supported on SOC15 dGPUs only 42 | public string ? crit_hyst; 43 | 44 | // temperature emergency max value(asic shutdown) in millidegrees Celsius 45 | // these are supported on SOC15 dGPUs only 46 | public string ? emergency; 47 | 48 | // Temperature max value. 49 | public string ? max; 50 | 51 | // Temperature min value. 52 | public string ? min; 53 | 54 | public string open_file (string filename) { 55 | try { 56 | string read; 57 | FileUtils.get_contents (filename, out read); 58 | return read.replace ("\n", ""); 59 | } catch (FileError e) { 60 | warning ("%s", e.message); 61 | return ""; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Resources/Hwmon/HwmonVoltage.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | // This struct holds paths to temperature data 7 | // Learn more: https://www.kernel.org/doc/html/v5.11/gpu/amdgpu.html#hwmon-interfaces 8 | 9 | [Compact] 10 | public class Monitor.HwmonVoltage : Object { 11 | // voltage channel label 12 | public string label; 13 | 14 | // in0_input: the voltage on the GPU in millivolts 15 | // in1_input: the voltage on the Northbridge in millivolts 16 | public string input; 17 | } 18 | -------------------------------------------------------------------------------- /src/Resources/Hwmon/IHwmonPathsParserInterface.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public interface Monitor.IHwmonPathsParserInterface : Object { 7 | 8 | public abstract string name { get; protected set; } 9 | 10 | protected abstract Gee.HashSet all_paths { get; protected set; } 11 | 12 | public abstract void parse (); 13 | 14 | public virtual void add_path (string path) { 15 | all_paths.add (path); 16 | } 17 | 18 | public virtual string open_file (string filename) { 19 | try { 20 | string read; 21 | FileUtils.get_contents (filename, out read); 22 | return read.replace ("\n", ""); 23 | } catch (FileError e) { 24 | warning ("%s", e.message); 25 | return ""; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Resources/Memory.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | namespace Monitor { 7 | public class Memory : Object { 8 | public double total = 0; 9 | public double used = 0; 10 | public double shared; 11 | public double buffer; 12 | public double cached; 13 | public double locked; 14 | 15 | private GTop.Memory mem; 16 | 17 | public uint used_percentage { 18 | get { 19 | return (uint) (Math.round ((used / total) * 100)); 20 | } 21 | } 22 | 23 | public uint shared_percentage { 24 | get { 25 | return (uint) (Math.round ((shared / used) * 100)); 26 | } 27 | } 28 | 29 | public uint buffer_percentage { 30 | get { 31 | return (uint) (Math.round ((buffer / used) * 100)); 32 | } 33 | } 34 | 35 | public uint cached_percentage { 36 | get { 37 | return (uint) (Math.round ((cached / used) * 100)); 38 | } 39 | } 40 | 41 | public uint locked_percentage { 42 | get { 43 | return (uint) (Math.round ((locked / used) * 100)); 44 | } 45 | } 46 | 47 | public void update () { 48 | GTop.get_mem (out mem); 49 | total = (double) (mem.total); 50 | used = (double) mem.user; 51 | shared = (double) (mem.shared); 52 | buffer = (double) (mem.buffer); 53 | cached = (double) (mem.cached); 54 | locked = (double) (mem.locked); 55 | } 56 | 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Resources/Network.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: LGPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2020 Tudor Plugaru 4 | * 2020 stsdc 5 | * 6 | * Authored by: Tudor Plugaru 7 | */ 8 | 9 | public class Monitor.Network : GLib.Object { 10 | public int bytes_in; 11 | private int bytes_in_old; 12 | 13 | public int bytes_out; 14 | private int bytes_out_old; 15 | 16 | // flag first run 17 | // bc first calculasion is wrong 18 | private bool dumb_flag; 19 | 20 | public Network () { 21 | bytes_in = 0; 22 | bytes_in_old = 0; 23 | bytes_out = 0; 24 | bytes_out_old = 0; 25 | dumb_flag = true; 26 | } 27 | 28 | public void update () { 29 | GTop.NetList netlist; 30 | GTop.NetLoad netload; 31 | 32 | var devices = GTop.get_netlist (out netlist); 33 | var bytes_out_new = 0; 34 | var bytes_in_new = 0; 35 | for (uint j = 0; j < netlist.number; ++j) { 36 | var device = devices[j]; 37 | if (device != "lo" && device.substring (0, 3) != "tun") { 38 | GTop.get_netload (out netload, device); 39 | 40 | bytes_out_new += (int) netload.bytes_out; 41 | bytes_in_new += (int) netload.bytes_in; 42 | } 43 | } 44 | 45 | if (!dumb_flag) { 46 | bytes_out = (bytes_out_new - bytes_out_old) / MonitorApp.settings.get_int ("update-time"); 47 | bytes_in = (bytes_in_new - bytes_in_old) / MonitorApp.settings.get_int ("update-time"); 48 | } 49 | 50 | bytes_out_old = bytes_out_new; 51 | bytes_in_old = bytes_in_new; 52 | 53 | 54 | dumb_flag = false; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/Resources/Resources.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Monitor.Resources : Object { 7 | public CPU cpu; 8 | public Memory memory; 9 | public Swap swap; 10 | public Network network; 11 | public Storage storage; 12 | public Gee.ArrayList gpu_list = new Gee.ArrayList (); 13 | private HwmonPathParser hwmon_path_parser; 14 | 15 | construct { 16 | hwmon_path_parser = new HwmonPathParser (); 17 | 18 | memory = new Memory (); 19 | cpu = new CPU (); 20 | swap = new Swap (); 21 | network = new Network (); 22 | storage = new Storage (); 23 | 24 | detect_gpu_pci_devices (); 25 | 26 | cpu.temperatures = hwmon_path_parser.cpu_paths_parser.temperatures; 27 | 28 | update (); 29 | } 30 | 31 | public void update () { 32 | Timeout.add_seconds (MonitorApp.settings.get_int ("update-time"), () => { 33 | new Thread ("update-resources", () => { 34 | cpu.update (); 35 | memory.update (); 36 | network.update (); 37 | storage.update (); 38 | 39 | foreach (var gpu in gpu_list) { 40 | gpu.update (); 41 | } 42 | }); 43 | return true; 44 | }); 45 | } 46 | 47 | private void detect_gpu_pci_devices () { 48 | Pci.Access pci_access = new Pci.Access (); 49 | 50 | pci_access.init (); 51 | pci_access.scan_bus (); 52 | 53 | char namebuf[1024]; 54 | 55 | for (unowned Pci.Dev pci_device = pci_access.devices; pci_device != null; pci_device = pci_device.next) { 56 | pci_device.fill_info (Pci.FILL_IDENT | Pci.FILL_BASES | Pci.FILL_CLASS_EXT | Pci.FILL_LABEL | Pci.FILL_CLASS); 57 | string name = pci_access.lookup_name (namebuf, Pci.LookupMode.DEVICE, pci_device.vendor_id, pci_device.device_id); 58 | 59 | // Looking for a specific PCI device class 60 | if (pci_device.device_class == Utils.PCI_CLASS_VGA_CONTROLLER || pci_device.device_class == Utils.PCI_CLASS_3D_CONTROLLER) { 61 | // print (" %04x:%02x:%02x.%d\n", pci_device.domain_16, pci_device.bus, pci_device.dev, pci_device.func); 62 | 63 | switch (pci_device.vendor_id) { 64 | case Utils.PCI_VENDOR_ID_INTEL: 65 | debug ("PCI device: GPU: Intel %s", name); 66 | IGPU gpu = new GPUIntel (pci_access, pci_device); 67 | gpu_list.add (gpu); 68 | break; 69 | 70 | case Utils.PCI_VENDOR_ID_NVIDIA: 71 | debug ("PCI device: GPU: nVidia %s", name); 72 | IGPU gpu = new GPUNvidia (pci_access, pci_device); 73 | gpu_list.add (gpu); 74 | break; 75 | 76 | case Utils.PCI_VENDOR_ID_AMD: 77 | debug ("PCI device: GPU: AMD %s", name); 78 | IGPU gpu = new GPUAmd (pci_access, pci_device); 79 | gpu.hwmon_temperatures = hwmon_path_parser.gpu_paths_parser.temperatures; 80 | gpu_list.add (gpu); 81 | break; 82 | 83 | default: 84 | warning ("GPU: Unknown: 0x%llX : %s", pci_device.vendor_id, name); 85 | break; 86 | } 87 | } else { 88 | debug ("PCI device: vendor: 0x%llX class:0x%llX %s", pci_device.vendor_id, pci_device.device_class, name); 89 | } 90 | } 91 | } 92 | 93 | public ResourcesSerialized serialize () { 94 | 95 | // quick fix; so no need to comment out GPU 96 | // code for Indicator and Preferences 97 | IGPU gpu = gpu_list.size > 0 ? gpu_list.first () : null; 98 | 99 | return ResourcesSerialized () { 100 | cpu_percentage = cpu.percentage, 101 | cpu_frequency = cpu.frequency, 102 | cpu_temperature = cpu.temperature_mean, 103 | memory_percentage = memory.used_percentage, 104 | memory_used = memory.used, 105 | memory_total = memory.total, 106 | swap_percentage = swap.percentage, 107 | swap_used = swap.used, 108 | swap_total = swap.total, 109 | network_up = network.bytes_out, 110 | network_down = network.bytes_in, 111 | gpu_percentage = gpu != null ? gpu.percentage : 0, 112 | gpu_memory_percentage = gpu != null ? gpu.memory_percentage : 0, 113 | gpu_memory_used = gpu != null ? gpu.memory_vram_used : 0, 114 | gpu_memory_total = gpu != null ? gpu.memory_vram_total : 0, 115 | gpu_temperature = gpu != null ? gpu.temperature : 0 116 | }; 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/Resources/ResourcesSerialized.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public struct ResourcesSerialized { 7 | public int cpu_percentage; 8 | public double cpu_frequency; 9 | public double cpu_temperature; 10 | public uint memory_percentage; 11 | public double memory_used; 12 | public double memory_total; 13 | public int swap_percentage; 14 | public double swap_used; 15 | public double swap_total; 16 | public int network_up; 17 | public int network_down; 18 | public int gpu_percentage; 19 | public uint gpu_memory_percentage; 20 | public double gpu_memory_used; 21 | public double gpu_memory_total; 22 | public double gpu_temperature; 23 | } 24 | -------------------------------------------------------------------------------- /src/Resources/Storage/Disk.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2021 Dirli 4 | * 2021 stsdc 5 | */ 6 | 7 | public class Monitor.Disk : GLib.Object { 8 | public string model; 9 | public uint64 size; 10 | public uint64 free; 11 | public string revision; 12 | public string id; 13 | public string device; 14 | public string partition; 15 | public GLib.Icon drive_icon; 16 | 17 | private Gee.ArrayList volumes = new Gee.ArrayList (); 18 | 19 | public Disk (UDisks.Drive drive) { 20 | model = drive.model; 21 | size = drive.size; 22 | revision = drive.revision; 23 | id = drive.id; 24 | free = 0; 25 | } 26 | 27 | public void add_volume (Volume vol) { 28 | volumes.add (vol); 29 | free = free + vol.free; 30 | } 31 | 32 | public Gee.ArrayList get_volumes () { 33 | var volumes_arr = new Gee.ArrayList (); 34 | 35 | volumes.foreach ((vol) => { 36 | 37 | volumes_arr.add (vol); 38 | 39 | return true; 40 | }); 41 | 42 | volumes_arr.sort (compare_volumes); 43 | 44 | return volumes_arr; 45 | } 46 | 47 | private int compare_volumes (Volume? vol1, Volume? vol2) { 48 | if (vol1 == null) { 49 | return (vol2 == null) ? 0 : -1; 50 | } 51 | 52 | if (vol2 == null) { 53 | return 1; 54 | } 55 | 56 | return GLib.strcmp (vol1.device, vol2.device); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Resources/Storage/StorageBlock.vala: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elementary/monitor/cce725f44e32e6474ba0580fa58aa2ac91c4a4f7/src/Resources/Storage/StorageBlock.vala -------------------------------------------------------------------------------- /src/Resources/Storage/StorageParser.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | class Monitor.StorageParser : Object { 7 | private const string BLOCKS_PATH = "/sys/block"; 8 | 9 | public Gee.ArrayList get_slaves_names (string volume_name) { 10 | Gee.ArrayList slaves_names = new Gee.ArrayList (); 11 | 12 | try { 13 | Dir slaves_dir = Dir.open (Path.build_filename (BLOCKS_PATH, volume_name, "slaves"), 0); 14 | 15 | string ? slave = null; 16 | 17 | while ((slave = slaves_dir.read_name ()) != null) { 18 | debug ("Found slave: " + slave); 19 | slaves_names.add (slave); 20 | } 21 | 22 | } catch (FileError e) { 23 | warning ("%s", e.message); 24 | } 25 | 26 | return slaves_names; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/Resources/Storage/Volume.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | [Compact] 7 | public class Monitor.Volume : Object { 8 | public string device; 9 | public string label; 10 | public string type; 11 | public string uuid; 12 | public string mount_point; 13 | public uint64 size; 14 | public uint64 free; 15 | public uint64 offset; 16 | 17 | // means the volume is only on one physical disk 18 | public bool strict_affiliation { public get; private set; } 19 | 20 | public Gee.ArrayList slaves = new Gee.ArrayList (); 21 | 22 | 23 | public Volume (UDisks.Block block) { 24 | device = block.device; 25 | label = block.id_label; 26 | type = block.id_type; 27 | size = block.size; 28 | uuid = block.id_uuid; 29 | } 30 | 31 | public void add_slave (string? new_slave) { 32 | check_affiliation (new_slave); 33 | slaves.add (new_slave); 34 | } 35 | 36 | private void check_affiliation (string new_slave) { 37 | if (slaves.size > 0) { 38 | foreach (string slave in slaves) { 39 | if (slave.contains (new_slave[0:3])) { 40 | strict_affiliation = true; 41 | debug ("Slave volume %s of %s is on the same disk as all other slave volumes", new_slave, device); 42 | } else { 43 | strict_affiliation = false; 44 | debug ("Slave volume %s of %s is on the same disk as all other slave volumes", new_slave, device); 45 | } 46 | } 47 | } else { 48 | debug ("First slave: %s", new_slave); 49 | strict_affiliation = true; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Resources/Swap.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Monitor.Swap : Object { 7 | public double total { get; private set; default = 0; } 8 | public double used { get; private set; default = 0; } 9 | 10 | private GTop.Swap swap; 11 | 12 | public int percentage { 13 | get { 14 | update (); 15 | 16 | // The total amount of the swap is 0 when it is unavailable 17 | if (total == 0) { 18 | return 0; 19 | } else { 20 | return (int) (Math.round ((used / total) * 100)); 21 | } 22 | } 23 | } 24 | 25 | public Swap () { 26 | } 27 | 28 | private void update () { 29 | GTop.get_swap (out swap); 30 | total = (double) (swap.total / 1024 / 1024) / 1000; 31 | used = (double) (swap.used / 1024 / 1024) / 1000; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/Services/Appearance.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Monitor.Appearance : Object { 7 | public static void set_prefered_style () { 8 | var granite_settings = Granite.Settings.get_default (); 9 | var gtk_settings = Gtk.Settings.get_default (); 10 | 11 | bool is_dark = granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK; 12 | gtk_settings.gtk_application_prefer_dark_theme = is_dark; 13 | 14 | 15 | var provider = new Gtk.CssProvider (); 16 | 17 | if (is_dark) { 18 | provider.load_from_resource ("/io/elementary/monitor/monitor-dark.css"); 19 | } else { 20 | provider.load_from_resource ("/io/elementary/monitor/monitor-light.css"); 21 | } 22 | 23 | Gtk.StyleContext.add_provider_for_screen (Gdk.Screen.get_default (), provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); 24 | 25 | // We listen to changes in Granite.Settings and update our app if the user changes their preference 26 | granite_settings.notify["prefers-color-scheme"].connect (() => { 27 | is_dark = granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK; 28 | gtk_settings.gtk_application_prefer_dark_theme = is_dark; 29 | 30 | if (is_dark) { 31 | provider.load_from_resource ("/io/elementary/monitor/monitor-dark.css"); 32 | } else { 33 | provider.load_from_resource ("/io/elementary/monitor/monitor-light.css"); 34 | } 35 | }); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Services/DBusServer.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | [DBus (name = "io.elementary.monitor")] 7 | public class Monitor.DBusServer : Object { 8 | private const string DBUS_NAME = "io.elementary.monitor"; 9 | private const string DBUS_PATH = "/io/elementary/monitor"; 10 | 11 | private static GLib.Once instance; 12 | 13 | public static unowned DBusServer get_default () { 14 | return instance.once (() => { return new DBusServer (); }); 15 | } 16 | 17 | public signal void update (ResourcesSerialized data); 18 | public signal void indicator_state (bool state); 19 | public signal void indicator_cpu_state (bool state); 20 | public signal void indicator_cpu_frequency_state (bool state); 21 | public signal void indicator_cpu_temperature_state (bool state); 22 | public signal void indicator_memory_state (bool state); 23 | public signal void indicator_network_up_state (bool state); 24 | public signal void indicator_network_down_state (bool state); 25 | public signal void indicator_gpu_state (bool state); 26 | public signal void indicator_gpu_memory_state (bool state); 27 | public signal void indicator_gpu_temperature_state (bool state); 28 | public signal void quit (); 29 | public signal void show (); 30 | 31 | construct { 32 | Bus.own_name ( 33 | BusType.SESSION, 34 | DBUS_NAME, 35 | BusNameOwnerFlags.NONE, 36 | (connection) => on_bus_aquired (connection), 37 | () => {}, 38 | null 39 | ); 40 | } 41 | 42 | public void quit_monitor () throws IOError, DBusError { 43 | quit (); 44 | } 45 | 46 | public void show_monitor () throws IOError, DBusError { 47 | show (); 48 | } 49 | 50 | private void on_bus_aquired (DBusConnection conn) { 51 | try { 52 | debug ("DBus registered!"); 53 | conn.register_object ("/io/elementary/monitor", get_default ()); 54 | } catch (Error e) { 55 | error (e.message); 56 | } 57 | } 58 | 59 | } 60 | 61 | [DBus (name = "io.elementary.monitor")] 62 | public errordomain DBusServerError { 63 | SOME_ERROR 64 | } 65 | -------------------------------------------------------------------------------- /src/Views/ProcessView/ProcessInfoView/OpenFilesTreeView.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Monitor.OpenFilesTreeView : Gtk.TreeView { 7 | public new OpenFilesTreeViewModel model; 8 | private Gtk.TreeViewColumn path_column; 9 | private Regex ? regex; 10 | 11 | public signal void process_selected (Process process); 12 | 13 | public OpenFilesTreeView (OpenFilesTreeViewModel model) { 14 | this.model = model; 15 | /* *INDENT-OFF* */ 16 | regex = /(?i:^.*\.(xpm|png)$)/; // vala-lint=space-before-paren, 17 | /* *INDENT-ON* */ 18 | 19 | show_expanders = false; 20 | 21 | // setup name column 22 | path_column = new Gtk.TreeViewColumn (); 23 | path_column.title = _("Opened files"); 24 | path_column.expand = true; 25 | path_column.min_width = 250; 26 | path_column.set_sort_column_id (Column.NAME); 27 | 28 | var icon_cell = new Gtk.CellRendererPixbuf (); 29 | path_column.pack_start (icon_cell, false); 30 | // path_column.add_attribute (icon_cell, "icon_name", Column.ICON); 31 | path_column.set_cell_data_func (icon_cell, icon_cell_layout); 32 | 33 | var name_cell = new Gtk.CellRendererText (); 34 | name_cell.ellipsize = Pango.EllipsizeMode.END; 35 | name_cell.set_fixed_height_from_font (1); 36 | path_column.pack_start (name_cell, false); 37 | path_column.add_attribute (name_cell, "text", Column.NAME); 38 | insert_column (path_column, -1); 39 | 40 | // resize all of the columns 41 | columns_autosize (); 42 | 43 | set_model (model); 44 | 45 | hadjustment = null; 46 | vadjustment = null; 47 | vexpand = true; 48 | 49 | } 50 | 51 | public void icon_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer icon_cell, Gtk.TreeModel model, Gtk.TreeIter iter) { 52 | try { 53 | var icon = Icon.new_for_string ("emblem-documents-symbolic"); 54 | ((Gtk.CellRendererPixbuf)icon_cell).icon_name = icon.to_string (); 55 | } catch (Error e) { 56 | warning (e.message); 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/Views/ProcessView/ProcessInfoView/Preventor.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Monitor.Preventor : Gtk.Stack { 7 | private Gtk.Box preventive_action_bar; 8 | private Gtk.Label confirmation_label; 9 | private Gtk.Button confirm_button; 10 | private Gtk.Button deny_button; 11 | 12 | private Gtk.Widget child_widget; 13 | 14 | public signal void confirmed (bool is_confirmed); 15 | 16 | construct { 17 | valign = Gtk.Align.END; 18 | 19 | preventive_action_bar = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); 20 | preventive_action_bar.valign = Gtk.Align.START; 21 | preventive_action_bar.halign = Gtk.Align.END; 22 | preventive_action_bar.margin_top = 10; 23 | 24 | 25 | confirmation_label = new Gtk.Label (_("Are you sure you want to do this?")); 26 | confirmation_label.margin_end = 10; 27 | 28 | confirm_button = new Gtk.Button.with_label (_("Yes")); 29 | confirm_button.margin_end = 10; 30 | confirm_button.get_style_context ().add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION); 31 | 32 | deny_button = new Gtk.Button.with_label (_("No")); 33 | 34 | preventive_action_bar.add (confirmation_label); 35 | preventive_action_bar.add (confirm_button); 36 | preventive_action_bar.add (deny_button); 37 | } 38 | 39 | public Preventor (Gtk.Widget _child, string name) { 40 | child_widget = _child; 41 | add_named (child_widget, name); 42 | add_named (preventive_action_bar, "preventive_action_bar"); 43 | 44 | deny_button.clicked.connect (() => { 45 | set_transition_type (Gtk.StackTransitionType.SLIDE_UP); 46 | set_visible_child (child_widget); 47 | confirmed (false); 48 | }); 49 | 50 | confirm_button.clicked.connect (() => { 51 | set_transition_type (Gtk.StackTransitionType.SLIDE_UP); 52 | set_visible_child (child_widget); 53 | confirmed (true); 54 | }); 55 | } 56 | 57 | public void set_prevention (string confirmation_text) { 58 | set_transition_type (Gtk.StackTransitionType.SLIDE_DOWN); 59 | confirmation_label.set_text (_(confirmation_text)); 60 | set_visible_child (preventive_action_bar); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Monitor.ProcessInfoCPURAM : Gtk.Grid { 7 | private Gtk.Label cpu_label; 8 | private Gtk.Label ram_label; 9 | 10 | private Chart cpu_chart; 11 | private Chart ram_chart; 12 | 13 | construct { 14 | column_spacing = 6; 15 | row_spacing = 6; 16 | vexpand = false; 17 | column_homogeneous = true; 18 | row_homogeneous = false; 19 | 20 | cpu_chart = new Chart (1); 21 | cpu_chart.set_serie_color (0, Utils.Colors.get_rgba_color (Utils.Colors.LIME_300)); 22 | ram_chart = new Chart (1); 23 | ram_chart.set_serie_color (0, Utils.Colors.get_rgba_color (Utils.Colors.LIME_300)); 24 | 25 | cpu_chart.height_request = 60; 26 | ram_chart.height_request = 60; 27 | 28 | var cpu_graph_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); 29 | cpu_graph_box.add (cpu_chart); 30 | 31 | var mem_graph_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); 32 | mem_graph_box.add (ram_chart); 33 | 34 | cpu_label = new Gtk.Label ("CPU: " + Utils.NO_DATA); 35 | cpu_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL); 36 | cpu_label.halign = Gtk.Align.START; 37 | 38 | ram_label = new Gtk.Label ("RAM: " + Utils.NO_DATA); 39 | ram_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL); 40 | ram_label.halign = Gtk.Align.START; 41 | 42 | attach (cpu_label, 0, 0, 1, 1); 43 | attach (ram_label, 1, 0, 1, 1); 44 | 45 | attach (cpu_graph_box, 0, 1, 1, 1); 46 | attach (mem_graph_box, 1, 1, 1, 1); 47 | } 48 | 49 | public void set_charts_data (Process process) { 50 | cpu_chart.preset_data (0, process.cpu_percentage_history); 51 | ram_chart.preset_data (0, process.mem_percentage_history); 52 | } 53 | 54 | public void update (Process process) { 55 | cpu_label.set_text ((_("CPU: %.1f%%")).printf (process.cpu_percentage)); 56 | ram_label.set_text ((_("RAM: %.1f%%")).printf (process.mem_percentage)); 57 | 58 | cpu_chart.update (0, process.cpu_percentage); 59 | ram_chart.update (0, process.mem_percentage); 60 | } 61 | 62 | public void clear_graphs () { 63 | cpu_chart.clear (); 64 | ram_chart.clear (); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Monitor.ProcessInfoHeader : Gtk.Grid { 7 | private Gtk.Image icon; 8 | public Gtk.Label state; 9 | public Gtk.Label application_name; 10 | public LabelRoundy pid; 11 | 12 | public LabelRoundy ppid; 13 | public LabelRoundy pgrp; 14 | public LabelRoundy nice; 15 | public LabelRoundy priority; 16 | public LabelRoundy num_threads; 17 | public LabelRoundy username; 18 | 19 | private Regex ? regex; 20 | 21 | construct { 22 | column_spacing = 12; 23 | 24 | /* *INDENT-OFF* */ 25 | regex = /(?i:^.*\.(xpm|png)$)/; // vala-lint=space-before-paren, 26 | /* *INDENT-ON* */ 27 | 28 | icon = new Gtk.Image.from_icon_name ("application-x-executable", Gtk.IconSize.DIALOG); 29 | icon.set_pixel_size (64); 30 | icon.valign = Gtk.Align.END; 31 | 32 | state = new Gtk.Label ("?"); 33 | state.halign = Gtk.Align.START; 34 | state.get_style_context ().add_class ("state_badge"); 35 | 36 | var icon_container = new Gtk.Fixed (); 37 | icon_container.put (icon, 0, 0); 38 | icon_container.put (state, -5, 48); 39 | 40 | application_name = new Gtk.Label (_("N/A")); 41 | application_name.get_style_context ().add_class ("h2"); 42 | application_name.ellipsize = Pango.EllipsizeMode.END; 43 | application_name.tooltip_text = _("N/A"); 44 | application_name.halign = Gtk.Align.START; 45 | application_name.valign = Gtk.Align.START; 46 | 47 | pid = new LabelRoundy (_("PID")); 48 | nice = new LabelRoundy (_("NI")); 49 | priority = new LabelRoundy (_("PRI")); 50 | num_threads = new LabelRoundy (_("THR")); 51 | // ppid = new LabelRoundy (_("PPID")); 52 | // pgrp = new LabelRoundy (_("PGRP")); 53 | 54 | // TODO: tooltip_text UID 55 | username = new LabelRoundy (""); 56 | 57 | var wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); 58 | wrapper.add (pid); 59 | wrapper.add (priority); 60 | wrapper.add (nice); 61 | wrapper.add (num_threads); 62 | wrapper.add (username); 63 | 64 | attach (icon_container, 0, 0, 1, 2); 65 | attach (application_name, 1, 0, 3, 1); 66 | attach (wrapper, 1, 1, 1, 1); 67 | } 68 | 69 | public void update (Process process) { 70 | application_name.set_text (process.application_name); 71 | application_name.tooltip_text = process.command; 72 | pid.set_text (process.stat.pid.to_string ()); 73 | nice.set_text (process.stat.nice.to_string ()); 74 | priority.set_text (process.stat.priority.to_string ()); 75 | 76 | if (process.uid == 0) { 77 | username.val.get_style_context ().add_class ("username-root"); 78 | username.val.get_style_context ().remove_class ("username-other"); 79 | username.val.get_style_context ().remove_class ("username-current"); 80 | } else if (process.uid == (int) Posix.getuid ()) { 81 | username.val.get_style_context ().add_class ("username-current"); 82 | username.val.get_style_context ().remove_class ("username-other"); 83 | username.val.get_style_context ().remove_class ("username-root"); 84 | } else { 85 | username.val.get_style_context ().add_class ("username-other"); 86 | username.val.get_style_context ().remove_class ("username-root"); 87 | username.val.get_style_context ().remove_class ("username-current"); 88 | } 89 | 90 | username.set_text (process.username); 91 | username.tooltip_text = process.uid.to_string (); 92 | num_threads.set_text (process.stat.num_threads.to_string ()); 93 | state.set_text (process.stat.state); 94 | state.tooltip_text = set_state_tooltip (); 95 | num_threads.set_text (process.stat.num_threads.to_string ()); 96 | set_icon (process); 97 | } 98 | 99 | private void set_icon (Process process) { 100 | // this construction should be somewhere else 101 | var icon_name = process.icon.to_string (); 102 | 103 | if (!regex.match (icon_name)) { 104 | icon.set_from_icon_name (icon_name, Gtk.IconSize.DIALOG); 105 | } else { 106 | try { 107 | var pixbuf = new Gdk.Pixbuf.from_file_at_size (icon_name, 48, -1); 108 | icon.set_from_pixbuf (pixbuf); 109 | } catch (Error e) { 110 | warning (e.message); 111 | } 112 | } 113 | } 114 | 115 | private string set_state_tooltip () { 116 | switch (state.label) { 117 | case "D": 118 | return _("The app is waiting in an uninterruptible disk sleep"); 119 | case "I": 120 | return _("Idle kernel thread"); 121 | case "R": 122 | return _("The process is running or runnable (on run queue)"); 123 | case "S": 124 | return _("The process is in an interruptible sleep; waiting for an event to complete"); 125 | case "T": 126 | return _("The process is stopped by a job control signal"); 127 | case "t": 128 | return _("The process is stopped by a debugger during the tracing"); 129 | case "Z": 130 | return _("The app is terminated but not reaped by its parent"); 131 | default: 132 | return ""; 133 | } 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Monitor.ProcessInfoIOStats : Gtk.Grid { 7 | private Gtk.Label rchar_label; 8 | private Gtk.Label wchar_label; 9 | private Gtk.Label syscr_label; 10 | private Gtk.Label syscw_label; 11 | private Gtk.Label write_bytes_label; 12 | private Gtk.Label read_bytes_label; 13 | private Gtk.Label cancelled_write_bytes_label; 14 | 15 | public OpenFilesTreeView open_files_tree_view; 16 | 17 | construct { 18 | column_spacing = 6; 19 | row_spacing = 6; 20 | column_homogeneous = true; 21 | row_homogeneous = false; 22 | 23 | var opened_files_label = create_label (_("Opened files")); 24 | opened_files_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL); 25 | opened_files_label.margin_top = 24; 26 | 27 | var characters_label = create_label (_("Characters")); 28 | characters_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL); 29 | rchar_label = create_label (_("N/A")); 30 | wchar_label = create_label (_("N/A")); 31 | 32 | var system_calls_label = create_label (_("System calls")); 33 | system_calls_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL); 34 | syscr_label = create_label (_("N/A")); 35 | syscw_label = create_label (_("N/A")); 36 | 37 | var io_label = create_label (_("Read/Written")); 38 | io_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL); 39 | write_bytes_label = create_label (_("N/A")); 40 | read_bytes_label = create_label (_("N/A")); 41 | 42 | var cancelled_write_label = create_label (_("Cancelled write")); 43 | cancelled_write_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL); 44 | 45 | cancelled_write_bytes_label = create_label (Utils.NO_DATA); 46 | 47 | attach (io_label, 0, 1, 1, 1); 48 | attach (create_label_with_icon (read_bytes_label, "go-up-symbolic"), 0, 2, 1, 1); 49 | attach (create_label_with_icon (write_bytes_label, "go-down-symbolic"), 0, 3, 1, 1); 50 | 51 | attach (cancelled_write_label, 1, 1, 1, 1); 52 | attach (cancelled_write_bytes_label, 1, 2, 1, 1); 53 | 54 | // attach (opened_files_label, 0, 3, 3, 1); 55 | 56 | var model = new OpenFilesTreeViewModel (); 57 | var open_files_tree_view_scrolled = new Gtk.ScrolledWindow (null, null); 58 | open_files_tree_view = new OpenFilesTreeView (model); 59 | open_files_tree_view_scrolled.add (open_files_tree_view); 60 | attach (open_files_tree_view_scrolled, 0, 4, 3, 1); 61 | } 62 | 63 | public void update (Process process) { 64 | write_bytes_label.set_text (format_size ((uint64) process.io.write_bytes, IEC_UNITS)); 65 | read_bytes_label.set_text (format_size ((uint64) process.io.read_bytes, IEC_UNITS)); 66 | cancelled_write_bytes_label.set_text (format_size ((uint64) process.io.cancelled_write_bytes, IEC_UNITS)); 67 | } 68 | 69 | private Gtk.Label create_label (string text) { 70 | var label = new Gtk.Label (text); 71 | label.halign = Gtk.Align.START; 72 | return label; 73 | } 74 | 75 | private Gtk.Image create_icon (string icon_name) { 76 | var icon = new Gtk.Image (); 77 | icon.gicon = new ThemedIcon (icon_name); 78 | icon.halign = Gtk.Align.START; 79 | icon.pixel_size = 16; 80 | return icon; 81 | } 82 | 83 | private Gtk.Grid create_label_with_icon (Gtk.Label label, string icon_name) { 84 | var grid = new Gtk.Grid (); 85 | grid.column_spacing = 2; 86 | grid.attach (create_icon (icon_name), 0, 0, 1, 1); 87 | grid.attach (label, 1, 0, 1, 1); 88 | return grid; 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/Views/ProcessView/ProcessView.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Monitor.ProcessView : Gtk.Box { 7 | public TreeViewModel treeview_model; 8 | public CPUProcessTreeView process_tree_view; 9 | 10 | public ProcessInfoView process_info_view; 11 | 12 | construct { 13 | process_info_view = new ProcessInfoView (); 14 | 15 | // hide on startup 16 | process_info_view.no_show_all = true; 17 | } 18 | 19 | public ProcessView () { 20 | treeview_model = new TreeViewModel (); 21 | 22 | process_tree_view = new CPUProcessTreeView (treeview_model); 23 | process_tree_view.process_selected.connect ((process) => on_process_selected (process)); 24 | 25 | // making tree view scrollable 26 | var process_tree_view_scrolled = new Gtk.ScrolledWindow (null, null); 27 | process_tree_view_scrolled.add (process_tree_view); 28 | 29 | var paned = new Gtk.Paned (Gtk.Orientation.HORIZONTAL); 30 | paned.pack1 (process_tree_view_scrolled, true, false); 31 | paned.pack2 (process_info_view, false, false); 32 | // paned.set_min_position (200); 33 | paned.set_position (paned.max_position); 34 | paned.set_hexpand (true); 35 | 36 | add (paned); 37 | } 38 | 39 | public void on_process_selected (Process process) { 40 | process_info_view.process = process; 41 | process_info_view.no_show_all = false; 42 | // process_info_view.show_all (); 43 | } 44 | 45 | public void update () { 46 | new Thread ("update-processes", () => { 47 | Idle.add (() => { 48 | process_info_view.update (); 49 | treeview_model.process_manager.update_processes.begin (); 50 | 51 | return false; 52 | }); 53 | return true; 54 | }); 55 | 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/Views/SystemView/SystemCPUInfoPopover.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Monitor.SystemCPUInfoPopover : Gtk.Box { 7 | private CPU cpu; 8 | 9 | construct { 10 | margin = 12; 11 | orientation = Gtk.Orientation.VERTICAL; 12 | } 13 | 14 | 15 | public SystemCPUInfoPopover (CPU _cpu) { 16 | 17 | cpu = _cpu; 18 | 19 | var stack = new Gtk.Stack () { 20 | transition_type = Gtk.StackTransitionType.SLIDE_LEFT_RIGHT, 21 | height_request = 300, 22 | width_request = 400, 23 | margin_top = 12, 24 | }; 25 | 26 | stack.add_titled (general_page (), "general_page", _("General")); 27 | stack.add_titled (features_page (), "features_page", _("Features")); 28 | stack.add_titled (bugs_page (), "bugs_page", _("Bugs")); 29 | 30 | Gtk.StackSwitcher stack_switcher = new Gtk.StackSwitcher () { 31 | valign = Gtk.Align.CENTER, 32 | halign = Gtk.Align.CENTER, 33 | }; 34 | stack_switcher.set_stack (stack); 35 | 36 | add (stack_switcher); 37 | add (stack); 38 | } 39 | 40 | private Gtk.Label label (string text) { 41 | var label = new Gtk.Label (text) { 42 | halign = Gtk.Align.START, 43 | valign = Gtk.Align.CENTER, 44 | wrap = true, 45 | margin = 6, 46 | }; 47 | 48 | return label; 49 | } 50 | 51 | private Gtk.ListBox general_page () { 52 | var listbox = new Gtk.ListBox () { 53 | activate_on_single_click = false 54 | }; 55 | 56 | listbox.add (label (_("Model:") + " " + cpu.model)); 57 | listbox.add (label (_("Family:") + " " + cpu.family)); 58 | listbox.add (label (_("Microcode ver.:") + " " + cpu.microcode)); 59 | listbox.add (label (_("Bogomips:") + " " + cpu.bogomips)); 60 | 61 | if (cpu.core_list[0].caches.has_key ("L1Instruction")) { 62 | var value = cpu.cache_multipliers["L1Instruction"].to_string () + "×" + cpu.core_list[0].caches["L1Instruction"].size; 63 | listbox.add (label (_("L1 Instruction cache: ") + value)); 64 | } 65 | if (cpu.core_list[0].caches.has_key ("L1Data")) { 66 | var value = cpu.cache_multipliers["L1Data"].to_string () + "×" + cpu.core_list[0].caches["L1Data"].size; 67 | listbox.add (label (_("L1 Data cache: ") + value)); 68 | } 69 | if (cpu.core_list[0].caches.has_key ("L1")) { 70 | var value = cpu.cache_multipliers["L1"].to_string () + "×" + cpu.core_list[0].caches["L1"].size; 71 | listbox.add (label (_("L1 cache: ") + value)); 72 | } 73 | if (cpu.core_list[0].caches.has_key ("L2")) { 74 | listbox.add (label (_("L2 Cache size: ") + cpu.cache_multipliers["L2"].to_string () + "×" + cpu.core_list[0].caches["L2"].size)); 75 | } 76 | if (cpu.core_list[0].caches.has_key ("L3")) { 77 | listbox.add (label (_("L3 Cache size: ") + cpu.cache_multipliers["L3"].to_string () + "×" + cpu.core_list[0].caches["L3"].size)); 78 | } 79 | 80 | listbox.add (label (_("Address sizes: ") + cpu.address_sizes)); 81 | 82 | return listbox; 83 | } 84 | 85 | private Gtk.Widget features_page () { 86 | var listbox = new Gtk.ListBox () { 87 | activate_on_single_click = false 88 | }; 89 | 90 | foreach (var feature in cpu.features) { 91 | listbox.add (create_row (feature.key, feature.value)); 92 | } 93 | 94 | var scrolled_window = new Gtk.ScrolledWindow (null, null); 95 | scrolled_window.add (listbox); 96 | 97 | return scrolled_window; 98 | } 99 | 100 | private Gtk.Widget bugs_page () { 101 | var listbox = new Gtk.ListBox () { 102 | activate_on_single_click = false 103 | }; 104 | 105 | foreach (var bug in cpu.bugs) { 106 | listbox.add (create_row (bug.key, bug.value)); 107 | } 108 | 109 | var scrolled_window = new Gtk.ScrolledWindow (null, null); 110 | scrolled_window.add (listbox); 111 | 112 | return scrolled_window; 113 | } 114 | 115 | private Gtk.ListBoxRow create_row (string flag, string flag_description) { 116 | var row = new Gtk.ListBoxRow (); 117 | var grid = new Gtk.Grid () { 118 | column_spacing = 2, 119 | }; 120 | 121 | var flag_label = new Gtk.Label (flag) { 122 | halign = Gtk.Align.START, 123 | valign = Gtk.Align.CENTER, 124 | wrap = true, 125 | margin = 6, 126 | }; 127 | flag_label.get_style_context ().add_class ("flags_badge"); 128 | 129 | 130 | grid.attach (flag_label, 0, 0, 1, 1); 131 | grid.attach (label (flag_description), 1, 0, 1, 1); 132 | row.add (grid); 133 | 134 | return row; 135 | } 136 | 137 | } 138 | 139 | // public class Monitor.X : Gtk.ListBoxRow { 140 | // construct { 141 | // get_style_context ().add_class ("open_files_list_box_row"); 142 | // } 143 | // public X (string _text) { 144 | // var text = _text; 145 | // var grid = new Gtk.Grid (); 146 | // grid.column_spacing = 2; 147 | 148 | // Gtk.Label label = new Gtk.Label (text); 149 | // label.halign = Gtk.Align.START; 150 | // grid.attach (label, 1, 0, 1, 1); 151 | 152 | // add (grid); 153 | // } 154 | // } 155 | -------------------------------------------------------------------------------- /src/Views/SystemView/SystemGPUView.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Monitor.SystemGPUView : Monitor.WidgetResource { 7 | private Chart gpu_chart; 8 | private Chart gpu_vram_percentage_chart; 9 | private Chart gpu_temperature_chart; 10 | private IGPU gpu; 11 | 12 | private LabelRoundy gpu_vram_percentage_label; 13 | private LabelRoundy gpu_temperature_label; 14 | 15 | 16 | construct { 17 | gpu_vram_percentage_label = new LabelRoundy (_("VRAM")); 18 | gpu_vram_percentage_label.margin = 6; 19 | gpu_vram_percentage_label.margin_top = 2; 20 | 21 | gpu_temperature_label = new LabelRoundy (_("TEMPERATURE")); 22 | gpu_temperature_label.margin = 6; 23 | gpu_temperature_label.margin_top = 2; 24 | 25 | gpu_vram_percentage_chart = new Chart (1); 26 | gpu_vram_percentage_chart.set_serie_color (0, Utils.Colors.get_rgba_color (Utils.Colors.LIME_500)); 27 | gpu_vram_percentage_chart.height_request = -1; 28 | gpu_vram_percentage_chart.config.y_axis.fixed_max = 100.0; 29 | gpu_temperature_chart = new Chart (1); 30 | gpu_temperature_chart.set_serie_color (0, Utils.Colors.get_rgba_color (Utils.Colors.LIME_500)); 31 | gpu_temperature_chart.height_request = -1; 32 | 33 | var grid_frequency_info = new Gtk.Grid (); 34 | grid_frequency_info.attach (gpu_vram_percentage_label, 0, 0, 1, 1); 35 | grid_frequency_info.attach (gpu_vram_percentage_chart, 0, 0, 1, 1); 36 | 37 | var grid_temperature_info = new Gtk.Grid (); 38 | grid_temperature_info.attach (gpu_temperature_label, 0, 0, 1, 1); 39 | grid_temperature_info.attach (gpu_temperature_chart, 0, 0, 1, 1); 40 | 41 | 42 | 43 | var smol_charts_container = new Gtk.Grid (); 44 | smol_charts_container.width_request = 200; 45 | smol_charts_container.hexpand = false; 46 | smol_charts_container.halign = Gtk.Align.START; 47 | smol_charts_container.attach (grid_frequency_info, 0, 0, 1, 1); 48 | smol_charts_container.attach (grid_temperature_info, 0, 1, 1, 1); 49 | smol_charts_container.row_spacing = 6; 50 | smol_charts_container.margin_start = 6; 51 | 52 | add_charts_container (smol_charts_container); 53 | } 54 | 55 | public SystemGPUView (IGPU _gpu) { 56 | gpu = _gpu; 57 | 58 | title = gpu.name; 59 | 60 | gpu_chart = new Chart (1); 61 | gpu_chart.set_serie_color (0, Utils.Colors.get_rgba_color (Utils.Colors.LIME_500)); 62 | set_main_chart (gpu_chart); 63 | 64 | set_main_chart_overlay (gpu_usage_grid ()); 65 | } 66 | 67 | private Gtk.Grid gpu_usage_grid () { 68 | Gtk.Grid grid = new Gtk.Grid () { 69 | column_spacing = 8, 70 | row_spacing = 4, 71 | margin = 6 72 | }; 73 | 74 | return grid; 75 | } 76 | 77 | public void update () { 78 | label_vertical_main_metric = (("%d%%").printf (gpu.percentage)); 79 | gpu_chart.update (0, gpu.percentage); 80 | 81 | gpu_vram_percentage_chart.update (0, gpu.memory_percentage); 82 | gpu_temperature_chart.update (0, gpu.temperature); 83 | gpu_vram_percentage_label.set_text (("%.2f %s").printf (gpu.memory_percentage, "%")); 84 | gpu_temperature_label.set_text (("%.2f %s").printf (gpu.temperature, _("℃"))); 85 | 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/Views/SystemView/SystemMemoryView.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Monitor.SystemMemoryView : Monitor.WidgetResource { 7 | private Chart memory_chart; 8 | private Memory memory; 9 | 10 | private LabelRoundy memory_buffered_label = new LabelRoundy (_("Buffered")); 11 | private LabelRoundy memory_cached_label = new LabelRoundy (_("Cached")); 12 | private LabelRoundy memory_locked_label = new LabelRoundy (_("Locked")); 13 | private LabelRoundy memory_total_label = new LabelRoundy (_("Total")); 14 | private LabelRoundy memory_used_label = new LabelRoundy (_("Used")); 15 | private LabelRoundy memory_shared_label = new LabelRoundy (_("Shared")); 16 | 17 | construct { 18 | title = (_("Memory")); 19 | 20 | } 21 | 22 | public SystemMemoryView (Memory _memory) { 23 | memory = _memory; 24 | 25 | memory_chart = new Chart (1); 26 | memory_chart.set_serie_color (0, Utils.Colors.get_rgba_color (Utils.Colors.LIME_300)); 27 | // memory_used_label.set_color ("grape_500"); 28 | 29 | // memory_chart.set_serie_color (1, Utils.Colors.get_rgba_color (Utils.Colors.LIME_300)); 30 | // memory_shared_label.set_color ("blueberry_100"); 31 | 32 | // memory_chart.set_serie_color (2, Utils.Colors.get_rgba_color (Utils.Colors.LIME_500)); 33 | // memory_chart.set_serie_color (3, Utils.Colors.get_rgba_color (Utils.Colors.LIME_700)); 34 | // memory_chart.set_serie_color (4, Utils.Colors.get_rgba_color (Utils.Colors.LIME_900)); 35 | set_main_chart (memory_chart); 36 | 37 | set_main_chart_overlay (memory_usage_grid ()); 38 | } 39 | 40 | private Gtk.Grid memory_usage_grid () { 41 | Gtk.Grid grid = new Gtk.Grid () { 42 | column_spacing = 8, 43 | row_spacing = 4, 44 | margin = 6 45 | }; 46 | 47 | grid.attach (memory_used_label, 0, 0, 1, 1); 48 | grid.attach (memory_total_label, 0, 1, 1, 1); 49 | grid.attach (memory_shared_label, 1, 0, 1, 1); 50 | grid.attach (memory_buffered_label, 1, 1, 1, 1); 51 | grid.attach (memory_cached_label, 2, 0, 1, 1); 52 | grid.attach (memory_locked_label, 2, 1, 1, 1); 53 | 54 | return grid; 55 | } 56 | 57 | public void update () { 58 | label_vertical_main_metric = (("%u%%").printf (memory.used_percentage)); 59 | memory_chart.update (0, memory.used_percentage); 60 | // memory_chart.update (1, memory.shared_percentage); 61 | // memory_chart.update (2, memory.shared_percentage + memory.buffer_percentage); 62 | // memory_chart.update (3, memory.shared_percentage + memory.buffer_percentage + memory.cached_percentage); 63 | // memory_chart.update (3, memory.shared_percentage + memory.buffer_percentage + memory.cached_percentage + memory.locked_percentage); 64 | 65 | memory_total_label.set_text (format_size ((uint64) memory.total, IEC_UNITS)); 66 | memory_used_label.set_text (format_size ((uint64) memory.used, IEC_UNITS)); 67 | memory_buffered_label.set_text (format_size ((uint64) memory.buffer, IEC_UNITS)); 68 | memory_cached_label.set_text (format_size ((uint64) memory.cached, IEC_UNITS)); 69 | memory_locked_label.set_text (format_size ((uint64) memory.locked, IEC_UNITS)); 70 | 71 | memory_shared_label.set_text (format_size ((uint64) memory.shared, IEC_UNITS)); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/Views/SystemView/SystemNetworkView.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Monitor.SystemNetworkView : Gtk.Grid { 7 | private Chart network_chart; 8 | private Network network; 9 | 10 | private Granite.HeaderLabel network_name_label; 11 | private LabelRoundy network_upload_label; 12 | private LabelRoundy network_download_label; 13 | 14 | construct { 15 | margin = 12; 16 | column_spacing = 12; 17 | set_vexpand (false); 18 | } 19 | 20 | public SystemNetworkView (Network _network) { 21 | network = _network; 22 | 23 | network_name_label = new Granite.HeaderLabel (_("Network")); 24 | 25 | network_download_label = new LabelRoundy (_("DOWN")); 26 | network_download_label.val.set_width_chars (7); 27 | network_download_label.set_color ("blue"); 28 | 29 | network_upload_label = new LabelRoundy (_("UP")); 30 | network_upload_label.val.set_width_chars (7); 31 | network_upload_label.set_color ("green"); 32 | 33 | network_chart = new Chart (2); 34 | network_chart.config.y_axis.fixed_max = null; 35 | 36 | network_chart.set_serie_color (0, { 155 / 255.0, 219 / 255.0, 77 / 255.0, 1.0 }); 37 | network_chart.set_serie_color (1, { 100 / 255.0, 186 / 255.0, 255 / 255.0, 1.0 }); 38 | 39 | var labels_grid = new Gtk.Grid (); 40 | labels_grid.row_spacing = 6; 41 | labels_grid.column_spacing = 6; 42 | labels_grid.margin = 6; 43 | labels_grid.attach (network_download_label, 0, 0, 1, 1); 44 | labels_grid.attach (network_upload_label, 1, 0, 1, 1); 45 | 46 | attach (network_name_label, 0, 0, 1, 1); 47 | attach (labels_grid, 0, 1, 2, 2); 48 | attach (network_chart, 0, 1, 2, 2); 49 | } 50 | 51 | public void update () { 52 | double up_bytes = network.bytes_out; 53 | double down_bytes = network.bytes_in; 54 | if (up_bytes >= 0 && down_bytes >= 0) { 55 | network_download_label.set_text (("%s/s").printf (format_size ((uint64) down_bytes, IEC_UNITS))); 56 | network_upload_label.set_text (("%s/s").printf (format_size ((uint64) up_bytes, IEC_UNITS))); 57 | network_chart.update (0, up_bytes); 58 | network_chart.update (1, down_bytes); 59 | } 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/Views/SystemView/SystemStorageView.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Monitor.SystemStorageView : Gtk.Grid { 7 | private Chart storage_chart; 8 | private Storage storage; 9 | 10 | private Granite.HeaderLabel storage_name_label; 11 | private LabelRoundy storage_read_label; 12 | private LabelRoundy storage_write_label; 13 | 14 | private Gtk.Box drive_cards_container; 15 | 16 | construct { 17 | margin = 12; 18 | column_spacing = 12; 19 | set_vexpand (false); 20 | } 21 | 22 | public SystemStorageView (Storage _storage) { 23 | storage = _storage; 24 | 25 | storage_name_label = new Granite.HeaderLabel (_("Storage")); 26 | 27 | storage_write_label = new LabelRoundy (_("WRITE")); 28 | storage_write_label.val.set_width_chars (7); 29 | storage_write_label.set_color ("blue"); 30 | 31 | storage_read_label = new LabelRoundy (_("READ")); 32 | storage_read_label.val.set_width_chars (7); 33 | storage_read_label.set_color ("green"); 34 | 35 | storage_chart = new Chart (2); 36 | storage_chart.config.y_axis.fixed_max = null; 37 | storage_chart.set_serie_color (0, { 155 / 255.0, 219 / 255.0, 77 / 255.0, 1.0 }); 38 | storage_chart.set_serie_color (1, { 100 / 255.0, 186 / 255.0, 255 / 255.0, 1.0 }); 39 | 40 | var labels_grid = new Gtk.Grid (); 41 | labels_grid.row_spacing = 6; 42 | labels_grid.column_spacing = 6; 43 | labels_grid.margin = 6; 44 | labels_grid.attach (storage_write_label, 0, 0, 1, 1); 45 | labels_grid.attach (storage_read_label, 1, 0, 1, 1); 46 | 47 | drive_cards_container = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); 48 | 49 | storage.get_drives ().foreach (add_drive_card); 50 | 51 | attach (storage_name_label, 0, 0, 1, 1); 52 | attach (drive_cards_container, 0, 1, 1, 1); 53 | attach (labels_grid, 0, 2, 2, 2); 54 | attach (storage_chart, 0, 2, 2, 2); 55 | } 56 | 57 | private bool add_drive_card (owned Disk ? drive) { 58 | drive_cards_container.add (build_drive_card (drive.model, drive.device, drive.size, drive.free)); 59 | return true; 60 | } 61 | 62 | private Gtk.Box build_drive_card (string model, string device, uint64 size, uint64 free) { 63 | var drive_card = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); 64 | drive_card.get_style_context ().add_class ("card"); 65 | drive_card.get_style_context ().add_class ("rounded"); 66 | 67 | drive_card.halign = Gtk.Align.START; 68 | drive_card.margin_end = 12; 69 | drive_card.margin_top = 6; 70 | drive_card.margin_bottom = 12; 71 | 72 | var drive_grid = new Gtk.Grid (); 73 | // drive_grid.row_spacing = 6; 74 | drive_grid.column_spacing = 6; 75 | drive_grid.margin = 6; 76 | 77 | var drive_name_label = new Gtk.Label (model); 78 | drive_name_label.get_style_context ().add_class ("h3"); 79 | drive_name_label.margin = 6; 80 | drive_name_label.margin_bottom = 0; 81 | drive_name_label.halign = Gtk.Align.START; 82 | 83 | string size_string = format_size ((uint64) size, IEC_UNITS); 84 | string used_string = format_size ((uint64) (size - free), IEC_UNITS); 85 | 86 | string drive_block_name_and_size_string = "%s 𐄁 %s / %s".printf (device, used_string, size_string); 87 | 88 | if (free == 0)drive_block_name_and_size_string = "%s 𐄁 %s".printf (device, size_string); 89 | 90 | var drive_block_name_and_size_label = new Gtk.Label (drive_block_name_and_size_string); 91 | drive_block_name_and_size_label.get_style_context ().add_class ("h4"); 92 | drive_block_name_and_size_label.get_style_context ().add_class ("text-secondary"); 93 | drive_block_name_and_size_label.margin = 6; 94 | drive_block_name_and_size_label.margin_top = 0; 95 | drive_block_name_and_size_label.halign = Gtk.Align.START; 96 | 97 | var drive_not_mounted_label = new Gtk.Label (_("Not mounted")); 98 | drive_not_mounted_label.halign = Gtk.Align.START; 99 | drive_not_mounted_label.get_style_context ().add_class ("h4"); 100 | drive_not_mounted_label.margin_start = 6; 101 | 102 | var usagebar = new Gtk.LevelBar (); 103 | usagebar.get_style_context ().add_class ("flat"); 104 | usagebar.margin = 6; 105 | usagebar.margin_top = 0; 106 | usagebar.set_max_value (100.0); 107 | usagebar.set_min_value (0.0); 108 | usagebar.set_value (100.0 * (size - free) / size); 109 | 110 | drive_grid.attach (drive_name_label, 0, 0, 1, 1); 111 | drive_grid.attach (drive_block_name_and_size_label, 0, 1, 1, 1); 112 | if (free == 0) { 113 | drive_grid.attach (drive_not_mounted_label, 0, 2, 1, 1); 114 | } else { 115 | drive_grid.attach (usagebar, 0, 2, 1, 1); 116 | } 117 | drive_card.add (drive_grid); 118 | 119 | return drive_card; 120 | } 121 | 122 | public void update () { 123 | double up_bytes = storage.bytes_read; 124 | double down_bytes = storage.bytes_write; 125 | if (up_bytes >= 0 && down_bytes >= 0) { 126 | storage_write_label.set_text (("%s/s").printf (format_size ((uint64) down_bytes, IEC_UNITS))); 127 | storage_read_label.set_text (("%s/s").printf (format_size ((uint64) up_bytes, IEC_UNITS))); 128 | storage_chart.update (0, up_bytes); 129 | storage_chart.update (1, down_bytes); 130 | } 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /src/Views/SystemView/SystemView.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Monitor.SystemView : Gtk.Box { 7 | private Resources resources; 8 | 9 | private SystemCPUView cpu_view; 10 | private SystemMemoryView memory_view; 11 | private SystemNetworkView network_view; 12 | private SystemStorageView storage_view; 13 | private GLib.List gpu_views = new GLib.List (); 14 | 15 | construct { 16 | orientation = Gtk.Orientation.VERTICAL; 17 | hexpand = true; 18 | } 19 | 20 | public SystemView (Resources _resources) { 21 | resources = _resources; 22 | 23 | cpu_view = new SystemCPUView (resources.cpu); 24 | memory_view = new SystemMemoryView (resources.memory); 25 | network_view = new SystemNetworkView (resources.network); 26 | storage_view = new SystemStorageView (resources.storage); 27 | 28 | var scrolled_window = new Gtk.ScrolledWindow (null, null); 29 | var wrapper = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); 30 | wrapper.expand = true; 31 | scrolled_window.add (wrapper); 32 | 33 | 34 | wrapper.add (cpu_view); 35 | wrapper.add (memory_view); 36 | wrapper.add (network_view); 37 | wrapper.add (storage_view); 38 | 39 | foreach (IGPU gpu in resources.gpu_list) { 40 | if (gpu is GPUIntel || gpu is GPUNvidia) { 41 | wrapper.add (build_no_support_label (gpu.name)); 42 | } else { 43 | var gpu_view = new SystemGPUView (gpu); 44 | gpu_views.append (gpu_view); 45 | wrapper.add (gpu_view); 46 | } 47 | } 48 | 49 | add (scrolled_window); 50 | } 51 | 52 | public void update () { 53 | cpu_view.update (); 54 | memory_view.update (); 55 | network_view.update (); 56 | storage_view.update (); 57 | gpu_views.foreach ((gpu_view) => gpu_view.update ()); 58 | } 59 | 60 | private Granite.HeaderLabel build_no_support_label (string gpu_name) { 61 | string notification_text = _("The %s GPU was detected, but is not yet supported.").printf (gpu_name); 62 | return new Granite.HeaderLabel (notification_text) { 63 | margin = 12, 64 | }; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/Widgets/Chart/Chart.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Monitor.Chart : Gtk.Box { 7 | private LiveChart.Chart live_chart; 8 | private uint series_quantity; 9 | private Utils.Colors colors = new Utils.Colors (); 10 | public LiveChart.Config config; 11 | 12 | 13 | construct { 14 | get_style_context ().add_class ("graph"); 15 | 16 | vexpand = true; 17 | height_request = 120; 18 | 19 | config = new LiveChart.Config (); 20 | config.y_axis.unit = "%"; 21 | config.y_axis.tick_interval = 25; 22 | config.y_axis.fixed_max = 100.0; 23 | config.y_axis.labels.visible = false; 24 | config.x_axis.labels.visible = false; 25 | 26 | config.padding = LiveChart.Padding () { 27 | smart = LiveChart.AutoPadding.NONE, 28 | top = 0, 29 | right = 0, 30 | bottom = 0, 31 | left = -1 32 | }; 33 | 34 | live_chart = new LiveChart.Chart (config); 35 | live_chart.expand = true; 36 | live_chart.legend.visible = false; 37 | live_chart.grid.visible = true; 38 | live_chart.background.visible = false; 39 | // live_chart.background.color = Gdk.RGBA () { 40 | // red = 1, green = 1, blue = 1, alpha = 1 41 | // }; // White background 42 | } 43 | 44 | public Chart (uint _series_quantity, bool smooth = true, double renderer_area_alfa = 0.2) { 45 | series_quantity = _series_quantity; 46 | 47 | if (smooth) { 48 | with_smooth_line (renderer_area_alfa); 49 | } else { 50 | with_straight_line (renderer_area_alfa); 51 | } 52 | } 53 | 54 | private Chart with_smooth_line (double renderer_area_alfa = 0.2) { 55 | for (int i = 0; i < series_quantity; i++) { 56 | var renderer = new LiveChart.SmoothLineArea (new LiveChart.Values (1000)); 57 | renderer.area_alpha = renderer_area_alfa; 58 | var serie = new LiveChart.Serie (("Serie %d").printf (i), renderer); 59 | 60 | // The idea is to make area a bit less darker or lighter then the base line color 61 | // var color = colors.get_color_by_index (i); 62 | // renderer.region = new LiveChart.Region.between(0, double.MAX).with_line_color(color).with_area_color(color); 63 | 64 | serie.line.color = colors.get_color_by_index (i); 65 | 66 | live_chart.add_serie (serie); 67 | } 68 | add (live_chart); 69 | return this; 70 | } 71 | 72 | private Chart with_straight_line (double renderer_area_alfa = 0.5) { 73 | for (int i = 0; i < series_quantity; i++) { 74 | var renderer = new LiveChart.LineArea (new LiveChart.Values (1000)); 75 | renderer.area_alpha = renderer_area_alfa; 76 | var serie = new LiveChart.Serie (("Serie %d").printf (i), renderer); 77 | 78 | serie.line.color = colors.get_color_by_index (i); 79 | live_chart.add_serie (serie); 80 | } 81 | add (live_chart); 82 | return this; 83 | } 84 | 85 | public void set_serie_color (int serie_number, Gdk.RGBA color) { 86 | try { 87 | live_chart.series[serie_number].line.color = color; 88 | } catch (LiveChart.ChartError e) { 89 | error (e.message); 90 | } 91 | } 92 | 93 | public void update (int serie_number, double value) { 94 | try { 95 | live_chart.series[serie_number].add (value); 96 | } catch (LiveChart.ChartError e) { 97 | error (e.message); 98 | } 99 | } 100 | 101 | public void preset_data (int serie_number, Gee.ArrayList history) { 102 | var refresh_rate_in_ms = 2000; 103 | try { 104 | live_chart.add_unaware_timestamp_collection_by_index (serie_number, history, refresh_rate_in_ms); 105 | } catch (LiveChart.ChartError e) { 106 | error (e.message); 107 | } 108 | } 109 | 110 | public void clear () { 111 | // var series = live_chart.series; 112 | foreach (var serie in live_chart.series) { 113 | serie.clear (); 114 | } 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/Widgets/Headerbar/Search.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Monitor.Search : Gtk.SearchEntry { 7 | public MainWindow window { get; construct; } 8 | private Gtk.TreeModelFilter filter_model; 9 | private CPUProcessTreeView process_tree_view; 10 | 11 | public Search (MainWindow window) { 12 | Object (window: window); 13 | } 14 | 15 | construct { 16 | this.process_tree_view = window.process_view.process_tree_view; 17 | this.placeholder_text = _("Search Process"); 18 | this.tooltip_markup = Granite.markup_accel_tooltip ({ "F" }, _("Type process name or PID to search")); 19 | 20 | filter_model = new Gtk.TreeModelFilter (window.process_view.treeview_model, null); 21 | connect_signal (); 22 | filter_model.set_visible_func (filter_func); 23 | // process_tree_view.set_model (filter_model); 24 | 25 | var sort_model = new Gtk.TreeModelSort.with_model (filter_model); 26 | process_tree_view.set_model (sort_model); 27 | } 28 | 29 | private void connect_signal () { 30 | this.search_changed.connect (() => { 31 | // collapse tree only when search is focused and changed 32 | if (this.is_focus) { 33 | process_tree_view.collapse_all (); 34 | } 35 | 36 | filter_model.refilter (); 37 | 38 | // focus on child row to avoid the app crashes by clicking "Kill/End Process" buttons in headerbar 39 | process_tree_view.focus_on_child_row (); 40 | this.grab_focus (); 41 | 42 | if (this.text != "") { 43 | this.insert_at_cursor (""); 44 | } 45 | }); 46 | 47 | activate.connect (() => { 48 | window.process_view.process_tree_view.focus_on_first_row (); 49 | }); 50 | } 51 | 52 | private bool filter_func (Gtk.TreeModel model, Gtk.TreeIter iter) { 53 | string name_haystack; 54 | int pid_haystack; 55 | string cmd_haystack; 56 | bool found = false; 57 | var needle = this.text; 58 | 59 | // should help with assertion errors, donno 60 | // if (needle == null) return true; 61 | 62 | if (needle.length == 0) { 63 | return true; 64 | } 65 | 66 | model.get (iter, Column.NAME, out name_haystack, -1); 67 | model.get (iter, Column.PID, out pid_haystack, -1); 68 | model.get (iter, Column.CMD, out cmd_haystack, -1); 69 | 70 | // sometimes name_haystack is null 71 | if (name_haystack != null) { 72 | bool name_found = name_haystack.casefold ().contains (needle.casefold ()) || false; 73 | bool pid_found = pid_haystack.to_string ().casefold ().contains (needle.casefold ()) || false; 74 | bool cmd_found = cmd_haystack.casefold ().contains (needle.casefold ()) || false; 75 | found = name_found || pid_found || cmd_found; 76 | } 77 | 78 | 79 | Gtk.TreeIter child_iter; 80 | bool child_found = false; 81 | 82 | if (model.iter_children (out child_iter, iter)) { 83 | do { 84 | child_found = filter_func (model, child_iter); 85 | } while (model.iter_next (ref child_iter) && !child_found); 86 | } 87 | 88 | if (child_found && needle.length > 0) { 89 | process_tree_view.expand_all (); 90 | } 91 | 92 | return found || child_found; 93 | } 94 | 95 | // reset filter, grab focus and insert the character 96 | public void activate_entry (string search_text = "") { 97 | this.text = ""; 98 | this.search_changed (); 99 | this.insert_at_cursor (search_text); 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/Widgets/Labels/LabelRoundy.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Monitor.LabelRoundy : Gtk.Fixed { 7 | public Gtk.Label val; 8 | public Gtk.Label desc; 9 | 10 | public LabelRoundy (string description) { 11 | val = new Gtk.Label (Utils.NO_DATA) { 12 | selectable = true 13 | }; 14 | val.get_style_context ().add_class ("roundy-label"); 15 | 16 | desc = new Gtk.Label (description.up ()); 17 | desc.get_style_context ().add_class ("small-text"); 18 | 19 | put (val, 0, 12); 20 | put (desc, 6, 0); 21 | } 22 | 23 | public void set_color (string colorname) { 24 | val.get_style_context ().add_class (colorname); 25 | } 26 | 27 | public void set_text (string text) { 28 | val.set_text (text); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/Widgets/Labels/LabelVertical.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Monitor.LabelVertical : Gtk.EventBox { 7 | private Gtk.Grid grid; 8 | 9 | public signal void clicked (); 10 | 11 | public Gtk.Label val; 12 | public Gtk.Label desc; 13 | 14 | construct { 15 | grid = new Gtk.Grid (); 16 | margin_start = 12; 17 | margin_top = 6; 18 | 19 | get_style_context ().add_class ("label-vertical"); 20 | } 21 | 22 | public LabelVertical (string description) { 23 | val = new Gtk.Label (Utils.NO_DATA); 24 | val.get_style_context ().add_class (Granite.STYLE_CLASS_H2_LABEL); 25 | 26 | desc = new Gtk.Label (description.up ()); 27 | desc.get_style_context ().add_class ("small-text"); 28 | 29 | grid.attach (desc, 0, 0, 1, 1); 30 | grid.attach (val, 0, 1, 1, 1); 31 | 32 | add (grid); 33 | 34 | events |= Gdk.EventMask.BUTTON_RELEASE_MASK; 35 | 36 | button_release_event.connect ((event) => { 37 | clicked (); 38 | return false; 39 | }); 40 | } 41 | 42 | public void set_text (string text) { 43 | val.set_text (text); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/Widgets/Statusbar/Statusbar.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Monitor.Statusbar : Gtk.ActionBar { 7 | Gtk.Label cpu_usage_label; 8 | Gtk.Label memory_usage_label; 9 | Gtk.Label swap_usage_label; 10 | Gtk.Label gpu_usage_label; 11 | 12 | construct { 13 | var cpu_icon = new Gtk.Image.from_icon_name ("cpu-symbolic", Gtk.IconSize.SMALL_TOOLBAR) { 14 | tooltip_text = _("CPU") 15 | }; 16 | 17 | var ram_icon = new Gtk.Image.from_icon_name ("ram-symbolic", Gtk.IconSize.SMALL_TOOLBAR) { 18 | tooltip_text = _("Memory") 19 | }; 20 | 21 | var swap_icon = new Gtk.Image.from_icon_name ("swap-symbolic", Gtk.IconSize.SMALL_TOOLBAR) { 22 | tooltip_text = _("Swap") 23 | }; 24 | 25 | var gpu_icon = new Gtk.Image.from_icon_name ("gpu-symbolic", Gtk.IconSize.SMALL_TOOLBAR) { 26 | tooltip_text = _("GPU") 27 | }; 28 | 29 | cpu_usage_label = new Gtk.Label (_("Calculating…")); 30 | cpu_usage_label.set_width_chars (4); 31 | cpu_usage_label.xalign = 0; 32 | pack_start (cpu_icon); 33 | pack_start (cpu_usage_label); 34 | 35 | memory_usage_label = new Gtk.Label (_("Calculating…")); 36 | memory_usage_label.set_width_chars (4); 37 | memory_usage_label.xalign = 0; 38 | ram_icon.margin_start = 6; 39 | pack_start (ram_icon); 40 | pack_start (memory_usage_label); 41 | 42 | swap_usage_label = new Gtk.Label (_("Calculating…")); 43 | swap_usage_label.set_width_chars (4); 44 | swap_usage_label.xalign = 0; 45 | swap_icon.margin_start = 6; 46 | pack_start (swap_icon); 47 | pack_start (swap_usage_label); 48 | 49 | gpu_usage_label = new Gtk.Label (_("Calculating…")); 50 | gpu_usage_label.set_width_chars (4); 51 | gpu_usage_label.xalign = 0; 52 | gpu_icon.margin_start = 6; 53 | pack_start (gpu_icon); 54 | pack_start (gpu_usage_label); 55 | 56 | var support_ua_label = new Gtk.LinkButton.with_label ("http://stand-with-ukraine.pp.ua/", _("🇺🇦")); 57 | var github_label = new Gtk.LinkButton.with_label ("https://github.com/elementary/monitor", _("Check on Github")); 58 | 59 | var version_label = new Gtk.Label ("%s".printf (VCS_TAG)) { 60 | selectable = true 61 | }; 62 | version_label.get_style_context ().add_class ("dim-label"); 63 | 64 | // pack_end (build_separator_middot ()); 65 | pack_end (github_label); 66 | pack_end (build_separator_middot ()); 67 | pack_end (version_label); 68 | pack_end (build_separator_middot ()); 69 | pack_end (support_ua_label); 70 | 71 | } 72 | 73 | private Gtk.Label build_separator_middot () { 74 | var label = new Gtk.Label ("𐄁") { 75 | margin_end = 6, 76 | margin_start = 6, 77 | }; 78 | label.get_style_context ().add_class ("dim-label"); 79 | return label; 80 | } 81 | 82 | public bool update (ResourcesSerialized sysres) { 83 | cpu_usage_label.set_text (("%d%%").printf (sysres.cpu_percentage)); 84 | memory_usage_label.set_text (("%u%%").printf (sysres.memory_percentage)); 85 | gpu_usage_label.set_text (("%d%%").printf (sysres.gpu_percentage)); 86 | 87 | string cpu_tooltip_text = ("%.2f %s").printf (sysres.cpu_frequency, _("GHz")); 88 | cpu_usage_label.tooltip_text = cpu_tooltip_text; 89 | 90 | string memory_tooltip_text = ("%s / %s").printf ( 91 | format_size ((uint64) sysres.memory_used, IEC_UNITS), 92 | format_size ((uint64) sysres.memory_total, IEC_UNITS) 93 | ); 94 | memory_usage_label.tooltip_text = memory_tooltip_text; 95 | 96 | // The total amount of the swap is 0 when it is unavailable 97 | if (sysres.swap_total == 0) { 98 | swap_usage_label.set_text ("N/A"); 99 | } else { 100 | swap_usage_label.set_text (("%d%%").printf (sysres.swap_percentage)); 101 | string swap_tooltip_text = ("%.1f %s / %.1f %s").printf (sysres.swap_used, _("GiB"), sysres.swap_total, _("GiB")); 102 | swap_usage_label.tooltip_text = swap_tooltip_text; 103 | } 104 | 105 | return true; 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /src/Widgets/WidgetResource/WidgetResource.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Monitor.WidgetResource : Gtk.Box { 7 | private Granite.HeaderLabel _title = new Granite.HeaderLabel (Utils.NO_DATA); 8 | 9 | public string title { 10 | set { 11 | _title.label = value; 12 | } 13 | } 14 | 15 | public Gtk.Popover popover_more_info; 16 | private LabelVertical _label_vertical_main_metric = new LabelVertical (_("UTILIZATION")); 17 | 18 | public string label_vertical_main_metric { 19 | set { 20 | _label_vertical_main_metric.set_text (value); 21 | } 22 | } 23 | 24 | private Gtk.Box charts_container = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); 25 | 26 | private Gtk.Grid grid_main_chart_container; 27 | private Gtk.Grid grid_main_onchart_info_container; 28 | private Gtk.Grid grid_header; 29 | 30 | 31 | construct { 32 | margin = 12; 33 | margin_top = 6; 34 | set_vexpand (false); 35 | orientation = Gtk.Orientation.VERTICAL; 36 | 37 | 38 | 39 | grid_header = new Gtk.Grid () { 40 | column_spacing = 6, 41 | }; 42 | grid_header.attach (_title, 0, 0, 1, 1); 43 | add (grid_header); 44 | 45 | 46 | grid_main_chart_container = new Gtk.Grid (); 47 | grid_main_chart_container.attach (build_grid_main_onchart_info_container (), 0, 0, 1, 1); 48 | 49 | charts_container.pack_start (grid_main_chart_container, true, true, 0); 50 | 51 | add (charts_container); 52 | 53 | } 54 | 55 | private Gtk.Grid build_grid_main_onchart_info_container () { 56 | grid_main_onchart_info_container = new Gtk.Grid () { 57 | column_spacing = 6, 58 | margin = 6, 59 | valign = Gtk.Align.START, 60 | halign = Gtk.Align.START, 61 | }; 62 | 63 | grid_main_onchart_info_container.get_style_context ().add_class ("usage-label-container"); 64 | grid_main_onchart_info_container.attach (_label_vertical_main_metric, 0, 0, 1, 1); 65 | 66 | return grid_main_onchart_info_container; 67 | } 68 | 69 | public void set_main_chart (Chart chart) { 70 | grid_main_chart_container.attach (chart, 0, 0, 1, 1); 71 | } 72 | 73 | public void set_main_chart_overlay (Gtk.Widget widget) { 74 | grid_main_onchart_info_container.attach (widget, 1, 0, 1, 1); 75 | } 76 | 77 | public void add_charts_container (Gtk.Widget widget) { 78 | charts_container.pack_start (widget, false, false, 0); 79 | } 80 | 81 | public void set_popover_more_info (Gtk.Widget widget) { 82 | var button_more_info = new Gtk.ToggleButton () { 83 | has_focus = false, 84 | valign = Gtk.Align.START, 85 | halign = Gtk.Align.START 86 | }; 87 | button_more_info.get_style_context ().add_class ("circular"); 88 | // button_more_info.get_style_context ().add_class ("popup"); 89 | var icon = new Gtk.Image (); 90 | icon.gicon = new ThemedIcon ("dialog-information"); 91 | icon.pixel_size = 16; 92 | button_more_info.set_image (icon); 93 | 94 | popover_more_info = new Gtk.Popover (button_more_info) { 95 | position = Gtk.PositionType.BOTTOM, 96 | modal = true, 97 | visible = false, 98 | }; 99 | popover_more_info.closed.connect (() => { button_more_info.set_active (false); }); 100 | button_more_info.clicked.connect (() => { popover_more_info.show_all (); }); 101 | 102 | popover_more_info.add (widget); 103 | 104 | grid_header.attach (button_more_info, 1, 0, 1, 1); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/meson.build: -------------------------------------------------------------------------------- 1 | source_app_files = [ 2 | 'Monitor.vala', 3 | 'MainWindow.vala', 4 | 'Utils.vala', 5 | 'PCIUtils.vala', 6 | 7 | # Views 8 | 'Views/ProcessView/ProcessView.vala', 9 | 'Views/ProcessView/ProcessInfoView/ProcessInfoView.vala', 10 | 'Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala', 11 | 12 | 'Views/PreferencesView.vala', 13 | 14 | 'Views/SystemView/SystemView.vala', 15 | 'Views/SystemView/SystemCPUView.vala', 16 | 'Views/SystemView/SystemCPUInfoPopover.vala', 17 | 'Views/SystemView/SystemMemoryView.vala', 18 | 'Views/SystemView/SystemNetworkView.vala', 19 | 'Views/SystemView/SystemStorageView.vala', 20 | 'Views/SystemView/SystemGPUView.vala', 21 | 22 | # Widgets related only to ProcessInfoView 23 | 'Views/ProcessView/ProcessInfoView/Preventor.vala', 24 | 'Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala', 25 | 'Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala', 26 | 'Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala', 27 | 'Views/ProcessView/ProcessInfoView/OpenFilesTreeView.vala', 28 | 29 | # Widgets 30 | 'Widgets/Headerbar/Search.vala', 31 | 'Widgets/Statusbar/Statusbar.vala', 32 | 'Widgets/Labels/LabelVertical.vala', 33 | 'Widgets/Labels/LabelRoundy.vala', 34 | 'Widgets/Chart/Chart.vala', 35 | 'Widgets/WidgetResource/WidgetResource.vala', 36 | 37 | # Models 38 | 'Models/TreeViewModel.vala', 39 | 'Models/OpenFilesTreeViewModel.vala', 40 | 41 | # Other 42 | # 'Managers/AppManager.vala', 43 | 'Managers/ProcessManager.vala', 44 | 'Managers/Process.vala', 45 | 'Managers/ProcessStructs.vala', 46 | 'Managers/ProcessUtils.vala', 47 | 48 | # Services 49 | 'Services/DBusServer.vala', 50 | 'Services/Appearance.vala', 51 | 52 | # Resources 53 | 'Resources/Resources.vala', 54 | 'Resources/ResourcesSerialized.vala', 55 | 'Resources/CPU.vala', 56 | 'Resources/CPUCache.vala', 57 | 'Resources/Core.vala', 58 | 'Resources/Memory.vala', 59 | 'Resources/Swap.vala', 60 | 'Resources/Network.vala', 61 | 'Resources/Cgroup/Cgroup.vala', 62 | 'Resources/Cgroup/CgroupStructs.vala', 63 | 64 | 'Resources/Storage/Storage.vala', 65 | 'Resources/Storage/StorageParser.vala', 66 | 'Resources/Storage/Disk.vala', 67 | 'Resources/Storage/Volume.vala', 68 | 69 | 'Resources/GPU/IGPU.vala', 70 | 'Resources/GPU/GPUAmd.vala', 71 | 'Resources/GPU/GPUNvidia.vala', 72 | 'Resources/GPU/GPUIntel.vala', 73 | 74 | 'Resources/Hwmon/HwmonPathsParser.vala', 75 | 'Resources/Hwmon/IHwmonPathsParserInterface.vala', 76 | 'Resources/Hwmon/HwmonPathsParserCPU.vala', 77 | 'Resources/Hwmon/HwmonPathsParserGPU.vala', 78 | 'Resources/Hwmon/HwmonPathsParserIwlwifi.vala', 79 | 'Resources/Hwmon/HwmonPathsParserNVMe.vala', 80 | 'Resources/Hwmon/HwmonTemperature.vala', 81 | 'Resources/Hwmon/HwmonVoltage.vala', 82 | 'Resources/Hwmon/HwmonFrequency.vala', 83 | 'Resources/Hwmon/HwmonFan.vala', 84 | 'Resources/Hwmon/HwmonPWM.vala', 85 | 'Resources/Hwmon/HwmonPower.vala', 86 | 87 | ] 88 | 89 | executable( 90 | meson.project_name(), 91 | icons_gresource, 92 | css_gresource, 93 | source_app_files, 94 | project_config, 95 | dependencies: app_dependencies, 96 | install: true 97 | ) 98 | 99 | if get_option('indicator-wingpanel').enabled() 100 | message ('Indicator Wingpanel will be built') 101 | subdir('Indicator') 102 | endif 103 | -------------------------------------------------------------------------------- /subprojects/live-chart.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | url = https://github.com/elementary/live-chart.git 3 | revision = 5a690045f2e3df1d78ff0ea1e5df6470a6760639 4 | depth = 1 5 | 6 | [provide] 7 | livechart = livechart_static_dep 8 | -------------------------------------------------------------------------------- /tests/list-src.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | find . -name "*.vala" -------------------------------------------------------------------------------- /tests/meson.build: -------------------------------------------------------------------------------- 1 | test_sources = files(run_command('list-src.sh', check: true).stdout().strip().split('\n')) 2 | 3 | 4 | test( 5 | 'monitor-statusbar-test', 6 | executable('monitor-statusbar-test', test_sources, [ 7 | meson.source_root() / 'src/Widgets/Statusbar/Statusbar.vala', 8 | meson.source_root() / 'src/Resources/ResourcesSerialized.vala', 9 | meson.source_root() / 'src/Utils.vala' 10 | ], 11 | project_config, 12 | dependencies: app_dependencies) 13 | ) -------------------------------------------------------------------------------- /tests/runner.vala: -------------------------------------------------------------------------------- 1 | void main (string[] args) { 2 | 3 | Test.init (ref args); 4 | Gtk.init (ref args); 5 | 6 | test_statusbar (); 7 | 8 | Test.run (); 9 | } 10 | -------------------------------------------------------------------------------- /tests/test_statusbar.vala: -------------------------------------------------------------------------------- 1 | using Monitor; 2 | 3 | private void test_statusbar () { 4 | 5 | Test.add_func ("/Monitor/Widgets/Statusbar/Statusbar#Statusbar", () => { 6 | 7 | var statusbar = new Monitor.Statusbar (); 8 | ResourcesSerialized sysres = ResourcesSerialized () { 9 | cpu_percentage = 99, 10 | cpu_frequency = 1.44, 11 | cpu_temperature = 34.0, 12 | memory_percentage = 99, 13 | memory_used = 2.0, 14 | memory_total = 4.0, 15 | swap_percentage = 1, 16 | swap_used = 0.1, 17 | swap_total = 1.0, 18 | network_up = 12, 19 | network_down = 23, 20 | gpu_percentage = 20 21 | gpu_memory_percentage = 10 22 | gpu_temperature = 31.0 23 | }; 24 | 25 | bool update_result = statusbar.update (sysres); 26 | 27 | assert (update_result == true); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /vapi/libxnvctrl.vapi: -------------------------------------------------------------------------------- 1 | namespace NVCtrl { 2 | [CCode (cheader_filename = "NVCtrl/NVCtrlLib.h", cname = "XNVCTRLQueryAttribute", cprefix = "nv_ctrl_lib_", has_type_id = false)] 3 | public static bool XNVCTRLQueryAttribute ( 4 | X.Display *dpy, 5 | int screen, 6 | uint display_mask, 7 | uint attribute, 8 | int *value 9 | ); 10 | 11 | [CCode (cheader_filename = "NVCtrl/NVCtrlLib.h", cname = "XNVCTRLQueryTargetAttribute", cprefix = "nv_ctrl_lib_", has_type_id = false)] 12 | public static bool XNVCTRLQueryTargetAttribute ( 13 | X.Display *dpy, 14 | int target_Type, 15 | int target_id, 16 | uint display_mask, 17 | uint attribute, 18 | int *value 19 | ); 20 | 21 | [CCode (cheader_filename = "NVCtrl/NVCtrlLib.h", cname = "XNVCTRLQueryTargetStringAttribute", cprefix = "nv_ctrl_lib_", has_type_id = false)] 22 | public static bool XNVCTRLQueryTargetStringAttribute ( 23 | X.Display *dpy, 24 | int target_type, 25 | int target_id, 26 | uint display_mask, 27 | uint attribute, 28 | char **ptr 29 | ); 30 | } 31 | 32 | [CCode (cheader_filename = "NVCtrl/NVCtrl.h")] 33 | public const uint NV_CTRL_GPU_CORE_TEMPERATURE; 34 | public const uint NV_CTRL_GPU_CURRENT_CLOCK_FREQS; 35 | public const uint NV_CTRL_TOTAL_GPU_MEMORY; 36 | public const uint NV_CTRL_STRING_GPU_UTILIZATION; 37 | public const uint NV_CTRL_USED_DEDICATED_GPU_MEMORY; 38 | public const uint NV_CTRL_TOTAL_DEDICATED_GPU_MEMORY; 39 | public const uint NV_CTRL_GPU_CURRENT_PROCESSOR_CLOCK_FREQS; 40 | public const uint NV_CTRL_STRING_PRODUCT_NAME; 41 | public const uint NV_CTRL_PCI_ID; 42 | public const int NV_CTRL_TARGET_TYPE_GPU; 43 | --------------------------------------------------------------------------------