Browse Source

replace theme heartbeat as the implementation was flawed. instead check window object for existence of required theme functions and give user option to switch themes if check fails.

sisyphus
Dustin Falgout 8 years ago
parent
commit
cc41cee218
  1. 147
      src/greeter.c
  2. 5
      src/gresource/css/style.css
  3. 82
      src/gresource/js/ThemeHeartbeat.js
  4. 2
      src/gresource/js/ThemeUtils.js

147
src/greeter.c

@ -69,17 +69,12 @@ static int
static gint config_timeout; static gint config_timeout;
static gboolean static gboolean debug_mode;
debug_mode,
heartbeat,
heartbeat_exit;
static void static void
initialize_web_extensions_cb(WebKitWebContext *context, gpointer user_data) { initialize_web_extensions_cb(WebKitWebContext *context, gpointer user_data) {
webkit_web_context_set_web_extensions_directory(context, WEBEXT_DIR); webkit_web_context_set_web_extensions_directory(context, WEBEXT_DIR);
} }
@ -104,7 +99,6 @@ context_menu_cb(WebKitWebView *view,
GdkEvent *event, GdkEvent *event,
WebKitHitTestResult *hit_test_result, WebKitHitTestResult *hit_test_result,
gpointer user_data) { gpointer user_data) {
/* Returning true without creating a custom context menu results in no context /* Returning true without creating a custom context menu results in no context
* menu being shown. Thus, we are returning the opposite of debug_mode to get * menu being shown. Thus, we are returning the opposite of debug_mode to get
* desired result (which is only show menu when debug_mode is enabled. * desired result (which is only show menu when debug_mode is enabled.
@ -113,50 +107,6 @@ context_menu_cb(WebKitWebView *view,
} }
static gboolean
check_theme_heartbeat(void) {
if (! heartbeat && ! heartbeat_exit) {
/* Theme heartbeat not received. We assume that an error has occurred
* which broke script execution. We will fallback to the simple theme
* so the user won't be stuck with a broken login screen.
*/
g_warning("[ERROR] :: A problem was detected with the current theme. Falling back to simple theme...");
webkit_web_view_load_uri(
WEBKIT_WEB_VIEW(web_view),
g_strdup_printf("file://%ssimple/index.html", THEME_DIR)
);
}
heartbeat = FALSE;
return heartbeat;
}
/**
* Callback for Theme Heartbeat.
*/
static void
theme_heartbeat_handler(void) {
if (! heartbeat) {
/* Setup g_timeout callback for theme heartbeat check */
g_timeout_add_seconds(8, (GSourceFunc) check_theme_heartbeat, NULL);
heartbeat = TRUE;
heartbeat_exit = FALSE;
}
}
/**
* Before starting the user's session, the web process will send a signal to exit the hearbeat
* in order to prevent a race condition while the greeter is shutting down.
*/
static void
theme_heartbeat_exit_handler(void) {
heartbeat_exit = TRUE;
}
/** /**
* Makes the greeter behave a bit more like a screensaver if it was launched as * Makes the greeter behave a bit more like a screensaver if it was launched as
* a lock-screen by blanking the screen. * a lock-screen by blanking the screen.
@ -210,17 +160,11 @@ message_received_cb(WebKitUserContentManager *manager,
if (strcmp(message_str, "LockHint") == 0) { if (strcmp(message_str, "LockHint") == 0) {
lock_hint_enabled_handler(); lock_hint_enabled_handler();
} else if (strcmp(message_str, "Heartbeat") == 0) {
theme_heartbeat_handler();
} else if (strcmp(message_str, "Heartbeat::Exit") == 0) {
theme_heartbeat_exit_handler();
} else { } else {
printf("UI PROCESS - message_received_cb(): no match!"); printf("UI PROCESS - message_received_cb(): no match!");
} }
g_free(message_str); g_free(message_str);
} }
@ -275,6 +219,89 @@ javascript_bundle_injection_setup() {
} }
static void
theme_function_exists_cb(GObject *object,
GAsyncResult *result,
gpointer user_data) {
WebKitJavascriptResult *js_result;
GError *error = NULL;
JSValueRef value;
JSGlobalContextRef context;
gboolean result_as_bool;
js_result = webkit_web_view_run_javascript_finish(WEBKIT_WEB_VIEW(object), result, &error);
if (NULL != error) {
g_warning ("Error running javascript: %s", error->message);
g_error_free(error);
return;
} else {
context = webkit_javascript_result_get_global_context(js_result);
value = webkit_javascript_result_get_value(js_result);
result_as_bool = JSValueToBoolean(context, value);
}
if (FALSE == result_as_bool) {
GtkWidget *dialog, *label, *content_area, *button, *button_box;
dialog = gtk_dialog_new_with_buttons(
_("Greeter Theme Error Detected"),
GTK_WINDOW(window),
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
_("_Load Default Theme"),
GTK_RESPONSE_ACCEPT,
_("_Load Fallback Theme"),
GTK_RESPONSE_OK,
_("_Cancel"),
GTK_RESPONSE_REJECT,
NULL
);
content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
button = gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), GTK_RESPONSE_REJECT);
button_box = gtk_widget_get_parent(button);
label = gtk_label_new(_("An error was detected in the current theme that could interfere with the system login process."));
gtk_button_box_set_layout(GTK_BUTTON_BOX(button_box), GTK_BUTTONBOX_EXPAND);
gtk_container_add(GTK_CONTAINER(content_area), label);
gtk_widget_show_all(content_area);
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
gchar *log_msg = "[ERROR] :: A problem was detected with the current theme. Falling back to simple theme...";
if (GTK_RESPONSE_ACCEPT == response) {
g_warning(log_msg);
webkit_web_view_load_uri(WEBKIT_WEB_VIEW(web_view), g_strdup_printf("file://%s/antergos/index.html", THEME_DIR));
} else if (GTK_RESPONSE_OK == response) {
g_warning(log_msg);
webkit_web_view_load_uri(WEBKIT_WEB_VIEW(web_view), g_strdup_printf("file://%s/simple/index.html", THEME_DIR));
}
gtk_widget_destroy(dialog);
}
webkit_javascript_result_unref(js_result);
}
gboolean
maybe_show_theme_fallback_dialog(void) {
/* Check for existence of a function that themes must add to window object */
webkit_web_view_run_javascript(
WEBKIT_WEB_VIEW(web_view),
"(() => 'authentication_complete' in window)()",
NULL,
(GAsyncReadyCallback) theme_function_exists_cb,
NULL
);
return FALSE;
}
int int
main(int argc, char **argv) { main(int argc, char **argv) {
GdkScreen *screen; GdkScreen *screen;
@ -355,9 +382,6 @@ main(int argc, char **argv) {
gdk_window_set_cursor(root_window, gdk_cursor_new_for_display(default_display, GDK_LEFT_PTR)); gdk_window_set_cursor(root_window, gdk_cursor_new_for_display(default_display, GDK_LEFT_PTR));
/* Set the GTK theme to Adwaita */
g_object_set(gtk_settings_get_default(), "gtk-theme-name", "Adwaita", NULL);
/* Setup the main window */ /* Setup the main window */
window = gtk_window_new(GTK_WINDOW_TOPLEVEL); window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
screen = gtk_window_get_screen(GTK_WINDOW(window)); screen = gtk_window_get_screen(GTK_WINDOW(window));
@ -426,6 +450,9 @@ main(int argc, char **argv) {
/* Maybe disable the context (right-click) menu. */ /* Maybe disable the context (right-click) menu. */
g_signal_connect(WEBKIT_WEB_VIEW(web_view), "context-menu", G_CALLBACK(context_menu_cb), NULL); g_signal_connect(WEBKIT_WEB_VIEW(web_view), "context-menu", G_CALLBACK(context_menu_cb), NULL);
/* Register callback to check if theme loaded successfully */
g_timeout_add_seconds(5, (GSourceFunc) maybe_show_theme_fallback_dialog, NULL);
/* There's no turning back now, let's go! */ /* There's no turning back now, let's go! */
gtk_container_add(GTK_CONTAINER(window), web_view); gtk_container_add(GTK_CONTAINER(window), web_view);
webkit_web_view_load_uri(WEBKIT_WEB_VIEW(web_view), webkit_web_view_load_uri(WEBKIT_WEB_VIEW(web_view),

5
src/gresource/css/style.css

@ -2,3 +2,8 @@ window,
GtkWindow { GtkWindow {
background: #000000; background: #000000;
} }
dialog .dialog-vbox > label,
GtkDialog .dialog-vbox > GtkLabel {
margin: 20px 15px;
}

82
src/gresource/js/ThemeHeartbeat.js

@ -1,82 +0,0 @@
/*
* ThemeHeartbeat.js
*
* Copyright © 2016 Antergos Developers <dev@antergos.com>
*
* This file is part of lightdm-webkit2-greeter.
*
* lightdm-webkit2-greeter is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* lightdm-webkit2-greeter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* The following additional terms are in effect as per Section 7 of the license:
*
* The preservation of all legal notices and author attributions in
* the material or in the Appropriate Legal Notices displayed
* by works containing it is required.
*
* You should have received a copy of the GNU General Public License
* along with lightdm-webkit2-greeter; If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Singleton class for the greeter theme heartbeat.
*
* Once instantiated, the instance will begin sending a heartbeat message to the greeter
* every 5 seconds. Upon receiving the first heartbeat message, the greeter will schedule checks
* to ensure that subsequent heartbeat messages are received.
*
* If a heartbeat message is not received by the time any of the greeter's
* subsequent checks run, it will assume that there has been an error in the theme's script
* execution and fall back to the simple theme.
*/
class ThemeHeartbeat {
constructor() {
if ( '__heartbeat' in window ) {
return __heartbeat;
}
window.__heartbeat = theme_utils.bind_this(this);
this.heartbeat = '';
this.heartbeats = 0;
this.initialize_theme_heartbeat();
return window.__heartbeat;
}
initialize_theme_heartbeat() {
if ( '' !== this.heartbeat ) {
console.log( 'Heartbeat has already been initialized!' );
return;
}
console.log('Initializing theme heartbeat.');
this.send_heartbeat();
this.heartbeat = setInterval(this.send_heartbeat, 5000);
}
send_heartbeat() {
++this.heartbeats;
if ( true === lightdm.session_starting ) {
clearInterval( this.heartbeat );
return;
}
if ( this.heartbeats < 2 ) {
console.log('Sending heartbeat...');
}
window.webkit.messageHandlers.GreeterBridge.postMessage('Heartbeat');
}
}

2
src/gresource/js/ThemeUtils.js

@ -227,8 +227,6 @@ const __theme_utils = new Promise( (resolve, reject) => {
__theme_utils.then( result => { __theme_utils.then( result => {
window.theme_utils = result; window.theme_utils = result;
new ThemeHeartbeat();
/** /**
* @deprecated * @deprecated
* @type {LightDM.ThemeUtils} * @type {LightDM.ThemeUtils}

Loading…
Cancel
Save