Enhancement: Fixes #356, taskmgr - layout and process view

This commit is contained in:
Rory Fewell
2025-05-14 22:52:15 +01:00
parent 45a78d3ac3
commit d833b61879
31 changed files with 2215 additions and 15 deletions

View File

@@ -24,3 +24,4 @@ shell/taskband
shell/winver
wallpapers
windows/notepad
windows/taskmgr

View File

@@ -17,7 +17,7 @@
*/
void wintc_menu_shell_deselect_on_leave(
GtkWidget* widget,
WINTC_UNUSED(GdkEvent* event),
GdkEvent* event,
GtkMenuShell* menu_shell
);
@@ -26,8 +26,16 @@ void wintc_menu_shell_deselect_on_leave(
*/
void wintc_menu_shell_select_on_enter(
GtkWidget* widget,
WINTC_UNUSED(GdkEvent* event),
GdkEvent* event,
GtkMenuShell* menu_shell
);
/**
* Callback for closing the toplevel window upon a GtkButton clicked event.
*/
void wintc_button_close_window_on_clicked(
GtkButton* self,
gpointer user_data
);
#endif

View File

@@ -69,6 +69,16 @@ gchar* wintc_str_set_suffix(
const gchar* suffix
);
/**
* Duplicates the substring in an array of delimiter separated values by the
* specified index.
*/
gchar* wintc_strdup_delimited(
const gchar* str,
gchar* delim_str,
guint index
);
/**
* Duplicates part of a string from the start and ending at the first
* occurrence of the specified delimiter (exclusive, so the delimiter will not
@@ -152,7 +162,7 @@ guint wintc_strv_length(
* Extracts a substring from one string to create a new string.
*
* @param start A pointer to the start of the substring.
* @param end A pointer to the end of the substring.
* @param end A pointer to the end of the substring or NULL.
* @return A copy of the substring.
*/
gchar* wintc_substr(

View File

@@ -3,6 +3,7 @@
#include "../public/defprocs.h"
#include "../public/shorthand.h"
#include "../public/window.h"
//
// PUBLIC FUNCTIONS
@@ -32,3 +33,13 @@ void wintc_menu_shell_select_on_enter(
widget
);
}
void wintc_button_close_window_on_clicked(
GtkButton* self,
WINTC_UNUSED(gpointer user_data)
)
{
gtk_window_close(
wintc_widget_get_toplevel_window(GTK_WIDGET(self))
);
}

View File

@@ -60,6 +60,35 @@ gchar* wintc_str_set_suffix(
}
}
gchar* wintc_strdup_delimited(
const gchar* str,
gchar* delim_str,
guint index
)
{
gint delim_len = strlen(delim_str);
const gchar* next = str;
for (guint i = 0; i < index; i++)
{
if (next != str)
{
next += delim_len; // Advance past the delimiter
}
next = strstr(next, delim_str);
if (!next)
{
return NULL;
}
}
next += delim_len;
return wintc_substr(next, strstr(next, delim_str));
}
gchar* wintc_strdup_nextchr(
const gchar* str,
gssize len,
@@ -224,6 +253,11 @@ gchar* wintc_substr(
const gchar* end
)
{
if (!end)
{
end = start + strlen(start);
}
if (end < start)
{
g_critical("substr: invalid substring requested");

View File

@@ -21,16 +21,18 @@ include(../../packaging/cmake-inc/linking/CMakeLists.txt)
include(../../packaging/cmake-inc/packaging/CMakeLists.txt)
include(../../packaging/cmake-inc/resources/CMakeLists.txt)
wintc_resolve_library(gdk-pixbuf-2.0 GDK_PIXBUF)
wintc_resolve_library(glib-2.0 GLIB)
wintc_resolve_library(gtk+-3.0 GTK3)
wintc_resolve_library(wintc-comctl WINTC_COMCTL)
wintc_resolve_library(wintc-comgtk WINTC_COMGTK)
wintc_resolve_library(wintc-exec WINTC_EXEC)
wintc_resolve_library(wintc-shcommon WINTC_SHCOMMON)
wintc_resolve_library(wintc-shellext WINTC_SHELLEXT)
wintc_resolve_library(wintc-shlang WINTC_SHLANG)
wintc_resolve_library(wintc-winbrand WINTC_WINBRAND)
wintc_resolve_library(libcanberra CANBERRA)
wintc_resolve_library(libcanberra-gtk3 CANBERRA_GTK3)
wintc_resolve_library(gdk-pixbuf-2.0 GDK_PIXBUF)
wintc_resolve_library(glib-2.0 GLIB)
wintc_resolve_library(gtk+-3.0 GTK3)
wintc_resolve_library(wintc-comctl WINTC_COMCTL)
wintc_resolve_library(wintc-comgtk WINTC_COMGTK)
wintc_resolve_library(wintc-exec WINTC_EXEC)
wintc_resolve_library(wintc-shcommon WINTC_SHCOMMON)
wintc_resolve_library(wintc-shellext WINTC_SHELLEXT)
wintc_resolve_library(wintc-shlang WINTC_SHLANG)
wintc_resolve_library(wintc-winbrand WINTC_WINBRAND)
wintc_compile_resources()
@@ -51,6 +53,8 @@ add_library(
src/icnvwbeh.c
public/icnvwbeh.h
src/resources.c
public/sound.h
src/sound.c
src/trevwbeh.c
public/trevwbeh.h
src/nmspace.c
@@ -81,6 +85,8 @@ target_include_directories(
libwintc-shell
SYSTEM
BEFORE
PRIVATE ${CANBERRA_INCLUDE_DIRS}
PRIVATE ${CANBERRA_GTK3_INCLUDE_DIRS}
PRIVATE ${GDK_PIXBUF_INCLUDE_DIRS}
PRIVATE ${GLIB_INCLUDE_DIRS}
PRIVATE ${GTK3_INCLUDE_DIRS}
@@ -95,6 +101,8 @@ target_include_directories(
target_link_directories(
libwintc-shell
PRIVATE ${CANBERRA_LIBRARY_DIRS}
PRIVATE ${CANBERRA_GTK3_LIBRARY_DIRS}
PRIVATE ${GDK_PIXBUF_LIBRARY_DIRS}
PRIVATE ${GLIB_LIBRARY_DIRS}
PRIVATE ${GTK3_LIBRARY_DIRS}
@@ -109,6 +117,8 @@ target_link_directories(
target_link_libraries(
libwintc-shell
PRIVATE ${CANBERRA_LIBRARIES}
PRIVATE ${CANBERRA_GTK3_LIBRARIES}
PRIVATE ${GDK_PIXBUF_LIBRARIES}
PRIVATE ${GLIB_LIBRARIES}
PRIVATE ${GTK3_LIBRARIES}

View File

@@ -1,3 +1,5 @@
bt,rt:canberra
bt,rt:canberra-gtk3
bt,rt:gdk-pixbuf2
bt,rt:glib2
bt,rt:gtk3

View File

@@ -8,6 +8,7 @@
#include "@LIB_HEADER_DIR@/fsclipbd.h"
#include "@LIB_HEADER_DIR@/icnvwbeh.h"
#include "@LIB_HEADER_DIR@/nmspace.h"
#include "@LIB_HEADER_DIR@/sound.h"
#include "@LIB_HEADER_DIR@/trevwbeh.h"
#include "@LIB_HEADER_DIR@/vwcpl.h"
#include "@LIB_HEADER_DIR@/vwdesk.h"

View File

@@ -0,0 +1,52 @@
#ifndef __SHELL_SOUND_H__
#define __SHELL_SOUND_H__
#include <glib.h>
//
// PUBLIC DEFINES
//
#define WINTC_SHELL_SND_ASTERISK "dialog-warning"
#define WINTC_SHELL_SND_BATTCRIT "battery-low"
#define WINTC_SHELL_SND_CRITSTOP "dialog-error"
#define WINTC_SHELL_SND_CLOSEPRG "windows-close-program"
#define WINTC_SHELL_SND_DEFAULT "bell-window-system"
#define WINTC_SHELL_SND_DEVADD "device-added-media"
#define WINTC_SHELL_SND_DEVREM "device-removed-media"
#define WINTC_SHELL_SND_DEVFAIL "windows-hardfail"
#define WINTC_SHELL_SND_EXCLAM "dialog-question"
#define WINTC_SHELL_SND_EXITWIN "desktop-logout"
#define WINTC_SHELL_SND_BATTLOW "battery-caution"
#define WINTC_SHELL_SND_MAXIMIZE "windows-maximize"
#define WINTC_SHELL_SND_MENUCMD "windows-menu-command"
#define WINTC_SHELL_SND_MENUPOP "windows-menu-popup"
#define WINTC_SHELL_SND_MINIMIZE "windows-minimize"
#define WINTC_SHELL_SND_NEWMAIL "message-new-email"
#define WINTC_SHELL_SND_OPENPRG "windows-open-program"
#define WINTC_SHELL_SND_PRINTCMP "windows-print-complete"
#define WINTC_SHELL_SND_PROGERR "windows-program-error"
#define WINTC_SHELL_SND_QUESTION "windows-question"
#define WINTC_SHELL_SND_RESTDOWN "windows-restore-down"
#define WINTC_SHELL_SND_RESTUP "windows-restore-up"
#define WINTC_SHELL_SND_SELECT "windows-select"
#define WINTC_SHELL_SND_SHOWTOOL "windows-show-toolbar-band"
#define WINTC_SHELL_SND_STARTWIN "desktop-login"
#define WINTC_SHELL_SND_SYSNOTIF "windows-system-notification"
#define WINTC_SHELL_SND_LOGOFF "windows-logoff"
#define WINTC_SHELL_SND_LOGON "windows-logon"
#define WINTC_SHELL_SND_BLKPOPUP "windows-blocked-popup"
#define WINTC_SHELL_SND_CMPNAV "windows-complete-navigation"
#define WINTC_SHELL_SND_EMPTYBIN "trash-empty"
#define WINTC_SHELL_SND_INFOBAR "windows-information-bar"
#define WINTC_SHELL_SND_MOVEITEM "windows-move-menu-item"
#define WINTC_SHELL_SND_STARTNAV "windows-start-navigation"
//
// PUBLIC FUNCTIONS
//
void wintc_sh_play_sound(
const gchar* name
);
#endif

22
shared/shell/src/sound.c Normal file
View File

@@ -0,0 +1,22 @@
#include <canberra.h>
#include <canberra-gtk.h>
#include <glib.h>
#include "../public/sound.h"
//
// PUBLIC FUNCTIONS
//
void wintc_sh_play_sound(
const gchar* name
)
{
ca_context* ctx = ca_gtk_context_get();
ca_context_play(
ctx,
0,
CA_PROP_EVENT_ID, name,
NULL
);
}

View File

@@ -2,5 +2,7 @@ bt,rt:glib2
bt,rt:gtk3
bt,rt:wintc-comctl
bt,rt:wintc-comgtk
bt,rt:wintc-exec
bt,rt:wintc-shcommon
bt,rt:wintc-shellext
bt,rt:wintc-shlang

View File

@@ -1,8 +1,6 @@
#ifndef __INTAPI_H__
#define __INTAPI_H__
#include <glib.h>
//
// PUBLIC CONSTANTS
//

View File

@@ -0,0 +1,108 @@
cmake_minimum_required(VERSION 3.12)
project(
wintc-taskmgr
VERSION 1.0
DESCRIPTION "Windows Total Conversion Task Manager application."
LANGUAGES C
)
set(PROJECT_ANYARCH false)
set(PROJECT_FREESTATUS true)
set(PROJECT_MAINTAINER "Rory Fewell <roryf@oddmatics.uk>")
set(PROJECT_ROOT ${CMAKE_CURRENT_LIST_DIR})
include(GNUInstallDirs)
include(../../packaging/cmake-inc/common/CMakeLists.txt)
include(../../packaging/cmake-inc/linking/CMakeLists.txt)
include(../../packaging/cmake-inc/locale/CMakeLists.txt)
include(../../packaging/cmake-inc/packaging/CMakeLists.txt)
include(../../packaging/cmake-inc/resources/CMakeLists.txt)
wintc_resolve_library(glib-2.0 GLIB)
wintc_resolve_library(gtk+-3.0 GTK3)
wintc_resolve_library(wintc-comctl WINTC_COMCTL)
wintc_resolve_library(wintc-comgtk WINTC_COMGTK)
wintc_resolve_library(wintc-shcommon WINTC_SHCOMMON)
wintc_resolve_library(wintc-shell WINTC_SHELL)
wintc_resolve_library(wintc-shellext WINTC_SHELLEXT)
wintc_resolve_library(wintc-shlang WINTC_SHLANG)
wintc_compile_resources()
wintc_create_meta_h()
add_executable(
wintc-taskmgr
src/application.c
src/application.h
src/intapi.h
src/main.c
src/meta.h
src/pageproc.c
src/pageproc.h
src/procmon.c
src/procmon.h
src/resources.c
src/window.c
src/window.h
)
set_target_properties(
wintc-taskmgr
PROPERTIES
OUTPUT_NAME taskmgr
)
target_compile_options(
wintc-taskmgr
PRIVATE ${WINTC_COMPILE_OPTIONS}
)
target_include_directories(
wintc-taskmgr
SYSTEM
PRIVATE ${GLIB_INCLUDE_DIRS}
PRIVATE ${GTK3_INCLUDE_DIRS}
PRIVATE ${WINTC_COMCTL_INCLUDE_DIRS}
PRIVATE ${WINTC_COMGTK_INCLUDE_DIRS}
PRIVATE ${WINTC_SHCOMMON_INCLUDE_DIRS}
PRIVATE ${WINTC_SHELL_INCLUDE_DIRS}
PRIVATE ${WINTC_SHELLEXT_INCLUDE_DIRS}
PRIVATE ${WINTC_SHLANG_INCLUDE_DIRS}
)
target_link_directories(
wintc-taskmgr
PRIVATE ${GLIB_LIBRARY_DIRS}
PRIVATE ${GTK3_LIBRARY_DIRS}
PRIVATE ${WINTC_COMCTL_LIBRARY_DIRS}
PRIVATE ${WINTC_COMGTK_LIBRARY_DIRS}
PRIVATE ${WINTC_SHCOMMON_LIBRARY_DIRS}
PRIVATE ${WINTC_SHELL_LIBRARY_DIRS}
PRIVATE ${WINTC_SHELLEXT_LIBRARY_DIRS}
PRIVATE ${WINTC_SHLANG_LIBRARY_DIRS}
)
target_link_libraries(
wintc-taskmgr
PRIVATE ${GLIB_LIBRARIES}
PRIVATE ${GTK3_LIBRARIES}
PRIVATE ${WINTC_COMCTL_LIBRARIES}
PRIVATE ${WINTC_COMGTK_LIBRARIES}
PRIVATE ${WINTC_SHCOMMON_LIBRARIES}
PRIVATE ${WINTC_SHELL_LIBRARIES}
PRIVATE ${WINTC_SHELLEXT_LIBRARIES}
PRIVATE ${WINTC_SHLANG_LIBRARIES}
)
# Installation
#
wintc_configure_and_install_packaging()
wintc_install_icons_into_package()
install(
TARGETS wintc-taskmgr
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

View File

@@ -0,0 +1,4 @@
# taskmgr
This directory contains the source code for the *Task Manager*.
![Image](https://github.com/user-attachments/assets/a2c0c17d-8d9e-4e4a-a995-3922b39fcfc8)

8
windows/taskmgr/deps Normal file
View File

@@ -0,0 +1,8 @@
bt,rt:glib2
bt,rt:gtk3
bt,rt:wintc-comctl
bt,rt:wintc-comgtk
bt,rt:wintc-shcommon
bt,rt:wintc-shell
bt,rt:wintc-shellext
bt,rt:wintc-shlang

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

View File

@@ -0,0 +1,90 @@
#include <glib.h>
#include <gtk/gtk.h>
#include <wintc/comctl.h>
#include <wintc/comgtk.h>
#include "application.h"
#include "window.h"
//
// GTK OOP CLASS/INSTANCE DEFINITIONS
//
struct _WinTCTaskmgrApplicationClass
{
GtkApplicationClass __parent__;
};
struct _WinTCTaskmgrApplication
{
GtkApplication __parent__;
};
//
// FORWARD DECLARATIONS
//
static void wintc_taskmgr_application_activate(
GApplication* application
);
static void wintc_taskmgr_application_startup(
GApplication* application
);
//
// GTK TYPE DEFINITIONS & CTORS
//
G_DEFINE_TYPE(
WinTCTaskmgrApplication,
wintc_taskmgr_application,
GTK_TYPE_APPLICATION
)
static void wintc_taskmgr_application_class_init(
WinTCTaskmgrApplicationClass* klass
)
{
GApplicationClass* application_class = G_APPLICATION_CLASS(klass);
application_class->activate = wintc_taskmgr_application_activate;
application_class->startup = wintc_taskmgr_application_startup;
}
static void wintc_taskmgr_application_init(
WINTC_UNUSED(WinTCTaskmgrApplication* self)
) { }
//
// CLASS VIRTUAL METHODS
//
static void wintc_taskmgr_application_activate(
GApplication* application
)
{
GtkWidget* new_window =
wintc_taskmgr_window_new(WINTC_TASKMGR_APPLICATION(application));
gtk_widget_show_all(new_window);
}
static void wintc_taskmgr_application_startup(
GApplication* application
)
{
(G_APPLICATION_CLASS(wintc_taskmgr_application_parent_class))
->startup(application);
wintc_ctl_install_default_styles();
}
//
// PUBLIC FUNCTIONS
//
WinTCTaskmgrApplication* wintc_taskmgr_application_new(void)
{
return WINTC_TASKMGR_APPLICATION(
g_object_new(
wintc_taskmgr_application_get_type(),
"application-id", "uk.co.oddmatics.wintc.samples.taskmgr",
NULL
)
);
}

View File

@@ -0,0 +1,27 @@
#ifndef __APPLICATION_H__
#define __APPLICATION_H__
#include <glib.h>
#include <gtk/gtk.h>
//
// GTK OOP BOILERPLATE
//
typedef struct _WinTCTaskmgrApplicationClass WinTCTaskmgrApplicationClass;
typedef struct _WinTCTaskmgrApplication WinTCTaskmgrApplication;
#define WINTC_TYPE_TASKMGR_APPLICATION (wintc_taskmgr_application_get_type())
#define WINTC_TASKMGR_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WINTC_TYPE_TASKMGR_APPLICATION, WinTCTaskmgrApplication))
#define WINTC_TASKMGR_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WINTC_TYPE_TASKMGR_APPLICATION, WinTCTaskmgrApplicationClass))
#define IS_WINTC_TASKMGR_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WINTC_TYPE_TASKMGR_APPLICATION))
#define IS_WINTC_TASKMGR_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WINTC_TYPE_TASKMGR_APPLICATION))
#define WINTC_TASKMGR_APPLICATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WINTC_TYPE_TASKMGR_APPLICATION, WinTCTaskmgrApplicationClass))
GType wintc_taskmgr_application_get_type(void) G_GNUC_CONST;
//
// PUBLIC FUNCTIONS
//
WinTCTaskmgrApplication* wintc_taskmgr_application_new(void);
#endif

View File

@@ -0,0 +1,9 @@
#ifndef __INTAPI_H__
#define __INTAPI_H__
//
// PUBLIC CONSTANTS
//
#define WINTC_TASKMGR_HOSTEXT_PAGE 1
#endif

View File

@@ -0,0 +1,32 @@
#include <glib.h>
#include <glib/gi18n.h>
#include <locale.h>
#include <wintc/shlang.h>
#include "application.h"
#include "meta.h"
int main(
int argc,
char* argv[]
)
{
// Set up locales
//
setlocale(LC_ALL, "");
bindtextdomain(PKG_NAME, WINTC_LOCALE_DIR);
textdomain(PKG_NAME);
// Launch application
//
WinTCTaskmgrApplication* app = wintc_taskmgr_application_new();
int status;
g_set_application_name("Taskmgr");
status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}

View File

@@ -0,0 +1,295 @@
#include <glib.h>
#include <gtk/gtk.h>
#include <signal.h>
#include <wintc/comgtk.h>
#include <wintc/shcommon.h>
#include <wintc/shell.h>
#include <wintc/shellext.h>
#include <wintc/shlang.h>
#include "intapi.h"
#include "pageproc.h"
#include "procmon.h"
//
// FORWARD DECLARATIONS
//
static void wintc_taskmgr_page_processes_constructed(
GObject* object
);
static void on_button_endproc_clicked(
GtkButton* self,
gpointer user_data
);
static void on_dlgkill_button_yes_clicked(
GtkButton* self,
gpointer user_data
);
static void on_treeview_cursor_changed(
GtkWidget* self,
gpointer user_data
);
//
// GTK OOP CLASS/INSTANCE DEFINITIONS
//
typedef struct _WinTCTaskmgrPageProcesses
{
WinTCShextUIController __parent__;
// UI
//
GtkWidget* button_endproc;
GtkWidget* treeview_procs;
} WinTCTaskmgrPageProcess;
//
// GTK TYPE DEFINITIONS & CTORS
//
G_DEFINE_TYPE(
WinTCTaskmgrPageProcesses,
wintc_taskmgr_page_processes,
WINTC_TYPE_SHEXT_UI_CONTROLLER
)
static void wintc_taskmgr_page_processes_class_init(
WinTCTaskmgrPageProcessesClass* klass
)
{
GObjectClass* object_class = G_OBJECT_CLASS(klass);
object_class->constructed = wintc_taskmgr_page_processes_constructed;
}
static void wintc_taskmgr_page_processes_init(
WINTC_UNUSED(WinTCTaskmgrPageProcesses* self)
) {}
//
// CLASS VIRTUAL METHODS
//
static void wintc_taskmgr_page_processes_constructed(
GObject* object
)
{
WinTCTaskmgrPageProcesses* page = WINTC_TASKMGR_PAGE_PROCESSES(object);
GtkBuilder* builder =
gtk_builder_new_from_resource(
"/uk/oddmatics/wintc/taskmgr/page-processes.ui"
);
wintc_lc_builder_preprocess_widget_text(builder);
// Insert page into host
//
WinTCIShextUIHost* ui_host =
wintc_shext_ui_controller_get_ui_host(
WINTC_SHEXT_UI_CONTROLLER(object)
);
wintc_builder_get_objects(
builder,
"button-endproc", &(page->button_endproc),
"tree-view", &(page->treeview_procs),
NULL
);
wintc_ishext_ui_host_get_ext_widget(
ui_host,
WINTC_TASKMGR_HOSTEXT_PAGE,
GTK_TYPE_BOX,
builder
);
g_object_unref(builder);
// Set up treeview
//
WinTCTaskmgrProcmon* procmon = wintc_taskmgr_procmon_get_instance();
wintc_taskmgr_procmon_bind_tree_view_model(
procmon,
GTK_TREE_VIEW(page->treeview_procs)
);
gtk_tree_view_append_column(
GTK_TREE_VIEW(page->treeview_procs),
gtk_tree_view_column_new_with_attributes(
"Image Name",
gtk_cell_renderer_text_new(),
"text", COLUMN_IMAGE_NAME,
NULL
)
);
gtk_tree_view_append_column(
GTK_TREE_VIEW(page->treeview_procs),
gtk_tree_view_column_new_with_attributes(
"User Name",
gtk_cell_renderer_text_new(),
"text", COLUMN_USER_NAME,
NULL
)
);
gtk_tree_view_append_column(
GTK_TREE_VIEW(page->treeview_procs),
gtk_tree_view_column_new_with_attributes(
"CPU",
gtk_cell_renderer_text_new(),
"text", COLUMN_CPU_USAGE,
NULL
)
);
gtk_tree_view_append_column(
GTK_TREE_VIEW(page->treeview_procs),
gtk_tree_view_column_new_with_attributes(
"Mem Usage",
gtk_cell_renderer_text_new(),
"text", COLUMN_MEM_USAGE,
NULL
)
);
// Hook up signals
//
g_signal_connect(
page->button_endproc,
"clicked",
G_CALLBACK(on_button_endproc_clicked),
page
);
g_signal_connect(
page->treeview_procs,
"cursor-changed",
G_CALLBACK(on_treeview_cursor_changed),
page
);
// Chain up
//
(G_OBJECT_CLASS(wintc_taskmgr_page_processes_parent_class))
->constructed(object);
}
//
// CALLBACKS
//
static void on_button_endproc_clicked(
GtkButton* self,
gpointer user_data
)
{
WinTCTaskmgrPageProcesses* page = WINTC_TASKMGR_PAGE_PROCESSES(user_data);
GtkTreeIter iter;
GtkTreeModel* model = NULL;
if (
!gtk_tree_selection_get_selected(
gtk_tree_view_get_selection(GTK_TREE_VIEW(page->treeview_procs)),
&model,
&iter
)
)
{
return;
}
// Grab the PID and kill
//
guint pid = 0;
gtk_tree_model_get(
model,
&iter,
COLUMN_PID, &pid,
-1
);
// Spawn the dialog to confirm the action
//
GtkBuilder* builder;
GtkWidget* button_no = NULL;
GtkWidget* button_yes = NULL;
GtkWidget* wnd = NULL;
builder =
gtk_builder_new_from_resource(
"/uk/oddmatics/wintc/taskmgr/dlgkill.ui"
);
wintc_lc_builder_preprocess_widget_text(builder);
wintc_builder_get_objects(
builder,
"main-wnd", &wnd,
"button-no", &button_no,
"button-yes", &button_yes,
NULL
);
gtk_window_set_modal(
GTK_WINDOW(wnd),
TRUE
);
gtk_window_set_transient_for(
GTK_WINDOW(wnd),
wintc_widget_get_toplevel_window(GTK_WIDGET(self))
);
g_signal_connect(
button_no,
"clicked",
G_CALLBACK(wintc_button_close_window_on_clicked),
NULL
);
g_signal_connect(
button_yes,
"clicked",
G_CALLBACK(on_dlgkill_button_yes_clicked),
GUINT_TO_POINTER(pid)
);
gtk_window_present_with_time(
GTK_WINDOW(wnd),
0
);
wintc_sh_play_sound(WINTC_SHELL_SND_EXCLAM);
g_object_unref(builder);
}
static void on_dlgkill_button_yes_clicked(
GtkButton* self,
gpointer user_data
)
{
guint pid = GPOINTER_TO_UINT(user_data);
gtk_window_close(
wintc_widget_get_toplevel_window(GTK_WIDGET(self))
);
kill(pid, SIGKILL);
}
static void on_treeview_cursor_changed(
GtkWidget* self,
gpointer user_data
)
{
WinTCTaskmgrPageProcesses* page = WINTC_TASKMGR_PAGE_PROCESSES(user_data);
gtk_widget_set_sensitive(
page->button_endproc,
gtk_tree_selection_get_selected(
gtk_tree_view_get_selection(GTK_TREE_VIEW(self)),
NULL,
NULL
)
);
}

View File

@@ -0,0 +1,20 @@
#ifndef __PAGEPROC_H__
#define __PAGEPROC_H__
#include <glib.h>
#include <wintc/shellext.h>
//
// GTK OOP BOILERPLATE
//
#define WINTC_TYPE_TASKMGR_PAGE_PROCESSES (wintc_taskmgr_page_processes_get_type())
G_DECLARE_FINAL_TYPE(
WinTCTaskmgrPageProcesses,
wintc_taskmgr_page_processes,
WINTC,
TASKMGR_PAGE_PROCESSES,
WinTCShextUIController
)
#endif

View File

@@ -0,0 +1,523 @@
#include <glib.h>
#include <gtk/gtk.h>
#include <stdlib.h>
#include <wintc/comgtk.h>
#include <wintc/shcommon.h>
#include "procmon.h"
//
// FORWARD DECLARATIONS
//
static void process_get_details(
guint pid,
gchar** owner,
guint* cpu_time,
guint* mem_total
);
static void process_get_totals(
guint* cpu_time
);
static gboolean timeout_process_monitor(
gpointer user_data
);
//
// STATIC DATA
//
static gchar* S_PROC_STAT_PATH = NULL;
//
// GTK OOP CLASS/INSTANCE DEFINITIONS
//
typedef struct _WinTCTaskmgrProcmon
{
GObject __parent__;
// State
//
guint id_procmon;
guint last_cpu_time;
GtkListStore* model_procs;
} WinTCTaskmgrProcmon;
//
// GTK TYPE DEFINITIONS & CTORS
//
G_DEFINE_TYPE(
WinTCTaskmgrProcmon,
wintc_taskmgr_procmon,
G_TYPE_OBJECT
)
static void wintc_taskmgr_procmon_class_init(
WINTC_UNUSED(WinTCTaskmgrProcmonClass* klass)
)
{
S_PROC_STAT_PATH =
g_build_path(
G_DIR_SEPARATOR_S,
G_DIR_SEPARATOR_S,
"proc",
"stat",
NULL
);
}
static void wintc_taskmgr_procmon_init(
WinTCTaskmgrProcmon* self
)
{
// Set up model
//
self->model_procs =
gtk_list_store_new(
N_COLUMNS,
G_TYPE_UINT,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_UINT,
G_TYPE_INT,
G_TYPE_INT
);
// Start process monitor
//
self->id_procmon =
g_timeout_add_seconds(
1,
(GSourceFunc) timeout_process_monitor,
self
);
}
//
// PUBLIC FUNCTIONS
//
WinTCTaskmgrProcmon* wintc_taskmgr_procmon_get_instance(void)
{
static WinTCTaskmgrProcmon* singleton;
if (!singleton)
{
singleton =
WINTC_TASKMGR_PROCMON(
g_object_new(
WINTC_TYPE_TASKMGR_PROCMON,
NULL
)
);
}
return singleton;
}
void wintc_taskmgr_procmon_bind_tree_view_model(
WinTCTaskmgrProcmon* procmon,
GtkTreeView* tree_view
)
{
gtk_tree_view_set_model(
tree_view,
GTK_TREE_MODEL(procmon->model_procs)
);
}
//
// PRIVATE FUNCTIONS
//
static void process_get_details(
guint pid,
gchar** owner,
guint* cpu_time,
guint* mem_total
)
{
GError* error = NULL;
gchar* pid_str = g_strdup_printf("%u", pid);
// Owner
//
if (owner)
{
GFile* file_pid = g_file_new_build_filename(
G_DIR_SEPARATOR_S,
"proc",
pid_str,
NULL
);
GFileInfo* file_info = g_file_query_info(
file_pid,
G_FILE_ATTRIBUTE_OWNER_USER,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
NULL,
&error
);
if (file_info)
{
*owner =
g_file_info_get_attribute_as_string(
file_info,
G_FILE_ATTRIBUTE_OWNER_USER
);
g_object_unref(file_info);
}
else
{
#ifdef WINTC_CHECKED
g_warning("Problem querying file info for process %s", pid_str);
wintc_log_error_and_clear(&error);
#else
g_clear_error(&error);
#endif
}
g_object_unref(file_pid);
}
// Stats
//
// FIXME: This is pretty rough, we use utime + stime / total CPU time for
// usage, and we're just displaying virtual memory usage in KB for
// memory total
//
// This is likely pretty far from how Windows displays these stats,
// but it's better than nothing for now
//
gchar* stat_path = g_build_path(
G_DIR_SEPARATOR_S,
G_DIR_SEPARATOR_S,
"proc",
pid_str,
"stat",
NULL
);
gchar* stat_str = NULL;
*cpu_time = 0;
*mem_total = 0;
if (g_file_get_contents(stat_path, &stat_str, NULL, NULL))
{
gchar* mem_s = wintc_strdup_delimited(stat_str, " ", 22);
gchar* utime_s = wintc_strdup_delimited(stat_str, " ", 13);
gchar* stime_s = wintc_strdup_delimited(stat_str, " ", 14);
*cpu_time = strtoul(utime_s, NULL, 0) + strtoul(stime_s, NULL, 0);
*mem_total = strtoul(mem_s, NULL, 0) / 1024;
g_free(stat_str);
g_free(mem_s);
g_free(utime_s);
g_free(stime_s);
}
g_free(stat_path);
g_free(pid_str);
}
static void process_get_totals(
guint* cpu_time
)
{
gchar* cpu_stats = NULL;
if (
g_file_get_contents(
S_PROC_STAT_PATH,
&cpu_stats,
NULL,
NULL
)
)
{
gchar* last_stime_s = wintc_strdup_delimited(
cpu_stats + 5, // skip 'cpu '
" ",
0
);
gchar* last_utime_s = wintc_strdup_delimited(
cpu_stats + 5,
" ",
2
);
*cpu_time =
strtoul(last_stime_s, NULL, 0) + strtoul(last_utime_s, NULL, 0);
g_free(last_stime_s);
g_free(last_utime_s);
g_free(cpu_stats);
}
}
//
// CALLBACKS
//
static gboolean timeout_process_monitor(
gpointer user_data
)
{
WinTCTaskmgrProcmon* procmon = WINTC_TASKMGR_PROCMON(user_data);
// Acquire the total CPU time stats
//
guint total_cpu_delta;
guint total_cpu_time;
process_get_totals(
&total_cpu_time
);
total_cpu_delta = total_cpu_time - procmon->last_cpu_time;
// We store a mapping of PIDs that we found to check against later
//
GHashTable* map_pid_to_exe =
g_hash_table_new_full(
g_direct_hash,
g_direct_equal,
NULL,
(GDestroyNotify) g_free
);
// Retrieve stuff under /proc
//
GList* proc_dirs =
wintc_sh_fs_get_names_as_list(
G_DIR_SEPARATOR_S "proc",
TRUE,
G_FILE_TEST_IS_DIR,
FALSE,
NULL
);
for (GList* iter = proc_dirs; iter; iter = iter->next)
{
const gchar* dir_name = wintc_basename((gchar*) iter->data);
// Only interested in PIDs
//
if (!g_ascii_isdigit(*dir_name))
{
continue;
}
// Retrieve the exe info
//
GFile* file_exe = g_file_new_build_filename(
G_DIR_SEPARATOR_S,
(gchar*) iter->data,
"exe",
NULL
);
GFileInfo* file_info = g_file_query_info(
file_exe,
"standard::symlink-target",
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
NULL,
NULL
);
g_object_unref(file_exe);
if (!file_info)
{
continue;
}
// Pull the info
//
gchar* exe_target =
g_file_info_get_attribute_as_string(
file_info,
"standard::symlink-target"
);
// Track this process
//
if (exe_target)
{
g_hash_table_insert(
map_pid_to_exe,
GUINT_TO_POINTER(
strtoul(dir_name, NULL, 0)
),
g_strdup(wintc_basename(exe_target))
);
g_free(exe_target);
}
g_object_unref(file_info);
}
g_list_free_full(proc_dirs, (GDestroyNotify) g_free);
// Iterate over the current list store, update rows where we have a
// mapping, remove ones we don't, and then insert the remainder
//
GtkTreeIter tree_iter;
if (
gtk_tree_model_get_iter_first(
GTK_TREE_MODEL(procmon->model_procs),
&tree_iter
)
)
{
while (TRUE)
{
guint pid = 0;
gchar* exe = NULL;
gtk_tree_model_get(
GTK_TREE_MODEL(procmon->model_procs),
&tree_iter,
COLUMN_PID, &pid,
COLUMN_IMAGE_NAME, &exe,
-1
);
// If we either don't have a mapping or it doesn't match, delete
// the row
//
const gchar* cmp_exe =
g_hash_table_lookup(map_pid_to_exe, GUINT_TO_POINTER(pid));
if (
!cmp_exe ||
g_strcmp0(exe, cmp_exe) != 0
)
{
if (
!gtk_list_store_remove(
procmon->model_procs,
&tree_iter
)
)
{
break;
}
continue;
}
g_free(exe);
// We DO have a mapping AND it matches, so update the row (and
// remove the mapping so we know it has been dealt with)
//
guint cpu_time;
guint last_cpu_time;
guint mem_usage;
process_get_details(
pid,
NULL,
&cpu_time,
&mem_usage
);
gtk_tree_model_get(
GTK_TREE_MODEL(procmon->model_procs),
&tree_iter,
COLUMN_CPU_TIME, &last_cpu_time,
-1
);
// Update the records
//
guint cpu_delta = cpu_time - last_cpu_time;
gdouble cpu_pct = cpu_delta / (gdouble) total_cpu_delta;
gtk_list_store_set(
procmon->model_procs,
&tree_iter,
COLUMN_CPU_TIME, cpu_time,
COLUMN_CPU_USAGE, (gint) (cpu_pct * 100),
COLUMN_MEM_USAGE, mem_usage,
-1
);
g_hash_table_remove(
map_pid_to_exe,
GUINT_TO_POINTER(pid)
);
// Next...
//
if (
!gtk_tree_model_iter_next(
GTK_TREE_MODEL(procmon->model_procs),
&tree_iter
)
)
{
break;
}
}
}
// Iterate over the remaining items in the map to add them
//
GHashTableIter map_iter;
gpointer map_key_pid;
gpointer map_value_exe;
g_hash_table_iter_init(&map_iter, map_pid_to_exe);
while (
g_hash_table_iter_next(
&map_iter,
&map_key_pid,
&map_value_exe
)
)
{
const gchar* exe = (gchar*) map_value_exe;
guint pid = GPOINTER_TO_UINT(map_key_pid);
guint cpu_time;
guint mem_total;
gchar* owner = NULL;
process_get_details(
pid,
&owner,
&cpu_time,
&mem_total
);
gtk_list_store_append(
procmon->model_procs,
&tree_iter
);
gtk_list_store_set(
procmon->model_procs,
&tree_iter,
COLUMN_PID, pid,
COLUMN_IMAGE_NAME, exe,
COLUMN_USER_NAME, owner,
COLUMN_CPU_TIME, cpu_time,
COLUMN_CPU_USAGE, 0,
COLUMN_MEM_USAGE, mem_total,
-1
);
g_free(owner);
}
g_hash_table_destroy(map_pid_to_exe);
// Update processor stats
//
procmon->last_cpu_time = total_cpu_time;
return G_SOURCE_CONTINUE;
}

View File

@@ -0,0 +1,44 @@
#ifndef __PROCMON_H__
#define __PROCMON_H__
#include <glib.h>
#include <gtk/gtk.h>
//
// PUBLIC ENUMS
//
enum
{
COLUMN_PID = 0,
COLUMN_IMAGE_NAME,
COLUMN_USER_NAME,
COLUMN_CPU_TIME, // utime + stime
COLUMN_CPU_USAGE,
COLUMN_MEM_USAGE,
N_COLUMNS
};
//
// GTK OOP BOILERPLATE
//
#define WINTC_TYPE_TASKMGR_PROCMON (wintc_taskmgr_procmon_get_type())
G_DECLARE_FINAL_TYPE(
WinTCTaskmgrProcmon,
wintc_taskmgr_procmon,
WINTC,
TASKMGR_PROCMON,
GObject
)
//
// PUBLIC FUNCTIONS
//
WinTCTaskmgrProcmon* wintc_taskmgr_procmon_get_instance(void);
void wintc_taskmgr_procmon_bind_tree_view_model(
WinTCTaskmgrProcmon* procmon,
GtkTreeView* tree_view
);
#endif

View File

@@ -0,0 +1,115 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow" id="main-wnd">
<property name="can-focus">False</property>
<property name="resizable">False</property>
<property name="title" translatable="yes">Task Manager Warning</property>
<property name="type-hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">horizontal</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">dialog-warning</property>
<property name="pixel-size">32</property>
<property name="yalign">0.0</property>
<style>
<class name="wintc-mr-lg" />
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">WARNING: Terminating a process can cause undesired results including loss of data and system instability. The process will not be given the chance to save its state or data before it is terminated. Are you sure you want to terminate the process?</property>
<property name="max-width-chars">46</property>
<property name="wrap">TRUE</property>
<property name="xalign">0.0</property>
<style>
<class name="wintc-mr-sm" />
</style>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">horizontal</property>
<property name="halign">GTK_ALIGN_CENTER</property>
<child>
<object class="GtkButton" id="button-yes">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="label" translatable="no">%CTL_YES%</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button-no">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="label" translatable="no">%CTL_NO%</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="wintc-button-box" />
<class name="wintc-mt-lg" />
</style>
</object>
</child>
<style>
<class name="wintc-mb-lg" />
<class name="wintc-ml-lg" />
<class name="wintc-mr-lg" />
<class name="wintc-mt-lg" />
</style>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="3.24"/>
<object class="GtkLabel" id="label-title">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="label" translatable="yes">Processes</property>
</object>
<object class="GtkBox" id="page">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="overlay-scrolling">False</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkTreeView" id="tree-view">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">horizontal</property>
<child>
<object class="GtkCheckButton" id="check-allusers">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="label" translatable="yes">Show processes from all users</property>
<property name="sensitive">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button-endproc">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="label" translatable="yes">End Process</property>
<property name="sensitive">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="wintc-mt-md" />
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="wintc-mb-lg" />
<class name="wintc-ml-lg" />
<class name="wintc-mr-lg" />
<class name="wintc-mt-lg" />
</style>
</object>
</interface>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/uk/oddmatics/wintc/taskmgr">
<file>dlgkill.ui</file>
<file>taskmgr.ui</file>
<file>page-processes.ui</file>
</gresource>
</gresources>

View File

@@ -0,0 +1,314 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="3.24"/>
<object class="GtkBox" id="main-box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkMenuBar" id="main-menubar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">%CTL_FILEMENU%</property>
<child type="submenu">
<object class="GtkMenu">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="action-name">win.notimpl</property>
<property name="label" translatable="yes">New Task (Run...)</property>
<property name="use-underline">True</property>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="action-name">win.exit</property>
<property name="label" translatable="yes">Exit Task Manager</property>
<property name="use-underline">True</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Options</property>
<child type="submenu">
<object class="GtkMenu">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="action-name">win.notimpl</property>
<property name="label" translatable="yes">Always On Top</property>
<property name="use-underline">True</property>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="action-name">win.notimpl</property>
<property name="label" translatable="yes">Minimize On Use</property>
<property name="use-underline">True</property>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="action-name">win.notimpl</property>
<property name="label" translatable="yes">Hide When Minimized</property>
<property name="use-underline">True</property>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="action-name">win.notimpl</property>
<property name="label" translatable="yes">Show 16-bit tasks</property>
<property name="use-underline">True</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">%CTL_VIEWMENU%</property>
<child type="submenu">
<object class="GtkMenu">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="action-name">win.notimpl</property>
<property name="label" translatable="yes">Refresh Now</property>
<property name="use-underline">True</property>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Update Speed</property>
<property name="use-underline">True</property>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="action-name">win.notimpl</property>
<property name="label" translatable="yes">Select Columns</property>
<property name="use-underline">True</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Shut Down</property>
<child type="submenu">
<object class="GtkMenu">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="action-name">win.notimpl</property>
<property name="label" translatable="yes">Stand By</property>
<property name="use-underline">True</property>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="action-name">win.notimpl</property>
<property name="label" translatable="yes">Hibernate</property>
<property name="use-underline">True</property>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="action-name">win.notimpl</property>
<property name="label" translatable="yes">Turn Off</property>
<property name="use-underline">True</property>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="action-name">win.notimpl</property>
<property name="label" translatable="yes">Restart</property>
<property name="use-underline">True</property>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="action-name">win.notimpl</property>
<property name="label" translatable="yes">Log Off %s</property>
<property name="use-underline">True</property>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="action-name">win.notimpl</property>
<property name="label" translatable="yes">Switch User</property>
<property name="use-underline">True</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">%CTL_HELPMENU%</property>
<child type="submenu">
<object class="GtkMenu">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="action-name">win.notimpl</property>
<property name="label" translatable="yes">Task Manager Help Topics</property>
<property name="use-underline">True</property>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="action-name">win.about</property>
<property name="label" translatable="yes">About Task Manager</property>
<property name="use-underline">True</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkNotebook" id="main-notebook">
<property name="visible">True</property>
<property name="can-focus">True</property>
<style>
<class name="wintc-mb-md" />
<class name="wintc-ml-md" />
<class name="wintc-mr-md" />
<class name="wintc-mt-md" />
</style>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box-status">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">horizontal</property>
<child>
<object class="GtkLabel" id="label-procs">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Processes: %d</property>
<style>
<class name="wintc-mb-sm" />
<class name="wintc-ml-sm" />
<class name="wintc-mr-sm" />
<class name="wintc-mt-sm" />
</style>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
</object>
</interface>

View File

@@ -0,0 +1,334 @@
#include <glib.h>
#include <gtk/gtk.h>
#include <wintc/comgtk.h>
#include <wintc/shell.h>
#include <wintc/shellext.h>
#include <wintc/shlang.h>
#include "application.h"
#include "intapi.h"
#include "pageproc.h"
#include "window.h"
//
// FORWARD DECLARATIONS
//
static void wintc_taskmgr_window_ishext_ui_host_interface_init(
WinTCIShextUIHostInterface* iface
);
static void wintc_taskmgr_window_constructed(
GObject* object
);
static void wintc_taskmgr_window_dispose(
GObject* object
);
static GtkWidget* wintc_taskmgr_window_get_ext_widget(
WinTCIShextUIHost* host,
guint ext_id,
GType expected_type,
gpointer ctx
);
static void action_notimpl(
GSimpleAction* action,
GVariant* parameter,
gpointer user_data
);
static void action_about(
GSimpleAction* action,
GVariant* parameter,
gpointer user_data
);
static void action_exit(
GSimpleAction* action,
GVariant* parameter,
gpointer user_data
);
//
// STATIC DATA
//
static GActionEntry s_window_actions[] = {
{
.name = "notimpl",
.activate = action_notimpl,
.parameter_type = NULL,
.state = NULL,
.change_state = NULL
},
{
.name = "about",
.activate = action_about,
.parameter_type = NULL,
.state = NULL,
.change_state = NULL
},
{
.name = "exit",
.activate = action_exit,
.parameter_type = NULL,
.state = NULL,
.change_state = NULL
}
};
//
// GTK OOP CLASS/INSTANCE DEFINITIONS
//
struct _WinTCTaskmgrWindowClass
{
GtkApplicationWindowClass __parent__;
};
struct _WinTCTaskmgrWindow
{
GtkApplicationWindow __parent__;
// UI
//
GtkWidget* notebook_main;
GtkWidget* menubar_main;
WinTCShextUIController* uictl_processes;
};
//
// GTK TYPE DEFINITION & CTORS
//
G_DEFINE_TYPE_WITH_CODE(
WinTCTaskmgrWindow,
wintc_taskmgr_window,
GTK_TYPE_APPLICATION_WINDOW,
G_IMPLEMENT_INTERFACE(
WINTC_TYPE_ISHEXT_UI_HOST,
wintc_taskmgr_window_ishext_ui_host_interface_init
)
)
static void wintc_taskmgr_window_class_init(
WinTCTaskmgrWindowClass* klass
)
{
GObjectClass* object_class = G_OBJECT_CLASS(klass);
object_class->constructed = wintc_taskmgr_window_constructed;
object_class->dispose = wintc_taskmgr_window_dispose;
}
static void wintc_taskmgr_window_init(
WinTCTaskmgrWindow* self
)
{
GtkBuilder* builder;
GtkWidget* main_box = NULL;
// Define GActions
//
g_action_map_add_action_entries(
G_ACTION_MAP(self),
s_window_actions,
G_N_ELEMENTS(s_window_actions),
self
);
// Initialize UI
//
builder =
gtk_builder_new_from_resource(
"/uk/oddmatics/wintc/taskmgr/taskmgr.ui"
);
wintc_lc_builder_preprocess_widget_text(builder);
wintc_builder_get_objects(
builder,
"main-box", &main_box,
"main-menubar", &(self->menubar_main),
"main-notebook", &(self->notebook_main),
NULL
);
gtk_container_add(GTK_CONTAINER(self), main_box);
gtk_widget_set_size_request(
GTK_WIDGET(self),
396,
420
);
g_object_unref(builder);
}
static void wintc_taskmgr_window_ishext_ui_host_interface_init(
WinTCIShextUIHostInterface* iface
)
{
iface->get_ext_widget = wintc_taskmgr_window_get_ext_widget;
}
//
// CLASS VIRTUAL METHODS
//
static void wintc_taskmgr_window_constructed(
GObject* object
)
{
WinTCTaskmgrWindow* wnd = WINTC_TASKMGR_WINDOW(object);
// Init pages
//
wnd->uictl_processes =
wintc_shext_ui_controller_new_from_type(
WINTC_TYPE_TASKMGR_PAGE_PROCESSES,
WINTC_ISHEXT_UI_HOST(object)
);
(G_OBJECT_CLASS(wintc_taskmgr_window_parent_class))
->constructed(object);
}
static void wintc_taskmgr_window_dispose(
GObject* object
)
{
WinTCTaskmgrWindow* wnd = WINTC_TASKMGR_WINDOW(object);
g_clear_object(&(wnd->uictl_processes));
(G_OBJECT_CLASS(wintc_taskmgr_window_parent_class))
->dispose(object);
}
//
// INTERFACE METHODS (WinTCIShextUIHost)
//
static GtkWidget* wintc_taskmgr_window_get_ext_widget(
WinTCIShextUIHost* host,
guint ext_id,
GType expected_type,
gpointer ctx
)
{
WinTCTaskmgrWindow* wnd = WINTC_TASKMGR_WINDOW(host);
switch (ext_id)
{
case WINTC_TASKMGR_HOSTEXT_PAGE:
if (!GTK_IS_BUILDER(ctx))
{
g_critical(
"%s",
"ext_widget: Expected a GtkBuilder!"
);
return NULL;
}
// Try to pull the necessary widgets
//
GtkWidget* label_title = NULL;
GtkWidget* widget_page = NULL;
wintc_builder_get_objects(
GTK_BUILDER(ctx),
"label-title", &label_title,
"page", &widget_page,
NULL
);
if (!label_title || !widget_page)
{
g_critical("%s", "ext_widget: Missing required page widgets.");
return NULL;
}
if (G_OBJECT_TYPE(widget_page) != expected_type)
{
g_critical("%s", "ext_widget: Expected type mismatch.");
return NULL;
}
gtk_notebook_append_page(
GTK_NOTEBOOK(wnd->notebook_main),
widget_page,
label_title
);
return widget_page;
default:
g_critical("ext_widget: %u", ext_id);
return NULL;
}
}
//
// PUBLIC FUNCTIONS
//
GtkWidget* wintc_taskmgr_window_new(
WinTCTaskmgrApplication* app
)
{
return GTK_WIDGET(
g_object_new(
WINTC_TYPE_TASKMGR_WINDOW,
"application", GTK_APPLICATION(app),
"title", "Windows Task Manager",
NULL
)
);
}
//
// CALLBACKS
//
static void action_notimpl(
WINTC_UNUSED(GSimpleAction* action),
WINTC_UNUSED(GVariant* parameter),
gpointer user_data
)
{
WinTCTaskmgrWindow* wnd = WINTC_TASKMGR_WINDOW(user_data);
GError* error = NULL;
g_set_error(
&error,
WINTC_GENERAL_ERROR,
WINTC_GENERAL_ERROR_NOTIMPL,
"%s",
"Action not implemented."
);
wintc_nice_error_and_clear(&error, GTK_WINDOW(wnd));
}
static void action_about(
WINTC_UNUSED(GSimpleAction* action),
WINTC_UNUSED(GVariant* parameter),
gpointer user_data
)
{
WinTCTaskmgrWindow* wnd = WINTC_TASKMGR_WINDOW(user_data);
wintc_sh_about(
GTK_WINDOW(wnd),
"Windows Task Manager",
NULL,
"taskmgr"
);
}
static void action_exit(
WINTC_UNUSED(GSimpleAction* action),
WINTC_UNUSED(GVariant* parameter),
gpointer user_data
)
{
WinTCTaskmgrWindow* wnd = WINTC_TASKMGR_WINDOW(user_data);
gtk_widget_destroy(GTK_WIDGET(wnd));
}

View File

@@ -0,0 +1,31 @@
#ifndef __WINDOW_H__
#define __WINDOW_H__
#include <glib.h>
#include <gtk/gtk.h>
#include "application.h"
//
// GTK OOP BOILERPLATE
//
typedef struct _WinTCTaskmgrWindowClass WinTCTaskmgrWindowClass;
typedef struct _WinTCTaskmgrWindow WinTCTaskmgrWindow;
#define WINTC_TYPE_TASKMGR_WINDOW (wintc_taskmgr_window_get_type())
#define WINTC_TASKMGR_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WINTC_TYPE_TASKMGR_WINDOW, WinTCTaskmgrWindow))
#define WINTC_TASKMGR_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WINTC_TYPE_TASKMGR_WINDOW, WinTCTaskmgrWindowClass))
#define IS_WINTC_TASKMGR_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WINTC_TYPE_TASKMGR_WINDOW))
#define IS_WINTC_TASKMGR_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WINTC_TYPE_TASKMGR_WINDOW))
#define WINTC_TASKMGR_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WINTC_TYPE_TASKMGR_WINDOW, WinTCTaskmgrWindowClass))
GType wintc_taskmgr_window_get_type(void) G_GNUC_CONST;
//
// PUBLIC FUNCTIONS
//
GtkWidget* wintc_taskmgr_window_new(
WinTCTaskmgrApplication* app
);
#endif