summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am23
-rw-r--r--configure.ac8
-rw-r--r--src/facebook-connection.c2
-rw-r--r--src/login.c172
-rw-r--r--tests/test-browser.cc336
5 files changed, 533 insertions, 8 deletions
diff --git a/Makefile.am b/Makefile.am
index 8302211..a0ae24f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,10 +1,15 @@
-AM_CFLAGS = -Wall -Werror -Wmissing-prototypes
-AM_CPPFLAGS = -DLIBEXECDIR=\"$(libexecdir)\"
ACLOCAL_AMFLAGS = -I m4
+AM_CFLAGS = -Wall -Werror -Wmissing-prototypes
+AM_CXXFLAGS = -Wall -Werror
+AM_CPPFLAGS = -DMOZILLA_LIBDIR=\"$(mozilla_libdir)\" \
+ -DTELEPATHY_LIBDIR=\"$(telepathy_libdir)\"
+
telepathy_libdir=$(libdir)/telepathy
-telepathy_lib_PROGRAMS = src/telepathy-gruschler
-libexec_PROGRAMS = src/telepathy-gruschler-login
+telepathy_lib_PROGRAMS = src/telepathy-gruschler \
+ src/telepathy-gruschler-login
+
+mozilla_libdir = @mozilla_libdir@
src_telepathy_gruschler_CFLAGS = $(AM_CFLAGS) $(GRUSCHLER_CFLAGS)
src_telepathy_gruschler_LDADD = $(AM_LDFLAGS) $(GRUSCHLER_LIBS)
@@ -17,5 +22,13 @@ src_telepathy_gruschler_SOURCES = src/connection-manager.c \
src/main.c
src_telepathy_gruschler_login_CFLAGS = $(AM_CFLAGS) $(LOGIN_CFLAGS)
-src_telepathy_gruschler_login_LDADD = $(AM_LDFLAGS) $(LOGIN_LIBS)
+src_telepathy_gruschler_login_LDFLAGS = $(AM_LDFLAGS) -rpath $(mozilla_libdir)
+src_telepathy_gruschler_login_LDADD = $(LOGIN_LIBS)
src_telepathy_gruschler_login_SOURCES = src/login.c
+
+noinst_PROGRAMS = tests/test-browser
+tests_test_browser_CXXFLAGS = $(AM_CXXFLAGS) $(LOGIN_CFLAGS) -fshort-wchar
+tests_test_browser_LDFLAGS = $(AM_LDFLAGS) -rpath $(mozilla_libdir)
+tests_test_browser_LDADD = $(LOGIN_LIBS) -L/usr/lib/microb-engine-devel/lib -lxpcomglue_s
+tests_test_browser_SOURCES = tests/test-browser.cc
+
diff --git a/configure.ac b/configure.ac
index d00d457..bd731ac 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,8 +17,12 @@ PKG_CHECK_MODULES([GRUSCHLER],
rtcom-telepathy-glib >= 0.1.38
telepathy-glib >= 0.7.35])
PKG_CHECK_MODULES([LOGIN],
- [gtkembedmoz >= 1.7
- gtk+-2.0 >= 2.14])
+ [gtk+-2.0 >= 2.14
+ hildon-1 >= 2.2])
+
+LOGIN_CFLAGS="$LOGIN_CFLAGS -I/usr/lib/microb-engine-devel/include"
+LOGIN_LIBS="$LOGIN_LIBS -lgtkembedmoz"
+AC_SUBST([mozilla_libdir],[/usr/lib/microb-engine])
FACEBOOK_APPKEY([GRUSCHLER])
diff --git a/src/facebook-connection.c b/src/facebook-connection.c
index 8883354..914be3a 100644
--- a/src/facebook-connection.c
+++ b/src/facebook-connection.c
@@ -1150,7 +1150,7 @@ static gboolean
_run_login_helper (GruschlerFacebookConnection *self,
GError **error)
{
- char *argv[] = { LIBEXECDIR "/telepathy-gruschler-login", NULL };
+ char *argv[] = { TELEPATHY_LIBDIR "/telepathy-gruschler-login", NULL };
int fd;
g_return_val_if_fail (0 == self->priv->login_helper_pid, FALSE);
diff --git a/src/login.c b/src/login.c
new file mode 100644
index 0000000..1d03eae
--- /dev/null
+++ b/src/login.c
@@ -0,0 +1,172 @@
+#include "config.h"
+
+#include <gtkmozembed.h>
+//FIXME #include <gtkmozembed_common.h>
+
+#include <string.h>
+
+typedef struct {
+ const char *api_key;
+ const char *next_url;
+ const char *cancel_url;
+ const char *permissions;
+} AppData;
+
+static char *
+get_login_url (AppData *app)
+{
+ char *args[] = {
+ g_uri_escape_string (app->api_key, NULL, TRUE),
+ g_uri_escape_string (app->next_url, NULL, TRUE),
+ g_uri_escape_string (app->cancel_url, NULL, TRUE),
+ g_uri_escape_string (app->permissions, NULL, TRUE)
+ };
+
+ char *url;
+ int i;
+
+ url = g_strdup_printf ("http://www.facebook.com/login.php?v=1.0&"
+ "fbconnect=true&display=popup&return_session=true&"
+ "api_key=%s&next=%s&cancel_url=%s&req_perm=%s",
+ args[0], args[1], args[2], args[3]);
+
+ for (i = 0; i < G_N_ELEMENTS (args); ++i)
+ g_free (args[i]);
+
+ return url;
+}
+
+static char *
+get_session (const char *query)
+{
+ const char *start, *end;
+
+ if ('?' != query[0] ||
+ NULL == (start = strstr (query, "session=")) ||
+ NULL == strchr ("?&", start[-1]))
+ return NULL;
+
+ start += strlen ("session=");
+
+ if (!(end = strchr (start, '&')))
+ end = query + strlen (query);
+
+ return g_uri_unescape_segment (start, end, NULL);
+}
+
+static void
+location_cb (GtkMozEmbed *embed,
+ AppData *app)
+{
+ const char *location;
+
+ location = gtk_moz_embed_get_location (embed);
+
+ if (!strcmp (location, app->cancel_url))
+ {
+ gtk_main_quit ();
+ return;
+ }
+
+ if (g_str_has_prefix (location, app->next_url))
+ {
+ char *session;
+
+ session = get_session (location + strlen (app->next_url));
+
+ if (session)
+ g_print ("GRUSCHLER-SESSION:%s\n", session);
+
+ g_free (session);
+ gtk_main_quit ();
+
+ return;
+ }
+}
+
+#if 0
+static void
+set_boolean (char *key,
+ gboolean value)
+{
+ gtk_moz_embed_common_set_pref (G_TYPE_BOOLEAN, key, &value);
+}
+
+static void
+set_integer (char *key,
+ int value)
+{
+ gtk_moz_embed_common_set_pref (G_TYPE_INT, key, &value);
+}
+#endif
+
+int
+main (int argc,
+ char **argv)
+{
+ AppData app = {
+ GRUSCHLER_FACEBOOK_APIKEY,
+ "http://www.facebook.com/connect/login_success.html",
+ "http://www.facebook.com/connect/login_failure.html",
+ "offline_access",
+ };
+
+ GOptionEntry options[] = {
+ { "api-key", 0, 0, G_OPTION_ARG_STRING, &app.api_key,
+ "Facebook API key of the application", "KEY" },
+ { "next-url", 0, 0, G_OPTION_ARG_STRING, &app.next_url,
+ "URL of the page to visit after successful login", "URL" },
+ { "cancel-url", 0, 0, G_OPTION_ARG_STRING, &app.next_url,
+ "URL of the page to visit when login was aborted", "URL" },
+ { "permissions", 0, 0, G_OPTION_ARG_STRING, &app.permissions,
+ "Comma separated list of requested permissions", "LIST" },
+ { NULL, }
+ };
+
+ GtkWidget *window, *embed;
+ GError *error = NULL;
+ unsigned chrome;
+ char *url;
+
+ if (!gtk_init_with_args (&argc, &argv, NULL, options, NULL, &error))
+ {
+ g_printerr ("Usage Error: %s\n", error->message);
+ g_error_free (error);
+ return 2;
+ }
+
+ gtk_moz_embed_set_path (MOZILLA_LIBDIR);
+
+#if 0
+ set_boolean ("gtkmozembed.no_destroy_on_last_window", TRUE);
+ set_integer ("gtkmozembed.kinetic.type", 1);
+
+ gtk_moz_embed_common_save_prefs ();
+#endif
+
+ embed = gtk_moz_embed_new ();
+
+ chrome = gtk_moz_embed_get_chrome_mask (GTK_MOZ_EMBED (embed));
+g_print ("%x\n", chrome);
+ chrome &= ~GTK_MOZ_EMBED_FLAG_SCROLLBARSON;
+g_print ("%x\n", chrome);
+ gtk_moz_embed_set_chrome_mask (GTK_MOZ_EMBED (embed), chrome);
+
+
+ g_signal_connect (embed, "location", G_CALLBACK (location_cb), &app);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+ gtk_container_add (GTK_CONTAINER (window), embed);
+ gtk_widget_show_all (window);
+
+ url = get_login_url (&app);
+ url = g_strdup ("http://www.spiegel.de/");
+ g_print ("loading %s\n", url);
+ gtk_moz_embed_load_url (GTK_MOZ_EMBED (embed), url);
+ g_free (url);
+
+ gtk_main ();
+
+ return 0;
+}
diff --git a/tests/test-browser.cc b/tests/test-browser.cc
new file mode 100644
index 0000000..3e50853
--- /dev/null
+++ b/tests/test-browser.cc
@@ -0,0 +1,336 @@
+#include "config.h"
+
+#define MOZILLA_CLIENT
+
+#include <hildon/hildon.h>
+#include <stdlib.h>
+
+#include <gtkmozembed.h>
+#include <gtkmozembed_internal.h>
+
+#include <nsCOMPtr.h>
+#include <nsIDOMWindow.h>
+#include <nsIDOMWindowUtils.h>
+#include <nsIInterfaceRequestorUtils.h>
+#include <nsEmbedString.h>
+
+static gboolean
+expose_event_cb (GtkWidget *widget, GdkEventExpose *event)
+{
+
+ cairo_t *cr = gdk_cairo_create (widget->window);
+
+ GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
+ gdk_cairo_set_source_pixmap (cr, child->window, child->allocation.x, child->allocation.y);
+
+ /* draw no more than our expose event intersects our child */
+ GdkRegion *region = gdk_region_rectangle (&child->allocation);
+ gdk_region_intersect (region, event->region);
+ gdk_cairo_region (cr, region);
+ cairo_clip (cr);
+
+ /* composite, with a 50% opacity */
+ cairo_paint_with_alpha (cr, 254./255);
+
+ /* scollbars */
+ cairo_set_source_rgba (cr, 0.8, 0.8, 0.8, 0.8);
+
+ cairo_rectangle (cr,
+ child->allocation.x + child->allocation.width -
+ HILDON_MARGIN_DEFAULT - HILDON_MARGIN_HALF,
+ child->allocation.y + HILDON_MARGIN_HALF,
+ HILDON_MARGIN_DEFAULT,
+ 0.6 * (child->allocation.height - HILDON_MARGIN_DOUBLE));
+ cairo_rectangle (cr,
+ child->allocation.x + HILDON_MARGIN_HALF,
+ child->allocation.y + child->allocation.height -
+ HILDON_MARGIN_DEFAULT - HILDON_MARGIN_HALF,
+ 0.6 * (child->allocation.width - HILDON_MARGIN_DOUBLE),
+ HILDON_MARGIN_DEFAULT);
+
+ cairo_fill (cr);
+
+ cairo_destroy (cr);
+ return FALSE;
+}
+
+static GdkEvent *last_button_event = NULL;
+
+#if 0
+#include <gdk/gdkx.h>
+
+static const char *
+event_name (GdkEventType type)
+{
+ static GEnumClass *enum_class = NULL;
+ GEnumValue *value;
+
+ if (!enum_class)
+ enum_class = static_cast<GEnumClass *> (g_type_class_ref (GDK_TYPE_EVENT_TYPE));
+
+ value = g_enum_get_value (enum_class, type);
+ return (value ? value->value_nick : "unknown");
+}
+
+static void
+send_motion_event (GtkWidget *widget, GdkEventMotion *event)
+{
+ XEvent xev;
+
+ xev.xmotion.type = MotionNotify;
+ xev.xmotion.serial = 0;
+ xev.xmotion.send_event = True;
+ xev.xmotion.display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget));
+ xev.xmotion.window = GDK_WINDOW_XWINDOW (gtk_widget_get_window (widget));
+ xev.xmotion.root = GDK_WINDOW_XWINDOW (gtk_widget_get_root_window (widget));
+ xev.xmotion.subwindow = GDK_WINDOW_XWINDOW (gtk_widget_get_window (widget));
+ xev.xmotion.time = event->time;
+ xev.xmotion.x = event->x;
+ xev.xmotion.y = event->y;
+ xev.xmotion.x_root = event->x_root;
+ xev.xmotion.y_root = event->y_root;
+ xev.xmotion.same_screen = True;
+
+ xev.xmotion.state = event->state;
+ xev.xmotion.is_hint = event->is_hint;
+
+ XSendEvent(xev.xbutton.display, xev.xbutton.window, True, 0, &xev);
+}
+
+static void
+send_crossing_event (GtkWidget *widget, GdkEventCrossing *event)
+{
+ XEvent xev;
+
+ switch (event->type)
+ {
+ case GDK_ENTER_NOTIFY:
+ xev.xcrossing.type = EnterNotify;
+ break;
+ case GDK_LEAVE_NOTIFY:
+ xev.xcrossing.type = LeaveNotify;
+ break;
+ default:
+ g_return_if_reached ();
+ }
+
+ xev.xcrossing.serial = 0;
+ xev.xcrossing.send_event = True;
+ xev.xcrossing.display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget));
+ xev.xcrossing.window = GDK_WINDOW_XWINDOW (gtk_widget_get_window (widget));
+ xev.xcrossing.root = GDK_WINDOW_XWINDOW (gtk_widget_get_root_window (widget));
+ xev.xcrossing.subwindow = GDK_WINDOW_XWINDOW (gtk_widget_get_window (widget));
+ xev.xcrossing.time = event->time;
+ xev.xcrossing.x = event->x;
+ xev.xcrossing.y = event->y;
+ xev.xcrossing.x_root = event->x_root;
+ xev.xcrossing.y_root = event->y_root;
+ xev.xcrossing.same_screen = True;
+
+ xev.xcrossing.mode = event->mode;
+ xev.xcrossing.detail = event->detail;
+ xev.xcrossing.focus = event->focus;
+ xev.xcrossing.state = event->state;
+
+ XSendEvent(xev.xbutton.display, xev.xbutton.window, True, 0, &xev);
+}
+
+static gboolean
+event_cb (GtkWidget *widget, GdkEvent *event)
+{
+ GtkWidget *child;
+
+ g_print ("%s: %s event (%d) for %s (%p/%p)\n",
+ G_STRFUNC, event_name (event->type),
+ event->type, gtk_widget_get_name (widget),
+ widget->window, event->any.window);
+
+ if (!GTK_IS_BIN (widget) || widget->window != event->any.window)
+ return FALSE;
+
+ child = gtk_bin_get_child (GTK_BIN (widget));
+
+ switch (event->type)
+ {
+ case GDK_MOTION_NOTIFY:
+ send_motion_event (child, &event->motion);
+ break;
+
+ case GDK_ENTER_NOTIFY:
+ case GDK_LEAVE_NOTIFY:
+ send_crossing_event (child, &event->crossing);
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+#endif
+
+static void
+send_mouse_event (GtkWidget *embed, GdkEvent *event, const nsAString &name)
+{
+ nsCOMPtr<nsIWebBrowser> browser;
+ gtk_moz_embed_get_nsIWebBrowser (GTK_MOZ_EMBED (embed), getter_AddRefs (browser));
+
+ nsCOMPtr<nsIDOMWindow> window;
+ browser->GetContentDOMWindow (getter_AddRefs (window));
+
+ nsCOMPtr<nsIDOMWindowUtils> utils (do_GetInterface (window));
+
+ utils->SendMouseEvent(name,
+ float(event->button.x), float(event->button.y),
+ event->button.button, 1, 0, PR_FALSE);
+}
+
+static gboolean
+button_press_cb (GtkWidget *widget, GdkEvent *event)
+{
+ g_print ("%s: event-type=%d\n", G_STRFUNC, event->type);
+
+ if (last_button_event)
+ gdk_event_free (last_button_event);
+
+ last_button_event = gdk_event_copy (event);
+
+ GtkWidget *embed = gtk_bin_get_child (GTK_BIN (widget));
+ send_mouse_event (embed, event, NS_LITERAL_STRING("mousedown"));
+
+ return TRUE;
+}
+
+static gboolean
+button_release_cb (GtkWidget *widget, GdkEvent *event)
+{
+ g_print ("%s: event-type=%d, %p %p\n", G_STRFUNC, event->type, widget->window, event->any.window);
+
+ GtkWidget *embed = gtk_bin_get_child (GTK_BIN (widget));
+ send_mouse_event (embed, event, NS_LITERAL_STRING("mouseup"));
+
+ if (last_button_event)
+ {
+ int dx = abs (event->button.x - last_button_event->button.x);
+ int dy = abs (event->button.y - last_button_event->button.y);
+
+ if (3 >= dx && 3 >= dy)
+ {
+ g_print ("foo\n");
+ send_mouse_event (embed, event, NS_LITERAL_STRING("click"));
+#if 0
+XEvent xev;
+xev.xbutton.type = ButtonPress;
+xev.xbutton.serial = 0;
+xev.xbutton.send_event = True;
+xev.xbutton.display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (child));
+xev.xbutton.window = GDK_WINDOW_XWINDOW (gtk_widget_get_window (child));
+xev.xbutton.root = GDK_WINDOW_XWINDOW (gtk_widget_get_root_window (child));
+xev.xbutton.subwindow = GDK_WINDOW_XWINDOW (gtk_widget_get_window (child));
+xev.xbutton.time = last_button_event->button.time;
+xev.xbutton.x = last_button_event->button.x;
+xev.xbutton.y = last_button_event->button.y;
+xev.xbutton.x_root = last_button_event->button.x_root;
+xev.xbutton.y_root = last_button_event->button.y_root;
+xev.xbutton.state = last_button_event->button.state;
+xev.xbutton.button = last_button_event->button.button;
+xev.xbutton.same_screen = True;
+XSendEvent(xev.xbutton.display, xev.xbutton.window, True, 0, &xev);
+
+xev.xbutton.type = ButtonRelease;
+xev.xbutton.serial = 0;
+xev.xbutton.send_event = True;
+xev.xbutton.display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (child));
+xev.xbutton.window = GDK_WINDOW_XWINDOW (gtk_widget_get_window (child));
+xev.xbutton.root = GDK_WINDOW_XWINDOW (gtk_widget_get_root_window (child));
+xev.xbutton.subwindow = GDK_WINDOW_XWINDOW (gtk_widget_get_window (child));
+xev.xbutton.time = event->button.time;
+xev.xbutton.x = event->button.x;
+xev.xbutton.y = event->button.y;
+xev.xbutton.x_root = event->button.x_root;
+xev.xbutton.y_root = event->button.y_root;
+xev.xbutton.state = event->button.state;
+xev.xbutton.button = event->button.button;
+xev.xbutton.same_screen = True;
+XSendEvent(xev.xbutton.display, xev.xbutton.window, True, 0, &xev);
+#endif
+#if 0
+ last_button_event->button.window = child->window;
+ gtk_widget_event (child, last_button_event);
+
+ event = gdk_event_copy (event);
+ event->button.window = child->window;
+ gtk_widget_event (child, event);
+ //gdk_event_free (event);
+#endif
+ }
+ else
+ gdk_event_free (last_button_event);
+
+ last_button_event = NULL;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+moz_button_press_cb (GtkWidget *widget, GdkEvent *event)
+{
+ g_print ("%s: window=%p/%p, event=%p/%p\n", G_STRFUNC, widget->window, event->any.window, event, last_button_event);
+ return TRUE;
+}
+
+static gboolean
+moz_button_release_cb (GtkWidget *widget, GdkEvent *event)
+{
+ g_print ("%s: window=%p/%p, event=%p/%p\n", G_STRFUNC, widget->window, event->any.window, event, last_button_event);
+ return TRUE;
+}
+
+static int
+open_uri_cb (GtkMozEmbed *embed, const char *aURI)
+{
+ g_print ("%s: %s\n", __func__, aURI);
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ guint32 chrome;
+
+ hildon_gtk_init (&argc, &argv);
+
+ GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+ g_signal_connect_after (window, "expose-event", G_CALLBACK (expose_event_cb), NULL);
+
+ GtkWidget *ebox = gtk_event_box_new ();
+ gtk_container_add (GTK_CONTAINER (window), ebox);
+ gtk_event_box_set_above_child (GTK_EVENT_BOX (ebox), TRUE);
+ //g_signal_connect (ebox, "event", G_CALLBACK (event_cb), NULL);
+ g_signal_connect (ebox, "button-press-event", G_CALLBACK (button_press_cb), NULL);
+ g_signal_connect (ebox, "button-release-event", G_CALLBACK (button_release_cb), NULL);
+ gtk_widget_add_events (ebox, GDK_POINTER_MOTION_MASK);
+
+ gtk_moz_embed_set_path (MOZILLA_LIBDIR);
+ GtkWidget *embed = gtk_moz_embed_new ();
+
+ chrome = gtk_moz_embed_get_chrome_mask (GTK_MOZ_EMBED (embed));
+ gtk_moz_embed_set_chrome_mask (GTK_MOZ_EMBED (embed), chrome & ~GTK_MOZ_EMBED_FLAG_SCROLLBARSON);
+ gtk_moz_embed_load_url (GTK_MOZ_EMBED (embed), "file:///home/mathias/.dashboard.html");
+ g_signal_connect (embed, "button-press-event", G_CALLBACK (moz_button_press_cb), NULL);
+ g_signal_connect (embed, "button-release-event", G_CALLBACK (moz_button_release_cb), NULL);
+ g_signal_connect (embed, "open-uri", G_CALLBACK (open_uri_cb), NULL);
+ //g_signal_connect (embed, "event", G_CALLBACK (event_cb), NULL);
+ gtk_container_add (GTK_CONTAINER (ebox), embed);
+
+ gtk_widget_show_all (window);
+
+ gdk_window_set_composited (ebox->window, TRUE);
+
+ gtk_main ();
+
+ return 0;
+
+}