summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2021-08-20 06:17:23 +0000
committerMatthias Clasen <mclasen@redhat.com>2021-08-20 06:17:23 +0000
commitdf6d8df3242d3e139df99dcccecf7ca9bbeed95d (patch)
tree2b8cf549112b8cae16915ec11ed03dbbd7e1f0f8
parent16fe854011956d477fad7047ab5db2aa29ffc04b (diff)
parenta1b49a7dc93d8e75af600bce27fa4edcc5961513 (diff)
downloadpango-df6d8df3242d3e139df99dcccecf7ca9bbeed95d.tar.gz
Merge branch 'block-cursor-fixes' into 'main'
pango-view: Change annotation handling See merge request GNOME/pango!417
-rw-r--r--pango/pango-layout.c33
-rw-r--r--tests/testmisc.c72
-rw-r--r--utils/viewer-pangocairo.c358
3 files changed, 320 insertions, 143 deletions
diff --git a/pango/pango-layout.c b/pango/pango-layout.c
index ee58243b..669410ee 100644
--- a/pango/pango-layout.c
+++ b/pango/pango-layout.c
@@ -2374,7 +2374,8 @@ pango_layout_index_to_pos (PangoLayout *layout,
int index,
PangoRectangle *pos)
{
- PangoRectangle logical_rect;
+ PangoRectangle line_logical_rect;
+ PangoRectangle run_logical_rect;
PangoLayoutIter iter;
PangoLayoutLine *layout_line = NULL;
int x_pos;
@@ -2393,10 +2394,10 @@ pango_layout_index_to_pos (PangoLayout *layout,
if (tmp_line->start_index > index)
{
- /* index is in the paragraph delim&iters, move to
+ /* index is in the paragraph delimiters, move to
* end of previous line
*
- * This shouldn’t occur in the first loop &iteration as the first
+ * This shouldn’t occur in the first loop iteration as the first
* line’s start_index should always be 0.
*/
g_assert (layout_line != NULL);
@@ -2404,24 +2405,28 @@ pango_layout_index_to_pos (PangoLayout *layout,
break;
}
+ pango_layout_iter_get_line_extents (&iter, NULL, &line_logical_rect);
+
layout_line = tmp_line;
- if (layout_line->start_index + layout_line->length > index)
+ if (layout_line->start_index + layout_line->length >= index)
{
- while (TRUE)
+ do
{
PangoLayoutRun *run = _pango_layout_iter_get_run (&iter);
- pango_layout_iter_get_run_extents (&iter, NULL, &logical_rect);
+ pango_layout_iter_get_run_extents (&iter, NULL, &run_logical_rect);
- if (run->item->offset <= index && index < run->item->offset + run->item->length)
+ if (!run)
break;
- if (!pango_layout_iter_next_run (&iter))
+ if (run->item->offset <= index && index < run->item->offset + run->item->length)
break;
- }
+ }
+ while (pango_layout_iter_next_run (&iter));
- break;
+ if (layout_line->start_index + layout_line->length > index)
+ break;
}
if (!pango_layout_iter_next_line (&iter))
@@ -2431,16 +2436,16 @@ pango_layout_index_to_pos (PangoLayout *layout,
}
}
- pos->y = logical_rect.y;
- pos->height = logical_rect.height;
+ pos->y = run_logical_rect.y;
+ pos->height = run_logical_rect.height;
pango_layout_line_index_to_x (layout_line, index, 0, &x_pos);
- pos->x = logical_rect.x + x_pos;
+ pos->x = line_logical_rect.x + x_pos;
if (index < layout_line->start_index + layout_line->length)
{
pango_layout_line_index_to_x (layout_line, index, 1, &x_pos);
- pos->width = (logical_rect.x + x_pos) - pos->x;
+ pos->width = (line_logical_rect.x + x_pos) - pos->x;
}
else
pos->width = 0;
diff --git a/tests/testmisc.c b/tests/testmisc.c
index 8ebfec80..da24388b 100644
--- a/tests/testmisc.c
+++ b/tests/testmisc.c
@@ -418,6 +418,77 @@ test_index_to_x (void)
g_object_unref (context);
}
+static gboolean
+pango_rectangle_contains (const PangoRectangle *r1,
+ const PangoRectangle *r2)
+{
+ return r2->x >= r1->x &&
+ r2->y >= r1->y &&
+ r2->x + r2->width <= r1->x + r1->width &&
+ r2->y + r2->height <= r1->y + r1->height;
+}
+
+static void
+test_extents (void)
+{
+ PangoContext *context;
+ const char *tests[] = {
+ "Some long text that has multiple lines that are wrapped by Pango."
+ };
+
+ context = pango_font_map_create_context (pango_cairo_font_map_get_default ());
+
+ for (int i = 0; i < G_N_ELEMENTS (tests); i++)
+ {
+ PangoLayout *layout;
+ PangoLayoutIter *iter;
+ PangoRectangle layout_extents;
+ PangoRectangle line_extents;
+ PangoRectangle run_extents;
+ PangoRectangle cluster_extents;
+ PangoRectangle char_extents;
+ PangoRectangle pos;
+
+ layout = pango_layout_new (context);
+ pango_layout_set_text (layout, tests[i], -1);
+ pango_layout_set_width (layout, 60 * PANGO_SCALE);
+
+ pango_layout_get_extents (layout, NULL, &layout_extents);
+
+ iter = pango_layout_get_iter (layout);
+
+ do
+ {
+ pango_layout_iter_get_line_extents (iter, NULL, &line_extents);
+ pango_layout_iter_get_run_extents (iter, NULL, &run_extents);
+ pango_layout_iter_get_cluster_extents (iter, NULL, &cluster_extents);
+ pango_layout_iter_get_char_extents (iter, &char_extents);
+
+ pango_layout_index_to_pos (layout,
+ pango_layout_iter_get_index (iter),
+ &pos);
+ if (pos.width < 0)
+ {
+ pos.x += pos.width;
+ pos.width = - pos.width;
+ }
+
+ g_assert_true (pango_rectangle_contains (&layout_extents, &line_extents));
+ g_assert_true (pango_rectangle_contains (&line_extents, &run_extents));
+ g_assert_true (pango_rectangle_contains (&run_extents, &cluster_extents));
+ g_assert_true (pango_rectangle_contains (&cluster_extents, &char_extents));
+
+ g_assert_true (pango_rectangle_contains (&line_extents, &pos));
+ }
+ while (pango_layout_iter_next_char (iter));
+
+ pango_layout_iter_free (iter);
+ g_object_unref (layout);
+ }
+
+ g_object_unref (context);
+}
+
int
main (int argc, char *argv[])
{
@@ -442,6 +513,7 @@ main (int argc, char *argv[])
g_test_add_func ("/bidi/get-cursor-crash", test_get_cursor_crash);
g_test_add_func ("/bidi/get-cursor", test_get_cursor);
g_test_add_func ("/layout/index-to-x", test_index_to_x);
+ g_test_add_func ("/layout/extents", test_extents);
return g_test_run ();
}
diff --git a/utils/viewer-pangocairo.c b/utils/viewer-pangocairo.c
index ac3b49c3..77201666 100644
--- a/utils/viewer-pangocairo.c
+++ b/utils/viewer-pangocairo.c
@@ -148,20 +148,32 @@ pangocairo_view_destroy_surface (gpointer instance,
g_slice_free (CairoSurface, surface);
}
+enum {
+ ANNOTATE_GRAVITY_ROOF = 1,
+ ANNOTATE_BLOCK_PROGRESSION = 2,
+ ANNOTATE_BASELINES = 4,
+ ANNOTATE_LAYOUT_EXTENTS = 8,
+ ANNOTATE_LINE_EXTENTS = 16,
+ ANNOTATE_RUN_EXTENTS = 32,
+ ANNOTATE_CLUSTER_EXTENTS = 64,
+ ANNOTATE_CHAR_EXTENTS = 128,
+ ANNOTATE_LAST = 256,
+};
+
static void
render_callback (PangoLayout *layout,
- int x,
- int y,
- gpointer context,
- gpointer state)
+ int x,
+ int y,
+ gpointer context,
+ gpointer state)
{
cairo_t *cr = (cairo_t *) context;
- int annotate = (GPOINTER_TO_INT (state) + opt_annotate) % 4;
+ int annotate = (GPOINTER_TO_INT (state) + opt_annotate) % ANNOTATE_LAST;
cairo_save (cr);
cairo_translate (cr, x, y);
- if (annotate)
+ if (annotate != 0)
{
cairo_pattern_t *pattern;
PangoRectangle ink, logical;
@@ -170,127 +182,135 @@ render_callback (PangoLayout *layout,
pango_layout_get_extents (layout, &ink, &logical);
- if (annotate >= 2)
+ if (annotate & ANNOTATE_GRAVITY_ROOF)
+ {
+ /* draw resolved gravity "roof" in blue */
+ cairo_save (cr);
+ cairo_translate (cr,
+ (double)logical.x / PANGO_SCALE,
+ (double)logical.y / PANGO_SCALE);
+ cairo_scale (cr,
+ (double)logical.width / PANGO_SCALE * 0.5,
+ (double)logical.height / PANGO_SCALE * 0.5);
+ cairo_translate (cr, 1.0, 1.0);
+ cairo_rotate (cr,
+ pango_gravity_to_rotation (
+ pango_context_get_gravity (
+ pango_layout_get_context (layout))));
+ cairo_move_to (cr, -1.0, -1.0);
+ cairo_rel_line_to (cr, +1.0, -0.2); /* / */
+ cairo_rel_line_to (cr, +1.0, +0.2); /* \ */
+ cairo_close_path (cr); /* - */
+ pattern = cairo_pattern_create_linear (0, -1.0, 0, -1.2);
+ cairo_pattern_add_color_stop_rgba (pattern, 0.0, 0.0, 0.0, 1.0, 0.0);
+ cairo_pattern_add_color_stop_rgba (pattern, 1.0, 0.0, 0.0, 1.0, 0.15);
+ cairo_set_source (cr, pattern);
+ cairo_fill (cr);
+ /* once more, without close_path this time */
+ cairo_move_to (cr, -1.0, -1.0);
+ cairo_rel_line_to (cr, +1.0, -0.2); /* / */
+ cairo_rel_line_to (cr, +1.0, +0.2); /* \ */
+ /* silly line_width is not locked :(. get rid of scale. */
+ cairo_restore (cr);
+ cairo_save (cr);
+ cairo_set_source_rgba (cr, 0.0, 0.0, 0.7, 0.2);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+ }
+
+ if (annotate & ANNOTATE_BLOCK_PROGRESSION)
+ {
+ /* draw block progression arrow in green */
+ cairo_save (cr);
+ cairo_translate (cr,
+ (double)logical.x / PANGO_SCALE,
+ (double)logical.y / PANGO_SCALE);
+ cairo_scale (cr,
+ (double)logical.width / PANGO_SCALE * 0.5,
+ (double)logical.height / PANGO_SCALE * 0.5);
+ cairo_translate (cr, 1.0, 1.0);
+ cairo_move_to (cr, -0.4, -0.7);
+ cairo_rel_line_to (cr, +0.8, 0.0); /* -- */
+ cairo_rel_line_to (cr, 0.0, +0.9); /* | */
+ cairo_rel_line_to (cr, +0.4, 0.0); /* - */
+ cairo_rel_line_to (cr, -0.8, +0.5); /* / */
+ cairo_rel_line_to (cr, -0.8, -0.5); /* \ */
+ cairo_rel_line_to (cr, +0.4, 0.0); /* - */
+ cairo_close_path (cr); /* | */
+ pattern = cairo_pattern_create_linear (0, -0.7, 0, 0.7);
+ cairo_pattern_add_color_stop_rgba (pattern, 0.0, 0.0, 1.0, 0.0, 0.0);
+ cairo_pattern_add_color_stop_rgba (pattern, 1.0, 0.0, 1.0, 0.0, 0.15);
+ cairo_set_source (cr, pattern);
+ cairo_fill_preserve (cr);
+ /* silly line_width is not locked :(. get rid of scale. */
+ cairo_restore (cr);
+ cairo_save (cr);
+ cairo_set_source_rgba (cr, 0.0, 0.7, 0.0, 0.2);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+ }
+
+ if (annotate & ANNOTATE_BASELINES)
+ {
+ /* draw baselines with line direction arrow in orange */
+ cairo_save (cr);
+ cairo_set_source_rgba (cr, 1.0, 0.5, 0.0, 0.5);
+ iter = pango_layout_get_iter (layout);
+ do
+ {
+ PangoLayoutLine *line = pango_layout_iter_get_line (iter);
+ double width = (double)logical.width / PANGO_SCALE;
+
+ y = pango_layout_iter_get_baseline (iter);
+ cairo_save (cr);
+ cairo_translate (cr,
+ (double)logical.x / PANGO_SCALE + width * 0.5,
+ (double)y / PANGO_SCALE);
+ if (line->resolved_dir)
+ cairo_scale (cr, -1, 1);
+ cairo_move_to (cr, -width * .5, -lw*0.2);
+ cairo_rel_line_to (cr, +width * .9, -lw*0.3);
+ cairo_rel_line_to (cr, 0, -lw);
+ cairo_rel_line_to (cr, +width * .1, +lw*1.5);
+ cairo_rel_line_to (cr, -width * .1, +lw*1.5);
+ cairo_rel_line_to (cr, 0, -lw);
+ cairo_rel_line_to (cr, -width * .9, -lw*0.3);
+ cairo_close_path (cr);
+ cairo_fill (cr);
+ cairo_restore (cr);
+ }
+ while (pango_layout_iter_next_line (iter));
+ pango_layout_iter_free (iter);
+ cairo_restore (cr);
+ }
+
+ if (annotate & ANNOTATE_LAYOUT_EXTENTS)
{
- /* draw resolved gravity "roof" in blue */
- cairo_save (cr);
- cairo_translate (cr,
- (double)logical.x / PANGO_SCALE,
- (double)logical.y / PANGO_SCALE);
- cairo_scale (cr,
- (double)logical.width / PANGO_SCALE * 0.5,
- (double)logical.height / PANGO_SCALE * 0.5);
- cairo_translate (cr, 1.0, 1.0);
- cairo_rotate (cr,
- pango_gravity_to_rotation (
- pango_context_get_gravity (
- pango_layout_get_context (layout))));
- cairo_move_to (cr, -1.0, -1.0);
- cairo_rel_line_to (cr, +1.0, -0.2); /* / */
- cairo_rel_line_to (cr, +1.0, +0.2); /* \ */
- cairo_close_path (cr); /* - */
- pattern = cairo_pattern_create_linear (0, -1.0, 0, -1.2);
- cairo_pattern_add_color_stop_rgba (pattern, 0.0, 0.0, 0.0, 1.0, 0.0);
- cairo_pattern_add_color_stop_rgba (pattern, 1.0, 0.0, 0.0, 1.0, 0.15);
- cairo_set_source (cr, pattern);
- cairo_fill (cr);
- /* once more, without close_path this time */
- cairo_move_to (cr, -1.0, -1.0);
- cairo_rel_line_to (cr, +1.0, -0.2); /* / */
- cairo_rel_line_to (cr, +1.0, +0.2); /* \ */
- /* silly line_width is not locked :(. get rid of scale. */
- cairo_restore (cr);
- cairo_save (cr);
- cairo_set_source_rgba (cr, 0.0, 0.0, 0.7, 0.2);
- cairo_stroke (cr);
- cairo_restore (cr);
-
-
- /* draw block progression arrow in green */
- cairo_save (cr);
- cairo_translate (cr,
- (double)logical.x / PANGO_SCALE,
- (double)logical.y / PANGO_SCALE);
- cairo_scale (cr,
- (double)logical.width / PANGO_SCALE * 0.5,
- (double)logical.height / PANGO_SCALE * 0.5);
- cairo_translate (cr, 1.0, 1.0);
- cairo_move_to (cr, -0.4, -0.7);
- cairo_rel_line_to (cr, +0.8, 0.0); /* -- */
- cairo_rel_line_to (cr, 0.0, +0.9); /* | */
- cairo_rel_line_to (cr, +0.4, 0.0); /* - */
- cairo_rel_line_to (cr, -0.8, +0.5); /* / */
- cairo_rel_line_to (cr, -0.8, -0.5); /* \ */
- cairo_rel_line_to (cr, +0.4, 0.0); /* - */
- cairo_close_path (cr); /* | */
- pattern = cairo_pattern_create_linear (0, -0.7, 0, 0.7);
- cairo_pattern_add_color_stop_rgba (pattern, 0.0, 0.0, 1.0, 0.0, 0.0);
- cairo_pattern_add_color_stop_rgba (pattern, 1.0, 0.0, 1.0, 0.0, 0.15);
- cairo_set_source (cr, pattern);
- cairo_fill_preserve (cr);
- /* silly line_width is not locked :(. get rid of scale. */
- cairo_restore (cr);
- cairo_save (cr);
- cairo_set_source_rgba (cr, 0.0, 0.7, 0.0, 0.2);
- cairo_stroke (cr);
- cairo_restore (cr);
- }
-
- /* draw baselines with line direction arrow in orange */
- cairo_save (cr);
- cairo_set_source_rgba (cr, 1.0, 0.5, 0.0, 0.5);
- iter = pango_layout_get_iter (layout);
- do
- {
- PangoLayoutLine *line = pango_layout_iter_get_line (iter);
- double width = (double)logical.width / PANGO_SCALE;
-
- y = pango_layout_iter_get_baseline (iter);
- cairo_save (cr);
- cairo_translate (cr,
- (double)logical.x / PANGO_SCALE + width * 0.5,
- (double)y / PANGO_SCALE);
- if (line->resolved_dir)
- cairo_scale (cr, -1, 1);
- cairo_move_to (cr, -width * .5, -lw*0.2);
- cairo_rel_line_to (cr, +width * .9, -lw*0.3);
- cairo_rel_line_to (cr, 0, -lw);
- cairo_rel_line_to (cr, +width * .1, +lw*1.5);
- cairo_rel_line_to (cr, -width * .1, +lw*1.5);
- cairo_rel_line_to (cr, 0, -lw);
- cairo_rel_line_to (cr, -width * .9, -lw*0.3);
- cairo_close_path (cr);
- cairo_fill (cr);
- cairo_restore (cr);
- }
- while (pango_layout_iter_next_line (iter));
- pango_layout_iter_free (iter);
- cairo_restore (cr);
-
- /* draw the logical rect in red */
- cairo_save (cr);
- cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.5);
-
- cairo_rectangle (cr,
- (double)logical.x / PANGO_SCALE - lw / 2,
- (double)logical.y / PANGO_SCALE - lw / 2,
- (double)logical.width / PANGO_SCALE + lw,
- (double)logical.height / PANGO_SCALE + lw);
- cairo_stroke (cr);
- cairo_restore (cr);
-
- /* draw the ink rect in green */
- cairo_save (cr);
- cairo_set_source_rgba (cr, 0.0, 1.0, 0.0, 0.5);
- cairo_rectangle (cr,
- (double)ink.x / PANGO_SCALE - lw / 2,
- (double)ink.y / PANGO_SCALE - lw / 2,
- (double)ink.width / PANGO_SCALE + lw,
- (double)ink.height / PANGO_SCALE + lw);
- cairo_stroke (cr);
- cairo_restore (cr);
-
- if (opt_annotate >= 3)
+ /* draw the logical rect in red */
+ cairo_save (cr);
+ cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.5);
+
+ cairo_rectangle (cr,
+ (double)logical.x / PANGO_SCALE - lw / 2,
+ (double)logical.y / PANGO_SCALE - lw / 2,
+ (double)logical.width / PANGO_SCALE + lw,
+ (double)logical.height / PANGO_SCALE + lw);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+
+ /* draw the ink rect in green */
+ cairo_save (cr);
+ cairo_set_source_rgba (cr, 0.0, 1.0, 0.0, 0.5);
+ cairo_rectangle (cr,
+ (double)ink.x / PANGO_SCALE - lw / 2,
+ (double)ink.y / PANGO_SCALE - lw / 2,
+ (double)ink.width / PANGO_SCALE + lw,
+ (double)ink.height / PANGO_SCALE + lw);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+ }
+
+ if (annotate & ANNOTATE_LINE_EXTENTS)
{
/* draw the logical rects for lines in red */
cairo_save (cr);
@@ -298,7 +318,7 @@ render_callback (PangoLayout *layout,
iter = pango_layout_get_iter (layout);
do
- {
+ {
PangoRectangle rect;
pango_layout_iter_get_line_extents (iter, NULL, &rect);
@@ -313,6 +333,78 @@ render_callback (PangoLayout *layout,
pango_layout_iter_free (iter);
cairo_restore (cr);
}
+
+ if (annotate & ANNOTATE_RUN_EXTENTS)
+ {
+ /* draw the logical rects for runs in blue */
+ cairo_save (cr);
+ cairo_set_source_rgba (cr, 0.0, 0.0, 1.0, 0.5);
+
+ iter = pango_layout_get_iter (layout);
+ do
+ {
+ PangoRectangle rect;
+
+ pango_layout_iter_get_run_extents (iter, NULL, &rect);
+ cairo_rectangle (cr,
+ (double)rect.x / PANGO_SCALE - lw / 2,
+ (double)rect.y / PANGO_SCALE - lw / 2,
+ (double)rect.width / PANGO_SCALE + lw,
+ (double)rect.height / PANGO_SCALE + lw);
+ cairo_stroke (cr);
+ }
+ while (pango_layout_iter_next_run (iter));
+ pango_layout_iter_free (iter);
+ cairo_restore (cr);
+ }
+
+ if (annotate & ANNOTATE_CLUSTER_EXTENTS)
+ {
+ /* draw the logical rects for clusters in purple */
+ cairo_save (cr);
+ cairo_set_source_rgba (cr, 1.0, 0.0, 1.0, 0.5);
+
+ iter = pango_layout_get_iter (layout);
+ do
+ {
+ PangoRectangle rect;
+
+ pango_layout_iter_get_cluster_extents (iter, NULL, &rect);
+ cairo_rectangle (cr,
+ (double)rect.x / PANGO_SCALE - lw / 2,
+ (double)rect.y / PANGO_SCALE - lw / 2,
+ (double)rect.width / PANGO_SCALE + lw,
+ (double)rect.height / PANGO_SCALE + lw);
+ cairo_stroke (cr);
+ }
+ while (pango_layout_iter_next_cluster (iter));
+ pango_layout_iter_free (iter);
+ cairo_restore (cr);
+ }
+
+ if (annotate & ANNOTATE_CHAR_EXTENTS)
+ {
+ /* draw the logical rects for chars in orange */
+ cairo_save (cr);
+ cairo_set_source_rgba (cr, 1.0, 0.5, 0.0, 0.5);
+
+ iter = pango_layout_get_iter (layout);
+ do
+ {
+ PangoRectangle rect;
+
+ pango_layout_iter_get_cluster_extents (iter, NULL, &rect);
+ cairo_rectangle (cr,
+ (double)rect.x / PANGO_SCALE - lw / 2,
+ (double)rect.y / PANGO_SCALE - lw / 2,
+ (double)rect.width / PANGO_SCALE + lw,
+ (double)rect.height / PANGO_SCALE + lw);
+ cairo_stroke (cr);
+ }
+ while (pango_layout_iter_next_cluster (iter));
+ pango_layout_iter_free (iter);
+ cairo_restore (cr);
+ }
}
cairo_move_to (cr, 0, 0);
@@ -458,8 +550,16 @@ pangocairo_view_get_option_group (const PangoViewer *klass G_GNUC_UNUSED)
{
GOptionEntry entries[] =
{
- {"annotate", 0, 0, G_OPTION_ARG_INT, &opt_annotate,
- "Annotate the output", "1, 2 or 3"},
+ {"annotate", 0, 0, G_OPTION_ARG_INT, &opt_annotate,
+ "Annotate the output\n"
+ "\t\t\t\t\t\t\t 1 - gravity\n"
+ "\t\t\t\t\t\t\t 2 - block progression\n"
+ "\t\t\t\t\t\t\t 4 - baselines\n"
+ "\t\t\t\t\t\t\t 8 - layout extents\n"
+ "\t\t\t\t\t\t\t 16 - line extents\n"
+ "\t\t\t\t\t\t\t 32 - run extents\n"
+ "\t\t\t\t\t\t\t 64 - cluster extents\n"
+ "\t\t\t\t\t\t\t 128 - char extents", "FLAGS"},
{NULL}
};
GOptionGroup *group;