Enhancement: Fixes #291, Implement desktop wallpaper support

This commit is contained in:
Rory Fewell
2024-05-09 22:36:54 +01:00
parent 8224319135
commit 53443329dc
78 changed files with 5548 additions and 127 deletions

View File

@@ -0,0 +1,82 @@
cmake_minimum_required(VERSION 3.5)
project(
wintc-regsvc
VERSION 1.0
DESCRIPTION "Windows Total Conversion registry service."
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/packaging/CMakeLists.txt)
wintc_resolve_library(glib-2.0 GLIB)
wintc_resolve_library(gtk+-3.0 GTK3)
wintc_resolve_library(sqlite3 SQLITE3)
wintc_resolve_library(wintc-comgtk WINTC_COMGTK)
wintc_resolve_library(wintc-registry WINTC_REGISTRY)
add_executable(
wintc-regsvc
src/backend.c
src/backend.h
src/main.c
)
set_target_properties(
wintc-regsvc
PROPERTIES
OUTPUT_NAME regsvc
)
target_compile_options(
wintc-regsvc
PRIVATE ${WINTC_COMPILE_OPTIONS}
)
target_include_directories(
wintc-regsvc
SYSTEM
BEFORE
PRIVATE ${GLIB_INCLUDE_DIRS}
PRIVATE ${GTK3_INCLUDE_DIRS}
PRIVATE ${SQLITE3_INCLUDE_DIRS}
PRIVATE ${WINTC_COMGTK_INCLUDE_DIRS}
PRIVATE ${WINTC_REGISTRY_INCLUDE_DIRS}
)
target_link_directories(
wintc-regsvc
PRIVATE ${GLIB_LIBRARY_DIRS}
PRIVATE ${GTK3_LIBRARY_DIRS}
PRIVATE ${SQLITE3_LIBRARY_DIRS}
PRIVATE ${WINTC_COMGTK_LIBRARY_DIRS}
PRIVATE ${WINTC_REGISTRY_LIBRARY_DIRS}
)
target_link_libraries(
wintc-regsvc
PRIVATE ${GLIB_LIBRARIES}
PRIVATE ${GTK3_LIBRARIES}
PRIVATE ${SQLITE3_LIBRARIES}
PRIVATE ${WINTC_COMGTK_LIBRARIES}
PRIVATE ${WINTC_REGISTRY_LIBRARIES}
)
# Installation
#
wintc_configure_and_install_packaging()
install(
TARGETS wintc-regsvc
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

8
base/regsvc/README.MD Normal file
View File

@@ -0,0 +1,8 @@
# regsvc
This directory contains the source-code for the registry service/daemon.
## Details
Essentially `regsvc` is a very billy-basic daemon that provides the backend for the simplified 'registry' interface defined by `libwintc-registry`.
- The registry is implemented as a daemon for DBus-based IPC, so things like Control Panel applets can configure settings and the recipient programs (like the desktop) can be notified
- It's not a full clone of the Windows Registry, just a very simple form
- The backend uses SQLite3 for storage in the user profile

5
base/regsvc/deps Normal file
View File

@@ -0,0 +1,5 @@
bt,rt:glib2
bt,rt:gtk3
bt,rt:sqlite3
bt,rt:wintc-comgtk
bt,rt:wintc-registry

713
base/regsvc/src/backend.c Normal file
View File

@@ -0,0 +1,713 @@
#include <glib.h>
#include <sqlite3.h>
#include <wintc/comgtk.h>
#include "backend.h"
#define WINTC_COMPONENT_REGISTRY "registry"
#define BAIL_ON_FAIL(query) \
rc = (query); \
if (rc == SQLITE_ERROR || rc == SQLITE_MISUSE) \
{ \
handle_sqlite_problem(rc); \
sqlite3_finalize(stmt); \
return FALSE; \
}
//
// PRIVATE CONSTANTS
//
static const gchar* S_SQL_INIT =
"CREATE TABLE IF NOT EXISTS RegKey ("
" Id INTEGER PRIMARY KEY,"
" ParentId INTEGER,"
" Name VARCHAR(255) NOT NULL,"
" FOREIGN KEY(ParentId) REFERENCES RegKey(Id),"
" UNIQUE(ParentId, Name)"
");"
"CREATE TABLE IF NOT EXISTS RegKeyValue ("
" Id INTEGER PRIMARY KEY,"
" OwnerKey INTEGER,"
" Name VARCHAR(255),"
" ItemType INTEGER,"
" ItemValue BLOB,"
" FOREIGN KEY(OwnerKey) REFERENCES RegKey(Id),"
" UNIQUE(OwnerKey, Name)"
");"
"INSERT OR REPLACE INTO RegKey VALUES (1, NULL, 'HKEY_CURRENT_USER');";
//
// STATIC DATA
//
static sqlite3* s_db = NULL;
//
// FORWARD DECLARATIONS
//
static gboolean db_create_regkey(
const gchar* key_name,
gint parent_id,
gint* out_id
);
static gboolean db_get_regkey_id(
const gchar* key_name,
gint parent_id,
gint* out_id
);
static gboolean db_traverse_to_key(
const gchar* key_path,
gint* out_id
);
static void handle_sqlite_problem(
gint rc
);
static gboolean is_valid_key_path(
GSList* components
);
static gboolean is_valid_value_name(
const gchar* value_name
);
static GSList* path_to_components(
const gchar* key_path
);
//
// INTERNAL FUNCTIONS
//
void backend_close(void)
{
if (!s_db)
{
return;
}
WINTC_LOG_DEBUG("%s", "regsvc: sqlite closing profile");
sqlite3_close(s_db);
s_db = NULL;
}
gboolean backend_init(void)
{
GError* error = NULL;
gchar* path;
gint rc;
if (s_db)
{
return TRUE;
}
// Open DB handle
//
if (!wintc_profile_ensure_exists(WINTC_COMPONENT_REGISTRY, &error))
{
wintc_log_error_and_clear(&error);
return FALSE;
}
path = wintc_profile_get_path(WINTC_COMPONENT_REGISTRY, "ntuser.db");
rc = sqlite3_open(path, &s_db);
WINTC_LOG_DEBUG("regsvc: sqlite opening %s", path);
g_free(path);
if (rc)
{
g_critical(
"regsvc: failed to open profile sqlite %s",
sqlite3_errmsg(s_db)
);
sqlite3_close(s_db);
return FALSE;
}
// Ensure tables initialised
//
char* error_sql = NULL;
rc =
sqlite3_exec(
s_db,
S_SQL_INIT,
NULL,
NULL,
&error_sql
);
if (rc != SQLITE_OK)
{
g_critical(
"regsvc: failed to init tables %s",
error_sql
);
sqlite3_free(error_sql);
return FALSE;
}
return TRUE;
}
gboolean backend_create_key(
const gchar* key_path
)
{
GSList* components = path_to_components(key_path);
WINTC_LOG_DEBUG("regsvc: backend create key %s", key_path);
if (!is_valid_key_path(components))
{
WINTC_LOG_DEBUG(
"regsvc: backend create key: key/value not valid '%s'",
key_path
);
g_slist_free_full(components, g_free);
return FALSE;
}
// Iterate over to create the key
//
gint last_id = 0;
gboolean success = TRUE;
for (GSList* iter = components; iter; iter = iter->next)
{
const gchar* key_name = (gchar*) iter->data;
gint this_id = 0;
WINTC_LOG_DEBUG("regsvc: create key checking for part '%s'", key_name);
// Check if key exists first
//
if (!db_get_regkey_id(key_name, last_id, &this_id))
{
success = FALSE;
break;
}
// If needed, create the key
//
if (!this_id)
{
WINTC_LOG_DEBUG("%s", "regsvc: need to create that key");
if (!db_create_regkey(key_name, last_id, &this_id))
{
success = FALSE;
break;
}
}
last_id = this_id;
}
g_slist_free_full(components, g_free);
return success;
}
gboolean backend_get_key_value(
const gchar* key_path,
const gchar* value_name,
WinTCRegistryValueType value_type,
void* value_data
)
{
gint key_id = 0;
gint rc;
if (value_data == NULL)
{
g_critical("%s", "regsvc: backend nowhere to store kv");
return FALSE;
}
if (
!is_valid_value_name(value_name) ||
!db_traverse_to_key(key_path, &key_id)
)
{
WINTC_LOG_DEBUG(
"regsvc: backend get kv: key/value not valid '%s->%s'",
key_path,
value_name
);
return FALSE;
}
// Retrieve key stuff
//
sqlite3_stmt* stmt = NULL;
BAIL_ON_FAIL(
sqlite3_prepare(
s_db,
"SELECT ItemType, ItemValue FROM RegKeyValue WHERE OwnerKey = ? AND Name = ?;",
-1,
&stmt,
NULL
)
);
BAIL_ON_FAIL(sqlite3_bind_int(stmt, 1, key_id));
BAIL_ON_FAIL(sqlite3_bind_text(stmt, 2, value_name, -1, SQLITE_STATIC));
BAIL_ON_FAIL(sqlite3_step(stmt));
// Analyze result
//
WinTCRegistryValueType found_type = WINTC_REG_INVALID;
gboolean success = FALSE;
if (rc == SQLITE_ROW)
{
found_type = (WinTCRegistryValueType) sqlite3_column_int(stmt, 0);
if (found_type == value_type)
{
switch (value_type)
{
case WINTC_REG_DWORD:
*((gint*) value_data) =
sqlite3_column_int(stmt, 1);
break;
case WINTC_REG_QWORD:
*((gint64*) value_data) =
sqlite3_column_int64(stmt, 1);
break;
case WINTC_REG_SZ:
*((gchar**) value_data) =
g_strdup((const gchar*) sqlite3_column_text(stmt, 1));
break;
default:
g_critical(
"regsvc: backend unknown key type %d",
value_type
);
break;
}
success = TRUE;
}
}
sqlite3_finalize(stmt);
return success;
}
gboolean backend_set_key_value(
const gchar* key_path,
const gchar* value_name,
WinTCRegistryValueType value_type,
void* value_data
)
{
gint key_id = 0;
gint rc;
if (value_data == NULL)
{
g_critical("%s", "regsvc: backend no data provided to set kv");
return FALSE;
}
if (
!is_valid_value_name(value_name) ||
!db_traverse_to_key(key_path, &key_id)
)
{
WINTC_LOG_DEBUG(
"regsvc: backend set kv: key/value not valid '%s->%s'",
key_path,
value_name
);
return FALSE;
}
WINTC_LOG_DEBUG("regsvc: traversed to key id %d", key_id);
// Check if we already have a key value
//
gint value_id = 0;
sqlite3_stmt* stmt = NULL;
BAIL_ON_FAIL(
sqlite3_prepare(
s_db,
"SELECT Id FROM RegKeyValue WHERE OwnerKey = ? AND Name = ?;",
-1,
&stmt,
NULL
)
);
BAIL_ON_FAIL(sqlite3_bind_int(stmt, 1, key_id));
BAIL_ON_FAIL(sqlite3_bind_text(stmt, 2, value_name, -1, SQLITE_STATIC));
BAIL_ON_FAIL(sqlite3_step(stmt));
if (rc == SQLITE_ROW)
{
value_id = sqlite3_column_int(stmt, 0);
}
sqlite3_finalize(stmt);
// Set new value
//
gint blob_bind_pos;
if (value_id)
{
BAIL_ON_FAIL(
sqlite3_prepare(
s_db,
"UPDATE RegKeyValue SET ItemType = ?, ItemValue = ? WHERE Id = ?;",
-1,
&stmt,
NULL
)
);
BAIL_ON_FAIL(sqlite3_bind_int(stmt, 1, value_type));
BAIL_ON_FAIL(sqlite3_bind_int(stmt, 3, value_id));
blob_bind_pos = 2;
}
else
{
BAIL_ON_FAIL(
sqlite3_prepare(
s_db,
"INSERT INTO RegKeyValue VALUES (NULL, ?, ?, ?, ?);",
-1,
&stmt,
NULL
)
);
BAIL_ON_FAIL(sqlite3_bind_int(stmt, 1, key_id));
BAIL_ON_FAIL(
sqlite3_bind_text(
stmt,
2,
value_name,
-1,
SQLITE_STATIC
)
);
BAIL_ON_FAIL(sqlite3_bind_int(stmt, 3, value_type));
blob_bind_pos = 4;
}
switch (value_type)
{
case WINTC_REG_DWORD:
BAIL_ON_FAIL(
sqlite3_bind_int(
stmt,
blob_bind_pos,
*((gint*) value_data)
)
);
break;
case WINTC_REG_QWORD:
BAIL_ON_FAIL(
sqlite3_bind_int64(
stmt,
blob_bind_pos,
*((gint64*) value_data)
)
);
break;
case WINTC_REG_SZ:
BAIL_ON_FAIL(
sqlite3_bind_text(
stmt,
blob_bind_pos,
*((gchar**) value_data),
-1,
SQLITE_STATIC
)
);
break;
default:
g_critical("regsvc: sqlite no binding for %d", value_type);
break;
}
BAIL_ON_FAIL(sqlite3_step(stmt));
sqlite3_finalize(stmt);
return TRUE;
}
//
// PRIVATE FUNCTIONS
//
static gboolean db_create_regkey(
const gchar* key_name,
gint parent_id,
gint* out_id
)
{
gint rc;
sqlite3_stmt* stmt = NULL;
WINTC_SAFE_REF_SET(out_id, 0);
BAIL_ON_FAIL(
sqlite3_prepare(
s_db,
"INSERT INTO RegKey VALUES (NULL, ?, ?);",
-1,
&stmt,
NULL
)
);
if (!parent_id)
{
BAIL_ON_FAIL(sqlite3_bind_null(stmt, 1));
}
else
{
BAIL_ON_FAIL(sqlite3_bind_int(stmt, 1, parent_id));
}
BAIL_ON_FAIL(
sqlite3_bind_text(
stmt,
2,
key_name,
-1,
SQLITE_STATIC
)
);
BAIL_ON_FAIL(sqlite3_step(stmt));
return db_get_regkey_id(
key_name,
parent_id,
out_id
);
}
static gboolean db_get_regkey_id(
const gchar* key_name,
gint parent_id,
gint* out_id
)
{
gint rc;
sqlite3_stmt* stmt = NULL;
WINTC_SAFE_REF_SET(out_id, 0);
BAIL_ON_FAIL(
sqlite3_prepare(
s_db,
"SELECT Id FROM RegKey WHERE ParentId IS ? AND Name = ?;",
-1,
&stmt,
NULL
)
);
if (!parent_id)
{
BAIL_ON_FAIL(sqlite3_bind_null(stmt, 1));
}
else
{
BAIL_ON_FAIL(sqlite3_bind_int(stmt, 1, parent_id));
}
BAIL_ON_FAIL(sqlite3_bind_text(stmt, 2, key_name, -1, SQLITE_STATIC));
BAIL_ON_FAIL(sqlite3_step(stmt));
if (rc == SQLITE_ROW)
{
WINTC_SAFE_REF_SET(out_id, sqlite3_column_int(stmt, 0));
}
sqlite3_finalize(stmt);
return TRUE;
}
static gboolean db_traverse_to_key(
const gchar* key_path,
gint* out_id
)
{
GSList* components = path_to_components(key_path);
WINTC_SAFE_REF_SET(out_id, 0);
if (!is_valid_key_path(components))
{
// FIXME: Respond invalid path
g_slist_free_full(components, g_free);
return FALSE;
}
// Attempt to traverse to the key
//
gint last_id = 0;
gboolean success = TRUE;
for (GSList* iter = components; iter; iter = iter->next)
{
const gchar* key_name = (gchar*) iter->data;
gint this_id = 0;
if (!db_get_regkey_id(key_name, last_id, &this_id))
{
success = FALSE;
break;
}
last_id = this_id;
}
if (success)
{
WINTC_SAFE_REF_SET(out_id, last_id);
}
g_slist_free_full(components, g_free);
return success;
}
static void handle_sqlite_problem(
gint rc
)
{
switch (rc)
{
case SQLITE_ERROR:
WINTC_LOG_DEBUG("regsvc: sqlite error: %s", sqlite3_errmsg(s_db));
break;
case SQLITE_MISUSE:
g_critical("%s", "regsvc: sqlite misuse detected");
break;
default:
g_critical("regsvc: unknown sqlite problem %d", rc);
break;
}
}
static gboolean is_valid_key_path(
GSList* components
)
{
if (g_slist_length(components) == 0)
{
return FALSE;
}
// Root must be HKCU
//
if (
g_strcmp0(
(gchar*) g_slist_nth_data(components, 0),
"HKEY_CURRENT_USER"
) != 0
)
{
return FALSE;
}
// Max length of individual components is 255
//
for (GSList* iter = components; iter; iter = iter->next)
{
if (strlen((gchar*) iter->data) > 255)
{
return FALSE;
}
}
return TRUE;
}
static gboolean is_valid_value_name(
const gchar* value_name
)
{
// Can't contain backslashes
//
if (strchr(value_name, '\\'))
{
return FALSE;
}
// Max length of string is 255
//
if (strlen(value_name) > 255)
{
return FALSE;
}
return TRUE;
}
static GSList* path_to_components(
const gchar* key_path
)
{
GSList* components = NULL;
gchar** split = g_strsplit(key_path, "\\", -1);
// Move strings into list
//
for (gint i = 0; split[i] != NULL; i++)
{
components = g_slist_append(components, split[i]);
}
g_free(split); // The list now owns the strings
// Naughty hack... if the first component is HKCU, expand it to
// HKEY_CURRENT_USER
//
GSList* first = g_slist_nth(components, 0);
if (
g_strcmp0(
(gchar*) first->data,
"HKCU"
) == 0
)
{
g_free(first->data);
first->data = g_strdup("HKEY_CURRENT_USER");
}
return components;
}

29
base/regsvc/src/backend.h Normal file
View File

@@ -0,0 +1,29 @@
#ifndef __BACKEND_H__
#define __BACKEND_H__
#include <glib.h>
#include <wintc/registry.h>
//
// INTERNAL FUNCTIONS
//
void backend_close(void);
gboolean backend_init(void);
gboolean backend_create_key(
const gchar* key_path
);
gboolean backend_get_key_value(
const gchar* key_path,
const gchar* value_name,
WinTCRegistryValueType value_type,
void* value_data
);
gboolean backend_set_key_value(
const gchar* key_path,
const gchar* value_name,
WinTCRegistryValueType value_type,
void* value_data
);
#endif

376
base/regsvc/src/main.c Normal file
View File

@@ -0,0 +1,376 @@
#include <glib.h>
#include <glib-unix.h>
#include <signal.h>
#include <wintc/comgtk.h>
#include <wintc/registry.h>
#include "backend.h"
//
// STATIC DATA
//
static GMainLoop* s_main_loop = NULL;
//
// FORWARD DECLARATIONS
//
static void on_name_acquired(
GDBusConnection* connection,
const gchar* name,
gpointer user_data
);
static gboolean on_handle_create_key(
ZWinRegistryGDBUS* reg_dbus,
GDBusMethodInvocation* invocation,
const gchar* key_path,
gpointer user_data
);
static gboolean on_handle_get_key_value(
ZWinRegistryGDBUS* reg_dbus,
GDBusMethodInvocation* invocation,
const gchar* key_path,
const gchar* value_name,
WinTCRegistryValueType value_type,
gpointer user_data
);
static gboolean on_handle_set_key_value(
ZWinRegistryGDBUS* reg_dbus,
GDBusMethodInvocation* invocation,
const gchar* key_path,
const gchar* value_name,
GVariant* value_data,
gboolean silent,
gpointer user_data
);
static gboolean on_sigterm(
gpointer user_data
);
//
// ENTRY POINT
//
int main(
WINTC_UNUSED(int argc),
WINTC_UNUSED(char* argv[])
)
{
s_main_loop = g_main_loop_new(NULL, FALSE);
if (!backend_init())
{
return 1;
}
WINTC_LOG_DEBUG("regsvc: hosting name %s", "uk.oddmatics.wintc.registry");
g_bus_own_name(
G_BUS_TYPE_SESSION,
"uk.oddmatics.wintc.registry",
G_BUS_NAME_OWNER_FLAGS_NONE,
NULL,
on_name_acquired,
NULL,
NULL,
NULL
);
g_unix_signal_add(
SIGTERM,
on_sigterm,
NULL
);
g_main_loop_run(s_main_loop);
g_main_loop_unref(s_main_loop);
backend_close();
return 0;
}
//
// CALLBACKS
//
static void on_name_acquired(
GDBusConnection* connection,
WINTC_UNUSED(const gchar* name),
WINTC_UNUSED(gpointer user_data)
)
{
GError* error = NULL;
ZWinRegistryGDBUS* reg_dbus = zwin_registry_gdbus_skeleton_new();
g_signal_connect(
reg_dbus,
"handle-create-key",
G_CALLBACK(on_handle_create_key),
NULL
);
g_signal_connect(
reg_dbus,
"handle-get-key-value",
G_CALLBACK(on_handle_get_key_value),
NULL
);
g_signal_connect(
reg_dbus,
"handle-set-key-value",
G_CALLBACK(on_handle_set_key_value),
NULL
);
if (
!g_dbus_interface_skeleton_export(
G_DBUS_INTERFACE_SKELETON(reg_dbus),
connection,
"/uk/oddmatics/wintc/registry/GDBUS",
&error
)
)
{
wintc_log_error_and_clear(&error);
}
}
static gboolean on_handle_create_key(
ZWinRegistryGDBUS* reg_dbus,
GDBusMethodInvocation* invocation,
const gchar* key_path,
WINTC_UNUSED(gpointer user_data)
)
{
WINTC_LOG_DEBUG("regsvc: received create key request for %s", key_path);
// Very simply just try creating the key
//
gboolean success = backend_create_key(key_path);
zwin_registry_gdbus_complete_create_key(
reg_dbus,
invocation,
success ? 1 : 0
);
return TRUE;
}
static gboolean on_handle_get_key_value(
ZWinRegistryGDBUS* reg_dbus,
GDBusMethodInvocation* invocation,
const gchar* key_path,
const gchar* value_name,
WinTCRegistryValueType value_type,
WINTC_UNUSED(gpointer user_data)
)
{
WINTC_LOG_DEBUG(
"regsvc: received get key value for %s->%s",
key_path,
value_name
);
// Wrap up in a variant
//
gboolean success = FALSE;
gint value_data_int = 0;
gint64 value_data_int64 = 0;
gchar* value_data_str = NULL;
GVariant* variant_ret = NULL;
switch (value_type)
{
case WINTC_REG_DWORD:
success =
backend_get_key_value(
key_path,
value_name,
WINTC_REG_DWORD,
&value_data_int
);
if (success)
{
variant_ret =
g_variant_new(
"v",
g_variant_new_int32(value_data_int)
);
}
break;
case WINTC_REG_QWORD:
success =
backend_get_key_value(
key_path,
value_name,
WINTC_REG_QWORD,
&value_data_int64
);
if (success)
{
variant_ret =
g_variant_new(
"v",
g_variant_new_int64(value_data_int64)
);
}
break;
case WINTC_REG_SZ:
success =
backend_get_key_value(
key_path,
value_name,
WINTC_REG_SZ,
&value_data_str
);
if (success)
{
variant_ret =
g_variant_new(
"v",
g_variant_new_string(value_data_str)
);
g_free(value_data_str);
}
break;
default:
g_critical("regsvc: unknown type %d", value_type);
success = FALSE;
break;
}
if (!success)
{
// Cannot use maybe-type variants because they're not supported by
// DBus/GDBus, so just respond with 0 - libwintc-registry will discard
// the variant regardless if the result code is 0 so we could respond
// with any variant here and be fine
//
variant_ret = g_variant_new("v", g_variant_new_int32(0));
}
zwin_registry_gdbus_complete_get_key_value(
reg_dbus,
invocation,
variant_ret,
success ? 1 : 0
);
return TRUE;
}
static gboolean on_handle_set_key_value(
ZWinRegistryGDBUS* reg_dbus,
GDBusMethodInvocation* invocation,
const gchar* key_path,
const gchar* value_name,
GVariant* value_data,
gboolean silent,
WINTC_UNUSED(gpointer user_data)
)
{
WINTC_LOG_DEBUG(
"regsvc: received set key value for %s->%s",
key_path,
value_name
);
// The variant incoming determines the type etc.
//
GVariant* inner = g_variant_get_variant(value_data);
gboolean success = FALSE;
WinTCRegistryValueType value_type = wintc_registry_get_type_for_variant(
inner
);
gint value_data_int = 0;
gint64 value_data_int64 = 0;
gchar* value_data_str = NULL;
switch (value_type)
{
case WINTC_REG_DWORD:
value_data_int = g_variant_get_int32(inner);
success =
backend_set_key_value(
key_path,
value_name,
WINTC_REG_DWORD,
&value_data_int
);
break;
case WINTC_REG_QWORD:
value_data_int64 = g_variant_get_int64(inner);
success =
backend_set_key_value(
key_path,
value_name,
WINTC_REG_QWORD,
&value_data_int64
);
break;
case WINTC_REG_SZ:
value_data_str = g_variant_dup_string(inner, NULL);
success =
backend_set_key_value(
key_path,
value_name,
WINTC_REG_SZ,
&value_data_str
);
g_free(value_data_str);
break;
default:
g_critical("%s", "regsvc: set key unknown variant type");
break;
}
zwin_registry_gdbus_complete_set_key_value(
reg_dbus,
invocation,
success ? 1 : 0
);
if (success && !silent)
{
g_signal_emit_by_name(
reg_dbus,
"key-value-changed",
key_path,
value_name,
value_data,
NULL
);
}
return TRUE;
}
static gboolean on_sigterm(
WINTC_UNUSED(gpointer user_data)
)
{
WINTC_LOG_DEBUG("%s", "regsvc: sigterm, exiting...");
g_main_loop_quit(s_main_loop);
return FALSE;
}

View File

@@ -34,7 +34,7 @@ do_packaging()
# Build package now
#
(cd "${pkg_dir}/usr/local" && find . -type f,l) | sed 's/\.\///' > plist
(cd "${pkg_dir}/usr/local" && find -L . -type f) | sed 's/\.\///' > plist
pkg create -M manifest -r "${pkg_dir}" -p plist
cd "${CURDIR}"

View File

@@ -0,0 +1,55 @@
cmake_minimum_required(VERSION 3.5)
# Define function for gdbus-codegen
#
function(wintc_gdbus_codegen XML_FILE OUT_FILE_NOEXT CP_PUBLIC)
find_program(GDBUS_CODEGEN gdbus-codegen REQUIRED)
add_custom_command(
OUTPUT
${CMAKE_CURRENT_SOURCE_DIR}/src/${OUT_FILE_NOEXT}.c
${CMAKE_CURRENT_SOURCE_DIR}/src/${OUT_FILE_NOEXT}.h
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src
COMMAND ${GDBUS_CODEGEN}
ARGS
--interface-prefix uk.oddmatics.wintc.
--generate-c-code ${OUT_FILE_NOEXT}
--c-namespace ZWin
--c-generate-object-manager
${XML_FILE}
VERBATIM
DEPENDS
src/${XML_FILE}
)
add_custom_target(
dbus-codegen
DEPENDS
src/${OUT_FILE_NOEXT}.c
src/${OUT_FILE_NOEXT}.h
)
# If the header is needed in public/ for libraries then copy it
#
if (CP_PUBLIC)
find_program(CP cp REQUIRED)
add_custom_command(
OUTPUT
${CMAKE_CURRENT_SOURCE_DIR}/public/${OUT_FILE_NOEXT}.h
COMMAND ${CP}
ARGS
${CMAKE_CURRENT_SOURCE_DIR}/src/${OUT_FILE_NOEXT}.h
${CMAKE_CURRENT_SOURCE_DIR}/public/${OUT_FILE_NOEXT}.h
VERBATIM
DEPENDS
src/${OUT_FILE_NOEXT}.h
)
add_custom_target(
dbus-codegen-header
DEPENDS
public/${OUT_FILE_NOEXT}.h
)
endif()
endfunction()

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.12)
set(REPO_ROOT ${CMAKE_CURRENT_LIST_DIR}/../../..)
@@ -26,7 +26,7 @@ if (NOT CMAKE_BUILD_TYPE)
endif()
if (${CMAKE_BUILD_TYPE} STREQUAL Debug)
add_definitions(-DWINTC_CHECKED)
add_compile_definitions(WINTC_CHECKED)
endif()
# Handle SKU stuff

View File

@@ -16,6 +16,10 @@ if (NOT DEFINED WINTC_PKGMGR OR "${WINTC_PKGMGR}" STREQUAL "")
set(WINTC_PKGMGR raw)
endif()
# Export install prefix (useful for retrieving data at runtime)
#
add_compile_definitions(WINTC_RT_PREFIX="${CMAKE_INSTALL_PREFIX}")
# Set up library directory
#
if (

View File

@@ -1,6 +1,7 @@
base/bootvid
base/bldtag
base/logonui
base/regsvc
cursors/no-shadow/standard
cursors/with-shadow/standard
fonts
@@ -9,6 +10,7 @@ sounds
themes/native
themes/professional
themes/luna/blue
shell/cpl/desk
shell/cpl/printers
shell/cpl/sysdm
shell/desktop

2
private/play/dbus/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
# Ignore generated output
testreg-skel.*

View File

@@ -0,0 +1,74 @@
cmake_minimum_required(VERSION 3.5)
project(
wintc-dbus-test-clt
VERSION 1.0
DESCRIPTION "Windows Total Conversion DBus test client."
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/codegen/CMakeLists.txt)
include(../../../../packaging/cmake-inc/linking/CMakeLists.txt)
include(../../../../packaging/cmake-inc/packaging/CMakeLists.txt)
wintc_resolve_library(glib-2.0 GLIB)
wintc_resolve_library(gtk+-3.0 GTK3)
wintc_resolve_library(wintc-comgtk WINTC_COMGTK)
wintc_gdbus_codegen(
testreg.xml
testreg-skel
)
add_executable(
wintc-dbus-test-clt
src/main.c
src/testreg-skel.c
src/testreg-skel.h
)
target_compile_options(
wintc-dbus-test-clt
PRIVATE ${WINTC_COMPILE_OPTIONS}
)
target_include_directories(
wintc-dbus-test-clt
SYSTEM
BEFORE
PRIVATE ${GLIB_INCLUDE_DIRS}
PRIVATE ${GTK3_INCLUDE_DIRS}
PRIVATE ${WINTC_COMGTK_INCLUDE_DIRS}
)
target_link_directories(
wintc-dbus-test-clt
PRIVATE ${GLIB_LIBRARY_DIRS}
PRIVATE ${GTK3_LIBRARY_DIRS}
PRIVATE ${WINTC_COMGTK_LIBRARY_DIRS}
)
target_link_libraries(
wintc-dbus-test-clt
PRIVATE ${GLIB_LIBRARIES}
PRIVATE ${GTK3_LIBRARIES}
PRIVATE ${WINTC_COMGTK_LIBRARIES}
)
# Installation
#
wintc_configure_and_install_packaging()
install(
TARGETS wintc-dbus-test-clt
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

View File

@@ -0,0 +1,49 @@
#include <glib.h>
#include <wintc/comgtk.h>
#include "testreg-skel.h"
//
// ENTRY POINT
//
int main()
{
GError* error = NULL;
WinTCTestregGDBUS* proxy;
gchar* szoutput;
proxy =
win_tc_testreg_gdbus_proxy_new_for_bus_sync(
G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
"uk.oddmatics.wintc.testreg",
"/uk/oddmatics/wintc/testreg/GDBUS",
NULL,
&error
);
if (!proxy)
{
wintc_log_error_and_clear(&error);
return 1;
}
win_tc_testreg_gdbus_call_testing_sync(
proxy,
"hello!",
&szoutput,
NULL,
&error
);
if (error)
{
wintc_log_error_and_clear(&error);
return 1;
}
g_message("Client got: %s", szoutput);
g_object_unref(proxy);
return 0;
}

View File

@@ -0,0 +1,8 @@
<node>
<interface name="uk.oddmatics.wintc.testreg.GDBUS">
<method name="Testing">
<arg name="szinput" direction="in" type="s" />
<arg name="szoutput" direction="out" type="s" />
</method>
</interface>
</node>

View File

@@ -0,0 +1,75 @@
cmake_minimum_required(VERSION 3.5)
project(
wintc-dbus-test-srv
VERSION 1.0
DESCRIPTION "Windows Total Conversion DBus test server."
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/codegen/CMakeLists.txt)
include(../../../../packaging/cmake-inc/linking/CMakeLists.txt)
include(../../../../packaging/cmake-inc/packaging/CMakeLists.txt)
wintc_resolve_library(glib-2.0 GLIB)
wintc_resolve_library(gtk+-3.0 GTK3)
wintc_resolve_library(wintc-comgtk WINTC_COMGTK)
wintc_gdbus_codegen(
testreg.xml
testreg-skel
FALSE
)
add_executable(
wintc-dbus-test-srv
src/main.c
src/testreg-skel.c
src/testreg-skel.h
)
target_compile_options(
wintc-dbus-test-srv
PRIVATE ${WINTC_COMPILE_OPTIONS}
)
target_include_directories(
wintc-dbus-test-srv
SYSTEM
BEFORE
PRIVATE ${GLIB_INCLUDE_DIRS}
PRIVATE ${GTK3_INCLUDE_DIRS}
PRIVATE ${WINTC_COMGTK_INCLUDE_DIRS}
)
target_link_directories(
wintc-dbus-test-srv
PRIVATE ${GLIB_LIBRARY_DIRS}
PRIVATE ${GTK3_LIBRARY_DIRS}
PRIVATE ${WINTC_COMGTK_LIBRARY_DIRS}
)
target_link_libraries(
wintc-dbus-test-srv
PRIVATE ${GLIB_LIBRARIES}
PRIVATE ${GTK3_LIBRARIES}
PRIVATE ${WINTC_COMGTK_LIBRARIES}
)
# Installation
#
wintc_configure_and_install_packaging()
install(
TARGETS wintc-dbus-test-srv
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

View File

@@ -0,0 +1,3 @@
bt,rt:glib2
bt,rt:gtk3
bt,rt:wintc-comgtk

View File

@@ -0,0 +1,98 @@
#include <glib.h>
#include <wintc/comgtk.h>
#include "testreg-skel.h"
//
// FORWARD DECLARATIONS
//
static void on_name_acquired(
GDBusConnection* connection,
const gchar* name,
gpointer user_data
);
static gboolean on_handle_testing(
WinTCTestregGDBUS* iface,
GDBusMethodInvocation* invocation,
const gchar* szinput,
gpointer user_data
);
//
// ENTRY POINT
//
int main()
{
GMainLoop* loop;
loop = g_main_loop_new(NULL, FALSE);
g_bus_own_name(
G_BUS_TYPE_SESSION,
"uk.oddmatics.wintc.testreg",
G_BUS_NAME_OWNER_FLAGS_NONE,
NULL,
on_name_acquired,
NULL,
NULL,
NULL
);
g_main_loop_run(loop);
return 0;
}
//
// PRIVATE FUNCTIONS
//
static void on_name_acquired(
GDBusConnection* connection,
WINTC_UNUSED(const gchar* name),
WINTC_UNUSED(gpointer user_data)
)
{
GError* error = NULL;
WinTCTestregGDBUS* iface = win_tc_testreg_gdbus_skeleton_new();
g_signal_connect(
iface,
"handle-testing",
G_CALLBACK(on_handle_testing),
NULL
);
if (
!g_dbus_interface_skeleton_export(
G_DBUS_INTERFACE_SKELETON(iface),
connection,
"/uk/oddmatics/wintc/testreg/GDBUS",
&error
)
)
{
wintc_log_error_and_clear(&error);
}
}
static gboolean on_handle_testing(
WinTCTestregGDBUS* iface,
GDBusMethodInvocation* invocation,
const gchar* szinput,
WINTC_UNUSED(gpointer user_data)
)
{
gchar* szoutput = g_strdup_printf("GDBUS IN: %s", szinput);
win_tc_testreg_gdbus_complete_testing(
iface,
invocation,
szoutput
);
g_message("%s", szoutput);
g_free(szoutput);
return TRUE;
}

View File

@@ -0,0 +1,8 @@
<node>
<interface name="uk.oddmatics.wintc.testreg.GDBUS">
<method name="Testing">
<arg name="szinput" direction="in" type="s" />
<arg name="szoutput" direction="out" type="s" />
</method>
</interface>
</node>

View File

@@ -25,6 +25,8 @@ 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-comgtk WINTC_COMGTK)
wintc_resolve_library(wintc-shcommon WINTC_SHCOMMON)
wintc_resolve_library(wintc-shlang WINTC_SHLANG)
wintc_compile_resources()
@@ -33,6 +35,8 @@ add_library(
src/resources.c
src/animctl.c
public/animctl.h
src/cpl.c
public/cpl.h
src/style.c
public/style.h
)
@@ -57,6 +61,8 @@ target_include_directories(
PRIVATE ${GLIB_INCLUDE_DIRS}
PRIVATE ${GTK3_INCLUDE_DIRS}
PRIVATE ${WINTC_COMGTK_INCLUDE_DIRS}
PRIVATE ${WINTC_SHCOMMON_INCLUDE_DIRS}
PRIVATE ${WINTC_SHLANG_INCLUDE_DIRS}
)
target_link_directories(
@@ -65,6 +71,8 @@ target_link_directories(
PRIVATE ${GLIB_LIBRARY_DIRS}
PRIVATE ${GTK3_LIBRARY_DIRS}
PRIVATE ${WINTC_COMGTK_LIBRARY_DIRS}
PRIVATE ${WINTC_SHCOMMON_LIBRARY_DIRS}
PRIVATE ${WINTC_SHLANG_LIBRARY_DIRS}
)
target_link_libraries(
@@ -73,6 +81,8 @@ target_link_libraries(
PRIVATE ${GLIB_LIBRARIES}
PRIVATE ${GTK3_LIBRARIES}
PRIVATE ${WINTC_COMGTK_LIBRARIES}
PRIVATE ${WINTC_SHCOMMON_LIBRARIES}
PRIVATE ${WINTC_SHLANG_LIBRARIES}
)
# Installation

View File

@@ -2,3 +2,4 @@ bt,rt:gdk-pixbuf2
bt,rt:glib2
bt,rt:gtk3
bt,rt:wintc-comgtk
bt,rt:wintc-shlang

View File

@@ -0,0 +1,13 @@
#ifndef __COMCTL_CPL_H__
#define __COMCTL_CPL_H__
//
// PUBLIC FUNCTIONS
//
void wintc_ctl_cpl_notebook_append_page_from_resource(
GtkNotebook* notebook,
const gchar* resource_path,
...
);
#endif

View File

@@ -2,6 +2,7 @@
#define __WINTC_COMCTL_H__
#include "@LIB_HEADER_DIR@/animctl.h"
#include "@LIB_HEADER_DIR@/cpl.h"
#include "@LIB_HEADER_DIR@/style.h"
#endif

60
shared/comctl/src/cpl.c Normal file
View File

@@ -0,0 +1,60 @@
#include <glib.h>
#include <gtk/gtk.h>
#include <stdarg.h>
#include <wintc/comgtk.h>
#include <wintc/shlang.h>
#include "../public/cpl.h"
//
// PUBLIC FUNCTIONS
//
void wintc_ctl_cpl_notebook_append_page_from_resource(
GtkNotebook* notebook,
const gchar* resource_path,
...
)
{
GtkBuilder* builder;
GtkWidget* box_page;
GtkWidget* label_title;
builder = gtk_builder_new_from_resource(resource_path);
// Handle construction into UI
//
wintc_lc_builder_preprocess_widget_text(builder);
box_page = GTK_WIDGET(gtk_builder_get_object(builder, "page-box"));
label_title = GTK_WIDGET(gtk_builder_get_object(builder, "label-title"));
gtk_notebook_append_page(
notebook,
box_page,
label_title
);
// Pull out objects as requested, args are provided as pairs (name, dstptr)
//
va_list ap;
GtkWidget** next_dst;
gchar* next_name;
va_start(ap, resource_path);
next_name = va_arg(ap, gchar*);
while (next_name)
{
next_dst = va_arg(ap, GtkWidget**);
*next_dst = GTK_WIDGET(gtk_builder_get_object(builder, next_name));
// Iter
//
next_name = va_arg(ap, gchar*);
}
va_end(ap);
g_object_unref(G_OBJECT(builder));
}

2
shared/registry/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
# Ignore generated output
reg-dbus.*

View File

@@ -0,0 +1,91 @@
cmake_minimum_required(VERSION 3.5)
project(
libwintc-registry
VERSION 1.0
DESCRIPTION "Windows Total Conversion registry library."
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})
set(WINTC_NO_PEDANTIC_COMPILE true) # Necessary for gdbus-codegen
include(GNUInstallDirs)
include(../../packaging/cmake-inc/common/CMakeLists.txt)
include(../../packaging/cmake-inc/codegen/CMakeLists.txt)
include(../../packaging/cmake-inc/libraries/CMakeLists.txt)
include(../../packaging/cmake-inc/linking/CMakeLists.txt)
include(../../packaging/cmake-inc/packaging/CMakeLists.txt)
wintc_resolve_library(glib-2.0 GLIB)
wintc_resolve_library(gtk+-3.0 GTK3)
wintc_resolve_library(wintc-comgtk WINTC_COMGTK)
wintc_gdbus_codegen(
dbus-if.xml
reg-dbus
TRUE
)
add_library(
libwintc-registry
public/reg-dbus.h
src/reg-dbus.c
src/reg-dbus.h
src/regwrap.c
public/regwrap.h
src/variant.c
public/variant.h
)
set_target_properties(
libwintc-registry
PROPERTIES
SOVERSION 1
VERSION ${PROJECT_VERSION}
)
target_compile_options(
libwintc-registry
PRIVATE ${WINTC_COMPILE_OPTIONS}
)
target_include_directories(
libwintc-registry
SYSTEM
BEFORE
PRIVATE ${GLIB_INCLUDE_DIRS}
PRIVATE ${GTK3_INCLUDE_DIRS}
PRIVATE ${WINTC_COMGTK_INCLUDE_DIRS}
)
target_link_directories(
libwintc-registry
PRIVATE ${GLIB_LIBRARY_DIRS}
PRIVATE ${GTK3_LIBRARY_DIRS}
PRIVATE ${WINTC_COMGTK_LIBRARY_DIRS}
)
target_link_libraries(
libwintc-registry
PRIVATE ${GLIB_LIBRARIES}
PRIVATE ${GTK3_LIBRARIES}
PRIVATE ${WINTC_COMGTK_LIBRARIES}
)
# Installation
#
wintc_configure_and_install_packaging()
wintc_add_pkgconfig_install()
wintc_install_public_headers()
install(
TARGETS libwintc-registry
LIBRARY DESTINATION ${LIB_DIR}
)

View File

@@ -0,0 +1,5 @@
# libwintc-registry
This directory contains the source code for the registry library.
## Purpose
This library provides the GDBus interface and a simple client-side wrapper for interacting with the registry.

4
shared/registry/deps Normal file
View File

@@ -0,0 +1,4 @@
bt,rt:glib2
bt,rt:gtk3
bt,rt:python3-packaging
bt,rt:wintc-comgtk

View File

@@ -0,0 +1,8 @@
#ifndef __WINTC_REGISTRY_H__
#define __WINTC_REGISTRY_H__
#include "@LIB_HEADER_DIR@/reg-dbus.h"
#include "@LIB_HEADER_DIR@/regwrap.h"
#include "@LIB_HEADER_DIR@/variant.h"
#endif

View File

@@ -0,0 +1,80 @@
#ifndef __REGISTRY_REGWRAP_H__
#define __REGISTRY_REGWRAP_H__
#include <glib.h>
//
// PUBLIC ENUMS
//
typedef enum
{
WINTC_REG_INVALID,
WINTC_REG_DWORD,
WINTC_REG_QWORD,
WINTC_REG_SZ
} WinTCRegistryValueType;
//
// GLIB OOP BOILERPLATE
//
typedef struct _WinTCRegistryClass WinTCRegistryClass;
typedef struct _WinTCRegistry WinTCRegistry;
#define WINTC_TYPE_REGISTRY (wintc_registry_get_type())
#define WINTC_REGISTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WINTC_TYPE_REGISTRY, WinTCRegistry))
#define WINTC_REGISTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WINTC_TYPE_REGISTRY, WinTCRegistryClass))
#define IS_WINTC_REGISTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WINTC_TYPE_REGISTRY))
#define IS_WINTC_REGISTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WINTC_TYPE_REGISTRY))
#define WINTC_REGISTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WINTC_TYPE_REGISTRY, WinTCRegistry))
GType wintc_registry_get_type(void) G_GNUC_CONST;
//
// CALLBACK PROTOTYPES
//
typedef void (*WinTCRegistryKeyCallback) (
WinTCRegistry* registry,
const gchar* key_path,
const gchar* value_name,
GVariant* value_variant,
gpointer user_data
);
//
// PUBLIC FUNCTIONS
//
WinTCRegistry* wintc_registry_new(void);
gboolean wintc_registry_create_key(
WinTCRegistry* registry,
const gchar* key_path,
GError** error
);
gboolean wintc_registry_get_key_value(
WinTCRegistry* registry,
const gchar* key_path,
const gchar* value_name,
WinTCRegistryValueType value_type,
void* value_data,
GError** error
);
gboolean wintc_registry_set_key_value(
WinTCRegistry* registry,
const gchar* key_path,
const gchar* value_name,
WinTCRegistryValueType value_type,
const void* value_data,
gboolean silent,
GError** error
);
void wintc_registry_watch_key(
WinTCRegistry* registry,
const gchar* key_path,
WinTCRegistryKeyCallback callback,
gpointer user_data
);
#endif

View File

@@ -0,0 +1,15 @@
#ifndef __REGISTRY_VARIANT_H__
#define __REGISTRY_VARIANT_H__
#include <glib.h>
#include "regwrap.h"
//
// PUBLIC FUNCTIONS
//
WinTCRegistryValueType wintc_registry_get_type_for_variant(
GVariant* variant
);
#endif

View File

@@ -0,0 +1,30 @@
<node>
<interface name="uk.oddmatics.wintc.registry.GDBUS">
<method name="CreateKey">
<arg name="key_path" direction="in" type="s" />
<arg name="result" direction="out" type="i" />
</method>
<method name="GetKeyValue">
<arg name="key_path" direction="in" type="s" />
<arg name="value_name" direction="in" type="s" />
<arg name="value_type" direction="in" type="i" />
<arg name="value_data" direction="out" type="v" />
<arg name="result" direction="out" type="i" />
</method>
<method name="SetKeyValue">
<arg name="key_path" direction="in" type="s" />
<arg name="value_name" direction="in" type="s" />
<arg name="value_data" direction="in" type="v" />
<arg name="silent" direction="in" type="b" />
<arg name="result" direction="out" type="i" />
</method>
<signal name="KeyValueChanged">
<arg name="key_path" type="s" />
<arg name="value_name" type="s" />
<arg name="value_data" type="v" />
</signal>
</interface>
</node>

View File

@@ -0,0 +1,433 @@
#include <glib.h>
#include <wintc/comgtk.h>
#include "../public/reg-dbus.h"
#include "../public/regwrap.h"
//
// PRIVATE STRUCTS
//
typedef struct _RegistryCBData
{
WinTCRegistryKeyCallback callback;
gpointer user_data;
} RegistryCBData;
//
// FORWARD DECLARATIONS
//
static void wintc_registry_dispose(
GObject* object
);
static gboolean wintc_registry_ensure_proxy(
WinTCRegistry* registry,
GError** error
);
static void on_reg_key_value_changed(
ZWinRegistryGDBUS* proxy,
const gchar* key_path,
const gchar* value_name,
GVariant* value_data,
gpointer user_data
);
//
// GLIB OOP CLASS/INSTANCE DEFINITIONS
//
struct _WinTCRegistryClass
{
GObjectClass __parent__;
};
struct _WinTCRegistry
{
GObject __parent__;
gboolean connected_signal;
GHashTable* map_key_to_cb;
ZWinRegistryGDBUS* proxy;
};
//
// GLIB TYPE DEFINITIONS & CTORS
//
G_DEFINE_TYPE(
WinTCRegistry,
wintc_registry,
G_TYPE_OBJECT
)
static void wintc_registry_class_init(
WinTCRegistryClass* klass
)
{
GObjectClass* object_class = G_OBJECT_CLASS(klass);
object_class->dispose = wintc_registry_dispose;
}
static void wintc_registry_init(
WinTCRegistry* self
)
{
self->map_key_to_cb =
g_hash_table_new_full(
g_str_hash,
g_str_equal,
g_free,
g_free
);
}
//
// CLASS VIRTUAL METHODS
//
static void wintc_registry_dispose(
GObject* object
)
{
WinTCRegistry* registry = WINTC_REGISTRY(object);
g_hash_table_destroy(
registry->map_key_to_cb
);
(G_OBJECT_CLASS(wintc_registry_parent_class))->dispose(object);
}
//
// PUBLIC FUNCTIONS
//
WinTCRegistry* wintc_registry_new(void)
{
return WINTC_REGISTRY(
g_object_new(
WINTC_TYPE_REGISTRY,
NULL
)
);
}
gboolean wintc_registry_create_key(
WinTCRegistry* registry,
const gchar* key_path,
GError** error
)
{
GError* local_error = NULL;
WINTC_SAFE_REF_CLEAR(error);
if (!wintc_registry_ensure_proxy(registry, &local_error))
{
g_propagate_error(error, local_error);
return FALSE;
}
// Perform dbus call
//
gint result = 0;
if (
!zwin_registry_gdbus_call_create_key_sync(
registry->proxy,
key_path,
&result,
NULL,
&local_error
)
)
{
g_propagate_error(error, local_error);
return FALSE;
}
return !!result;
}
gboolean wintc_registry_get_key_value(
WinTCRegistry* registry,
const gchar* key_path,
const gchar* value_name,
WinTCRegistryValueType value_type,
void* value_data,
GError** error
)
{
GError* local_error = NULL;
WINTC_SAFE_REF_CLEAR(error);
switch (value_type)
{
case WINTC_REG_DWORD: *((gint*) value_data) = 0; break;
case WINTC_REG_QWORD: *((gint64*) value_data) = 0; break;
case WINTC_REG_SZ: *((gchar**) value_data) = NULL; break;
default:
g_critical("registry: unknown type %d", value_type);
return FALSE;
}
if (!wintc_registry_ensure_proxy(registry, &local_error))
{
g_propagate_error(error, local_error);
return FALSE;
}
// Perform dbus call
//
gint result = 0;
GVariant* value_variant = NULL;
if (
!zwin_registry_gdbus_call_get_key_value_sync(
registry->proxy,
key_path,
value_name,
value_type,
&value_variant,
&result,
NULL,
&local_error
)
)
{
g_propagate_error(error, local_error);
return FALSE;
}
if (result)
{
GVariant* inner = g_variant_get_variant(value_variant);
switch (value_type)
{
case WINTC_REG_DWORD:
*((gint*) value_data) =
g_variant_get_int32(inner);
break;
case WINTC_REG_QWORD:
*((gint64*) value_data) =
g_variant_get_int64(inner);
break;
case WINTC_REG_SZ:
*((gchar**) value_data) =
g_variant_dup_string(inner, NULL);
break;
default:
g_critical("registry: unknown type %d", value_type);
break;
}
}
g_variant_unref(value_variant);
return TRUE;
}
gboolean wintc_registry_set_key_value(
WinTCRegistry* registry,
const gchar* key_path,
const gchar* value_name,
WinTCRegistryValueType value_type,
const void* value_data,
gboolean silent,
GError** error
)
{
GError* local_error = NULL;
WINTC_SAFE_REF_CLEAR(error);
if (!wintc_registry_ensure_proxy(registry, &local_error))
{
g_propagate_error(error, local_error);
return FALSE;
}
// Set up variant
//
GVariant* value_variant = NULL;
switch (value_type)
{
case WINTC_REG_DWORD:
value_variant =
g_variant_new(
"v",
g_variant_new_int32(
*((const gint*) value_data)
)
);
break;
case WINTC_REG_QWORD:
value_variant =
g_variant_new(
"v",
g_variant_new_int64(
*((const gint64*) value_data)
)
);
break;
case WINTC_REG_SZ:
value_variant =
g_variant_new(
"v",
g_variant_new_string(
*((const gchar**) value_data)
)
);
break;
default:
g_critical("registry: unknown type %d", value_type);
return FALSE;
}
// Perform dbus call
//
gint result = 0;
if (
!zwin_registry_gdbus_call_set_key_value_sync(
registry->proxy,
key_path,
value_name,
value_variant,
silent,
&result,
NULL,
&local_error
)
)
{
g_propagate_error(error, local_error);
return FALSE;
}
return !!result;
}
void wintc_registry_watch_key(
WinTCRegistry* registry,
const gchar* key_path,
WinTCRegistryKeyCallback callback,
gpointer user_data
)
{
GError* error = NULL;
if (!wintc_registry_ensure_proxy(registry, &error))
{
wintc_log_error_and_clear(&error);
return;
}
// Add watcher
//
RegistryCBData* cb_data = g_new(RegistryCBData, 1);
cb_data->callback = callback;
cb_data->user_data = user_data;
if (!registry->connected_signal)
{
g_signal_connect(
registry->proxy,
"key-value-changed",
G_CALLBACK(on_reg_key_value_changed),
registry
);
}
if (
!g_hash_table_replace(
registry->map_key_to_cb,
g_strdup(key_path),
cb_data
)
)
{
g_warning("registry: overwritten key watcher for %s", key_path);
}
}
//
// PRIVATE FUNCTIONS
//
static gboolean wintc_registry_ensure_proxy(
WinTCRegistry* registry,
GError** error
)
{
GError* local_error = NULL;
WINTC_SAFE_REF_CLEAR(error);
if (registry->proxy)
{
return TRUE;
}
registry->proxy =
zwin_registry_gdbus_proxy_new_for_bus_sync(
G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
"uk.oddmatics.wintc.registry",
"/uk/oddmatics/wintc/registry/GDBUS",
NULL,
&local_error
);
if (!registry->proxy)
{
g_propagate_error(error, local_error);
return FALSE;
}
return TRUE;
}
//
// CALLBACKS
//
static void on_reg_key_value_changed(
WINTC_UNUSED(ZWinRegistryGDBUS* proxy),
const gchar* key_path,
const gchar* value_name,
GVariant* value_data,
gpointer user_data
)
{
WinTCRegistry* registry = WINTC_REGISTRY(user_data);
// Look up if there's a handler for this key
//
RegistryCBData* cb_data =
g_hash_table_lookup(registry->map_key_to_cb, key_path);
if (!cb_data)
{
return;
}
// Issue the callback
//
GVariant* inner = g_variant_get_variant(value_data);
cb_data->callback(
registry,
key_path,
value_name,
inner,
cb_data->user_data
);
}

View File

@@ -0,0 +1,28 @@
#include <glib.h>
#include <wintc/comgtk.h>
#include "../public/regwrap.h"
#include "../public/variant.h"
//
// PUBLIC FUNCTIONS
//
WinTCRegistryValueType wintc_registry_get_type_for_variant(
GVariant* variant
)
{
if (g_variant_is_of_type(variant, G_VARIANT_TYPE_INT32))
{
return WINTC_REG_DWORD;
}
else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_INT64))
{
return WINTC_REG_QWORD;
}
else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING))
{
return WINTC_REG_SZ;
}
return WINTC_REG_INVALID;
}

View File

@@ -26,6 +26,8 @@ wintc_resolve_library(wintc-comgtk WINTC_COMGTK)
add_library(
libwintc-shcommon
src/fs.c
public/fs.h
src/path.c
public/path.h
src/places.c

View File

@@ -0,0 +1,15 @@
#ifndef __SHCOMMON_FS_H__
#define __SHCOMMON_FS_H__
//
// PUBLIC FUNCTIONS
//
GSList* wintc_sh_fs_get_names_as_list(
const gchar* path,
gboolean full_names,
GFileTest test,
gboolean recursive,
GError** error
);
#endif

View File

@@ -1,6 +1,7 @@
#ifndef __WINTC_SHCOMMON_H__
#define __WINTC_SHCOMMON_H__
#include "@LIB_HEADER_DIR@/fs.h"
#include "@LIB_HEADER_DIR@/path.h"
#include "@LIB_HEADER_DIR@/places.h"

93
shared/shcommon/src/fs.c Normal file
View File

@@ -0,0 +1,93 @@
#include <glib.h>
#include <wintc/comgtk.h>
#include "../public/fs.h"
//
// PUBLIC FUNCTIONS
//
GSList* wintc_sh_fs_get_names_as_list(
const gchar* path,
gboolean full_names,
GFileTest test,
gboolean recursive,
GError** error
)
{
GDir* dir;
const gchar* dir_entry = NULL;
GSList* dirs_to_enum = NULL;
GSList* entries = NULL;
GSList* iter = NULL;
WINTC_SAFE_REF_CLEAR(error);
WINTC_LOG_DEBUG(
"shcommon: enum dir %s%s",
path,
recursive ? " (recursive)" : ""
);
// Push requested path as the first item
//
dirs_to_enum = g_slist_append(dirs_to_enum, g_strdup(path));
iter = dirs_to_enum;
while (iter)
{
WINTC_LOG_DEBUG("shcommon: enum iter dir %s", (gchar*) iter->data);
dir = g_dir_open((gchar*) iter->data, 0, error);
if (!dir)
{
g_slist_free_full(dirs_to_enum, g_free);
g_slist_free_full(entries, g_free);
return NULL;
}
while ((dir_entry = g_dir_read_name(dir)))
{
gchar* full_path =
g_build_path(
G_DIR_SEPARATOR_S,
(gchar*) iter->data,
dir_entry,
NULL
);
// Take a copy into dirs to enum if needed
//
if (recursive && g_file_test(full_path, G_FILE_TEST_IS_DIR))
{
WINTC_LOG_DEBUG("shcommon: enum iter, add dir %s", dir_entry);
dirs_to_enum =
g_slist_append(dirs_to_enum, g_strdup(full_path));
}
// Move into entries list if it's one we're interested in
//
if (!test || g_file_test(full_path, test))
{
entries =
g_slist_append(
entries,
g_strdup(full_names ? full_path : dir_entry)
);
}
g_free(full_path);
}
g_dir_close(dir);
// Iter to next dir
//
iter = iter->next;
}
g_slist_free_full(dirs_to_enum, g_free);
return entries;
}

View File

@@ -37,8 +37,6 @@ add_library(
public/cpl.h
src/error.c
public/error.h
src/fs.c
src/fs.h
src/icnvwbeh.c
public/icnvwbeh.h
public/trevwbeh.h

View File

@@ -1,8 +1,8 @@
#include <glib.h>
#include <wintc/comgtk.h>
#include <wintc/shcommon.h>
#include "../public/cpl.h"
#include "fs.h"
//
// PRIVATE CONSTANTS
@@ -20,7 +20,14 @@ static const gchar* S_CPL_KEY_ICON_NAME = "Icon";
//
GSList* wintc_sh_cpl_applet_get_all(void)
{
GSList* entries = wintc_sh_fs_get_names_as_list(S_CPL_ENTRIES_DIR, TRUE, NULL);
GSList* entries =
wintc_sh_fs_get_names_as_list(
S_CPL_ENTRIES_DIR,
TRUE,
G_FILE_TEST_IS_REGULAR,
FALSE,
NULL
);
if (!entries)
{

View File

@@ -1,47 +0,0 @@
#include <glib.h>
#include <wintc/comgtk.h>
#include "fs.h"
//
// PUBLIC FUNCTIONS
//
GSList* wintc_sh_fs_get_names_as_list(
const gchar* path,
gboolean full_names,
GError** error
)
{
GDir* dir;
const gchar* dir_entry = NULL;
GSList* entries = NULL;
WINTC_SAFE_REF_CLEAR(error);
WINTC_LOG_DEBUG("fs: enum dir %s", path);
dir = g_dir_open(path, 0, error);
if (!dir)
{
return NULL;
}
while ((dir_entry = g_dir_read_name(dir)))
{
gchar* next_name = full_names ?
g_build_path(
G_DIR_SEPARATOR_S,
path,
dir_entry,
NULL
) :
g_strdup(dir_entry);
entries = g_slist_append(entries, next_name);
}
g_dir_close(dir);
return entries;
}

View File

@@ -1,25 +0,0 @@
#ifndef __FS_H__
#define __FS_H__
#include <glib.h>
//
// FIXME: Temp! fs.c/h should be moved to another lib!
//
// For now we just have sync I/O here, we need:
// - Should move to async I/O
// - Move FS stuff to a separate lib
// - MIME type detection
// - Symlink/shortcut handling
//
//
// PUBLIC FUNCTIONS
//
GSList* wintc_sh_fs_get_names_as_list(
const gchar* path,
gboolean full_names,
GError** error
);
#endif

View File

@@ -3,7 +3,6 @@
#include <wintc/shcommon.h>
#include "../public/vwfs.h"
#include "fs.h"
//
// PRIVATE ENUMS
@@ -262,7 +261,14 @@ void wintc_sh_view_fs_refresh_items(
// FIXME: Error handling (no way of passing to caller)
//
GSList* entries = wintc_sh_fs_get_names_as_list(view_fs->path, FALSE, NULL);
GSList* entries =
wintc_sh_fs_get_names_as_list(
view_fs->path,
FALSE,
0,
FALSE,
NULL
);
// Create actual array
// FIXME: list->array should probs be in comgtk

View File

@@ -0,0 +1,116 @@
cmake_minimum_required(VERSION 3.5)
project(
wintc-cpl-desk
VERSION 1.0
DESCRIPTION "Windows Total Conversion Display Control Panel applet."
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-registry WINTC_REGISTRY)
wintc_resolve_library(wintc-shcommon WINTC_SHCOMMON)
wintc_resolve_library(wintc-shlang WINTC_SHLANG)
wintc_compile_resources()
wintc_create_meta_h()
add_executable(
wintc-cpl-desk
src/application.c
src/application.h
src/main.c
src/meta.h
src/monitor.c
src/monitor.h
src/resources.c
src/settings.c
src/settings.h
src/window.c
src/window.h
)
set_target_properties(
wintc-cpl-desk
PROPERTIES
OUTPUT_NAME desk.cpl
)
target_compile_options(
wintc-cpl-desk
PRIVATE ${WINTC_COMPILE_OPTIONS}
)
target_include_directories(
wintc-cpl-desk
SYSTEM
PRIVATE ${GLIB_INCLUDE_DIRS}
PRIVATE ${GTK3_INCLUDE_DIRS}
PRIVATE ${WINTC_COMCTL_INCLUDE_DIRS}
PRIVATE ${WINTC_COMGTK_INCLUDE_DIRS}
PRIVATE ${WINTC_REGISTRY_INCLUDE_DIRS}
PRIVATE ${WINTC_SHCOMMON_INCLUDE_DIRS}
PRIVATE ${WINTC_SHLANG_INCLUDE_DIRS}
)
target_link_directories(
wintc-cpl-desk
PRIVATE ${GLIB_LIBRARY_DIRS}
PRIVATE ${GTK3_LIBRARY_DIRS}
PRIVATE ${WINTC_COMCTL_LIBRARY_DIRS}
PRIVATE ${WINTC_COMGTK_LIBRARY_DIRS}
PRIVATE ${WINTC_REGISTRY_LIBRARY_DIRS}
PRIVATE ${WINTC_SHCOMMON_LIBRARY_DIRS}
PRIVATE ${WINTC_SHLANG_LIBRARY_DIRS}
)
target_link_libraries(
wintc-cpl-desk
PRIVATE m
PRIVATE ${GLIB_LIBRARIES}
PRIVATE ${GTK3_LIBRARIES}
PRIVATE ${WINTC_COMCTL_LIBRARIES}
PRIVATE ${WINTC_COMGTK_LIBRARIES}
PRIVATE ${WINTC_REGISTRY_LIBRARIES}
PRIVATE ${WINTC_SHCOMMON_LIBRARIES}
PRIVATE ${WINTC_SHLANG_LIBRARIES}
)
add_dependencies(
wintc-cpl-desk
build-gresources
)
# Installation
#
wintc_configure_and_install_packaging()
install(
FILES desk.desktop
DESTINATION share/wintc/cpl
)
install(
FILES uk.co.oddmatics.wintc.cpl-desk.desktop
DESTINATION share/applications
)
install(
TARGETS wintc-cpl-desk
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

7
shell/cpl/desk/deps Normal file
View File

@@ -0,0 +1,7 @@
bt,rt:glib2
bt,rt:gtk3
bt,rt:wintc-comctl
bt,rt:wintc-comgtk
bt,rt:wintc-registry
bt,rt:wintc-shcommon
bt,rt:wintc-shlang

View File

@@ -0,0 +1,5 @@
[CplApplet]
Name=Display
Comment=Change the appearance of your desktop, such as the background, screen saver, colors, font sizes, and screen resolution.
Exec=desk.cpl
Icon=preferences-desktop-display

View File

@@ -0,0 +1,97 @@
#include <glib.h>
#include <gtk/gtk.h>
#include <wintc/comctl.h>
#include <wintc/comgtk.h>
#include "application.h"
#include "window.h"
//
// CONSTANTS
//
static const gchar* S_APP_ID = "uk.co.oddmatics.wintc.cpl-desk";
//
// GTK OOP CLASS/INSTANCE DEFINITIONS
//
struct _WinTCCplDeskApplicationClass
{
GtkApplicationClass __parent__;
};
struct _WinTCCplDeskApplication
{
GtkApplication __parent__;
};
//
// FORWARD DECLARATIONS
//
static void wintc_cpl_desk_application_activate(
GApplication* application
);
static void wintc_cpl_desk_application_startup(
GApplication* application
);
//
// GTK TYPE DEFINITIONS & CTORS
//
G_DEFINE_TYPE(
WinTCCplDeskApplication,
wintc_cpl_desk_application,
GTK_TYPE_APPLICATION
)
static void wintc_cpl_desk_application_class_init(
WinTCCplDeskApplicationClass* klass
)
{
GApplicationClass* application_class = G_APPLICATION_CLASS(klass);
application_class->activate = wintc_cpl_desk_application_activate;
application_class->startup = wintc_cpl_desk_application_startup;
}
static void wintc_cpl_desk_application_init(
WINTC_UNUSED(WinTCCplDeskApplication* self)
) { }
//
// CLASS VIRTUAL METHODS
//
static void wintc_cpl_desk_application_activate(
GApplication* application
)
{
GtkWidget* new_window =
wintc_cpl_desk_window_new(WINTC_CPL_DESK_APPLICATION(application));
gtk_widget_show_all(new_window);
}
static void wintc_cpl_desk_application_startup(
GApplication* application
)
{
(G_APPLICATION_CLASS(wintc_cpl_desk_application_parent_class))
->startup(application);
g_set_prgname(S_APP_ID);
wintc_ctl_install_default_styles();
}
//
// PUBLIC FUNCTIONS
//
WinTCCplDeskApplication* wintc_cpl_desk_application_new(void)
{
return WINTC_CPL_DESK_APPLICATION(
g_object_new(
wintc_cpl_desk_application_get_type(),
"application-id", S_APP_ID,
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 _WinTCCplDeskApplicationClass WinTCCplDeskApplicationClass;
typedef struct _WinTCCplDeskApplication WinTCCplDeskApplication;
#define WINTC_TYPE_CPL_DESK_APPLICATION (wintc_cpl_desk_application_get_type())
#define WINTC_CPL_DESK_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WINTC_TYPE_CPL_DESK_APPLICATION, WinTCCplDeskApplication))
#define WINTC_CPL_DESK_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WINTC_TYPE_CPL_DESK_APPLICATION, WinTCCplDeskApplicationClass))
#define IS_WINTC_CPL_DESK_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WINTC_TYPE_CPL_DESK_APPLICATION))
#define IS_WINTC_CPL_DESK_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WINTC_TYPE_CPL_DESK_APPLICATION))
#define WINTC_CPL_DESK_APPLICATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WINTC_TYPE_CPL_DESK_APPLICATION, WinTCCplDeskApplicationClass))
GType wintc_cpl_desk_application_get_type(void) G_GNUC_CONST;
//
// PUBLIC FUNCTIONS
//
WinTCCplDeskApplication* wintc_cpl_desk_application_new(void);
#endif

32
shell/cpl/desk/src/main.c Normal file
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
//
WinTCCplDeskApplication* app = wintc_cpl_desk_application_new();
int status;
g_set_application_name("Display");
status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}

View File

@@ -0,0 +1,303 @@
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <math.h>
#include <wintc/comgtk.h>
#include "monitor.h"
//
// STATIC CONSTANTS
//
static const gint S_PREVIEW_IMAGE_OFFSET_X = 16;
static const gint S_PREVIEW_IMAGE_OFFSET_Y = 17;
static const gint S_PREVIEW_IMAGE_WIDTH = 152;
static const gint S_PREVIEW_IMAGE_HEIGHT = 112;
//
// GTK OOP CLASS/INSTANCE DEFINITIONS
//
struct _WinTCDeskMonitorClass
{
GtkWidgetClass __parent__;
GdkPixbuf* pixbuf_monitor;
cairo_surface_t* surface_monitor;
gint pixbuf_monitor_height;
gint pixbuf_monitor_width;
};
struct _WinTCDeskMonitor
{
GtkWidget __parent__;
// UI
//
GdkPixbuf* pixbuf_preview;
cairo_surface_t* surface_preview;
};
//
// FORWARD DECLARATIONS
//
static void wintc_desk_monitor_dispose(
GObject* object
);
static gboolean wintc_desk_monitor_draw(
GtkWidget* widget,
cairo_t* cr
);
static void wintc_desk_monitor_get_preferred_height(
GtkWidget* widget,
gint* minimum_height,
gint* natural_height
);
static void wintc_desk_monitor_get_preferred_height_for_width(
GtkWidget* widget,
gint width,
gint* minimum_height,
gint* natural_height
);
static void wintc_desk_monitor_get_preferred_width(
GtkWidget* widget,
gint* minimum_width,
gint* natural_width
);
static void wintc_desk_monitor_get_preferred_width_for_height(
GtkWidget* widget,
gint height,
gint* minimum_width,
gint* natural_width
);
//
// GTK TYPE DEFINITIONS & CTORS
//
G_DEFINE_TYPE(
WinTCDeskMonitor,
wintc_desk_monitor,
GTK_TYPE_WIDGET
)
static void wintc_desk_monitor_class_init(
WinTCDeskMonitorClass* klass
)
{
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
GObjectClass* object_class = G_OBJECT_CLASS(klass);
object_class->dispose = wintc_desk_monitor_dispose;
widget_class->draw =
wintc_desk_monitor_draw;
widget_class->get_preferred_height =
wintc_desk_monitor_get_preferred_height;
widget_class->get_preferred_height_for_width =
wintc_desk_monitor_get_preferred_height_for_width;
widget_class->get_preferred_width =
wintc_desk_monitor_get_preferred_width;
widget_class->get_preferred_width_for_height =
wintc_desk_monitor_get_preferred_width_for_height;
// Load shared monitor graphic resource
//
GError* error = NULL;
klass->pixbuf_monitor =
gdk_pixbuf_new_from_resource(
"/uk/oddmatics/wintc/cpl-desk/monitor.png",
&error
);
wintc_log_error_and_clear(&error);
if (klass->pixbuf_monitor)
{
klass->surface_monitor =
gdk_cairo_surface_create_from_pixbuf(
klass->pixbuf_monitor,
1,
NULL
);
klass->pixbuf_monitor_height =
gdk_pixbuf_get_height(
klass->pixbuf_monitor
);
klass->pixbuf_monitor_width =
gdk_pixbuf_get_width(
klass->pixbuf_monitor
);
}
}
static void wintc_desk_monitor_init(
WinTCDeskMonitor* self
)
{
gtk_widget_set_has_window(GTK_WIDGET(self), FALSE);
}
//
// CLASS VIRTUAL METHODS
//
static void wintc_desk_monitor_dispose(
GObject* object
)
{
WinTCDeskMonitor* monitor = WINTC_DESK_MONITOR(object);
g_clear_object(&(monitor->pixbuf_preview));
cairo_surface_destroy(g_steal_pointer(&monitor->surface_preview));
}
static gboolean wintc_desk_monitor_draw(
GtkWidget* widget,
cairo_t* cr
)
{
WinTCDeskMonitorClass* klass = WINTC_DESK_MONITOR_GET_CLASS(widget);
WinTCDeskMonitor* monitor = WINTC_DESK_MONITOR(widget);
// monitor size
gint monitor_height = klass->pixbuf_monitor_height;
gint monitor_width = klass->pixbuf_monitor_width;
// my size
gint my_height = gtk_widget_get_allocated_height(widget);
gint my_width = gtk_widget_get_allocated_width(widget);
// drawing origin
gdouble target_x = floor((my_width / 2.0f) - (monitor_width / 2.0f));
gdouble target_y = floor((my_height / 2.0f) - (monitor_height / 2.0f));
cairo_translate(
cr,
target_x,
target_y
);
cairo_set_source_surface(
cr,
klass->surface_monitor,
0.0f,
0.0f
);
cairo_pattern_set_extend(
cairo_get_source(cr),
CAIRO_EXTEND_NONE
);
cairo_paint(cr);
if (monitor->surface_preview)
{
cairo_translate(
cr,
S_PREVIEW_IMAGE_OFFSET_X,
S_PREVIEW_IMAGE_OFFSET_Y
);
cairo_set_source_surface(
cr,
monitor->surface_preview,
0.0f,
0.0f
);
cairo_pattern_set_extend(
cairo_get_source(cr),
CAIRO_EXTEND_NONE
);
cairo_paint(cr);
}
return FALSE;
}
static void wintc_desk_monitor_get_preferred_height(
GtkWidget* widget,
gint* minimum_height,
gint* natural_height
)
{
WinTCDeskMonitorClass* klass = WINTC_DESK_MONITOR_GET_CLASS(widget);
*minimum_height = klass->pixbuf_monitor_height;
*natural_height = klass->pixbuf_monitor_height;
}
static void wintc_desk_monitor_get_preferred_height_for_width(
GtkWidget* widget,
WINTC_UNUSED(gint width),
gint* minimum_height,
gint* natural_height
)
{
wintc_desk_monitor_get_preferred_height(
widget,
minimum_height,
natural_height
);
}
static void wintc_desk_monitor_get_preferred_width(
GtkWidget* widget,
gint* minimum_width,
gint* natural_width
)
{
WinTCDeskMonitorClass* klass = WINTC_DESK_MONITOR_GET_CLASS(widget);
*minimum_width = klass->pixbuf_monitor_width;
*natural_width = klass->pixbuf_monitor_width;
}
static void wintc_desk_monitor_get_preferred_width_for_height(
GtkWidget* widget,
WINTC_UNUSED(gint height),
gint* minimum_width,
gint* natural_width
)
{
wintc_desk_monitor_get_preferred_width(
widget,
minimum_width,
natural_width
);
}
//
// PUBLIC FUNCTIONS
//
GtkWidget* wintc_desk_monitor_new(void)
{
return GTK_WIDGET(
g_object_new(
WINTC_TYPE_DESK_MONITOR,
NULL
)
);
}
void wintc_desk_monitor_set_pixbuf(
WinTCDeskMonitor* monitor,
const GdkPixbuf* pixbuf
)
{
g_clear_object(&(monitor->pixbuf_preview));
cairo_surface_destroy(g_steal_pointer(&monitor->surface_preview));
monitor->pixbuf_preview =
gdk_pixbuf_scale_simple(
pixbuf,
S_PREVIEW_IMAGE_WIDTH,
S_PREVIEW_IMAGE_HEIGHT,
GDK_INTERP_NEAREST
);
monitor->surface_preview =
gdk_cairo_surface_create_from_pixbuf(
monitor->pixbuf_preview,
1,
NULL
);
}

View File

@@ -0,0 +1,33 @@
#ifndef __MONITOR_H__
#define __MONITOR_H__
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <glib.h>
#include <gtk/gtk.h>
//
// GTK OOP BOILERPLATE
//
typedef struct _WinTCDeskMonitorClass WinTCDeskMonitorClass;
typedef struct _WinTCDeskMonitor WinTCDeskMonitor;
#define WINTC_TYPE_DESK_MONITOR (wintc_desk_monitor_get_type())
#define WINTC_DESK_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WINTC_TYPE_DESK_MONITOR, WinTCDeskMonitor))
#define WINTC_DESK_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WINTC_TYPE_DESK_MONITOR, WinTCDeskMonitorClass))
#define IS_WINTC_DESK_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WINTC_TYPE_DESK_MONITOR))
#define IS_WINTC_DESK_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WINTC_TYPE_DESK_MONITOR))
#define WINTC_DESK_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WINTC_TYPE_DESK_MONITOR, WinTCDeskMonitorClass))
GType wintc_desk_monitor_get_type(void) G_GNUC_CONST;
//
// PUBLIC FUNCTIONS
//
GtkWidget* wintc_desk_monitor_new(void);
void wintc_desk_monitor_set_pixbuf(
WinTCDeskMonitor* monitor,
const GdkPixbuf* pixbuf
);
#endif

View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.40.0 -->
<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="GtkNotebook" id="main-notebook">
<property name="visible">True</property>
<property name="can-focus">True</property>
</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>
<child>
<object class="GtkButton" id="button-apply">
<property name="label" translatable="no">Apply</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="action-name">win.apply</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button-cancel">
<property name="label" translatable="no">%CTL_CANCEL%</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="action-name">win.cancel</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button-ok">
<property name="label" translatable="no">%CTL_OK%</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="action-name">win.ok</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">2</property>
</packing>
</child>
<style>
<class name="wintc-button-box"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</interface>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@@ -0,0 +1,164 @@
<?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">Appearance</property>
</object>
<object class="GtkBox" id="page-box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<!-- TODO: Need theme preview thing - uxtheme -->
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">horizontal</property>
<!-- Drop downs column -->
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Windows and buttons:</property>
<property name="xalign">0.0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkComboBox">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Color scheme:</property>
<property name="xalign">0.0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkComboBox">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Font size:</property>
<property name="xalign">0.0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkComboBox">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">5</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<!-- Side buttons column -->
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="valign">2</property>
<child>
<object class="GtkButton">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="halign">2</property>
<property name="label" translatable="yes">Effects...</property>
<property name="sensitive">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="halign">2</property>
<property name="label" translatable="yes">Advanced</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>
</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>
</object>
</interface>

View File

@@ -0,0 +1,183 @@
<?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">Desktop</property>
</object>
<object class="GtkBox" id="page-box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="WinTCDeskMonitor" id="monitor">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</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">Background:</property>
<property name="xalign">0.0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<!-- Form stuff - one horizontal outer box with two inner vert boxes -->
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">horizontal</property>
<!-- Wallpaper selection -->
<child>
<object class="GtkBox">
<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">False</property>
<property name="overlay-scrolling">False</property>
<property name="vscrollbar-policy">0</property>
<child>
<object class="GtkListBox" id="listbox-wallpapers">
<property name="visible">True</property>
<property name="can-focus">True</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="GtkButton">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="label" translatable="yes">Customize Desktop...</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>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<!-- Additional wallpaper settings -->
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkButton">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="label" translatable="yes">%PUNC_MOREINPUT%%CTL_BROWSE%</property>
<property name="sensitive">False</property>
</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">Position:</property>
<property name="xalign">0.0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkComboBox">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Color:</property>
<property name="xalign">0.0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkColorButton">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">4</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</interface>

View File

@@ -0,0 +1,219 @@
<?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">Screen Saver</property>
</object>
<object class="GtkBox" id="page-box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="WinTCDeskMonitor" id="monitor">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<!-- Screen saver options -->
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Screen saver</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="GtkComboBox">
<property name="visible">True</property>
<property name="can-focus">True</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">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="label" translatable="yes">Settings</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>
<child>
<object class="GtkButton">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="label" translatable="yes">Preview</property>
<property name="sensitive">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</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>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Wait:</property>
<property name="xalign">0.0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSpinButton">
<property name="visible">True</property>
<property name="can-focus">False</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>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">minutes</property>
<property name="xalign">0.0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkCheckButton">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">On resume, display Welcome screen</property>
<property name="sensitive">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Monitor power</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">To adjust monitor power settings and save energy, click Power.</property>
<property name="max-width-chars">49</property>
<property name="wrap">True</property>
<property name="xalign">1.0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="halign">2</property>
<property name="label" translatable="yes">Power</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>
</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,187 @@
<?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">Settings</property>
</object>
<object class="GtkBox" id="page-box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<!-- TODO: Need monitor preview widget -->
<child>
<object class="WinTCDeskMonitor" id="monitor">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</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">Display:</property>
<property name="xalign">0.0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">(not implemented)</property>
<property name="xalign">0.0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="homogeneous">True</property>
<property name="orientation">horizontal</property>
<!-- Screen resolution frame -->
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Screen resolution</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="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Less</property>
<property name="xalign">0.0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScale">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">More</property>
<property name="xalign">0.0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</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="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">blam! pixels</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Color quality</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkComboBox">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<!-- TODO: Color graphic thing here -->
</object>
</child>
</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">3</property>
</packing>
</child>
</object>
</interface>

View File

@@ -0,0 +1,113 @@
<?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">Themes</property>
</object>
<object class="GtkBox" id="page-box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">A theme is a background plus a set of sounds, icons, and other elements to help you personalize your computer with one click.</property>
<property name="max-width-chars">71</property>
<property name="wrap">True</property>
<property name="xalign">0.0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<!-- Theme selection -->
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Theme:</property>
<property name="xalign">0.0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</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="GtkComboBox">
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">%CTL_SAVEAS%</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</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>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">%CTL_DELETE%</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="sensitive">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<!-- Theme preview -->
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Sample:</property>
<property name="xalign">0.0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
</object>
</interface>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/uk/oddmatics/wintc/cpl-desk">
<file>desk.ui</file>
<file>page-appearance.ui</file>
<file>page-desktop.ui</file>
<file>page-scrnsave.ui</file>
<file>page-settings.ui</file>
<file>page-themes.ui</file>
<file>monitor.png</file>
<file>sample.png</file>
</gresource>
</gresources>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@@ -0,0 +1,246 @@
#include <glib.h>
#include <wintc/comgtk.h>
#include <wintc/registry.h>
#include "settings.h"
//
// PRIVATE ENUMS
//
enum
{
PROP_SETTINGS_CHANGED = 1
};
//
// GTK OOP CLASS/INSTANCE DEFINITIONS
//
struct _WinTCCplDeskSettingsClass
{
GObjectClass __parent__;
};
struct _WinTCCplDeskSettings
{
GObject __parent__;
// Properties
//
gchar* wallpaper_path;
// State
//
gboolean changed;
WinTCRegistry* registry;
};
//
// FORWARD DELCARATIONS
//
static void wintc_cpl_desk_settings_get_property(
GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec
);
static void wintc_cpl_desk_settings_set_property(
GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec
);
static void wintc_cpl_desk_settings_bump_changed(
WinTCCplDeskSettings* settings
);
//
// GTK TYPE DEFINITIONS & CTORS
//
G_DEFINE_TYPE(
WinTCCplDeskSettings,
wintc_cpl_desk_settings,
G_TYPE_OBJECT
)
static void wintc_cpl_desk_settings_class_init(
WinTCCplDeskSettingsClass* klass
)
{
GObjectClass* object_class = G_OBJECT_CLASS(klass);
object_class->get_property = wintc_cpl_desk_settings_get_property;
object_class->set_property = wintc_cpl_desk_settings_set_property;
g_object_class_install_property(
object_class,
PROP_SETTINGS_CHANGED,
g_param_spec_boolean(
"settings-changed",
"SettingsChanged",
"The state of whether there are unsaved changes to settings.",
FALSE,
G_PARAM_READWRITE
)
);
}
static void wintc_cpl_desk_settings_init(
WinTCCplDeskSettings* self
)
{
self->registry = wintc_registry_new();
}
//
// CLASS VIRTUAL METHODS
//
static void wintc_cpl_desk_settings_get_property(
GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec
)
{
WinTCCplDeskSettings* settings = WINTC_CPL_DESK_SETTINGS(object);
switch (prop_id)
{
case PROP_SETTINGS_CHANGED:
g_value_set_boolean(value, settings->changed);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
static void wintc_cpl_desk_settings_set_property(
GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec
)
{
WinTCCplDeskSettings* settings = WINTC_CPL_DESK_SETTINGS(object);
switch (prop_id)
{
case PROP_SETTINGS_CHANGED:
settings->changed = g_value_get_boolean(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
//
// PUBLIC FUNCTIONS
//
WinTCCplDeskSettings* wintc_cpl_desk_settings_new(void)
{
return g_object_new(WINTC_TYPE_CPL_DESK_SETTINGS, NULL);
}
gboolean wintc_cpl_desk_settings_apply(
WinTCCplDeskSettings* settings,
GError** error
)
{
if (
!wintc_registry_set_key_value(
settings->registry,
"HKCU\\Control Panel\\Desktop",
"Wallpaper",
WINTC_REG_SZ,
&(settings->wallpaper_path),
FALSE,
error
)
)
{
return FALSE;
}
g_object_set(
settings,
"settings-changed", FALSE,
NULL
);
return TRUE;
}
gboolean wintc_cpl_desk_settings_load(
WinTCCplDeskSettings* settings,
GError** error
)
{
gchar* sz_wallpaper = NULL;
if (
!wintc_registry_get_key_value(
settings->registry,
"HKCU\\Control Panel\\Desktop",
"Wallpaper",
WINTC_REG_SZ,
&sz_wallpaper,
error
)
)
{
return FALSE;
}
// Bin old settings
//
g_free(g_steal_pointer(&(settings->wallpaper_path)));
// Load in new settings
//
settings->wallpaper_path = sz_wallpaper;
g_object_set(
settings,
"settings-changed", FALSE,
NULL
);
return TRUE;
}
const gchar* wintc_cpl_desk_settings_get_wallpaper(
WinTCCplDeskSettings* settings
)
{
return settings->wallpaper_path;
}
void wintc_cpl_desk_settings_set_wallpaper(
WinTCCplDeskSettings* settings,
const gchar* path
)
{
g_free(g_steal_pointer(&(settings->wallpaper_path)));
settings->wallpaper_path = g_strdup(path);
wintc_cpl_desk_settings_bump_changed(settings);
}
//
// PRIVATE FUNCTIONS
//
static void wintc_cpl_desk_settings_bump_changed(
WinTCCplDeskSettings* settings
)
{
g_object_set(
settings,
"settings-changed", TRUE,
NULL
);
}

View File

@@ -0,0 +1,43 @@
#ifndef __SETTINGS_H__
#define __SETTINGS_H__
#include <glib.h>
//
// GTK OOP BOILERPLATE
//
typedef struct _WinTCCplDeskSettingsClass WinTCCplDeskSettingsClass;
typedef struct _WinTCCplDeskSettings WinTCCplDeskSettings;
#define WINTC_TYPE_CPL_DESK_SETTINGS (wintc_cpl_desk_settings_get_type())
#define WINTC_CPL_DESK_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WINTC_TYPE_CPL_DESK_SETTINGS, WinTCCplDeskSettings))
#define WINTC_CPL_DESK_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WINTC_TYPE_CPL_DESK_SETTINGS, WinTCCplDeskSettingsClass))
#define IS_WINTC_CPL_DESK_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WINTC_TYPE_CPL_DESK_SETTINGS))
#define IS_WINTC_CPL_DESK_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WINTC_TYPE_CPL_DESK_SETTINGS))
#define WINTC_CPL_DESK_SETTINGS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WINTC_TYPE_CPL_DESK_SETTINGS, WinTCCplDeskSettingsClass))
GType wintc_cpl_desk_settings_get_type(void) G_GNUC_CONST;
//
// PUBLIC FUNCTIONS
//
WinTCCplDeskSettings* wintc_cpl_desk_settings_new(void);
gboolean wintc_cpl_desk_settings_apply(
WinTCCplDeskSettings* settings,
GError** error
);
gboolean wintc_cpl_desk_settings_load(
WinTCCplDeskSettings* settings,
GError** error
);
const gchar* wintc_cpl_desk_settings_get_wallpaper(
WinTCCplDeskSettings* settings
);
void wintc_cpl_desk_settings_set_wallpaper(
WinTCCplDeskSettings* settings,
const gchar* path
);
#endif

520
shell/cpl/desk/src/window.c Normal file
View File

@@ -0,0 +1,520 @@
#include <glib.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <wintc/comctl.h>
#include <wintc/comgtk.h>
#include <wintc/shcommon.h>
#include <wintc/shlang.h>
#include "application.h"
#include "monitor.h"
#include "settings.h"
#include "window.h"
//
// FORWARD DECLARATIONS
//
static void wintc_cpl_desk_window_finalize(
GObject* object
);
static void add_wallpaper_to_list(
WinTCCplDeskWindow* wnd,
const gchar* path
);
static void refresh_wallpaper_list(
WinTCCplDeskWindow* wnd
);
static void select_wallpaper_from_list(
WinTCCplDeskWindow* wnd,
const gchar* path
);
static void action_apply(
GSimpleAction* action,
GVariant* parameter,
gpointer user_data
);
static void action_cancel(
GSimpleAction* action,
GVariant* parameter,
gpointer user_data
);
static void action_ok(
GSimpleAction* action,
GVariant* parameter,
gpointer user_data
);
static void on_listbox_wallpapers_row_selected(
GtkListBox* self,
GtkListBoxRow* row,
gpointer user_data
);
static gboolean on_window_map_event(
GtkWidget* self,
GdkEventAny* event,
gpointer user_data
);
//
// STATIC DATA
//
static GActionEntry s_window_actions[] = {
{
.name = "apply",
.activate = action_apply,
.parameter_type = NULL,
.state = NULL,
.change_state = NULL
},
{
.name = "cancel",
.activate = action_cancel,
.parameter_type = NULL,
.state = NULL,
.change_state = NULL
},
{
.name = "ok",
.activate = action_ok,
.parameter_type = NULL,
.state = NULL,
.change_state = NULL
}
};
//
// GTK OOP CLASS/INSTANCE DEFINITIONS
//
struct _WinTCCplDeskWindowClass
{
GtkApplicationWindowClass __parent__;
};
struct _WinTCCplDeskWindow
{
GtkApplicationWindow __parent__;
// State
//
GSList* list_wallpapers;
WinTCCplDeskSettings* settings;
// UI
//
GtkWidget* monitor_desktop;
GtkWidget* listbox_wallpapers;
GtkWidget* notebook_main;
gboolean sync_settings;
};
//
// GTK TYPE DEFINITION & CTORS
//
G_DEFINE_TYPE(
WinTCCplDeskWindow,
wintc_cpl_desk_window,
GTK_TYPE_APPLICATION_WINDOW
)
static void wintc_cpl_desk_window_class_init(
WinTCCplDeskWindowClass* klass
)
{
GObjectClass* object_class = G_OBJECT_CLASS(klass);
object_class->finalize = wintc_cpl_desk_window_finalize;
}
static void wintc_cpl_desk_window_init(
WinTCCplDeskWindow* self
)
{
GtkBuilder* builder;
GtkWidget* main_box;
gtk_widget_set_size_request(
GTK_WIDGET(self),
414, // Approx.
454
);
gtk_window_set_default_size(
GTK_WINDOW(self),
414, // Approx.
454
);
gtk_window_set_icon_name(
GTK_WINDOW(self),
"preferences-desktop-display"
);
gtk_window_set_resizable(
GTK_WINDOW(self),
FALSE
);
gtk_window_set_skip_taskbar_hint(
GTK_WINDOW(self),
TRUE
);
// Init settings
//
self->settings = wintc_cpl_desk_settings_new();
// Define GActions
//
g_action_map_add_action_entries(
G_ACTION_MAP(self),
s_window_actions,
G_N_ELEMENTS(s_window_actions),
self
);
g_object_bind_property(
self->settings,
"settings-changed",
g_action_map_lookup_action(
G_ACTION_MAP(self),
"apply"
),
"enabled",
0
);
// Initialize UI
//
g_type_ensure(WINTC_TYPE_DESK_MONITOR);
builder =
gtk_builder_new_from_resource(
"/uk/oddmatics/wintc/cpl-desk/desk.ui"
);
wintc_lc_builder_preprocess_widget_text(builder);
main_box = GTK_WIDGET(gtk_builder_get_object(builder, "main-box"));
gtk_container_add(GTK_CONTAINER(self), main_box);
// Pull out widgets
//
self->notebook_main = GTK_WIDGET(
gtk_builder_get_object(
builder,
"main-notebook"
)
);
g_object_unref(G_OBJECT(builder));
// Init pages
//
wintc_ctl_cpl_notebook_append_page_from_resource(
GTK_NOTEBOOK(self->notebook_main),
"/uk/oddmatics/wintc/cpl-desk/page-themes.ui",
NULL
);
wintc_ctl_cpl_notebook_append_page_from_resource(
GTK_NOTEBOOK(self->notebook_main),
"/uk/oddmatics/wintc/cpl-desk/page-desktop.ui",
"listbox-wallpapers", &(self->listbox_wallpapers),
"monitor", &(self->monitor_desktop),
NULL
);
wintc_ctl_cpl_notebook_append_page_from_resource(
GTK_NOTEBOOK(self->notebook_main),
"/uk/oddmatics/wintc/cpl-desk/page-scrnsave.ui",
NULL
);
wintc_ctl_cpl_notebook_append_page_from_resource(
GTK_NOTEBOOK(self->notebook_main),
"/uk/oddmatics/wintc/cpl-desk/page-appearance.ui",
NULL
);
wintc_ctl_cpl_notebook_append_page_from_resource(
GTK_NOTEBOOK(self->notebook_main),
"/uk/oddmatics/wintc/cpl-desk/page-settings.ui",
NULL
);
// Attach signals
//
g_signal_connect(
self,
"map-event",
G_CALLBACK(on_window_map_event),
NULL
);
g_signal_connect(
self->listbox_wallpapers,
"row-selected",
G_CALLBACK(on_listbox_wallpapers_row_selected),
self
);
// Initial load stuff
//
refresh_wallpaper_list(self);
}
//
// CLASS VIRTUAL METHODS
//
static void wintc_cpl_desk_window_finalize(
GObject* object
)
{
WinTCCplDeskWindow* wnd = WINTC_CPL_DESK_WINDOW(object);
g_slist_free_full(wnd->list_wallpapers, g_free);
(G_OBJECT_CLASS(wintc_cpl_desk_window_parent_class))->finalize(object);
}
//
// PUBLIC FUNCTIONS
//
GtkWidget* wintc_cpl_desk_window_new(
WinTCCplDeskApplication* app
)
{
return GTK_WIDGET(
g_object_new(
WINTC_TYPE_CPL_DESK_WINDOW,
"application", GTK_APPLICATION(app),
"title", _("Display Properties"),
NULL
)
);
}
//
// PRIVATE FUNCTIONS
//
static void add_wallpaper_to_list(
WinTCCplDeskWindow* wnd,
const gchar* path
)
{
gchar* filename = g_path_get_basename(path);
GtkWidget* label = gtk_label_new(filename);
gtk_label_set_xalign(GTK_LABEL(label), 0.0f);
gtk_list_box_insert(
GTK_LIST_BOX(wnd->listbox_wallpapers),
label,
-1
);
g_free(filename);
}
static void refresh_wallpaper_list(
WinTCCplDeskWindow* wnd
)
{
g_slist_free_full(wnd->list_wallpapers, g_free);
wintc_container_clear(GTK_CONTAINER(wnd->listbox_wallpapers));
// Load up wallpapers
//
GError* error = NULL;
GSList* iter = NULL;
wnd->list_wallpapers =
wintc_sh_fs_get_names_as_list(
WINTC_RT_PREFIX "/share/backgrounds",
TRUE,
G_FILE_TEST_IS_REGULAR,
TRUE,
&error
);
if (!wnd->list_wallpapers)
{
wintc_nice_error_and_clear(&error);
return;
}
iter = wnd->list_wallpapers;
while (iter)
{
add_wallpaper_to_list(wnd, (gchar*) iter->data);
iter = iter->next;
}
}
static void select_wallpaper_from_list(
WinTCCplDeskWindow* wnd,
const gchar* path
)
{
gint i = 0;
if (!path)
{
return;
}
for (GSList* iter = wnd->list_wallpapers; iter; iter = iter->next)
{
if (g_strcmp0((gchar*) iter->data, path) == 0)
{
gtk_list_box_select_row(
GTK_LIST_BOX(wnd->listbox_wallpapers),
gtk_list_box_get_row_at_index(
GTK_LIST_BOX(wnd->listbox_wallpapers),
i
)
);
return;
}
i++;
}
// The path isnt in the listbox, so add it and select last item
//
add_wallpaper_to_list(wnd, path);
gtk_list_box_select_row(
GTK_LIST_BOX(wnd->listbox_wallpapers),
gtk_list_box_get_row_at_index(
GTK_LIST_BOX(wnd->listbox_wallpapers),
g_slist_length(wnd->list_wallpapers) - 1
)
);
}
//
// CALLBACKS
//
static void action_apply(
WINTC_UNUSED(GSimpleAction* action),
WINTC_UNUSED(GVariant* parameter),
gpointer user_data
)
{
WinTCCplDeskWindow* wnd = WINTC_CPL_DESK_WINDOW(user_data);
GError* error = NULL;
if (!wintc_cpl_desk_settings_apply(wnd->settings, &error))
{
wintc_nice_error_and_clear(&error);
}
}
static void action_cancel(
WINTC_UNUSED(GSimpleAction* action),
WINTC_UNUSED(GVariant* parameter),
gpointer user_data
)
{
gtk_window_close(GTK_WINDOW(user_data));
}
static void action_ok(
WINTC_UNUSED(GSimpleAction* action),
WINTC_UNUSED(GVariant* parameter),
gpointer user_data
)
{
GAction* action_apply =
g_action_map_lookup_action(
G_ACTION_MAP(user_data),
"apply"
);
// Try applying settings...
//
g_action_activate(
action_apply,
NULL
);
// ...we can assume it worked if the apply action is disabled
//
if (!g_action_get_enabled(action_apply))
{
gtk_window_close(GTK_WINDOW(user_data));
}
}
static void on_listbox_wallpapers_row_selected(
WINTC_UNUSED(GtkListBox* self),
GtkListBoxRow* row,
gpointer user_data
)
{
WinTCCplDeskWindow* wnd = WINTC_CPL_DESK_WINDOW(user_data);
GError* error = NULL;
GdkPixbuf* pixbuf_wallpaper;
const gchar* wallpaper_path;
wallpaper_path =
g_slist_nth_data(
wnd->list_wallpapers,
gtk_list_box_row_get_index(row)
);
pixbuf_wallpaper =
gdk_pixbuf_new_from_file(
wallpaper_path,
&error
);
if (!pixbuf_wallpaper)
{
wintc_nice_error_and_clear(&error);
return;
}
wintc_desk_monitor_set_pixbuf(
WINTC_DESK_MONITOR(wnd->monitor_desktop),
pixbuf_wallpaper
);
if (!wnd->sync_settings)
{
wintc_cpl_desk_settings_set_wallpaper(
wnd->settings,
wallpaper_path
);
}
g_object_unref(pixbuf_wallpaper);
}
static gboolean on_window_map_event(
GtkWidget* self,
WINTC_UNUSED(GdkEventAny* event),
WINTC_UNUSED(gpointer user_data)
)
{
WinTCCplDeskWindow* wnd = WINTC_CPL_DESK_WINDOW(self);
GError* error = NULL;
if (!wintc_cpl_desk_settings_load(wnd->settings, &error))
{
wintc_nice_error_and_clear(&error);
return FALSE;
}
wnd->sync_settings = TRUE;
select_wallpaper_from_list(
wnd,
wintc_cpl_desk_settings_get_wallpaper(wnd->settings)
);
wnd->sync_settings = FALSE;
return FALSE;
}

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 _WinTCCplDeskWindowClass WinTCCplDeskWindowClass;
typedef struct _WinTCCplDeskWindow WinTCCplDeskWindow;
#define WINTC_TYPE_CPL_DESK_WINDOW (wintc_cpl_desk_window_get_type())
#define WINTC_CPL_DESK_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WINTC_TYPE_CPL_DESK_WINDOW, WinTCCplDeskWindow))
#define WINTC_CPL_DESK_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WINTC_TYPE_CPL_DESK_WINDOW, WinTCCplDeskWindowClass))
#define IS_WINTC_CPL_DESK_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WINTC_TYPE_CPL_DESK_WINDOW))
#define IS_WINTC_CPL_DESK_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WINTC_TYPE_CPL_DESK_WINDOW))
#define WINTC_CPL_DESK_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WINTC_TYPE_CPL_DESK_WINDOW, WinTCCplDeskWindowClass))
GType wintc_cpl_desk_window_get_type(void) G_GNUC_CONST;
//
// PUBLIC FUNCTIONS
//
GtkWidget* wintc_cpl_desk_window_new(
WinTCCplDeskApplication* app
);
#endif

View File

@@ -0,0 +1,10 @@
[Desktop Entry]
Name=Display
Comment=Change the appearance of your desktop, such as the background, screen saver, colors, font sizes, and screen resolution.
Exec=desk.cpl
Icon=preferences-desktop-display
Terminal=false
StartupNotify=false
Type=Application
Categories=Settings;GTK;
OnlyShowIn=WINTC;

View File

@@ -1,6 +1,7 @@
#include <glib.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <wintc/comctl.h>
#include <wintc/comgtk.h>
#include <wintc/shlang.h>
@@ -10,11 +11,6 @@
//
// FORWARD DECLARATIONS
//
static void add_sysdm_page(
GtkNotebook* notebook_main,
gchar* resource_path
);
static void action_close(
GSimpleAction* action,
GVariant* parameter,
@@ -117,9 +113,10 @@ static void wintc_cpl_sysdm_window_init(
// Init pages
//
add_sysdm_page(
wintc_ctl_cpl_notebook_append_page_from_resource(
GTK_NOTEBOOK(self->notebook_main),
"/uk/oddmatics/wintc/cpl-sysdm/page-gen.ui"
"/uk/oddmatics/wintc/cpl-sysdm/page-gen.ui",
NULL
);
}
@@ -140,34 +137,6 @@ GtkWidget* wintc_cpl_sysdm_window_new(
);
}
//
// PRIVATE FUNCTIONS
//
static void add_sysdm_page(
GtkNotebook* notebook_main,
gchar* resource_path
)
{
GtkBuilder* builder;
GtkWidget* box_page;
GtkWidget* label_title;
builder = gtk_builder_new_from_resource(resource_path);
wintc_lc_builder_preprocess_widget_text(builder);
box_page = GTK_WIDGET(gtk_builder_get_object(builder, "page-box"));
label_title = GTK_WIDGET(gtk_builder_get_object(builder, "label-title"));
gtk_notebook_append_page(
notebook_main,
box_page,
label_title
);
g_object_unref(G_OBJECT(builder));
}
//
// CALLBACKS
//

View File

@@ -22,6 +22,7 @@ include(../../packaging/cmake-inc/packaging/CMakeLists.txt)
wintc_resolve_library(glib-2.0 GLIB)
wintc_resolve_library(gtk+-3.0 GTK3)
wintc_resolve_library(wintc-comgtk WINTC_COMGTK)
wintc_resolve_library(wintc-registry WINTC_REGISTRY)
wintc_resolve_library(wintc-shelldpa WINTC_SHELLDPA)
add_executable(
@@ -29,6 +30,8 @@ add_executable(
src/application.c
src/application.h
src/main.c
src/settings.c
src/settings.h
src/window.c
src/window.h
)
@@ -45,6 +48,7 @@ target_include_directories(
PRIVATE ${GLIB_INCLUDE_DIRS}
PRIVATE ${GTK3_INCLUDE_DIRS}
PRIVATE ${WINTC_COMGTK_INCLUDE_DIRS}
PRIVATE ${WINTC_REGISTRY_INCLUDE_DIRS}
PRIVATE ${WINTC_SHELLDPA_INCLUDE_DIRS}
)
@@ -53,6 +57,7 @@ target_link_directories(
PRIVATE ${GLIB_LIBRARY_DIRS}
PRIVATE ${GTK3_LIBRARY_DIRS}
PRIVATE ${WINTC_COMGTK_LIBRARY_DIRS}
PRIVATE ${WINTC_REGISTRY_LIBRARY_DIRS}
PRIVATE ${WINTC_SHELLDPA_LIBRARY_DIRS}
)
@@ -61,6 +66,7 @@ target_link_libraries(
PRIVATE ${GLIB_LIBRARIES}
PRIVATE ${GTK3_LIBRARIES}
PRIVATE ${WINTC_COMGTK_LIBRARIES}
PRIVATE ${WINTC_REGISTRY_LIBRARIES}
PRIVATE ${WINTC_SHELLDPA_LIBRARIES}
)

View File

@@ -1,4 +1,5 @@
bt,rt:glib2
bt,rt:gtk3
bt,rt:wintc-comgtk
bt,rt:wintc-registry
bt,rt:wintc-shelldpa

View File

@@ -4,6 +4,7 @@
#include <wintc/shelldpa.h>
#include "application.h"
#include "settings.h"
#include "window.h"
//
@@ -17,6 +18,8 @@ struct _WinTCDesktopApplicationClass
struct _WinTCDesktopApplication
{
GtkApplication __parent__;
WinTCDesktopSettings* settings;
};
//
@@ -49,8 +52,11 @@ static void wintc_desktop_application_class_init(
}
static void wintc_desktop_application_init(
WINTC_UNUSED(WinTCDesktopApplication* self)
) {}
WinTCDesktopApplication* self
)
{
self->settings = wintc_desktop_settings_new();
}
//
// PUBLIC FUNCTIONS
@@ -97,7 +103,11 @@ static void wintc_desktop_application_activate(
for (int i = 0; i < n_monitors; i++)
{
GdkMonitor* monitor = gdk_display_get_monitor(display, i);
GtkWidget* wnd = wintc_desktop_window_new(desktop_app, monitor);
GtkWidget* wnd = wintc_desktop_window_new(
desktop_app,
monitor,
desktop_app->settings
);
gtk_widget_show_all(wnd);
}

View File

@@ -0,0 +1,283 @@
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <glib.h>
#include <wintc/comgtk.h>
#include <wintc/registry.h>
#include "settings.h"
//
// PRIVATE ENUMS
//
enum
{
PROP_PIXBUF_WALLPAPER = 1
};
//
// GTK OOP CLASS/INSTANCE DEFINITIONS
//
struct _WinTCDesktopSettingsClass
{
GObjectClass __parent__;
};
struct _WinTCDesktopSettings
{
GObject __parent__;
// State
//
WinTCRegistry* registry;
// Properties
//
GdkPixbuf* pixbuf_wallpaper;
};
//
// FORWARD DECLARATIONS
//
static void wintc_desktop_settings_dispose(
GObject* object
);
static void wintc_desktop_settings_get_property(
GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec
);
static void wintc_desktop_settings_set_property(
GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec
);
static void wintc_desktop_settings_set_wallpaper_path(
WinTCDesktopSettings* settings,
const gchar* wallpaper_path
);
static void regkey_changed_desktop_cb(
WinTCRegistry* registry,
const gchar* key_path,
const gchar* value_name,
GVariant* value_variant,
gpointer user_data
);
//
// GTK TYPE DEFINITIONS & CTORS
//
G_DEFINE_TYPE(
WinTCDesktopSettings,
wintc_desktop_settings,
G_TYPE_OBJECT
)
static void wintc_desktop_settings_class_init(
WinTCDesktopSettingsClass* klass
)
{
GObjectClass* object_class = G_OBJECT_CLASS(klass);
object_class->dispose = wintc_desktop_settings_dispose;
object_class->get_property = wintc_desktop_settings_get_property;
object_class->set_property = wintc_desktop_settings_set_property;
g_object_class_install_property(
object_class,
PROP_PIXBUF_WALLPAPER,
g_param_spec_object(
"pixbuf-wallpaper",
"PixbufWallpaper",
"The pixbuf that should be used as the desktop wallpaper.",
GDK_TYPE_PIXBUF,
G_PARAM_READWRITE
)
);
}
static void wintc_desktop_settings_init(
WinTCDesktopSettings* self
)
{
GError* error = NULL;
// Initial registry set up
//
self->registry = wintc_registry_new();
if (
!wintc_registry_create_key(
self->registry,
"HKCU\\Control Panel\\Desktop",
&error
)
)
{
wintc_log_error_and_clear(&error);
}
// Get some stuff from registry for startup
//
gchar* sz_wallpaper = NULL;
if (
!wintc_registry_get_key_value(
self->registry,
"HKCU\\Control Panel\\Desktop",
"Wallpaper",
WINTC_REG_SZ,
&sz_wallpaper,
&error
)
)
{
wintc_log_error_and_clear(&error);
}
if (sz_wallpaper)
{
wintc_desktop_settings_set_wallpaper_path(self, sz_wallpaper);
g_free(sz_wallpaper);
}
// Set up watcher
//
wintc_registry_watch_key(
self->registry,
"HKCU\\Control Panel\\Desktop",
regkey_changed_desktop_cb,
self
);
}
//
// CLASS VIRTUAL METHODS
//
static void wintc_desktop_settings_dispose(
GObject* object
)
{
WinTCDesktopSettings* settings = WINTC_DESKTOP_SETTINGS(object);
g_clear_object(&(settings->pixbuf_wallpaper));
(G_OBJECT_CLASS(wintc_desktop_settings_parent_class))->dispose(object);
}
static void wintc_desktop_settings_get_property(
GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec
)
{
WinTCDesktopSettings* settings = WINTC_DESKTOP_SETTINGS(object);
switch (prop_id)
{
case PROP_PIXBUF_WALLPAPER:
g_value_set_object(value, settings->pixbuf_wallpaper);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
static void wintc_desktop_settings_set_property(
GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec
)
{
WinTCDesktopSettings* settings = WINTC_DESKTOP_SETTINGS(object);
switch (prop_id)
{
case PROP_PIXBUF_WALLPAPER:
g_clear_object(&(settings->pixbuf_wallpaper));
settings->pixbuf_wallpaper = g_value_dup_object(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
//
// PUBLIC FUNCTIONS
//
WinTCDesktopSettings* wintc_desktop_settings_new(void)
{
return g_object_new(WINTC_TYPE_DESKTOP_SETTINGS, NULL);
}
//
// PRIVATE FUNCTIONS
//
static void wintc_desktop_settings_set_wallpaper_path(
WinTCDesktopSettings* settings,
const gchar* wallpaper_path
)
{
GError* error = NULL;
GdkPixbuf* pixbuf_wallpaper;
WINTC_LOG_DEBUG("desktop: setting wallpaper to %s", wallpaper_path);
pixbuf_wallpaper =
gdk_pixbuf_new_from_file(
wallpaper_path,
&error
);
if (!pixbuf_wallpaper)
{
wintc_log_error_and_clear(&error);
return;
}
g_object_set(
settings,
"pixbuf-wallpaper", pixbuf_wallpaper,
NULL
);
g_object_unref(pixbuf_wallpaper);
}
//
// CALLBACK
//
static void regkey_changed_desktop_cb(
WINTC_UNUSED(WinTCRegistry* registry),
const gchar* key_path,
const gchar* value_name,
GVariant* value_variant,
WINTC_UNUSED(gpointer user_data)
)
{
WinTCDesktopSettings* settings = WINTC_DESKTOP_SETTINGS(user_data);
WINTC_LOG_DEBUG("desktop: saw key changed %s->%s", key_path, value_name);
if (g_strcmp0(value_name, "Wallpaper") == 0)
{
if (wintc_registry_get_type_for_variant(value_variant) != WINTC_REG_SZ)
{
WINTC_LOG_DEBUG("%s", "desktop: wallpaper setting is not REG_SZ");
return;
}
wintc_desktop_settings_set_wallpaper_path(
settings,
g_variant_get_string(value_variant, NULL)
);
}
}

View File

@@ -0,0 +1,26 @@
#ifndef __SETTINGS_H__
#define __SETTINGS_H__
#include <glib.h>
//
// GTK OOP BOILERPLATE
//
typedef struct _WinTCDesktopSettingsClass WinTCDesktopSettingsClass;
typedef struct _WinTCDesktopSettings WinTCDesktopSettings;
#define WINTC_TYPE_DESKTOP_SETTINGS (wintc_desktop_settings_get_type())
#define WINTC_DESKTOP_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WINTC_TYPE_DESKTOP_SETTINGS, WinTCDesktopSettings))
#define WINTC_DESKTOP_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WINTC_TYPE_DESKTOP_SETTINGS, WinTCDesktopSettingsClass))
#define IS_WINTC_DESKTOP_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WINTC_TYPE_DESKTOP_SETTINGS))
#define IS_WINTC_DESKTOP_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WINTC_TYPE_DESKTOP_SETTINGS))
#define WINTC_DESKTOP_SETTINGS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WINTC_TYPE_DESKTOP_SETTINGS, WinTCDesktopSettingsClass))
GType wintc_desktop_settings_get_type(void) G_GNUC_CONST;
//
// PUBLIC FUNCTIONS
//
WinTCDesktopSettings* wintc_desktop_settings_new(void);
#endif

View File

@@ -1,12 +1,22 @@
#include <gdk/gdk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <wintc/comgtk.h>
#include <wintc/shelldpa.h>
#include "application.h"
#include "settings.h"
#include "window.h"
//
// PRIVATE ENUMS
//
enum
{
PROP_SETTINGS = 1
};
//
// GTK OOP CLASS/INSTANCE DEFINITIONS
//
@@ -18,16 +28,51 @@ struct _WinTCDesktopWindowClass
struct _WinTCDesktopWindow
{
WinTCDpaDesktopWindow __parent__;
// Drawing-related
//
GdkPixbuf* pixbuf_wallpaper;
cairo_surface_t* surface_wallpaper;
// State
//
WinTCDesktopSettings* settings;
};
//
// FORWARD DECLARATION
// FORWARD DECLARATIONS
//
static void wintc_desktop_window_dispose(
GObject* object
);
static void wintc_desktop_window_set_property(
GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec
);
static gboolean wintc_desktop_window_draw(
GtkWidget* widget,
cairo_t* cr
);
static void wintc_desktop_window_update_wallpaper(
WinTCDesktopWindow* wnd
);
static gboolean on_window_map_event(
GtkWidget* self,
GdkEventAny* event,
gpointer user_data
);
static void on_settings_notify_pixbuf_wallpaper(
GObject* self,
GParamSpec* pspec,
gpointer user_data
);
//
// GTK TYPE DEFINITION & CTORS
//
@@ -41,28 +86,175 @@ static void wintc_desktop_window_class_init(
WinTCDesktopWindowClass* klass
)
{
GObjectClass* object_class = G_OBJECT_CLASS(klass);
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
object_class->dispose = wintc_desktop_window_dispose;
object_class->set_property = wintc_desktop_window_set_property;
widget_class->draw = wintc_desktop_window_draw;
g_object_class_install_property(
object_class,
PROP_SETTINGS,
g_param_spec_object(
"settings",
"Settings",
"The shared desktop settings",
WINTC_TYPE_DESKTOP_SETTINGS,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY
)
);
}
static void wintc_desktop_window_init(
WINTC_UNUSED(WinTCDesktopWindow* self)
) {}
WinTCDesktopWindow* self
)
{
g_signal_connect(
self,
"map-event",
G_CALLBACK(on_window_map_event),
NULL
);
}
//
// CLASS VIRTUAL METHODS
//
static gboolean wintc_desktop_window_draw(
WINTC_UNUSED(GtkWidget* widget),
cairo_t* cr
static void wintc_desktop_window_dispose(
GObject* object
)
{
WinTCDesktopWindow* wnd = WINTC_DESKTOP_WINDOW(object);
if (wnd->surface_wallpaper)
{
cairo_surface_destroy(g_steal_pointer(&(wnd->surface_wallpaper)));
g_clear_object(&(wnd->pixbuf_wallpaper));
}
(G_OBJECT_CLASS(wintc_desktop_window_parent_class))->dispose(object);
}
static void wintc_desktop_window_set_property(
GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec
)
{
WinTCDesktopWindow* wnd = WINTC_DESKTOP_WINDOW(object);
switch (prop_id)
{
case PROP_SETTINGS:
wnd->settings = g_value_get_object(value);
g_signal_connect(
wnd->settings,
"notify::pixbuf-wallpaper",
G_CALLBACK(on_settings_notify_pixbuf_wallpaper),
wnd
);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
static gboolean wintc_desktop_window_draw(
GtkWidget* widget,
cairo_t* cr
)
{
WinTCDpaDesktopWindow* dpa_wnd = WINTC_DPA_DESKTOP_WINDOW(widget);
WinTCDesktopWindow* wnd = WINTC_DESKTOP_WINDOW(widget);
// FIXME: Just drawing default desktop background colour atm
//
cairo_set_source_rgb(cr, 0.0f, 0.298f, 0.596f);
cairo_paint(cr);
// FIXME: Billy basic drawing of the wallpaper, if present
//
if (wnd->surface_wallpaper)
{
cairo_set_source_surface(cr, wnd->surface_wallpaper, 0.0f, 0.0f);
cairo_paint(cr);
}
// Rough watermark drawing
//
if (gdk_monitor_is_primary(dpa_wnd->monitor))
{
static gchar* s_tag = NULL;
cairo_text_extents_t extents;
gdouble y;
gint height = gtk_widget_get_allocated_height(widget);
gint width = gtk_widget_get_allocated_width(widget);
if (!s_tag)
{
gchar* tag = wintc_build_get_tag();
s_tag =
g_strdup_printf("For testing purposes only. Build %s", tag);
g_free(tag);
}
// Default to white, IDK if Windows changes this...
//
cairo_set_source_rgb(cr, 1.0f, 1.0f, 1.0f);
// Handle build string first...
//
cairo_select_font_face(
cr,
"sans-serif",
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL
);
cairo_text_extents(cr, s_tag, &extents);
cairo_move_to(
cr,
width - extents.width - 10,
height - extents.height - 34 // FIXME: Hardcoded taskband height
);
cairo_show_text(cr, s_tag);
// ...and the product name
// FIXME: Hard coded temp name in here until we have a name
//
cairo_select_font_face(
cr,
"sans-serif",
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD
);
cairo_text_extents(cr, "Windows 'Total Conversion'", &extents);
cairo_get_current_point(cr, NULL, &y);
cairo_move_to(
cr,
width - extents.width - 10,
y - extents.height - 4
);
cairo_show_text(cr, "Windows 'Total Conversion'");
}
return FALSE;
}
@@ -71,7 +263,8 @@ static gboolean wintc_desktop_window_draw(
//
GtkWidget* wintc_desktop_window_new(
WinTCDesktopApplication* app,
GdkMonitor* monitor
GdkMonitor* monitor,
WinTCDesktopSettings* settings
)
{
return GTK_WIDGET(
@@ -82,7 +275,69 @@ GtkWidget* wintc_desktop_window_new(
"decorated", TRUE,
"monitor", monitor,
"resizable", FALSE,
"settings", settings,
NULL
)
);
}
//
// PRIVATE FUNCTIONS
//
static void wintc_desktop_window_update_wallpaper(
WinTCDesktopWindow* wnd
)
{
WINTC_LOG_DEBUG("%s", "desktop: window updating wallpaper");
if (wnd->surface_wallpaper)
{
cairo_surface_destroy(g_steal_pointer(&(wnd->surface_wallpaper)));
g_clear_object(&(wnd->pixbuf_wallpaper));
}
g_object_get(
wnd->settings,
"pixbuf-wallpaper", &(wnd->pixbuf_wallpaper),
NULL
);
if (wnd->pixbuf_wallpaper)
{
wnd->surface_wallpaper =
gdk_cairo_surface_create_from_pixbuf(
wnd->pixbuf_wallpaper,
1,
NULL
);
gtk_widget_queue_draw(GTK_WIDGET(wnd));
}
}
//
// CALLBACKS
//
static gboolean on_window_map_event(
GtkWidget* self,
WINTC_UNUSED(GdkEventAny* event),
WINTC_UNUSED(gpointer user_data)
)
{
wintc_desktop_window_update_wallpaper(
WINTC_DESKTOP_WINDOW(self)
);
return FALSE;
}
static void on_settings_notify_pixbuf_wallpaper(
WINTC_UNUSED(GObject* self),
WINTC_UNUSED(GParamSpec* pspec),
gpointer user_data
)
{
wintc_desktop_window_update_wallpaper(
WINTC_DESKTOP_WINDOW(user_data)
);
}

View File

@@ -5,6 +5,7 @@
#include <gtk/gtk.h>
#include "application.h"
#include "settings.h"
//
// GTK OOP BOILERPLATE
@@ -26,7 +27,8 @@ GType wintc_desktop_window_get_type(void) G_GNUC_CONST;
//
GtkWidget* wintc_desktop_window_new(
WinTCDesktopApplication* app,
GdkMonitor* monitor
GdkMonitor* monitor,
WinTCDesktopSettings* settings
);
#endif

View File

@@ -14,13 +14,17 @@ msgfmt-->bt,rt-->gettext
plymouth-->bt,rt-->plymouth
pulseaudio-->bt-->pulseaudio-dev
pulseaudio-->rt-->libpulse
python3-packaging-->bt,rt-->py3-packaging
python3-venv-->bt,rt-->py3-virtualenv
sass-->bt,rt-->sassc
sqlite3-->bt-->sqlite-dev
sqlite3-->rt-->sqlite
sysinfo-->bt,rt-->NULL
wintc-comctl-->bt,rt-->libwintc-comctl
wintc-comgtk-->bt,rt-->libwintc-comgtk
wintc-exec-->bt,rt-->libwintc-exec
wintc-msgina-->bt,rt-->libwintc-msgina
wintc-registry-->bt,rt-->libwintc-registry
wintc-shcommon-->bt,rt-->libwintc-shcommon
wintc-shell-->bt,rt-->libwintc-shell
wintc-shelldpa-->bt,rt-->libwintc-shelldpa

View File

@@ -7,13 +7,16 @@ lightdm-->bt,rt-->lightdm
msgfmt-->bt,rt-->gettext
plymouth-->bt,rt-->plymouth
pulseaudio-->bt,rt-->libpulse
python3-packaging-->bt,rt-->python-packaging
python3-venv-->bt,rt-->python3
sass-->bt,rt-->ruby-sass
sqlite3-->bt,rt-->sqlite
sysinfo-->bt,rt-->NULL
wintc-comctl-->bt,rt-->wintc-comctl
wintc-comgtk-->bt,rt-->wintc-comgtk
wintc-exec-->bt,rt-->wintc-exec
wintc-msgina-->bt,rt-->wintc-msgina
wintc-registry-->bt,rt-->wintc-registry
wintc-shcommon-->bt,rt-->wintc-shcommon
wintc-shell-->bt,rt-->wintc-shell
wintc-shelldpa-->bt,rt-->wintc-shelldpa

View File

@@ -7,13 +7,16 @@ lightdm-->bt,rt-->lightdm
msgfmt-->bt,rt-->gettext
plymouth-->bt,rt-->splash
pulseaudio-->bt,rt-->pulseaudio
python3-packaging-->bt,rt-->py39-packaging
python3-venv-->bt,rt-->py39-virtualenv
sass-->bt,rt-->rubygem-sass
sqlite3-->bt,rt-->sqlite3
sysinfo-->bt,rt-->libsysinfo
wintc-comctl-->bt,rt-->wintc-comctl
wintc-comgtk-->bt,rt-->wintc-comgtk
wintc-exec-->bt,rt-->wintc-exec
wintc-msgina-->bt,rt-->wintc-msgina
wintc-registry-->bt,rt-->wintc-registry
wintc-shcommon-->bt,rt-->wintc-shcommon
wintc-shell-->bt,rt-->wintc-shell
wintc-shelldpa-->bt,rt-->wintc-shelldpa

View File

@@ -14,13 +14,17 @@ msgfmt-->bt,rt-->gettext
plymouth-->bt,rt-->plymouth
pulseaudio-->bt-->libpulse-dev
pulseaudio-->rt-->libpulse0
python3-packaging-->bt,rt-->python3-packaging
python3-venv-->bt,rt-->python3-venv
sass-->bt,rt-->ruby-sass
sqlite3-->bt-->libsqlite3-dev
sqlite3-->rt-->libsqlite3-0
sysinfo-->bt,rt-->NULL
wintc-comctl-->bt,rt-->libwintc-comctl
wintc-comgtk-->bt,rt-->libwintc-comgtk
wintc-exec-->bt,rt-->libwintc-exec
wintc-msgina-->bt,rt-->libwintc-msgina
wintc-registry-->bt,rt-->libwintc-registry
wintc-shcommon-->bt,rt-->libwintc-shcommon
wintc-shell-->bt,rt-->libwintc-shell
wintc-shelldpa-->bt,rt-->libwintc-shelldpa

View File

@@ -14,13 +14,17 @@ msgfmt-->bt,rt-->gettext
plymouth-->bt,rt-->plymouth
pulseaudio-->bt-->pulseaudio-libs-devel
pulseaudio-->rt-->pulseaudio-libs
python3-packaging-->bt,rt-->python3-packaging
python3-venv-->bt,rt-->python3-virtualenv
sass-->bt,rt-->rubygem-sass
sqlite3-->bt-->sqlite-devel
sqlite3-->rt-->sqlite
sysinfo-->bt,rt-->NULL
wintc-comctl-->bt,rt-->wintc-comctl
wintc-comgtk-->bt,rt-->wintc-comgtk
wintc-exec-->bt,rt-->wintc-exec
wintc-msgina-->bt,rt-->wintc-msgina
wintc-registry-->bt,rt-->wintc-registry
wintc-shcommon-->bt,rt-->wintc-shcommon
wintc-shell-->bt,rt-->wintc-shell
wintc-shelldpa-->bt,rt-->wintc-shelldpa