[libgnomekbd] Multiple fixes: pango, subscripts etc



commit 342b82bfd0308275618180652dc56e7d9b663642
Author: Sergey V. Udaltsov <svu gnome org>
Date:   Sun Mar 28 23:56:40 2010 +0100

    Multiple fixes: pango, subscripts etc
    
    The label rendering changed from 'toy' API in cairo to proper
    pango-cairo usage.
    https://bugzilla.gnome.org/show_bug.cgi?id=612371 (partially, no change
    handling yet)
    
    The subscripts are used for variants of the same layout,
    https://bugzilla.gnome.org/show_bug.cgi?id=613853

 libgnomekbd/gkbd-indicator.c |  198 +++++++++++++++++++++++-------------------
 libgnomekbd/gkbd-status.c    |  168 ++++++++++++++++++++++++++---------
 2 files changed, 234 insertions(+), 132 deletions(-)
---
diff --git a/libgnomekbd/gkbd-indicator.c b/libgnomekbd/gkbd-indicator.c
index 17162a6..5def369 100644
--- a/libgnomekbd/gkbd-indicator.c
+++ b/libgnomekbd/gkbd-indicator.c
@@ -273,6 +273,9 @@ flag_exposed (GtkWidget * flag, GdkEventExpose * event, GdkPixbuf * image)
 	int ih = gdk_pixbuf_get_height (image);
 	GtkAllocation allocation;
 	gboolean scaling_needed;
+	double xwiratio, ywiratio, wiratio;
+	int sw, sh, ox, oy;
+	GdkPixbuf *scaled;
 
 	gtk_widget_get_allocation (flag, &allocation);
 	scaling_needed =
@@ -281,19 +284,19 @@ flag_exposed (GtkWidget * flag, GdkEventExpose * event, GdkPixbuf * image)
 	      (allocation.width >= iw && allocation.height == ih));
 
 	/* widget-to-image scales, X and Y */
-	double xwiratio = 1.0 * allocation.width / iw;
-	double ywiratio = 1.0 * allocation.height / ih;
-	double wiratio = xwiratio < ywiratio ? xwiratio : ywiratio;
+	xwiratio = 1.0 * allocation.width / iw;
+	ywiratio = 1.0 * allocation.height / ih;
+	wiratio = xwiratio < ywiratio ? xwiratio : ywiratio;
 
 	/* scaled width and height */
-	int sw = iw * wiratio;
-	int sh = ih * wiratio;
+	sw = iw * wiratio;
+	sh = ih * wiratio;
 
 	/* offsets */
-	int ox = (allocation.width - sw) >> 1;
-	int oy = (allocation.height - sh) >> 1;
+	ox = (allocation.width - sw) >> 1;
+	oy = (allocation.height - sh) >> 1;
 
-	GdkPixbuf *scaled =
+	scaled =
 	    scaling_needed ? gdk_pixbuf_scale_simple (image, sw, sh,
 						      GDK_INTERP_HYPER) :
 	    image;
@@ -309,6 +312,89 @@ flag_exposed (GtkWidget * flag, GdkEventExpose * event, GdkPixbuf * image)
 		g_object_unref (G_OBJECT (scaled));
 }
 
+gchar *
+gkbd_indicator_extract_layout_name (int group, XklEngine * engine,
+				    GkbdKeyboardConfig * kbd_cfg,
+				    gchar ** short_group_names,
+				    gchar ** full_group_names)
+{
+	char *layout_name;
+	if (group < g_strv_length (short_group_names)) {
+		if (xkl_engine_get_features (engine) &
+		    XKLF_MULTIPLE_LAYOUTS_SUPPORTED) {
+			char *full_layout_name = (char *)
+			    g_slist_nth_data (kbd_cfg->layouts_variants,
+					      group);
+			char *variant_name;
+			if (!gkbd_keyboard_config_split_items
+			    (full_layout_name, &layout_name,
+			     &variant_name))
+				/* just in case */
+				layout_name = full_layout_name;
+
+			/* make it freeable */
+			layout_name = g_strdup (layout_name);
+
+			if (short_group_names != NULL) {
+				char *short_group_name =
+				    short_group_names[group];
+				if (short_group_name != NULL
+				    && *short_group_name != '\0') {
+					/* drop the long name */
+					g_free (layout_name);
+					layout_name =
+					    g_strdup (short_group_name);
+				}
+			}
+		} else {
+			layout_name = g_strdup (full_group_names[group]);
+		}
+	}
+
+	if (layout_name == NULL)
+		layout_name = g_strdup ("??");
+
+	return layout_name;
+}
+
+gchar *
+gkbd_indicator_create_label_title (int group, GHashTable ** ln2cnt_map,
+				   gchar * layout_name)
+{
+	gpointer pcounter = NULL;
+	char *prev_layout_name = NULL;
+	char *lbl_title = NULL;
+	int counter = 0;
+
+	if (group == 0) {
+		*ln2cnt_map =
+		    g_hash_table_new_full (g_str_hash, g_str_equal,
+					   g_free, NULL);
+	}
+
+	/* Process layouts with repeating description */
+	if (g_hash_table_lookup_extended
+	    (*ln2cnt_map, layout_name, (gpointer *) & prev_layout_name,
+	     &pcounter)) {
+		/* "next" same description */
+		gchar appendix[10] = "";
+		gint utf8length;
+		gunichar cidx;
+		counter = GPOINTER_TO_INT (pcounter);
+		/* Unicode subscript 2, 3, 4 */
+		cidx = 0x2081 + counter;
+		utf8length = g_unichar_to_utf8 (cidx, appendix);
+		appendix[utf8length] = '\0';
+		lbl_title = g_strconcat (layout_name, appendix, NULL);
+	} else {
+		/* "first" time this description */
+		lbl_title = g_strdup (layout_name);
+	}
+	g_hash_table_insert (*ln2cnt_map, layout_name,
+			     GINT_TO_POINTER (counter + 1));
+	return lbl_title;
+}
+
 static GtkWidget *
 gkbd_indicator_prepare_drawing (GkbdIndicator * gki, int group)
 {
@@ -331,96 +417,32 @@ gkbd_indicator_prepare_drawing (GkbdIndicator * gki, int group)
 				  G_CALLBACK (flag_exposed), image);
 		gtk_container_add (GTK_CONTAINER (ebox), flag);
 	} else {
-		gpointer pcounter = NULL;
-		char *prev_layout_name = NULL, **ppln;
 		char *lbl_title = NULL;
-		int counter = 0;
 		char *layout_name = NULL;
 		GtkWidget *align, *label;
-		/**
-		 * Map "short desciption" -> 
-		 * number of layouts in the configuration 
-		 * having this short description
-		 */
-		static GHashTable *short_descrs = NULL;
-
-		if (group == 0)
-			short_descrs =
-			    g_hash_table_new_full (g_str_hash, g_str_equal,
-						   g_free, NULL);
-
-
-		if (group < g_strv_length (globals.short_group_names)) {
-			if (xkl_engine_get_features (globals.engine) &
-			    XKLF_MULTIPLE_LAYOUTS_SUPPORTED) {
-				char *full_layout_name = (char *)
-				    g_slist_nth_data (globals.kbd_cfg.
-						      layouts_variants,
-						      group);
-				char *variant_name;
-				if (!gkbd_keyboard_config_split_items
-				    (full_layout_name, &layout_name,
-				     &variant_name))
-					/* just in case */
-					layout_name = full_layout_name;
-
-				/* make it freeable */
-				layout_name = g_strdup (layout_name);
-
-				if (globals.short_group_names != NULL) {
-					char *short_group_name =
-					    globals.short_group_names
-					    [group];
-					if (short_group_name != NULL
-					    && *short_group_name != '\0') {
-						/* drop the long name */
-						g_free (layout_name);
-						layout_name =
-						    g_strdup
-						    (short_group_name);
-					}
-				}
-			} else {
-				layout_name =
-				    g_strdup (globals.full_group_names
-					      [group]);
-			}
-		}
+		static GHashTable *ln2cnt_map = NULL;
 
-		if (layout_name == NULL)
-			layout_name = g_strdup ("??");
-
-		/* Process layouts with repeating description */
-		ppln = &prev_layout_name;
-		if (g_hash_table_lookup_extended
-		    (short_descrs, layout_name,
-		     (gpointer *) ppln, &pcounter)) {
-			/* "next" same description */
-			gchar appendix[10] = "";
-			gint utf8length;
-			gunichar cidx;
-			counter = GPOINTER_TO_INT (pcounter);
-			/* Unicode subscript 2, 3, 4 */
-			cidx = 0x2081 + counter;
-			utf8length = g_unichar_to_utf8 (cidx, appendix);
-			appendix[utf8length] = '\0';
-			lbl_title =
-			    g_strconcat (layout_name, appendix, NULL);
-		} else {
-			/* "first" time this description */
-			lbl_title = g_strdup (layout_name);
-		}
-		g_hash_table_insert (short_descrs, layout_name,
-				     GINT_TO_POINTER (counter + 1));
+		layout_name =
+		    gkbd_indicator_extract_layout_name (group,
+							globals.engine,
+							&globals.kbd_cfg,
+							globals.short_group_names,
+							globals.full_group_names);
+
+		lbl_title =
+		    gkbd_indicator_create_label_title (group,
+						       &ln2cnt_map,
+						       layout_name);
 
 		align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
 		label = gtk_label_new (lbl_title);
 		g_free (lbl_title);
 		gtk_label_set_angle (GTK_LABEL (label), gki->priv->angle);
 
-		if (group == xkl_engine_get_num_groups (globals.engine)) {
-			g_hash_table_destroy (short_descrs);
-			short_descrs = NULL;
+		if (group + 1 ==
+		    xkl_engine_get_num_groups (globals.engine)) {
+			g_hash_table_destroy (ln2cnt_map);
+			ln2cnt_map = NULL;
 		}
 
 		gtk_container_add (GTK_CONTAINER (align), label);
diff --git a/libgnomekbd/gkbd-status.c b/libgnomekbd/gkbd-status.c
index 2efb00f..eafdd17 100644
--- a/libgnomekbd/gkbd-status.c
+++ b/libgnomekbd/gkbd-status.c
@@ -43,7 +43,10 @@ typedef struct _gki_globals {
 	gchar **full_group_names;
 	gchar **short_group_names;
 
-	gint current_size;
+	gint current_width;
+	gint current_height;
+	int real_width;
+
 	GSList *icons;		/* list of GdkPixbuf */
 	GSList *widget_instances;	/* list of GkbdStatus */
 	gulong state_changed_handler;
@@ -122,12 +125,31 @@ gkbd_status_activate (GkbdStatus * gki)
 	gkbd_desktop_config_lock_next_group (&globals.cfg);
 }
 
+/* hackish xref */
+extern gchar *gkbd_indicator_extract_layout_name (int group,
+						  XklEngine * engine,
+						  GkbdKeyboardConfig *
+						  kbd_cfg,
+						  gchar **
+						  short_group_names,
+						  gchar **
+						  full_group_names);
+
+extern gchar *gkbd_indicator_create_label_title (int group,
+						 GHashTable **
+						 ln2cnt_map,
+						 gchar * layout_name);
+
 static void
 gkbd_status_render_cairo (cairo_t * cr, int group)
 {
-	cairo_text_extents_t te;
-	gchar *lbl = globals.short_group_names[group];
 	double r, g, b;
+	PangoFontDescription *pfd;
+	PangoContext *pcc;
+	PangoLayout *pl;
+	int lwidth, lheight;
+	gchar *layout_name, *lbl_title;
+	static GHashTable *ln2cnt_map = NULL;
 
 	if (globals.ind_cfg.background_color != NULL &&
 	    globals.ind_cfg.background_color[0] != 0) {
@@ -135,8 +157,8 @@ gkbd_status_render_cairo (cairo_t * cr, int group)
 		    (globals.ind_cfg.background_color, "%lg %lg %lg", &r,
 		     &g, &b) == 3) {
 			cairo_set_source_rgb (cr, r, g, b);
-			cairo_rectangle (cr, 0, 0, globals.current_size,
-					 globals.current_size);
+			cairo_rectangle (cr, 0, 0, globals.current_width,
+					 globals.current_height);
 			cairo_fill (cr);
 		}
 	}
@@ -157,19 +179,60 @@ gkbd_status_render_cairo (cairo_t * cr, int group)
 					CAIRO_FONT_WEIGHT_NORMAL);
 	}
 
-	if (globals.ind_cfg.font_size > 0) {
-		cairo_set_font_size (cr, globals.ind_cfg.font_size);
+	pfd = pango_font_description_new ();
+	pango_font_description_set_family (pfd,
+					   globals.ind_cfg.font_family);
+	pango_font_description_set_style (pfd, PANGO_STYLE_NORMAL);
+	pango_font_description_set_weight (pfd, PANGO_WEIGHT_NORMAL);
+	pango_font_description_set_size (pfd,
+					 globals.ind_cfg.font_size *
+					 PANGO_SCALE);
+
+	pcc = pango_cairo_create_context (cr);
+	pango_cairo_context_set_font_options (pcc,
+					      gdk_screen_get_font_options
+					      (gdk_screen_get_default ()));
+
+	pl = pango_layout_new (pcc);
+
+	layout_name = gkbd_indicator_extract_layout_name (group,
+							  globals.engine,
+							  &globals.kbd_cfg,
+							  globals.
+							  short_group_names,
+							  globals.
+							  full_group_names);
+	lbl_title =
+	    gkbd_indicator_create_label_title (group, &ln2cnt_map,
+					       layout_name);
+
+	if (group + 1 == xkl_engine_get_num_groups (globals.engine)) {
+		g_hash_table_destroy (ln2cnt_map);
+		ln2cnt_map = NULL;
 	}
 
-	cairo_text_extents (cr, lbl, &te);
+	pango_layout_set_text (pl, lbl_title, -1);
+
+	g_free(lbl_title);
+
+	pango_layout_set_font_description (pl, pfd);
+	pango_layout_get_size (pl, &lwidth, &lheight);
+
 	cairo_move_to (cr,
-		       (globals.current_size >> 1) - te.width / 2 -
-		       te.x_bearing,
-		       (globals.current_size >> 1) - te.height / 2 -
-		       te.y_bearing);
-	cairo_show_text (cr, lbl);
+		       (globals.current_width - lwidth / PANGO_SCALE) / 2,
+		       (globals.current_height -
+			lheight / PANGO_SCALE) / 2);
 
+	pango_cairo_show_layout (cr, pl);
+
+	pango_font_description_free (pfd);
+	g_object_unref (pl);
+	g_object_unref (pcc);
 	cairo_destroy (cr);
+
+	globals.real_width = (lwidth / PANGO_SCALE) + 4;
+	if (globals.real_width > globals.current_width)
+		globals.real_width = globals.current_width;
 }
 
 static inline guint8
@@ -180,24 +243,34 @@ convert_color_channel (guint8 src, guint8 alpha)
 
 static void
 convert_bgra_to_rgba (guint8 const *src, guint8 * dst, int width,
-		      int height)
+		      int height, int new_width)
 {
-	guint8 const *src_pixel = src;
+	int xoffset = width - new_width;
+
+	/* *4 */
+	int ptr_step = xoffset << 2;
+
+	/* / 2 * 4 */
+	guint8 const *src_pixel = src + ((xoffset >> 1) << 2);
+
 	guint8 *dst_pixel = dst;
 	int x, y;
 
-	for (y = 0; y < height; y++) {
-		for (x = 0; x < width; x++) {
+	for (y = height; --y >= 0; src_pixel += ptr_step) {
+		for (x = new_width; --x >= 0;) {
+			/* src is native-endian! */
+			gint isrc = *(gint *) src_pixel;
+			gint8 alpha = isrc >> 24;
+
 			dst_pixel[0] =
-			    convert_color_channel (src_pixel[2],
-						   src_pixel[3]);
+			    convert_color_channel (isrc & 0xFF, alpha);
 			dst_pixel[1] =
-			    convert_color_channel (src_pixel[1],
-						   src_pixel[3]);
+			    convert_color_channel ((isrc >> 8) & 0xFF,
+						   alpha);
 			dst_pixel[2] =
-			    convert_color_channel (src_pixel[0],
-						   src_pixel[3]);
-			dst_pixel[3] = src_pixel[3];
+			    convert_color_channel ((isrc >> 16) & 0xFF,
+						   alpha);
+			dst_pixel[3] = alpha;
 
 			dst_pixel += 4;
 			src_pixel += 4;
@@ -212,19 +285,20 @@ gkbd_status_prepare_drawing (GkbdStatus * gki, int group)
 	char *image_filename;
 	GdkPixbuf *image;
 
-	if (globals.current_size == 0)
+	if (globals.current_width == 0)
 		return NULL;
 
 	if (globals.ind_cfg.show_flags) {
 
 		image_filename =
-		    (char *) g_slist_nth_data (globals.
-					       ind_cfg.image_filenames,
-					       group);
+		    (char *) g_slist_nth_data (globals.ind_cfg.
+					       image_filenames, group);
 
 		image = gdk_pixbuf_new_from_file_at_size (image_filename,
-							  globals.current_size,
-							  globals.current_size,
+							  globals.
+							  current_width,
+							  globals.
+							  current_height,
 							  &gerror);
 
 		if (image == NULL) {
@@ -239,7 +313,8 @@ gkbd_status_prepare_drawing (GkbdStatus * gki, int group)
 								    NULL ?
 								    "Unknown"
 								    :
-								    gerror->message);
+								    gerror->
+								    message);
 			g_signal_connect (G_OBJECT (dialog), "response",
 					  G_CALLBACK (gtk_widget_destroy),
 					  NULL);
@@ -263,19 +338,20 @@ gkbd_status_prepare_drawing (GkbdStatus * gki, int group)
 	} else {
 		cairo_surface_t *cs =
 		    cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-						globals.current_size,
-						globals.current_size);
+						globals.current_width,
+						globals.current_height);
 		unsigned char *cairo_data;
 		guchar *pixbuf_data;
 		gkbd_status_render_cairo (cairo_create (cs), group);
 		cairo_data = cairo_image_surface_get_data (cs);
 		pixbuf_data =
 		    g_new0 (guchar,
-			    4 * globals.current_size *
-			    globals.current_size);
+			    4 * globals.real_width *
+			    globals.current_height);
 		convert_bgra_to_rgba (cairo_data, pixbuf_data,
-				      globals.current_size,
-				      globals.current_size);
+				      globals.current_width,
+				      globals.current_height,
+				      globals.real_width);
 
 #if 0
 		char pngfilename[20];
@@ -289,9 +365,10 @@ gkbd_status_prepare_drawing (GkbdStatus * gki, int group)
 						  GDK_COLORSPACE_RGB,
 						  TRUE,
 						  8,
-						  globals.current_size,
-						  globals.current_size,
-						  globals.current_size * 4,
+						  globals.real_width,
+						  globals.current_height,
+						  globals.real_width *
+						  4,
 						  (GdkPixbufDestroyNotify)
 						  g_free, NULL);
 		xkl_debug (150,
@@ -532,8 +609,9 @@ gkbd_status_stop_listen (void)
 static void
 gkbd_status_size_changed (GkbdStatus * gki, gint size)
 {
-	if (globals.current_size != size) {
-		globals.current_size = size;
+	if (globals.current_height != size) {
+		globals.current_height = size;
+		globals.current_width = size * 3 / 2;
 		gkbd_status_reinit_ui (gki);
 	}
 }
@@ -632,13 +710,15 @@ gkbd_status_global_term (void)
 	if (g_signal_handler_is_connected
 	    (globals.engine, globals.state_changed_handler)) {
 		g_signal_handler_disconnect (globals.engine,
-					     globals.state_changed_handler);
+					     globals.
+					     state_changed_handler);
 		globals.state_changed_handler = 0;
 	}
 	if (g_signal_handler_is_connected
 	    (globals.engine, globals.config_changed_handler)) {
 		g_signal_handler_disconnect (globals.engine,
-					     globals.config_changed_handler);
+					     globals.
+					     config_changed_handler);
 		globals.config_changed_handler = 0;
 	}
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]