diff --git a/src/lightdm-webkit2-greeter-ext.c b/src/lightdm-webkit2-greeter-ext.c index 47524a6..54af08e 100644 --- a/src/lightdm-webkit2-greeter-ext.c +++ b/src/lightdm-webkit2-greeter-ext.c @@ -35,8 +35,7 @@ #include #include -#define WEBKIT_DOM_USE_UNSTABLE_API -#include +#include #include #include @@ -53,6 +52,7 @@ static JSClassRef lightdm_layout_class, lightdm_session_class; + static JSValueRef get_user_name_cb(JSContextRef context, JSObjectRef thisObject, @@ -65,6 +65,7 @@ get_user_name_cb(JSContextRef context, return JSValueMakeString(context, string); } + static JSValueRef get_user_real_name_cb(JSContextRef context, JSObjectRef thisObject, @@ -77,6 +78,7 @@ get_user_real_name_cb(JSContextRef context, return JSValueMakeString(context, string); } + static JSValueRef get_user_display_name_cb(JSContextRef context, JSObjectRef thisObject, @@ -89,6 +91,7 @@ get_user_display_name_cb(JSContextRef context, return JSValueMakeString(context, string); } + static JSValueRef get_user_image_cb(JSContextRef context, JSObjectRef thisObject, @@ -101,6 +104,7 @@ get_user_image_cb(JSContextRef context, return JSValueMakeString(context, string); } + static JSValueRef get_user_language_cb(JSContextRef context, JSObjectRef thisObject, @@ -118,6 +122,7 @@ get_user_language_cb(JSContextRef context, return JSValueMakeString(context, string); } + static JSValueRef get_user_layout_cb(JSContextRef context, JSObjectRef thisObject, @@ -135,6 +140,7 @@ get_user_layout_cb(JSContextRef context, return JSValueMakeString(context, string); } + static JSValueRef get_user_session_cb(JSContextRef context, JSObjectRef thisObject, @@ -152,6 +158,7 @@ get_user_session_cb(JSContextRef context, return JSValueMakeString(context, string); } + static JSValueRef get_user_logged_in_cb(JSContextRef context, JSObjectRef thisObject, @@ -161,6 +168,7 @@ get_user_logged_in_cb(JSContextRef context, return JSValueMakeBoolean(context, lightdm_user_get_logged_in(user)); } + static JSValueRef get_language_code_cb(JSContextRef context, JSObjectRef thisObject, @@ -173,6 +181,7 @@ get_language_code_cb(JSContextRef context, return JSValueMakeString(context, string); } + static JSValueRef get_language_name_cb(JSContextRef context, JSObjectRef thisObject, @@ -185,6 +194,7 @@ get_language_name_cb(JSContextRef context, return JSValueMakeString(context, string); } + static JSValueRef get_language_territory_cb(JSContextRef context, JSObjectRef thisObject, @@ -197,6 +207,7 @@ get_language_territory_cb(JSContextRef context, return JSValueMakeString(context, string); } + static JSValueRef get_layout_name_cb(JSContextRef context, JSObjectRef thisObject, @@ -209,6 +220,7 @@ get_layout_name_cb(JSContextRef context, return JSValueMakeString(context, string); } + static JSValueRef get_layout_short_description_cb(JSContextRef context, JSObjectRef thisObject, @@ -221,6 +233,7 @@ get_layout_short_description_cb(JSContextRef context, return JSValueMakeString(context, string); } + static JSValueRef get_layout_description_cb(JSContextRef context, JSObjectRef thisObject, @@ -233,6 +246,7 @@ get_layout_description_cb(JSContextRef context, return JSValueMakeString(context, string); } + static JSValueRef get_session_key_cb(JSContextRef context, JSObjectRef thisObject, @@ -246,6 +260,7 @@ get_session_key_cb(JSContextRef context, } + static JSValueRef get_session_name_cb(JSContextRef context, JSObjectRef thisObject, @@ -258,6 +273,7 @@ get_session_name_cb(JSContextRef context, return JSValueMakeString(context, string); } + static JSValueRef get_session_comment_cb(JSContextRef context, JSObjectRef thisObject, @@ -270,6 +286,7 @@ get_session_comment_cb(JSContextRef context, return JSValueMakeString(context, string); } + static JSValueRef get_hostname_cb(JSContextRef context, JSObjectRef thisObject, @@ -282,6 +299,7 @@ get_hostname_cb(JSContextRef context, return JSValueMakeString(context, string); } + static JSValueRef get_num_users_cb(JSContextRef context, JSObjectRef thisObject, @@ -293,6 +311,7 @@ get_num_users_cb(JSContextRef context, return JSValueMakeNumber(context, num_users); } + static JSValueRef get_users_cb(JSContextRef context, JSObjectRef thisObject, @@ -317,6 +336,7 @@ get_users_cb(JSContextRef context, return array; } + static JSValueRef get_languages_cb(JSContextRef context, JSObjectRef thisObject, @@ -341,6 +361,7 @@ get_languages_cb(JSContextRef context, return array; } + static JSValueRef get_default_language_cb(JSContextRef context, JSObjectRef thisObject, @@ -353,6 +374,7 @@ get_default_language_cb(JSContextRef context, return JSValueMakeString(context, string); } + static JSValueRef get_default_layout_cb(JSContextRef context, JSObjectRef thisObject, @@ -365,6 +387,7 @@ get_default_layout_cb(JSContextRef context, return JSValueMakeString(context, string); } + static JSValueRef get_layouts_cb(JSContextRef context, JSObjectRef thisObject, @@ -390,6 +413,7 @@ get_layouts_cb(JSContextRef context, return array; } + static JSValueRef get_layout_cb(JSContextRef context, JSObjectRef thisObject, @@ -403,6 +427,7 @@ get_layout_cb(JSContextRef context, return JSValueMakeString(context, string); } + static bool set_layout_cb(JSContextRef context, JSObjectRef thisObject, @@ -426,6 +451,7 @@ set_layout_cb(JSContextRef context, return true; } + static JSValueRef get_sessions_cb(JSContextRef context, JSObjectRef thisObject, @@ -450,6 +476,7 @@ get_sessions_cb(JSContextRef context, return array; } + static JSValueRef get_default_session_cb(JSContextRef context, JSObjectRef thisObject, @@ -463,6 +490,7 @@ get_default_session_cb(JSContextRef context, return JSValueMakeString(context, string); } + static JSValueRef get_timed_login_user_cb(JSContextRef context, JSObjectRef thisObject, @@ -476,6 +504,18 @@ get_timed_login_user_cb(JSContextRef context, return JSValueMakeString(context, string); } + +static JSValueRef +get_lock_hint_cb(JSContextRef context, + JSObjectRef thisObject, + JSStringRef propertyName, + JSValueRef *exception) { + LightDMGreeter *greeter = JSObjectGetPrivate(thisObject); + + return JSValueMakeBoolean(lightdm_greeter_get_lock_hint(greeter)); +} + + static JSValueRef get_timed_login_delay_cb(JSContextRef context, JSObjectRef thisObject, @@ -488,6 +528,7 @@ get_timed_login_delay_cb(JSContextRef context, return JSValueMakeNumber(context, delay); } + static JSValueRef cancel_timed_login_cb(JSContextRef context, JSObjectRef function, @@ -506,6 +547,7 @@ cancel_timed_login_cb(JSContextRef context, return JSValueMakeNull(context); } + static JSValueRef start_authentication_cb(JSContextRef context, JSObjectRef function, @@ -530,6 +572,7 @@ start_authentication_cb(JSContextRef context, return JSValueMakeNull(context); } + static JSValueRef provide_secret_cb(JSContextRef context, JSObjectRef function, @@ -555,6 +598,7 @@ provide_secret_cb(JSContextRef context, return JSValueMakeNull(context); } + static JSValueRef cancel_authentication_cb(JSContextRef context, JSObjectRef function, @@ -573,6 +617,7 @@ cancel_authentication_cb(JSContextRef context, return JSValueMakeNull(context); } + static JSValueRef get_authentication_user_cb(JSContextRef context, JSObjectRef thisObject, @@ -582,6 +627,7 @@ get_authentication_user_cb(JSContextRef context, return JSValueMakeString(context, JSStringCreateWithUTF8CString(lightdm_greeter_get_authentication_user(greeter))); } + static JSValueRef get_is_authenticated_cb(JSContextRef context, JSObjectRef thisObject, @@ -591,6 +637,7 @@ get_is_authenticated_cb(JSContextRef context, return JSValueMakeBoolean(context, lightdm_greeter_get_is_authenticated(greeter)); } + static JSValueRef get_can_suspend_cb(JSContextRef context, JSObjectRef thisObject, @@ -599,6 +646,7 @@ get_can_suspend_cb(JSContextRef context, return JSValueMakeBoolean(context, lightdm_get_can_suspend()); } + static JSValueRef suspend_cb(JSContextRef context, JSObjectRef function, @@ -615,6 +663,7 @@ suspend_cb(JSContextRef context, return JSValueMakeNull(context); } + static JSValueRef get_can_hibernate_cb(JSContextRef context, JSObjectRef thisObject, @@ -623,6 +672,7 @@ get_can_hibernate_cb(JSContextRef context, return JSValueMakeBoolean(context, lightdm_get_can_hibernate()); } + static JSValueRef hibernate_cb(JSContextRef context, JSObjectRef function, @@ -639,6 +689,7 @@ hibernate_cb(JSContextRef context, return JSValueMakeNull(context); } + static JSValueRef get_can_restart_cb(JSContextRef context, JSObjectRef thisObject, @@ -647,6 +698,7 @@ get_can_restart_cb(JSContextRef context, return JSValueMakeBoolean(context, lightdm_get_can_restart()); } + static JSValueRef restart_cb(JSContextRef context, JSObjectRef function, @@ -663,6 +715,7 @@ restart_cb(JSContextRef context, return JSValueMakeNull(context); } + static JSValueRef get_can_shutdown_cb(JSContextRef context, JSObjectRef thisObject, @@ -671,6 +724,7 @@ get_can_shutdown_cb(JSContextRef context, return JSValueMakeBoolean(context, lightdm_get_can_shutdown()); } + static JSValueRef shutdown_cb(JSContextRef context, JSObjectRef function, @@ -687,6 +741,7 @@ shutdown_cb(JSContextRef context, return JSValueMakeNull(context); } + static JSValueRef login_cb(JSContextRef context, JSObjectRef function, @@ -718,6 +773,7 @@ login_cb(JSContextRef context, return JSValueMakeNull(context); } + static JSValueRef set_language_cb(JSContextRef context, JSObjectRef function, @@ -740,6 +796,7 @@ set_language_cb(JSContextRef context, return JSValueMakeNull(context); } + static JSValueRef gettext_cb(JSContextRef context, JSObjectRef function, @@ -763,6 +820,7 @@ gettext_cb(JSContextRef context, return JSValueMakeString(context, result); } + static JSValueRef ngettext_cb(JSContextRef context, JSObjectRef function, @@ -793,6 +851,7 @@ ngettext_cb(JSContextRef context, return JSValueMakeString(context, result); } + static const JSStaticValue lightdm_user_values[] = { {"name", get_user_name_cb, NULL, kJSPropertyAttributeReadOnly}, {"real_name", get_user_real_name_cb, NULL, kJSPropertyAttributeReadOnly}, @@ -841,6 +900,7 @@ static const JSStaticValue lightdm_greeter_values[] = { {"can_hibernate", get_can_hibernate_cb, NULL, kJSPropertyAttributeReadOnly}, {"can_restart", get_can_restart_cb, NULL, kJSPropertyAttributeReadOnly}, {"can_shutdown", get_can_shutdown_cb, NULL, kJSPropertyAttributeReadOnly}, + {"lock_hint", get_lock_hint_cb, NULL, kJSPropertyAttributeReadOnly}, {NULL, NULL, NULL, 0}}; static const JSStaticFunction lightdm_greeter_functions[] = { @@ -910,6 +970,7 @@ static const JSClassDefinition gettext_definition = { gettext_functions, /* Static functions */ }; + static void web_page_created_callback(WebKitWebExtension *extension, WebKitWebPage *web_page, gpointer user_data) { /*@formatter:off*/ @@ -920,6 +981,7 @@ web_page_created_callback(WebKitWebExtension *extension, WebKitWebPage *web_page /*@formatter:on*/ } + static void window_object_cleared_callback(WebKitScriptWorld *world, WebKitWebPage *web_page, @@ -928,6 +990,8 @@ window_object_cleared_callback(WebKitScriptWorld *world, JSObjectRef gettext_object, lightdm_greeter_object; JSGlobalContextRef jsContext; JSObjectRef globalObject; + WebKitDOMDocument *dom_document; + WebkitDOMDOMWindow *dom_window; page_id = webkit_web_page_get_id(web_page); @@ -942,16 +1006,32 @@ window_object_cleared_callback(WebKitScriptWorld *world, lightdm_session_class = JSClassCreate(&lightdm_session_definition); gettext_object = JSObjectMake(jsContext, gettext_class, NULL); - - JSObjectSetProperty(jsContext, globalObject, JSStringCreateWithUTF8CString("gettext"), gettext_object, - kJSPropertyAttributeNone, NULL); + JSObjectSetProperty(jsContext, + globalObject, + JSStringCreateWithUTF8CString("gettext"), + gettext_object, + kJSPropertyAttributeNone, + NULL); lightdm_greeter_object = JSObjectMake(jsContext, lightdm_greeter_class, greeter); + JSObjectSetProperty(jsContext, + globalObject, + JSStringCreateWithUTF8CString("lightdm"), + lightdm_greeter_object, + kJSPropertyAttributeNone, + NULL); + + // If lightdm was started as a lock-screen, send signal to our UI process. + if (lightdm_greeter_get_lock_hint(greeter)) { + dom_document = webkit_web_page_get_dom_document(web_page); + dom_window = webkit_dom_document_get_default_view(dom_document); + + webkit_dom_dom_window_webkit_message_handlers_post_message(dom_window, 'Greeter', 'lock_hint_cb'); + } - JSObjectSetProperty(jsContext, globalObject, JSStringCreateWithUTF8CString("lightdm"), lightdm_greeter_object, - kJSPropertyAttributeNone, NULL); } + static void show_prompt_cb(LightDMGreeter *greeter, const gchar *text, @@ -982,6 +1062,7 @@ show_prompt_cb(LightDMGreeter *greeter, } } + static void show_message_cb(LightDMGreeter *greeter, const gchar *text, @@ -1009,6 +1090,7 @@ show_message_cb(LightDMGreeter *greeter, } } + static void authentication_complete_cb(LightDMGreeter *greeter, WebKitWebExtension *extension) { @@ -1033,16 +1115,16 @@ authentication_complete_cb(LightDMGreeter *greeter, WebKitWebExtension *extensio G_MODULE_EXPORT void webkit_web_extension_initialize(WebKitWebExtension *extension) { - LightDMGreeter *greeter; - - greeter = lightdm_greeter_new(); + LightDMGreeter *greeter = lightdm_greeter_new(); g_signal_connect(G_OBJECT(greeter), "authentication-complete", G_CALLBACK(authentication_complete_cb), extension); g_signal_connect(G_OBJECT(greeter), "show-prompt", G_CALLBACK(show_prompt_cb), extension); g_signal_connect(G_OBJECT(greeter), "show-message", G_CALLBACK(show_message_cb), extension); - g_signal_connect(webkit_script_world_get_default(), "window-object-cleared", - G_CALLBACK(window_object_cleared_callback), greeter); + g_signal_connect(webkit_script_world_get_default(), + "window-object-cleared", + G_CALLBACK(window_object_cleared_callback), + greeter); lightdm_greeter_connect_sync(greeter, NULL); } diff --git a/src/lightdm-webkit2-greeter.c b/src/lightdm-webkit2-greeter.c index 216fa53..9a20186 100644 --- a/src/lightdm-webkit2-greeter.c +++ b/src/lightdm-webkit2-greeter.c @@ -43,9 +43,10 @@ #include -static GtkWidget *web_view; -static GtkWidget *window; +static GtkWidget *web_view; +static GtkWidget *window; static WebKitSettings *webkit_settings; +static GdkDisplay *default_display; static GdkFilterReturn @@ -53,8 +54,8 @@ wm_window_filter(GdkXEvent *gxevent, GdkEvent *event, gpointer data) { XEvent *xevent = (XEvent *) gxevent; if (xevent->type == MapNotify) { - GdkDisplay *display = gdk_x11_lookup_xdisplay(xevent->xmap.display); - GdkWindow *win = gdk_x11_window_foreign_new_for_display(display, xevent->xmap.window); + GdkDisplay *display = gdk_x11_lookup_xdisplay(xevent->xmap.display); + GdkWindow *win = gdk_x11_window_foreign_new_for_display(display, xevent->xmap.window); GdkWindowTypeHint win_type = gdk_window_get_type_hint(win); if (win_type != GDK_WINDOW_TYPE_HINT_COMBO @@ -66,7 +67,7 @@ wm_window_filter(GdkXEvent *gxevent, GdkEvent *event, gpointer data) { } else if (xevent->type == UnmapNotify) { Window xwin; - int revert_to = RevertToNone; + int revert_to = RevertToNone; XGetInputFocus(xevent->xunmap.display, &xwin, &revert_to); if (revert_to == RevertToNone) { @@ -77,6 +78,7 @@ wm_window_filter(GdkXEvent *gxevent, GdkEvent *event, gpointer data) { return GDK_FILTER_CONTINUE; } + static void initialize_web_extensions_cb(WebKitWebContext *context, gpointer user_data) { @@ -84,6 +86,7 @@ initialize_web_extensions_cb(WebKitWebContext *context, gpointer user_data) { } + static void create_new_webkit_settings_object(void) { webkit_settings = webkit_settings_new_with_settings( @@ -101,15 +104,47 @@ create_new_webkit_settings_object(void) { ); } + static gboolean -context_menu_cb(WebKitWebView *web_view, - WebKitContextMenu *context_menu, - GdkEvent *event, - WebKitHitTestResult *hit_test_result, - gpointer user_data) { +context_menu_cb(WebKitWebView *view, + WebKitContextMenu *context_menu, + GdkEvent *event, + WebKitHitTestResult *hit_test_result, + gpointer user_data) { return TRUE; } + +static void +lock_hint_cb(void) { + // Make the greeter behave a bit more like a screensaver if used as un/lock-screen by blanking the screen. + Display *display = gdk_x11_display_get_xdisplay(default_display); + XGetScreenSaver(display, &timeout, &interval, &prefer_blanking, &allow_exposures); + XForceScreenSaver(display, ScreenSaverActive); + XSetScreenSaver(display, + config_get_int(NULL, CONFIG_KEY_SCREENSAVER_TIMEOUT, 60), + 0, + ScreenSaverActive, + DefaultExposures); +} + + +static void +message_received_cb(WebKitUserContentManager *manager, + WebKitJavascriptResult *message, + gpointer user_data) { + char *message_str; + + message_str = get_js_result_as_string(message); + + /* TODO: + * Abstract this by using JSON for exchanging messages so the handler can be used for more than one task/event. + */ + lock_hint_cb(); + +} + + static gboolean fade_timer_cb(gpointer data) { gdouble opacity; @@ -125,54 +160,66 @@ fade_timer_cb(gpointer data) { return TRUE; } + static void quit_cb(void) { - // Fade out the greeter g_timeout_add(40, (GSourceFunc) fade_timer_cb, NULL); + } int main(int argc, char **argv) { - GdkScreen *screen; - GdkWindow *root_window; - GdkRectangle geometry; - GKeyFile *keyfile; - gchar *theme; - GdkRGBA bg_color; + GdkScreen *screen; + GdkWindow *root_window; + GdkRectangle geometry; + GKeyFile *keyfile; + gchar *theme; + GdkRGBA bg_color; + WebKitUserContentManager *manager; + WebKitWebContext *context; g_unix_signal_add(SIGTERM, (GSourceFunc) quit_cb, /* is_callback */ GINT_TO_POINTER(TRUE)); gtk_init(&argc, &argv); - WebKitWebContext *context = webkit_web_context_get_default(); - g_signal_connect(context, "initialize-web-extensions", G_CALLBACK(initialize_web_extensions_cb), NULL); - - // Apply greeter settings from conf file keyfile = g_key_file_new(); g_key_file_load_from_file(keyfile, "/etc/lightdm/lightdm-webkit2-greeter.conf", G_KEY_FILE_NONE, NULL); theme = g_key_file_get_string(keyfile, "greeter", "webkit-theme", NULL); // Setup the main window - window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - screen = gtk_window_get_screen(GTK_WINDOW(window)); + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + screen = gtk_window_get_screen(GTK_WINDOW(window)); root_window = gdk_get_default_root_window(); + display = gdk_display_get_default(); gtk_window_set_decorated(GTK_WINDOW(window), FALSE); gdk_screen_get_monitor_geometry(screen, gdk_screen_get_primary_monitor(screen), &geometry); gtk_window_set_default_size(GTK_WINDOW(window), geometry.width, geometry.height); gtk_window_move(GTK_WINDOW(window), geometry.x, geometry.y); - gdk_window_set_cursor(root_window, gdk_cursor_new_for_display(gdk_display_get_default(), GDK_LEFT_PTR)); + gdk_window_set_cursor(root_window, gdk_cursor_new_for_display(display, GDK_LEFT_PTR)); // There is no window manager, so we need to implement some of its functionality gdk_window_set_events(root_window, gdk_window_get_events(root_window) | GDK_SUBSTRUCTURE_MASK); gdk_window_add_filter(root_window, wm_window_filter, NULL); - // Configure the web_view's settings. + // Register and connect handler for setting the web extensions directory so webkit can find our extension + context = webkit_web_context_get_default(); + g_signal_connect(context, "initialize-web-extensions", G_CALLBACK(initialize_web_extensions_cb), NULL); + + // Register and connect handler for messages sent from our web extension + manager = webkit_user_content_manager_new(); + webkit_user_content_manager_register_script_message_handler(manager, "Greeter"); + g_signal_connect(manager, "script-message-received::Greeter", G_CALLBACK(message_received_cb), NULL); + + // Create the web_view + web_view = webkit_web_view_new_with_user_content_manager(manager); + + // Set the web_view's settings. create_new_webkit_settings_object(); - web_view = webkit_web_view_new_with_settings(webkit_settings); + webkit_web_view_set_settings(web_view, webkit_settings); // The default background is white which causes a flash effect when the greeter starts. Make it black instead. gdk_rgba_parse(&bg_color, "#000000"); @@ -183,10 +230,9 @@ main(int argc, char **argv) { gtk_container_add(GTK_CONTAINER(window), web_view); webkit_web_view_load_uri(WEBKIT_WEB_VIEW(web_view), g_strdup_printf("file://%s/%s/index.html", THEME_DIR, theme)); - - gtk_widget_show_all(window); + gtk_main(); return 0;