Also make Done button use two cells in the grid because BaseWindow's navigation area has now three rows instead of two (layout indicator added) and the "Done" button should be centered between the second and the third rows.
Also use taller PNG for the spoke header.
Signed-off-by: Vratislav Podzimek vpodzime@redhat.com --- data/pixmaps/anaconda_spoke_header.png | Bin 185 -> 183 bytes widgets/src/BaseWindow.c | 15 +++++- widgets/src/LayoutIndicator.c | 96 +++++++++++++++++++-------------- widgets/src/LayoutIndicator.h | 7 +++ widgets/src/SpokeWindow.c | 4 +- 5 files changed, 80 insertions(+), 42 deletions(-)
diff --git a/data/pixmaps/anaconda_spoke_header.png b/data/pixmaps/anaconda_spoke_header.png index f1feefc..492be50 100644 Binary files a/data/pixmaps/anaconda_spoke_header.png and b/data/pixmaps/anaconda_spoke_header.png differ diff --git a/widgets/src/BaseWindow.c b/widgets/src/BaseWindow.c index 7493ca4..8c285b7 100644 --- a/widgets/src/BaseWindow.c +++ b/widgets/src/BaseWindow.c @@ -21,6 +21,7 @@ #include <stdlib.h> #include <string.h>
+#include "LayoutIndicator.h" #include "BaseWindow.h" #include "intl.h"
@@ -85,6 +86,7 @@ enum { #define DEFAULT_DISTRIBUTION N_("DISTRIBUTION INSTALLATION") #define DEFAULT_WINDOW_NAME N_("SPOKE NAME") #define DEFAULT_BETA N_("PRE-RELEASE / TESTING") +#define LAYOUT_INDICATOR_LABEL_WIDTH 10
struct _AnacondaBaseWindowPrivate { gboolean is_beta, info_shown; @@ -92,6 +94,7 @@ struct _AnacondaBaseWindowPrivate { GtkWidget *alignment; GtkWidget *nav_box, *nav_area, *action_area; GtkWidget *name_label, *distro_label, *beta_label; + GtkWidget *layout_indicator;
/* Untranslated versions of various things. */ gchar *orig_name, *orig_distro, *orig_beta; @@ -267,7 +270,7 @@ static void anaconda_base_window_init(AnacondaBaseWindow *win) {
/* Create the beta label. */ win->priv->beta_label = gtk_label_new(NULL); - markup = g_markup_printf_escaped("<span foreground='red' weight='bold' size='large'>%s</span>", _(DEFAULT_BETA)); + markup = g_markup_printf_escaped("<span foreground='red' weight='bold' size='medium'>%s</span>", _(DEFAULT_BETA)); gtk_label_set_markup(GTK_LABEL(win->priv->beta_label), markup); g_free(markup); gtk_misc_set_alignment(GTK_MISC(win->priv->beta_label), 0, 0); @@ -275,10 +278,20 @@ static void anaconda_base_window_init(AnacondaBaseWindow *win) {
win->priv->orig_beta = g_strdup(DEFAULT_BETA);
+ /* Create the layout indicator */ + win->priv->layout_indicator = anaconda_layout_indicator_new(); + anaconda_layout_indicator_set_label_width(ANACONDA_LAYOUT_INDICATOR(win->priv->layout_indicator), + LAYOUT_INDICATOR_LABEL_WIDTH); + gtk_widget_set_halign(win->priv->layout_indicator, GTK_ALIGN_CENTER); + gtk_widget_set_hexpand(win->priv->layout_indicator, FALSE); + gtk_widget_set_margin_top(win->priv->layout_indicator, 6); + gtk_widget_set_margin_bottom(win->priv->layout_indicator, 4); + /* Add everything to the nav area. */ gtk_grid_attach(GTK_GRID(win->priv->nav_area), win->priv->name_label, 0, 0, 1, 1); gtk_grid_attach(GTK_GRID(win->priv->nav_area), win->priv->distro_label, 1, 0, 1, 1); gtk_grid_attach(GTK_GRID(win->priv->nav_area), win->priv->beta_label, 1, 1, 1, 1); + gtk_grid_attach(GTK_GRID(win->priv->nav_area), win->priv->layout_indicator, 1, 2, 1, 1); }
static void anaconda_base_window_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { diff --git a/widgets/src/LayoutIndicator.c b/widgets/src/LayoutIndicator.c index 1ae7432..5ac34c5 100644 --- a/widgets/src/LayoutIndicator.c +++ b/widgets/src/LayoutIndicator.c @@ -56,8 +56,9 @@ struct _AnacondaLayoutIndicatorPrivate { GtkWidget *icon; GtkLabel *layout_label; GdkCursor *cursor; - XklEngine *engine; XklConfigRec *config_rec; + gulong state_changed_handler_id; + gulong config_changed_handler_id; };
G_DEFINE_TYPE(AnacondaLayoutIndicator, anaconda_layout_indicator, GTK_TYPE_EVENT_BOX) @@ -65,7 +66,7 @@ G_DEFINE_TYPE(AnacondaLayoutIndicator, anaconda_layout_indicator, GTK_TYPE_EVENT static void anaconda_layout_indicator_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void anaconda_layout_indicator_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
-static void anaconda_layout_indicator_dispose(AnacondaLayoutIndicator *indicator); +static void anaconda_layout_indicator_dispose(GObject *indicator); static void anaconda_layout_indicator_realize(GtkWidget *widget, gpointer user_data);
static void anaconda_layout_indicator_clicked(GtkWidget *widget, GdkEvent *event, gpointer user_data); @@ -84,7 +85,7 @@ static void anaconda_layout_indicator_class_init(AnacondaLayoutIndicatorClass *k
object_class->get_property = anaconda_layout_indicator_get_property; object_class->set_property = anaconda_layout_indicator_set_property; - object_class->dispose = (GObjectFinalizeFunc) anaconda_layout_indicator_dispose; + object_class->dispose = anaconda_layout_indicator_dispose;
/** * AnacondaLayoutIndicator:layout: @@ -135,6 +136,26 @@ GtkWidget *anaconda_layout_indicator_new() { static void anaconda_layout_indicator_init(AnacondaLayoutIndicator *self) { GdkDisplay *display; GdkRGBA background_color = { 0.0, 0.0, 0.0, 0.0 }; + AnacondaLayoutIndicatorClass *klass = ANACONDA_LAYOUT_INDICATOR_GET_CLASS(self); + + if (!klass->engine) { + /* This code cannot go to class_init because that way it would be called + when GObject type system is initialized and Gdk won't give us the + display. Thus the first instance being created has to populate these + class-wide stuff */ + + /* initialize XklEngine instance that will be used by all LayoutIndicator instances */ + display = gdk_display_get_default(); + klass->engine = xkl_engine_get_instance(GDK_DISPLAY_XDISPLAY(display)); + + /* make XklEngine listening */ + xkl_engine_start_listen(klass->engine, XKLL_TRACK_KEYBOARD_STATE); + + /* hook up X events with XklEngine + * (passing NULL as the first argument means we want X events from all windows) + */ + gdk_window_add_filter(NULL, (GdkFilterFunc) handle_xevent, klass->engine); + }
g_return_if_fail(gdk_rgba_parse(&background_color, "#fdfdfd"));
@@ -167,30 +188,20 @@ static void anaconda_layout_indicator_init(AnacondaLayoutIndicator *self) { gtk_widget_override_background_color(GTK_WIDGET(self), GTK_STATE_FLAG_NORMAL, &background_color);
- /* initialize XklEngine and XklConfigRec instances providing signals and data */ - display = gdk_display_get_default(); - self->priv->engine = xkl_engine_get_instance(GDK_DISPLAY_XDISPLAY(display)); + /* initialize XklConfigRec instance providing data */ self->priv->config_rec = xkl_config_rec_new(); - xkl_config_rec_get_from_server(self->priv->config_rec, self->priv->engine); - - /* make XklEngine listening and hook up handler for its "X-state-changed" and - "X-config-changed" signals */ - xkl_engine_start_listen(self->priv->engine, XKLL_TRACK_KEYBOARD_STATE); - g_signal_connect(self->priv->engine, "X-state-changed", - G_CALLBACK(x_state_changed), - g_object_ref(self)); - g_signal_connect(self->priv->engine, "X-config-changed", - G_CALLBACK(x_config_changed), - g_object_ref(self)); - - /* - * hook up X events with XklEngine - * (passing NULL as the first argument means we want X events from all windows) - */ - gdk_window_add_filter(NULL, (GdkFilterFunc) handle_xevent, self->priv->engine); + xkl_config_rec_get_from_server(self->priv->config_rec, klass->engine);
- /* init layout item with the current layout */ - self->priv->layout = get_current_layout(self->priv->engine, self->priv->config_rec); + /* hook up handler for "X-state-changed" and "X-config-changed" signals */ + self->priv->state_changed_handler_id = g_signal_connect(klass->engine, "X-state-changed", + G_CALLBACK(x_state_changed), + g_object_ref(self)); + self->priv->config_changed_handler_id = g_signal_connect(klass->engine, "X-config-changed", + G_CALLBACK(x_config_changed), + g_object_ref(self)); + + /* init layout attribute with the current layout */ + self->priv->layout = get_current_layout(klass->engine, self->priv->config_rec);
/* create layout label and set desired properties */ self->priv->layout_label = GTK_LABEL(gtk_label_new(NULL)); @@ -204,7 +215,8 @@ static void anaconda_layout_indicator_init(AnacondaLayoutIndicator *self) { anaconda_layout_indicator_refresh_ui_elements(self);
/* create the little keyboard icon and set its left margin */ - self->priv->icon = gtk_image_new_from_icon_name("input-keyboard-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR); + self->priv->icon = gtk_image_new_from_icon_name("input-keyboard-symbolic", + GTK_ICON_SIZE_SMALL_TOOLBAR);
/* create and populate the main box */ self->priv->main_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4)); @@ -219,9 +231,15 @@ static void anaconda_layout_indicator_init(AnacondaLayoutIndicator *self) { gtk_container_add(GTK_CONTAINER(self), GTK_WIDGET(self->priv->main_box)); }
-static void anaconda_layout_indicator_dispose(AnacondaLayoutIndicator *self) { - /* finalize X events listening and unref all objects we reference - (may be called multiple times) */ +static void anaconda_layout_indicator_dispose(GObject *object) { + AnacondaLayoutIndicator *self = ANACONDA_LAYOUT_INDICATOR(object); + AnacondaLayoutIndicatorClass *klass = ANACONDA_LAYOUT_INDICATOR_GET_CLASS(self); + + /* disconnect signals (XklEngine will outlive us) */ + g_signal_handler_disconnect(klass->engine, self->priv->state_changed_handler_id); + g_signal_handler_disconnect(klass->engine, self->priv->config_changed_handler_id); + + /* unref all objects we reference (may be called multiple times) */ if (self->priv->layout_label) { gtk_widget_destroy(GTK_WIDGET(self->priv->layout_label)); self->priv->layout_label = NULL; @@ -230,12 +248,6 @@ static void anaconda_layout_indicator_dispose(AnacondaLayoutIndicator *self) { g_object_unref(self->priv->cursor); self->priv->cursor = NULL; } - if (self->priv->engine) { - xkl_engine_stop_listen(self->priv->engine, XKLL_TRACK_KEYBOARD_STATE); - gdk_window_remove_filter(NULL, (GdkFilterFunc) handle_xevent, self->priv->engine); - g_object_unref(self->priv->engine); - self->priv->engine = NULL; - } if (self->priv->config_rec) { g_object_unref(self->priv->config_rec); self->priv->config_rec = NULL; @@ -282,18 +294,19 @@ static void anaconda_layout_indicator_set_property(GObject *object, guint prop_i
static void anaconda_layout_indicator_clicked(GtkWidget *widget, GdkEvent *event, gpointer data) { AnacondaLayoutIndicator *self = ANACONDA_LAYOUT_INDICATOR(widget); + AnacondaLayoutIndicatorClass *klass = ANACONDA_LAYOUT_INDICATOR_GET_CLASS(self);
if (event->type != GDK_BUTTON_RELEASE) return;
- XklState *state = xkl_engine_get_current_state(self->priv->engine); - guint n_groups = xkl_engine_get_num_groups(self->priv->engine); + XklState *state = xkl_engine_get_current_state(klass->engine); + guint n_groups = xkl_engine_get_num_groups(klass->engine);
/* cycle over groups */ guint next_group = (state->group + 1) % n_groups;
/* activate next group */ - xkl_engine_lock_group(self->priv->engine, next_group); + xkl_engine_lock_group(klass->engine, next_group); }
static void anaconda_layout_indicator_refresh_ui_elements(AnacondaLayoutIndicator *self) { @@ -310,8 +323,10 @@ static void anaconda_layout_indicator_refresh_ui_elements(AnacondaLayoutIndicato }
static void anaconda_layout_indicator_refresh_layout(AnacondaLayoutIndicator *self) { + AnacondaLayoutIndicatorClass *klass = ANACONDA_LAYOUT_INDICATOR_GET_CLASS(self); + g_free(self->priv->layout); - self->priv->layout = get_current_layout(self->priv->engine, self->priv->config_rec); + self->priv->layout = get_current_layout(klass->engine, self->priv->config_rec);
anaconda_layout_indicator_refresh_ui_elements(self); } @@ -373,9 +388,10 @@ static void x_state_changed(XklEngine *engine, XklEngineStateChange type, static void x_config_changed(XklEngine *engine, gpointer data) { g_return_if_fail(data); AnacondaLayoutIndicator *indicator = ANACONDA_LAYOUT_INDICATOR(data); + AnacondaLayoutIndicatorClass *klass = ANACONDA_LAYOUT_INDICATOR_GET_CLASS(indicator);
/* load current configuration from the X server */ - xkl_config_rec_get_from_server(indicator->priv->config_rec, indicator->priv->engine); + xkl_config_rec_get_from_server(indicator->priv->config_rec, klass->engine);
anaconda_layout_indicator_refresh_layout(indicator); } diff --git a/widgets/src/LayoutIndicator.h b/widgets/src/LayoutIndicator.h index c679186..82694e6 100644 --- a/widgets/src/LayoutIndicator.h +++ b/widgets/src/LayoutIndicator.h @@ -21,6 +21,7 @@ #define _LAYOUT_INDICATOR_H
#include <gtk/gtk.h> +#include <libxklavier/xklavier.h>
G_BEGIN_DECLS
@@ -53,9 +54,15 @@ struct _AnacondaLayoutIndicator { * the widget class structure in order for the class mechanism * to work correctly. This allows an AnacondaLayoutIndicatorClass * pointer to be cast to a #GtkEventBox pointer. + * @engine: A singleton XklEngine instance that is used by all instances of + * LayoutIndicator. */ struct _AnacondaLayoutIndicatorClass { GtkEventBoxClass parent_class; + + /* this has to be a class attribute, because XklEngine is a singleton that + should be used by all instances */ + XklEngine *engine; };
GType anaconda_layout_indicator_get_type (void); diff --git a/widgets/src/SpokeWindow.c b/widgets/src/SpokeWindow.c index 9c1ae47..5cdec4a 100644 --- a/widgets/src/SpokeWindow.c +++ b/widgets/src/SpokeWindow.c @@ -144,6 +144,8 @@ static void anaconda_spoke_window_init(AnacondaSpokeWindow *win) { /* Create the button. */ win->priv->button = gtk_button_new_with_mnemonic(DEFAULT_BUTTON_LABEL); gtk_widget_set_halign(win->priv->button, GTK_ALIGN_START); + gtk_widget_set_vexpand(win->priv->button, FALSE); + gtk_widget_set_valign(win->priv->button, GTK_ALIGN_CENTER);
/* Hook up some signals for that button. The signal handlers here will * just raise our own custom signals for the whole window. @@ -153,7 +155,7 @@ static void anaconda_spoke_window_init(AnacondaSpokeWindow *win) {
/* And then put the button into the navigation area. */ nav_area = anaconda_base_window_get_nav_area(ANACONDA_BASE_WINDOW(win)); - gtk_grid_attach(GTK_GRID(nav_area), win->priv->button, 0, 1, 1, 1); + gtk_grid_attach(GTK_GRID(nav_area), win->priv->button, 0, 1, 1, 2); }
static void anaconda_spoke_window_realize(GtkWidget *widget, gpointer user_data) {