Enhancement: Fixes #205, Create logonui LightDM greeter

This commit is contained in:
Rory Fewell
2023-11-23 21:58:22 +00:00
parent 9ff5265f19
commit 984004013c
135 changed files with 5386 additions and 120 deletions

111
base/logonui/CMakeLists.txt Normal file
View File

@@ -0,0 +1,111 @@
cmake_minimum_required(VERSION 3.0)
project(
wintc-logonui
VERSION 1.0
DESCRIPTION "Windows Total Conversion logon user interface."
LANGUAGES C
)
set(PROJECT_ANYARCH false)
set(PROJECT_FREESTATUS false)
set(PROJECT_MAINTAINER "Rory Fewell <roryf@oddmatics.uk>")
set(PROJECT_ROOT ${CMAKE_CURRENT_LIST_DIR})
# Necessary because we use g_signal_handlers_disconnect...
set(WINTC_NO_PEDANTIC_COMPILE true)
include(GNUInstallDirs)
include(../../packaging/cmake-inc/common/CMakeLists.txt)
include(../../packaging/cmake-inc/linking/CMakeLists.txt)
include(../../packaging/cmake-inc/packaging/CMakeLists.txt)
include(../../packaging/cmake-inc/resources/CMakeLists.txt)
wintc_resolve_library(gdk-pixbuf-2.0 GDK_PIXBUF)
wintc_resolve_library(glib-2.0 GLIB)
wintc_resolve_library(gtk+-3.0 GTK3)
wintc_resolve_library(liblightdm-gobject-1 LIGHTDM)
wintc_resolve_library(wintc-comctl WINTC_COMCTL)
wintc_resolve_library(wintc-comgtk WINTC_COMGTK)
wintc_resolve_library(wintc-msgina WINTC_MSGINA)
wintc_compile_resources()
add_executable(
wintc-logonui
src/main.c
src/resources.c
src/window.c
src/window.h
src/classic/ui.c
src/classic/ui.h
src/welcome/ui.c
src/welcome/ui.h
src/welcome/userlist.c
src/welcome/userlist.h
)
set_target_properties(
wintc-logonui
PROPERTIES
OUTPUT_NAME logonui
)
target_compile_options(
wintc-logonui
PRIVATE ${WINTC_COMPILE_OPTIONS}
)
target_include_directories(
wintc-logonui
SYSTEM
PRIVATE ${GDK_PIXBUF_INCLUDE_DIRS}
PRIVATE ${GLIB_INCLUDE_DIRS}
PRIVATE ${GTK3_INCLUDE_DIRS}
PRIVATE ${LIGHTDM_INCLUDE_DIRS}
PRIVATE ${WINTC_COMCTL_INCLUDE_DIRS}
PRIVATE ${WINTC_COMGTK_INCLUDE_DIRS}
PRIVATE ${WINTC_MSGINA_INCLUDE_DIRS}
)
target_link_directories(
wintc-logonui
PRIVATE ${GDK_PIXBUF_LIBRARY_DIRS}
PRIVATE ${GLIB_LIBRARY_DIRS}
PRIVATE ${GTK3_LIBRARY_DIRS}
PRIVATE ${LIGHTDM_LIBRARY_DIRS}
PRIVATE ${WINTC_COMCTL_LIBRARY_DIRS}
PRIVATE ${WINTC_COMGTK_LIBRARY_DIRS}
PRIVATE ${WINTC_MSGINA_LIBRARY_DIRS}
)
target_link_libraries(
wintc-logonui
PRIVATE ${GDK_PIXBUF_LIBRARIES}
PRIVATE ${GLIB_LIBRARIES}
PRIVATE ${GTK3_LIBRARIES}
PRIVATE ${LIGHTDM_LIBRARIES}
PRIVATE ${WINTC_COMCTL_LIBRARIES}
PRIVATE ${WINTC_COMGTK_LIBRARIES}
PRIVATE ${WINTC_MSGINA_LIBRARIES}
)
add_dependencies(
wintc-logonui
build-gresources
)
# Installation
#
wintc_configure_and_install_packaging()
install(
FILES wintc-logonui.desktop
DESTINATION share/xgreeters
)
install(
TARGETS wintc-logonui
RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}
)

4
base/logonui/README.MD Normal file
View File

@@ -0,0 +1,4 @@
# logonui
This directory contains the source-code for the Windows Logon User Interface.
![image](https://github.com/rozniak/xfce-winxp-tc/assets/13258281/83f8c2e4-3e03-478f-b7e2-8721ee43f71a)

7
base/logonui/deps Normal file
View File

@@ -0,0 +1,7 @@
bt,rt:gdk-pixbuf2
bt,rt:glib2
bt,rt:gtk3
bt,rt:lightdm
bt,rt:wintc-comctl
bt,rt:wintc-comgtk
bt,rt:wintc-msgina

View File

@@ -0,0 +1,128 @@
#include <gdk/gdk.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <wintc-comgtk.h>
#include <wintc-msgina.h>
#include "ui.h"
#include "../window.h"
//
// GTK OOP CLASS/INSTANCE DEFINITIONS
//
struct _WinTCClassicUIPrivate
{
GtkWidget* wnd_gina;
};
struct _WinTCClassicUIClass
{
GtkWidgetClass __parent__;
};
struct _WinTCClassicUI
{
GtkWidget __parent__;
WinTCClassicUIPrivate* priv;
};
//
// FORWARD DECLARATIONS
//
static gboolean wintc_classic_ui_draw(
GtkWidget* widget,
cairo_t* cr
);
static void on_self_realized(
GtkWidget* self,
gpointer user_data
);
//
// GTK TYPE DEFINITIONS & CTORS
//
G_DEFINE_TYPE_WITH_CODE(
WinTCClassicUI,
wintc_classic_ui,
GTK_TYPE_WIDGET,
G_ADD_PRIVATE(WinTCClassicUI)
)
static void wintc_classic_ui_class_init(
WinTCClassicUIClass* klass
)
{
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
widget_class->draw = wintc_classic_ui_draw;
}
static void wintc_classic_ui_init(
WinTCClassicUI* self
)
{
self->priv = wintc_classic_ui_get_instance_private(self);
gtk_widget_set_has_window(GTK_WIDGET(self), FALSE);
// Set up widgets
//
self->priv->wnd_gina = wintc_gina_auth_window_new();
// Connect to realize signal to begin when we're ready
//
g_signal_connect(
self,
"realize",
G_CALLBACK(on_self_realized),
NULL
);
}
//
// CLASS VIRTUAL METHODS
//
static gboolean wintc_classic_ui_draw(
WINTC_UNUSED(GtkWidget* widget),
cairo_t* cr
)
{
// BG color is #004E98
// FIXME: This is the default desktop colour, should be it be defined in
// a shell lib? Also see shell/desktop
//
cairo_set_source_rgb(cr, 0.0f, 0.298f, 0.596f);
cairo_paint(cr);
return FALSE;
}
//
// PUBLIC FUNCTIONS
//
GtkWidget* wintc_classic_ui_new(void)
{
return GTK_WIDGET(
g_object_new(
TYPE_WINTC_CLASSIC_UI,
"hexpand", TRUE,
"vexpand", TRUE,
NULL
)
);
}
//
// CALLBACKS
//
static void on_self_realized(
GtkWidget* self,
WINTC_UNUSED(gpointer user_data)
)
{
WinTCClassicUI* classic_ui = WINTC_CLASSIC_UI(self);
gtk_widget_show_all(classic_ui->priv->wnd_gina);
}

View File

@@ -0,0 +1,28 @@
#ifndef __CLASSIC_UI_H__
#define __CLASSIC_UI_H__
#include <glib.h>
#include <gtk/gtk.h>
//
// GTK OOP BOILERPLATE
//
typedef struct _WinTCClassicUIPrivate WinTCClassicUIPrivate;
typedef struct _WinTCClassicUIClass WinTCClassicUIClass;
typedef struct _WinTCClassicUI WinTCClassicUI;
#define TYPE_WINTC_CLASSIC_UI (wintc_classic_ui_get_type())
#define WINTC_CLASSIC_UI(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_WINTC_CLASSIC_UI, WinTCClassicUI))
#define WINTC_CLASSIC_UI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((obj), TYPE_WINTC_CLASSIC_UI, WinTCClassicUI))
#define IS_WINTC_CLASSIC_UI(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_WINTC_CLASSIC_UI))
#define IS_WINTC_CLASSIC_UI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_WINTC_CLASSIC_UI))
#define WINTC_CLASSIC_UI_GET_CLASS(obj) (G_TYPE_CHECK_INSTANCE_GET_CLASS((obj), TYPE_WINTC_CLASSIC_UI))
GType wintc_classic_ui_get_type(void) G_GNUC_CONST;
//
// PUBLIC FUNCTIONS
//
GtkWidget* wintc_classic_ui_new(void);
#endif

41
base/logonui/src/main.c Normal file
View File

@@ -0,0 +1,41 @@
#include <glib.h>
#include <gtk/gtk.h>
#include <wintc-comgtk.h>
#include "window.h"
//
// ENTRY POINT
//
int main(
int argc,
char* argv[]
)
{
GtkWidget* window;
gtk_init(&argc, &argv);
// Set up theme
// FIXME: There should probably be an API for this rather than directly
// plopping the name straight in GTK
// FIXME: This should be configurable via INI option and simply default to
// Luna for clients, and Classic for servers
//
g_object_set(
gtk_settings_get_default(),
"gtk-theme-name",
"Windows XP style (Blue)",
NULL
);
// Create the window and launch
//
window = wintc_logonui_window_new();
gtk_widget_show_all(window);
gtk_main();
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 690 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/uk/oddmatics/wintc/logonui">
<!-- -->
<!-- GRAPHICAL RESOURCES -->
<!-- -->
<file>bglight.png</file>
<file>ejctbtna.png</file>
<file>ejctbtn.png</file>
<file>entry.png</file>
<file>gobtna.png</file>
<file>gobtn.png</file>
<file>hintbtna.png</file>
<file>hintbtn.png</file>
<file>hsepa.png</file>
<file>hsepb.png</file>
<file>logoani.png</file>
<file>logo.png</file>
<file>scdnbtn.png</file>
<file>scrollbar.png</file>
<file>scupbtn.png</file>
<file>shtdbtna.png</file>
<file>shtdbtn.png</file>
<file>tilehot.png</file>
<file>tile.png</file>
<file>userpic.png</file>
<file>usersel.png</file>
<file>vsep.png</file>
<!-- -->
<!-- CSS RESOURCES -->
<!-- -->
<file>welcome-ui.css</file>
</gresource>
</gresources>

Binary file not shown.

After

Width:  |  Height:  |  Size: 828 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 826 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 709 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

View File

@@ -0,0 +1,21 @@
.box-instruction label,
.box-wait label,
.box-welcome label
{
color: #EFF7FF;
font-family: 'Arial';
}
.box-instruction label,
.box-wait label
{
font-size: 14pt;
}
.box-welcome label
{
font-size: 36pt;
font-style: italic;
font-weight: bold;
text-shadow: 2px 3px 0px #3151B5;
}

View File

@@ -0,0 +1,846 @@
#include <gdk/gdk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <wintc-comctl.h>
#include <wintc-comgtk.h>
#include <wintc-msgina.h>
#include "ui.h"
#include "userlist.h"
#include "../window.h"
#define DELAY_SECONDS_AT_LEAST 2
#define DELAY_SECONDS_POLL 1
#define LOGOANI_FRAME_COUNT 50
#define LOGOANI_FRAME_RATE 15
#define TOP_RIBBON_THICKNESS 78
#define BOTTOM_RIBBON_THICKNESS 94
#define STRIP_THICKNESS 2
// HMARGIN is potentially 40 or thereabouts
// WIDTH is based off 360 per half + 1 for vseparator
// VMARGIN is a guesstimate
//
#define INNER_BOX_HMARGIN 32
#define INNER_BOX_WIDTH (720 + 1)
#define INNER_BOX_VMARGIN 8
#define INNER_BOX_COLLAPSE ((INNER_BOX_HMARGIN * 2) + INNER_BOX_WIDTH)
//
// GTK OOP CLASS/INSTANCE DEFINITIONS
//
struct _WinTCWelcomeUIPrivate
{
GSList* child_widgets;
// Graphic resources
//
GdkPixbuf* pixbuf_bglight;
GdkPixbuf* pixbuf_hsepa;
GdkPixbuf* pixbuf_hsepb;
cairo_surface_t* surface_bglight;
cairo_surface_t* surface_hsepa;
cairo_surface_t* surface_hsepb;
// Logo resources
//
guint ani_id_logo_ins;
guint ani_id_logo_wait;
GdkPixbuf* pixbuf_logo;
GdkPixbuf* pixbuf_logoani;
// UI
//
GtkWidget* box_container;
GtkWidget* box_instruction;
GtkWidget* box_login;
GtkWidget* box_wait;
GtkWidget* box_welcome;
GtkWidget* animation_logo_ins;
GtkWidget* animation_logo_wait;
GtkWidget* label_instruction;
GtkWidget* label_wait;
GtkWidget* label_welcome;
GtkWidget* scrollwnd;
GtkWidget* user_list;
// State
//
WinTCGinaState current_state;
WinTCGinaLogonSession* logon_session;
};
struct _WinTCWelcomeUIClass
{
GtkContainerClass __parent__;
GtkCssProvider* css_provider;
};
struct _WinTCWelcomeUI
{
GtkContainer __parent__;
WinTCWelcomeUIPrivate* priv;
};
//
// FORWARD DECLARATIONS
//
static void wintc_welcome_ui_finalize(
GObject* gobject
);
static gboolean wintc_welcome_ui_draw(
GtkWidget* widget,
cairo_t* cr
);
static void wintc_welcome_ui_size_allocate(
GtkWidget* widget,
GtkAllocation* allocation
);
static void wintc_welcome_ui_add(
GtkContainer* container,
GtkWidget* widget
);
static void wintc_welcome_ui_forall(
GtkContainer* container,
gboolean include_internals,
GtkCallback callback,
gpointer callback_data
);
static void wintc_welcome_ui_remove(
GtkContainer* container,
GtkWidget* widget
);
static void wintc_welcome_ui_change_state(
WinTCWelcomeUI* welcome_ui,
WinTCGinaState next_state
);
static void wintc_welcome_ui_internal_add(
WinTCWelcomeUI* welcome_ui,
GtkWidget* widget
);
static void on_self_realized(
GtkWidget* self,
gpointer user_data
);
static void on_logon_session_attempt_complete(
WinTCGinaLogonSession* logon_session,
WinTCGinaResponse response,
gpointer user_data
);
static gboolean on_timeout_delay_done(
gpointer user_data
);
static gboolean on_timeout_poll_ready(
gpointer user_data
);
//
// GTK TYPE DEFINITIONS & CTORS
//
G_DEFINE_TYPE_WITH_CODE(
WinTCWelcomeUI,
wintc_welcome_ui,
GTK_TYPE_CONTAINER,
G_ADD_PRIVATE(WinTCWelcomeUI)
)
static void wintc_welcome_ui_class_init(
WinTCWelcomeUIClass* klass
)
{
GtkContainerClass* container_class = GTK_CONTAINER_CLASS(klass);
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
GObjectClass* object_class = G_OBJECT_CLASS(klass);
object_class->finalize = wintc_welcome_ui_finalize;
widget_class->draw = wintc_welcome_ui_draw;
widget_class->size_allocate = wintc_welcome_ui_size_allocate;
container_class->add = wintc_welcome_ui_add;
container_class->forall = wintc_welcome_ui_forall;
container_class->remove = wintc_welcome_ui_remove;
klass->css_provider = gtk_css_provider_new();
gtk_css_provider_load_from_resource(
klass->css_provider,
"/uk/oddmatics/wintc/logonui/welcome-ui.css"
);
gtk_style_context_add_provider_for_screen(
gdk_screen_get_default(),
GTK_STYLE_PROVIDER(klass->css_provider),
GTK_STYLE_PROVIDER_PRIORITY_FALLBACK
);
}
static void wintc_welcome_ui_init(
WinTCWelcomeUI* self
)
{
self->priv = wintc_welcome_ui_get_instance_private(self);
gtk_widget_set_has_window(GTK_WIDGET(self), FALSE);
// Set initial state
//
self->priv->current_state = WINTC_GINA_STATE_NONE;
self->priv->logon_session = wintc_gina_logon_session_new();
g_signal_connect(
self->priv->logon_session,
"attempt-complete",
G_CALLBACK(on_logon_session_attempt_complete),
self
);
// Set up image resources
//
self->priv->pixbuf_bglight =
gdk_pixbuf_new_from_resource(
"/uk/oddmatics/wintc/logonui/bglight.png",
NULL // FIXME: Error reporting
);
self->priv->pixbuf_hsepa =
gdk_pixbuf_new_from_resource(
"/uk/oddmatics/wintc/logonui/hsepa.png",
NULL // FIXME: Error reporting
);
self->priv->pixbuf_hsepb =
gdk_pixbuf_new_from_resource(
"/uk/oddmatics/wintc/logonui/hsepb.png",
NULL // FIXME: Error reporting
);
self->priv->surface_bglight =
gdk_cairo_surface_create_from_pixbuf(
self->priv->pixbuf_bglight,
1,
NULL
);
self->priv->surface_hsepa =
gdk_cairo_surface_create_from_pixbuf(
self->priv->pixbuf_hsepa,
1,
NULL
);
self->priv->surface_hsepb =
gdk_cairo_surface_create_from_pixbuf(
self->priv->pixbuf_hsepb,
1,
NULL
);
self->priv->pixbuf_logo =
gdk_pixbuf_new_from_resource(
"/uk/oddmatics/wintc/logonui/logo.png",
NULL // FIXME: Error reporting
);
self->priv->pixbuf_logoani =
gdk_pixbuf_new_from_resource(
"/uk/oddmatics/wintc/logonui/logoani.png",
NULL // FIXME: Error reporting
);
// Set up 'Please wait...' box
//
self->priv->box_wait = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
self->priv->animation_logo_wait = wintc_animation_new();
self->priv->label_wait = gtk_label_new("Please wait...");
self->priv->ani_id_logo_wait =
wintc_animation_add_static(
WINTC_ANIMATION(self->priv->animation_logo_wait),
self->priv->pixbuf_logo
);
wintc_animation_set_halign(
WINTC_ANIMATION(self->priv->animation_logo_wait),
GTK_ALIGN_END
);
wintc_animation_set_valign(
WINTC_ANIMATION(self->priv->animation_logo_wait),
GTK_ALIGN_END
);
wintc_animation_play(
WINTC_ANIMATION(self->priv->animation_logo_wait),
self->priv->ani_id_logo_wait,
0,
WINTC_ANIMATION_INFINITE
);
gtk_label_set_xalign(GTK_LABEL(self->priv->label_wait), 1.0f);
gtk_label_set_yalign(GTK_LABEL(self->priv->label_wait), 0.0f);
gtk_box_pack_start(
GTK_BOX(self->priv->box_wait),
self->priv->animation_logo_wait,
TRUE,
TRUE,
0
);
gtk_box_pack_start(
GTK_BOX(self->priv->box_wait),
self->priv->label_wait,
TRUE,
TRUE,
0
);
// Set up instruction box
//
self->priv->box_instruction = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
self->priv->animation_logo_ins = wintc_animation_new();
self->priv->label_instruction =
gtk_label_new("To begin, click your user name");
gtk_label_set_xalign(GTK_LABEL(self->priv->label_instruction), 1.0f);
gtk_label_set_yalign(GTK_LABEL(self->priv->label_instruction), 0.0f);
self->priv->ani_id_logo_ins =
wintc_animation_add_framesheet(
WINTC_ANIMATION(self->priv->animation_logo_ins),
self->priv->pixbuf_logoani,
LOGOANI_FRAME_COUNT
);
wintc_animation_set_halign(
WINTC_ANIMATION(self->priv->animation_logo_ins),
GTK_ALIGN_END
);
wintc_animation_set_valign(
WINTC_ANIMATION(self->priv->animation_logo_ins),
GTK_ALIGN_END
);
wintc_animation_play(
WINTC_ANIMATION(self->priv->animation_logo_ins),
self->priv->ani_id_logo_ins,
LOGOANI_FRAME_RATE,
WINTC_ANIMATION_INFINITE
);
gtk_box_pack_start(
GTK_BOX(self->priv->box_instruction),
self->priv->animation_logo_ins,
TRUE,
TRUE,
0
);
gtk_box_pack_start(
GTK_BOX(self->priv->box_instruction),
self->priv->label_instruction,
TRUE,
TRUE,
0
);
// Set up login box
//
self->priv->box_login = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
self->priv->scrollwnd = gtk_scrolled_window_new(NULL, NULL);
self->priv->user_list =
wintc_welcome_user_list_new(self->priv->logon_session);
gtk_container_add(
GTK_CONTAINER(self->priv->scrollwnd),
self->priv->user_list
);
gtk_box_pack_start(
GTK_BOX(self->priv->box_login),
self->priv->scrollwnd,
FALSE,
FALSE,
0
);
gtk_box_set_center_widget(
GTK_BOX(self->priv->box_login),
self->priv->scrollwnd
);
// Set up 'welcome' box
//
self->priv->box_welcome = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
self->priv->label_welcome = gtk_label_new("welcome");
gtk_label_set_xalign(GTK_LABEL(self->priv->label_welcome), 0.8f);
gtk_label_set_yalign(GTK_LABEL(self->priv->label_welcome), 0.5f);
gtk_box_pack_start(
GTK_BOX(self->priv->box_welcome),
self->priv->label_welcome,
TRUE,
TRUE,
0
);
// Set up container
//
self->priv->box_container = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_set_homogeneous(
GTK_BOX(self->priv->box_container),
TRUE
);
wintc_welcome_ui_internal_add(self, self->priv->box_container);
// Add style classes
//
wintc_widget_add_style_class(self->priv->box_instruction, "box-instruction");
wintc_widget_add_style_class(self->priv->box_login, "box-login");
wintc_widget_add_style_class(self->priv->box_wait, "box-wait");
wintc_widget_add_style_class(self->priv->box_welcome, "box-welcome");
// Hold an additional reference to the boxes, so we can add/remove
// them ourselves without them getting binned
//
g_object_ref(self->priv->box_instruction);
g_object_ref(self->priv->box_login);
g_object_ref(self->priv->box_wait);
g_object_ref(self->priv->box_welcome);
// Connect to realize signal to kick off everything when we're
// actually live
//
g_signal_connect(
self,
"realize",
G_CALLBACK(on_self_realized),
NULL
);
}
//
// CLASS VIRTUAL METHODS
//
static void wintc_welcome_ui_finalize(
GObject* gobject
)
{
WinTCWelcomeUI* welcome_ui = WINTC_WELCOME_UI(gobject);
// Bin graphical resources
//
cairo_surface_destroy(welcome_ui->priv->surface_bglight);
cairo_surface_destroy(welcome_ui->priv->surface_hsepa);
cairo_surface_destroy(welcome_ui->priv->surface_hsepb);
g_clear_object(&(welcome_ui->priv->pixbuf_bglight));
g_clear_object(&(welcome_ui->priv->pixbuf_hsepa));
g_clear_object(&(welcome_ui->priv->pixbuf_hsepb));
g_clear_object(&(welcome_ui->priv->pixbuf_logoani));
// Bin additional references held for the boxes
//
g_clear_object(&(welcome_ui->priv->box_instruction));
g_clear_object(&(welcome_ui->priv->box_login));
g_clear_object(&(welcome_ui->priv->box_wait));
g_clear_object(&(welcome_ui->priv->box_welcome));
(G_OBJECT_CLASS(wintc_welcome_ui_parent_class))->finalize(gobject);
}
static gboolean wintc_welcome_ui_draw(
GtkWidget* widget,
cairo_t* cr
)
{
WinTCWelcomeUI* welcome_ui = WINTC_WELCOME_UI(widget);
gint height = gtk_widget_get_allocated_height(widget);
gint width = gtk_widget_get_allocated_width(widget);
// Background is #5A7EDC
//
cairo_set_source_rgb(cr, 0.35f, 0.49f, 0.86f);
cairo_paint(cr);
// Draw top banner edge
//
gint hsepa_width = gdk_pixbuf_get_width(welcome_ui->priv->pixbuf_hsepa);
cairo_save(cr);
cairo_scale(cr, (double) width / (double) hsepa_width, 1.0f);
cairo_set_source_surface(
cr,
welcome_ui->priv->surface_hsepa,
0.0f,
(double) TOP_RIBBON_THICKNESS
);
cairo_paint(cr);
cairo_restore(cr);
// Draw top banner fill (#00309C)
//
cairo_save(cr);
cairo_rectangle(
cr,
0.0f,
0.0f,
(double) width,
(double) TOP_RIBBON_THICKNESS
);
cairo_clip(cr);
cairo_set_source_rgb(cr, 0.0f, 0.19f, 0.61f);
cairo_paint(cr);
cairo_restore(cr);
// Draw bg light
//
cairo_set_source_surface(
cr,
welcome_ui->priv->surface_bglight,
0.0f,
(double) (TOP_RIBBON_THICKNESS + STRIP_THICKNESS)
);
cairo_paint(cr);
// Draw bottom banner edge
//
gint hsepb_width = gdk_pixbuf_get_width(welcome_ui->priv->pixbuf_hsepb);
cairo_save(cr);
cairo_scale(cr, (double) width / (double) hsepb_width, 1.0f);
cairo_set_source_surface(
cr,
welcome_ui->priv->surface_hsepb,
0.0f,
(double) (height - BOTTOM_RIBBON_THICKNESS - STRIP_THICKNESS)
);
cairo_paint(cr);
cairo_restore(cr);
// Draw bottom banner fill (#1D32A4)
// FIXME: This should actually be a gradient!
//
cairo_save(cr);
cairo_rectangle(
cr,
0.0f,
(double) (height - BOTTOM_RIBBON_THICKNESS),
(double) width,
(double) BOTTOM_RIBBON_THICKNESS
);
cairo_clip(cr);
cairo_set_source_rgb(cr, 0.11f, 0.19f, 0.64f);
cairo_paint(cr);
cairo_restore(cr);
// Chain up
//
(GTK_WIDGET_CLASS(wintc_welcome_ui_parent_class))->draw(widget, cr);
return FALSE;
}
static void wintc_welcome_ui_size_allocate(
GtkWidget* widget,
GtkAllocation* allocation
)
{
WinTCWelcomeUI* welcome_ui = WINTC_WELCOME_UI(widget);
gtk_widget_set_allocation(widget, allocation);
// FIXME: We're not handling collapse at low res (640x480)
// FIXME: We're also not doing anything about low res on the Y axis
//
if (allocation->width < INNER_BOX_COLLAPSE)
{
g_critical(
"Screen res is too low, 800x600 required and we got width of %d",
allocation->width
);
return;
}
// Just deal with >= 800x600 for now
//
gint centre_ui = allocation->width / 2;
gint centre_box = (INNER_BOX_WIDTH / 2);
GtkAllocation box_alloc;
box_alloc.x = centre_ui - centre_box + INNER_BOX_HMARGIN;
box_alloc.y = TOP_RIBBON_THICKNESS
+ STRIP_THICKNESS
+ INNER_BOX_VMARGIN;
box_alloc.width = INNER_BOX_WIDTH;
box_alloc.height = allocation->height
- TOP_RIBBON_THICKNESS
- BOTTOM_RIBBON_THICKNESS
- (STRIP_THICKNESS * 2)
- (INNER_BOX_VMARGIN * 2);
gtk_widget_size_allocate(
welcome_ui->priv->box_container,
&box_alloc
);
}
static void wintc_welcome_ui_add(
WINTC_UNUSED(GtkContainer* container),
WINTC_UNUSED(GtkWidget* widget)
)
{
g_critical("%s", "wintc_welcome_ui_add - not allowed!");
}
static void wintc_welcome_ui_forall(
GtkContainer* container,
WINTC_UNUSED(gboolean include_internals),
GtkCallback callback,
gpointer callback_data
)
{
WinTCWelcomeUI* welcome_ui = WINTC_WELCOME_UI(container);
g_slist_foreach(
welcome_ui->priv->child_widgets,
(GFunc) callback,
callback_data
);
}
static void wintc_welcome_ui_remove(
WINTC_UNUSED(GtkContainer* container),
WINTC_UNUSED(GtkWidget* widget)
)
{
g_critical("%s", "wintc_welcome_ui_remove - not allowed!");
}
//
// PUBLIC FUNCTIONS
//
GtkWidget* wintc_welcome_ui_new(void)
{
return GTK_WIDGET(
g_object_new(
TYPE_WINTC_WELCOME_UI,
"hexpand", TRUE,
"vexpand", TRUE,
NULL
)
);
}
//
// PRIVATE FUNCTIONS
//
static void wintc_welcome_ui_change_state(
WinTCWelcomeUI* welcome_ui,
WinTCGinaState next_state
)
{
// Disable current state, if any
//
switch (welcome_ui->priv->current_state)
{
case WINTC_GINA_STATE_STARTING:
gtk_container_remove(
GTK_CONTAINER(welcome_ui->priv->box_container),
welcome_ui->priv->box_wait
);
break;
case WINTC_GINA_STATE_PROMPT:
gtk_container_remove(
GTK_CONTAINER(welcome_ui->priv->box_container),
welcome_ui->priv->box_instruction
);
gtk_container_remove(
GTK_CONTAINER(welcome_ui->priv->box_container),
welcome_ui->priv->box_login
);
break;
case WINTC_GINA_STATE_LAUNCHING:
gtk_container_remove(
GTK_CONTAINER(welcome_ui->priv->box_container),
welcome_ui->priv->box_welcome
);
break;
default: break;
}
// Set up new state
//
switch (next_state)
{
case WINTC_GINA_STATE_STARTING:
gtk_box_pack_start(
GTK_BOX(welcome_ui->priv->box_container),
welcome_ui->priv->box_wait,
TRUE,
TRUE,
0
);
wintc_gina_logon_session_establish(
welcome_ui->priv->logon_session
);
g_timeout_add_seconds(
DELAY_SECONDS_AT_LEAST,
on_timeout_delay_done,
welcome_ui
);
break;
case WINTC_GINA_STATE_PROMPT:
gtk_box_pack_start(
GTK_BOX(welcome_ui->priv->box_container),
welcome_ui->priv->box_instruction,
TRUE,
TRUE,
0
);
gtk_box_pack_start(
GTK_BOX(welcome_ui->priv->box_container),
welcome_ui->priv->box_login,
TRUE,
TRUE,
0
);
break;
case WINTC_GINA_STATE_LAUNCHING:
gtk_box_pack_start(
GTK_BOX(welcome_ui->priv->box_container),
welcome_ui->priv->box_welcome,
TRUE,
TRUE,
0
);
g_timeout_add_seconds(
DELAY_SECONDS_AT_LEAST,
on_timeout_delay_done,
welcome_ui
);
break;
default: break;
}
gtk_widget_show_all(
welcome_ui->priv->box_container
);
welcome_ui->priv->current_state = next_state;
}
static void wintc_welcome_ui_internal_add(
WinTCWelcomeUI* welcome_ui,
GtkWidget* widget
)
{
gtk_widget_set_parent(widget, GTK_WIDGET(welcome_ui));
welcome_ui->priv->child_widgets =
g_slist_append(welcome_ui->priv->child_widgets, widget);
}
//
// CALLBACKS
//
static void on_self_realized(
GtkWidget* self,
WINTC_UNUSED(gpointer user_data)
)
{
wintc_welcome_ui_change_state(
WINTC_WELCOME_UI(self),
WINTC_GINA_STATE_STARTING
);
}
static void on_logon_session_attempt_complete(
WINTC_UNUSED(WinTCGinaLogonSession* logon_session),
WinTCGinaResponse response,
gpointer user_data
)
{
WinTCWelcomeUI* welcome_ui = WINTC_WELCOME_UI(user_data);
if (response == WINTC_GINA_RESPONSE_OKAY)
{
wintc_welcome_ui_change_state(
welcome_ui,
WINTC_GINA_STATE_LAUNCHING
);
}
}
static gboolean on_timeout_delay_done(
gpointer user_data
)
{
WinTCWelcomeUI* welcome_ui = WINTC_WELCOME_UI(user_data);
switch (welcome_ui->priv->current_state)
{
case WINTC_GINA_STATE_STARTING:
g_timeout_add_seconds(
DELAY_SECONDS_POLL,
on_timeout_poll_ready,
welcome_ui
);
break;
case WINTC_GINA_STATE_LAUNCHING:
wintc_gina_logon_session_finish(
welcome_ui->priv->logon_session
);
break;
default:
g_critical("%s", "Invalid state reached for delay.");
break;
}
return G_SOURCE_REMOVE;
}
static gboolean on_timeout_poll_ready(
gpointer user_data
)
{
WinTCWelcomeUI* welcome_ui = WINTC_WELCOME_UI(user_data);
if (
wintc_gina_logon_session_is_available(
welcome_ui->priv->logon_session
)
)
{
wintc_welcome_ui_change_state(
welcome_ui,
WINTC_GINA_STATE_PROMPT
);
return G_SOURCE_REMOVE;
}
return G_SOURCE_CONTINUE;
}

View File

@@ -0,0 +1,28 @@
#ifndef __WELCOME_UI_H__
#define __WELCOME_UI_H__
#include <glib.h>
#include <gtk/gtk.h>
//
// GTK OOP BOILERPLATE
//
typedef struct _WinTCWelcomeUIPrivate WinTCWelcomeUIPrivate;
typedef struct _WinTCWelcomeUIClass WinTCWelcomeUIClass;
typedef struct _WinTCWelcomeUI WinTCWelcomeUI;
#define TYPE_WINTC_WELCOME_UI (wintc_welcome_ui_get_type())
#define WINTC_WELCOME_UI(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_WINTC_WELCOME_UI, WinTCWelcomeUI))
#define WINTC_WELCOME_UI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_WINTC_WELCOME_UI, WinTCWelcomeUI))
#define IS_WINTC_WELCOME_UI(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_WINTC_WELCOME_UI))
#define IS_WINTC_WELCOME_UI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_WINTC_WELCOME_UI))
#define WINTC_WELCOME_UI_GET_CLASS(obj) (G_TYPE_CHECK_INSTANCE_GET_CLASS((obj), TYPE_WINTC_WELCOME_UI))
GType wintc_welcome_ui_get_type(void) G_GNUC_CONST;
//
// PUBLIC FUNCTIONS
//
GtkWidget* wintc_welcome_ui_new(void);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,31 @@
#ifndef __USERLIST_H__
#define __USERLIST_H__
#include <glib.h>
#include <gtk/gtk.h>
#include <wintc-msgina.h>
//
// GTK OOP BOILERPLATE
//
typedef struct _WinTCWelcomeUserListPrivate WinTCWelcomeUserListPrivate;
typedef struct _WinTCWelcomeUserListClass WinTCWelcomeUserListClass;
typedef struct _WinTCWelcomeUserList WinTCWelcomeUserList;
#define TYPE_WINTC_WELCOME_USER_LIST (wintc_welcome_user_list_get_type())
#define WINTC_WELCOME_USER_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_WINTC_WELCOME_USER_LIST, WinTCWelcomeUserList))
#define WINTC_WELCOME_USER_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_WINTC_WELCOME_USER_LIST, WinTCWelcomeUserList))
#define IS_WINTC_WELCOME_USER_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_WINTC_WELCOME_USER_LIST))
#define IS_WINTC_WELCOME_USER_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_WINTC_WELCOME_USER_LIST))
#define WINTC_WELCOME_USER_LIST_GET_CLASS(obj) (G_TYPE_CHECK_INSTANCE_GET_CLASS((obj), TYPE_WINTC_WELCOME_USER_LIST))
GType wintc_welcome_user_list_get_type(void) G_GNUC_CONST;
//
// PUBLIC FUNCTIONS
//
GtkWidget* wintc_welcome_user_list_new(
WinTCGinaLogonSession* logon_session
);
#endif

224
base/logonui/src/window.c Normal file
View File

@@ -0,0 +1,224 @@
#include <gdk/gdk.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <wintc-comgtk.h>
#include "window.h"
#include "classic/ui.h"
#include "welcome/ui.h"
//
// PRIVATE ENUMS
//
enum
{
PROP_PREFER_CLASSIC_LOGON = 1,
N_PROPERTIES
};
//
// GTK OOP CLASS/INSTANCE DEFINITIONS
//
struct _WinTCLogonUIWindowPrivate
{
GtkWidget* login_ui;
};
struct _WinTCLogonUIWindowClass
{
GtkWindowClass __parent__;
};
struct _WinTCLogonUIWindow
{
GtkWindow __parent__;
WinTCLogonUIWindowPrivate* priv;
};
//
// FORWARD DECLARATIONS
//
static void wintc_logonui_window_set_property(
GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec
);
static gboolean on_window_map_event(
GtkWidget* self,
GdkEventAny* event,
gpointer user_data
);
static void on_window_realize(
GtkWidget* self,
gpointer user_data
);
//
// GTK TYPE DEFINITIONS & CTORS
//
G_DEFINE_TYPE_WITH_CODE(
WinTCLogonUIWindow,
wintc_logonui_window,
GTK_TYPE_WINDOW,
G_ADD_PRIVATE(WinTCLogonUIWindow)
)
static void wintc_logonui_window_class_init(
WinTCLogonUIWindowClass* klass
)
{
GObjectClass* object_class = G_OBJECT_CLASS(klass);
object_class->set_property = wintc_logonui_window_set_property;
g_object_class_install_property(
object_class,
PROP_PREFER_CLASSIC_LOGON,
g_param_spec_boolean(
"prefer-classic-logon",
"PreferClassicLogon",
"Prefer to use the classic logon user-interface.",
FALSE,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY
)
);
}
static void wintc_logonui_window_init(
WinTCLogonUIWindow* self
)
{
self->priv = wintc_logonui_window_get_instance_private(self);
// Set up window
//
GdkDisplay* display = gdk_display_get_default();
GdkRectangle geometry;
GdkMonitor* monitor = gdk_display_get_primary_monitor(display);
gdk_monitor_get_geometry(monitor, &geometry);
gtk_widget_set_size_request(
GTK_WIDGET(self),
geometry.width,
geometry.height
);
gtk_window_move(
GTK_WINDOW(self),
geometry.x,
geometry.y
);
// We delay some stuff until realize/map events:
// - we do not add the welcome/classic UI widget until we
// hit the 'map-event' signal, this ensures that any child
// windows are created after this window
// - delay cursor / other init until we realize the GDK
// resources for the window
//
g_signal_connect(
self,
"map-event",
G_CALLBACK(on_window_map_event),
NULL
);
g_signal_connect(
self,
"realize",
G_CALLBACK(on_window_realize),
NULL
);
//
// Welcome/Classic UI is decided/init'd in set_property
//
}
//
// CLASS VIRTUAL METHODS
//
static void wintc_logonui_window_set_property(
GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec
)
{
WinTCLogonUIWindow* window = WINTC_LOGONUI_WINDOW(object);
switch (prop_id)
{
case PROP_PREFER_CLASSIC_LOGON:
if (g_value_get_boolean(value))
{
window->priv->login_ui =
wintc_classic_ui_new();
}
else
{
window->priv->login_ui =
wintc_welcome_ui_new();
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
//
// PUBLIC FUNCTIONS
//
GtkWidget* wintc_logonui_window_new()
{
return GTK_WIDGET(
g_object_new(
TYPE_WINTC_LOGONUI_WINDOW,
"type", GTK_WINDOW_TOPLEVEL,
"decorated", FALSE,
"resizable", FALSE,
"type-hint", GDK_WINDOW_TYPE_HINT_DESKTOP,
"prefer-classic-logon", FALSE,
NULL
)
);
}
//
// CALLBACKS
//
static gboolean on_window_map_event(
GtkWidget* self,
WINTC_UNUSED(GdkEventAny* event),
WINTC_UNUSED(gpointer user_data)
)
{
WinTCLogonUIWindow* window = WINTC_LOGONUI_WINDOW(self);
gtk_container_add(
GTK_CONTAINER(self),
window->priv->login_ui
);
gtk_widget_show_all(window->priv->login_ui);
return TRUE;
}
static void on_window_realize(
GtkWidget* self,
WINTC_UNUSED(gpointer user_data)
)
{
gdk_window_set_cursor(
gtk_widget_get_window(self),
gdk_cursor_new_for_display(
gdk_display_get_default(),
GDK_LEFT_PTR
)
);
}

28
base/logonui/src/window.h Normal file
View File

@@ -0,0 +1,28 @@
#ifndef __WINDOW_H__
#define __WINDOW_H__
#include <glib.h>
#include <gtk/gtk.h>
//
// GTK OOP BOILERPLATE
//
typedef struct _WinTCLogonUIWindowPrivate WinTCLogonUIWindowPrivate;
typedef struct _WinTCLogonUIWindowClass WinTCLogonUIWindowClass;
typedef struct _WinTCLogonUIWindow WinTCLogonUIWindow;
#define TYPE_WINTC_LOGONUI_WINDOW (wintc_logonui_window_get_type())
#define WINTC_LOGONUI_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_WINTC_LOGONUI_WINDOW, WinTCLogonUIWindow))
#define WINTC_LOGONUI_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_WINTC_LOGONUI_WINDOW, WinTCLogonUIWindow))
#define IS_WINTC_LOGONUI_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_WINTC_LOGONUI_WINDOW))
#define IS_WINTC_LOGONUI_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_WINTC_LOGONUI_WINDOW))
#define WINTC_LOGONUI_WINDOW_GET_CLASS(obj) (G_TYPE_CHECK_INSTANCE_GET_CLASS((obj), TYPE_WINTC_LOGONUI_WINDOW))
GType wintc_logonui_window_get_type(void) G_GNUC_CONST;
//
// PUBLIC FUNCTIONS
//
GtkWidget* wintc_logonui_window_new();
#endif

View File

@@ -0,0 +1,5 @@
[Desktop Entry]
Name=WinTC LogonUI Greeter
Comment=This is the Windows Total Conversion logon user interface.
Exec=logonui
Type=Application

View File

@@ -162,7 +162,7 @@ check_deps()
#
case "${dist_id}" in
archpkg)
pacman -Q -k "${pkg_name}" >/dev/null 2>&1
pacman -Q -i "${pkg_name}" >/dev/null 2>&1
;;
deb)
dpkg -s "${pkg_name}" >/dev/null 2>&1

View File

@@ -21,6 +21,10 @@ option(
# Define pre-processor macro for checked builds
#
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
if (${CMAKE_BUILD_TYPE} STREQUAL Debug)
add_definitions(-DWINTC_CHECKED)
endif()

View File

@@ -1,5 +1,6 @@
base/bootvid
base/bldtag
base/logonui
cursors/no-shadow/standard
cursors/with-shadow/standard
fonts

View File

@@ -21,14 +21,18 @@ include(../../packaging/cmake-inc/linking/CMakeLists.txt)
include(../../packaging/cmake-inc/packaging/CMakeLists.txt)
include(../../packaging/cmake-inc/resources/CMakeLists.txt)
wintc_resolve_library(glib-2.0 GLIB)
wintc_resolve_library(gtk+-3.0 GTK3)
wintc_resolve_library(gdk-pixbuf-2.0 GDK_PIXBUF)
wintc_resolve_library(glib-2.0 GLIB)
wintc_resolve_library(gtk+-3.0 GTK3)
wintc_resolve_library(wintc-comgtk WINTC_COMGTK)
wintc_compile_resources()
add_library(
libwintc-comctl
src/resources.c
src/animctl.c
src/animctl.h
src/style.c
src/style.h
)
@@ -49,20 +53,26 @@ target_compile_options(
target_include_directories(
libwintc-comctl
SYSTEM
PRIVATE ${GDK_PIXBUF_INCLUDE_DIRS}
PRIVATE ${GLIB_INCLUDE_DIRS}
PRIVATE ${GTK3_INCLUDE_DIRS}
PRIVATE ${WINTC_COMGTK_INCLUDE_DIRS}
)
target_link_directories(
libwintc-comctl
PRIVATE ${GDK_PIXBUF_LIBRARY_DIRS}
PRIVATE ${GLIB_LIBRARY_DIRS}
PRIVATE ${GTK3_LIBRARY_DIRS}
PRIVATE ${WINTC_COMGTK_LIBRARY_DIRS}
)
target_link_libraries(
libwintc-comctl
PRIVATE ${GDK_PIXBUF_LIBRARIES}
PRIVATE ${GLIB_LIBRARIES}
PRIVATE ${GTK3_LIBRARIES}
PRIVATE ${WINTC_COMGTK_LIBRARIES}
)
# Installation

View File

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

View File

@@ -1,10 +1,72 @@
#ifndef __WINTC_COMCTL_H__
#define __WINTC_COMCTL_H__
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <glib.h>
#include <gtk/gtk.h>
//
// Animation control
//
#define WINTC_ANIMATION_INFINITE 0
#define WINTC_ANIMATION_NONE 0
typedef struct _WinTCAnimationPrivate WinTCAnimationPrivate;
typedef struct _WinTCAnimationClass WinTCAnimationClass;
typedef struct _WinTCAnimation WinTCAnimation;
#define TYPE_WINTC_ANIMATION (wintc_animation_get_type())
#define WINTC_ANIMATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_WINTC_ANIMATION, WinTCAnimation))
#define WINTC_ANIMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_WINTC_ANIMATION, WinTCAnimation))
#define IS_WINTC_ANIMATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_WINTC_ANIMATION))
#define IS_WINTC_ANIMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_WINTC_ANIMATION))
#define WINTC_ANIMATION_GET_CLASS(obj) (G_TYPE_CHECK_INSTANCE_GET_CLASS((obj), TYPE_WINTC_ANIMATION))
GType wintc_animation_get_type(void) G_GNUC_CONST;
GtkWidget* wintc_animation_new(void);
guint wintc_animation_add_framesheet(
WinTCAnimation* anim,
GdkPixbuf* framesheet_pixbuf,
gint frame_count
);
guint wintc_animation_add_static(
WinTCAnimation* anim,
GdkPixbuf* static_pixbuf
);
guint wintc_animation_get_count(
WinTCAnimation* anim
);
GtkAlign wintc_animation_get_halign(
WinTCAnimation* anim
);
GtkAlign wintc_animation_get_valign(
WinTCAnimation* anim
);
void wintc_animation_play(
WinTCAnimation* anim,
guint id,
gint frame_rate,
gint repeats
);
void wintc_animation_remove(
WinTCAnimation* anim,
guint id
);
void wintc_animation_set_halign(
WinTCAnimation* anim,
GtkAlign align
);
void wintc_animation_set_valign(
WinTCAnimation* anim,
GtkAlign align
);
//
// Default CSS stuff
//
#define WINTC_COMCTL_BUTTON_BOX_CLASS "wintc-button-box"
#define WINTC_COMCTL_BUTTON_BOX_CSS_CLASS "wintc-button-box"
void wintc_comctl_install_default_styles(void);

739
shared/comctl/src/animctl.c Normal file
View File

@@ -0,0 +1,739 @@
#include <gdk/gdk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <wintc-comgtk.h>
#include "animctl.h"
#define ONE_SECOND_IN_US 1000000
//
// PRIVATE ENUMS
//
enum
{
PROP_HALIGN = 1,
PROP_VALIGN,
N_PROPERTIES
};
//
// PRIVATE STURCTURE DEFINITIONS
//
typedef struct _WinTCAnimationData
{
GdkPixbuf* pixbuf_bmp;
cairo_surface_t* surface_bmp;
gint frame_count;
gint frame_height;
} WinTCAnimationData;
//
// GTK OOP CLASS/INSTANCE DEFINITIONS
//
struct _WinTCAnimationPrivate
{
GSList* animations;
gboolean is_animating;
guint tick_id;
WinTCAnimationData* current_anim;
gint current_frame;
gint desired_repeats;
gint last_frame;
gint64 origin_frame_time;
gint64 per_frame_time;
gint64 playback_total_time;
GtkAlign halign;
GtkAlign valign;
};
struct _WinTCAnimationClass
{
GtkWidgetClass __parent__;
};
struct _WinTCAnimation
{
GtkWidget __parent__;
WinTCAnimationPrivate* priv;
};
//
// FORWARD DECLARATIONS
//
static void wintc_animation_finalize(
GObject* gobject
);
static void wintc_animation_get_property(
GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec
);
static void wintc_animation_set_property(
GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec
);
static gboolean wintc_animation_draw(
GtkWidget* widget,
cairo_t* cr
);
static void wintc_animation_get_preferred_height(
GtkWidget* widget,
gint* minimum_height,
gint* natural_height
);
static void wintc_animation_get_preferred_height_for_width(
GtkWidget* widget,
gint width,
gint* minimum_height,
gint* natural_height
);
static void wintc_animation_get_preferred_width(
GtkWidget* widget,
gint* minimum_width,
gint* natural_width
);
static void wintc_animation_get_preferred_width_for_height(
GtkWidget* widget,
gint height,
gint* minimum_width,
gint* natural_width
);
static void free_anim_data(
WinTCAnimationData* anim_data
);
static gboolean wintc_animation_step(
GtkWidget* widget,
GdkFrameClock* frame_clock,
gpointer user_data
);
//
// GTK TYPE DEFINITIONS & CTORS
//
G_DEFINE_TYPE_WITH_CODE(
WinTCAnimation,
wintc_animation,
GTK_TYPE_WIDGET,
G_ADD_PRIVATE(WinTCAnimation)
)
static void wintc_animation_class_init(
WinTCAnimationClass* klass
)
{
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
GObjectClass* object_class = G_OBJECT_CLASS(klass);
object_class->finalize = wintc_animation_finalize;
object_class->get_property = wintc_animation_get_property;
object_class->set_property = wintc_animation_set_property;
widget_class->draw =
wintc_animation_draw;
widget_class->get_preferred_height =
wintc_animation_get_preferred_height;
widget_class->get_preferred_height_for_width =
wintc_animation_get_preferred_height_for_width;
widget_class->get_preferred_width =
wintc_animation_get_preferred_width;
widget_class->get_preferred_width_for_height =
wintc_animation_get_preferred_width_for_height;
g_object_class_install_property(
object_class,
PROP_HALIGN,
g_param_spec_enum(
"gfx-halign",
"GfxHAlign",
"The horizontal alignment for drawing.",
GTK_TYPE_ALIGN,
GTK_ALIGN_CENTER,
G_PARAM_WRITABLE
)
);
g_object_class_install_property(
object_class,
PROP_VALIGN,
g_param_spec_enum(
"gfx-valign",
"GfxVAlign",
"The vertical alignment for drawing.",
GTK_TYPE_ALIGN,
GTK_ALIGN_CENTER,
G_PARAM_WRITABLE
)
);
}
static void wintc_animation_init(
WinTCAnimation* self
)
{
self->priv = wintc_animation_get_instance_private(self);
gtk_widget_set_has_window(GTK_WIDGET(self), FALSE);
}
//
// CLASS VIRTUAL METHODS
//
static void wintc_animation_finalize(
GObject* gobject
)
{
WinTCAnimation* anim = WINTC_ANIMATION(gobject);
g_slist_free_full(
anim->priv->animations,
(GDestroyNotify) free_anim_data
);
if (anim->priv->tick_id > 0)
{
gtk_widget_remove_tick_callback(
GTK_WIDGET(anim),
anim->priv->tick_id
);
}
(G_OBJECT_CLASS(wintc_animation_parent_class))->finalize(gobject);
}
static void wintc_animation_get_property(
GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec
)
{
WinTCAnimation* anim = WINTC_ANIMATION(object);
switch (prop_id)
{
case PROP_HALIGN:
g_value_set_enum(value, anim->priv->halign);
break;
case PROP_VALIGN:
g_value_set_enum(value, anim->priv->valign);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
static void wintc_animation_set_property(
GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec
)
{
WinTCAnimation* anim = WINTC_ANIMATION(object);
switch (prop_id)
{
case PROP_HALIGN:
anim->priv->halign = g_value_get_enum(value);
gtk_widget_queue_draw(GTK_WIDGET(object));
break;
case PROP_VALIGN:
anim->priv->valign = g_value_get_enum(value);
gtk_widget_queue_draw(GTK_WIDGET(object));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
static gboolean wintc_animation_draw(
GtkWidget* widget,
cairo_t* cr
)
{
WinTCAnimation* anim = WINTC_ANIMATION(widget);
if (anim->priv->current_anim == NULL)
{
return FALSE;
}
// Set up to render the graphic
//
gint graphic_height;
gint graphic_width;
double y_offset;
graphic_width =
cairo_image_surface_get_width(
anim->priv->current_anim->surface_bmp
);
if (anim->priv->current_anim->frame_count > 1)
{
graphic_height = anim->priv->current_anim->frame_height;
y_offset = (graphic_height * anim->priv->current_frame) * -1.0f;
}
else
{
graphic_height =
cairo_image_surface_get_height(
anim->priv->current_anim->surface_bmp
);
y_offset = 0.0f;
}
// Calculate where we're drawing...
//
gint my_height = gtk_widget_get_allocated_height(widget);
gint my_width = gtk_widget_get_allocated_width(widget);
double target_x;
double target_y;
double target_width = graphic_width;
double target_height = graphic_height;
double target_scale_w = 1.0f;
double target_scale_h = 1.0f;
switch (anim->priv->halign)
{
case GTK_ALIGN_END:
target_x = (double) (my_width - graphic_width);
break;
case GTK_ALIGN_CENTER:
target_x = (double) ((my_width / 2) - (graphic_width / 2));
break;
case GTK_ALIGN_FILL:
target_width = my_width;
target_scale_w = (double) my_width / (double) graphic_width;
// Fall-through
default:
target_x = 0.0f;
break;
}
switch (anim->priv->valign)
{
case GTK_ALIGN_END:
target_y = (double) (my_height - graphic_height);
break;
case GTK_ALIGN_CENTER:
target_y = (double) ((my_height / 2) - (graphic_height / 2));
break;
case GTK_ALIGN_FILL:
target_height = my_height;
target_scale_h = (double) my_height / (double) graphic_height;
// Fall-through
default:
target_y = 0.0f;
break;
}
// Draw now
//
cairo_save(cr);
cairo_translate(cr, target_x, target_y);
cairo_rectangle(
cr,
0.0f,
0.0f,
(double) target_width,
(double) target_height
);
cairo_clip(cr);
cairo_scale(cr, target_scale_w, target_scale_h);
cairo_set_source_surface(
cr,
anim->priv->current_anim->surface_bmp,
0.0f,
y_offset
);
cairo_pattern_set_extend(
cairo_get_source(cr),
CAIRO_EXTEND_NONE
);
cairo_paint(cr);
cairo_restore(cr);
anim->priv->last_frame = anim->priv->current_frame;
return FALSE;
}
static void wintc_animation_get_preferred_height(
GtkWidget* widget,
gint* minimum_height,
gint* natural_height
)
{
WinTCAnimation* anim = WINTC_ANIMATION(widget);
gint height = 0;
if (anim->priv->current_anim != NULL)
{
if (anim->priv->current_anim->frame_count == 1)
{
height =
cairo_image_surface_get_height(
anim->priv->current_anim->surface_bmp
);
}
else
{
height = anim->priv->current_anim->frame_height;
}
}
*minimum_height = height;
*natural_height = height;
}
static void wintc_animation_get_preferred_height_for_width(
GtkWidget* widget,
WINTC_UNUSED(gint width),
gint* minimum_height,
gint* natural_height
)
{
wintc_animation_get_preferred_height(
widget,
minimum_height,
natural_height
);
}
static void wintc_animation_get_preferred_width(
GtkWidget* widget,
gint* minimum_width,
gint* natural_width
)
{
WinTCAnimation* anim = WINTC_ANIMATION(widget);
if (anim->priv->current_anim == NULL)
{
minimum_width = 0;
natural_width = 0;
return;
}
gint width =
cairo_image_surface_get_width(
anim->priv->current_anim->surface_bmp
);
*minimum_width = width;
*natural_width = width;
}
static void wintc_animation_get_preferred_width_for_height(
GtkWidget* widget,
WINTC_UNUSED(gint height),
gint* minimum_width,
gint* natural_width
)
{
wintc_animation_get_preferred_width(
widget,
minimum_width,
natural_width
);
}
//
// PUBLIC FUNCTIONS
//
GtkWidget* wintc_animation_new(void)
{
return GTK_WIDGET(
g_object_new(
TYPE_WINTC_ANIMATION,
NULL
)
);
}
guint wintc_animation_add_framesheet(
WinTCAnimation* anim,
GdkPixbuf* framesheet_pixbuf,
gint frame_count
)
{
WinTCAnimationData* anim_data = g_new0(WinTCAnimationData, 1);
gint height = gdk_pixbuf_get_height(framesheet_pixbuf);
g_object_ref(framesheet_pixbuf);
anim_data->pixbuf_bmp = framesheet_pixbuf;
anim_data->surface_bmp =
gdk_cairo_surface_create_from_pixbuf(
framesheet_pixbuf,
1,
NULL // FIXME: Error reporting
);
anim_data->frame_count = frame_count;
anim_data->frame_height = height / frame_count;
anim->priv->animations =
g_slist_append(
anim->priv->animations,
anim_data
);
return wintc_animation_get_count(anim);
}
guint wintc_animation_add_static(
WinTCAnimation* anim,
GdkPixbuf* static_pixbuf
)
{
WinTCAnimationData* anim_data = g_new0(WinTCAnimationData, 1);
g_object_ref(static_pixbuf);
anim_data->pixbuf_bmp = static_pixbuf;
anim_data->surface_bmp =
gdk_cairo_surface_create_from_pixbuf(
static_pixbuf,
1,
NULL // FIXME: Error reporting
);
anim_data->frame_count = 1;
anim_data->frame_height = 0;
anim->priv->animations =
g_slist_append(
anim->priv->animations,
anim_data
);
return wintc_animation_get_count(anim);
}
guint wintc_animation_get_count(
WinTCAnimation* anim
)
{
return g_slist_length(anim->priv->animations);
}
GtkAlign wintc_animation_get_halign(
WinTCAnimation* anim
)
{
GtkAlign value;
g_object_get(anim, "gfx-halign", &value, NULL);
return value;
}
GtkAlign wintc_animation_get_valign(
WinTCAnimation* anim
)
{
GtkAlign value;
g_object_get(anim, "gfx-valign", &value, NULL);
return value;
}
void wintc_animation_play(
WinTCAnimation* anim,
guint id,
gint frame_rate,
gint repeats
)
{
// Reset anim state values
//
anim->priv->is_animating = FALSE;
anim->priv->current_anim = NULL;
anim->priv->current_frame = 0;
anim->priv->last_frame = 0;
anim->priv->desired_repeats = 0;
anim->priv->origin_frame_time = 0;
anim->priv->per_frame_time = 0;
anim->priv->playback_total_time = 0;
// Queue a draw regardless of what happens
//
gtk_widget_queue_draw(GTK_WIDGET(anim));
// Check we're being asked to actually play anything
//
if (id > wintc_animation_get_count(anim))
{
g_warning("WinTCAnimation - attempted to play invalid ID %u", id);
return;
}
if (id == WINTC_ANIMATION_NONE)
{
return;
}
// Wahey! We have been asked to play something!
//
gint real_id = id - 1; // The consumer is given the count rather than index
// in the 'add' APIs, so that we can have a special
// meaning for 0 (WINTC_ANIMATION_NONE)
GSList* anim_link = g_slist_nth(
anim->priv->animations,
real_id
);
WinTCAnimationData* anim_data = anim_link->data;
anim->priv->current_anim = anim_data;
if (
anim_data->frame_count > 1 &&
frame_rate > 0
)
{
anim->priv->is_animating = TRUE;
anim->priv->desired_repeats = repeats;
anim->priv->origin_frame_time = g_get_monotonic_time();
anim->priv->per_frame_time = ONE_SECOND_IN_US / frame_rate;
anim->priv->playback_total_time =
anim->priv->per_frame_time * anim_data->frame_count;
if (anim->priv->tick_id == 0)
{
gtk_widget_add_tick_callback(
GTK_WIDGET(anim),
(GtkTickCallback) wintc_animation_step,
NULL,
NULL
);
}
}
}
void wintc_animation_remove(
WinTCAnimation* anim,
guint id
)
{
if (id == 0 || id > wintc_animation_get_count(anim))
{
g_warning("WinTCAnimation - attempted to remove invalid ID %u", id);
return;
}
gint real_id = id - 1;
GSList* to_delete = g_slist_nth(anim->priv->animations, real_id);
free_anim_data(to_delete->data);
anim->priv->animations =
g_slist_delete_link(
anim->priv->animations,
to_delete
);
}
void wintc_animation_set_halign(
WinTCAnimation* anim,
GtkAlign align
)
{
g_object_set(anim, "gfx-halign", align, NULL);
}
void wintc_animation_set_valign(
WinTCAnimation* anim,
GtkAlign align
)
{
g_object_set(anim, "gfx-valign", align, NULL);
}
//
// PRIVATE FUNCTIONS
//
static void free_anim_data(
WinTCAnimationData* anim_data
)
{
cairo_surface_destroy(anim_data->surface_bmp);
g_clear_object(&(anim_data->pixbuf_bmp));
g_free(anim_data);
}
//
// CALLBACKS
//
static gboolean wintc_animation_step(
GtkWidget* widget,
GdkFrameClock* frame_clock,
WINTC_UNUSED(gpointer user_data)
)
{
WinTCAnimation* anim = WINTC_ANIMATION(widget);
if (!anim->priv->is_animating)
{
return G_SOURCE_REMOVE;
}
gint64 frame_time = gdk_frame_clock_get_frame_time(frame_clock);
gint64 progress = frame_time - anim->priv->origin_frame_time;
gint64 repeat_no = progress / anim->priv->playback_total_time;
gint64 within_frame = progress % anim->priv->playback_total_time;
gint frame_no = (gint) (within_frame / anim->priv->per_frame_time);
if (
anim->priv->desired_repeats != WINTC_ANIMATION_INFINITE &&
anim->priv->desired_repeats < repeat_no
)
{
return G_SOURCE_REMOVE;
}
if (anim->priv->last_frame != frame_no)
{
gtk_widget_queue_draw(widget);
}
anim->priv->current_frame = frame_no;
return G_SOURCE_CONTINUE;
}

View File

@@ -0,0 +1,72 @@
#ifndef __ANIMCTL_H__
#define __ANIMCTL_H__
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <glib.h>
#include <gtk/gtk.h>
//
// PUBLIC DEFINES
//
#define WINTC_ANIMATION_INFINITE 0
#define WINTC_ANIMATION_NONE 0
//
// GTK OOP BOILERPLATE
//
typedef struct _WinTCAnimationPrivate WinTCAnimationPrivate;
typedef struct _WinTCAnimationClass WinTCAnimationClass;
typedef struct _WinTCAnimation WinTCAnimation;
#define TYPE_WINTC_ANIMATION (wintc_animation_get_type())
#define WINTC_ANIMATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_WINTC_ANIMATION, WinTCAnimation))
#define WINTC_ANIMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_WINTC_ANIMATION, WinTCAnimation))
#define IS_WINTC_ANIMATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_WINTC_ANIMATION))
#define IS_WINTC_ANIMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_WINTC_ANIMATION))
#define WINTC_ANIMATION_GET_CLASS(obj) (G_TYPE_CHECK_INSTANCE_GET_CLASS((obj), TYPE_WINTC_ANIMATION))
GType wintc_animation_get_type(void) G_GNUC_CONST;
//
// PUBLIC FUNCTIONS
//
GtkWidget* wintc_animation_new(void);
guint wintc_animation_add_framesheet(
WinTCAnimation* anim,
GdkPixbuf* framesheet_pixbuf,
gint frame_count
);
guint wintc_animation_add_static(
WinTCAnimation* anim,
GdkPixbuf* static_pixbuf
);
guint wintc_animation_get_count(
WinTCAnimation* anim
);
GtkAlign wintc_animation_get_halign(
WinTCAnimation* anim
);
GtkAlign wintc_animation_get_valign(
WinTCAnimation* anim
);
void wintc_animation_play(
WinTCAnimation* anim,
guint id,
gint frame_rate,
gint repeats
);
void wintc_animation_remove(
WinTCAnimation* anim,
guint id
);
void wintc_animation_set_halign(
WinTCAnimation* anim,
GtkAlign align
);
void wintc_animation_set_valign(
WinTCAnimation* anim,
GtkAlign align
);
#endif

View File

@@ -13,6 +13,10 @@ set(PROJECT_MAINTAINER "Rory Fewell <roryf@oddmatics.uk>")
set(PROJECT_ROOT ${CMAKE_CURRENT_LIST_DIR})
# Necessary due to fn ptr casts in marshal.c
#
set(WINTC_NO_PEDANTIC_COMPILE true)
include(GNUInstallDirs)
include(../../packaging/cmake-inc/common/CMakeLists.txt)
@@ -35,6 +39,8 @@ add_library(
src/gchar.h
src/list.c
src/list.h
src/marshal.c
src/marshal.h
src/msgbox.c
src/msgbox.h
src/profile.c

View File

@@ -8,7 +8,13 @@
// Debugging
//
#define WINTC_ENVVAR_DEBUG_LOGGING "WINDEBUG"
#define WINTC_LOG_DEBUG(...) if (getenv(WINTC_ENVVAR_DEBUG_LOGGING)) { g_message(__VA_ARGS__); }
#define WINTC_LOG_USER_DEBUG(...) if (getenv(WINTC_ENVVAR_DEBUG_LOGGING)) { g_message(__VA_ARGS__); }
#ifdef WINTC_CHECKED
#define WINTC_LOG_DEBUG(...) g_message(__VA_ARGS__);
#else
#define WINTC_LOG_DEBUG(...)
#endif
//
// Shorthand
@@ -101,6 +107,27 @@ GList* wintc_list_read_from_string(
const gchar* str
);
//
// Closure Marshals
//
void wintc_cclosure_marshal_BOOLEAN__VOID(
GClosure* closure,
GValue* return_value,
guint n_param_values,
const GValue* param_values,
gpointer invocation_hint,
gpointer marshal_data
);
void wintc_cclosure_marshal_INT__VOID(
GClosure* closure,
GValue* return_value,
guint n_param_values,
const GValue* param_values,
gpointer invocation_hint,
gpointer marshal_data
);
//
// Message Box-related
//
@@ -208,4 +235,4 @@ void wintc_focus_window(
GtkWindow* window
);
#endif
#endif

View File

@@ -1,7 +1,17 @@
#ifndef __DEBUG_H__
#define __DEBUG_H__
// Two variants for debug messaging are provided:
// USER_DEBUG is at runtime, intended at end user debugging
// DEBUG is compile time, intended for development
//
#define WINTC_ENVVAR_DEBUG_LOGGING "WINDEBUG"
#define WINTC_LOG_DEBUG(...) if (getenv(WINTC_ENVVAR_DEBUG_LOGGING)) { g_message(__VA_ARGS__); }
#define WINTC_LOG_USER_DEBUG(...) if (getenv(WINTC_ENVVAR_DEBUG_LOGGING)) { g_message(__VA_ARGS__); }
#ifdef WINTC_CHECKED
#define WINTC_LOG_DEBUG(...) g_message(__VA_ARGS__);
#else
#define WINTC_LOG_DEBUG(...)
#endif
#endif

View File

@@ -0,0 +1,96 @@
#include <glib.h>
#include <gtk/gtk.h>
#include "marshal.h"
#include "shorthand.h"
//
// PUBLIC FUNCTIONS
//
void wintc_cclosure_marshal_BOOLEAN__VOID(
GClosure* closure,
GValue* return_value,
guint n_param_values,
const GValue* param_values,
WINTC_UNUSED(gpointer invocation_hint),
gpointer marshal_data
)
{
typedef gboolean (*GMarshalFunc_BOOLEAN__VOID) (
gpointer data1,
gpointer data2
);
GMarshalFunc_BOOLEAN__VOID callback;
GCClosure* cc;
gpointer data1;
gpointer data2;
gboolean v_return;
cc = (GCClosure*) closure;
g_return_if_fail(n_param_values == 1);
if (G_CCLOSURE_SWAP_DATA(closure))
{
data1 = closure->data;
data2 = g_value_peek_pointer(param_values + 0);
}
else
{
data1 = g_value_peek_pointer(param_values + 0);
data2 = closure->data;
}
callback =
(GMarshalFunc_BOOLEAN__VOID)
(marshal_data ? marshal_data : cc->callback);
v_return = callback(data1, data2);
g_value_set_boolean(return_value, v_return);
}
void wintc_cclosure_marshal_INT__VOID(
GClosure* closure,
GValue* return_value,
guint n_param_values,
const GValue* param_values,
WINTC_UNUSED(gpointer invocation_hint),
gpointer marshal_data
)
{
typedef gint (*GMarshalFunc_INT__VOID) (
gpointer data1,
gpointer data2
);
GMarshalFunc_INT__VOID callback;
GCClosure* cc;
gpointer data1;
gpointer data2;
gboolean v_return;
cc = (GCClosure*) closure;
g_return_if_fail(n_param_values == 1);
if (G_CCLOSURE_SWAP_DATA(closure))
{
data1 = closure->data;
data2 = g_value_peek_pointer(param_values + 0);
}
else
{
data1 = g_value_peek_pointer(param_values + 0);
data2 = closure->data;
}
callback =
(GMarshalFunc_INT__VOID)
(marshal_data ? marshal_data : cc->callback);
v_return = callback(data1, data2);
g_value_set_int(return_value, v_return);
}

View File

@@ -0,0 +1,28 @@
#ifndef __MARSHAL_H__
#define __MARSHAL_H__
#include <glib.h>
#include <gtk/gtk.h>
//
// PUBLIC FUNCTIONS
//
void wintc_cclosure_marshal_BOOLEAN__VOID(
GClosure* closure,
GValue* return_value,
guint n_param_values,
const GValue* param_values,
gpointer invocation_hint,
gpointer marshal_data
);
void wintc_cclosure_marshal_INT__VOID(
GClosure* closure,
GValue* return_value,
guint n_param_values,
const GValue* param_values,
gpointer invocation_hint,
gpointer marshal_data
);
#endif

View File

@@ -1,7 +0,0 @@
Package: lib@PROJECT_NAME@-@PROJECT_VERSION@
Version: @PROJECT_VERSION@
Maintainer: Rory Fewell <roryf@oddmatics.uk>
Architecture: @ARCH_NAME@
Section: free
Description: @PROJECT_DESCRIPTION@
Depends: @DEB_DEPENDENCIES@

View File

@@ -76,7 +76,7 @@ gboolean wintc_launch_command(
WINTC_SAFE_REF_CLEAR(out_error);
WINTC_LOG_DEBUG("Launching %s", cmdline);
WINTC_LOG_USER_DEBUG("Launching %s", cmdline);
// Iterate through parsers
//
@@ -93,7 +93,7 @@ gboolean wintc_launch_command(
return FALSE;
}
WINTC_LOG_DEBUG("Parse result: %s", real_cmdline);
WINTC_LOG_USER_DEBUG("Parse result: %s", real_cmdline);
wintc_strsteal(&tmp_cmdline, &real_cmdline);
@@ -104,7 +104,7 @@ gboolean wintc_launch_command(
//
real_cmdline = tmp_cmdline;
WINTC_LOG_DEBUG("Parsed command line: %s", real_cmdline);
WINTC_LOG_USER_DEBUG("Parsed command line: %s", real_cmdline);
// Parse the command line into an argument vector
//
@@ -142,14 +142,14 @@ gboolean wintc_launch_command(
if (!success)
{
WINTC_LOG_DEBUG("Failed to launch: %s", error->message);
WINTC_LOG_USER_DEBUG("Failed to launch: %s", error->message);
g_propagate_error(out_error, error);
return FALSE;
}
WINTC_LOG_DEBUG("Done.");
WINTC_LOG_USER_DEBUG("Done.");
return TRUE;
}
@@ -201,7 +201,7 @@ static gboolean parse_file_in_cmdline(
g_strcmp0(file_mime, "application/x-sharedlib") != 0
)
{
WINTC_LOG_DEBUG("Not an executable, will look for handler.");
WINTC_LOG_USER_DEBUG("Not an executable, will look for handler.");
handler_entry =
wintc_query_mime_handler(
@@ -211,7 +211,7 @@ static gboolean parse_file_in_cmdline(
if (handler_entry == NULL)
{
WINTC_LOG_DEBUG("I have nothing to handle the file!");
WINTC_LOG_USER_DEBUG("I have nothing to handle the file!");
g_propagate_error(out_error, error);
WINTC_SAFE_REF_SET(out_cmdline, g_strdup(cmdline));
@@ -282,7 +282,7 @@ static gboolean parse_unc_path_in_cmdline(
if (unc_regex == NULL)
{
WINTC_LOG_DEBUG("Failed to create the UNC path regex.");
WINTC_LOG_USER_DEBUG("Failed to create the UNC path regex.");
g_propagate_error(out_error, error);
@@ -292,7 +292,7 @@ static gboolean parse_unc_path_in_cmdline(
// Examine command line
//
WINTC_LOG_DEBUG("Checking if %s looks like a UNC path...", cmdline);
WINTC_LOG_USER_DEBUG("Checking if %s looks like a UNC path...", cmdline);
g_regex_match(unc_regex, cmdline, 0, &match_info);
@@ -302,7 +302,7 @@ static gboolean parse_unc_path_in_cmdline(
//
if (match_count == 0)
{
WINTC_LOG_DEBUG("Nope!");
WINTC_LOG_USER_DEBUG("Nope!");
g_match_info_free(match_info);
@@ -313,7 +313,7 @@ static gboolean parse_unc_path_in_cmdline(
// Command line IS a UNC path, we need to retrieve the target host and path
//
WINTC_LOG_DEBUG("Yeah, looks like a UNC path.");
WINTC_LOG_USER_DEBUG("Yeah, looks like a UNC path.");
host = g_strdup(g_match_info_fetch(match_info, 1));
@@ -329,8 +329,8 @@ static gboolean parse_unc_path_in_cmdline(
g_match_info_free(match_info);
// Construct URI (doesn't matter if path is NULL, the func stops at the first
// NULL anyway)
// Construct URI (doesn't matter if path is NULL, the func stops at the
// first NULL anyway)
//
uri = g_strconcat("smb://", host, path, NULL);
@@ -376,7 +376,7 @@ static gboolean parse_url_in_cmdline(
if (url_regex == NULL)
{
WINTC_LOG_DEBUG("Failed to create the URL regex.");
WINTC_LOG_USER_DEBUG("Failed to create the URL regex.");
g_propagate_error(out_error, error);
@@ -386,7 +386,7 @@ static gboolean parse_url_in_cmdline(
// Examine command line
//
WINTC_LOG_DEBUG("Checking if %s looks like a URL...", cmdline);
WINTC_LOG_USER_DEBUG("Checking if %s looks like a URL...", cmdline);
g_regex_match(url_regex, cmdline, 0, &match_info);
@@ -394,7 +394,7 @@ static gboolean parse_url_in_cmdline(
//
if (g_match_info_get_match_count(match_info) == 0)
{
WINTC_LOG_DEBUG("Nope!");
WINTC_LOG_USER_DEBUG("Nope!");
g_match_info_free(match_info);
@@ -405,7 +405,7 @@ static gboolean parse_url_in_cmdline(
// Command line IS a URL, retrieve the scheme, query the handling program...
//
WINTC_LOG_DEBUG("Yeah, looks like a URL.");
WINTC_LOG_USER_DEBUG("Yeah, looks like a URL.");
uri_scheme = g_match_info_fetch(match_info, 1);
mime_type = g_strdup_printf(
@@ -421,7 +421,7 @@ static gboolean parse_url_in_cmdline(
if (handler_entry == NULL)
{
WINTC_LOG_DEBUG("I have nothing to handle the URL!");
WINTC_LOG_USER_DEBUG("I have nothing to handle the URL!");
g_propagate_error(out_error, error);
@@ -476,7 +476,7 @@ static gchar** true_shell_parse_argv(
if (error != NULL)
{
WINTC_LOG_DEBUG("Failed to parse command line: %s", cmdline);
WINTC_LOG_USER_DEBUG("Failed to parse command line: %s", cmdline);
g_propagate_error(out_error, error);

View File

@@ -24,7 +24,7 @@ gchar* wintc_query_mime_for_file(
gint status;
gboolean success = FALSE;
WINTC_LOG_DEBUG("Querying MIME type for: %s", filepath);
WINTC_LOG_USER_DEBUG("Querying MIME type for: %s", filepath);
WINTC_SAFE_REF_CLEAR(out_error);
@@ -47,7 +47,7 @@ gchar* wintc_query_mime_for_file(
{
g_strstrip(cmd_output);
WINTC_LOG_DEBUG("Determined: %s", cmd_output);
WINTC_LOG_USER_DEBUG("Determined: %s", cmd_output);
return cmd_output;
}
@@ -56,14 +56,14 @@ gchar* wintc_query_mime_for_file(
//
if (error != NULL)
{
WINTC_LOG_DEBUG("An error occurred: %s", error->message);
WINTC_LOG_USER_DEBUG("An error occurred: %s", error->message);
g_propagate_error(out_error, error);
return NULL;
}
WINTC_LOG_DEBUG("Failed with code %d", status);
WINTC_LOG_USER_DEBUG("Failed with code %d", status);
switch (status)
{
@@ -109,7 +109,7 @@ GDesktopAppInfo* wintc_query_mime_handler(
gchar* filename = NULL;
gboolean success = FALSE;
WINTC_LOG_DEBUG("Querying handler for MIME type %s", mime_query);
WINTC_LOG_USER_DEBUG("Querying handler for MIME type %s", mime_query);
WINTC_SAFE_REF_CLEAR(out_error);
@@ -128,7 +128,7 @@ GDesktopAppInfo* wintc_query_mime_handler(
if (!success)
{
WINTC_LOG_DEBUG("Failed to query MIME type: %s", error->message);
WINTC_LOG_USER_DEBUG("Failed to query MIME type: %s", error->message);
g_propagate_error(out_error, error);
@@ -143,7 +143,7 @@ GDesktopAppInfo* wintc_query_mime_handler(
if (output_length == 0)
{
WINTC_LOG_DEBUG("No handler found!");
WINTC_LOG_USER_DEBUG("No handler found!");
g_set_error(
out_error,
@@ -167,7 +167,7 @@ GDesktopAppInfo* wintc_query_mime_handler(
);
entry = g_desktop_app_info_new(filename);
WINTC_LOG_DEBUG("Query returned: %s", filename);
WINTC_LOG_USER_DEBUG("Query returned: %s", filename);
g_free(cmd_output);
g_free(filename);
@@ -182,7 +182,7 @@ GDesktopAppInfo* wintc_query_mime_handler(
mime_query
);
WINTC_LOG_DEBUG("Association found, but the desktop entry doesn't exist.");
WINTC_LOG_USER_DEBUG("Association found, but the desktop entry doesn't exist.");
return NULL;
}

View File

@@ -0,0 +1,103 @@
cmake_minimum_required(VERSION 3.0)
project(
libwintc-msgina
VERSION 1.0
DESCRIPTION "Windows Total Conversion GINA library."
LANGUAGES C
)
set(PROJECT_ANYARCH false)
set(PROJECT_FREESTATUS false)
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/libraries/CMakeLists.txt)
include(../../packaging/cmake-inc/linking/CMakeLists.txt)
include(../../packaging/cmake-inc/packaging/CMakeLists.txt)
include(../../packaging/cmake-inc/resources/CMakeLists.txt)
wintc_resolve_library(gdk-pixbuf-2.0 GDK_PIXBUF)
wintc_resolve_library(glib-2.0 GLIB)
wintc_resolve_library(gtk+-3.0 GTK3)
wintc_resolve_library(liblightdm-gobject-1 LIGHTDM)
wintc_resolve_library(wintc-comctl WINTC_COMCTL)
wintc_resolve_library(wintc-comgtk WINTC_COMGTK)
wintc_resolve_library(wintc-winbrand WINTC_WINBRAND)
wintc_compile_resources()
add_library(
libwintc-msgina
src/resources.c
src/authwnd.c
src/authwnd.h
src/challenge.h
src/logon.c
src/logon.h
src/state.h
src/stripctl.c
src/stripctl.h
)
set_target_properties(
libwintc-msgina
PROPERTIES
PUBLIC_HEADER public/wintc-msgina.h
SOVERSION 1
VERSION ${PROJECT_VERSION}
)
target_compile_options(
libwintc-msgina
PRIVATE ${WINTC_COMPILE_OPTIONS}
)
target_include_directories(
libwintc-msgina
SYSTEM
PRIVATE ${GDK_PIXBUF_INCLUDE_DIRS}
PRIVATE ${GLIB_INCLUDE_DIRS}
PRIVATE ${GTK3_INCLUDE_DIRS}
PRIVATE ${LIGHTDM_INCLUDE_DIRS}
PRIVATE ${WINTC_COMCTL_INCLUDE_DIRS}
PRIVATE ${WINTC_COMGTK_INCLUDE_DIRS}
PRIVATE ${WINTC_WINBRAND_INCLUDE_DIRS}
)
target_link_directories(
libwintc-msgina
PRIVATE ${GDK_PIXBUF_LIBRARY_DIRS}
PRIVATE ${GLIB_LIBRARY_DIRS}
PRIVATE ${GTK3_LIBRARY_DIRS}
PRIVATE ${LIGHTDM_LIBRARY_DIRS}
PRIVATE ${WINTC_COMCTL_LIBRARY_DIRS}
PRIVATE ${WINTC_COMGTK_LIBRARY_DIRS}
PRIVATE ${WINTC_WINBRAND_LIBRARY_DIRS}
)
target_link_libraries(
libwintc-msgina
PRIVATE ${GDK_PIXBUF_LIBRARIES}
PRIVATE ${GLIB_LIBRARIES}
PRIVATE ${GTK3_LIBRARIES}
PRIVATE ${LIGHTDM_LIBRARIES}
PRIVATE ${WINTC_COMCTL_LIBRARIES}
PRIVATE ${WINTC_COMGTK_LIBRARIES}
PRIVATE ${WINTC_WINBRAND_LIBRARIES}
)
# Installation
#
wintc_configure_and_install_packaging()
wintc_add_pkgconfig_install()
install(
TARGETS libwintc-msgina
LIBRARY DESTINATION ${LIB_DIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)

7
shared/msgina/README.MD Normal file
View File

@@ -0,0 +1,7 @@
# libwintc-msgina
This directory contains the source-code for the GINA services (logon/security/auth related functions).
# Purpose
This library provides services related to security. At the moment this includes the APIs for performing user logon (via LightDM), and contains the 'classic' logon dialog.
In future this should be expanded to handle other forms of logon rather than just simple text based local auth, as well as things like the Windows Security dialog.

4
shared/msgina/deps Normal file
View File

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

View File

@@ -0,0 +1,77 @@
#ifndef __WINTC_MSGINA_H__
#define __WINTC_MSGINA_H__
#include <glib.h>
#include <gtk/gtk.h>
//
// Authentication window
//
typedef struct _WinTCGinaAuthWindowPrivate WinTCGinaAuthWindowPrivate;
typedef struct _WinTCGinaAuthWindowClass WinTCGinaAuthWindowClass;
typedef struct _WinTCGinaAuthWindow WinTCGinaAuthWindow;
#define TYPE_WINTC_GINA_AUTH_WINDOW (wintc_gina_auth_window_get_type())
#define WINTC_GINA_AUTH_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_WINTC_GINA_AUTH_WINDOW, WinTCGinaAuthWindow))
#define WINTC_GINA_AUTH_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_WINTC_GINA_AUTH_WINDOW, WinTCGinaAuthWindow))
#define IS_WINTC_GINA_AUTH_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_WINTC_GINA_AUTH_WINDOW))
#define IS_WINTC_GINA_AUTH_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_WINTC_GINA_AUTH_WINDOW))
#define WINTC_GINA_WINDOW_GET_CLASS(obj) (G_TYPE_CHECK_INSTANCE_GET_CLASS((obj), TYPE_WINTC_GINA_AUTH_WINDOW))
GType wintc_gina_auth_window_get_type(void) G_GNUC_CONST;
GtkWidget* wintc_gina_auth_window_new(void);
//
// Challenge auth
//
typedef enum
{
WINTC_GINA_RESPONSE_OKAY = 0,
WINTC_GINA_RESPONSE_FAIL = 1
} WinTCGinaResponse;
//
// Logon session
//
typedef struct _WinTCGinaLogonSessionClass WinTCGinaLogonSessionClass;
typedef struct _WinTCGinaLogonSession WinTCGinaLogonSession;
#define TYPE_WINTC_GINA_LOGON_SESSION (wintc_gina_logon_session_get_type())
#define WINTC_GINA_LOGON_SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_WINTC_GINA_LOGON_SESSION, WinTCGinaLogonSession))
#define WINTC_GINA_LOGON_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_WINTC_GINA_LOGON_SESSION, WinTCGinaLogonSession))
#define IS_WINTC_GINA_LOGON_SESSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_WINTC_GINA_LOGON_SESSION))
#define IS_WINTC_GINA_LOGON_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_WINTC_GINA_LOGON_SESSION))
#define WINTC_GINA_LOGON_SESSION_GET_CLASS(obj) (G_TYPE_CHECK_INSTANCE_GET_CLASS((obj), TYPE_WINTC_GINA_LOGON_SESSION)
GType wintc_gina_logon_session_get_type(void) G_GNUC_CONST;
WinTCGinaLogonSession* wintc_gina_logon_session_new(void);
gboolean wintc_gina_logon_session_establish(
WinTCGinaLogonSession* logon_session
);
void wintc_gina_logon_session_finish(
WinTCGinaLogonSession* logon_session
);
gboolean wintc_gina_logon_session_is_available(
WinTCGinaLogonSession* logon_session
);
void wintc_gina_logon_session_try_logon(
WinTCGinaLogonSession* logon_session,
const gchar* username,
const gchar* password
);
//
// State
//
typedef enum
{
WINTC_GINA_STATE_NONE = 0,
WINTC_GINA_STATE_STARTING,
WINTC_GINA_STATE_PROMPT,
WINTC_GINA_STATE_LAUNCHING
} WinTCGinaState;
#endif

631
shared/msgina/src/authwnd.c Normal file
View File

@@ -0,0 +1,631 @@
#include <gdk/gdk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <wintc-comctl.h>
#include <wintc-comgtk.h>
#include <wintc-winbrand.h>
#include "authwnd.h"
#include "challenge.h"
#include "logon.h"
#include "state.h"
#include "stripctl.h"
#define DELAY_SECONDS_AT_LEAST 2
#define DELAY_SECONDS_POLL 1
//
// GTK OOP CLASS/INSTANCE DEFINITIONS
//
struct _WinTCGinaAuthWindowPrivate
{
// Image resources
//
GdkPixbuf* pixbuf_banner;
GdkPixbuf* pixbuf_bannerx;
// UI
//
GtkWidget* box_container;
GtkWidget* box_brand;
GtkWidget* box_login;
GtkWidget* box_wait;
GtkWidget* button_submit;
GtkWidget* entry_password;
GtkWidget* entry_username;
GtkWidget* strip;
// State
//
WinTCGinaState current_state;
WinTCGinaLogonSession* logon_session;
};
struct _WinTCGinaAuthWindowClass
{
GtkWindowClass __parent__;
};
struct _WinTCGinaAuthWindow
{
GtkWindow __parent__;
WinTCGinaAuthWindowPrivate* priv;
};
//
// FORWARD DECLARATIONS
//
static void wintc_gina_auth_window_finalize(
GObject* object
);
static void wintc_gina_auth_window_change_state(
WinTCGinaAuthWindow* window,
WinTCGinaState next_state
);
static void on_self_realized(
GtkWidget* self,
gpointer user_data
);
static void on_logon_session_attempt_complete(
WinTCGinaLogonSession* logon_session,
WinTCGinaResponse response,
gpointer user_data
);
static void on_button_submit_clicked(
GtkButton* self,
gpointer user_data
);
static gboolean on_timeout_delay_done(
gpointer user_data
);
static gboolean on_timeout_poll_ready(
gpointer user_data
);
//
// GTK TYPE DEFINITIONS & CTORS
//
G_DEFINE_TYPE_WITH_CODE(
WinTCGinaAuthWindow,
wintc_gina_auth_window,
GTK_TYPE_WINDOW,
G_ADD_PRIVATE(WinTCGinaAuthWindow)
)
static void wintc_gina_auth_window_class_init(
WinTCGinaAuthWindowClass* klass
)
{
GObjectClass* object_class = G_OBJECT_CLASS(klass);
object_class->finalize = wintc_gina_auth_window_finalize;
// Load up styles
//
GtkCssProvider* css_authwnd = gtk_css_provider_new();
gtk_css_provider_load_from_resource(
css_authwnd,
"/uk/oddmatics/wintc/msgina/authwnd.css"
);
gtk_style_context_add_provider_for_screen(
gdk_screen_get_default(),
GTK_STYLE_PROVIDER(css_authwnd),
GTK_STYLE_PROVIDER_PRIORITY_FALLBACK
);
wintc_comctl_install_default_styles();
}
static void wintc_gina_auth_window_init(
WinTCGinaAuthWindow* self
)
{
self->priv = wintc_gina_auth_window_get_instance_private(self);
// Acquire branding pixbufs
//
GError* err_banner = NULL;
GError* err_bannerx = NULL;
self->priv->pixbuf_banner = wintc_brand_get_brand_pixmap(
WINTC_BRAND_PART_BANNER,
&err_banner
);
self->priv->pixbuf_bannerx = wintc_brand_get_brand_pixmap(
WINTC_BRAND_PART_BANNER_TALL,
&err_bannerx
);
wintc_display_error_and_clear(&err_banner);
wintc_display_error_and_clear(&err_bannerx);
// Set up branding box
//
GtkWidget* image_brand =
gtk_image_new_from_pixbuf(
self->priv->pixbuf_bannerx
);
self->priv->box_brand = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
self->priv->strip = wintc_gina_strip_new();
gtk_box_pack_start(
GTK_BOX(self->priv->box_brand),
image_brand,
FALSE,
FALSE,
0
);
gtk_box_pack_start(
GTK_BOX(self->priv->box_brand),
self->priv->strip,
FALSE,
FALSE,
0
);
// Set up 'Please wait...' box
//
GtkWidget* label_wait = gtk_label_new("Please wait...");
self->priv->box_wait = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
wintc_widget_add_style_class(
self->priv->box_wait,
"please-wait"
);
gtk_widget_set_halign(
label_wait,
GTK_ALIGN_START
);
gtk_widget_set_valign(
label_wait,
GTK_ALIGN_START
);
gtk_box_pack_start(
GTK_BOX(self->priv->box_wait),
label_wait,
TRUE,
TRUE,
0
);
// Set up login box
//
GtkWidget* box_buttons = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
GtkWidget* grid_login = gtk_grid_new();
GtkWidget* label_password = gtk_label_new("Password:");
GtkWidget* label_username = gtk_label_new("User name:");
self->priv->box_login = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
self->priv->button_submit = gtk_button_new_with_label("OK");
self->priv->entry_password = gtk_entry_new();
self->priv->entry_username = gtk_entry_new();
wintc_widget_add_style_class(
box_buttons,
WINTC_COMCTL_BUTTON_BOX_CSS_CLASS
);
wintc_widget_add_style_class(
self->priv->box_login,
"login"
);
gtk_widget_set_halign(
label_password,
GTK_ALIGN_START
);
gtk_widget_set_halign(
label_username,
GTK_ALIGN_START
);
gtk_entry_set_visibility(GTK_ENTRY(self->priv->entry_password), FALSE);
g_signal_connect(
self->priv->button_submit,
"clicked",
G_CALLBACK(on_button_submit_clicked),
self
);
gtk_grid_attach(
GTK_GRID(grid_login),
label_username,
0,
0,
1,
1
);
gtk_grid_attach(
GTK_GRID(grid_login),
self->priv->entry_username,
1,
0,
1,
1
);
gtk_grid_attach(
GTK_GRID(grid_login),
label_password,
0,
1,
1,
1
);
gtk_grid_attach(
GTK_GRID(grid_login),
self->priv->entry_password,
1,
1,
1,
1
);
gtk_box_pack_end(
GTK_BOX(box_buttons),
self->priv->button_submit,
FALSE,
FALSE,
0
);
gtk_container_add(
GTK_CONTAINER(self->priv->box_login),
grid_login
);
gtk_container_add(
GTK_CONTAINER(self->priv->box_login),
box_buttons
);
// Set up remainder of UI
//
GtkWidget* header_bar = gtk_header_bar_new();
self->priv->box_container = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_header_bar_set_title(
GTK_HEADER_BAR(header_bar),
"Log On to Windows"
);
gtk_container_add(
GTK_CONTAINER(self->priv->box_container),
self->priv->box_brand
);
gtk_container_add(
GTK_CONTAINER(self),
self->priv->box_container
);
gtk_window_set_titlebar(
GTK_WINDOW(self),
header_bar
);
// Hold additional references to the boxes, so we can add/remove
// them ourselves without them getting binned
//
g_object_ref(self->priv->box_login);
g_object_ref(self->priv->box_wait);
// Connect to realize signal to kick off everything when we're
// actually live
//
g_signal_connect(
self,
"realize",
G_CALLBACK(on_self_realized),
NULL
);
// Set initial state
//
self->priv->current_state = WINTC_GINA_STATE_NONE;
self->priv->logon_session = wintc_gina_logon_session_new();
g_signal_connect(
self->priv->logon_session,
"attempt-complete",
G_CALLBACK(on_logon_session_attempt_complete),
self
);
}
//
// CLASS VIRTUAL METHODS
//
static void wintc_gina_auth_window_finalize(
GObject* gobject
)
{
WinTCGinaAuthWindow* window = WINTC_GINA_AUTH_WINDOW(gobject);
g_clear_object(&(window->priv->pixbuf_banner));
g_clear_object(&(window->priv->pixbuf_bannerx));
// Bin additional references held for the boxes
//
g_clear_object(&(window->priv->box_login));
g_clear_object(&(window->priv->box_wait));
(G_OBJECT_CLASS(wintc_gina_auth_window_parent_class))->finalize(gobject);
}
//
// PUBLIC FUNCTIONS
//
GtkWidget* wintc_gina_auth_window_new(void)
{
return GTK_WIDGET(
g_object_new(
TYPE_WINTC_GINA_AUTH_WINDOW,
"type", GTK_WINDOW_TOPLEVEL,
"resizable", FALSE,
NULL
)
);
}
//
// PRIVATE FUNCTIONS
//
static void wintc_gina_auth_window_change_state(
WinTCGinaAuthWindow* window,
WinTCGinaState next_state
)
{
// Disable current state, if any
//
switch (window->priv->current_state)
{
case WINTC_GINA_STATE_STARTING:
case WINTC_GINA_STATE_LAUNCHING:
wintc_gina_strip_stop_animating(
WINTC_GINA_STRIP(window->priv->strip)
);
gtk_container_remove(
GTK_CONTAINER(window->priv->box_container),
window->priv->box_wait
);
break;
case WINTC_GINA_STATE_PROMPT:
gtk_container_remove(
GTK_CONTAINER(window->priv->box_container),
window->priv->box_login
);
break;
default: break;
}
// Set up new state
//
switch (next_state)
{
case WINTC_GINA_STATE_STARTING:
gtk_box_pack_start(
GTK_BOX(window->priv->box_container),
window->priv->box_wait,
TRUE,
TRUE,
0
);
wintc_gina_strip_animate(
WINTC_GINA_STRIP(window->priv->strip)
);
wintc_gina_logon_session_establish(
window->priv->logon_session
);
g_timeout_add_seconds(
DELAY_SECONDS_AT_LEAST,
on_timeout_delay_done,
window
);
break;
case WINTC_GINA_STATE_PROMPT:
gtk_box_pack_start(
GTK_BOX(window->priv->box_container),
window->priv->box_login,
TRUE,
TRUE,
0
);
break;
case WINTC_GINA_STATE_LAUNCHING:
gtk_box_pack_start(
GTK_BOX(window->priv->box_container),
window->priv->box_wait,
TRUE,
TRUE,
0
);
wintc_gina_strip_animate(
WINTC_GINA_STRIP(window->priv->strip)
);
g_timeout_add_seconds(
DELAY_SECONDS_AT_LEAST,
on_timeout_delay_done,
window
);
break;
default: break;
}
gtk_widget_show_all(
window->priv->box_container
);
window->priv->current_state = next_state;
}
//
// CALLBACKS
//
static void on_self_realized(
GtkWidget* self,
WINTC_UNUSED(gpointer user_data)
)
{
wintc_gina_auth_window_change_state(
WINTC_GINA_AUTH_WINDOW(self),
WINTC_GINA_STATE_STARTING
);
}
static void on_logon_session_attempt_complete(
WINTC_UNUSED(WinTCGinaLogonSession* logon_session),
WinTCGinaResponse response,
gpointer user_data
)
{
WinTCGinaAuthWindow* window = WINTC_GINA_AUTH_WINDOW(user_data);
switch (response)
{
case WINTC_GINA_RESPONSE_OKAY:
wintc_gina_auth_window_change_state(
window,
WINTC_GINA_STATE_LAUNCHING
);
break;
case WINTC_GINA_RESPONSE_FAIL:
// FIXME: Prompt for failure
gtk_entry_set_text(
GTK_ENTRY(window->priv->entry_password),
""
);
gtk_entry_set_text(
GTK_ENTRY(window->priv->entry_username),
""
);
gtk_widget_set_sensitive(
window->priv->button_submit,
TRUE
);
gtk_widget_set_sensitive(
window->priv->entry_password,
TRUE
);
gtk_widget_set_sensitive(
window->priv->entry_username,
TRUE
);
wintc_gina_strip_stop_animating(
WINTC_GINA_STRIP(window->priv->strip)
);
break;
default: break;
}
}
static void on_button_submit_clicked(
WINTC_UNUSED(GtkButton* self),
gpointer user_data
)
{
WinTCGinaAuthWindow* window = WINTC_GINA_AUTH_WINDOW(user_data);
gtk_widget_set_sensitive(
window->priv->button_submit,
FALSE
);
gtk_widget_set_sensitive(
window->priv->entry_password,
FALSE
);
gtk_widget_set_sensitive(
window->priv->entry_username,
FALSE
);
wintc_gina_strip_animate(
WINTC_GINA_STRIP(window->priv->strip)
);
wintc_gina_logon_session_try_logon(
window->priv->logon_session,
gtk_entry_get_text(GTK_ENTRY(window->priv->entry_username)),
gtk_entry_get_text(GTK_ENTRY(window->priv->entry_password))
);
}
static gboolean on_timeout_delay_done(
gpointer user_data
)
{
WinTCGinaAuthWindow* window = WINTC_GINA_AUTH_WINDOW(user_data);
switch (window->priv->current_state)
{
case WINTC_GINA_STATE_STARTING:
g_timeout_add_seconds(
DELAY_SECONDS_POLL,
on_timeout_poll_ready,
window
);
break;
case WINTC_GINA_STATE_LAUNCHING:
wintc_gina_logon_session_finish(
window->priv->logon_session
);
break;
default:
g_critical("%s", "Invalid state reached for delay.");
break;
}
return G_SOURCE_REMOVE;
}
static gboolean on_timeout_poll_ready(
gpointer user_data
)
{
WinTCGinaAuthWindow* window = WINTC_GINA_AUTH_WINDOW(user_data);
if (
wintc_gina_logon_session_is_available(
window->priv->logon_session
)
)
{
wintc_gina_auth_window_change_state(
window,
WINTC_GINA_STATE_PROMPT
);
return G_SOURCE_REMOVE;
}
return G_SOURCE_CONTINUE;
}

View File

@@ -0,0 +1,28 @@
#ifndef __AUTHWND_H__
#define __AUTHWND_H__
#include <glib.h>
#include <gtk/gtk.h>
//
// GTK OOP BOILERPLATE
//
typedef struct _WinTCGinaAuthWindowPrivate WinTCGinaAuthWindowPrivate;
typedef struct _WinTCGinaAuthWindowClass WinTCGinaAuthWindowClass;
typedef struct _WinTCGinaAuthWindow WinTCGinaAuthWindow;
#define TYPE_WINTC_GINA_AUTH_WINDOW (wintc_gina_auth_window_get_type())
#define WINTC_GINA_AUTH_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_WINTC_GINA_AUTH_WINDOW, WinTCGinaAuthWindow))
#define WINTC_GINA_AUTH_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_WINTC_GINA_AUTH_WINDOW, WinTCGinaAuthWindow))
#define IS_WINTC_GINA_AUTH_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_WINTC_GINA_AUTH_WINDOW))
#define IS_WINTC_GINA_AUTH_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_WINTC_GINA_AUTH_WINDOW))
#define WINTC_GINA_WINDOW_GET_CLASS(obj) (G_TYPE_CHECK_INSTANCE_GET_CLASS((obj), TYPE_WINTC_GINA_AUTH_WINDOW))
GType wintc_gina_auth_window_get_type(void) G_GNUC_CONST;
//
// PUBLIC FUNCTIONS
//
GtkWidget* wintc_gina_auth_window_new(void);
#endif

View File

@@ -0,0 +1,10 @@
#ifndef __CHALLENGE_H__
#define __CHALLENGE_H__
typedef enum
{
WINTC_GINA_RESPONSE_OKAY = 0,
WINTC_GINA_RESPONSE_FAIL = 1
} WinTCGinaResponse;
#endif

281
shared/msgina/src/logon.c Normal file
View File

@@ -0,0 +1,281 @@
#include <glib.h>
#include <lightdm.h>
#include <wintc-comgtk.h>
#include "challenge.h"
#include "logon.h"
//
// PRIVATE ENUMS
//
enum
{
SIGNAL_ATTEMPT_COMPLETE = 0,
N_SIGNALS
};
//
// STATIC DATA
//
static gint wintc_gina_logon_session_signals[N_SIGNALS] = { 0 };
//
// GLIB OOP CLASS/INSTANCE DEFINITIONS
//
struct _WinTCGinaLogonSessionClass
{
GObjectClass __parent__;
};
struct _WinTCGinaLogonSession
{
GObject __parent__;
gboolean auth_complete;
gboolean auth_ready;
LightDMGreeter* greeter;
gchar* response_pwd;
};
//
// FORWARD DECLARATIONS
//
static void on_greeter_authentication_complete(
LightDMGreeter* greeter,
gpointer user_data
);
static void on_greeter_show_prompt(
LightDMGreeter* greeter,
gchar* text,
WINTC_UNUSED(LightDMPromptType type),
gpointer user_data
);
//
// GLIB TYPE DEFINITIONS & CTORS
//
G_DEFINE_TYPE(
WinTCGinaLogonSession,
wintc_gina_logon_session,
G_TYPE_OBJECT
)
static void wintc_gina_logon_session_class_init(
WinTCGinaLogonSessionClass* klass
)
{
GObjectClass* object_class = G_OBJECT_CLASS(klass);
wintc_gina_logon_session_signals[SIGNAL_ATTEMPT_COMPLETE] =
g_signal_new(
"attempt-complete",
G_TYPE_FROM_CLASS(object_class),
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
g_cclosure_marshal_VOID__INT,
G_TYPE_NONE,
1,
G_TYPE_INT
);
}
static void wintc_gina_logon_session_init(
WinTCGinaLogonSession* self
)
{
self->auth_ready = FALSE;
self->greeter = NULL;
}
//
// PUBLIC FUNCTIONS
//
WinTCGinaLogonSession* wintc_gina_logon_session_new()
{
return WINTC_GINA_LOGON_SESSION(
g_object_new(
TYPE_WINTC_GINA_LOGON_SESSION,
NULL
)
);
}
gboolean wintc_gina_logon_session_establish(
WinTCGinaLogonSession* logon_session
)
{
WINTC_LOG_DEBUG("GINA - establish()");
if (!logon_session->greeter)
{
WINTC_LOG_DEBUG("GINA - new lightdm greeter");
logon_session->greeter = lightdm_greeter_new();
g_signal_connect(
logon_session->greeter,
"authentication-complete",
G_CALLBACK(on_greeter_authentication_complete),
logon_session
);
g_signal_connect(
logon_session->greeter,
"show-prompt",
G_CALLBACK(on_greeter_show_prompt),
logon_session
);
}
WINTC_LOG_DEBUG("GINA - lightdm connect sync");
if (
!lightdm_greeter_connect_to_daemon_sync(
logon_session->greeter,
NULL
)
)
{
g_critical("%s", "Failed to connect to LightDM daemon.");
return FALSE;
}
// FIXME: Error handling
//
lightdm_greeter_authenticate(
logon_session->greeter,
NULL,
NULL
);
return TRUE;
}
void wintc_gina_logon_session_finish(
WinTCGinaLogonSession* logon_session
)
{
WINTC_LOG_DEBUG("GINA - finish requested");
if (!logon_session->auth_complete)
{
g_warning("%s", "Attempt to complete incomplete logon.");
return;
}
// FIXME: Error handling required
// FIXME: If this fails, we need to restart auth! The UI
// does not handle this either
//
lightdm_greeter_start_session_sync(
logon_session->greeter,
NULL,
NULL
);
}
gboolean wintc_gina_logon_session_is_available(
WinTCGinaLogonSession* logon_session
)
{
WINTC_LOG_DEBUG("GINA - polled");
return logon_session->auth_ready;
}
void wintc_gina_logon_session_try_logon(
WinTCGinaLogonSession* logon_session,
const gchar* username,
const gchar* password
)
{
WINTC_LOG_DEBUG("GINA - logon attempt requested");
if (logon_session->auth_complete)
{
g_warning("%s", "Attempt to logon a second time.");
return;
}
logon_session->response_pwd = g_strdup(password);
// FIXME: Error handling
//
lightdm_greeter_respond(
logon_session->greeter,
username,
NULL
);
}
//
// CALLBACKS
//
static void on_greeter_authentication_complete(
LightDMGreeter* greeter,
gpointer user_data
)
{
WinTCGinaLogonSession* logon_session =
WINTC_GINA_LOGON_SESSION(user_data);
WINTC_LOG_DEBUG("GINA - lightdm auth complete");
logon_session->auth_complete =
lightdm_greeter_get_is_authenticated(greeter);
g_signal_emit(
logon_session,
wintc_gina_logon_session_signals[SIGNAL_ATTEMPT_COMPLETE],
0,
logon_session->auth_complete ?
WINTC_GINA_RESPONSE_OKAY :
WINTC_GINA_RESPONSE_FAIL
);
// If the auth failed, have to restart
//
if (!logon_session->auth_complete)
{
// FIXME: Error handling
//
lightdm_greeter_authenticate(greeter, NULL, NULL);
}
}
static void on_greeter_show_prompt(
LightDMGreeter* greeter,
gchar* text,
WINTC_UNUSED(LightDMPromptType type),
gpointer user_data
)
{
WinTCGinaLogonSession* logon_session =
WINTC_GINA_LOGON_SESSION(user_data);
WINTC_LOG_DEBUG("GINA - lightdm prompt: %s", text);
if (g_strcmp0(text, "login:") == 0)
{
logon_session->auth_ready = TRUE;
}
else if (g_strcmp0(text, "Password: ") == 0)
{
// FIXME: Error handling
//
lightdm_greeter_respond(
greeter,
logon_session->response_pwd,
NULL
);
g_free(logon_session->response_pwd);
logon_session->response_pwd = NULL;
}
else
{
g_critical("Unknown prompt: %s", text);
}
}

41
shared/msgina/src/logon.h Normal file
View File

@@ -0,0 +1,41 @@
#ifndef __LOGON_H__
#define __LOGON_H__
#include <glib.h>
//
// GLIB BOILERPLATE
//
typedef struct _WinTCGinaLogonSessionClass WinTCGinaLogonSessionClass;
typedef struct _WinTCGinaLogonSession WinTCGinaLogonSession;
#define TYPE_WINTC_GINA_LOGON_SESSION (wintc_gina_logon_session_get_type())
#define WINTC_GINA_LOGON_SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_WINTC_GINA_LOGON_SESSION, WinTCGinaLogonSession))
#define WINTC_GINA_LOGON_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_WINTC_GINA_LOGON_SESSION, WinTCGinaLogonSession))
#define IS_WINTC_GINA_LOGON_SESSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_WINTC_GINA_LOGON_SESSION))
#define IS_WINTC_GINA_LOGON_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_WINTC_GINA_LOGON_SESSION))
#define WINTC_GINA_LOGON_SESSION_GET_CLASS(obj) (G_TYPE_CHECK_INSTANCE_GET_CLASS((obj), TYPE_WINTC_GINA_LOGON_SESSION)
GType wintc_gina_logon_session_get_type(void) G_GNUC_CONST;
//
// PUBLIC FUNCTIONS
//
WinTCGinaLogonSession* wintc_gina_logon_session_new(void);
gboolean wintc_gina_logon_session_establish(
WinTCGinaLogonSession* logon_session
);
void wintc_gina_logon_session_finish(
WinTCGinaLogonSession* logon_session
);
gboolean wintc_gina_logon_session_is_available(
WinTCGinaLogonSession* logon_session
);
void wintc_gina_logon_session_try_logon(
WinTCGinaLogonSession* logon_session,
const gchar* username,
const gchar* password
);
#endif

View File

@@ -0,0 +1,20 @@
box.please-wait
{
margin: 15px 0px;
margin-left: 8px;
}
grid
{
margin: 15px 0px;
}
grid *
{
margin: 3px 10px 4px;
}
grid entry
{
min-width: 240px;
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/uk/oddmatics/wintc/msgina">
<file>authwnd.css</file>
</gresource>
</gresources>

12
shared/msgina/src/state.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef __STATE_H__
#define __STATE_H__
typedef enum
{
WINTC_GINA_STATE_NONE = 0,
WINTC_GINA_STATE_STARTING,
WINTC_GINA_STATE_PROMPT,
WINTC_GINA_STATE_LAUNCHING
} WinTCGinaState;
#endif

View File

@@ -0,0 +1,316 @@
#include <gdk/gdk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <wintc-comgtk.h>
#include <wintc-winbrand.h>
#include "stripctl.h"
#define ONE_SECOND_IN_US 1000000
#define ANIM_RATE_SECONDS 2
#define ANIM_RATE_IN_US (ANIM_RATE_SECONDS * ONE_SECOND_IN_US)
//
// GTK OOP CLASS/INSTANCE DEFINITIONS
//
struct _WinTCGinaStripPrivate
{
GdkPixbuf* pixbuf_strip;
cairo_surface_t* surface_strip;
gboolean is_animating;
gint64 origin_time;
};
struct _WinTCGinaStripClass
{
GtkWidgetClass __parent__;
};
struct _WinTCGinaStrip
{
GtkWidget __parent__;
WinTCGinaStripPrivate* priv;
};
//
// FORWARD DECLARATIONS
//
static void wintc_gina_strip_finalize(
GObject* gobject
);
static gboolean wintc_gina_strip_draw(
GtkWidget* widget,
cairo_t* cr
);
static void wintc_gina_strip_get_preferred_height(
GtkWidget* widget,
gint* minimum_height,
gint* natural_height
);
static void wintc_gina_strip_get_preferred_height_for_width(
GtkWidget* widget,
gint width,
gint* minimum_height,
gint* natural_height
);
static void wintc_gina_strip_get_preferred_width(
GtkWidget* widget,
gint* minimum_width,
gint* natural_width
);
static void wintc_gina_strip_get_preferred_width_for_height(
GtkWidget* widget,
gint height,
gint* minimum_width,
gint* natural_width
);
static gboolean wintc_gina_strip_step(
GtkWidget* widget,
GdkFrameClock* frame_clock,
gpointer user_data
);
//
// GTK TYPE DEFINITIONS & CTORS
//
G_DEFINE_TYPE_WITH_CODE(
WinTCGinaStrip,
wintc_gina_strip,
GTK_TYPE_WIDGET,
G_ADD_PRIVATE(WinTCGinaStrip)
)
static void wintc_gina_strip_class_init(
WinTCGinaStripClass* klass
)
{
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
GObjectClass* object_class = G_OBJECT_CLASS(klass);
object_class->finalize = wintc_gina_strip_finalize;
widget_class->draw =
wintc_gina_strip_draw;
widget_class->get_preferred_height =
wintc_gina_strip_get_preferred_height;
widget_class->get_preferred_height_for_width =
wintc_gina_strip_get_preferred_height_for_width;
widget_class->get_preferred_width =
wintc_gina_strip_get_preferred_width;
widget_class->get_preferred_width_for_height =
wintc_gina_strip_get_preferred_width_for_height;
}
static void wintc_gina_strip_init(
WinTCGinaStrip* self
)
{
self->priv = wintc_gina_strip_get_instance_private(self);
gtk_widget_set_has_window(GTK_WIDGET(self), FALSE);
// Load assets
//
GError* error = NULL;
self->priv->pixbuf_strip =
wintc_brand_get_brand_pixmap(
WINTC_BRAND_PART_STRIP_ANIM,
&error
);
// FIXME: Handle error
self->priv->surface_strip =
gdk_cairo_surface_create_from_pixbuf(
self->priv->pixbuf_strip,
1,
NULL // FIXME: Error reporting
);
}
//
// CLASS VIRTUAL METHODS
//
static void wintc_gina_strip_finalize(
GObject* gobject
)
{
WinTCGinaStrip* strip = WINTC_GINA_STRIP(gobject);
cairo_surface_destroy(strip->priv->surface_strip);
g_clear_object(&(strip->priv->pixbuf_strip));
(G_OBJECT_CLASS(wintc_gina_strip_parent_class))->finalize(gobject);
}
static gboolean wintc_gina_strip_draw(
GtkWidget* widget,
cairo_t* cr
)
{
WinTCGinaStrip* strip = WINTC_GINA_STRIP(widget);
gdouble x_offset = 0.0f;
// If animating, work out offset of strip based
// on time
//
if (strip->priv->is_animating)
{
gint64 current_time = g_get_monotonic_time();
gint64 delta = strip->priv->origin_time - current_time;
gint64 mod_time = delta % ANIM_RATE_IN_US;
gdouble within_pct = (gdouble) mod_time / ANIM_RATE_IN_US;
gint img_width =
cairo_image_surface_get_width(
strip->priv->surface_strip
);
x_offset = (gint) (img_width * within_pct);
}
// Paint now
//
cairo_set_source_surface(
cr,
strip->priv->surface_strip,
x_offset,
0.0f
);
cairo_pattern_set_extend(
cairo_get_source(cr),
CAIRO_EXTEND_REPEAT
);
cairo_paint(cr);
return FALSE;
}
static void wintc_gina_strip_get_preferred_height(
GtkWidget* widget,
gint* minimum_height,
gint* natural_height
)
{
gint height;
WinTCGinaStrip* strip = WINTC_GINA_STRIP(widget);
height =
cairo_image_surface_get_height(
strip->priv->surface_strip
);
*minimum_height = height;
*natural_height = height;
}
static void wintc_gina_strip_get_preferred_height_for_width(
GtkWidget* widget,
WINTC_UNUSED(gint width),
gint* minimum_height,
gint* natural_height
)
{
wintc_gina_strip_get_preferred_height(
widget,
minimum_height,
natural_height
);
}
static void wintc_gina_strip_get_preferred_width(
GtkWidget* widget,
gint* minimum_width,
gint* natural_width
)
{
WinTCGinaStrip* strip = WINTC_GINA_STRIP(widget);
gint width;
width =
cairo_image_surface_get_width(
strip->priv->surface_strip
);
*minimum_width = width;
*natural_width = width;
}
static void wintc_gina_strip_get_preferred_width_for_height(
GtkWidget* widget,
WINTC_UNUSED(gint height),
gint* minimum_width,
gint* natural_width
)
{
wintc_gina_strip_get_preferred_width(
widget,
minimum_width,
natural_width
);
}
//
// PUBLIC FUNCTIONS
//
GtkWidget* wintc_gina_strip_new(void)
{
return GTK_WIDGET(
g_object_new(
TYPE_WINTC_GINA_STRIP,
NULL
)
);
}
void wintc_gina_strip_animate(
WinTCGinaStrip* strip
)
{
if (strip->priv->is_animating)
{
return;
}
strip->priv->is_animating = TRUE;
strip->priv->origin_time = g_get_monotonic_time();
gtk_widget_add_tick_callback(
GTK_WIDGET(strip),
(GtkTickCallback) wintc_gina_strip_step,
NULL,
NULL
);
}
void wintc_gina_strip_stop_animating(
WinTCGinaStrip* strip
)
{
strip->priv->is_animating = FALSE;
}
//
// CALLBACKS
//
static gboolean wintc_gina_strip_step(
GtkWidget* widget,
WINTC_UNUSED(GdkFrameClock* frame_clock),
WINTC_UNUSED(gpointer user_data)
)
{
WinTCGinaStrip* strip = WINTC_GINA_STRIP(widget);
gtk_widget_queue_draw(widget);
return strip->priv->is_animating ?
G_SOURCE_CONTINUE : G_SOURCE_REMOVE;
}

View File

@@ -0,0 +1,32 @@
#ifndef __STRIPCTL_H__
#define __STRIPCTL_H__
//
// GTK OOP BOILERPLATE
//
typedef struct _WinTCGinaStripPrivate WinTCGinaStripPrivate;
typedef struct _WinTCGinaStripClass WinTCGinaStripClass;
typedef struct _WinTCGinaStrip WinTCGinaStrip;
#define TYPE_WINTC_GINA_STRIP (wintc_gina_strip_get_type())
#define WINTC_GINA_STRIP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_WINTC_GINA_STRIP, WinTCGinaStrip))
#define WINTC_GINA_STRIP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_WINTC_GINA_STRIP, WinTCGinaStrip))
#define IS_WINTC_GINA_STRIP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_WINTC_GINA_STRIP))
#define IS_WINTC_GINA_STRIP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_WINTC_GINA_STRIP))
#define WINTC_GINA_STRIP_GET_CLASS(obj) (G_TYPE_CHECK_INSTANCE_GET_CLASS((obj), TYPE_WINTC_GINA_STRIP))
GType wintc_gina_strip_get_type(void) G_GNUC_CONST;
//
// PUBLIC FUNCTIONS
//
GtkWidget* wintc_gina_strip_new(void);
void wintc_gina_strip_animate(
WinTCGinaStrip* strip
);
void wintc_gina_strip_stop_animating(
WinTCGinaStrip* strip
);
#endif

View File

@@ -108,7 +108,8 @@ gboolean init_dll_wnck()
p_wnck_window_get_mini_icon == NULL ||
p_wnck_window_get_name == NULL ||
p_wnck_window_is_skip_tasklist == NULL ||
p_wnck_window_minimize == NULL
p_wnck_window_minimize == NULL ||
p_wnck_window_unminimize == NULL
)
{
g_warning("%s", "libwnck loaded, but not all symbols.");

View File

@@ -20,6 +20,8 @@ include(../../packaging/cmake-inc/libraries/CMakeLists.txt)
include(../../packaging/cmake-inc/linking/CMakeLists.txt)
include(../../packaging/cmake-inc/packaging/CMakeLists.txt)
set(WINTC_BRAND_DIR ${WINTC_ASSETS_INSTALL_DIR}/brand)
wintc_resolve_library(gdk-pixbuf-2.0 GDK_PIXBUF)
wintc_resolve_library(glib-2.0 GLIB)
@@ -65,64 +67,50 @@ target_link_libraries(
# Pick banner based on SKU
#
if (${WINTC_SKU} MATCHES "^xpclient-(.+)")
if (${CMAKE_MATCH_1} STREQUAL "pro")
if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64")
set(WINBRAND_BANNER_NAME x64pro)
elseif (
${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ia64" OR
${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv8"
)
set(WINBRAND_BANNER_NAME 64bit)
else()
set(WINBRAND_BANNER_NAME pro)
endif()
else()
set(WINBRAND_BANNER_NAME ${CMAKE_MATCH_1})
endif()
elseif (${WINTC_SKU} MATCHES "^dnsrv-(.+)")
if (
${CMAKE_MATCH_1} STREQUAL "sbs" OR
${CMAKE_MATCH_1} STREQUAL "web" OR
${CMAKE_MATCH_1} STREQUAL "ccs" OR
NOT ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64"
)
set(WINBRAND_BANNER_NAME srv2k3${CMAKE_MATCH_1})
else()
set(WINBRAND_BANNER_NAME x64srv2k3${CMAKE_MATCH_1})
endif()
elseif (${WINTC_SKU} MATCHES "^dnsrv_r2-(.+)")
set(WINBRAND_BANNER_NAME ${WINTC_SKU})
if (${WINTC_SKU} STREQUAL "xpclient-pro")
if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64")
set(WINBRAND_BANNER_NAME x64srv2k3r2${CMAKE_MATCH_1})
else()
set(WINBRAND_BANNER_NAME srv2k3r2${CMAKE_MATCH_1})
endif()
elseif (${WINTC_SKU} STREQUAL "homesrv")
set(WINBRAND_BANNER_NAME homesrv)
else()
message(
FATAL_ERROR
"No banner defined for SKU: ${WINTC_SKU}"
set(WINBRAND_BANNER_NAME ${WINTC_SKU}_amd64)
elseif (
${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ia64" OR
${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv8"
)
set(WINBRAND_BANNER_NAME ${WINTC_SKU}_ia64)
endif()
elseif (${WINTC_SKU} MATCHES "^dnsrv(_r2)?-(.+)")
if (${CMAKE_MATCH_2} MATCHES "(dtc|ent|std)")
set(WINBRAND_BANNER_NAME ${WINTC_SKU}_amd64)
endif()
endif()
# Installation
#
wintc_configure_and_install_packaging()
wintc_add_pkgconfig_install()
install(
FILES res/banner-${WINBRAND_BANNER_NAME}.png
DESTINATION ${WINTC_ASSETS_INSTALL_DIR}/brand
FILES res/banner/${WINBRAND_BANNER_NAME}.png
DESTINATION ${WINTC_BRAND_DIR}
RENAME banner.png
)
install(
FILES res/strip-xp.png
DESTINATION ${WINTC_ASSETS_INSTALL_DIR}/brand
RENAME strip.png
FILES res/bannerx/${WINBRAND_BANNER_NAME}.png
DESTINATION ${WINTC_BRAND_DIR}
RENAME bannerx.png
)
install(
FILES res/strip-static.png
DESTINATION ${WINTC_BRAND_DIR}
)
install(
FILES res/strip-anim.png
DESTINATION ${WINTC_BRAND_DIR}
)
install(
TARGETS libwintc-winbrand
LIBRARY DESTINATION ${LIB_DIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
)

View File

@@ -7,12 +7,17 @@
//
// Branding banners
//
GdkPixbuf* wintc_brand_get_banner(
GError** error
);
typedef enum
{
WINTC_BRAND_PART_BANNER = 0,
WINTC_BRAND_PART_BANNER_TALL,
WINTC_BRAND_PART_STRIP_STATIC = 10,
WINTC_BRAND_PART_STRIP_ANIM
} WinTCBrandPart;
GdkPixbuf* wintc_brand_get_progress_strip(
GError** error
GdkPixbuf* wintc_brand_get_brand_pixmap(
WinTCBrandPart part,
GError** error
);
#endif

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Some files were not shown because too many files have changed in this diff Show More