diff --git a/eekboard/eekboard-context.c b/eekboard/eekboard-context.c
index a870ade8..60c028b8 100644
--- a/eekboard/eekboard-context.c
+++ b/eekboard/eekboard-context.c
@@ -60,6 +60,7 @@ struct _EekboardContextPrivate
     GHashTable *keyboard_hash;
     gboolean keyboard_visible;
     gboolean enabled;
+    gboolean fullscreen;
 };
 
 static void
@@ -558,15 +559,17 @@ eekboard_context_set_group (EekboardContext *context,
 
     g_return_if_fail (priv->keyboard);
 
-    eek_element_set_group (EEK_ELEMENT(priv->keyboard), group);
-    g_dbus_proxy_call (G_DBUS_PROXY(context),
-                       "SetGroup",
-                       g_variant_new ("(i)", group),
-                       G_DBUS_CALL_FLAGS_NONE,
-                       -1,
-                       cancellable,
-                       context_async_ready_callback,
-                       NULL);
+    if (eek_element_get_group (EEK_ELEMENT(priv->keyboard)) != group) {
+        eek_element_set_group (EEK_ELEMENT(priv->keyboard), group);
+        g_dbus_proxy_call (G_DBUS_PROXY(context),
+                           "SetGroup",
+                           g_variant_new ("(i)", group),
+                           G_DBUS_CALL_FLAGS_NONE,
+                           -1,
+                           cancellable,
+                           context_async_ready_callback,
+                           NULL);
+    }
 }
 
 /**
@@ -744,3 +747,26 @@ eekboard_context_is_enabled (EekboardContext *context)
     priv = EEKBOARD_CONTEXT_GET_PRIVATE (context);
     return priv->enabled;
 }
+
+void
+eekboard_context_set_fullscreen (EekboardContext *context,
+                                 gboolean         fullscreen,
+                                 GCancellable    *cancellable)
+{
+    EekboardContextPrivate *priv;
+
+    g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
+
+    priv = EEKBOARD_CONTEXT_GET_PRIVATE (context);
+    if (priv->fullscreen != fullscreen) {
+        g_dbus_proxy_call (G_DBUS_PROXY(context),
+                           "SetFullscreen",
+                           g_variant_new ("(b)", fullscreen),
+                           G_DBUS_CALL_FLAGS_NONE,
+                           -1,
+                           cancellable,
+                           context_async_ready_callback,
+                           NULL);
+    }
+    return priv->enabled;
+}
diff --git a/eekboard/eekboard-context.h b/eekboard/eekboard-context.h
index b19ab831..829c645e 100644
--- a/eekboard/eekboard-context.h
+++ b/eekboard/eekboard-context.h
@@ -73,39 +73,41 @@ struct _EekboardContextClass {
     gpointer pdummy[23];
 };
 
-GType            eekboard_context_get_type      (void) G_GNUC_CONST;
+GType            eekboard_context_get_type       (void) G_GNUC_CONST;
 
-EekboardContext *eekboard_context_new           (GDBusConnection *connection,
-                                                 const gchar     *object_path,
-                                                 GCancellable    *cancellable);
-guint            eekboard_context_add_keyboard  (EekboardContext *context,
-                                                 EekKeyboard     *keyboard,
-                                                 GCancellable    *cancellable);
-void             eekboard_context_remove_keyboard
-                                                (EekboardContext *context,
-                                                 guint            keyboard_id,
-                                                 GCancellable    *cancellable);
-void             eekboard_context_set_keyboard  (EekboardContext *context,
-                                                 guint            keyboard_id,
-                                                 GCancellable    *cancellable);
-void             eekboard_context_show_keyboard (EekboardContext *context,
-                                                 GCancellable    *cancellable);
-void             eekboard_context_hide_keyboard (EekboardContext *context,
-                                                 GCancellable    *cancellable);
-void             eekboard_context_set_group     (EekboardContext *context,
-                                                 gint             group,
-                                                 GCancellable    *cancellable);
-void             eekboard_context_press_key     (EekboardContext *context,
-                                                 guint            keycode,
-                                                 GCancellable    *cancellable);
-void             eekboard_context_release_key   (EekboardContext *context,
-                                                 guint            keycode,
-                                                 GCancellable    *cancellable);
+EekboardContext *eekboard_context_new            (GDBusConnection *connection,
+                                                  const gchar     *object_path,
+                                                  GCancellable    *cancellable);
+guint            eekboard_context_add_keyboard   (EekboardContext *context,
+                                                  EekKeyboard     *keyboard,
+                                                  GCancellable    *cancellable);
+void             eekboard_context_remove_keyboard (EekboardContext *context,
+                                                   guint            keyboard_id,
+                                                   GCancellable    *cancellable);
+void             eekboard_context_set_keyboard   (EekboardContext *context,
+                                                  guint            keyboard_id,
+                                                  GCancellable    *cancellable);
+void             eekboard_context_show_keyboard  (EekboardContext *context,
+                                                  GCancellable    *cancellable);
+void             eekboard_context_hide_keyboard  (EekboardContext *context,
+                                                  GCancellable    *cancellable);
+void             eekboard_context_set_group      (EekboardContext *context,
+                                                  gint             group,
+                                                  GCancellable    *cancellable);
+void             eekboard_context_press_key      (EekboardContext *context,
+                                                  guint            keycode,
+                                                  GCancellable    *cancellable);
+void             eekboard_context_release_key    (EekboardContext *context,
+                                                  guint            keycode,
+                                                  GCancellable    *cancellable);
 gboolean         eekboard_context_is_keyboard_visible
-                                                (EekboardContext *context);
-void             eekboard_context_set_enabled   (EekboardContext *context,
-                                                 gboolean         enabled);
-gboolean         eekboard_context_is_enabled    (EekboardContext *context);
+                                                 (EekboardContext *context);
+void             eekboard_context_set_enabled    (EekboardContext *context,
+                                                  gboolean         enabled);
+gboolean         eekboard_context_is_enabled     (EekboardContext *context);
+void             eekboard_context_set_fullscreen (EekboardContext *context,
+                                                  gboolean         fullscreen,
+                                                  GCancellable    *cancellable);
 
 G_END_DECLS
 #endif  /* EEKBOARD_CONTEXT_H */
diff --git a/src/desktop-client-main.c b/src/desktop-client-main.c
index 9f4c889c..7b47d8be 100644
--- a/src/desktop-client-main.c
+++ b/src/desktop-client-main.c
@@ -40,6 +40,8 @@ static gchar *opt_model = NULL;
 static gchar *opt_layouts = NULL;
 static gchar *opt_options = NULL;
 
+static gboolean opt_fullscreen = FALSE;
+
 static const GOptionEntry options[] = {
     {"system", 'y', 0, G_OPTION_ARG_NONE, &opt_system,
      N_("Connect to the system bus")},
@@ -59,6 +61,8 @@ static const GOptionEntry options[] = {
      N_("Specify layouts")},
     {"options", '\0', 0, G_OPTION_ARG_STRING, &opt_options,
      N_("Specify options")},
+    {"fullscreen", 'F', 0, G_OPTION_ARG_NONE, &opt_fullscreen,
+     N_("Create window in fullscreen mode")},
     {NULL}
 };
 
@@ -224,6 +228,12 @@ main (int argc, char **argv)
         g_object_unref (context);
     }
 
+    if (opt_fullscreen) {
+        g_object_get (client, "context", &context, NULL);
+        eekboard_context_set_fullscreen (context, TRUE, NULL);
+        g_object_unref (context);
+    }
+
     g_object_get (client, "eekboard", &eekboard, NULL);
     g_signal_connect (eekboard, "destroyed",
                       G_CALLBACK(on_destroyed), loop);
diff --git a/src/server-context.c b/src/server-context.c
index 59d9e682..bee86b57 100644
--- a/src/server-context.c
+++ b/src/server-context.c
@@ -56,6 +56,9 @@ static const gchar introspection_xml[] =
     "    "
     "      "
     "    "
+    "    "
+    "      "
+    "    "
     "    "
     "    "
     "    "
@@ -94,6 +97,7 @@ struct _ServerContext {
 
     gboolean enabled;
     gboolean last_keyboard_visible;
+    gboolean fullscreen;
 
     GtkWidget *window;
     GtkWidget *widget;
@@ -189,20 +193,61 @@ on_realize (GtkWidget *widget,
                               GDK_FUNC_MOVE |
                               GDK_FUNC_MINIMIZE |
                               GDK_FUNC_CLOSE);
-
-    gtk_window_set_opacity (GTK_WINDOW(context->window), 0.9);
 }
 
 #define DEFAULT_THEME (THEMEDIR "/default.css")
 
 static void
-update_widget (ServerContext *context)
+set_geometry (ServerContext *context)
 {
     GdkScreen *screen;
     GdkWindow *root;
     gint monitor;
     GdkRectangle rect;
     EekBounds bounds;
+
+    screen = gdk_screen_get_default ();
+    root = gtk_widget_get_root_window (context->window);
+    monitor = gdk_screen_get_monitor_at_window (screen, root);
+    gdk_screen_get_monitor_geometry (screen, monitor, &rect);
+    eek_element_get_bounds (EEK_ELEMENT(context->keyboard), &bounds);
+
+    if (context->fullscreen) {
+        gtk_window_set_decorated (GTK_WINDOW(context->window), FALSE);
+        gtk_widget_set_size_request (context->widget,
+                                     rect.width,
+                                     rect.height / 2);
+        gtk_window_move (GTK_WINDOW(context->window),
+                         0,
+                         rect.height / 2);
+        gtk_window_set_opacity (GTK_WINDOW(context->window), 0.8);
+    } else {
+#if HAVE_CLUTTER_GTK
+        ClutterActor *stage =
+            gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED(context->widget));
+        clutter_stage_set_user_resizable (CLUTTER_STAGE(stage), TRUE);
+        clutter_stage_set_minimum_size (CLUTTER_STAGE(stage),
+                                        bounds.width / 3,
+                                        bounds.height / 3);
+        g_signal_connect (stage,
+                          "allocation-changed",
+                          G_CALLBACK(on_allocation_changed),
+                          actor);
+#else
+        gtk_widget_set_size_request (context->widget,
+                                     bounds.width,
+                                     bounds.height);
+#endif
+        gtk_window_move (GTK_WINDOW(context->window),
+                         MAX(rect.width - 20 - bounds.width, 0),
+                         MAX(rect.height - 40 - bounds.height, 0));
+    }
+}
+
+static void
+update_widget (ServerContext *context)
+{
+    EekBounds bounds;
     EekTheme *theme;
 #if HAVE_CLUTTER_GTK
     ClutterActor *stage, *actor;
@@ -223,20 +268,11 @@ update_widget (ServerContext *context)
     clutter_container_add_actor (CLUTTER_CONTAINER(stage), actor);
 
     clutter_stage_set_color (CLUTTER_STAGE(stage), &stage_color);
-    clutter_stage_set_user_resizable (CLUTTER_STAGE(stage), TRUE);
-    clutter_stage_set_minimum_size (CLUTTER_STAGE(stage),
-                                    bounds.width / 3,
-                                    bounds.height / 3);
-    g_signal_connect (stage,
-                      "allocation-changed",
-                      G_CALLBACK(on_allocation_changed),
-                      actor);
 #else
     context->widget = eek_gtk_keyboard_new (context->keyboard);
     if (theme)
         eek_gtk_keyboard_set_theme (EEK_GTK_KEYBOARD(context->widget), theme);
 #endif
-    gtk_widget_set_size_request (context->widget, bounds.width, bounds.height);
 
     if (!context->window) {
         context->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
@@ -251,18 +287,11 @@ update_widget (ServerContext *context)
         gtk_window_set_title (GTK_WINDOW(context->window), _("Keyboard"));
         gtk_window_set_icon_name (GTK_WINDOW(context->window), "eekboard");
         gtk_window_set_keep_above (GTK_WINDOW(context->window), TRUE);
-        gtk_window_set_decorated (GTK_WINDOW(context->window), FALSE);
 
         g_signal_connect (context->window, "realize",
                           G_CALLBACK(on_realize), context);
 
-        screen = gdk_screen_get_default ();
-        root = gtk_widget_get_root_window (context->window);
-        monitor = gdk_screen_get_monitor_at_window (screen, root);
-        gdk_screen_get_monitor_geometry (screen, monitor, &rect);
-        gtk_window_move (GTK_WINDOW(context->window),
-                         MAX(rect.width - 20 - bounds.width, 0),
-                         MAX(rect.height - 40 - bounds.height, 0));
+        set_geometry (context);
     }
     gtk_container_add (GTK_CONTAINER(context->window), context->widget);
 }
@@ -593,6 +622,22 @@ handle_method_call (GDBusConnection       *connection,
         return;
     }
 
+    if (g_strcmp0 (method_name, "SetFullscreen") == 0) {
+        gboolean fullscreen;
+
+        g_variant_get (parameters, "(b)", &fullscreen);
+
+        if (context->fullscreen == fullscreen) {
+            g_dbus_method_invocation_return_value (invocation, NULL);
+            return;
+        }
+        context->fullscreen = fullscreen;
+        set_geometry (context);
+
+        g_dbus_method_invocation_return_value (invocation, NULL);
+        return;
+    }
+
     if (g_strcmp0 (method_name, "SetGroup") == 0) {
         gint group;