
In locales where the Wi-Fi signal-strength characters couldn't be represented (eg, LANG=C), the entire Wi-Fi SSID + signal strength string would fail to convert, causing the Wi-Fi section of the connection list to show up as a series of blank lines. Fix this by testing beforehand whether the characters can convert, and falling back to plain ASCII if not. (And also, fix the similar code in nmt-newt-section.c, which got broken when nmt_newt_locale_from_utf8() was changed to never return NULL.) Also, for paranoia, represent the signal-strength strings via \nnn escapes rather than actual UTF-8 data, to guarantee that they get compiled to the expected values even if the source files get re-encoded. https://bugzilla.gnome.org/show_bug.cgi?id=733007
410 lines
12 KiB
C
410 lines
12 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Copyright 2013 Red Hat, Inc.
|
|
*/
|
|
|
|
/**
|
|
* SECTION:nmt-newt-section
|
|
* @short_description: A collapsible section
|
|
*
|
|
* #NmtNewtSection is a container with two children; the header and
|
|
* the body. The header is always visible, but the body is only
|
|
* visible when the container is #NmtNewtSection:open.
|
|
*
|
|
* Note that there is no default way to open and close an
|
|
* #NmtNewtSection. You need to implement this yourself. (Eg, by
|
|
* binding the #NmtToggleButton:active property of an #NmtToggleButton
|
|
* in the section's header to the section's #NmtNewtSection:open
|
|
* property.)
|
|
*
|
|
* In addition to the header and body, the #NmtNewtSection also draws
|
|
* a border along the left side, indicating the extent of the section.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include "nmt-newt-section.h"
|
|
#include "nmt-newt-grid.h"
|
|
#include "nmt-newt-label.h"
|
|
#include "nmt-newt-utils.h"
|
|
|
|
G_DEFINE_TYPE (NmtNewtSection, nmt_newt_section, NMT_TYPE_NEWT_CONTAINER)
|
|
|
|
#define NMT_NEWT_SECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_SECTION, NmtNewtSectionPrivate))
|
|
|
|
typedef struct {
|
|
NmtNewtWidget *header;
|
|
int hheight_req, hwidth_req;
|
|
|
|
NmtNewtWidget *body;
|
|
int bheight_req, bwidth_req;
|
|
|
|
NmtNewtWidget *border_grid;
|
|
NmtNewtWidget *border_open_label;
|
|
NmtNewtWidget *border_closed_label;
|
|
NmtNewtWidget *border_end_label;
|
|
GPtrArray *border_line_labels;
|
|
|
|
gboolean open;
|
|
} NmtNewtSectionPrivate;
|
|
|
|
static char *closed_glyph, *open_glyph, *line_glyph, *end_glyph;
|
|
|
|
enum {
|
|
PROP_0,
|
|
|
|
PROP_OPEN,
|
|
|
|
LAST_PROP
|
|
};
|
|
|
|
/**
|
|
* nmt_newt_section_new:
|
|
*
|
|
* Creates a new #NmtNewtSection
|
|
*
|
|
* Returns: a new #NmtNewtSection
|
|
*/
|
|
NmtNewtWidget *
|
|
nmt_newt_section_new (void)
|
|
{
|
|
return g_object_new (NMT_TYPE_NEWT_SECTION,
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
nmt_newt_section_init (NmtNewtSection *section)
|
|
{
|
|
NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (section);
|
|
NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_newt_section_parent_class);
|
|
|
|
priv->border_grid = nmt_newt_grid_new ();
|
|
parent_class->add (NMT_NEWT_CONTAINER (section), priv->border_grid);
|
|
|
|
priv->border_open_label = nmt_newt_label_new (open_glyph);
|
|
nmt_newt_widget_set_visible (priv->border_open_label, FALSE);
|
|
nmt_newt_grid_add (NMT_NEWT_GRID (priv->border_grid), priv->border_open_label, 0, 0);
|
|
|
|
priv->border_closed_label = nmt_newt_label_new (closed_glyph);
|
|
nmt_newt_grid_add (NMT_NEWT_GRID (priv->border_grid), priv->border_closed_label, 0, 0);
|
|
|
|
priv->border_end_label = nmt_newt_label_new (end_glyph);
|
|
nmt_newt_widget_set_visible (priv->border_open_label, FALSE);
|
|
nmt_newt_grid_add (NMT_NEWT_GRID (priv->border_grid), priv->border_end_label, 0, 1);
|
|
|
|
priv->border_line_labels = g_ptr_array_new ();
|
|
}
|
|
|
|
static void
|
|
nmt_newt_section_finalize (GObject *object)
|
|
{
|
|
NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (object);
|
|
|
|
g_ptr_array_unref (priv->border_line_labels);
|
|
|
|
G_OBJECT_CLASS (nmt_newt_section_parent_class)->finalize (object);
|
|
}
|
|
|
|
/**
|
|
* nmt_newt_section_set_header:
|
|
* @section: an #NmtNewtSection
|
|
* @header: the header widget
|
|
*
|
|
* Sets @section's header widget.
|
|
*/
|
|
void
|
|
nmt_newt_section_set_header (NmtNewtSection *section,
|
|
NmtNewtWidget *header)
|
|
{
|
|
NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (section);
|
|
NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_newt_section_parent_class);
|
|
NmtNewtContainer *container = NMT_NEWT_CONTAINER (section);
|
|
|
|
if (priv->header)
|
|
parent_class->remove (container, priv->header);
|
|
priv->header = header;
|
|
parent_class->add (container, header);
|
|
}
|
|
|
|
/**
|
|
* nmt_newt_section_get_header:
|
|
* @section: an #NmtNewtSection
|
|
*
|
|
* Gets @section's header widget.
|
|
*
|
|
* Returns: @section's header widget.
|
|
*/
|
|
NmtNewtWidget *
|
|
nmt_newt_section_get_header (NmtNewtSection *section)
|
|
{
|
|
NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (section);
|
|
|
|
return priv->header;
|
|
}
|
|
|
|
/**
|
|
* nmt_newt_section_set_body:
|
|
* @section: an #NmtNewtSection
|
|
* @body: the body widget
|
|
*
|
|
* Sets @section's body widget.
|
|
*/
|
|
void
|
|
nmt_newt_section_set_body (NmtNewtSection *section,
|
|
NmtNewtWidget *body)
|
|
{
|
|
NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (section);
|
|
NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_newt_section_parent_class);
|
|
NmtNewtContainer *container = NMT_NEWT_CONTAINER (section);
|
|
|
|
if (priv->body)
|
|
parent_class->remove (container, priv->body);
|
|
priv->body = body;
|
|
parent_class->add (container, body);
|
|
}
|
|
|
|
/**
|
|
* nmt_newt_section_get_body:
|
|
* @section: an #NmtNewtSection
|
|
*
|
|
* Gets @section's body widget.
|
|
*
|
|
* Returns: @section's body widget.
|
|
*/
|
|
NmtNewtWidget *
|
|
nmt_newt_section_get_body (NmtNewtSection *section)
|
|
{
|
|
NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (section);
|
|
|
|
return priv->body;
|
|
}
|
|
|
|
static void
|
|
nmt_newt_section_remove (NmtNewtContainer *container,
|
|
NmtNewtWidget *widget)
|
|
{
|
|
NmtNewtSection *section = NMT_NEWT_SECTION (container);
|
|
NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (section);
|
|
NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_newt_section_parent_class);
|
|
|
|
if (widget == priv->header)
|
|
priv->header = NULL;
|
|
else if (widget == priv->body)
|
|
priv->body = NULL;
|
|
else if (widget == priv->border_grid)
|
|
priv->border_grid = NULL;
|
|
|
|
parent_class->remove (container, widget);
|
|
}
|
|
|
|
static newtComponent *
|
|
nmt_newt_section_get_components (NmtNewtWidget *widget)
|
|
{
|
|
NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (widget);
|
|
newtComponent *child_cos;
|
|
GPtrArray *cos;
|
|
int i;
|
|
|
|
g_return_val_if_fail (priv->header != NULL && priv->body != NULL, NULL);
|
|
|
|
cos = g_ptr_array_new ();
|
|
|
|
child_cos = nmt_newt_widget_get_components (priv->border_grid);
|
|
for (i = 0; child_cos[i]; i++)
|
|
g_ptr_array_add (cos, child_cos[i]);
|
|
g_free (child_cos);
|
|
|
|
child_cos = nmt_newt_widget_get_components (priv->header);
|
|
for (i = 0; child_cos[i]; i++)
|
|
g_ptr_array_add (cos, child_cos[i]);
|
|
g_free (child_cos);
|
|
|
|
if (priv->open) {
|
|
child_cos = nmt_newt_widget_get_components (priv->body);
|
|
for (i = 0; child_cos[i]; i++)
|
|
g_ptr_array_add (cos, child_cos[i]);
|
|
g_free (child_cos);
|
|
}
|
|
|
|
g_ptr_array_add (cos, NULL);
|
|
return (newtComponent *) g_ptr_array_free (cos, FALSE);
|
|
}
|
|
|
|
static void
|
|
nmt_newt_section_size_request (NmtNewtWidget *widget,
|
|
int *width,
|
|
int *height)
|
|
{
|
|
NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (widget);
|
|
int border_width, border_height;
|
|
|
|
g_return_if_fail (priv->header != NULL && priv->body != NULL);
|
|
|
|
nmt_newt_widget_size_request (priv->border_grid, &border_width, &border_height);
|
|
nmt_newt_widget_size_request (priv->header, &priv->hwidth_req, &priv->hheight_req);
|
|
nmt_newt_widget_size_request (priv->body, &priv->bwidth_req, &priv->bheight_req);
|
|
|
|
*width = MAX (priv->hwidth_req, priv->bwidth_req) + 2;
|
|
*height = priv->open ? priv->hheight_req + priv->bheight_req + 1 : priv->hheight_req;
|
|
}
|
|
|
|
static void
|
|
adjust_border_for_allocation (NmtNewtSectionPrivate *priv,
|
|
int height)
|
|
{
|
|
int i;
|
|
|
|
/* We have to use a series of one-line labels rather than a multi-line
|
|
* textbox, because newt will hide any component that's partially offscreen,
|
|
* but we want the on-screen portion of the border to show even if part of
|
|
* it is offscreen.
|
|
*/
|
|
|
|
if (height == 1) {
|
|
nmt_newt_widget_set_visible (priv->border_closed_label, TRUE);
|
|
nmt_newt_widget_set_visible (priv->border_open_label, FALSE);
|
|
for (i = 0; i < priv->border_line_labels->len; i++)
|
|
nmt_newt_widget_set_visible (priv->border_line_labels->pdata[i], FALSE);
|
|
nmt_newt_widget_set_visible (priv->border_end_label, FALSE);
|
|
} else {
|
|
nmt_newt_widget_set_visible (priv->border_closed_label, FALSE);
|
|
nmt_newt_widget_set_visible (priv->border_open_label, TRUE);
|
|
for (i = 0; i < height - 2; i++) {
|
|
if (i >= priv->border_line_labels->len) {
|
|
NmtNewtWidget *label;
|
|
|
|
label = nmt_newt_label_new (line_glyph);
|
|
g_ptr_array_add (priv->border_line_labels, label);
|
|
nmt_newt_grid_add (NMT_NEWT_GRID (priv->border_grid), label, 0, i + 1);
|
|
} else
|
|
nmt_newt_widget_set_visible (priv->border_line_labels->pdata[i], TRUE);
|
|
}
|
|
nmt_newt_widget_set_visible (priv->border_end_label, TRUE);
|
|
nmt_newt_grid_move (NMT_NEWT_GRID (priv->border_grid), priv->border_end_label, 0, height - 1);
|
|
}
|
|
}
|
|
|
|
static void
|
|
nmt_newt_section_size_allocate (NmtNewtWidget *widget,
|
|
int x,
|
|
int y,
|
|
int width,
|
|
int height)
|
|
{
|
|
NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (widget);
|
|
|
|
adjust_border_for_allocation (priv, height);
|
|
|
|
nmt_newt_widget_size_allocate (priv->border_grid, x, y, 1, height);
|
|
nmt_newt_widget_size_allocate (priv->header, x + 2, y, width, priv->hheight_req);
|
|
if (priv->open) {
|
|
nmt_newt_widget_size_allocate (priv->body, x + 2, y + priv->hheight_req,
|
|
width, height - priv->hheight_req);
|
|
}
|
|
}
|
|
|
|
static void
|
|
nmt_newt_section_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (object);
|
|
|
|
switch (prop_id) {
|
|
case PROP_OPEN:
|
|
priv->open = g_value_get_boolean (value);
|
|
nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (object));
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
nmt_newt_section_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (object);
|
|
|
|
switch (prop_id) {
|
|
case PROP_OPEN:
|
|
g_value_set_boolean (value, priv->open);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
nmt_newt_section_class_init (NmtNewtSectionClass *section_class)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (section_class);
|
|
NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (section_class);
|
|
NmtNewtContainerClass *container_class = NMT_NEWT_CONTAINER_CLASS (section_class);
|
|
|
|
g_type_class_add_private (section_class, sizeof (NmtNewtSectionPrivate));
|
|
|
|
/* virtual methods */
|
|
object_class->set_property = nmt_newt_section_set_property;
|
|
object_class->get_property = nmt_newt_section_get_property;
|
|
object_class->finalize = nmt_newt_section_finalize;
|
|
|
|
widget_class->get_components = nmt_newt_section_get_components;
|
|
widget_class->size_request = nmt_newt_section_size_request;
|
|
widget_class->size_allocate = nmt_newt_section_size_allocate;
|
|
|
|
container_class->remove = nmt_newt_section_remove;
|
|
|
|
/* properties */
|
|
|
|
/**
|
|
* NmtNewtSection:open:
|
|
*
|
|
* %TRUE if the section is open (ie, its body is visible), %FALSE
|
|
* if not.
|
|
*/
|
|
g_object_class_install_property
|
|
(object_class, PROP_OPEN,
|
|
g_param_spec_boolean ("open", "", "",
|
|
FALSE,
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_STATIC_STRINGS));
|
|
|
|
/* globals */
|
|
closed_glyph = nmt_newt_locale_from_utf8 ("\342\225\220"); /* ═ */
|
|
open_glyph = nmt_newt_locale_from_utf8 ("\342\225\244"); /* ╤ */
|
|
line_glyph = nmt_newt_locale_from_utf8 ("\342\224\202"); /* │ */
|
|
end_glyph = nmt_newt_locale_from_utf8 ("\342\224\224"); /* └ */
|
|
if (!*closed_glyph || !*open_glyph || !*line_glyph || !*end_glyph) {
|
|
g_free (closed_glyph);
|
|
g_free (open_glyph);
|
|
g_free (line_glyph);
|
|
g_free (end_glyph);
|
|
|
|
closed_glyph = g_strdup ("-");
|
|
open_glyph = g_strdup ("+");
|
|
line_glyph = g_strdup ("|");
|
|
end_glyph = g_strdup ("\\");
|
|
}
|
|
}
|