diff options
Diffstat (limited to 'clients/tui')
124 files changed, 24945 insertions, 0 deletions
diff --git a/clients/tui/Makefile.am b/clients/tui/Makefile.am new file mode 100644 index 00000000..ad9335da --- /dev/null +++ b/clients/tui/Makefile.am @@ -0,0 +1,128 @@ +if BUILD_NMTUI + +SUBDIRS = newt . + +AM_CPPFLAGS= \ + -I$(top_srcdir) \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/libnm-core \ + -I$(top_builddir)/libnm-core \ + -I$(top_srcdir)/libnm \ + -I$(top_builddir)/libnm \ + -I$(srcdir)/newt \ + -I$(top_srcdir)/clients/common \ + $(GLIB_CFLAGS) \ + $(NEWT_CFLAGS) \ + $(GUDEV_CFLAGS) \ + -DG_LOG_DOMAIN=\""nmtui"\" \ + -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ + -DLOCALEDIR=\""$(localedir)"\" \ + $(NULL) + +bin_PROGRAMS = nmtui +links = nmtui-edit nmtui-connect nmtui-hostname + +install-exec-hook: + for link in $(links); do \ + ln -f $(DESTDIR)$(bindir)/nmtui $(DESTDIR)$(bindir)/$$link; \ + done + +uninstall-hook: + for link in $(links); do \ + rm -f $(DESTDIR)$(bindir)/$$link; \ + done + +nmtui_SOURCES = \ + nmtui.c \ + nmtui.h \ + nmtui-connect.c \ + nmtui-connect.h \ + nmtui-edit.c \ + nmtui-edit.h \ + nmtui-hostname.c \ + nmtui-hostname.h \ + \ + nm-editor-bindings.c \ + nm-editor-bindings.h \ + nm-editor-utils.c \ + nm-editor-utils.h \ + \ + nmt-address-list.c \ + nmt-address-list.h \ + nmt-connect-connection-list.c \ + nmt-connect-connection-list.h \ + nmt-device-entry.c \ + nmt-device-entry.h \ + nmt-edit-connection-list.c \ + nmt-edit-connection-list.h \ + nmt-editor-grid.c \ + nmt-editor-grid.h \ + nmt-editor-page.c \ + nmt-editor-page.h \ + nmt-editor-page-device.c \ + nmt-editor-page-device.h \ + nmt-editor-section.c \ + nmt-editor-section.h \ + nmt-editor.c \ + nmt-editor.h \ + nmt-ip-entry.c \ + nmt-ip-entry.h \ + nmt-mac-entry.c \ + nmt-mac-entry.h \ + nmt-mtu-entry.c \ + nmt-mtu-entry.h \ + nmt-page-bond.c \ + nmt-page-bond.h \ + nmt-page-bridge.c \ + nmt-page-bridge.h \ + nmt-page-bridge-port.c \ + nmt-page-bridge-port.h \ + nmt-page-dsl.c \ + nmt-page-dsl.h \ + nmt-page-ethernet.c \ + nmt-page-ethernet.h \ + nmt-page-infiniband.c \ + nmt-page-infiniband.h \ + nmt-page-ip4.c \ + nmt-page-ip4.h \ + nmt-page-ip6.c \ + nmt-page-ip6.h \ + nmt-page-ppp.c \ + nmt-page-ppp.h \ + nmt-page-team.c \ + nmt-page-team.h \ + nmt-page-team-port.c \ + nmt-page-team-port.h \ + nmt-page-vlan.c \ + nmt-page-vlan.h \ + nmt-page-wifi.c \ + nmt-page-wifi.h \ + nmt-password-dialog.c \ + nmt-password-dialog.h \ + nmt-password-fields.c \ + nmt-password-fields.h \ + nmt-route-editor.c \ + nmt-route-editor.h \ + nmt-route-entry.c \ + nmt-route-entry.h \ + nmt-route-table.c \ + nmt-route-table.h \ + nmt-slave-list.c \ + nmt-slave-list.h \ + nmt-utils.c \ + nmt-utils.h \ + nmt-widget-list.c \ + nmt-widget-list.h \ + $(srcdir)/../common/nm-secret-agent-simple.c \ + $(srcdir)/../common/nm-secret-agent-simple.h \ + $(NULL) + +nmtui_LDADD = \ + $(top_builddir)/libnm/libnm.la \ + $(builddir)/newt/libnmt-newt.a \ + $(GUDEV_LIBS) \ + $(NEWT_LIBS) \ + $(GLIB_LIBS) \ + $(NULL) + +endif diff --git a/clients/tui/Makefile.in b/clients/tui/Makefile.in new file mode 100644 index 00000000..86b2a3b9 --- /dev/null +++ b/clients/tui/Makefile.in @@ -0,0 +1,1131 @@ +# Makefile.in generated by automake 1.13.4 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@BUILD_NMTUI_TRUE@bin_PROGRAMS = nmtui$(EXEEXT) +subdir = clients/tui +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/build-aux/depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ + $(top_srcdir)/m4/compiler_warnings.m4 \ + $(top_srcdir)/m4/gettext.m4 \ + $(top_srcdir)/m4/gnome-code-coverage.m4 \ + $(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \ + $(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \ + $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +PROGRAMS = $(bin_PROGRAMS) +am__nmtui_SOURCES_DIST = nmtui.c nmtui.h nmtui-connect.c \ + nmtui-connect.h nmtui-edit.c nmtui-edit.h nmtui-hostname.c \ + nmtui-hostname.h nm-editor-bindings.c nm-editor-bindings.h \ + nm-editor-utils.c nm-editor-utils.h nmt-address-list.c \ + nmt-address-list.h nmt-connect-connection-list.c \ + nmt-connect-connection-list.h nmt-device-entry.c \ + nmt-device-entry.h nmt-edit-connection-list.c \ + nmt-edit-connection-list.h nmt-editor-grid.c nmt-editor-grid.h \ + nmt-editor-page.c nmt-editor-page.h nmt-editor-page-device.c \ + nmt-editor-page-device.h nmt-editor-section.c \ + nmt-editor-section.h nmt-editor.c nmt-editor.h nmt-ip-entry.c \ + nmt-ip-entry.h nmt-mac-entry.c nmt-mac-entry.h nmt-mtu-entry.c \ + nmt-mtu-entry.h nmt-page-bond.c nmt-page-bond.h \ + nmt-page-bridge.c nmt-page-bridge.h nmt-page-bridge-port.c \ + nmt-page-bridge-port.h nmt-page-dsl.c nmt-page-dsl.h \ + nmt-page-ethernet.c nmt-page-ethernet.h nmt-page-infiniband.c \ + nmt-page-infiniband.h nmt-page-ip4.c nmt-page-ip4.h \ + nmt-page-ip6.c nmt-page-ip6.h nmt-page-ppp.c nmt-page-ppp.h \ + nmt-page-team.c nmt-page-team.h nmt-page-team-port.c \ + nmt-page-team-port.h nmt-page-vlan.c nmt-page-vlan.h \ + nmt-page-wifi.c nmt-page-wifi.h nmt-password-dialog.c \ + nmt-password-dialog.h nmt-password-fields.c \ + nmt-password-fields.h nmt-route-editor.c nmt-route-editor.h \ + nmt-route-entry.c nmt-route-entry.h nmt-route-table.c \ + nmt-route-table.h nmt-slave-list.c nmt-slave-list.h \ + nmt-utils.c nmt-utils.h nmt-widget-list.c nmt-widget-list.h \ + $(srcdir)/../common/nm-secret-agent-simple.c \ + $(srcdir)/../common/nm-secret-agent-simple.h +@BUILD_NMTUI_TRUE@am_nmtui_OBJECTS = nmtui.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmtui-connect.$(OBJEXT) nmtui-edit.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmtui-hostname.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nm-editor-bindings.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nm-editor-utils.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-address-list.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-connect-connection-list.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-device-entry.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-edit-connection-list.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-editor-grid.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-editor-page.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-editor-page-device.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-editor-section.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-editor.$(OBJEXT) nmt-ip-entry.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-mac-entry.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-mtu-entry.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-page-bond.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-page-bridge.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-page-bridge-port.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-page-dsl.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-page-ethernet.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-page-infiniband.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-page-ip4.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-page-ip6.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-page-ppp.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-page-team.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-page-team-port.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-page-vlan.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-page-wifi.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-password-dialog.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-password-fields.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-route-editor.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-route-entry.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-route-table.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-slave-list.$(OBJEXT) nmt-utils.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nmt-widget-list.$(OBJEXT) \ +@BUILD_NMTUI_TRUE@ nm-secret-agent-simple.$(OBJEXT) +nmtui_OBJECTS = $(am_nmtui_OBJECTS) +am__DEPENDENCIES_1 = +@BUILD_NMTUI_TRUE@nmtui_DEPENDENCIES = $(top_builddir)/libnm/libnm.la \ +@BUILD_NMTUI_TRUE@ $(builddir)/newt/libnmt-newt.a \ +@BUILD_NMTUI_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ +@BUILD_NMTUI_TRUE@ $(am__DEPENDENCIES_1) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(nmtui_SOURCES) +DIST_SOURCES = $(am__nmtui_SOURCES_DIST) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = newt . +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALL_LINGUAS = @ALL_LINGUAS@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BLUEZ5_CFLAGS = @BLUEZ5_CFLAGS@ +BLUEZ5_LIBS = @BLUEZ5_LIBS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CKDB_PATH = @CKDB_PATH@ +CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@ +CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@ +CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DBUS_CFLAGS = @DBUS_CFLAGS@ +DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@ +DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@ +DBUS_LIBS = @DBUS_LIBS@ +DBUS_SYS_DIR = @DBUS_SYS_DIR@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DHCLIENT_PATH = @DHCLIENT_PATH@ +DHCPCD_PATH = @DHCPCD_PATH@ +DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ +DLLTOOL = @DLLTOOL@ +DNSMASQ_PATH = @DNSMASQ_PATH@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GENHTML = @GENHTML@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GLIB_LIBS = @GLIB_LIBS@ +GLIB_MAKEFILE = @GLIB_MAKEFILE@ +GLIB_MKENUMS = @GLIB_MKENUMS@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUTLS_CFLAGS = @GNUTLS_CFLAGS@ +GNUTLS_LIBS = @GNUTLS_LIBS@ +GREP = @GREP@ +GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ +GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ +GTKDOC_MKPDF = @GTKDOC_MKPDF@ +GTKDOC_REBASE = @GTKDOC_REBASE@ +GUDEV_CFLAGS = @GUDEV_CFLAGS@ +GUDEV_LIBS = @GUDEV_LIBS@ +HTML_DIR = @HTML_DIR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ +INTLTOOL_MERGE = @INTLTOOL_MERGE@ +INTLTOOL_PERL = @INTLTOOL_PERL@ +INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ +INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@ +INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@ +INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@ +INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@ +INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@ +INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@ +INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@ +INTROSPECTION_LIBS = @INTROSPECTION_LIBS@ +INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@ +INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@ +INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@ +IPTABLES_PATH = @IPTABLES_PATH@ +IWMX_SDK_CFLAGS = @IWMX_SDK_CFLAGS@ +IWMX_SDK_LIBS = @IWMX_SDK_LIBS@ +KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBDL = @LIBDL@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBM = @LIBM@ +LIBNDP_CFLAGS = @LIBNDP_CFLAGS@ +LIBNDP_LIBS = @LIBNDP_LIBS@ +LIBNL_CFLAGS = @LIBNL_CFLAGS@ +LIBNL_LIBS = @LIBNL_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@ +LIBSOUP_LIBS = @LIBSOUP_LIBS@ +LIBTEAMDCTL_CFLAGS = @LIBTEAMDCTL_CFLAGS@ +LIBTEAMDCTL_LIBS = @LIBTEAMDCTL_LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MM_GLIB_CFLAGS = @MM_GLIB_CFLAGS@ +MM_GLIB_LIBS = @MM_GLIB_LIBS@ +MOC = @MOC@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NEWT_CFLAGS = @NEWT_CFLAGS@ +NEWT_LIBS = @NEWT_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ +NM_MICRO_VERSION = @NM_MICRO_VERSION@ +NM_MINOR_VERSION = @NM_MINOR_VERSION@ +NM_MODIFY_SYSTEM_POLICY = @NM_MODIFY_SYSTEM_POLICY@ +NM_VERSION = @NM_VERSION@ +NSS_CFLAGS = @NSS_CFLAGS@ +NSS_LIBS = @NSS_LIBS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +POLKIT_CFLAGS = @POLKIT_CFLAGS@ +POLKIT_LIBS = @POLKIT_LIBS@ +POSUB = @POSUB@ +PPPD_PATH = @PPPD_PATH@ +PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@ +PPPOE_PATH = @PPPOE_PATH@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +RANLIB = @RANLIB@ +READLINE_LIBS = @READLINE_LIBS@ +SED = @SED@ +SELINUX_CFLAGS = @SELINUX_CFLAGS@ +SELINUX_LIBS = @SELINUX_LIBS@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SYSTEMD_200_CFLAGS = @SYSTEMD_200_CFLAGS@ +SYSTEMD_200_LIBS = @SYSTEMD_200_LIBS@ +SYSTEMD_INHIBIT_CFLAGS = @SYSTEMD_INHIBIT_CFLAGS@ +SYSTEMD_INHIBIT_LIBS = @SYSTEMD_INHIBIT_LIBS@ +SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ +SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ +SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ +UDEV_DIR = @UDEV_DIR@ +USE_NLS = @USE_NLS@ +UUID_CFLAGS = @UUID_CFLAGS@ +UUID_LIBS = @UUID_LIBS@ +VALGRIND_RULES = @VALGRIND_RULES@ +VAPIGEN = @VAPIGEN@ +VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@ +VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +intltool__v_merge_options_ = @intltool__v_merge_options_@ +intltool__v_merge_options_0 = @intltool__v_merge_options_0@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +nmbinary = @nmbinary@ +nmconfdir = @nmconfdir@ +nmdatadir = @nmdatadir@ +nmrundir = @nmrundir@ +nmstatedir = @nmstatedir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +systemdsystemunitdir = @systemdsystemunitdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +with_dhclient = @with_dhclient@ +with_dhcpcd = @with_dhcpcd@ +with_netconfig = @with_netconfig@ +with_resolvconf = @with_resolvconf@ +with_valgrind = @with_valgrind@ +@BUILD_NMTUI_TRUE@SUBDIRS = newt . +@BUILD_NMTUI_TRUE@AM_CPPFLAGS = \ +@BUILD_NMTUI_TRUE@ -I$(top_srcdir) \ +@BUILD_NMTUI_TRUE@ -I$(top_srcdir)/include \ +@BUILD_NMTUI_TRUE@ -I$(top_srcdir)/libnm-core \ +@BUILD_NMTUI_TRUE@ -I$(top_builddir)/libnm-core \ +@BUILD_NMTUI_TRUE@ -I$(top_srcdir)/libnm \ +@BUILD_NMTUI_TRUE@ -I$(top_builddir)/libnm \ +@BUILD_NMTUI_TRUE@ -I$(srcdir)/newt \ +@BUILD_NMTUI_TRUE@ -I$(top_srcdir)/clients/common \ +@BUILD_NMTUI_TRUE@ $(GLIB_CFLAGS) \ +@BUILD_NMTUI_TRUE@ $(NEWT_CFLAGS) \ +@BUILD_NMTUI_TRUE@ $(GUDEV_CFLAGS) \ +@BUILD_NMTUI_TRUE@ -DG_LOG_DOMAIN=\""nmtui"\" \ +@BUILD_NMTUI_TRUE@ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ +@BUILD_NMTUI_TRUE@ -DLOCALEDIR=\""$(localedir)"\" \ +@BUILD_NMTUI_TRUE@ $(NULL) + +@BUILD_NMTUI_TRUE@links = nmtui-edit nmtui-connect nmtui-hostname +@BUILD_NMTUI_TRUE@nmtui_SOURCES = \ +@BUILD_NMTUI_TRUE@ nmtui.c \ +@BUILD_NMTUI_TRUE@ nmtui.h \ +@BUILD_NMTUI_TRUE@ nmtui-connect.c \ +@BUILD_NMTUI_TRUE@ nmtui-connect.h \ +@BUILD_NMTUI_TRUE@ nmtui-edit.c \ +@BUILD_NMTUI_TRUE@ nmtui-edit.h \ +@BUILD_NMTUI_TRUE@ nmtui-hostname.c \ +@BUILD_NMTUI_TRUE@ nmtui-hostname.h \ +@BUILD_NMTUI_TRUE@ \ +@BUILD_NMTUI_TRUE@ nm-editor-bindings.c \ +@BUILD_NMTUI_TRUE@ nm-editor-bindings.h \ +@BUILD_NMTUI_TRUE@ nm-editor-utils.c \ +@BUILD_NMTUI_TRUE@ nm-editor-utils.h \ +@BUILD_NMTUI_TRUE@ \ +@BUILD_NMTUI_TRUE@ nmt-address-list.c \ +@BUILD_NMTUI_TRUE@ nmt-address-list.h \ +@BUILD_NMTUI_TRUE@ nmt-connect-connection-list.c \ +@BUILD_NMTUI_TRUE@ nmt-connect-connection-list.h \ +@BUILD_NMTUI_TRUE@ nmt-device-entry.c \ +@BUILD_NMTUI_TRUE@ nmt-device-entry.h \ +@BUILD_NMTUI_TRUE@ nmt-edit-connection-list.c \ +@BUILD_NMTUI_TRUE@ nmt-edit-connection-list.h \ +@BUILD_NMTUI_TRUE@ nmt-editor-grid.c \ +@BUILD_NMTUI_TRUE@ nmt-editor-grid.h \ +@BUILD_NMTUI_TRUE@ nmt-editor-page.c \ +@BUILD_NMTUI_TRUE@ nmt-editor-page.h \ +@BUILD_NMTUI_TRUE@ nmt-editor-page-device.c \ +@BUILD_NMTUI_TRUE@ nmt-editor-page-device.h \ +@BUILD_NMTUI_TRUE@ nmt-editor-section.c \ +@BUILD_NMTUI_TRUE@ nmt-editor-section.h \ +@BUILD_NMTUI_TRUE@ nmt-editor.c \ +@BUILD_NMTUI_TRUE@ nmt-editor.h \ +@BUILD_NMTUI_TRUE@ nmt-ip-entry.c \ +@BUILD_NMTUI_TRUE@ nmt-ip-entry.h \ +@BUILD_NMTUI_TRUE@ nmt-mac-entry.c \ +@BUILD_NMTUI_TRUE@ nmt-mac-entry.h \ +@BUILD_NMTUI_TRUE@ nmt-mtu-entry.c \ +@BUILD_NMTUI_TRUE@ nmt-mtu-entry.h \ +@BUILD_NMTUI_TRUE@ nmt-page-bond.c \ +@BUILD_NMTUI_TRUE@ nmt-page-bond.h \ +@BUILD_NMTUI_TRUE@ nmt-page-bridge.c \ +@BUILD_NMTUI_TRUE@ nmt-page-bridge.h \ +@BUILD_NMTUI_TRUE@ nmt-page-bridge-port.c \ +@BUILD_NMTUI_TRUE@ nmt-page-bridge-port.h \ +@BUILD_NMTUI_TRUE@ nmt-page-dsl.c \ +@BUILD_NMTUI_TRUE@ nmt-page-dsl.h \ +@BUILD_NMTUI_TRUE@ nmt-page-ethernet.c \ +@BUILD_NMTUI_TRUE@ nmt-page-ethernet.h \ +@BUILD_NMTUI_TRUE@ nmt-page-infiniband.c \ +@BUILD_NMTUI_TRUE@ nmt-page-infiniband.h \ +@BUILD_NMTUI_TRUE@ nmt-page-ip4.c \ +@BUILD_NMTUI_TRUE@ nmt-page-ip4.h \ +@BUILD_NMTUI_TRUE@ nmt-page-ip6.c \ +@BUILD_NMTUI_TRUE@ nmt-page-ip6.h \ +@BUILD_NMTUI_TRUE@ nmt-page-ppp.c \ +@BUILD_NMTUI_TRUE@ nmt-page-ppp.h \ +@BUILD_NMTUI_TRUE@ nmt-page-team.c \ +@BUILD_NMTUI_TRUE@ nmt-page-team.h \ +@BUILD_NMTUI_TRUE@ nmt-page-team-port.c \ +@BUILD_NMTUI_TRUE@ nmt-page-team-port.h \ +@BUILD_NMTUI_TRUE@ nmt-page-vlan.c \ +@BUILD_NMTUI_TRUE@ nmt-page-vlan.h \ +@BUILD_NMTUI_TRUE@ nmt-page-wifi.c \ +@BUILD_NMTUI_TRUE@ nmt-page-wifi.h \ +@BUILD_NMTUI_TRUE@ nmt-password-dialog.c \ +@BUILD_NMTUI_TRUE@ nmt-password-dialog.h \ +@BUILD_NMTUI_TRUE@ nmt-password-fields.c \ +@BUILD_NMTUI_TRUE@ nmt-password-fields.h \ +@BUILD_NMTUI_TRUE@ nmt-route-editor.c \ +@BUILD_NMTUI_TRUE@ nmt-route-editor.h \ +@BUILD_NMTUI_TRUE@ nmt-route-entry.c \ +@BUILD_NMTUI_TRUE@ nmt-route-entry.h \ +@BUILD_NMTUI_TRUE@ nmt-route-table.c \ +@BUILD_NMTUI_TRUE@ nmt-route-table.h \ +@BUILD_NMTUI_TRUE@ nmt-slave-list.c \ +@BUILD_NMTUI_TRUE@ nmt-slave-list.h \ +@BUILD_NMTUI_TRUE@ nmt-utils.c \ +@BUILD_NMTUI_TRUE@ nmt-utils.h \ +@BUILD_NMTUI_TRUE@ nmt-widget-list.c \ +@BUILD_NMTUI_TRUE@ nmt-widget-list.h \ +@BUILD_NMTUI_TRUE@ $(srcdir)/../common/nm-secret-agent-simple.c \ +@BUILD_NMTUI_TRUE@ $(srcdir)/../common/nm-secret-agent-simple.h \ +@BUILD_NMTUI_TRUE@ $(NULL) + +@BUILD_NMTUI_TRUE@nmtui_LDADD = \ +@BUILD_NMTUI_TRUE@ $(top_builddir)/libnm/libnm.la \ +@BUILD_NMTUI_TRUE@ $(builddir)/newt/libnmt-newt.a \ +@BUILD_NMTUI_TRUE@ $(GUDEV_LIBS) \ +@BUILD_NMTUI_TRUE@ $(NEWT_LIBS) \ +@BUILD_NMTUI_TRUE@ $(GLIB_LIBS) \ +@BUILD_NMTUI_TRUE@ $(NULL) + +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu clients/tui/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu clients/tui/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +nmtui$(EXEEXT): $(nmtui_OBJECTS) $(nmtui_DEPENDENCIES) $(EXTRA_nmtui_DEPENDENCIES) + @rm -f nmtui$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(nmtui_OBJECTS) $(nmtui_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-editor-bindings.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-editor-utils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-secret-agent-simple.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-address-list.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-connect-connection-list.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-device-entry.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-edit-connection-list.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-editor-grid.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-editor-page-device.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-editor-page.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-editor-section.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-editor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-ip-entry.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-mac-entry.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-mtu-entry.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-page-bond.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-page-bridge-port.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-page-bridge.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-page-dsl.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-page-ethernet.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-page-infiniband.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-page-ip4.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-page-ip6.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-page-ppp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-page-team-port.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-page-team.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-page-vlan.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-page-wifi.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-password-dialog.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-password-fields.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-route-editor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-route-entry.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-route-table.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-slave-list.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-utils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-widget-list.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmtui-connect.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmtui-edit.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmtui-hostname.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmtui.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +nm-secret-agent-simple.o: $(srcdir)/../common/nm-secret-agent-simple.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-secret-agent-simple.o -MD -MP -MF $(DEPDIR)/nm-secret-agent-simple.Tpo -c -o nm-secret-agent-simple.o `test -f '$(srcdir)/../common/nm-secret-agent-simple.c' || echo '$(srcdir)/'`$(srcdir)/../common/nm-secret-agent-simple.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-secret-agent-simple.Tpo $(DEPDIR)/nm-secret-agent-simple.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(srcdir)/../common/nm-secret-agent-simple.c' object='nm-secret-agent-simple.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm-secret-agent-simple.o `test -f '$(srcdir)/../common/nm-secret-agent-simple.c' || echo '$(srcdir)/'`$(srcdir)/../common/nm-secret-agent-simple.c + +nm-secret-agent-simple.obj: $(srcdir)/../common/nm-secret-agent-simple.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-secret-agent-simple.obj -MD -MP -MF $(DEPDIR)/nm-secret-agent-simple.Tpo -c -o nm-secret-agent-simple.obj `if test -f '$(srcdir)/../common/nm-secret-agent-simple.c'; then $(CYGPATH_W) '$(srcdir)/../common/nm-secret-agent-simple.c'; else $(CYGPATH_W) '$(srcdir)/$(srcdir)/../common/nm-secret-agent-simple.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-secret-agent-simple.Tpo $(DEPDIR)/nm-secret-agent-simple.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(srcdir)/../common/nm-secret-agent-simple.c' object='nm-secret-agent-simple.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm-secret-agent-simple.obj `if test -f '$(srcdir)/../common/nm-secret-agent-simple.c'; then $(CYGPATH_W) '$(srcdir)/../common/nm-secret-agent-simple.c'; else $(CYGPATH_W) '$(srcdir)/$(srcdir)/../common/nm-secret-agent-simple.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(PROGRAMS) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +@BUILD_NMTUI_FALSE@install-exec-hook: +@BUILD_NMTUI_FALSE@uninstall-hook: +clean: clean-recursive + +clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-hook +.MAKE: $(am__recursive_targets) install-am install-exec-am \ + install-strip uninstall-am + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-binPROGRAMS clean-generic clean-libtool \ + cscopelist-am ctags ctags-am distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-exec-hook \ + install-html install-html-am install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-hook + + +@BUILD_NMTUI_TRUE@install-exec-hook: +@BUILD_NMTUI_TRUE@ for link in $(links); do \ +@BUILD_NMTUI_TRUE@ ln -f $(DESTDIR)$(bindir)/nmtui $(DESTDIR)$(bindir)/$$link; \ +@BUILD_NMTUI_TRUE@ done + +@BUILD_NMTUI_TRUE@uninstall-hook: +@BUILD_NMTUI_TRUE@ for link in $(links); do \ +@BUILD_NMTUI_TRUE@ rm -f $(DESTDIR)$(bindir)/$$link; \ +@BUILD_NMTUI_TRUE@ done + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/clients/tui/newt/Makefile.am b/clients/tui/newt/Makefile.am new file mode 100644 index 00000000..e572238b --- /dev/null +++ b/clients/tui/newt/Makefile.am @@ -0,0 +1,53 @@ +AM_CPPFLAGS= \ + -I$(top_srcdir)/include \ + -DG_LOG_DOMAIN=\""nmtui"\" \ + $(GLIB_CFLAGS) \ + $(NEWT_CFLAGS) \ + $(NULL) + +noinst_LIBRARIES = libnmt-newt.a + +libnmt_newt_a_SOURCES = \ + nmt-newt.h \ + nmt-newt-types.h \ + nmt-newt-button.c \ + nmt-newt-button.h \ + nmt-newt-button-box.c \ + nmt-newt-button-box.h \ + nmt-newt-checkbox.c \ + nmt-newt-checkbox.h \ + nmt-newt-component.c \ + nmt-newt-component.h \ + nmt-newt-container.c \ + nmt-newt-container.h \ + nmt-newt-entry.c \ + nmt-newt-entry.h \ + nmt-newt-entry-numeric.c \ + nmt-newt-entry-numeric.h \ + nmt-newt-form.c \ + nmt-newt-form.h \ + nmt-newt-grid.c \ + nmt-newt-grid.h \ + nmt-newt-hacks.c \ + nmt-newt-hacks.h \ + nmt-newt-label.c \ + nmt-newt-label.h \ + nmt-newt-listbox.c \ + nmt-newt-listbox.h \ + nmt-newt-popup.c \ + nmt-newt-popup.h \ + nmt-newt-section.c \ + nmt-newt-section.h \ + nmt-newt-separator.c \ + nmt-newt-separator.h \ + nmt-newt-stack.c \ + nmt-newt-stack.h \ + nmt-newt-textbox.c \ + nmt-newt-textbox.h \ + nmt-newt-toggle-button.c \ + nmt-newt-toggle-button.h \ + nmt-newt-utils.c \ + nmt-newt-utils.h \ + nmt-newt-widget.c \ + nmt-newt-widget.h \ + $(NULL) diff --git a/clients/tui/newt/Makefile.in b/clients/tui/newt/Makefile.in new file mode 100644 index 00000000..64abce69 --- /dev/null +++ b/clients/tui/newt/Makefile.in @@ -0,0 +1,805 @@ +# Makefile.in generated by automake 1.13.4 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = clients/tui/newt +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/build-aux/depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ + $(top_srcdir)/m4/compiler_warnings.m4 \ + $(top_srcdir)/m4/gettext.m4 \ + $(top_srcdir)/m4/gnome-code-coverage.m4 \ + $(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \ + $(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \ + $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +libnmt_newt_a_AR = $(AR) $(ARFLAGS) +libnmt_newt_a_LIBADD = +am_libnmt_newt_a_OBJECTS = nmt-newt-button.$(OBJEXT) \ + nmt-newt-button-box.$(OBJEXT) nmt-newt-checkbox.$(OBJEXT) \ + nmt-newt-component.$(OBJEXT) nmt-newt-container.$(OBJEXT) \ + nmt-newt-entry.$(OBJEXT) nmt-newt-entry-numeric.$(OBJEXT) \ + nmt-newt-form.$(OBJEXT) nmt-newt-grid.$(OBJEXT) \ + nmt-newt-hacks.$(OBJEXT) nmt-newt-label.$(OBJEXT) \ + nmt-newt-listbox.$(OBJEXT) nmt-newt-popup.$(OBJEXT) \ + nmt-newt-section.$(OBJEXT) nmt-newt-separator.$(OBJEXT) \ + nmt-newt-stack.$(OBJEXT) nmt-newt-textbox.$(OBJEXT) \ + nmt-newt-toggle-button.$(OBJEXT) nmt-newt-utils.$(OBJEXT) \ + nmt-newt-widget.$(OBJEXT) +libnmt_newt_a_OBJECTS = $(am_libnmt_newt_a_OBJECTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libnmt_newt_a_SOURCES) +DIST_SOURCES = $(libnmt_newt_a_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALL_LINGUAS = @ALL_LINGUAS@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BLUEZ5_CFLAGS = @BLUEZ5_CFLAGS@ +BLUEZ5_LIBS = @BLUEZ5_LIBS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CKDB_PATH = @CKDB_PATH@ +CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@ +CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@ +CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DBUS_CFLAGS = @DBUS_CFLAGS@ +DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@ +DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@ +DBUS_LIBS = @DBUS_LIBS@ +DBUS_SYS_DIR = @DBUS_SYS_DIR@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DHCLIENT_PATH = @DHCLIENT_PATH@ +DHCPCD_PATH = @DHCPCD_PATH@ +DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ +DLLTOOL = @DLLTOOL@ +DNSMASQ_PATH = @DNSMASQ_PATH@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GENHTML = @GENHTML@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GLIB_LIBS = @GLIB_LIBS@ +GLIB_MAKEFILE = @GLIB_MAKEFILE@ +GLIB_MKENUMS = @GLIB_MKENUMS@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUTLS_CFLAGS = @GNUTLS_CFLAGS@ +GNUTLS_LIBS = @GNUTLS_LIBS@ +GREP = @GREP@ +GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ +GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ +GTKDOC_MKPDF = @GTKDOC_MKPDF@ +GTKDOC_REBASE = @GTKDOC_REBASE@ +GUDEV_CFLAGS = @GUDEV_CFLAGS@ +GUDEV_LIBS = @GUDEV_LIBS@ +HTML_DIR = @HTML_DIR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ +INTLTOOL_MERGE = @INTLTOOL_MERGE@ +INTLTOOL_PERL = @INTLTOOL_PERL@ +INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ +INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@ +INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@ +INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@ +INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@ +INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@ +INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@ +INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@ +INTROSPECTION_LIBS = @INTROSPECTION_LIBS@ +INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@ +INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@ +INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@ +IPTABLES_PATH = @IPTABLES_PATH@ +IWMX_SDK_CFLAGS = @IWMX_SDK_CFLAGS@ +IWMX_SDK_LIBS = @IWMX_SDK_LIBS@ +KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBDL = @LIBDL@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBM = @LIBM@ +LIBNDP_CFLAGS = @LIBNDP_CFLAGS@ +LIBNDP_LIBS = @LIBNDP_LIBS@ +LIBNL_CFLAGS = @LIBNL_CFLAGS@ +LIBNL_LIBS = @LIBNL_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@ +LIBSOUP_LIBS = @LIBSOUP_LIBS@ +LIBTEAMDCTL_CFLAGS = @LIBTEAMDCTL_CFLAGS@ +LIBTEAMDCTL_LIBS = @LIBTEAMDCTL_LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MM_GLIB_CFLAGS = @MM_GLIB_CFLAGS@ +MM_GLIB_LIBS = @MM_GLIB_LIBS@ +MOC = @MOC@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NEWT_CFLAGS = @NEWT_CFLAGS@ +NEWT_LIBS = @NEWT_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ +NM_MICRO_VERSION = @NM_MICRO_VERSION@ +NM_MINOR_VERSION = @NM_MINOR_VERSION@ +NM_MODIFY_SYSTEM_POLICY = @NM_MODIFY_SYSTEM_POLICY@ +NM_VERSION = @NM_VERSION@ +NSS_CFLAGS = @NSS_CFLAGS@ +NSS_LIBS = @NSS_LIBS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +POLKIT_CFLAGS = @POLKIT_CFLAGS@ +POLKIT_LIBS = @POLKIT_LIBS@ +POSUB = @POSUB@ +PPPD_PATH = @PPPD_PATH@ +PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@ +PPPOE_PATH = @PPPOE_PATH@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +RANLIB = @RANLIB@ +READLINE_LIBS = @READLINE_LIBS@ +SED = @SED@ +SELINUX_CFLAGS = @SELINUX_CFLAGS@ +SELINUX_LIBS = @SELINUX_LIBS@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SYSTEMD_200_CFLAGS = @SYSTEMD_200_CFLAGS@ +SYSTEMD_200_LIBS = @SYSTEMD_200_LIBS@ +SYSTEMD_INHIBIT_CFLAGS = @SYSTEMD_INHIBIT_CFLAGS@ +SYSTEMD_INHIBIT_LIBS = @SYSTEMD_INHIBIT_LIBS@ +SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ +SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ +SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ +UDEV_DIR = @UDEV_DIR@ +USE_NLS = @USE_NLS@ +UUID_CFLAGS = @UUID_CFLAGS@ +UUID_LIBS = @UUID_LIBS@ +VALGRIND_RULES = @VALGRIND_RULES@ +VAPIGEN = @VAPIGEN@ +VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@ +VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +intltool__v_merge_options_ = @intltool__v_merge_options_@ +intltool__v_merge_options_0 = @intltool__v_merge_options_0@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +nmbinary = @nmbinary@ +nmconfdir = @nmconfdir@ +nmdatadir = @nmdatadir@ +nmrundir = @nmrundir@ +nmstatedir = @nmstatedir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +systemdsystemunitdir = @systemdsystemunitdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +with_dhclient = @with_dhclient@ +with_dhcpcd = @with_dhcpcd@ +with_netconfig = @with_netconfig@ +with_resolvconf = @with_resolvconf@ +with_valgrind = @with_valgrind@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/include \ + -DG_LOG_DOMAIN=\""nmtui"\" \ + $(GLIB_CFLAGS) \ + $(NEWT_CFLAGS) \ + $(NULL) + +noinst_LIBRARIES = libnmt-newt.a +libnmt_newt_a_SOURCES = \ + nmt-newt.h \ + nmt-newt-types.h \ + nmt-newt-button.c \ + nmt-newt-button.h \ + nmt-newt-button-box.c \ + nmt-newt-button-box.h \ + nmt-newt-checkbox.c \ + nmt-newt-checkbox.h \ + nmt-newt-component.c \ + nmt-newt-component.h \ + nmt-newt-container.c \ + nmt-newt-container.h \ + nmt-newt-entry.c \ + nmt-newt-entry.h \ + nmt-newt-entry-numeric.c \ + nmt-newt-entry-numeric.h \ + nmt-newt-form.c \ + nmt-newt-form.h \ + nmt-newt-grid.c \ + nmt-newt-grid.h \ + nmt-newt-hacks.c \ + nmt-newt-hacks.h \ + nmt-newt-label.c \ + nmt-newt-label.h \ + nmt-newt-listbox.c \ + nmt-newt-listbox.h \ + nmt-newt-popup.c \ + nmt-newt-popup.h \ + nmt-newt-section.c \ + nmt-newt-section.h \ + nmt-newt-separator.c \ + nmt-newt-separator.h \ + nmt-newt-stack.c \ + nmt-newt-stack.h \ + nmt-newt-textbox.c \ + nmt-newt-textbox.h \ + nmt-newt-toggle-button.c \ + nmt-newt-toggle-button.h \ + nmt-newt-utils.c \ + nmt-newt-utils.h \ + nmt-newt-widget.c \ + nmt-newt-widget.h \ + $(NULL) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu clients/tui/newt/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu clients/tui/newt/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +libnmt-newt.a: $(libnmt_newt_a_OBJECTS) $(libnmt_newt_a_DEPENDENCIES) $(EXTRA_libnmt_newt_a_DEPENDENCIES) + $(AM_V_at)-rm -f libnmt-newt.a + $(AM_V_AR)$(libnmt_newt_a_AR) libnmt-newt.a $(libnmt_newt_a_OBJECTS) $(libnmt_newt_a_LIBADD) + $(AM_V_at)$(RANLIB) libnmt-newt.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-button-box.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-button.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-checkbox.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-component.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-container.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-entry-numeric.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-entry.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-form.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-grid.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-hacks.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-label.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-listbox.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-popup.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-section.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-separator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-stack.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-textbox.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-toggle-button.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-utils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-widget.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLIBRARIES cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/clients/tui/newt/nmt-newt-button-box.c b/clients/tui/newt/nmt-newt-button-box.c new file mode 100644 index 00000000..4fba1daf --- /dev/null +++ b/clients/tui/newt/nmt-newt-button-box.c @@ -0,0 +1,386 @@ +/* -*- 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-button-box + * @short_description: A container for #NmtNewtButtons + * + * #NmtNewtButtonBox is a container for creating and holding + * #NmtNewtButtons. + * + * A button box can be either horizontally or vertically laid out, and + * has two sections within it: the "start" (left or top) and "end" + * (right or bottom). Buttons are added from left to right or top to bottom + * within each of the two sections. + */ + +#include "config.h" + +#include <string.h> + +#include "nmt-newt-button-box.h" +#include "nmt-newt-button.h" + +G_DEFINE_TYPE (NmtNewtButtonBox, nmt_newt_button_box, NMT_TYPE_NEWT_CONTAINER) + +#define NMT_NEWT_BUTTON_BOX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_BUTTON_BOX, NmtNewtButtonBoxPrivate)) + +typedef struct { + NmtNewtButtonBoxOrientation orientation; + GPtrArray *start_buttons, *end_buttons; +} NmtNewtButtonBoxPrivate; + +enum { + PROP_0, + + PROP_ORIENTATION, + + LAST_PROP +}; + +/** + * NmtNewtButtonBoxOrientation: + * @NMT_NEWT_BUTTON_BOX_HORIZONTAL: horizontal + * @NMT_NEWT_BUTTON_BOX_VERTICAL: vertical + * + * The orientation of an #NmtNewtButtonBox + */ + +/** + * nmt_newt_button_box_new: + * @orientation: the orientation + * + * Creates a new #NmtNewtButtonBox + * + * Returns: a new #NmtNewtButtonBox + */ +NmtNewtWidget * +nmt_newt_button_box_new (NmtNewtButtonBoxOrientation orientation) +{ + return g_object_new (NMT_TYPE_NEWT_BUTTON_BOX, + "orientation", orientation, + NULL); +} + +static void +nmt_newt_button_box_init (NmtNewtButtonBox *bbox) +{ + NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (bbox); + + priv->start_buttons = g_ptr_array_new (); + priv->end_buttons = g_ptr_array_new (); +} + +/** + * nmt_newt_button_box_add_start: + * @bbox: an #NmtNewtButtonBox + * @label: the label for the newt button + * + * Creates a new #NmtNewtButton with the given @label, adds it + * to the "start" section of @bbox, and returns the newly-created + * button. + * + * Returns: the newly-created button, already added to @bbox + */ +NmtNewtWidget * +nmt_newt_button_box_add_start (NmtNewtButtonBox *bbox, + const char *label) +{ + NmtNewtWidget *button; + + button = nmt_newt_button_new (label); + nmt_newt_button_box_add_widget_start (bbox, button); + return button; +} + +/** + * nmt_newt_button_box_add_widget_start: + * @bbox: an #NmtNewtButtonBox + * @widget: the #NmtNewtWidget to add + * + * Adds the given widget to the "start" section of @bbox. + */ +void +nmt_newt_button_box_add_widget_start (NmtNewtButtonBox *bbox, + NmtNewtWidget *widget) +{ + NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (bbox); + + NMT_NEWT_CONTAINER_CLASS (nmt_newt_button_box_parent_class)-> + add (NMT_NEWT_CONTAINER (bbox), widget); + g_ptr_array_add (priv->start_buttons, widget); +} + +/** + * nmt_newt_button_box_add_end: + * @bbox: an #NmtNewtButtonBox + * @label: the label for the newt button + * + * Creates a new #NmtNewtButton with the given @label, adds it + * to the "end" section of @bbox, and returns the newly-created + * button. + * + * Returns: the newly-created button, already added to @bbox + */ +NmtNewtWidget * +nmt_newt_button_box_add_end (NmtNewtButtonBox *bbox, + const char *label) +{ + NmtNewtWidget *button; + + button = nmt_newt_button_new (label); + nmt_newt_button_box_add_widget_end (bbox, button); + return button; +} + +/** + * nmt_newt_button_box_add_widget_end: + * @bbox: an #NmtNewtButtonBox + * @widget: the #NmtNewtWidget to add + * + * Adds the given widget to the "end" section of @bbox. + */ +void +nmt_newt_button_box_add_widget_end (NmtNewtButtonBox *bbox, + NmtNewtWidget *widget) +{ + NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (bbox); + + NMT_NEWT_CONTAINER_CLASS (nmt_newt_button_box_parent_class)-> + add (NMT_NEWT_CONTAINER (bbox), widget); + g_ptr_array_add (priv->end_buttons, widget); +} + +static void +nmt_newt_button_box_remove (NmtNewtContainer *container, + NmtNewtWidget *child) +{ + NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (container); + int i; + + NMT_NEWT_CONTAINER_CLASS (nmt_newt_button_box_parent_class)-> + remove (container, child); + + for (i = 0; i < priv->start_buttons->len; i++) { + if (priv->start_buttons->pdata[i] == (gpointer) child) { + g_ptr_array_remove_index (priv->start_buttons, i); + return; + } + } + for (i = 0; i < priv->end_buttons->len; i++) { + if (priv->end_buttons->pdata[i] == (gpointer) child) { + g_ptr_array_remove_index (priv->end_buttons, i); + return; + } + } +} + +static void +add_buttons (GPtrArray *buttons, GPtrArray *cos) +{ + NmtNewtWidget *child; + newtComponent *child_cos; + int i, c; + + for (i = 0; i < buttons->len; i++) { + child = buttons->pdata[i]; + + if (!nmt_newt_widget_get_visible (child)) + continue; + + child_cos = nmt_newt_widget_get_components (child); + for (c = 0; child_cos[c]; c++) + g_ptr_array_add (cos, child_cos[c]); + g_free (child_cos); + } +} + +static newtComponent * +nmt_newt_button_box_get_components (NmtNewtWidget *widget) +{ + NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (widget); + GPtrArray *cos; + + cos = g_ptr_array_new (); + add_buttons (priv->start_buttons, cos); + add_buttons (priv->end_buttons, cos); + g_ptr_array_add (cos, NULL); + + return (newtComponent *) g_ptr_array_free (cos, FALSE); +} + +static void +size_request_buttons (NmtNewtButtonBox *bbox, + GPtrArray *buttons, + int *width, + int *height) +{ + NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (bbox); + int child_width, child_height; + int i; + + for (i = 0; i < buttons->len; i++) { + NmtNewtWidget *child = buttons->pdata[i]; + + nmt_newt_widget_size_request (child, &child_width, &child_height); + if (priv->orientation == NMT_NEWT_BUTTON_BOX_HORIZONTAL) { + *width += child_width; + if (i > 0) + *width += 1; + *height = MAX (*height, child_height); + } else { + *height += child_height; + if (i > 0) + *height += 1; + *width = MAX (*width, child_width); + } + } +} + +static void +nmt_newt_button_box_size_request (NmtNewtWidget *widget, + int *width, + int *height) +{ + NmtNewtButtonBox *bbox = NMT_NEWT_BUTTON_BOX (widget); + NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (widget); + + *width = *height = 0; + size_request_buttons (bbox, priv->start_buttons, width, height); + size_request_buttons (bbox, priv->end_buttons, width, height); + + if (priv->start_buttons && priv->end_buttons) { + if (priv->orientation == NMT_NEWT_BUTTON_BOX_HORIZONTAL) + *width += 1; + else + *height += 1; + } +} + +static void +nmt_newt_button_box_size_allocate (NmtNewtWidget *widget, + int x, + int y, + int width, + int height) +{ + NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (widget); + NmtNewtWidget *child; + int child_x, child_y, child_width, child_height; + int i; + + child_x = x; + child_y = y; + for (i = 0; i < priv->start_buttons->len; i++) { + child = priv->start_buttons->pdata[i]; + nmt_newt_widget_size_request (child, &child_width, &child_height); + + if (priv->orientation == NMT_NEWT_BUTTON_BOX_HORIZONTAL) { + nmt_newt_widget_size_allocate (child, child_x, child_y, child_width, child_height); + child_x += child_width + 1; + } else { + nmt_newt_widget_size_allocate (child, child_x, child_y, child_width, child_height); + child_y += child_height + 1; + } + } + + if (priv->orientation == NMT_NEWT_BUTTON_BOX_HORIZONTAL) + child_x = x + width; + else + child_y = y + height; + + for (i = priv->end_buttons->len - 1; i >= 0; i--) { + child = priv->end_buttons->pdata[i]; + nmt_newt_widget_size_request (child, &child_width, &child_height); + + if (priv->orientation == NMT_NEWT_BUTTON_BOX_HORIZONTAL) { + nmt_newt_widget_size_allocate (child, + child_x - child_width, child_y, + child_width, child_height); + child_x -= child_width + 1; + } else { + nmt_newt_widget_size_allocate (child, + child_x, child_y - child_height, + child_width, child_height); + child_y -= child_height + 1; + } + } +} + +static void +nmt_newt_button_box_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_ORIENTATION: + priv->orientation = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_button_box_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_ORIENTATION: + g_value_set_int (value, priv->orientation); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_button_box_class_init (NmtNewtButtonBoxClass *bbox_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (bbox_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (bbox_class); + NmtNewtContainerClass *container_class = NMT_NEWT_CONTAINER_CLASS (bbox_class); + + g_type_class_add_private (bbox_class, sizeof (NmtNewtButtonBoxPrivate)); + + object_class->get_property = nmt_newt_button_box_get_property; + object_class->set_property = nmt_newt_button_box_set_property; + + widget_class->get_components = nmt_newt_button_box_get_components; + widget_class->size_request = nmt_newt_button_box_size_request; + widget_class->size_allocate = nmt_newt_button_box_size_allocate; + + container_class->remove = nmt_newt_button_box_remove; + + g_object_class_install_property + (object_class, PROP_ORIENTATION, + g_param_spec_int ("orientation", "", "", + 0, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/newt/nmt-newt-button-box.h b/clients/tui/newt/nmt-newt-button-box.h new file mode 100644 index 00000000..970588a4 --- /dev/null +++ b/clients/tui/newt/nmt-newt-button-box.h @@ -0,0 +1,65 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_BUTTON_BOX_H +#define NMT_NEWT_BUTTON_BOX_H + +#include "nmt-newt-grid.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_BUTTON_BOX (nmt_newt_button_box_get_type ()) +#define NMT_NEWT_BUTTON_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_BUTTON_BOX, NmtNewtButtonBox)) +#define NMT_NEWT_BUTTON_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_BUTTON_BOX, NmtNewtButtonBoxClass)) +#define NMT_IS_NEWT_BUTTON_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_BUTTON_BOX)) +#define NMT_IS_NEWT_BUTTON_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_BUTTON_BOX)) +#define NMT_NEWT_BUTTON_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_BUTTON_BOX, NmtNewtButtonBoxClass)) + +struct _NmtNewtButtonBox { + NmtNewtContainer parent; + +}; + +typedef struct { + NmtNewtContainerClass parent; + +} NmtNewtButtonBoxClass; + +GType nmt_newt_button_box_get_type (void); + +typedef enum { + NMT_NEWT_BUTTON_BOX_HORIZONTAL, + NMT_NEWT_BUTTON_BOX_VERTICAL +} NmtNewtButtonBoxOrientation; + +NmtNewtWidget *nmt_newt_button_box_new (NmtNewtButtonBoxOrientation orientation); + +NmtNewtWidget *nmt_newt_button_box_add_start (NmtNewtButtonBox *bbox, + const char *label); +NmtNewtWidget *nmt_newt_button_box_add_end (NmtNewtButtonBox *bbox, + const char *label); + +void nmt_newt_button_box_add_widget_start (NmtNewtButtonBox *bbox, + NmtNewtWidget *widget); +void nmt_newt_button_box_add_widget_end (NmtNewtButtonBox *bbox, + NmtNewtWidget *widget); + + +G_END_DECLS + +#endif /* NMT_NEWT_BUTTON_BOX_H */ diff --git a/clients/tui/newt/nmt-newt-button.c b/clients/tui/newt/nmt-newt-button.c new file mode 100644 index 00000000..00dbcd79 --- /dev/null +++ b/clients/tui/newt/nmt-newt-button.c @@ -0,0 +1,261 @@ +/* -*- 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-button + * @short_description: Push buttons + * + * #NmtNewtButton implements a button widget. + */ + +#include "config.h" + +#include "nmt-newt-button.h" +#include "nmt-newt-utils.h" + +G_DEFINE_TYPE (NmtNewtButton, nmt_newt_button, NMT_TYPE_NEWT_COMPONENT) + +#define NMT_NEWT_BUTTON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_BUTTON, NmtNewtButtonPrivate)) + +typedef struct { + char *label; +} NmtNewtButtonPrivate; + +enum { + PROP_0, + PROP_LABEL, + + LAST_PROP +}; + +enum { + CLICKED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +/** + * nmt_newt_button_new: + * @label: the (initial) button label + * + * Creates a new button. + * + * Returns: a new #NmtNewtButton + */ +NmtNewtWidget * +nmt_newt_button_new (const char *label) +{ + return g_object_new (NMT_TYPE_NEWT_BUTTON, + "label", label, + NULL); +} + +/** + * nmt_newt_button_set_label: + * @button: an #NmtNewtButton + * @label: the new label + * + * Updates @button's label. + */ +void +nmt_newt_button_set_label (NmtNewtButton *button, + const char *label) +{ + NmtNewtButtonPrivate *priv = NMT_NEWT_BUTTON_GET_PRIVATE (button); + + if (!g_strcmp0 (priv->label, label)) + return; + + g_free (priv->label); + priv->label = g_strdup (label); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (button)); +} + +/** + * nmt_newt_button_get_label: + * @button: an #NmtNewtButton + * + * Gets @button's label. + * + * Returns: @button's label. + */ +const char * +nmt_newt_button_get_label (NmtNewtButton *button) +{ + NmtNewtButtonPrivate *priv = NMT_NEWT_BUTTON_GET_PRIVATE (button); + + return priv->label; +} + +static void +nmt_newt_button_init (NmtNewtButton *button) +{ +} + +static void +nmt_newt_button_finalize (GObject *object) +{ + NmtNewtButtonPrivate *priv = NMT_NEWT_BUTTON_GET_PRIVATE (object); + + g_free (priv->label); + + G_OBJECT_CLASS (nmt_newt_button_parent_class)->finalize (object); +} + +static newtComponent +nmt_newt_button_build_component (NmtNewtComponent *component, + gboolean sensitive) +{ + NmtNewtButtonPrivate *priv = NMT_NEWT_BUTTON_GET_PRIVATE (component); + newtComponent co; + char *label = NULL, *label_lc; + + if (sensitive) { + label_lc = nmt_newt_locale_from_utf8 (priv->label); + co = newtCompactButton (-1, -1, label_lc); + g_free (label_lc); + } else { + label = g_strdup_printf (" <%s>", priv->label); + label_lc = nmt_newt_locale_from_utf8 (label); + co = newtLabel (-1, -1, label_lc); + g_free (label_lc); + newtLabelSetColors (co, NMT_NEWT_COLORSET_DISABLED_BUTTON); + } + + return co; +} + +static void +nmt_newt_button_size_request (NmtNewtWidget *widget, + int *width, + int *height) +{ + NMT_NEWT_WIDGET_CLASS (nmt_newt_button_parent_class)->size_request (widget, width, height); + + /* remove the automatically-added left padding */ + (*width)--; +} + +static void +nmt_newt_button_size_allocate (NmtNewtWidget *widget, + int x, + int y, + int width, + int height) +{ + /* account for the automatically-added left padding */ + x--; + width++; + + NMT_NEWT_WIDGET_CLASS (nmt_newt_button_parent_class)->size_allocate (widget, x, y, width, height); +} + +static void +nmt_newt_button_activated (NmtNewtWidget *widget) +{ + g_signal_emit (widget, signals[CLICKED], 0); + + NMT_NEWT_WIDGET_CLASS (nmt_newt_button_parent_class)->activated (widget); +} + +static void +nmt_newt_button_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) { + case PROP_LABEL: + nmt_newt_button_set_label (NMT_NEWT_BUTTON (object), + g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_button_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtButtonPrivate *priv = NMT_NEWT_BUTTON_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_LABEL: + g_value_set_string (value, priv->label); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_button_class_init (NmtNewtButtonClass *button_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (button_class); + NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (button_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (button_class); + + g_type_class_add_private (button_class, sizeof (NmtNewtButtonPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_button_set_property; + object_class->get_property = nmt_newt_button_get_property; + object_class->finalize = nmt_newt_button_finalize; + + widget_class->size_request = nmt_newt_button_size_request; + widget_class->size_allocate = nmt_newt_button_size_allocate; + widget_class->activated = nmt_newt_button_activated; + + component_class->build_component = nmt_newt_button_build_component; + + /* signals */ + + /** + * NmtNewtButton::clicked: + * @button: the #NmtNewtButton + * + * Emitted when the button is clicked. + */ + signals[CLICKED] = + g_signal_new ("clicked", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); + + /* properties */ + + /** + * NmtNewtButton:label: + * + * The button's label + */ + g_object_class_install_property + (object_class, PROP_LABEL, + g_param_spec_string ("label", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/newt/nmt-newt-button.h b/clients/tui/newt/nmt-newt-button.h new file mode 100644 index 00000000..52e95c5d --- /dev/null +++ b/clients/tui/newt/nmt-newt-button.h @@ -0,0 +1,53 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_BUTTON_H +#define NMT_NEWT_BUTTON_H + +#include "nmt-newt-component.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_BUTTON (nmt_newt_button_get_type ()) +#define NMT_NEWT_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_BUTTON, NmtNewtButton)) +#define NMT_NEWT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_BUTTON, NmtNewtButtonClass)) +#define NMT_IS_NEWT_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_BUTTON)) +#define NMT_IS_NEWT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_BUTTON)) +#define NMT_NEWT_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_BUTTON, NmtNewtButtonClass)) + +struct _NmtNewtButton { + NmtNewtComponent parent; + +}; + +typedef struct { + NmtNewtComponentClass parent; + +} NmtNewtButtonClass; + +GType nmt_newt_button_get_type (void); + +NmtNewtWidget *nmt_newt_button_new (const char *label); + +void nmt_newt_button_set_label (NmtNewtButton *button, + const char *label); +const char *nmt_newt_button_get_label (NmtNewtButton *button); + +G_END_DECLS + +#endif /* NMT_NEWT_BUTTON_H */ diff --git a/clients/tui/newt/nmt-newt-checkbox.c b/clients/tui/newt/nmt-newt-checkbox.c new file mode 100644 index 00000000..69d9920a --- /dev/null +++ b/clients/tui/newt/nmt-newt-checkbox.c @@ -0,0 +1,237 @@ +/* -*- 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-checkbox + * @short_description: Checkboxes + * + * #NmtNewtCheckbox implements a checkbox widget. + */ + +#include "config.h" + +#include "nmt-newt-checkbox.h" +#include "nmt-newt-utils.h" + +G_DEFINE_TYPE (NmtNewtCheckbox, nmt_newt_checkbox, NMT_TYPE_NEWT_COMPONENT) + +#define NMT_NEWT_CHECKBOX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_CHECKBOX, NmtNewtCheckboxPrivate)) + +typedef struct { + char *label_lc; + gboolean active; +} NmtNewtCheckboxPrivate; + +enum { + PROP_0, + PROP_LABEL, + PROP_ACTIVE, + + LAST_PROP +}; + +#define CHECKBOX_INACTIVE ' ' +#define CHECKBOX_ACTIVE 'X' +#define CHECKBOX_STATES " X" + +/** + * nmt_newt_checkbox_new: + * @label: the (initial) checkbox label + * + * Creates a new checkbox. + * + * Returns: a new #NmtNewtCheckbox + */ +NmtNewtWidget * +nmt_newt_checkbox_new (const char *label) +{ + return g_object_new (NMT_TYPE_NEWT_CHECKBOX, + "label", label, + NULL); +} + +/** + * nmt_newt_checkbox_set_active: + * @checkbox: an #NmtNewtCheckbox + * @active: whether @checkbox should be checked + * + * Updates @checkbox's checked state + */ +void +nmt_newt_checkbox_set_active (NmtNewtCheckbox *checkbox, + gboolean active) +{ + NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (checkbox); + newtComponent co; + + active = !!active; + if (active == priv->active) + return; + + priv->active = active; + + co = nmt_newt_component_get_component (NMT_NEWT_COMPONENT (checkbox)); + if (co) + newtCheckboxSetValue (co, priv->active ? CHECKBOX_ACTIVE : CHECKBOX_INACTIVE); + + g_object_notify (G_OBJECT (checkbox), "active"); +} + +/** + * nmt_newt_checkbox_get_active: + * @checkbox: an #NmtNewtCheckbox + * + * Gets @checkbox's checked state + * + * Returns: @checkbox's checked state + */ +gboolean +nmt_newt_checkbox_get_active (NmtNewtCheckbox *checkbox) +{ + NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (checkbox); + + return priv->active; +} + +static void +nmt_newt_checkbox_init (NmtNewtCheckbox *checkbox) +{ +} + +static void +nmt_newt_checkbox_finalize (GObject *object) +{ + NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (object); + + g_free (priv->label_lc); + + G_OBJECT_CLASS (nmt_newt_checkbox_parent_class)->finalize (object); +} + +static void +checkbox_toggled_callback (newtComponent co, + void *checkbox) +{ + NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (checkbox); + gboolean active; + + active = (newtCheckboxGetValue (co) == CHECKBOX_ACTIVE); + if (active != priv->active) { + priv->active = active; + g_object_notify (checkbox, "active"); + } +} + +static newtComponent +nmt_newt_checkbox_build_component (NmtNewtComponent *component, + gboolean sensitive) +{ + NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (component); + newtComponent co; + + co = newtCheckbox (-1, -1, priv->label_lc, + priv->active ? CHECKBOX_ACTIVE : CHECKBOX_INACTIVE, + CHECKBOX_STATES, NULL); + if (!sensitive) + newtCheckboxSetFlags (co, NEWT_FLAG_DISABLED, NEWT_FLAGS_SET); + newtComponentAddCallback (co, checkbox_toggled_callback, component); + return co; +} + +static void +nmt_newt_checkbox_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtCheckbox *checkbox = NMT_NEWT_CHECKBOX (object); + NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_LABEL: + g_free (priv->label_lc); + priv->label_lc = nmt_newt_locale_from_utf8 (g_value_get_string (value)); + break; + case PROP_ACTIVE: + nmt_newt_checkbox_set_active (checkbox, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_checkbox_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_LABEL: + g_value_take_string (value, nmt_newt_locale_to_utf8 (priv->label_lc)); + break; + case PROP_ACTIVE: + g_value_set_boolean (value, priv->active); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_checkbox_class_init (NmtNewtCheckboxClass *checkbox_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (checkbox_class); + NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (checkbox_class); + + g_type_class_add_private (checkbox_class, sizeof (NmtNewtCheckboxPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_checkbox_set_property; + object_class->get_property = nmt_newt_checkbox_get_property; + object_class->finalize = nmt_newt_checkbox_finalize; + + component_class->build_component = nmt_newt_checkbox_build_component; + + /** + * NmtNewtCheckbox:label: + * + * The checkbox's label + */ + g_object_class_install_property + (object_class, PROP_LABEL, + g_param_spec_string ("label", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtCheckbox:active: + * + * The checkbox's checked state + */ + g_object_class_install_property + (object_class, PROP_ACTIVE, + g_param_spec_boolean ("active", "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/newt/nmt-newt-checkbox.h b/clients/tui/newt/nmt-newt-checkbox.h new file mode 100644 index 00000000..c277386b --- /dev/null +++ b/clients/tui/newt/nmt-newt-checkbox.h @@ -0,0 +1,53 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_CHECKBOX_H +#define NMT_NEWT_CHECKBOX_H + +#include "nmt-newt-component.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_CHECKBOX (nmt_newt_checkbox_get_type ()) +#define NMT_NEWT_CHECKBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_CHECKBOX, NmtNewtCheckbox)) +#define NMT_NEWT_CHECKBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_CHECKBOX, NmtNewtCheckboxClass)) +#define NMT_IS_NEWT_CHECKBOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_CHECKBOX)) +#define NMT_IS_NEWT_CHECKBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_CHECKBOX)) +#define NMT_NEWT_CHECKBOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_CHECKBOX, NmtNewtCheckboxClass)) + +struct _NmtNewtCheckbox { + NmtNewtComponent parent; + +}; + +typedef struct { + NmtNewtComponentClass parent; + +} NmtNewtCheckboxClass; + +GType nmt_newt_checkbox_get_type (void); + +NmtNewtWidget *nmt_newt_checkbox_new (const char *label); + +void nmt_newt_checkbox_set_active (NmtNewtCheckbox *checkbox, + gboolean active); +gboolean nmt_newt_checkbox_get_active (NmtNewtCheckbox *checkbox); + +G_END_DECLS + +#endif /* NMT_NEWT_CHECKBOX_H */ diff --git a/clients/tui/newt/nmt-newt-component.c b/clients/tui/newt/nmt-newt-component.c new file mode 100644 index 00000000..98f6df63 --- /dev/null +++ b/clients/tui/newt/nmt-newt-component.c @@ -0,0 +1,309 @@ +/* -*- 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-component + * @short_description: Base class for widgets that wrap #newtComponents + * + * #NmtNewtComponent is the abstract class for #NmtNewtWidgets that + * wrap a (single) #newtComponent. + */ + +#include "config.h" + +#include "nmt-newt-component.h" +#include "nmt-newt-form.h" +#include "nmt-newt-hacks.h" + +G_DEFINE_ABSTRACT_TYPE (NmtNewtComponent, nmt_newt_component, NMT_TYPE_NEWT_WIDGET) + +#define NMT_NEWT_COMPONENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_COMPONENT, NmtNewtComponentPrivate)) + +typedef struct { + newtComponent co; + gboolean own_component; + gboolean sensitive; +} NmtNewtComponentPrivate; + +enum { + PROP_0, + + PROP_COMPONENT, + PROP_SENSITIVE, + + LAST_PROP +}; + +static void +nmt_newt_component_init (NmtNewtComponent *component) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (component); + + priv->sensitive = TRUE; +} + +static void +nmt_newt_component_unrealize (NmtNewtWidget *widget) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget); + + if (!priv->co) + return; + + newtComponentAddCallback (priv->co, NULL, NULL); + newtComponentAddDestroyCallback (priv->co, NULL, NULL); + + if (priv->own_component) + newtComponentDestroy (priv->co); + priv->co = NULL; +} + +static void +component_destroy_callback (newtComponent co, + void *component) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (component); + + priv->own_component = FALSE; + nmt_newt_widget_unrealize (component); + nmt_newt_widget_needs_rebuild (component); +} + +static void +nmt_newt_component_realize (NmtNewtWidget *widget) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget); + + nmt_newt_component_unrealize (widget); + priv->co = NMT_NEWT_COMPONENT_GET_CLASS (widget)-> + build_component (NMT_NEWT_COMPONENT (widget), priv->sensitive); + priv->own_component = TRUE; + if (!priv->sensitive) + newtComponentTakesFocus (priv->co, FALSE); + newtComponentAddDestroyCallback (priv->co, component_destroy_callback, widget); +} + +static newtComponent * +nmt_newt_component_get_components (NmtNewtWidget *widget) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget); + newtComponent *cos; + + priv->own_component = FALSE; + cos = g_new0 (newtComponent, 2); + cos[0] = priv->co; + return cos; +} + +static NmtNewtWidget * +nmt_newt_component_find_component (NmtNewtWidget *widget, + newtComponent co) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget); + + if (co == priv->co) + return widget; + else + return NULL; +} + +static void +nmt_newt_component_size_request (NmtNewtWidget *widget, + int *width, + int *height) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget); + + newtComponentGetSize (priv->co, width, height); +} + +static void +nmt_newt_component_size_allocate (NmtNewtWidget *widget, + int x, + int y, + int width, + int height) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget); + newtGrid grid; + + /* You can't directly place a newtComponent, so we create a newtGrid, + * position the component within that, and then place the grid. + */ + grid = newtCreateGrid (1, 1); + newtGridSetField (grid, 0, 0, + NEWT_GRID_COMPONENT, priv->co, + x, y, 0, 0, + NEWT_ANCHOR_LEFT | NEWT_ANCHOR_TOP, 0); + newtGridPlace (grid, 0, 0); + newtGridFree (grid, FALSE); +} + +static newtComponent +nmt_newt_component_get_focus_component (NmtNewtWidget *widget) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget); + + return priv->co; +} + +/** + * nmt_newt_component_get_component: + * @component: an #NmtNewtComponent + * + * A simpler version of nmt_newt_widget_get_components() for the + * single-component case. Also, unlike + * nmt_newt_widget_get_component(), this does not realize the widget + * if it isn't already realized. FIXME: why? + * + * Returns: @component's #newtComponent + */ +newtComponent +nmt_newt_component_get_component (NmtNewtComponent *component) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (component); + + return priv->co; +} + +/** + * nmt_newt_component_get_sensitive: + * @component: an #NmtNewtComponent + * + * Gets @component's #NmtNewtComponent:sensitive property, indicating + * whether the widget is available for manipulation. Insensitive + * components will be skipped over in the keyboard tab chain, and may + * be displayed differently. + * + * Returns: @component's #NmtNewtComponent:sensitive property + */ +gboolean +nmt_newt_component_get_sensitive (NmtNewtComponent *component) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (component); + + return priv->sensitive; +} + +/** + * nmt_newt_component_set_sensitive: + * @component: an #NmtNewtComponent + * @sensitive: whether @component should be sensitive + * + * Sets @component's #NmtNewtComponent:sensitive property. + */ +void +nmt_newt_component_set_sensitive (NmtNewtComponent *component, + gboolean sensitive) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (component); + + sensitive = !!sensitive; + if (priv->sensitive == sensitive) + return; + + priv->sensitive = sensitive; + g_object_notify (G_OBJECT (component), "sensitive"); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (component)); +} + +static void +nmt_newt_component_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtComponent *component = NMT_NEWT_COMPONENT (object); + + switch (prop_id) { + case PROP_SENSITIVE: + nmt_newt_component_set_sensitive (component, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_component_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtComponent *component = NMT_NEWT_COMPONENT (object); + + switch (prop_id) { + case PROP_COMPONENT: + g_value_set_pointer (value, nmt_newt_component_get_component (component)); + break; + case PROP_SENSITIVE: + g_value_set_boolean (value, nmt_newt_component_get_sensitive (component)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_component_class_init (NmtNewtComponentClass *component_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (component_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (component_class); + + g_type_class_add_private (component_class, sizeof (NmtNewtComponentPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_component_set_property; + object_class->get_property = nmt_newt_component_get_property; + + widget_class->realize = nmt_newt_component_realize; + widget_class->unrealize = nmt_newt_component_unrealize; + widget_class->get_components = nmt_newt_component_get_components; + widget_class->find_component = nmt_newt_component_find_component; + widget_class->size_request = nmt_newt_component_size_request; + widget_class->size_allocate = nmt_newt_component_size_allocate; + widget_class->get_focus_component = nmt_newt_component_get_focus_component; + + /* properties */ + + /** + * NmtNewtComponent:component: + * + * The component's #newtComponent + */ + g_object_class_install_property + (object_class, PROP_COMPONENT, + g_param_spec_pointer ("component", "", "", + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtComponent:sensitive: + * + * Whether the component is sensitive. Insensitive components will + * be skipped over in the keyboard tab chain, and may be displayed + * differently. + */ + g_object_class_install_property + (object_class, PROP_SENSITIVE, + g_param_spec_boolean ("sensitive", "", "", + TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/newt/nmt-newt-component.h b/clients/tui/newt/nmt-newt-component.h new file mode 100644 index 00000000..2ffa018e --- /dev/null +++ b/clients/tui/newt/nmt-newt-component.h @@ -0,0 +1,57 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_COMPONENT_H +#define NMT_NEWT_COMPONENT_H + +#include "nmt-newt-widget.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_COMPONENT (nmt_newt_component_get_type ()) +#define NMT_NEWT_COMPONENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_COMPONENT, NmtNewtComponent)) +#define NMT_NEWT_COMPONENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_COMPONENT, NmtNewtComponentClass)) +#define NMT_IS_NEWT_COMPONENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_COMPONENT)) +#define NMT_IS_NEWT_COMPONENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_COMPONENT)) +#define NMT_NEWT_COMPONENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_COMPONENT, NmtNewtComponentClass)) + +struct _NmtNewtComponent { + NmtNewtWidget parent; + +}; + +typedef struct { + NmtNewtWidgetClass parent; + + /* methods */ + newtComponent (*build_component) (NmtNewtComponent *component, + gboolean sensitive); + +} NmtNewtComponentClass; + +GType nmt_newt_component_get_type (void); + +newtComponent nmt_newt_component_get_component (NmtNewtComponent *component); + +gboolean nmt_newt_component_get_sensitive (NmtNewtComponent *component); +void nmt_newt_component_set_sensitive (NmtNewtComponent *component, + gboolean sensitive); + +G_END_DECLS + +#endif /* NMT_NEWT_COMPONENT_H */ diff --git a/clients/tui/newt/nmt-newt-container.c b/clients/tui/newt/nmt-newt-container.c new file mode 100644 index 00000000..03f677fb --- /dev/null +++ b/clients/tui/newt/nmt-newt-container.c @@ -0,0 +1,252 @@ +/* -*- 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-container + * @short_description: Base class for containers + * + * #NmtNewtContainer is the base class for #NmtNewtWidgets that + * contain other widgets. + * + * #NmtNewtGrid is the most generic container type. + */ + +#include "config.h" + +#include <string.h> + +#include "nmt-newt-container.h" +#include "nmt-newt-component.h" + +G_DEFINE_ABSTRACT_TYPE (NmtNewtContainer, nmt_newt_container, NMT_TYPE_NEWT_WIDGET) + +#define NMT_NEWT_CONTAINER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_CONTAINER, NmtNewtContainerPrivate)) + +typedef struct { + GPtrArray *children; + +} NmtNewtContainerPrivate; + +static void child_needs_rebuild (NmtNewtWidget *widget, gpointer user_data); + +static void +nmt_newt_container_init (NmtNewtContainer *container) +{ + NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (container); + + priv->children = g_ptr_array_new (); +} + +static void +nmt_newt_container_finalize (GObject *object) +{ + NmtNewtContainer *container = NMT_NEWT_CONTAINER (object); + NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (object); + + while (priv->children->len) + nmt_newt_container_remove (container, priv->children->pdata[0]); + + G_OBJECT_CLASS (nmt_newt_container_parent_class)->finalize (object); +} + +static void +nmt_newt_container_realize (NmtNewtWidget *widget) +{ + NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (widget); + int i; + + for (i = 0; i < priv->children->len; i++) + nmt_newt_widget_realize (priv->children->pdata[i]); +} + +static void +nmt_newt_container_unrealize (NmtNewtWidget *widget) +{ + NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (widget); + int i; + + for (i = 0; i < priv->children->len; i++) + nmt_newt_widget_unrealize (priv->children->pdata[i]); +} + +static void +child_needs_rebuild (NmtNewtWidget *widget, + gpointer user_data) +{ + NmtNewtWidget *container = user_data; + + nmt_newt_widget_needs_rebuild (container); +} + +static void +nmt_newt_container_real_child_validity_changed (NmtNewtContainer *container, + NmtNewtWidget *widget) +{ + NmtNewtContainerPrivate *priv; + int i; + + if (widget) { + if (!nmt_newt_widget_get_visible (widget)) + return; + if (!nmt_newt_widget_get_valid (widget)) { + nmt_newt_widget_set_valid (NMT_NEWT_WIDGET (container), FALSE); + return; + } + } + + priv = NMT_NEWT_CONTAINER_GET_PRIVATE (container); + for (i = 0; i < priv->children->len; i++) { + widget = priv->children->pdata[i]; + if ( nmt_newt_widget_get_visible (widget) + && !nmt_newt_widget_get_valid (widget)) { + nmt_newt_widget_set_valid (NMT_NEWT_WIDGET (container), FALSE); + return; + } + } + + nmt_newt_widget_set_valid (NMT_NEWT_WIDGET (container), TRUE); +} + +static void +nmt_newt_container_child_validity_changed (NmtNewtContainer *container, + NmtNewtWidget *widget) +{ + NMT_NEWT_CONTAINER_GET_CLASS (container)->child_validity_changed (container, widget); +} + +static void +child_validity_notify (GObject *object, + GParamSpec *pspec, + gpointer container) +{ + nmt_newt_container_child_validity_changed (container, NMT_NEWT_WIDGET (object)); +} + +static void +nmt_newt_container_real_add (NmtNewtContainer *container, + NmtNewtWidget *widget) +{ + NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (container); + + g_signal_connect (widget, "needs-rebuild", G_CALLBACK (child_needs_rebuild), container); + g_signal_connect (widget, "notify::valid", G_CALLBACK (child_validity_notify), container); + g_ptr_array_add (priv->children, g_object_ref_sink (widget)); + nmt_newt_widget_set_parent (widget, NMT_NEWT_WIDGET (container)); + + nmt_newt_container_child_validity_changed (container, widget); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (container)); +} + +static void +nmt_newt_container_real_remove (NmtNewtContainer *container, + NmtNewtWidget *widget) +{ + NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (container); + int i; + + for (i = 0; i < priv->children->len; i++) { + if (widget == priv->children->pdata[i]) { + g_ptr_array_remove_index (priv->children, i); + g_signal_handlers_disconnect_by_func (widget, G_CALLBACK (child_needs_rebuild), container); + g_signal_handlers_disconnect_by_func (widget, G_CALLBACK (child_validity_notify), container); + nmt_newt_widget_set_parent (widget, NULL); + g_object_unref (widget); + + nmt_newt_container_child_validity_changed (container, NULL); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (container)); + return; + } + } +} + +/** + * nmt_newt_container_remove: + * @container: the #NmtNewtContainer + * @widget: the child to remove + * + * Removes @widget from @container. + * + * Note that there is not a corresponding + * <literal>nmt_newt_container_add ()</literal>; you must use + * container-type-specific methods to add widgets to containers. + */ +void +nmt_newt_container_remove (NmtNewtContainer *container, + NmtNewtWidget *widget) +{ + NMT_NEWT_CONTAINER_GET_CLASS (container)->remove (container, widget); +} + +static NmtNewtWidget * +nmt_newt_container_find_component (NmtNewtWidget *widget, + newtComponent co) +{ + NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (widget); + NmtNewtWidget *found, *child; + int i; + + for (i = 0; i < priv->children->len; i++) { + child = priv->children->pdata[i]; + + found = nmt_newt_widget_find_component (child, co); + if (found) + return found; + } + + return NULL; +} + +/** + * nmt_newt_container_get_children: + * @container: an #NmtNewtContainer + * + * Gets a list of @container's children. + * + * Returns: (transfer full): a list of @container's children. + */ +GSList * +nmt_newt_container_get_children (NmtNewtContainer *container) +{ + NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (container); + GSList *ret; + int i; + + for (i = 0, ret = NULL; i < priv->children->len; i++) + ret = g_slist_prepend (ret, g_object_ref (priv->children->pdata[i])); + return g_slist_reverse (ret); +} + +static void +nmt_newt_container_class_init (NmtNewtContainerClass *container_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (container_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (container_class); + + g_type_class_add_private (container_class, sizeof (NmtNewtContainerPrivate)); + + /* virtual methods */ + object_class->finalize = nmt_newt_container_finalize; + + widget_class->realize = nmt_newt_container_realize; + widget_class->unrealize = nmt_newt_container_unrealize; + widget_class->find_component = nmt_newt_container_find_component; + + container_class->add = nmt_newt_container_real_add; + container_class->remove = nmt_newt_container_real_remove; + container_class->child_validity_changed = nmt_newt_container_real_child_validity_changed; +} diff --git a/clients/tui/newt/nmt-newt-container.h b/clients/tui/newt/nmt-newt-container.h new file mode 100644 index 00000000..6f182925 --- /dev/null +++ b/clients/tui/newt/nmt-newt-container.h @@ -0,0 +1,61 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_CONTAINER_H +#define NMT_NEWT_CONTAINER_H + +#include "nmt-newt-widget.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_CONTAINER (nmt_newt_container_get_type ()) +#define NMT_NEWT_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_CONTAINER, NmtNewtContainer)) +#define NMT_NEWT_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_CONTAINER, NmtNewtContainerClass)) +#define NMT_IS_NEWT_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_CONTAINER)) +#define NMT_IS_NEWT_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_CONTAINER)) +#define NMT_NEWT_CONTAINER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_CONTAINER, NmtNewtContainerClass)) + +struct _NmtNewtContainer { + NmtNewtWidget parent; + +}; + +typedef struct { + NmtNewtWidgetClass parent; + + /* methods */ + void (*add) (NmtNewtContainer *container, + NmtNewtWidget *child); + void (*remove) (NmtNewtContainer *container, + NmtNewtWidget *child); + + void (*child_validity_changed) (NmtNewtContainer *container, + NmtNewtWidget *child); + +} NmtNewtContainerClass; + +GType nmt_newt_container_get_type (void); + +void nmt_newt_container_remove (NmtNewtContainer *container, + NmtNewtWidget *widget); + +GSList *nmt_newt_container_get_children (NmtNewtContainer *container); + +G_END_DECLS + +#endif /* NMT_NEWT_CONTAINER_H */ diff --git a/clients/tui/newt/nmt-newt-entry-numeric.c b/clients/tui/newt/nmt-newt-entry-numeric.c new file mode 100644 index 00000000..416b4b79 --- /dev/null +++ b/clients/tui/newt/nmt-newt-entry-numeric.c @@ -0,0 +1,215 @@ +/* -*- 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-entry-numeric + * @short_description: Numeric text entry + * + * #NmtNewtEntryNumeric implements a numeric-only #NmtNewtEntry. + * + * #NmtNewtEntryNumeric provides its own #NmtNewtEntryFilter and + * #NmtNewtEntryValidator functions, so you should not set your own. + */ + +#include "config.h" + +#include <stdlib.h> + +#include "nmt-newt-entry-numeric.h" + +G_DEFINE_TYPE (NmtNewtEntryNumeric, nmt_newt_entry_numeric, NMT_TYPE_NEWT_ENTRY) + +#define NMT_NEWT_ENTRY_NUMERIC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_ENTRY_NUMERIC, NmtNewtEntryNumericPrivate)) + +typedef struct { + int min, max; +} NmtNewtEntryNumericPrivate; + +enum { + PROP_0, + PROP_MINIMUM, + PROP_MAXIMUM, + + LAST_PROP +}; + +/** + * nmt_newt_entry_numeric_new: + * @width: the entry's width in characters + * @min: the minimum valid value + * @max: the maximum valid value + * + * Creates a new #NmtNewtEntryNumeric, accepting values in the + * indicated range. + * + * Returns: a new #NmtNewtEntryNumeric + */ +NmtNewtWidget * +nmt_newt_entry_numeric_new (int width, + int min, + int max) +{ + return g_object_new (NMT_TYPE_NEWT_ENTRY_NUMERIC, + "width", width, + "minimum", min, + "maximum", max, + NULL); +} + +static gboolean +newt_entry_numeric_filter (NmtNewtEntry *entry, + const char *text, + int ch, + int position, + gpointer user_data) +{ + NmtNewtEntryNumericPrivate *priv = NMT_NEWT_ENTRY_NUMERIC_GET_PRIVATE (entry); + + if (g_ascii_isdigit (ch)) + return TRUE; + + if (ch == '-' && position == 0 && priv->min < 0) + return TRUE; + + return FALSE; +} + +static gboolean +newt_entry_numeric_validate (NmtNewtEntry *entry, + const char *text, + gpointer user_data) +{ + NmtNewtEntryNumericPrivate *priv = NMT_NEWT_ENTRY_NUMERIC_GET_PRIVATE (entry); + int val; + char *end; + + if (!*text) + return FALSE; + + val = strtoul (text, &end, 10); + if (*end) + return FALSE; + if (val < priv->min || val > priv->max) + return FALSE; + + return TRUE; +} + +static void +nmt_newt_entry_numeric_init (NmtNewtEntryNumeric *entry) +{ + nmt_newt_entry_set_filter (NMT_NEWT_ENTRY (entry), newt_entry_numeric_filter, NULL); + nmt_newt_entry_set_validator (NMT_NEWT_ENTRY (entry), newt_entry_numeric_validate, NULL); +} + +static void +nmt_newt_entry_numeric_constructed (GObject *object) +{ + NmtNewtEntryNumericPrivate *priv = NMT_NEWT_ENTRY_NUMERIC_GET_PRIVATE (object); + + if (!*nmt_newt_entry_get_text (NMT_NEWT_ENTRY (object))) { + char buf[32]; + + g_snprintf (buf, sizeof (buf), "%d", priv->min); + nmt_newt_entry_set_text (NMT_NEWT_ENTRY (object), buf); + } + + G_OBJECT_CLASS (nmt_newt_entry_numeric_parent_class)->constructed (object); +} + +static void +nmt_newt_entry_numeric_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtEntryNumericPrivate *priv = NMT_NEWT_ENTRY_NUMERIC_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_MINIMUM: + priv->min = g_value_get_int (value); + break; + case PROP_MAXIMUM: + priv->max = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_entry_numeric_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtEntryNumericPrivate *priv = NMT_NEWT_ENTRY_NUMERIC_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_MINIMUM: + g_value_set_int (value, priv->min); + break; + case PROP_MAXIMUM: + g_value_set_int (value, priv->max); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_entry_numeric_class_init (NmtNewtEntryNumericClass *entry_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (entry_class); + + g_type_class_add_private (entry_class, sizeof (NmtNewtEntryNumericPrivate)); + + /* virtual methods */ + object_class->constructed = nmt_newt_entry_numeric_constructed; + object_class->set_property = nmt_newt_entry_numeric_set_property; + object_class->get_property = nmt_newt_entry_numeric_get_property; + + /** + * NmtNewtEntryNumeric:minimum: + * + * The minimum #NmtNewtWidget:valid value for the entry. If this + * is non-negative, then the entry will not allow negative numbers + * to be entered. + */ + g_object_class_install_property + (object_class, PROP_MINIMUM, + g_param_spec_int ("minimum", "", "", + G_MININT, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtEntryNumeric:maximum: + * + * The maximum #NmtNewtWidget:valid value for the entry. + */ + g_object_class_install_property + (object_class, PROP_MAXIMUM, + g_param_spec_int ("maximum", "", "", + G_MININT, G_MAXINT, G_MAXINT, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/newt/nmt-newt-entry-numeric.h b/clients/tui/newt/nmt-newt-entry-numeric.h new file mode 100644 index 00000000..43ac3449 --- /dev/null +++ b/clients/tui/newt/nmt-newt-entry-numeric.h @@ -0,0 +1,51 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_ENTRY_NUMERIC_H +#define NMT_NEWT_ENTRY_NUMERIC_H + +#include "nmt-newt-entry.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_ENTRY_NUMERIC (nmt_newt_entry_numeric_get_type ()) +#define NMT_NEWT_ENTRY_NUMERIC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_ENTRY_NUMERIC, NmtNewtEntryNumeric)) +#define NMT_NEWT_ENTRY_NUMERIC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_ENTRY_NUMERIC, NmtNewtEntryNumericClass)) +#define NMT_IS_NEWT_ENTRY_NUMERIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_ENTRY_NUMERIC)) +#define NMT_IS_NEWT_ENTRY_NUMERIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_ENTRY_NUMERIC)) +#define NMT_NEWT_ENTRY_NUMERIC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_ENTRY_NUMERIC, NmtNewtEntryNumericClass)) + +struct _NmtNewtEntryNumeric { + NmtNewtEntry parent; + +}; + +typedef struct { + NmtNewtEntryClass parent; + +} NmtNewtEntryNumericClass; + +GType nmt_newt_entry_numeric_get_type (void); + +NmtNewtWidget *nmt_newt_entry_numeric_new (int width, + int min, + int max); + +G_END_DECLS + +#endif /* NMT_NEWT_ENTRY_NUMERIC_H */ diff --git a/clients/tui/newt/nmt-newt-entry.c b/clients/tui/newt/nmt-newt-entry.c new file mode 100644 index 00000000..7c92d00a --- /dev/null +++ b/clients/tui/newt/nmt-newt-entry.c @@ -0,0 +1,540 @@ +/* -*- 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-entry + * @short_description: Text entries + * + * #NmtNewtEntry implements entry widgets, with optional filtering and + * validation. + * + * See also #NmtNewtEntryNumeric, for numeric-only entries. + */ + +#include "config.h" + +#include <string.h> + +#include "nmt-newt-entry.h" +#include "nmt-newt-form.h" +#include "nmt-newt-hacks.h" +#include "nmt-newt-utils.h" + +G_DEFINE_TYPE (NmtNewtEntry, nmt_newt_entry, NMT_TYPE_NEWT_COMPONENT) + +#define NMT_NEWT_ENTRY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_ENTRY, NmtNewtEntryPrivate)) + +typedef struct { + int width; + NmtNewtEntryFlags flags; + char *text; + int last_cursor_pos; + guint idle_update; + + NmtNewtEntryFilter filter; + gpointer filter_data; + + NmtNewtEntryValidator validator; + gpointer validator_data; +} NmtNewtEntryPrivate; + +enum { + PROP_0, + PROP_TEXT, + PROP_WIDTH, + PROP_FLAGS, + PROP_PASSWORD, + + LAST_PROP +}; + +/** + * NmtNewtEntryFlags: + * @NMT_NEWT_ENTRY_NOSCROLL: the entry content should not scroll left + * and right + * @NMT_NEWT_ENTRY_PASSWORD: the entry should show '*'s instead of its + * actual contents + * @NMT_NEWT_ENTRY_NONEMPTY: the entry should be considered not + * #NmtNewtWidget:valid if it is empty. + * + * Flags describing an #NmtNewtEntry + */ + +/** + * nmt_newt_entry_new: + * @width: the width in characters for the entry + * @flags: flags describing the entry + * + * Creates a new #NmtNewtEntry. + * + * Returns: a new #NmtNewtEntry + */ +NmtNewtWidget * +nmt_newt_entry_new (int width, + NmtNewtEntryFlags flags) +{ + return g_object_new (NMT_TYPE_NEWT_ENTRY, + "width", width, + "flags", flags, + NULL); +} + +/** + * NmtNewtEntryFilter: + * @entry: the #NmtNewtEntry + * @text: the current contents of @entry + * @ch: the character just typed + * @position: the position of the cursor in @entry + * @user_data: the data passed to nmt_newt_entry_set_filter() + * + * Callback function used to filter the contents of an entry. + * + * Returns: %TRUE if @ch should be accepted, %FALSE if not + */ + +/** + * nmt_newt_entry_set_filter: + * @entry: an #NmtNewtEntry + * @filter: the function to use to filter the entry + * @user_data: data for @filter + * + * Sets a #NmtNewtEntryFilter on @entry, to allow filtering out + * certain characters from the entry. + * + * Note that @filter will only be called for printable characters (eg, + * not for cursor-control characters or the like), and that it will + * only be called for user input, not, eg, for + * nmt_newt_entry_set_text(). + */ +void +nmt_newt_entry_set_filter (NmtNewtEntry *entry, + NmtNewtEntryFilter filter, + gpointer user_data) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + + priv->filter = filter; + priv->filter_data = user_data; +} + +static void +nmt_newt_entry_check_valid (NmtNewtEntry *entry) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + gboolean valid; + + if ( (priv->flags & NMT_NEWT_ENTRY_NONEMPTY) + && *priv->text == '\0') + valid = FALSE; + else if (priv->validator) + valid = !!priv->validator (entry, priv->text, priv->validator_data); + else + valid = TRUE; + + nmt_newt_widget_set_valid (NMT_NEWT_WIDGET (entry), valid); +} + +/** + * NmtNewtEntryValidator: + * @entry: the #NmtNewtEntry + * @text: the current contents of @entry + * @user_data: the data passed to nmt_newt_entry_set_validator() + * + * Callback function used to validate the contents of an entry. + * + * Returns: whether the entry is #NmtNewtWidget:valid + */ + +/** + * nmt_newt_entry_set_validator: + * @entry: an #NmtNewtEntry + * @validator: the function to use to validate the entry + * @user_data: data for @validator + * + * Sets a #NmtNewtEntryValidator on @entry, to allow validation of + * the entry contents. If @validator returns %FALSE, then the entry + * will not be considered #NmtNewtWidget:valid. + */ +void +nmt_newt_entry_set_validator (NmtNewtEntry *entry, + NmtNewtEntryValidator validator, + gpointer user_data) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + + priv->validator = validator; + priv->validator_data = user_data; + + nmt_newt_entry_check_valid (entry); +} + +static void +nmt_newt_entry_set_text_internal (NmtNewtEntry *entry, + const char *text, + newtComponent co) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + + if (!text) + text = ""; + + if (!strcmp (priv->text, text)) + return; + + g_free (priv->text); + priv->text = g_strdup (text); + + if (co) { + char *text_lc; + + text_lc = priv->text ? nmt_newt_locale_from_utf8 (priv->text) : NULL; + newtEntrySet (co, text_lc, TRUE); + g_free (text_lc); + priv->last_cursor_pos = -1; + } + + g_object_freeze_notify (G_OBJECT (entry)); + nmt_newt_entry_check_valid (entry); + g_object_notify (G_OBJECT (entry), "text"); + g_object_thaw_notify (G_OBJECT (entry)); +} + +/** + * nmt_newt_entry_set_text: + * @entry: an #NmtNewtEntry + * @text: the new text + * + * Updates @entry's text. Note that this skips the entry's + * #NmtNewtEntryFilter, but will cause its #NmtNewtEntryValidator to + * be re-run. + */ +void +nmt_newt_entry_set_text (NmtNewtEntry *entry, + const char *text) +{ + newtComponent co; + + co = nmt_newt_component_get_component (NMT_NEWT_COMPONENT (entry)); + nmt_newt_entry_set_text_internal (entry, text, co); +} + +/** + * nmt_newt_entry_get_text: + * @entry: an #NmtNewtEntry + * + * Gets @entry's text + * + * Returns: @entry's text + */ +const char * +nmt_newt_entry_get_text (NmtNewtEntry *entry) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + + return priv->text; +} + +/** + * nmt_newt_entry_set_width: + * @entry: an #NmtNewtEntpry + * @widget: the new width + * + * Updates @entry's width + */ +void +nmt_newt_entry_set_width (NmtNewtEntry *entry, + int width) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + + if (priv->width == width) + return; + + priv->width = width; + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (entry)); + + g_object_notify (G_OBJECT (entry), "width"); +} + +/** + * nmt_newt_entry_get_width: + * @entry: an #NmtNewtEntry + * + * Gets @entry's width + * + * Returns: @entry's width + */ +int +nmt_newt_entry_get_width (NmtNewtEntry *entry) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + + return priv->width; +} + +static void +nmt_newt_entry_init (NmtNewtEntry *entry) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + + priv->text = g_strdup (""); + priv->last_cursor_pos = -1; +} + +static void +nmt_newt_entry_constructed (GObject *object) +{ + nmt_newt_entry_check_valid (NMT_NEWT_ENTRY (object)); + + G_OBJECT_CLASS (nmt_newt_entry_parent_class)->constructed (object); +} + +static void +nmt_newt_entry_finalize (GObject *object) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (object); + + g_free (priv->text); + if (priv->idle_update) + g_source_remove (priv->idle_update); + + G_OBJECT_CLASS (nmt_newt_entry_parent_class)->finalize (object); +} + +static gboolean +idle_update_entry (gpointer entry) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + newtComponent co = nmt_newt_component_get_component (entry); + char *text; + + priv->idle_update = 0; + if (!co) + return FALSE; + + priv->last_cursor_pos = newtEntryGetCursorPosition (co); + + text = nmt_newt_locale_to_utf8 (newtEntryGetValue (co)); + nmt_newt_entry_set_text_internal (entry, text, NULL); + g_free (text); + + return FALSE; +} + +static int +entry_filter (newtComponent entry, + void *self, + int ch, + int cursor) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (self); + + if (g_ascii_isprint (ch)) { + if (priv->filter) { + char *text = nmt_newt_locale_to_utf8 (newtEntryGetValue (entry)); + + if (!priv->filter (self, text, ch, cursor, priv->filter_data)) { + g_free (text); + return 0; + } + g_free (text); + } + } + + if (!priv->idle_update) + priv->idle_update = g_idle_add (idle_update_entry, self); + return ch; +} + +static guint +convert_flags (NmtNewtEntryFlags flags) +{ + guint newt_flags = NEWT_FLAG_RETURNEXIT; + + if (!(flags & NMT_NEWT_ENTRY_NOSCROLL)) + newt_flags |= NEWT_FLAG_SCROLL; + if (flags & NMT_NEWT_ENTRY_PASSWORD) + newt_flags |= NEWT_FLAG_PASSWORD; + + return newt_flags; +} + +static newtComponent +nmt_newt_entry_build_component (NmtNewtComponent *component, + gboolean sensitive) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (component); + newtComponent co; + char *text_lc; + int flags; + + flags = convert_flags (priv->flags); + if (!sensitive) + flags |= NEWT_FLAG_DISABLED; + + text_lc = priv->text ? nmt_newt_locale_from_utf8 (priv->text) : NULL; + co = newtEntry (-1, -1, text_lc, priv->width, NULL, flags); + g_free (text_lc); + + if (priv->last_cursor_pos != -1) + newtEntrySetCursorPosition (co, priv->last_cursor_pos); + + newtEntrySetFilter (co, entry_filter, component); + return co; +} + +static void +nmt_newt_entry_activated (NmtNewtWidget *widget) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (widget); + + if (priv->idle_update) { + g_source_remove (priv->idle_update); + idle_update_entry (widget); + } + + NMT_NEWT_WIDGET_CLASS (nmt_newt_entry_parent_class)->activated (widget); +} + +static void +nmt_newt_entry_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtEntry *entry = NMT_NEWT_ENTRY (object); + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + + switch (prop_id) { + case PROP_TEXT: + nmt_newt_entry_set_text (entry, g_value_get_string (value)); + break; + case PROP_WIDTH: + nmt_newt_entry_set_width (entry, g_value_get_int (value)); + break; + case PROP_FLAGS: + priv->flags = g_value_get_uint (value); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (entry)); + break; + case PROP_PASSWORD: + if (g_value_get_boolean (value)) + priv->flags |= NMT_NEWT_ENTRY_PASSWORD; + else + priv->flags &= ~NMT_NEWT_ENTRY_PASSWORD; + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (entry)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_entry_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtEntry *entry = NMT_NEWT_ENTRY (object); + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + + switch (prop_id) { + case PROP_TEXT: + g_value_set_string (value, nmt_newt_entry_get_text (entry)); + break; + case PROP_WIDTH: + g_value_set_int (value, priv->width); + break; + case PROP_FLAGS: + g_value_set_uint (value, priv->flags); + break; + case PROP_PASSWORD: + g_value_set_boolean (value, (priv->flags & NMT_NEWT_ENTRY_PASSWORD) != 0); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_entry_class_init (NmtNewtEntryClass *entry_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (entry_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (entry_class); + NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (entry_class); + + g_type_class_add_private (entry_class, sizeof (NmtNewtEntryPrivate)); + + /* virtual methods */ + object_class->constructed = nmt_newt_entry_constructed; + object_class->set_property = nmt_newt_entry_set_property; + object_class->get_property = nmt_newt_entry_get_property; + object_class->finalize = nmt_newt_entry_finalize; + + widget_class->activated = nmt_newt_entry_activated; + + component_class->build_component = nmt_newt_entry_build_component; + + /** + * NmtNewtEntry:text + * + * The entry's text + */ + g_object_class_install_property + (object_class, PROP_TEXT, + g_param_spec_string ("text", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtEntry:width + * + * The entry's width in characters + */ + g_object_class_install_property + (object_class, PROP_WIDTH, + g_param_spec_int ("width", "", "", + -1, 80, -1, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtEntry:flags + * + * The entry's #NmtNewtEntryFlags + */ + g_object_class_install_property + (object_class, PROP_FLAGS, + g_param_spec_uint ("flags", "", "", + 0, 0xFFFF, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtEntry:password + * + * %TRUE if #NmtNewtEntry:flags contains %NMT_NEWT_ENTRY_PASSWORD, + * %FALSE if not. + */ + g_object_class_install_property + (object_class, PROP_PASSWORD, + g_param_spec_boolean ("password", "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/newt/nmt-newt-entry.h b/clients/tui/newt/nmt-newt-entry.h new file mode 100644 index 00000000..8df0b137 --- /dev/null +++ b/clients/tui/newt/nmt-newt-entry.h @@ -0,0 +1,74 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_ENTRY_H +#define NMT_NEWT_ENTRY_H + +#include "nmt-newt-component.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_ENTRY (nmt_newt_entry_get_type ()) +#define NMT_NEWT_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_ENTRY, NmtNewtEntry)) +#define NMT_NEWT_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_ENTRY, NmtNewtEntryClass)) +#define NMT_IS_NEWT_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_ENTRY)) +#define NMT_IS_NEWT_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_ENTRY)) +#define NMT_NEWT_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_ENTRY, NmtNewtEntryClass)) + +struct _NmtNewtEntry { + NmtNewtComponent parent; + +}; + +typedef struct { + NmtNewtComponentClass parent; + +} NmtNewtEntryClass; + +GType nmt_newt_entry_get_type (void); + +typedef gboolean (*NmtNewtEntryFilter) (NmtNewtEntry *, const char *text, int ch, int position, gpointer); +typedef gboolean (*NmtNewtEntryValidator) (NmtNewtEntry *, const char *text, gpointer); + +typedef enum { + NMT_NEWT_ENTRY_NOSCROLL = (1 << 0), + NMT_NEWT_ENTRY_PASSWORD = (1 << 1), + NMT_NEWT_ENTRY_NONEMPTY = (1 << 2) +} NmtNewtEntryFlags; + +NmtNewtWidget *nmt_newt_entry_new (int width, + NmtNewtEntryFlags flags); + +void nmt_newt_entry_set_filter (NmtNewtEntry *entry, + NmtNewtEntryFilter filter, + gpointer user_data); +void nmt_newt_entry_set_validator (NmtNewtEntry *entry, + NmtNewtEntryValidator validator, + gpointer user_data); + +void nmt_newt_entry_set_text (NmtNewtEntry *entry, + const char *text); +const char *nmt_newt_entry_get_text (NmtNewtEntry *entry); + +void nmt_newt_entry_set_width (NmtNewtEntry *entry, + int width); +int nmt_newt_entry_get_width (NmtNewtEntry *entry); + +G_END_DECLS + +#endif /* NMT_NEWT_ENTRY_H */ diff --git a/clients/tui/newt/nmt-newt-form.c b/clients/tui/newt/nmt-newt-form.c new file mode 100644 index 00000000..19bd3998 --- /dev/null +++ b/clients/tui/newt/nmt-newt-form.c @@ -0,0 +1,753 @@ +/* -*- 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-form + * @short_description: The top-level NmtNewt widget + * + * #NmtNewtForm is the top-level widget that contains and presents a + * "form" (aka dialog) to the user. + */ + +#include "config.h" + +#include <fcntl.h> +#include <string.h> +#include <unistd.h> + +#include <glib/gi18n-lib.h> + +#include "nmt-newt-form.h" +#include "nmt-newt-button.h" +#include "nmt-newt-grid.h" +#include "nmt-newt-utils.h" + +G_DEFINE_TYPE (NmtNewtForm, nmt_newt_form, NMT_TYPE_NEWT_CONTAINER) + +#define NMT_NEWT_FORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_FORM, NmtNewtFormPrivate)) + +typedef struct { + newtComponent form; + NmtNewtWidget *content; + + guint x, y, width, height; + guint padding; + gboolean fixed_x, fixed_y; + gboolean fixed_width, fixed_height; + char *title_lc; + + gboolean dirty, escape_exits; + NmtNewtWidget *focus; +#ifdef HAVE_NEWTFORMGETSCROLLPOSITION + int scroll_position = 0; +#endif +} NmtNewtFormPrivate; + +enum { + PROP_0, + PROP_TITLE, + PROP_FULLSCREEN, + PROP_FULLSCREEN_VERTICAL, + PROP_FULLSCREEN_HORIZONTAL, + PROP_X, + PROP_Y, + PROP_WIDTH, + PROP_HEIGHT, + PROP_PADDING, + PROP_ESCAPE_EXITS, + + LAST_PROP +}; + +enum { + QUIT, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void nmt_newt_form_redraw (NmtNewtForm *form); + +/** + * nmt_newt_form_new: + * @title: (allow-none): the form title + * + * Creates a new form, which will be shown centered on the screen. + * Compare nmt_newt_form_new_fullscreen(). You can also position a + * form manually by setting its #NmtNewtForm:x and #NmtNewtForm:y + * properties at construct time, and/or by setting + * #NmtNewtForm:fullscreen, #NmtNewtform:fullscreen-horizontal, or + * #NmtNewtForm:fullscreen-vertical. + * + * If @title is NULL, the form will have no title. + * + * Returns: a new #NmtNewtForm + */ +NmtNewtForm * +nmt_newt_form_new (const char *title) +{ + return g_object_new (NMT_TYPE_NEWT_FORM, + "title", title, + NULL); +} + +/** + * nmt_newt_form_new_fullscreen: + * @title: (allow-none): the form title + * + * Creates a new fullscreen form. Compare nmt_newt_form_new(). + * + * If @title is NULL, the form will have no title. + * + * Returns: a new #NmtNewtForm + */ +NmtNewtForm * +nmt_newt_form_new_fullscreen (const char *title) +{ + return g_object_new (NMT_TYPE_NEWT_FORM, + "title", title, + "fullscreen", TRUE, + NULL); +} + +static void +nmt_newt_form_init (NmtNewtForm *form) +{ + g_object_ref_sink (form); +} + +static void +nmt_newt_form_finalize (GObject *object) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (object); + + g_free (priv->title_lc); + g_clear_object (&priv->focus); + + G_OBJECT_CLASS (nmt_newt_form_parent_class)->finalize (object); +} + +static void +nmt_newt_form_needs_rebuild (NmtNewtWidget *widget) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (widget); + + if (!priv->dirty) { + priv->dirty = TRUE; + nmt_newt_form_redraw (NMT_NEWT_FORM (widget)); + } +} + +static void +nmt_newt_form_remove (NmtNewtContainer *container, + NmtNewtWidget *widget) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (container); + NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_newt_form_parent_class); + + g_return_if_fail (widget == priv->content); + + parent_class->remove (container, widget); + priv->content = NULL; +} + +/** + * nmt_newt_form_set_content: + * @form: the #NmtNewtForm + * @content: the form's content + * + * Sets @form's content to be @content. + */ +void +nmt_newt_form_set_content (NmtNewtForm *form, + NmtNewtWidget *content) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form); + NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_newt_form_parent_class); + + if (priv->content) + nmt_newt_form_remove (NMT_NEWT_CONTAINER (form), priv->content); + + priv->content = content; + + if (priv->content) + parent_class->add (NMT_NEWT_CONTAINER (form), content); +} + +static void +nmt_newt_form_build (NmtNewtForm *form) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form); + int screen_height, screen_width, form_height, form_width; + newtComponent *cos; + int i; + + priv->dirty = FALSE; + nmt_newt_widget_realize (NMT_NEWT_WIDGET (form)); + + nmt_newt_widget_size_request (priv->content, &form_width, &form_height); + newtGetScreenSize (&screen_width, &screen_height); + + if (!priv->fixed_width) + priv->width = MIN (form_width + 2 * priv->padding, screen_width - 2); + if (!priv->fixed_height) + priv->height = MIN (form_height + 2 * priv->padding, screen_height - 2); + + if (!priv->fixed_x) + priv->x = (screen_width - form_width) / 2; + if (!priv->fixed_y) + priv->y = (screen_height - form_height) / 2; + + nmt_newt_widget_size_allocate (priv->content, + priv->padding, + priv->padding, + priv->width - 2 * priv->padding, + priv->height - 2 * priv->padding); + + if (priv->height - 2 * priv->padding < form_height) { + newtComponent scroll_bar = + newtVerticalScrollbar (priv->width - 1, 0, priv->height, + NEWT_COLORSET_WINDOW, + NEWT_COLORSET_ACTCHECKBOX); + + priv->form = newtForm (scroll_bar, NULL, NEWT_FLAG_NOF12); + newtFormAddComponent (priv->form, scroll_bar); + newtFormSetHeight (priv->form, priv->height - 2); + } else + priv->form = newtForm (NULL, NULL, NEWT_FLAG_NOF12); + + if (priv->escape_exits) + newtFormAddHotKey (priv->form, NEWT_KEY_ESCAPE); + + cos = nmt_newt_widget_get_components (priv->content); + for (i = 0; cos[i]; i++) + newtFormAddComponent (priv->form, cos[i]); + g_free (cos); + + if (priv->focus) { + newtComponent fco; + + fco = nmt_newt_widget_get_focus_component (priv->focus); + if (fco) + newtFormSetCurrent (priv->form, fco); + } +#ifdef HAVE_NEWTFORMGETSCROLLPOSITION + if (priv->scroll_position) + newtFormSetScrollPosition (priv->form, priv->scroll_position); +#endif + + newtOpenWindow (priv->x, priv->y, priv->width, priv->height, priv->title_lc); +} + +static void +nmt_newt_form_destroy (NmtNewtForm *form) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form); + +#ifdef HAVE_NEWTFORMGETSCROLLPOSITION + priv->scroll_position = newtFormGetScrollPosition (priv->form); +#endif + + newtFormDestroy (priv->form); + priv->form = NULL; + newtPopWindowNoRefresh (); + + nmt_newt_widget_unrealize (NMT_NEWT_WIDGET (form)); +} + +/* A "normal" newt program would call newtFormRun() to run newt's main loop + * and process events. But we want to let GLib's main loop control the program + * (eg, so libnm can process D-Bus notifications). So we call this function + * to run a single iteration of newt's main loop (or rather, to run newt's + * main loop for 1ms) whenever there are events for newt to process (redrawing + * or keypresses). + */ +static void +nmt_newt_form_iterate (NmtNewtForm *form) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form); + NmtNewtWidget *focus; + struct newtExitStruct es; + + if (priv->dirty) { + nmt_newt_form_destroy (form); + nmt_newt_form_build (form); + } + + newtFormSetTimer (priv->form, 1); + newtFormRun (priv->form, &es); + + if ( es.reason == NEWT_EXIT_HOTKEY + || es.reason == NEWT_EXIT_ERROR) { + /* The user hit Esc or there was an error. */ + g_clear_object (&priv->focus); + nmt_newt_form_quit (form); + return; + } + + if (es.reason == NEWT_EXIT_COMPONENT) { + /* The user hit Return/Space on a component; update the form focus + * to point that that component, and activate it. + */ + focus = nmt_newt_widget_find_component (priv->content, es.u.co); + if (focus) { + nmt_newt_form_set_focus (form, focus); + nmt_newt_widget_activated (focus); + } + } else { + /* The 1ms timer ran out. Update focus but don't do anything else. */ + focus = nmt_newt_widget_find_component (priv->content, + newtFormGetCurrent (priv->form)); + if (focus) + nmt_newt_form_set_focus (form, focus); + } +} + +/* @form_stack keeps track of all currently-displayed forms, from top to bottom. + * @keypress_source is the global stdin-monitoring GSource. When it triggers, + * nmt_newt_form_keypress_callback() iterates the top-most form, so it can + * process the keypress. + */ +static GSList *form_stack; +static GSource *keypress_source; + +static gboolean +nmt_newt_form_keypress_callback (int fd, + GIOCondition condition, + gpointer user_data) +{ + g_return_val_if_fail (form_stack != NULL, FALSE); + + nmt_newt_form_iterate (form_stack->data); + return TRUE; +} + +static gboolean +nmt_newt_form_timeout_callback (gpointer user_data) +{ + if (form_stack) + nmt_newt_form_iterate (form_stack->data); + return FALSE; +} + +static void +nmt_newt_form_redraw (NmtNewtForm *form) +{ + g_timeout_add (0, nmt_newt_form_timeout_callback, NULL); +} + +static void +nmt_newt_form_real_show (NmtNewtForm *form) +{ + if (!keypress_source) { + GIOChannel *io; + + io = g_io_channel_unix_new (STDIN_FILENO); + keypress_source = g_io_create_watch (io, G_IO_IN); + g_source_set_can_recurse (keypress_source, TRUE); + g_source_set_callback (keypress_source, + (GSourceFunc) nmt_newt_form_keypress_callback, + NULL, NULL); + g_source_attach (keypress_source, NULL); + g_io_channel_unref (io); + } + + nmt_newt_form_build (form); + form_stack = g_slist_prepend (form_stack, g_object_ref (form)); + nmt_newt_form_redraw (form); +} + +/** + * nmt_newt_form_show: + * @form: an #NmtNewtForm + * + * Displays @form and begins running it asynchronously in the default + * #GMainContext. If another form is currently running, it will remain + * visible in the background, but will not be able to receive keyboard + * input until @form exits. + * + * Call nmt_newt_form_quit() to quit the form. + */ +void +nmt_newt_form_show (NmtNewtForm *form) +{ + NMT_NEWT_FORM_GET_CLASS (form)->show (form); +} + +/** + * nmt_newt_form_run_sync: + * @form: an #NmtNewtForm + * + * Displays @form as with nmt_newt_form_show(), but then iterates the + * #GMainContext internally until @form exits. + * + * Returns: the widget whose activation caused @form to exit, or + * %NULL if it was not caused by a widget. FIXME: this exit value is + * sort of weird and may not be 100% accurate anyway. + */ +NmtNewtWidget * +nmt_newt_form_run_sync (NmtNewtForm *form) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form); + + nmt_newt_form_show (form); + while (priv->form) + g_main_context_iteration (NULL, TRUE); + + return priv->focus; +} + +/** + * nmt_newt_form_quit: + * @form: an #NmtNewtForm + * + * Causes @form to exit. + */ +void +nmt_newt_form_quit (NmtNewtForm *form) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form); + + g_return_if_fail (priv->form != NULL); + + nmt_newt_form_destroy (form); + + form_stack = g_slist_remove (form_stack, form); + + if (form_stack) + nmt_newt_form_iterate (form_stack->data); + else if (keypress_source) { + g_source_destroy (keypress_source); + g_clear_pointer (&keypress_source, g_source_unref); + } + + g_signal_emit (form, signals[QUIT], 0); + g_object_unref (form); +} + +/** + * nmt_newt_form_set_focus: + * @form: an #NmtNewtForm + * @widget: the widget to focus + * + * Focuses @widget in @form. + */ +void +nmt_newt_form_set_focus (NmtNewtForm *form, + NmtNewtWidget *widget) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form); + + g_return_if_fail (priv->form != NULL); + + if (priv->focus == widget) + return; + + if (priv->focus) + g_object_unref (priv->focus); + priv->focus = widget; + if (priv->focus) + g_object_ref (priv->focus); +} + +static void +nmt_newt_form_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (object); + int screen_width, screen_height; + + switch (prop_id) { + case PROP_TITLE: + if (g_value_get_string (value)) { + priv->title_lc = nmt_newt_locale_from_utf8 (g_value_get_string (value)); + } else + priv->title_lc = NULL; + break; + case PROP_FULLSCREEN: + if (g_value_get_boolean (value)) { + newtGetScreenSize (&screen_width, &screen_height); + priv->x = priv->y = 2; + priv->fixed_x = priv->fixed_y = TRUE; + priv->width = screen_width - 4; + priv->height = screen_height - 4; + priv->fixed_width = priv->fixed_height = TRUE; + } + break; + case PROP_FULLSCREEN_VERTICAL: + if (g_value_get_boolean (value)) { + newtGetScreenSize (&screen_width, &screen_height); + priv->y = 2; + priv->fixed_y = TRUE; + priv->height = screen_height - 4; + priv->fixed_height = TRUE; + } + break; + case PROP_FULLSCREEN_HORIZONTAL: + if (g_value_get_boolean (value)) { + newtGetScreenSize (&screen_width, &screen_height); + priv->x = 2; + priv->fixed_x = TRUE; + priv->width = screen_width - 4; + priv->fixed_width = TRUE; + } + break; + case PROP_X: + if (g_value_get_uint (value)) { + priv->x = g_value_get_uint (value); + priv->fixed_x = TRUE; + } + break; + case PROP_Y: + if (g_value_get_uint (value)) { + priv->y = g_value_get_uint (value); + priv->fixed_y = TRUE; + } + break; + case PROP_WIDTH: + if (g_value_get_uint (value)) { + priv->width = g_value_get_uint (value); + priv->fixed_width = TRUE; + } + break; + case PROP_HEIGHT: + if (g_value_get_uint (value)) { + priv->height = g_value_get_uint (value); + priv->fixed_height = TRUE; + } + break; + case PROP_PADDING: + priv->padding = g_value_get_uint (value); + break; + case PROP_ESCAPE_EXITS: + priv->escape_exits = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_form_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_TITLE: + if (priv->title_lc) { + g_value_take_string (value, nmt_newt_locale_to_utf8 (priv->title_lc)); + } else + g_value_set_string (value, NULL); + break; + case PROP_X: + g_value_set_uint (value, priv->x); + break; + case PROP_Y: + g_value_set_uint (value, priv->y); + break; + case PROP_WIDTH: + g_value_set_uint (value, priv->width); + break; + case PROP_HEIGHT: + g_value_set_uint (value, priv->height); + break; + case PROP_PADDING: + g_value_set_uint (value, priv->padding); + break; + case PROP_ESCAPE_EXITS: + g_value_set_boolean (value, priv->escape_exits); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_form_class_init (NmtNewtFormClass *form_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (form_class); + NmtNewtContainerClass *container_class = NMT_NEWT_CONTAINER_CLASS (form_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (form_class); + + g_type_class_add_private (form_class, sizeof (NmtNewtFormPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_form_set_property; + object_class->get_property = nmt_newt_form_get_property; + object_class->finalize = nmt_newt_form_finalize; + + widget_class->needs_rebuild = nmt_newt_form_needs_rebuild; + + container_class->remove = nmt_newt_form_remove; + + form_class->show = nmt_newt_form_real_show; + + /* signals */ + + /** + * NmtNewtForm::quit: + * @form: the #NmtNewtForm + * + * Emitted when the form quits. + */ + signals[QUIT] = + g_signal_new ("quit", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NmtNewtFormClass, quit), + NULL, NULL, NULL, + G_TYPE_NONE, 0); + + /** + * NmtNewtForm:title: + * + * The form's title. If non-%NULL, this will be displayed above + * the form in its border. + */ + g_object_class_install_property + (object_class, PROP_TITLE, + g_param_spec_string ("title", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY)); + /** + * NmtNewtForm:fullscreen: + * + * If %TRUE, the form will fill the entire "screen" (ie, terminal + * window). + */ + g_object_class_install_property + (object_class, PROP_FULLSCREEN, + g_param_spec_boolean ("fullscreen", "", "", + FALSE, + G_PARAM_WRITABLE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY)); + /** + * NmtNewtForm:fullscreen-vertical: + * + * If %TRUE, the form will fill the entire "screen" (ie, terminal + * window) vertically, but not necessarily horizontally. + */ + g_object_class_install_property + (object_class, PROP_FULLSCREEN_VERTICAL, + g_param_spec_boolean ("fullscreen-vertical", "", "", + FALSE, + G_PARAM_WRITABLE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY)); + /** + * NmtNewtForm:fullscreen-horizontal: + * + * If %TRUE, the form will fill the entire "screen" (ie, terminal + * window) horizontally, but not necessarily vertically. + */ + g_object_class_install_property + (object_class, PROP_FULLSCREEN_HORIZONTAL, + g_param_spec_boolean ("fullscreen-horizontal", "", "", + FALSE, + G_PARAM_WRITABLE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY)); + /** + * NmtNewtForm:x: + * + * The form's x coordinate. By default, the form will be centered + * on the screen. + */ + g_object_class_install_property + (object_class, PROP_X, + g_param_spec_uint ("x", "", "", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY)); + /** + * NmtNewtForm:y: + * + * The form's y coordinate. By default, the form will be centered + * on the screen. + */ + g_object_class_install_property + (object_class, PROP_Y, + g_param_spec_uint ("y", "", "", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY)); + /** + * NmtNewtForm:width: + * + * The form's width. By default, this will be determined by the + * width of the form's content. + */ + g_object_class_install_property + (object_class, PROP_WIDTH, + g_param_spec_uint ("width", "", "", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY)); + /** + * NmtNewtForm:height: + * + * The form's height. By default, this will be determined by the + * height of the form's content. + */ + g_object_class_install_property + (object_class, PROP_HEIGHT, + g_param_spec_uint ("height", "", "", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY)); + /** + * NmtNewtForm:padding: + * + * The padding between the form's content and its border. + */ + g_object_class_install_property + (object_class, PROP_PADDING, + g_param_spec_uint ("padding", "", "", + 0, G_MAXUINT, 1, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY)); + /** + * NmtNewtForm:escape-exits: + * + * If %TRUE, then hitting the Escape key will cause the form to + * exit. + */ + g_object_class_install_property + (object_class, PROP_ESCAPE_EXITS, + g_param_spec_boolean ("escape-exits", "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY)); +} diff --git a/clients/tui/newt/nmt-newt-form.h b/clients/tui/newt/nmt-newt-form.h new file mode 100644 index 00000000..be95eb68 --- /dev/null +++ b/clients/tui/newt/nmt-newt-form.h @@ -0,0 +1,66 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_FORM_H +#define NMT_NEWT_FORM_H + +#include "nmt-newt-container.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_FORM (nmt_newt_form_get_type ()) +#define NMT_NEWT_FORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_FORM, NmtNewtForm)) +#define NMT_NEWT_FORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_FORM, NmtNewtFormClass)) +#define NMT_IS_NEWT_FORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_FORM)) +#define NMT_IS_NEWT_FORM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_FORM)) +#define NMT_NEWT_FORM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_FORM, NmtNewtFormClass)) + +struct _NmtNewtForm { + NmtNewtContainer parent; + +}; + +typedef struct { + NmtNewtContainerClass parent; + + /* signals */ + void (*quit) (NmtNewtForm *form); + + /* methods */ + void (*show) (NmtNewtForm *form); + +} NmtNewtFormClass; + +GType nmt_newt_form_get_type (void); + +NmtNewtForm *nmt_newt_form_new (const char *title); +NmtNewtForm *nmt_newt_form_new_fullscreen (const char *title); + +void nmt_newt_form_set_content (NmtNewtForm *form, + NmtNewtWidget *content); + +void nmt_newt_form_show (NmtNewtForm *form); +NmtNewtWidget *nmt_newt_form_run_sync (NmtNewtForm *form); +void nmt_newt_form_quit (NmtNewtForm *form); + +void nmt_newt_form_set_focus (NmtNewtForm *form, + NmtNewtWidget *widget); + +G_END_DECLS + +#endif /* NMT_NEWT_FORM_H */ diff --git a/clients/tui/newt/nmt-newt-grid.c b/clients/tui/newt/nmt-newt-grid.c new file mode 100644 index 00000000..ac967334 --- /dev/null +++ b/clients/tui/newt/nmt-newt-grid.c @@ -0,0 +1,472 @@ +/* -*- 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-grid + * @short_description: Grid container + * + * #NmtNewtGrid is the most general-purpose container widget in NmtNewt. + * + * An #NmtNewtGrid consists of a number of rows and columns. There is + * no pre-established maximum row or columns. Rather, rows and columns + * exist if and only if there are widgets in them. + * + * The width of each column is the width of the widest widget in that + * column, and the height of each row is the height of the tallest + * widget in that row. Empty rows and empty columns take up no space, + * so a grid with a single widget at 0,0 would look exactly the same + * if the widget was at 5,10 instead. + * + * If a widget's cell ends up being larger than the widget's requested + * size, then by default the widget will be centered in its cell. + * However, this can be modified by changing its #NmtNewtGridFlags. + * FIXME: the FILL/ANCHOR flags can be implemented in #NmtNewtWidget + * and so should move there. Less clear about the EXPAND flags, which + * must be implemented by the container... + */ + +#include "config.h" + +#include <string.h> + +#include "nmt-newt-grid.h" + +G_DEFINE_TYPE (NmtNewtGrid, nmt_newt_grid, NMT_TYPE_NEWT_CONTAINER) + +#define NMT_NEWT_GRID_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_GRID, NmtNewtGridPrivate)) + +typedef struct { + NmtNewtWidget *widget; + int x, y; + NmtNewtGridFlags flags; + int req_height, req_width; +} NmtNewtGridChild; + +typedef struct { + GArray *children; + int max_x, max_y; + int *row_heights, *col_widths; + gboolean *expand_rows, *expand_cols; + int n_expand_rows, n_expand_cols; + int req_height, req_width; +} NmtNewtGridPrivate; + +/** + * nmt_newt_grid_new: + * + * Creates a new #NmtNewtGrid + * + * Returns: a new #NmtNewtGrid + */ +NmtNewtWidget * +nmt_newt_grid_new (void) +{ + return g_object_new (NMT_TYPE_NEWT_GRID, NULL); +} + +static void +nmt_newt_grid_init (NmtNewtGrid *grid) +{ + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid); + + priv->children = g_array_new (FALSE, FALSE, sizeof (NmtNewtGridChild)); +} + +static void +nmt_newt_grid_finalize (GObject *object) +{ + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (object); + + g_array_unref (priv->children); + g_clear_pointer (&priv->row_heights, g_free); + g_clear_pointer (&priv->col_widths, g_free); + g_clear_pointer (&priv->expand_rows, g_free); + g_clear_pointer (&priv->expand_cols, g_free); + + G_OBJECT_CLASS (nmt_newt_grid_parent_class)->finalize (object); +} + +static int +child_sort_func (gconstpointer a, + gconstpointer b) +{ + NmtNewtGridChild *child_a = (NmtNewtGridChild *)a; + NmtNewtGridChild *child_b = (NmtNewtGridChild *)b; + + if (child_a->y != child_b->y) + return child_a->y - child_b->y; + else + return child_a->x - child_b->x; +} + +static newtComponent * +nmt_newt_grid_get_components (NmtNewtWidget *widget) +{ + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (widget); + NmtNewtGridChild *children; + GPtrArray *cos; + newtComponent *child_cos; + int i, c; + + g_array_sort (priv->children, child_sort_func); + children = (NmtNewtGridChild *)priv->children->data; + + cos = g_ptr_array_new (); + + for (i = 0; i < priv->children->len; i++) { + if (!nmt_newt_widget_get_visible (children[i].widget)) + continue; + + child_cos = nmt_newt_widget_get_components (children[i].widget); + for (c = 0; child_cos[c]; c++) + g_ptr_array_add (cos, child_cos[c]); + g_free (child_cos); + } + g_ptr_array_add (cos, NULL); + + return (newtComponent *) g_ptr_array_free (cos, FALSE); +} + +static void +nmt_newt_grid_size_request (NmtNewtWidget *widget, + int *width, + int *height) +{ + NmtNewtGrid *grid = NMT_NEWT_GRID (widget); + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid); + NmtNewtGridChild *children = (NmtNewtGridChild *)priv->children->data; + int row, col, i; + + g_free (priv->row_heights); + g_free (priv->col_widths); + g_free (priv->expand_rows); + g_free (priv->expand_cols); + + priv->row_heights = g_new0 (int, priv->max_y + 1); + priv->col_widths = g_new0 (int, priv->max_x + 1); + priv->expand_rows = g_new0 (gboolean, priv->max_y + 1); + priv->expand_cols = g_new0 (gboolean, priv->max_x + 1); + priv->n_expand_rows = priv->n_expand_cols = 0; + + for (row = 0; row < priv->max_y + 1; row++) { + for (col = 0; col < priv->max_x + 1; col++) { + for (i = 0; i < priv->children->len; i++) { + if (children[i].x != col || children[i].y != row) + continue; + if (!nmt_newt_widget_get_visible (children[i].widget)) + continue; + + nmt_newt_widget_size_request (children[i].widget, + &children[i].req_width, + &children[i].req_height); + if (children[i].req_height > priv->row_heights[row]) + priv->row_heights[row] = children[i].req_height; + if (children[i].req_width > priv->col_widths[col]) + priv->col_widths[col] = children[i].req_width; + + if ( (children[i].flags & NMT_NEWT_GRID_EXPAND_X) + && !priv->expand_cols[children[i].x]) { + priv->expand_cols[children[i].x] = TRUE; + priv->n_expand_cols++; + } + if ( (children[i].flags & NMT_NEWT_GRID_EXPAND_Y) + && !priv->expand_rows[children[i].y]) { + priv->expand_rows[children[i].y] = TRUE; + priv->n_expand_rows++; + } + } + } + } + + priv->req_height = priv->req_width = 0; + for (row = 0; row < priv->max_y + 1; row++) + priv->req_height += priv->row_heights[row]; + for (col = 0; col < priv->max_x + 1; col++) + priv->req_width += priv->col_widths[col]; + + *height = priv->req_height; + *width = priv->req_width; +} + +static void +nmt_newt_grid_size_allocate (NmtNewtWidget *widget, + int x, + int y, + int width, + int height) +{ + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (widget); + NmtNewtGridChild *children = (NmtNewtGridChild *)priv->children->data, *child; + int i, row, col; + int child_x, child_y, child_width, child_height; + int extra, extra_all, extra_some; + + extra = width - priv->req_width; + if (extra > 0 && priv->n_expand_cols) { + extra_all = extra / priv->n_expand_cols; + extra_some = extra % priv->n_expand_cols; + + for (col = 0; col < priv->max_x + 1; col++) { + if (!priv->expand_cols[col]) + continue; + priv->col_widths[col] += extra_all; + if (extra_some) { + priv->col_widths[col]++; + extra_some--; + } + } + } + + extra = height - priv->req_height; + if (extra > 0 && priv->n_expand_rows) { + extra_all = extra / priv->n_expand_rows; + extra_some = extra % priv->n_expand_rows; + + for (row = 0; row < priv->max_y + 1; row++) { + if (!priv->expand_rows[row]) + continue; + priv->row_heights[row] += extra_all; + if (extra_some) { + priv->row_heights[row]++; + extra_some--; + } + } + } + + for (i = 0; i < priv->children->len; i++) { + child = &children[i]; + if (!nmt_newt_widget_get_visible (child->widget)) + continue; + + child_x = x; + for (col = 0; col < child->x; col++) + child_x += priv->col_widths[col]; + + if ((child->flags & NMT_NEWT_GRID_FILL_X) == NMT_NEWT_GRID_FILL_X) { + child_width = priv->col_widths[child->x]; + } else { + child_width = child->req_width; + if (child->flags & NMT_NEWT_GRID_ANCHOR_RIGHT) + child_x += priv->col_widths[child->x] - child->req_width; + else if (!(child->flags & NMT_NEWT_GRID_ANCHOR_LEFT)) + child_x += (priv->col_widths[child->x] - child->req_width) / 2; + } + + child_y = y; + for (row = 0; row < child->y; row++) + child_y += priv->row_heights[row]; + + if ((child->flags & NMT_NEWT_GRID_FILL_Y) == NMT_NEWT_GRID_FILL_Y) { + child_height = priv->row_heights[child->y]; + } else { + child_height = child->req_height; + if (child->flags & NMT_NEWT_GRID_ANCHOR_BOTTOM) + child_y += priv->row_heights[child->y] - child->req_height; + else if (!(child->flags & NMT_NEWT_GRID_ANCHOR_TOP)) + child_y += (priv->row_heights[child->y] - child->req_height) / 2; + } + + nmt_newt_widget_size_allocate (child->widget, + child_x, child_y, + child_width, child_height); + } +} + +static void +nmt_newt_grid_find_size (NmtNewtGrid *grid) +{ + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid); + NmtNewtGridChild *children = (NmtNewtGridChild *)priv->children->data; + int i; + + priv->max_x = priv->max_y = 0; + for (i = 0; i < priv->children->len; i++) { + if (children[i].x > priv->max_x) + priv->max_x = children[i].x; + if (children[i].y > priv->max_y) + priv->max_y = children[i].y; + } +} + +/** + * nmt_newt_grid_add: + * @grid: an #NmtNewtGrid + * @widget: the widget to add + * @x: x coordinate + * @y: y coordinate + * + * Adds @widget to @grid at @x, @y. See the discussion above for more + * details of exactly how this works. + */ +void +nmt_newt_grid_add (NmtNewtGrid *grid, + NmtNewtWidget *widget, + int x, + int y) +{ + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid); + NmtNewtGridChild child; + + NMT_NEWT_CONTAINER_CLASS (nmt_newt_grid_parent_class)->add (NMT_NEWT_CONTAINER (grid), widget); + + memset (&child, 0, sizeof (child)); + child.widget = widget; + child.x = x; + child.y = y; + child.flags = NMT_NEWT_GRID_FILL_X | NMT_NEWT_GRID_FILL_Y; + g_array_append_val (priv->children, child); + + if (x > priv->max_x) + priv->max_x = x; + if (y > priv->max_y) + priv->max_y = y; +} + +static int +find_child (NmtNewtGrid *grid, + NmtNewtWidget *widget) +{ + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid); + NmtNewtGridChild *children = (NmtNewtGridChild *)priv->children->data; + int i; + + for (i = 0; i < priv->children->len; i++) { + if (children[i].widget == widget) + return i; + } + + return -1; +} + +static void +nmt_newt_grid_remove (NmtNewtContainer *container, + NmtNewtWidget *widget) +{ + NmtNewtGrid *grid = NMT_NEWT_GRID (container); + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid); + int i; + + i = find_child (grid, widget); + if (i != -1) { + g_array_remove_index (priv->children, i); + nmt_newt_grid_find_size (grid); + } + + NMT_NEWT_CONTAINER_CLASS (nmt_newt_grid_parent_class)->remove (container, widget); +} + +/** + * nmt_newt_grid_move: + * @grid: an #NmtNewtGrid + * @widget: a child of @grid + * @x: x coordinate + * @y: y coordinate + * + * Moves @widget to the given new coordinates. + */ +void +nmt_newt_grid_move (NmtNewtGrid *grid, + NmtNewtWidget *widget, + int x, + int y) +{ + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid); + NmtNewtGridChild *children = (NmtNewtGridChild *)priv->children->data; + int i; + + i = find_child (grid, widget); + if (i != -1 && (children[i].x != x || children[i].y != y)) { + children[i].x = x; + children[i].y = y; + nmt_newt_grid_find_size (grid); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (grid)); + } +} + +/** + * NmtNewtGridFlags: + * @NMT_NEWT_GRID_EXPAND_X: The widget's cell should expand + * horizontally if the grid as a whole is given more width than + * it requested. + * @NMT_NEWT_GRID_EXPAND_Y: The widget's cell should expand + * vertically if the grid as a whole is given more height than + * it requested. + * @NMT_NEWT_GRID_ANCHOR_LEFT: If the widget's cell is wider than + * the widget requested, the widget should be anchored to the + * left of its cell rather than being centered. + * @NMT_NEWT_GRID_ANCHOR_RIGHT: If the widget's cell is wider than + * the widget requested, the widget should be anchored to the + * right of its cell rather than being centered. + * @NMT_NEWT_GRID_FILL_X: If the widget's cell is wider than + * the widget requested, the widget should be allocated the + * full width of the cell; this is equivalent to specifying + * both %NMT_NEWT_GRID_ANCHOR_LEFT and %NMT_NEWT_GRID_ANCHOR_RIGHT. + * @NMT_NEWT_GRID_ANCHOR_TOP: If the widget's cell is taller than + * the widget requested, the widget should be anchored to the + * top of its cell rather than being centered. + * @NMT_NEWT_GRID_ANCHOR_BOTTOM: If the widget's cell is taller than + * the widget requested, the widget should be anchored to the + * bottom of its cell rather than being centered. + * @NMT_NEWT_GRID_FILL_Y: If the widget's cell is taller than + * the widget requested, the widget should be allocated the + * full height of the cell; this is equivalent to specifying + * both %NMT_NEWT_GRID_ANCHOR_TOP and %NMT_NEWT_GRID_ANCHOR_BOTTOM. + * + * Flags describing how a widget is placed within its grid cell. + */ + +/** + * nmt_newt_grid_set_flags: + * @grid: an #NmtNewtGrid + * @widget: a child of @grid + * @flags: #NmtNewtGridFlags for @widget + * + * Sets the #NmtNewtGridFlags on @widget + */ +void +nmt_newt_grid_set_flags (NmtNewtGrid *grid, + NmtNewtWidget *widget, + NmtNewtGridFlags flags) +{ + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid); + NmtNewtGridChild *children = (NmtNewtGridChild *)priv->children->data; + int i; + + i = find_child (grid, widget); + if (i != -1) + children[i].flags = flags; +} + +static void +nmt_newt_grid_class_init (NmtNewtGridClass *grid_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (grid_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (grid_class); + NmtNewtContainerClass *container_class = NMT_NEWT_CONTAINER_CLASS (grid_class); + + g_type_class_add_private (grid_class, sizeof (NmtNewtGridPrivate)); + + /* virtual methods */ + object_class->finalize = nmt_newt_grid_finalize; + + widget_class->get_components = nmt_newt_grid_get_components; + widget_class->size_request = nmt_newt_grid_size_request; + widget_class->size_allocate = nmt_newt_grid_size_allocate; + + container_class->remove = nmt_newt_grid_remove; +} diff --git a/clients/tui/newt/nmt-newt-grid.h b/clients/tui/newt/nmt-newt-grid.h new file mode 100644 index 00000000..f36a38ee --- /dev/null +++ b/clients/tui/newt/nmt-newt-grid.h @@ -0,0 +1,72 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_GRID_H +#define NMT_NEWT_GRID_H + +#include "nmt-newt-container.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_GRID (nmt_newt_grid_get_type ()) +#define NMT_NEWT_GRID(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_GRID, NmtNewtGrid)) +#define NMT_NEWT_GRID_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_GRID, NmtNewtGridClass)) +#define NMT_IS_NEWT_GRID(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_GRID)) +#define NMT_IS_NEWT_GRID_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_GRID)) +#define NMT_NEWT_GRID_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_GRID, NmtNewtGridClass)) + +struct _NmtNewtGrid { + NmtNewtContainer parent; + +}; + +typedef struct { + NmtNewtContainerClass parent; + +} NmtNewtGridClass; + +GType nmt_newt_grid_get_type (void); + +typedef enum { + NMT_NEWT_GRID_EXPAND_X = (1 << 0), + NMT_NEWT_GRID_EXPAND_Y = (1 << 1), + NMT_NEWT_GRID_ANCHOR_LEFT = (1 << 2), + NMT_NEWT_GRID_ANCHOR_RIGHT = (1 << 3), + NMT_NEWT_GRID_FILL_X = NMT_NEWT_GRID_ANCHOR_LEFT | NMT_NEWT_GRID_ANCHOR_RIGHT, + NMT_NEWT_GRID_ANCHOR_TOP = (1 << 4), + NMT_NEWT_GRID_ANCHOR_BOTTOM = (1 << 5), + NMT_NEWT_GRID_FILL_Y = NMT_NEWT_GRID_ANCHOR_TOP | NMT_NEWT_GRID_ANCHOR_BOTTOM, +} NmtNewtGridFlags; + +NmtNewtWidget *nmt_newt_grid_new (void); + +void nmt_newt_grid_add (NmtNewtGrid *grid, + NmtNewtWidget *widget, + int x, + int y); +void nmt_newt_grid_move (NmtNewtGrid *grid, + NmtNewtWidget *widget, + int x, + int y); +void nmt_newt_grid_set_flags (NmtNewtGrid *grid, + NmtNewtWidget *widget, + NmtNewtGridFlags flags); + +G_END_DECLS + +#endif /* NMT_NEWT_GRID_H */ diff --git a/clients/tui/newt/nmt-newt-hacks.c b/clients/tui/newt/nmt-newt-hacks.c new file mode 100644 index 00000000..2d9b1725 --- /dev/null +++ b/clients/tui/newt/nmt-newt-hacks.c @@ -0,0 +1,103 @@ +/* -*- 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-hacks + * @short_description: Hacks! + * + * This contains hacky cheating implementations of certain newt + * functions that were added after 0.52.15. + */ + +#include "config.h" + +#include "nmt-newt-hacks.h" + +#if !defined (HAVE_NEWTCOMPONENTGETSIZE) || !defined (HAVE_NEWTENTRYGETCURSORPOSITION) +struct newtComponent_0_52_15_struct_hack { + int height, width; + int top, left; + int takesFocus; + int isMapped; + + struct componentOps *ops; + + newtCallback callback; + void *callbackData; + + newtCallback destroyCallback; + void *destroyCallbackData; + + void *data; +}; +#endif + +#ifndef HAVE_NEWTCOMPONENTGETSIZE +void +newtComponentGetSize (newtComponent component, + int *width, + int *height) +{ + struct newtComponent_0_52_15_struct_hack *hack = (void *) component; + + *width = hack->width; + *height = hack->height; +} + +void +newtComponentGetPosition (newtComponent component, + int *left, + int *top) +{ + struct newtComponent_0_52_15_struct_hack *hack = (void *) component; + + *left = hack->left; + *top = hack->top; +} +#endif + +#ifndef HAVE_NEWTENTRYGETCURSORPOSITION +struct newtEntry_0_52_15_struct_hack { + int flags; + char *buf; + const char **resultPtr; + int bufAlloced; + int bufUsed; + int cursorPosition; + /* ... */ +}; + +int +newtEntryGetCursorPosition (newtComponent component) +{ + struct newtComponent_0_52_15_struct_hack *co_hack = (void *) component; + struct newtEntry_0_52_15_struct_hack *entry_hack = co_hack->data; + + return entry_hack->cursorPosition; +} + +void +newtEntrySetCursorPosition (newtComponent component, + int position) +{ + struct newtComponent_0_52_15_struct_hack *co_hack = (void *) component; + struct newtEntry_0_52_15_struct_hack *entry_hack = co_hack->data; + + entry_hack->cursorPosition = position; +} +#endif diff --git a/clients/tui/newt/nmt-newt-hacks.h b/clients/tui/newt/nmt-newt-hacks.h new file mode 100644 index 00000000..ba8464af --- /dev/null +++ b/clients/tui/newt/nmt-newt-hacks.h @@ -0,0 +1,42 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_HACKS_H +#define NMT_NEWT_HACKS_H + +#include "config.h" + +#include <newt.h> + +#ifndef HAVE_NEWTCOMPONENTGETSIZE +void newtComponentGetSize (newtComponent component, + int *width, + int *height); + +void newtComponentGetPosition (newtComponent component, + int *left, + int *top); +#endif + +#ifndef HAVE_NEWTENTRYGETCURSORPOSITION +int newtEntryGetCursorPosition (newtComponent component); +void newtEntrySetCursorPosition (newtComponent component, + int position); +#endif + +#endif /* NMT_NEWT_HACKS_H */ diff --git a/clients/tui/newt/nmt-newt-label.c b/clients/tui/newt/nmt-newt-label.c new file mode 100644 index 00000000..9c4df8ed --- /dev/null +++ b/clients/tui/newt/nmt-newt-label.c @@ -0,0 +1,326 @@ +/* -*- 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-label + * @short_description: Labels + * + * #NmtNewtLabel implements a single-line label. + * + * See also #NmtNewtTextbox, for multiline. + */ + +#include "config.h" + +#include <string.h> + +#include "nmt-newt-label.h" +#include "nmt-newt-utils.h" + +G_DEFINE_TYPE (NmtNewtLabel, nmt_newt_label, NMT_TYPE_NEWT_COMPONENT) + +#define NMT_NEWT_LABEL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_LABEL, NmtNewtLabelPrivate)) + +typedef struct { + char *text; + NmtNewtLabelStyle style; + gboolean highlight; +} NmtNewtLabelPrivate; + +enum { + PROP_0, + PROP_TEXT, + PROP_STYLE, + PROP_HIGHLIGHT, + + LAST_PROP +}; + +/** + * nmt_newt_label_new: + * @text: the initial label text + * + * Creates a new #NmtNewtLabel + * + * Returns: a new #NmtNewtLabel + */ +NmtNewtWidget * +nmt_newt_label_new (const char *text) +{ + return g_object_new (NMT_TYPE_NEWT_LABEL, + "text", text, + NULL); +} + +/** + * nmt_newt_label_set_text: + * @label: an #NmtNewtLabel + * @text: the new text + * + * Updates @label's text. + */ +void +nmt_newt_label_set_text (NmtNewtLabel *label, + const char *text) +{ + NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (label); + + if (!g_strcmp0 (priv->text, text)) + return; + + g_free (priv->text); + priv->text = g_strdup (text); + + g_object_notify (G_OBJECT (label), "text"); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (label)); +} + +/** + * nmt_newt_label_get_text: + * @label: an #NmtNewtLabel + * + * Gets @label's text + * + * Returns: @label's text + */ +const char * +nmt_newt_label_get_text (NmtNewtLabel *label) +{ + NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (label); + + return priv->text; +} + +/** + * NmtNewtLabelStyle: + * @NMT_NEWT_LABEL_NORMAL: a normal label + * @NMT_NEWT_LABEL_PLAIN: a "plain-looking" label + * + * The label style. Normal labels are blue. Plain labels are black, + * making them look more like they are text in their own right rather + * than just being a label for something else. + */ + +/** + * nmt_newt_label_set_style: + * @label: an #NmtNewtLabel + * @style: the #NmtNewtLabelStyle + * + * Sets the style of @label + */ +void +nmt_newt_label_set_style (NmtNewtLabel *label, + NmtNewtLabelStyle style) +{ + NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (label); + + if (priv->style == style) + return; + + priv->style = style; + g_object_notify (G_OBJECT (label), "style"); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (label)); +} + +/** + * nmt_newt_label_get_style: + * @label: an #NmtNewtLabel + * + * Gets the style of @label + * + * Returns: the style of @label + */ +NmtNewtLabelStyle +nmt_newt_label_get_style (NmtNewtLabel *label) +{ + NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (label); + + return priv->style; +} + +/** + * nmt_newt_label_set_highlight: + * @label: an #NmtNewtLabel + * @highlight: %TRUE if @label should be highlighted + * + * Sets whether @label is highlighted. Highlighted labels are red; + * this is generally used to highlight invalid widgets. + */ +void +nmt_newt_label_set_highlight (NmtNewtLabel *label, + gboolean highlight) +{ + NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (label); + + highlight = !!highlight; + if (priv->highlight == highlight) + return; + + priv->highlight = highlight; + g_object_notify (G_OBJECT (label), "highlight"); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (label)); +} + +/** + * nmt_newt_label_get_highlight: + * @label: an #NmtNewtLabel + * + * Gets whether @label is highlighted. + * + * Returns: whether @label is highlighted. + */ +gboolean +nmt_newt_label_get_highlight (NmtNewtLabel *label) +{ + NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (label); + + return priv->highlight; +} + +static void +nmt_newt_label_init (NmtNewtLabel *label) +{ +} + +static void +nmt_newt_label_finalize (GObject *object) +{ + NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (object); + + g_free (priv->text); + + G_OBJECT_CLASS (nmt_newt_label_parent_class)->finalize (object); +} + +static newtComponent +nmt_newt_label_build_component (NmtNewtComponent *component, + gboolean sensitive) +{ + NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (component); + newtComponent co; + char *text_lc; + + text_lc = nmt_newt_locale_from_utf8 (priv->text); + co = newtLabel (-1, -1, text_lc); + g_free (text_lc); + + if (priv->highlight) + newtLabelSetColors (co, NMT_NEWT_COLORSET_BAD_LABEL); + else if (priv->style == NMT_NEWT_LABEL_PLAIN) + newtLabelSetColors (co, NMT_NEWT_COLORSET_PLAIN_LABEL); + + return co; +} + +static void +nmt_newt_label_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtLabel *label = NMT_NEWT_LABEL (object); + + switch (prop_id) { + case PROP_TEXT: + nmt_newt_label_set_text (label, g_value_get_string (value)); + break; + case PROP_STYLE: + nmt_newt_label_set_style (label, g_value_get_int (value)); + break; + case PROP_HIGHLIGHT: + nmt_newt_label_set_highlight (label, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_label_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_TEXT: + g_value_set_string (value, priv->text); + break; + case PROP_STYLE: + g_value_set_int (value, priv->style); + break; + case PROP_HIGHLIGHT: + g_value_set_boolean (value, priv->highlight); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_label_class_init (NmtNewtLabelClass *label_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (label_class); + NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (label_class); + + g_type_class_add_private (label_class, sizeof (NmtNewtLabelPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_label_set_property; + object_class->get_property = nmt_newt_label_get_property; + object_class->finalize = nmt_newt_label_finalize; + + component_class->build_component = nmt_newt_label_build_component; + + /** + * NmtNewtLabel:text: + * + * The label's text + */ + g_object_class_install_property + (object_class, PROP_TEXT, + g_param_spec_string ("text", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtLabel:style: + * + * The label's #NmtNewtLabelStyle + */ + g_object_class_install_property + (object_class, PROP_STYLE, + g_param_spec_int ("style", "", "", + 0, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtLabel:highlight: + * + * Whether the label is highlighted. + */ + g_object_class_install_property + (object_class, PROP_HIGHLIGHT, + g_param_spec_boolean ("highlight", "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/newt/nmt-newt-label.h b/clients/tui/newt/nmt-newt-label.h new file mode 100644 index 00000000..a4e0dcca --- /dev/null +++ b/clients/tui/newt/nmt-newt-label.h @@ -0,0 +1,66 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_LABEL_H +#define NMT_NEWT_LABEL_H + +#include "nmt-newt-component.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_LABEL (nmt_newt_label_get_type ()) +#define NMT_NEWT_LABEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_LABEL, NmtNewtLabel)) +#define NMT_NEWT_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_LABEL, NmtNewtLabelClass)) +#define NMT_IS_NEWT_LABEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_LABEL)) +#define NMT_IS_NEWT_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_LABEL)) +#define NMT_NEWT_LABEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_LABEL, NmtNewtLabelClass)) + +struct _NmtNewtLabel { + NmtNewtComponent parent; + +}; + +typedef struct { + NmtNewtComponentClass parent; + +} NmtNewtLabelClass; + +GType nmt_newt_label_get_type (void); + +typedef enum { + NMT_NEWT_LABEL_NORMAL, + NMT_NEWT_LABEL_PLAIN +} NmtNewtLabelStyle; + +NmtNewtWidget *nmt_newt_label_new (const char *text); + +void nmt_newt_label_set_text (NmtNewtLabel *label, + const char *text); +const char *nmt_newt_label_get_text (NmtNewtLabel *label); + +void nmt_newt_label_set_style (NmtNewtLabel *label, + NmtNewtLabelStyle style); +NmtNewtLabelStyle nmt_newt_label_get_style (NmtNewtLabel *label); + +void nmt_newt_label_set_highlight (NmtNewtLabel *label, + gboolean highlight); +gboolean nmt_newt_label_get_highlight (NmtNewtLabel *label); + +G_END_DECLS + +#endif /* NMT_NEWT_LABEL_H */ diff --git a/clients/tui/newt/nmt-newt-listbox.c b/clients/tui/newt/nmt-newt-listbox.c new file mode 100644 index 00000000..e450df91 --- /dev/null +++ b/clients/tui/newt/nmt-newt-listbox.c @@ -0,0 +1,548 @@ +/* -*- 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-listbox + * @short_description: Single-choice listboxes + * + * #NmtNewtListbox implements a single-choice listbox. + * + * A listbox has some number of rows, each associated with an + * arbitrary pointer value. The pointer values do not need to be + * unique, but some APIs will not be usable if they aren't. You + * can also cause rows with %NULL keys to be treated specially. + * + * The listbox will emit #NmtNewtWidget::activate when the user + * presses Return on a selection. + */ + +#include "config.h" + +#include "nmt-newt-listbox.h" +#include "nmt-newt-form.h" +#include "nmt-newt-utils.h" + +G_DEFINE_TYPE (NmtNewtListbox, nmt_newt_listbox, NMT_TYPE_NEWT_COMPONENT) + +#define NMT_NEWT_LISTBOX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_LISTBOX, NmtNewtListboxPrivate)) + +typedef struct { + int height, alloc_height, width; + gboolean fixed_height; + NmtNewtListboxFlags flags; + + GPtrArray *entries; + GPtrArray *keys; + + int active; + gpointer active_key; + gboolean skip_null_keys; + +} NmtNewtListboxPrivate; + +enum { + PROP_0, + PROP_HEIGHT, + PROP_FLAGS, + PROP_ACTIVE, + PROP_ACTIVE_KEY, + PROP_SKIP_NULL_KEYS, + + LAST_PROP +}; + +/** + * NmtNewtListboxFlags: + * @NMT_NEWT_LISTBOX_SCROLL: the listbox should have a scroll bar. + * @NMT_NEWT_LISTBOX_BORDER: the listbox should have a border around it. + * + * Flags describing an #NmtNewtListbox + */ + +/** + * nmt_newt_listbox_new: + * @height: the height of the listbox, or -1 for no fixed height + * @flags: the listbox flags + * + * Creates a new #NmtNewtListbox + * + * Returns: a new #NmtNewtListbox + */ +NmtNewtWidget * +nmt_newt_listbox_new (int height, + NmtNewtListboxFlags flags) +{ + return g_object_new (NMT_TYPE_NEWT_LISTBOX, + "height", height, + "flags", flags, + NULL); +} + +/** + * nmt_newt_listbox_append: + * @listbox: an #NmtNewtListbox + * @entry: the text for the new row + * @key: (allow-none): the key associated with @entry + * + * Adds a row to @listbox. + */ +void +nmt_newt_listbox_append (NmtNewtListbox *listbox, + const char *entry, + gpointer key) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox); + + g_ptr_array_add (priv->entries, nmt_newt_locale_from_utf8 (entry)); + g_ptr_array_add (priv->keys, key); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (listbox)); +} + +/** + * nmt_newt_listbox_clear: + * @listbox: an #NmtNewtListbox + * + * Clears the contents of @listbox. + */ +void +nmt_newt_listbox_clear (NmtNewtListbox *listbox) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox); + + g_ptr_array_set_size (priv->entries, 0); + g_ptr_array_set_size (priv->keys, 0); + + priv->active = -1; + priv->active_key = NULL; + + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (listbox)); +} + +/** + * nmt_newt_listbox_set_active: + * @listbox: an #NmtNewtListbox + * @active: the row to make active + * + * Sets @active to be the currently-selected row in @listbox, + * scrolling it into view if needed. + */ +void +nmt_newt_listbox_set_active (NmtNewtListbox *listbox, + int active) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox); + + if (active == priv->active) + return; + + g_return_if_fail (active >= 0 && active < priv->entries->len); + g_return_if_fail (!priv->skip_null_keys || priv->keys->pdata[active]); + + priv->active = active; + priv->active_key = priv->keys->pdata[active]; + + g_object_notify (G_OBJECT (listbox), "active"); + g_object_notify (G_OBJECT (listbox), "active-key"); +} + +/** + * nmt_newt_listbox_set_active_key: + * @listbox: an #NmtNewtListbox + * @active_key: the key for the row to make active + * + * Selects the (first) row in @listbox with @active_key as its key, + * scrolling it into view if needed. + */ +void +nmt_newt_listbox_set_active_key (NmtNewtListbox *listbox, + gpointer active_key) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox); + int i; + + if (active_key == priv->active_key) + return; + + g_return_if_fail (!priv->skip_null_keys || active_key); + + for (i = 0; i < priv->keys->len; i++) { + if (priv->keys->pdata[i] == active_key) { + priv->active = i; + priv->active_key = active_key; + + g_object_notify (G_OBJECT (listbox), "active"); + g_object_notify (G_OBJECT (listbox), "active-key"); + return; + } + } +} + +/** + * nmt_newt_listbox_get_active: + * @listbox: an #NmtNewtListbox + * + * Gets the currently-selected row in @listbox. + * + * Returns: the currently-selected row in @listbox. + */ +int +nmt_newt_listbox_get_active (NmtNewtListbox *listbox) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox); + + return priv->active; +} + +/** + * nmt_newt_listbox_get_active_key: + * @listbox: an #NmtNewtListbox + * + * Gets the key of the currently-selected row in @listbox. + * + * Returns: the key of the currently-selected row in @listbox. + */ +gpointer +nmt_newt_listbox_get_active_key (NmtNewtListbox *listbox) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox); + + return priv->active_key; +} + +/** + * nmt_newt_listbox_set_height: + * @listbox: an #NmtNewtListbox + * @height: the new height, or -1 for no fixed heigh + * + * Updates @listbox's height. + */ +void +nmt_newt_listbox_set_height (NmtNewtListbox *listbox, + int height) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox); + + priv->height = height; + priv->fixed_height = priv->height != 0; + g_object_notify (G_OBJECT (listbox), "height"); +} + +static void +nmt_newt_listbox_init (NmtNewtListbox *listbox) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox); + + priv->entries = g_ptr_array_new_with_free_func (g_free); + priv->keys = g_ptr_array_new (); + + priv->active = -1; +} + +static void +nmt_newt_listbox_finalize (GObject *object) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (object); + + g_ptr_array_unref (priv->entries); + g_ptr_array_unref (priv->keys); + + G_OBJECT_CLASS (nmt_newt_listbox_parent_class)->finalize (object); +} + +static void +nmt_newt_listbox_size_request (NmtNewtWidget *widget, + int *width, + int *height) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (widget); + + NMT_NEWT_WIDGET_CLASS (nmt_newt_listbox_parent_class)-> + size_request (widget, width, height); + + priv->alloc_height = -1; + if (!priv->fixed_height) + *height = 1; + priv->width = *width; +} + +static void +nmt_newt_listbox_size_allocate (NmtNewtWidget *widget, + int x, + int y, + int width, + int height) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (widget); + + if (width > priv->width) { + newtListboxSetWidth (nmt_newt_component_get_component (NMT_NEWT_COMPONENT (widget)), + width); + } + + NMT_NEWT_WIDGET_CLASS (nmt_newt_listbox_parent_class)-> + size_allocate (widget, x, y, width, height); + + priv->alloc_height = height; + + if (!priv->fixed_height && height != priv->height) { + priv->height = height; + nmt_newt_widget_needs_rebuild (widget); + } +} + +static void +update_active_internal (NmtNewtListbox *listbox, + int new_active) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox); + + if (priv->active == new_active) + return; + if (new_active >= priv->keys->len) + return; + + if (priv->skip_null_keys && !priv->keys->pdata[new_active]) { + if (new_active > priv->active) { + while ( new_active < priv->entries->len + && !priv->keys->pdata[new_active]) + new_active++; + } else { + while ( new_active >= 0 + && !priv->keys->pdata[new_active]) + new_active--; + } + + if ( new_active < 0 + || new_active >= priv->entries->len + || !priv->keys->pdata[new_active]) { + g_assert (priv->active >= 0 && priv->active < priv->entries->len); + return; + } + } + + nmt_newt_listbox_set_active (listbox, new_active); +} + +static void +selection_changed_callback (newtComponent co, + void *user_data) +{ + NmtNewtListbox *listbox = user_data; + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox); + int new_active; + + new_active = GPOINTER_TO_UINT (newtListboxGetCurrent (co)); + update_active_internal (listbox, new_active); + + if (priv->active != new_active) + newtListboxSetCurrent (co, priv->active); +} + +static guint +convert_flags (NmtNewtListboxFlags flags) +{ + guint newt_flags = NEWT_FLAG_RETURNEXIT; + + if (flags & NMT_NEWT_LISTBOX_SCROLL) + newt_flags |= NEWT_FLAG_SCROLL; + if (flags & NMT_NEWT_LISTBOX_BORDER) + newt_flags |= NEWT_FLAG_BORDER; + + return newt_flags; +} + +static newtComponent +nmt_newt_listbox_build_component (NmtNewtComponent *component, + gboolean sensitive) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (component); + newtComponent co; + int i, active; + + if (priv->active == -1) + update_active_internal (NMT_NEWT_LISTBOX (component), 0); + active = priv->active; + + co = newtListbox (-1, -1, priv->height, convert_flags (priv->flags)); + newtComponentAddCallback (co, selection_changed_callback, component); + + for (i = 0; i < priv->entries->len; i++) { + newtListboxAppendEntry (co, priv->entries->pdata[i], GUINT_TO_POINTER (i)); + if (active == -1 && priv->keys->pdata[i] == priv->active_key) + active = i; + } + + if (active != -1) + newtListboxSetCurrent (co, active); + + return co; +} + +static void +nmt_newt_listbox_activated (NmtNewtWidget *widget) +{ + NmtNewtListbox *listbox = NMT_NEWT_LISTBOX (widget); + newtComponent co = nmt_newt_component_get_component (NMT_NEWT_COMPONENT (widget)); + + nmt_newt_listbox_set_active (listbox, GPOINTER_TO_UINT (newtListboxGetCurrent (co))); + + NMT_NEWT_WIDGET_CLASS (nmt_newt_listbox_parent_class)->activated (widget); +} + +static void +nmt_newt_listbox_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtListbox *listbox = NMT_NEWT_LISTBOX (object); + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_HEIGHT: + priv->height = g_value_get_int (value); + priv->fixed_height = (priv->height != 0); + break; + case PROP_FLAGS: + priv->flags = g_value_get_uint (value); + break; + case PROP_ACTIVE: + nmt_newt_listbox_set_active (listbox, g_value_get_int (value)); + break; + case PROP_ACTIVE_KEY: + nmt_newt_listbox_set_active_key (listbox, g_value_get_pointer (value)); + break; + case PROP_SKIP_NULL_KEYS: + priv->skip_null_keys = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_listbox_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_HEIGHT: + g_value_set_int (value, priv->height); + break; + case PROP_FLAGS: + g_value_set_uint (value, priv->flags); + break; + case PROP_ACTIVE: + g_value_set_int (value, priv->active); + break; + case PROP_ACTIVE_KEY: + g_value_set_pointer (value, priv->active_key); + break; + case PROP_SKIP_NULL_KEYS: + g_value_set_boolean (value, priv->skip_null_keys); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_listbox_class_init (NmtNewtListboxClass *listbox_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (listbox_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (listbox_class); + NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (listbox_class); + + g_type_class_add_private (listbox_class, sizeof (NmtNewtListboxPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_listbox_set_property; + object_class->get_property = nmt_newt_listbox_get_property; + object_class->finalize = nmt_newt_listbox_finalize; + + widget_class->size_request = nmt_newt_listbox_size_request; + widget_class->size_allocate = nmt_newt_listbox_size_allocate; + widget_class->activated = nmt_newt_listbox_activated; + + component_class->build_component = nmt_newt_listbox_build_component; + + /* properties */ + + /** + * NmtNewtListbox:height: + * + * The listbox's height, or -1 if it has no fixed height. + */ + g_object_class_install_property + (object_class, PROP_HEIGHT, + g_param_spec_int ("height", "", "", + -1, 255, -1, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtListbox:flags: + * + * The listbox's #NmtNewtListboxFlags. + */ + g_object_class_install_property + (object_class, PROP_FLAGS, + g_param_spec_uint ("flags", "", "", + 0, 0xFFFF, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtListbox:active: + * + * The currently-selected row. + */ + g_object_class_install_property + (object_class, PROP_ACTIVE, + g_param_spec_int ("active", "", "", + 0, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtListbox:active-key: + * + * The key of the currently-selected row. + */ + g_object_class_install_property + (object_class, PROP_ACTIVE_KEY, + g_param_spec_pointer ("active-key", "", "", + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtListbox:skip-null-keys: + * + * If %TRUE, rows with %NULL key values will be skipped over when + * navigating the list with the arrow keys. + */ + g_object_class_install_property + (object_class, PROP_SKIP_NULL_KEYS, + g_param_spec_boolean ("skip-null-keys", "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/newt/nmt-newt-listbox.h b/clients/tui/newt/nmt-newt-listbox.h new file mode 100644 index 00000000..c18c9f8e --- /dev/null +++ b/clients/tui/newt/nmt-newt-listbox.h @@ -0,0 +1,71 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_LISTBOX_H +#define NMT_NEWT_LISTBOX_H + +#include "nmt-newt-component.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_LISTBOX (nmt_newt_listbox_get_type ()) +#define NMT_NEWT_LISTBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_LISTBOX, NmtNewtListbox)) +#define NMT_NEWT_LISTBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_LISTBOX, NmtNewtListboxClass)) +#define NMT_IS_NEWT_LISTBOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_LISTBOX)) +#define NMT_IS_NEWT_LISTBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_LISTBOX)) +#define NMT_NEWT_LISTBOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_LISTBOX, NmtNewtListboxClass)) + +struct _NmtNewtListbox { + NmtNewtComponent parent; + +}; + +typedef struct { + NmtNewtComponentClass parent; + +} NmtNewtListboxClass; + +GType nmt_newt_listbox_get_type (void); + +typedef enum { + NMT_NEWT_LISTBOX_SCROLL = (1 << 0), + NMT_NEWT_LISTBOX_BORDER = (1 << 1) +} NmtNewtListboxFlags; + +NmtNewtWidget *nmt_newt_listbox_new (int height, + NmtNewtListboxFlags flags); + +void nmt_newt_listbox_set_height (NmtNewtListbox *listbox, + int height); + +void nmt_newt_listbox_append (NmtNewtListbox *listbox, + const char *entry, + gpointer key); +void nmt_newt_listbox_clear (NmtNewtListbox *listbox); + +void nmt_newt_listbox_set_active (NmtNewtListbox *listbox, + int active); +void nmt_newt_listbox_set_active_key (NmtNewtListbox *listbox, + gpointer active_key); + +int nmt_newt_listbox_get_active (NmtNewtListbox *listbox); +gpointer nmt_newt_listbox_get_active_key (NmtNewtListbox *listbox); + +G_END_DECLS + +#endif /* NMT_NEWT_LISTBOX_H */ diff --git a/clients/tui/newt/nmt-newt-popup.c b/clients/tui/newt/nmt-newt-popup.c new file mode 100644 index 00000000..b604eaaa --- /dev/null +++ b/clients/tui/newt/nmt-newt-popup.c @@ -0,0 +1,360 @@ +/* -*- 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-popup + * @short_description: Pop-up menus + * + * #NmtNewtPopup implements a pop-up menu. When inactive, they appear + * the same as #NmtNewtButtons, displaying the label from the + * #NmtNewtPopup:active entry. When activated, they pop up a temporary + * #NmtNewtForm containing an #NmtNewtListbox to select from. + */ + +#include "config.h" + +#include <glib/gi18n-lib.h> + +#include "nmt-newt-popup.h" +#include "nmt-newt-form.h" +#include "nmt-newt-hacks.h" +#include "nmt-newt-listbox.h" +#include "nmt-newt-utils.h" + +G_DEFINE_TYPE (NmtNewtPopup, nmt_newt_popup, NMT_TYPE_NEWT_BUTTON) + +#define NMT_NEWT_POPUP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_POPUP, NmtNewtPopupPrivate)) + +typedef struct { + GArray *entries; + int active; +} NmtNewtPopupPrivate; + +enum { + PROP_0, + PROP_ACTIVE, + PROP_ACTIVE_ID, + + LAST_PROP +}; + +/** + * NmtNewtPopupEntry: + * @label: the user-visible label for the entry + * @id: the internal ID of the entry + * + * A single entry in a pop-up menu. + */ + +/** + * nmt_newt_popup_new: + * @entries: an array of #NmtNewtPopupEntry, terminated by an + * entry with a %NULL label + * + * Creates a new #NmtNewtPopup with the given entries. + * + * Returns: a new #NmtNewtPopup + */ +NmtNewtWidget * +nmt_newt_popup_new (NmtNewtPopupEntry *entries) +{ + NmtNewtWidget *widget; + NmtNewtPopupPrivate *priv; + int i; + + widget = g_object_new (NMT_TYPE_NEWT_POPUP, NULL); + priv = NMT_NEWT_POPUP_GET_PRIVATE (widget); + + for (i = 0; entries[i].label; i++) { + NmtNewtPopupEntry entry; + + entry.label = nmt_newt_locale_from_utf8 (_(entries[i].label)); + entry.id = g_strdup (entries[i].id); + g_array_append_val (priv->entries, entry); + } + + return widget; +} + +static void +popup_entry_clear_func (NmtNewtPopupEntry *entry) +{ + g_free (entry->label); + g_free (entry->id); +} + +static void +nmt_newt_popup_init (NmtNewtPopup *popup) +{ + NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (popup); + + priv->entries = g_array_sized_new (FALSE, FALSE, sizeof (NmtNewtPopupEntry), 10); + g_array_set_clear_func (priv->entries, (GDestroyNotify) popup_entry_clear_func); +} + +static void +nmt_newt_popup_finalize (GObject *object) +{ + NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (object); + + g_array_unref (priv->entries); + + G_OBJECT_CLASS (nmt_newt_popup_parent_class)->finalize (object); +} + +static newtComponent +nmt_newt_popup_build_component (NmtNewtComponent *component, + gboolean sensitive) +{ + NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (component); + NmtNewtPopupEntry *entries = (NmtNewtPopupEntry *)priv->entries->data; + + nmt_newt_button_set_label (NMT_NEWT_BUTTON (component), + entries[priv->active].label); + return NMT_NEWT_COMPONENT_CLASS (nmt_newt_popup_parent_class)-> + build_component (component, sensitive); +} + +static void +nmt_newt_popup_activated (NmtNewtWidget *widget) +{ + NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (widget); + NmtNewtPopupEntry *entries = (NmtNewtPopupEntry *)priv->entries->data; + NmtNewtForm *form; + NmtNewtWidget *listbox, *ret; + int button_x, button_y; + int window_x, window_y; + int list_w, list_h; + int i, active; + + listbox = nmt_newt_listbox_new (priv->entries->len, 0); + nmt_newt_widget_set_exit_on_activate (listbox, TRUE); + for (i = 0; i < priv->entries->len; i++) + nmt_newt_listbox_append (NMT_NEWT_LISTBOX (listbox), entries[i].label, NULL); + nmt_newt_listbox_set_active (NMT_NEWT_LISTBOX (listbox), priv->active); + nmt_newt_widget_set_padding (listbox, 1, 0, 1, 0); + + nmt_newt_widget_size_request (listbox, &list_w, &list_h); + + g_object_get (nmt_newt_widget_get_form (widget), + "x", &window_x, + "y", &window_y, + NULL); + newtComponentGetPosition (nmt_newt_component_get_component (NMT_NEWT_COMPONENT (widget)), + &button_x, &button_y); + /* (window_x + button_x) is the screen X coordinate of the newtComponent. A + * newtButton labelled "Foo" is rendered as " <Foo>" (with a preceding + * space), so the "F" is at (window_x + button_x + 2). We've added 1 column + * of padding to the left of the listbox, so we need to position the popup + * at (window_x + button_x + 1) in order for its text to be aligned with the + * button's text. (The x and y coordinates given to NmtNewtForm are the + * coordinates of the top left of the window content, ignoring the border + * graphics.) + */ + window_x += button_x + 1; + window_y += button_y - priv->active; + + form = g_object_new (NMT_TYPE_NEWT_FORM, + "x", window_x, + "y", window_y, + "width", list_w, + "height", list_h, + "padding", 0, + "escape-exits", TRUE, + NULL); + nmt_newt_form_set_content (form, listbox); + + ret = nmt_newt_form_run_sync (form); + if (ret == listbox) + active = nmt_newt_listbox_get_active (NMT_NEWT_LISTBOX (listbox)); + else + active = priv->active; + + g_object_unref (form); + + if (active != priv->active) { + priv->active = active; + g_object_notify (G_OBJECT (widget), "active"); + g_object_notify (G_OBJECT (widget), "active-id"); + nmt_newt_widget_needs_rebuild (widget); + } + + NMT_NEWT_WIDGET_CLASS (nmt_newt_popup_parent_class)->activated (widget); +} + +/** + * nmt_newt_popup_get_active: + * @popup: a #NmtNewtPopup + * + * Gets the index of the active entry in @popup. + * + * Returns: the index of the active entry in @popup. + */ +int +nmt_newt_popup_get_active (NmtNewtPopup *popup) +{ + NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (popup); + + return priv->active; +} + +/** + * nmt_newt_popup_set_active: + * @popup: a #NmtNewtPopup + * @active: the index of the new active entry + * + * Sets the active entry in @popup. + */ +void +nmt_newt_popup_set_active (NmtNewtPopup *popup, + int active) +{ + NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (popup); + + active = CLAMP (active, 0, priv->entries->len - 1); + + if (active != priv->active) { + priv->active = active; + g_object_notify (G_OBJECT (popup), "active"); + g_object_notify (G_OBJECT (popup), "active-id"); + } +} + +/** + * nmt_newt_popup_get_active_id: + * @popup: a #NmtNewtPopup + * + * Gets the textual ID of the active entry in @popup. + * + * Returns: the ID of the active entry in @popup. + */ +const char * +nmt_newt_popup_get_active_id (NmtNewtPopup *popup) +{ + NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (popup); + NmtNewtPopupEntry *entries = (NmtNewtPopupEntry *)priv->entries->data; + + return entries[priv->active].id; +} + +/** + * nmt_newt_popup_set_active_id: + * @popup: a #NmtNewtPopup + * @active_id: the ID of the new active entry + * + * Sets the active entry in @popup. + */ +void +nmt_newt_popup_set_active_id (NmtNewtPopup *popup, + const char *active_id) +{ + NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (popup); + NmtNewtPopupEntry *entries = (NmtNewtPopupEntry *)priv->entries->data; + int i; + + for (i = 0; i < priv->entries->len; i++) { + if (!g_strcmp0 (active_id, entries[i].id)) { + nmt_newt_popup_set_active (popup, i); + return; + } + } +} + +static void +nmt_newt_popup_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtPopup *popup = NMT_NEWT_POPUP (object); + + switch (prop_id) { + case PROP_ACTIVE: + nmt_newt_popup_set_active (popup, g_value_get_uint (value)); + break; + case PROP_ACTIVE_ID: + nmt_newt_popup_set_active_id (popup, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_popup_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtPopup *popup = NMT_NEWT_POPUP (object); + + switch (prop_id) { + case PROP_ACTIVE: + g_value_set_uint (value, nmt_newt_popup_get_active (popup)); + break; + case PROP_ACTIVE_ID: + g_value_set_string (value, nmt_newt_popup_get_active_id (popup)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_popup_class_init (NmtNewtPopupClass *popup_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (popup_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (popup_class); + NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (popup_class); + + g_type_class_add_private (popup_class, sizeof (NmtNewtPopupPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_popup_set_property; + object_class->get_property = nmt_newt_popup_get_property; + object_class->finalize = nmt_newt_popup_finalize; + + widget_class->activated = nmt_newt_popup_activated; + + component_class->build_component = nmt_newt_popup_build_component; + + /** + * NmtNewtPopup:active: + * + * The index of the currently-active entry. + */ + g_object_class_install_property + (object_class, PROP_ACTIVE, + g_param_spec_uint ("active", "", "", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtPopup:active-id: + * + * The textual ID of the currently-active entry. + */ + g_object_class_install_property + (object_class, PROP_ACTIVE_ID, + g_param_spec_string ("active-id", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/newt/nmt-newt-popup.h b/clients/tui/newt/nmt-newt-popup.h new file mode 100644 index 00000000..643ea2d8 --- /dev/null +++ b/clients/tui/newt/nmt-newt-popup.h @@ -0,0 +1,62 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_POPUP_H +#define NMT_NEWT_POPUP_H + +#include "nmt-newt-button.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_POPUP (nmt_newt_popup_get_type ()) +#define NMT_NEWT_POPUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_POPUP, NmtNewtPopup)) +#define NMT_NEWT_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_POPUP, NmtNewtPopupClass)) +#define NMT_IS_NEWT_POPUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_POPUP)) +#define NMT_IS_NEWT_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_POPUP)) +#define NMT_NEWT_POPUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_POPUP, NmtNewtPopupClass)) + +struct _NmtNewtPopup { + NmtNewtButton parent; + +}; + +typedef struct { + NmtNewtButtonClass parent; + +} NmtNewtPopupClass; + +GType nmt_newt_popup_get_type (void); + +typedef struct { + char *label; + char *id; +} NmtNewtPopupEntry; + +NmtNewtWidget *nmt_newt_popup_new (NmtNewtPopupEntry *entries); + +int nmt_newt_popup_get_active (NmtNewtPopup *popup); +void nmt_newt_popup_set_active (NmtNewtPopup *popup, + int active); + +const char *nmt_newt_popup_get_active_id (NmtNewtPopup *popup); +void nmt_newt_popup_set_active_id (NmtNewtPopup *popup, + const char *active_id); + +G_END_DECLS + +#endif /* NMT_NEWT_POPUP_H */ diff --git a/clients/tui/newt/nmt-newt-section.c b/clients/tui/newt/nmt-newt-section.c new file mode 100644 index 00000000..1a5035fc --- /dev/null +++ b/clients/tui/newt/nmt-newt-section.c @@ -0,0 +1,447 @@ +/* -*- 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 + * optionally 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; + + gboolean show_border; + 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_SHOW_BORDER, + PROP_OPEN, + + LAST_PROP +}; + +/** + * nmt_newt_section_new: + * @show_border: whether to show the border on the side of the section + * + * Creates a new #NmtNewtSection + * + * Returns: a new #NmtNewtSection + */ +NmtNewtWidget * +nmt_newt_section_new (gboolean show_border) +{ + return g_object_new (NMT_TYPE_NEWT_SECTION, + "show-border", show_border, + 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->show_border = TRUE; + + 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 (); + + if (priv->show_border) { + 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 w_ignore, h_ignore; + + g_return_if_fail (priv->header != NULL && priv->body != NULL); + + if (priv->show_border) + nmt_newt_widget_size_request (priv->border_grid, &w_ignore, &h_ignore); + 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; + if (priv->open) + *height = priv->hheight_req + priv->bheight_req + (priv->show_border ? 1 : 0); + else + *height = 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); + + if (priv->show_border) { + int w_ignore, h_ignore; + + adjust_border_for_allocation (priv, height); + nmt_newt_widget_size_request (priv->border_grid, &w_ignore, &h_ignore); + 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); + } else + nmt_newt_widget_size_allocate (priv->header, x, 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_SHOW_BORDER: + priv->show_border = g_value_get_boolean (value); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (object)); + break; + 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_SHOW_BORDER: + g_value_set_boolean (value, priv->show_border); + break; + 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:show-border: + * + * %TRUE if the section should show a border along the left side. + */ + g_object_class_install_property + (object_class, PROP_SHOW_BORDER, + g_param_spec_boolean ("show-border", "", "", + TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * 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 ("\\"); + } +} diff --git a/clients/tui/newt/nmt-newt-section.h b/clients/tui/newt/nmt-newt-section.h new file mode 100644 index 00000000..6bf59ebb --- /dev/null +++ b/clients/tui/newt/nmt-newt-section.h @@ -0,0 +1,57 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_SECTION_H +#define NMT_NEWT_SECTION_H + +#include "nmt-newt-container.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_SECTION (nmt_newt_section_get_type ()) +#define NMT_NEWT_SECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_SECTION, NmtNewtSection)) +#define NMT_NEWT_SECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_SECTION, NmtNewtSectionClass)) +#define NMT_IS_NEWT_SECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_SECTION)) +#define NMT_IS_NEWT_SECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_SECTION)) +#define NMT_NEWT_SECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_SECTION, NmtNewtSectionClass)) + +struct _NmtNewtSection { + NmtNewtContainer parent; + +}; + +typedef struct { + NmtNewtContainerClass parent; + +} NmtNewtSectionClass; + +GType nmt_newt_section_get_type (void); + +NmtNewtWidget *nmt_newt_section_new (gboolean show_border); + +void nmt_newt_section_set_header (NmtNewtSection *section, + NmtNewtWidget *header); +NmtNewtWidget *nmt_newt_section_get_header (NmtNewtSection *section); + +void nmt_newt_section_set_body (NmtNewtSection *section, + NmtNewtWidget *body); +NmtNewtWidget *nmt_newt_section_get_body (NmtNewtSection *section); + +G_END_DECLS + +#endif /* NMT_NEWT_SECTION_H */ diff --git a/clients/tui/newt/nmt-newt-separator.c b/clients/tui/newt/nmt-newt-separator.c new file mode 100644 index 00000000..07deb1af --- /dev/null +++ b/clients/tui/newt/nmt-newt-separator.c @@ -0,0 +1,66 @@ +/* -*- 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-separator + * @short_description: Separator + * + * #NmtNewtSeparator is just a blank label, which is used in a few places + * where a widget is needed but none is desired, or to add blank space + * between widgets in containers that don't implement padding. + */ + +#include "config.h" + +#include "nmt-newt-separator.h" + +G_DEFINE_TYPE (NmtNewtSeparator, nmt_newt_separator, NMT_TYPE_NEWT_COMPONENT) + +/** + * nmt_newt_separator_new: + * + * Creates a new #NmtNewtSeparator. + * + * Returns: a new #NmtNewtSeparator + */ +NmtNewtWidget * +nmt_newt_separator_new (void) +{ + return g_object_new (NMT_TYPE_NEWT_SEPARATOR, NULL); +} + +static void +nmt_newt_separator_init (NmtNewtSeparator *separator) +{ +} + +static newtComponent +nmt_newt_separator_build_component (NmtNewtComponent *component, + gboolean sensitive) +{ + return newtLabel (-1, -1, " "); +} + +static void +nmt_newt_separator_class_init (NmtNewtSeparatorClass *separator_class) +{ + NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (separator_class); + + /* virtual methods */ + component_class->build_component = nmt_newt_separator_build_component; +} diff --git a/clients/tui/newt/nmt-newt-separator.h b/clients/tui/newt/nmt-newt-separator.h new file mode 100644 index 00000000..3f4183d5 --- /dev/null +++ b/clients/tui/newt/nmt-newt-separator.h @@ -0,0 +1,49 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_SEPARATOR_H +#define NMT_NEWT_SEPARATOR_H + +#include "nmt-newt-component.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_SEPARATOR (nmt_newt_separator_get_type ()) +#define NMT_NEWT_SEPARATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_SEPARATOR, NmtNewtSeparator)) +#define NMT_NEWT_SEPARATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_SEPARATOR, NmtNewtSeparatorClass)) +#define NMT_IS_NEWT_SEPARATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_SEPARATOR)) +#define NMT_IS_NEWT_SEPARATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_SEPARATOR)) +#define NMT_NEWT_SEPARATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_SEPARATOR, NmtNewtSeparatorClass)) + +struct _NmtNewtSeparator { + NmtNewtComponent parent; + +}; + +typedef struct { + NmtNewtComponentClass parent; + +} NmtNewtSeparatorClass; + +GType nmt_newt_separator_get_type (void); + +NmtNewtWidget *nmt_newt_separator_new (void); + +G_END_DECLS + +#endif /* NMT_NEWT_SEPARATOR_H */ diff --git a/clients/tui/newt/nmt-newt-stack.c b/clients/tui/newt/nmt-newt-stack.c new file mode 100644 index 00000000..d94bdebf --- /dev/null +++ b/clients/tui/newt/nmt-newt-stack.c @@ -0,0 +1,368 @@ +/* -*- 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-stack + * @short_description: A stack of alternative widgets + * + * #NmtNewtStack implements a stack of widgets, only one of which is + * visible at any time. + * + * The height and width of the widget is determined only by its + * visible child. Likewise, the widget's #NmtNewtWidget:valid is + * determined only by the validity of its visible child, not its other + * children. + */ + +#include "config.h" + +#include <string.h> + +#include "nmt-newt-stack.h" + +G_DEFINE_TYPE (NmtNewtStack, nmt_newt_stack, NMT_TYPE_NEWT_CONTAINER) + +#define NMT_NEWT_STACK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_STACK, NmtNewtStackPrivate)) + +typedef struct { + GPtrArray *children; + GPtrArray *ids; + + guint active; +} NmtNewtStackPrivate; + +enum { + PROP_0, + PROP_ACTIVE, + PROP_ACTIVE_ID, + + LAST_PROP +}; + +/** + * nmt_newt_stack_new: + * + * Creates a new #NmtNewtStack + * + * Returns: a new #NmtNewtStack + */ +NmtNewtWidget * +nmt_newt_stack_new (void) +{ + return g_object_new (NMT_TYPE_NEWT_STACK, NULL); +} + +static void +nmt_newt_stack_init (NmtNewtStack *stack) +{ + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack); + + priv->children = g_ptr_array_new (); + priv->ids = g_ptr_array_new_with_free_func (g_free); +} + +static void +nmt_newt_stack_finalize (GObject *object) +{ + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (object); + + g_ptr_array_unref (priv->children); + g_ptr_array_unref (priv->ids); + + G_OBJECT_CLASS (nmt_newt_stack_parent_class)->finalize (object); +} + +static newtComponent * +nmt_newt_stack_get_components (NmtNewtWidget *widget) +{ + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (widget); + + if (priv->active > priv->children->len) + return NULL; + + return nmt_newt_widget_get_components (priv->children->pdata[priv->active]); +} + +static void +nmt_newt_stack_size_request (NmtNewtWidget *widget, + int *width, + int *height) +{ + NmtNewtStack *stack = NMT_NEWT_STACK (widget); + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack); + int i, child_width, child_height; + + if (priv->active > priv->children->len) { + *width = *height = 0; + return; + } + + /* We size-request all pages so that embedded NmtPageGrids will + * participate in their size-grouping (so that switching pages + * won't result in the column widths changing). + */ + for (i = 0; i < priv->children->len; i++) { + nmt_newt_widget_size_request (priv->children->pdata[i], &child_width, &child_height); + if (i == priv->active) { + *width = child_width; + *height = child_height; + } + } +} + +static void +nmt_newt_stack_size_allocate (NmtNewtWidget *widget, + int x, + int y, + int width, + int height) +{ + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (widget); + + if (priv->active > priv->children->len) + return; + + nmt_newt_widget_size_allocate (priv->children->pdata[priv->active], x, y, width, height); +} + +/** + * nmt_newt_stack_add: + * @stack: an #NmtNewtStack + * @id: the ID for the new page + * @widget: the widget to add + * + * Adds @widget to @stack with the given @id. + */ +void +nmt_newt_stack_add (NmtNewtStack *stack, + const char *id, + NmtNewtWidget *widget) +{ + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack); + + g_ptr_array_add (priv->children, widget); + g_ptr_array_add (priv->ids, g_strdup (id)); + + NMT_NEWT_CONTAINER_CLASS (nmt_newt_stack_parent_class)->add (NMT_NEWT_CONTAINER (stack), widget); +} + +static void +nmt_newt_stack_remove (NmtNewtContainer *container, + NmtNewtWidget *widget) +{ + NmtNewtStack *stack = NMT_NEWT_STACK (container); + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack); + int i; + + NMT_NEWT_CONTAINER_CLASS (nmt_newt_stack_parent_class)->remove (container, widget); + + for (i = 0; i < priv->children->len; i++) { + if (priv->children->pdata[i] == widget) { + g_ptr_array_remove_index (priv->children, i); + g_ptr_array_remove_index (priv->ids, i); + return; + } + } +} + +static void +nmt_newt_stack_child_validity_changed (NmtNewtContainer *container, + NmtNewtWidget *widget) +{ + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (container); + + if (priv->active > priv->children->len) + return; + + if (priv->children->pdata[priv->active] == (gpointer) widget) { + NMT_NEWT_CONTAINER_CLASS (nmt_newt_stack_parent_class)-> + child_validity_changed (container, widget); + } +} + +/** + * nmt_newt_stack_set_active: + * @stack: an #NmtNewtStack + * @active: the index of the new active page + * + * Sets the active page on @stack to @active. + */ +void +nmt_newt_stack_set_active (NmtNewtStack *stack, + guint active) +{ + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack); + + if (priv->active == active) + return; + + priv->active = active; + g_object_notify (G_OBJECT (stack), "active"); + g_object_notify (G_OBJECT (stack), "active-id"); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (stack)); +} + +/** + * nmt_newt_stack_get_active: + * @stack: an #NmtNewtStack + * + * Gets the index of the active page on @stack + * + * Returns: the index of the active page on @stack + */ +guint +nmt_newt_stack_get_active (NmtNewtStack *stack) +{ + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack); + + return priv->active; +} + +/** + * nmt_newt_stack_set_active_id: + * @stack: an #NmtNewtStack + * @active_id: the ID of the new active page + * + * Sets the active page on @stack to @active_id. + */ +void +nmt_newt_stack_set_active_id (NmtNewtStack *stack, + const char *id) +{ + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack); + int i; + + if (!g_strcmp0 (priv->ids->pdata[priv->active], id)) + return; + + for (i = 0; i < priv->ids->len; i++) { + if (!g_strcmp0 (priv->ids->pdata[i], id)) { + priv->active = i; + g_object_notify (G_OBJECT (stack), "active"); + g_object_notify (G_OBJECT (stack), "active-id"); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (stack)); + return; + } + } +} + +/** + * nmt_newt_stack_get_active_id: + * @stack: an #NmtNewtStack + * + * Gets the ID of the active page on @stack + * + * Returns: the ID of the active page on @stack + */ +const char * +nmt_newt_stack_get_active_id (NmtNewtStack *stack) +{ + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack); + + if (priv->active > priv->children->len) + return NULL; + + return priv->ids->pdata[priv->active]; +} + +static void +nmt_newt_stack_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtStack *stack = NMT_NEWT_STACK (object); + + switch (prop_id) { + case PROP_ACTIVE: + nmt_newt_stack_set_active (stack, g_value_get_uint (value)); + break; + case PROP_ACTIVE_ID: + nmt_newt_stack_set_active_id (stack, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_stack_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtStack *stack = NMT_NEWT_STACK (object); + + switch (prop_id) { + case PROP_ACTIVE: + g_value_set_uint (value, nmt_newt_stack_get_active (stack)); + break; + case PROP_ACTIVE_ID: + g_value_set_string (value, nmt_newt_stack_get_active_id (stack)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_stack_class_init (NmtNewtStackClass *stack_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (stack_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (stack_class); + NmtNewtContainerClass *container_class = NMT_NEWT_CONTAINER_CLASS (stack_class); + + g_type_class_add_private (stack_class, sizeof (NmtNewtStackPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_stack_set_property; + object_class->get_property = nmt_newt_stack_get_property; + object_class->finalize = nmt_newt_stack_finalize; + + widget_class->get_components = nmt_newt_stack_get_components; + widget_class->size_request = nmt_newt_stack_size_request; + widget_class->size_allocate = nmt_newt_stack_size_allocate; + + container_class->remove = nmt_newt_stack_remove; + container_class->child_validity_changed = nmt_newt_stack_child_validity_changed; + + /** + * NmtNewtStack:active: + * + * The index of the active page + */ + g_object_class_install_property + (object_class, PROP_ACTIVE, + g_param_spec_uint ("active", "", "", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtStack:active-id: + * + * The ID of the active page + */ + g_object_class_install_property + (object_class, PROP_ACTIVE_ID, + g_param_spec_string ("active-id", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/newt/nmt-newt-stack.h b/clients/tui/newt/nmt-newt-stack.h new file mode 100644 index 00000000..09afe4ba --- /dev/null +++ b/clients/tui/newt/nmt-newt-stack.h @@ -0,0 +1,61 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_STACK_H +#define NMT_NEWT_STACK_H + +#include "nmt-newt-container.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_STACK (nmt_newt_stack_get_type ()) +#define NMT_NEWT_STACK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_STACK, NmtNewtStack)) +#define NMT_NEWT_STACK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_STACK, NmtNewtStackClass)) +#define NMT_IS_NEWT_STACK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_STACK)) +#define NMT_IS_NEWT_STACK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_STACK)) +#define NMT_NEWT_STACK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_STACK, NmtNewtStackClass)) + +struct _NmtNewtStack { + NmtNewtContainer parent; + +}; + +typedef struct { + NmtNewtContainerClass parent; + +} NmtNewtStackClass; + +GType nmt_newt_stack_get_type (void); + +NmtNewtWidget *nmt_newt_stack_new (void); + +void nmt_newt_stack_add (NmtNewtStack *stack, + const char *id, + NmtNewtWidget *widget); + +void nmt_newt_stack_set_active (NmtNewtStack *stack, + guint active); +guint nmt_newt_stack_get_active (NmtNewtStack *stack); + +void nmt_newt_stack_set_active_id (NmtNewtStack *stack, + const char *id); +const char * nmt_newt_stack_get_active_id (NmtNewtStack *stack); + +G_END_DECLS + +#endif /* NMT_NEWT_STACK_H */ diff --git a/clients/tui/newt/nmt-newt-textbox.c b/clients/tui/newt/nmt-newt-textbox.c new file mode 100644 index 00000000..3d297160 --- /dev/null +++ b/clients/tui/newt/nmt-newt-textbox.c @@ -0,0 +1,295 @@ +/* -*- 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-textbox + * @short_description: Multi-line text box + * + * #NmtNewtTextbox implements a multi-line text, optionally with + * word-wrapping. + */ + +#include "config.h" + +#include <string.h> + +#include "nmt-newt-textbox.h" +#include "nmt-newt-utils.h" + +G_DEFINE_TYPE (NmtNewtTextbox, nmt_newt_textbox, NMT_TYPE_NEWT_COMPONENT) + +#define NMT_NEWT_TEXTBOX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_TEXTBOX, NmtNewtTextboxPrivate)) + +typedef struct { + int wrap_width; + NmtNewtTextboxFlags flags; + + char *text; + int width, height; +} NmtNewtTextboxPrivate; + +enum { + PROP_0, + PROP_TEXT, + PROP_FLAGS, + PROP_WRAP_WIDTH, + + LAST_PROP +}; + +/** + * NmtNewtTextboxFlags: + * @NMT_NEWT_TEXTBOX_SCROLLABLE: the textbox should be scollable. + * @NMT_NEWT_TEXTBOX_SET_BACKGROUND: the textbox should have a + * white background + * + * Flags for an #NmtNewtTextbox + */ + +/** + * nmt_newt_textbox_new: + * @flags: the textbox's flags + * @wrap_width: width in characters at which to word-wrap, or + * 0 to not wrap. + * + * Creates a new #NmtNewtTextbox. + * + * Returns: a new #NmtNewtTextbox + */ +NmtNewtWidget * +nmt_newt_textbox_new (NmtNewtTextboxFlags flags, + int wrap_width) +{ + return g_object_new (NMT_TYPE_NEWT_TEXTBOX, + "flags", flags, + "wrap-width", wrap_width, + NULL); +} + +/** + * nmt_newt_textbox_get_text: + * @textbox: an #NmtNewtTextbox + * + * Gets @textbox's text + * + * Returns: @textbox's text + */ +void +nmt_newt_textbox_set_text (NmtNewtTextbox *textbox, + const char *text) +{ + NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (textbox); + char **lines; + int i, width; + + if (!text) + text = ""; + if (!strcmp (priv->text, text)) + return; + + g_free (priv->text); + priv->text = g_strdup (text); + + priv->width = priv->height = 0; + lines = g_strsplit (priv->text, "\n", -1); + for (i = 0; lines[i]; i++) { + width = nmt_newt_text_width (lines[i]); + if (width > priv->width) + priv->width = width; + } + g_free (lines); + priv->height = MIN (i, 1); + + g_object_notify (G_OBJECT (textbox), "text"); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (textbox)); +} + +/** + * nmt_newt_textbox_get_text: + * @textbox: an #NmtNewtTextbox + * + * Gets @textbox's text + * + * Returns: @textbox's text + */ +const char * +nmt_newt_textbox_get_text (NmtNewtTextbox *textbox) +{ + NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (textbox); + + return priv->text; +} + +static void +nmt_newt_textbox_init (NmtNewtTextbox *textbox) +{ + NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (textbox); + + priv->text = g_strdup (""); +} + +static void +nmt_newt_textbox_finalize (GObject *object) +{ + NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (object); + + g_free (priv->text); + + G_OBJECT_CLASS (nmt_newt_textbox_parent_class)->finalize (object); +} + +static guint +convert_flags (NmtNewtTextboxFlags flags) +{ + guint newt_flags = 0; + + if (flags & NMT_NEWT_TEXTBOX_SCROLLABLE) + newt_flags |= NEWT_FLAG_SCROLL; + + return newt_flags; +} + +static newtComponent +nmt_newt_textbox_build_component (NmtNewtComponent *component, + gboolean sensitive) +{ + NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (component); + newtComponent co; + const char *text; + char *text_lc; + + text = priv->text; + if (!*text) + text = "\n"; + + text_lc = nmt_newt_locale_from_utf8 (text); + if (priv->wrap_width > 0) { + co = newtTextboxReflowed (-1, -1, text_lc, priv->wrap_width, 0, 0, 0); + } else { + co = newtTextbox (-1, -1, priv->width, priv->height, convert_flags (priv->flags)); + newtTextboxSetText (co, text_lc); + } + g_free (text_lc); + + if (priv->flags & NMT_NEWT_TEXTBOX_SET_BACKGROUND) + newtTextboxSetColors (co, NMT_NEWT_COLORSET_TEXTBOX_WITH_BACKGROUND, NEWT_COLORSET_ACTTEXTBOX); + + return co; +} + +static void +nmt_newt_textbox_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtTextbox *textbox = NMT_NEWT_TEXTBOX (object); + NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (textbox); + + switch (prop_id) { + case PROP_TEXT: + nmt_newt_textbox_set_text (textbox, g_value_get_string (value)); + break; + case PROP_FLAGS: + priv->flags = g_value_get_uint (value); + break; + case PROP_WRAP_WIDTH: + priv->wrap_width = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_textbox_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_TEXT: + g_value_set_string (value, priv->text); + break; + case PROP_FLAGS: + g_value_set_uint (value, priv->flags); + break; + case PROP_WRAP_WIDTH: + g_value_set_int (value, priv->wrap_width); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_textbox_class_init (NmtNewtTextboxClass *textbox_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (textbox_class); + NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (textbox_class); + + g_type_class_add_private (textbox_class, sizeof (NmtNewtTextboxPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_textbox_set_property; + object_class->get_property = nmt_newt_textbox_get_property; + object_class->finalize = nmt_newt_textbox_finalize; + + component_class->build_component = nmt_newt_textbox_build_component; + + /** + * NmtNewtTextbox:text: + * + * The textbox's text + */ + g_object_class_install_property + (object_class, PROP_TEXT, + g_param_spec_string ("text", "", "", + "", + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtTextbox:flags: + * + * The textbox's flags + */ + g_object_class_install_property + (object_class, PROP_FLAGS, + g_param_spec_uint ("flags", "", "", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtTextbox:wrap-width: + * + * The width in characters at which the textbox's text + * will wrap, or 0 if it does not wrap. + */ + g_object_class_install_property + (object_class, PROP_WRAP_WIDTH, + g_param_spec_int ("wrap-width", "", "", + 0, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/newt/nmt-newt-textbox.h b/clients/tui/newt/nmt-newt-textbox.h new file mode 100644 index 00000000..b3743aea --- /dev/null +++ b/clients/tui/newt/nmt-newt-textbox.h @@ -0,0 +1,59 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_TEXTBOX_H +#define NMT_NEWT_TEXTBOX_H + +#include "nmt-newt-component.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_TEXTBOX (nmt_newt_textbox_get_type ()) +#define NMT_NEWT_TEXTBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_TEXTBOX, NmtNewtTextbox)) +#define NMT_NEWT_TEXTBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_TEXTBOX, NmtNewtTextboxClass)) +#define NMT_IS_NEWT_TEXTBOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_TEXTBOX)) +#define NMT_IS_NEWT_TEXTBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_TEXTBOX)) +#define NMT_NEWT_TEXTBOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_TEXTBOX, NmtNewtTextboxClass)) + +struct _NmtNewtTextbox { + NmtNewtComponent parent; + +}; + +typedef struct { + NmtNewtComponentClass parent; + +} NmtNewtTextboxClass; + +GType nmt_newt_textbox_get_type (void); + +typedef enum { + NMT_NEWT_TEXTBOX_SCROLLABLE = (1 << 0), + NMT_NEWT_TEXTBOX_SET_BACKGROUND = (1 << 1) +} NmtNewtTextboxFlags; + +NmtNewtWidget *nmt_newt_textbox_new (NmtNewtTextboxFlags flags, + int wrap_width); + +void nmt_newt_textbox_set_text (NmtNewtTextbox *textbox, + const char *text); +const char *nmt_newt_textbox_get_text (NmtNewtTextbox *textbox); + +G_END_DECLS + +#endif /* NMT_NEWT_TEXTBOX_H */ diff --git a/clients/tui/newt/nmt-newt-toggle-button.c b/clients/tui/newt/nmt-newt-toggle-button.c new file mode 100644 index 00000000..ec4d9aca --- /dev/null +++ b/clients/tui/newt/nmt-newt-toggle-button.c @@ -0,0 +1,237 @@ +/* -*- 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-toggle-button + * @short_description: Toggle buttons + * + * #NmtNewtToggleButton implements a two-state toggle button. + */ + +#include "config.h" + +#include "nmt-newt-toggle-button.h" + +G_DEFINE_TYPE (NmtNewtToggleButton, nmt_newt_toggle_button, NMT_TYPE_NEWT_BUTTON) + +#define NMT_NEWT_TOGGLE_BUTTON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_TOGGLE_BUTTON, NmtNewtToggleButtonPrivate)) + +typedef struct { + char *on_label, *off_label; + gboolean active; +} NmtNewtToggleButtonPrivate; + +enum { + PROP_0, + PROP_ON_LABEL, + PROP_OFF_LABEL, + PROP_ACTIVE, + + LAST_PROP +}; + +/** + * nmt_newt_toggle_button_new: + * @on_label: the button's label when it is in the "on" state + * @off_label: the button's label when it is in the "off" state + * + * Creates a new #NmtNewtToggleButton + * + * Returns: a new #NmtNewtToggleButton + */ +NmtNewtWidget * +nmt_newt_toggle_button_new (const char *on_label, + const char *off_label) +{ + return g_object_new (NMT_TYPE_NEWT_TOGGLE_BUTTON, + "on-label", on_label, + "off-label", off_label, + NULL); +} + +/** + * nmt_newt_toggle_button_get_active: + * @button: an #NmtNewtToggleButton + * + * Gets whether @button is currently "on" or "off" + * + * Returns: whether @button is currently "on" (%TRUE) or "off" (%FALSE) + */ +gboolean +nmt_newt_toggle_button_get_active (NmtNewtToggleButton *button) +{ + NmtNewtToggleButtonPrivate *priv = NMT_NEWT_TOGGLE_BUTTON_GET_PRIVATE (button); + + return priv->active; +} + +/** + * nmt_newt_toggle_button_set_active: + * @button: an #NmtNewtToggleButton + * @active: whether @button should be "on" or "off" + * + * Sets whether @button is currently "on" or "off" + */ +void +nmt_newt_toggle_button_set_active (NmtNewtToggleButton *button, + gboolean active) +{ + NmtNewtToggleButtonPrivate *priv = NMT_NEWT_TOGGLE_BUTTON_GET_PRIVATE (button); + + if (priv->active == active) + return; + + priv->active = active; + g_object_set (G_OBJECT (button), + "label", active ? priv->on_label : priv->off_label, + NULL); + g_object_notify (G_OBJECT (button), "active"); +} + +static void +nmt_newt_toggle_button_init (NmtNewtToggleButton *button) +{ +} + +static void +nmt_newt_toggle_button_finalize (GObject *object) +{ + NmtNewtToggleButtonPrivate *priv = NMT_NEWT_TOGGLE_BUTTON_GET_PRIVATE (object); + + g_free (priv->on_label); + g_free (priv->off_label); + + G_OBJECT_CLASS (nmt_newt_toggle_button_parent_class)->finalize (object); +} + +static void +nmt_newt_toggle_button_activated (NmtNewtWidget *widget) +{ + NmtNewtToggleButton *button = NMT_NEWT_TOGGLE_BUTTON (widget); + + nmt_newt_toggle_button_set_active (button, !nmt_newt_toggle_button_get_active (button)); + + NMT_NEWT_WIDGET_CLASS (nmt_newt_toggle_button_parent_class)->activated (widget); +} + +static void +nmt_newt_toggle_button_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtToggleButtonPrivate *priv = NMT_NEWT_TOGGLE_BUTTON_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_ON_LABEL: + g_free (priv->on_label); + priv->on_label = g_value_dup_string (value); + if (priv->active) + g_object_set (object, "label", priv->on_label, NULL); + break; + case PROP_OFF_LABEL: + g_free (priv->off_label); + priv->off_label = g_value_dup_string (value); + if (!priv->active) + g_object_set (object, "label", priv->off_label, NULL); + break; + case PROP_ACTIVE: + priv->active = g_value_get_boolean (value); + g_object_set (object, + "label", priv->active ? priv->on_label : priv->off_label, + NULL); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_toggle_button_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtToggleButtonPrivate *priv = NMT_NEWT_TOGGLE_BUTTON_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_ON_LABEL: + g_value_set_string (value, priv->on_label); + break; + case PROP_OFF_LABEL: + g_value_set_string (value, priv->off_label); + break; + case PROP_ACTIVE: + g_value_set_boolean (value, priv->active); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_toggle_button_class_init (NmtNewtToggleButtonClass *button_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (button_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (button_class); + + g_type_class_add_private (button_class, sizeof (NmtNewtToggleButtonPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_toggle_button_set_property; + object_class->get_property = nmt_newt_toggle_button_get_property; + object_class->finalize = nmt_newt_toggle_button_finalize; + + widget_class->activated = nmt_newt_toggle_button_activated; + + /** + * NmtNewtToggleButton:on-label: + * + * The label the button displays when it is "on". + */ + g_object_class_install_property + (object_class, PROP_ON_LABEL, + g_param_spec_string ("on-label", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtToggleButton:off-label: + * + * The label the button displays when it is "off". + */ + g_object_class_install_property + (object_class, PROP_OFF_LABEL, + g_param_spec_string ("off-label", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtToggleButton:active: + * + * Whether the button is currently "on" (%TRUE) or "off" (%FALSE) + */ + g_object_class_install_property + (object_class, PROP_ACTIVE, + g_param_spec_boolean ("active", "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/newt/nmt-newt-toggle-button.h b/clients/tui/newt/nmt-newt-toggle-button.h new file mode 100644 index 00000000..e54c6d3f --- /dev/null +++ b/clients/tui/newt/nmt-newt-toggle-button.h @@ -0,0 +1,54 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_TOGGLE_BUTTON_H +#define NMT_NEWT_TOGGLE_BUTTON_H + +#include "nmt-newt-button.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_TOGGLE_BUTTON (nmt_newt_toggle_button_get_type ()) +#define NMT_NEWT_TOGGLE_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_TOGGLE_BUTTON, NmtNewtToggleButton)) +#define NMT_NEWT_TOGGLE_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_TOGGLE_BUTTON, NmtNewtToggleButtonClass)) +#define NMT_IS_NEWT_TOGGLE_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_TOGGLE_BUTTON)) +#define NMT_IS_NEWT_TOGGLE_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_TOGGLE_BUTTON)) +#define NMT_NEWT_TOGGLE_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_TOGGLE_BUTTON, NmtNewtToggleButtonClass)) + +struct _NmtNewtToggleButton { + NmtNewtButton parent; + +}; + +typedef struct { + NmtNewtButtonClass parent; + +} NmtNewtToggleButtonClass; + +GType nmt_newt_toggle_button_get_type (void); + +NmtNewtWidget *nmt_newt_toggle_button_new (const char *on_label, + const char *off_label); + +gboolean nmt_newt_toggle_button_get_active (NmtNewtToggleButton *button); +void nmt_newt_toggle_button_set_active (NmtNewtToggleButton *button, + gboolean active); + +G_END_DECLS + +#endif /* NMT_NEWT_TOGGLE_BUTTON_H */ diff --git a/clients/tui/newt/nmt-newt-types.h b/clients/tui/newt/nmt-newt-types.h new file mode 100644 index 00000000..608f7ff6 --- /dev/null +++ b/clients/tui/newt/nmt-newt-types.h @@ -0,0 +1,50 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_TYPES_H +#define NMT_NEWT_TYPES_H + +#include <glib-object.h> +#include <newt.h> +#include "nm-glib-compat.h" + +G_BEGIN_DECLS + +typedef struct _NmtNewtButton NmtNewtButton; +typedef struct _NmtNewtButtonBox NmtNewtButtonBox; +typedef struct _NmtNewtCheckbox NmtNewtCheckbox; +typedef struct _NmtNewtComponent NmtNewtComponent; +typedef struct _NmtNewtContainer NmtNewtContainer; +typedef struct _NmtNewtEntry NmtNewtEntry; +typedef struct _NmtNewtEntryNumeric NmtNewtEntryNumeric; +typedef struct _NmtNewtForm NmtNewtForm; +typedef struct _NmtNewtGrid NmtNewtGrid; +typedef struct _NmtNewtLabel NmtNewtLabel; +typedef struct _NmtNewtListbox NmtNewtListbox; +typedef struct _NmtNewtPopup NmtNewtPopup; +typedef struct _NmtNewtSection NmtNewtSection; +typedef struct _NmtNewtSectionBorder NmtNewtSectionBorder; +typedef struct _NmtNewtSeparator NmtNewtSeparator; +typedef struct _NmtNewtStack NmtNewtStack; +typedef struct _NmtNewtTextbox NmtNewtTextbox; +typedef struct _NmtNewtToggleButton NmtNewtToggleButton; +typedef struct _NmtNewtWidget NmtNewtWidget; + +G_END_DECLS + +#endif /* NMT_NEWT_COMPONENT_H */ diff --git a/clients/tui/newt/nmt-newt-utils.c b/clients/tui/newt/nmt-newt-utils.c new file mode 100644 index 00000000..70a65a84 --- /dev/null +++ b/clients/tui/newt/nmt-newt-utils.c @@ -0,0 +1,393 @@ +/* -*- 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-utils + * @short_description: Utility functions + */ + +#include "config.h" + +#include <errno.h> +#include <stdarg.h> +#include <unistd.h> +#include <sys/wait.h> + +#include <glib/gi18n-lib.h> + +#include "nm-glib-compat.h" +#include "nmt-newt-utils.h" + +static void +nmt_newt_dialog_g_log_handler (const char *log_domain, + GLogLevelFlags log_level, + const char *message, + gpointer user_data) +{ + const char *level_name; + char *full_message; + int screen_width, screen_height; + newtComponent text, ok, form; + newtGrid grid; + + g_assert (!(log_level & G_LOG_FLAG_RECURSION)); + + if (log_level & G_LOG_LEVEL_DEBUG) + return; + + switch (log_level & G_LOG_LEVEL_MASK) { + case G_LOG_LEVEL_ERROR: + level_name = "ERROR"; + break; + case G_LOG_LEVEL_CRITICAL: + level_name = "CRITICAL"; + break; + case G_LOG_LEVEL_WARNING: + level_name = "WARNING"; + break; + case G_LOG_LEVEL_MESSAGE: + level_name = "Message"; + break; + default: + level_name = NULL; + } + + full_message = g_strdup_printf ("%s%s%s%s%s", + log_domain ? log_domain : "", + log_domain && level_name ? " " : "", + level_name ? level_name : "", + log_domain || level_name ? ": " : "", + message); + + /* newtWinMessage() wraps the window too narrowly by default, so + * we don't want to use that. But we intentionally avoid using any + * NmtNewt classes, to avoid possible error recursion. + */ + + newtGetScreenSize (&screen_width, &screen_height); + text = newtTextboxReflowed (-1, -1, full_message, MAX (70, screen_width - 10), 0, 0, 0); + g_free (full_message); + + ok = newtButton (-1, -1, "OK"); + + grid = newtCreateGrid (1, 2); + newtGridSetField (grid, 0, 0, NEWT_GRID_COMPONENT, text, 0, 0, 0, 0, 0, 0); + newtGridSetField (grid, 0, 1, NEWT_GRID_COMPONENT, ok, 0, 1, 0, 0, + NEWT_ANCHOR_RIGHT, 0); + + newtGridWrappedWindow (grid, (char *) (level_name ? level_name : "")); + newtGridFree (grid, TRUE); + + form = newtForm (NULL, NULL, 0); + newtFormAddComponents (form, text, ok, NULL); + newtRunForm (form); + newtFormDestroy (form); + newtPopWindow (); +} + +static void +nmt_newt_basic_g_log_handler (const char *log_domain, + GLogLevelFlags log_level, + const char *message, + gpointer user_data) +{ + newtSuspend (); + g_log_default_handler (log_domain, log_level, message, NULL); + newtResume (); +} + +static void +nmt_newt_suspend_callback (gpointer user_data) +{ + newtSuspend (); + kill (getpid (), SIGTSTP); + newtResume (); +} + +/** + * nmt_newt_init: + * + * Wrapper for newtInit() that also does some nmt-newt-internal setup. + * This should be called once, before any other nmt-newt functions. + */ +void +nmt_newt_init (void) +{ + newtInit (); + newtCls (); + + newtSetColor (NEWT_COLORSET_CHECKBOX, "black", "lightgray"); + newtSetColor (NMT_NEWT_COLORSET_BAD_LABEL, "red", "lightgray"); + newtSetColor (NMT_NEWT_COLORSET_PLAIN_LABEL, "black", "lightgray"); + newtSetColor (NMT_NEWT_COLORSET_DISABLED_BUTTON, "blue", "lightgray"); + newtSetColor (NMT_NEWT_COLORSET_TEXTBOX_WITH_BACKGROUND, "black", "white"); + + if (g_getenv ("NMTUI_DEBUG")) + g_log_set_default_handler (nmt_newt_dialog_g_log_handler, NULL); + else + g_log_set_default_handler (nmt_newt_basic_g_log_handler, NULL); + + newtSetSuspendCallback (nmt_newt_suspend_callback, NULL); +} + +/** + * nmt_newt_finished: + * + * Wrapper for newtFinished(). Should be called at the end of the program. + */ +void +nmt_newt_finished (void) +{ + newtFinished (); + g_log_set_default_handler (g_log_default_handler, NULL); +} + +/** + * nmt_newt_message_dialog: + * @message: a printf()-style message format + * @...: arguments + * + * Displays the given message in a dialog box with a single "OK" + * button, and returns after the user clicks "OK". + */ +void +nmt_newt_message_dialog (const char *message, + ...) +{ + va_list ap; + char *msg, *msg_lc, *ok_lc; + + va_start (ap, message); + msg = g_strdup_vprintf (message, ap); + va_end (ap); + + msg_lc = nmt_newt_locale_from_utf8 (msg); + ok_lc = nmt_newt_locale_from_utf8 (_("OK")); + newtWinMessage (NULL, ok_lc, "%s", msg_lc); + + g_free (ok_lc); + g_free (msg_lc); + g_free (msg); +} + +/** + * nmt_newt_choice_dialog: + * @button1: the label for the first button + * @button2: the label for the second button + * @message: a printf()-style message format + * @...: arguments + * + * Displays the given message in a dialog box with two buttons with + * the indicated labels, and waits for the user to click one. + * + * Returns: which button was clicked: 0 for @button1 or 1 for @button2 + */ +int +nmt_newt_choice_dialog (const char *button1, + const char *button2, + const char *message, + ...) +{ + va_list ap; + char *msg, *msg_lc, *button1_lc, *button2_lc; + int choice; + + va_start (ap, message); + msg = g_strdup_vprintf (message, ap); + va_end (ap); + + msg_lc = nmt_newt_locale_from_utf8 (msg); + button1_lc = nmt_newt_locale_from_utf8 (button1); + button2_lc = nmt_newt_locale_from_utf8 (button2); + choice = newtWinChoice (NULL, button1_lc, button2_lc, "%s", msg_lc); + + g_free (button1_lc); + g_free (button2_lc); + g_free (msg_lc); + g_free (msg); + + return choice; +} + +/** + * nmt_newt_locale_to_utf8: + * @str_lc: a string in the user's locale encoding + * + * Convenience wrapper around g_locale_to_utf8(). + * + * Note that libnewt works in terms of the user's locale character + * set, NOT UTF-8, so all strings received from libnewt must be + * converted back to UTF-8 before being returned to the caller or used + * in other APIs. + * + * Returns: @str_lc, converted to UTF-8. + */ +char * +nmt_newt_locale_to_utf8 (const char *str_lc) +{ + char *str_utf8; + + str_utf8 = g_locale_to_utf8 (str_lc, -1, NULL, NULL, NULL); + if (!str_utf8) + str_utf8 = g_strdup (""); + return str_utf8; +} + +/** + * nmt_newt_locale_from_utf8: + * @str_utf8: a UTF-8 string + * + * Convenience wrapper around g_locale_from_utf8(). + * + * Note that libnewt works in terms of the user's locale character + * set, NOT UTF-8, so all strings from nmt-newt must be converted to + * locale encoding before being passed to libnewt. + * + * Returns: @str_utf8, converted to the user's locale encoding. + */ +char * +nmt_newt_locale_from_utf8 (const char *str_utf8) +{ + char *str_lc; + + str_lc = g_locale_from_utf8 (str_utf8, -1, NULL, NULL, NULL); + if (!str_lc) + str_lc = g_strdup (""); + return str_lc; +} + +/** + * nmt_newt_text_width + * @str: a UTF-8 string + * + * Computes the width (in terminal columns) of @str. + * + * Returns: the width of @str + */ +int +nmt_newt_text_width (const char *str) +{ + int width; + gunichar ch; + + for (width = 0; *str; str = g_utf8_next_char (str)) { + ch = g_utf8_get_char (str); + + /* Based on _vte_iso2022_unichar_width */ + if (G_LIKELY (ch < 0x80)) + width += 1; + else if (G_UNLIKELY (g_unichar_iszerowidth (ch))) + width += 0; + else if (G_UNLIKELY (g_unichar_iswide (ch))) + width += 2; + else + width += 1; + } + + return width; +} + +/** + * nmt_newt_edit_string: + * @data: data to edit + * + * libnewt does not have a multi-line editable text component, so + * nmt-newt provides this function instead, which will open the user's + * editor to edit a file containing the given @data (ensuring that the + * current screen state is saved before starting the editor and + * restored after it returns). + * + * Returns: the edited data, or %NULL if an error occurred. + */ +char * +nmt_newt_edit_string (const char *data) +{ + gssize len, nwrote; + char *filename, *argv[3]; + GError *error = NULL; + int fd, status; + char *new_data = NULL; + + fd = g_file_open_tmp ("XXXXXX.json", &filename, &error); + if (fd == -1) { + nmt_newt_message_dialog (_("Could not create temporary file: %s"), error->message); + g_error_free (error); + return NULL; + } + + len = data ? strlen (data) : 0; + while (len) { + do + nwrote = write (fd, data, len); + while (nwrote == -1 && errno == EINTR); + + len -= nwrote; + data += nwrote; + } + close (fd); + + argv[0] = (char *) g_getenv ("VISUAL"); + if (!argv[0]) + argv[0] = (char *) g_getenv ("EDITOR"); + if (!argv[0]) + argv[0] = (char *) "vi"; + argv[1] = filename; + argv[2] = NULL; + + newtSuspend (); + g_spawn_sync (NULL, argv, NULL, + G_SPAWN_SEARCH_PATH | G_SPAWN_CHILD_INHERITS_STDIN, + NULL, NULL, NULL, NULL, + &status, &error); + newtResume (); + + if (error) { + nmt_newt_message_dialog (_("Could not create temporary file: %s"), error->message); + g_error_free (error); + goto done; + } + +#if GLIB_CHECK_VERSION (2, 34, 0) + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + if (!g_spawn_check_exit_status (status, &error)) { + nmt_newt_message_dialog (_("Editor failed: %s"), error->message); + g_error_free (error); + goto done; + } + G_GNUC_END_IGNORE_DEPRECATIONS +#else + if (WIFEXITED (status)) { + if (WEXITSTATUS (status) != 0) + nmt_newt_message_dialog (_("Editor failed with status %d"), WEXITSTATUS (status)); + } else if (WIFSIGNALED (status)) + nmt_newt_message_dialog (_("Editor failed with signal %d"), WTERMSIG (status)); +#endif + + if (!g_file_get_contents (filename, &new_data, NULL, &error)) { + nmt_newt_message_dialog (_("Could not re-read file: %s"), error->message); + g_error_free (error); + goto done; + } + + done: + unlink (filename); + g_free (filename); + + return new_data; +} + diff --git a/clients/tui/newt/nmt-newt-utils.h b/clients/tui/newt/nmt-newt-utils.h new file mode 100644 index 00000000..3b37868a --- /dev/null +++ b/clients/tui/newt/nmt-newt-utils.h @@ -0,0 +1,53 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_UTILS_H +#define NMT_NEWT_UTILS_H + +#include <newt.h> +#include <glib.h> + +G_BEGIN_DECLS + +void nmt_newt_init (void); +void nmt_newt_finished (void); + +typedef enum { + NMT_NEWT_COLORSET_BAD_LABEL = NEWT_COLORSET_CUSTOM (0), + NMT_NEWT_COLORSET_PLAIN_LABEL, + NMT_NEWT_COLORSET_DISABLED_BUTTON, + NMT_NEWT_COLORSET_TEXTBOX_WITH_BACKGROUND +} NmtNewtColorsets; + +char *nmt_newt_locale_to_utf8 (const char *str_lc); +char *nmt_newt_locale_from_utf8 (const char *str_utf8); + +int nmt_newt_text_width (const char *str); + +void nmt_newt_message_dialog (const char *message, + ...); +int nmt_newt_choice_dialog (const char *button1, + const char *button2, + const char *message, + ...); + +char *nmt_newt_edit_string (const char *data); + +G_END_DECLS + +#endif /* NMT_NEWT_UTILS_H */ diff --git a/clients/tui/newt/nmt-newt-widget.c b/clients/tui/newt/nmt-newt-widget.c new file mode 100644 index 00000000..24c94db9 --- /dev/null +++ b/clients/tui/newt/nmt-newt-widget.c @@ -0,0 +1,668 @@ +/* -*- 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-widget + * @short_description: Base TUI Widget class + * + * #NmtNewtWidget is the abstract base class for nmt-newt. All widgets + * inherit from one of its two subclasses: #NmtNewtComponent, for + * widgets that wrap a (single) #newtComponent, and #NmtNewtContainer, + * for widgets consisting of multiple components. See those classes + * for more details. + * + * With the exception of #NmtNewtForm, all widgets start out with a + * floating reference, which will be sunk by the container they are + * added to. #NmtNewtForm is the "top-level" widget type, and so does + * not have a floating reference. + * + * FIXME: need RTL support + */ + +#include "config.h" + +#include "nmt-newt-widget.h" +#include "nmt-newt-form.h" + +G_DEFINE_ABSTRACT_TYPE (NmtNewtWidget, nmt_newt_widget, G_TYPE_INITIALLY_UNOWNED) + +#define NMT_NEWT_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_WIDGET, NmtNewtWidgetPrivate)) + +typedef struct { + NmtNewtWidget *parent; + gboolean visible, realized, valid; + gboolean exit_on_activate; + + int pad_left, pad_top, pad_right, pad_bottom; +} NmtNewtWidgetPrivate; + +enum { + PROP_0, + + PROP_PARENT, + PROP_VISIBLE, + PROP_VALID, + PROP_EXIT_ON_ACTIVATE, + + LAST_PROP +}; + +enum { + NEEDS_REBUILD, + ACTIVATED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void +nmt_newt_widget_init (NmtNewtWidget *widget) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + priv->visible = TRUE; + priv->valid = TRUE; +} + +static void +nmt_newt_widget_finalize (GObject *object) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (object); + + nmt_newt_widget_unrealize (NMT_NEWT_WIDGET (object)); + g_clear_object (&priv->parent); + + G_OBJECT_CLASS (nmt_newt_widget_parent_class)->finalize (object); +} + +/** + * nmt_newt_widget_realize: + * @widget: an #NmtNewtWidget + * + * "Realizes" @widget. That is, creates #newtComponents corresponding + * to @widget and its children. + * + * You should not need to call this yourself; an #NmtNewtForm will + * cause its children to be realized and unrealized as needed. + */ +void +nmt_newt_widget_realize (NmtNewtWidget *widget) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + if (!priv->realized) { + NMT_NEWT_WIDGET_GET_CLASS (widget)->realize (widget); + priv->realized = TRUE; + } +} + +/** + * nmt_newt_widget_unrealize: + * @widget: an #NmtNewtWidget + * + * "Unrealizes" @widget, destroying its #newtComponents. + * + * You should not need to call this yourself; an #NmtNewtForm will + * cause its children to be realized and unrealized as needed. + */ +void +nmt_newt_widget_unrealize (NmtNewtWidget *widget) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + if (priv->realized) { + NMT_NEWT_WIDGET_GET_CLASS (widget)->unrealize (widget); + priv->realized = FALSE; + } +} + +/** + * nmt_newt_widget_get_realized: + * @widget: an #NmtNewtWidget + * + * Checks if @widget is realized or not. + * + * Returns: whether @widget is realized. + */ +gboolean +nmt_newt_widget_get_realized (NmtNewtWidget *widget) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + return priv->realized; +} + +/** + * nmt_newt_widget_get_components: + * @widget: an #NmtNewtWidget + * + * Gets the #newtComponents that make up @widget, if @widget is + * visible. If @widget has not yet been realized, it will be realized + * first. + * + * If this function is called on a widget, then the widget will assume + * that someone else is now responsible for destroying the components, + * and so it will not destroy them itself when the widget is + * destroyed. Normally, components will end up being destroyed by the + * #NmtNewtForm they are added to. + * + * Returns: a %NULL-terminated array of components, in focus-chain + * order. You must free the array with g_free() when you are done + * with it. + */ +newtComponent * +nmt_newt_widget_get_components (NmtNewtWidget *widget) +{ + if (nmt_newt_widget_get_visible (widget)) { + nmt_newt_widget_realize (widget); + return NMT_NEWT_WIDGET_GET_CLASS (widget)->get_components (widget); + } else + return NULL; +} + +/** + * nmt_newt_widget_find_component: + * @widget: an #NmtNewtWidget + * @co: a #newtComponent + * + * Finds the widget inside @widget that owns @co. + * + * Return value: @co's owner, or %NULL if it was not found. + */ +NmtNewtWidget * +nmt_newt_widget_find_component (NmtNewtWidget *widget, + newtComponent co) +{ + return NMT_NEWT_WIDGET_GET_CLASS (widget)->find_component (widget, co); +} + +/** + * nmt_newt_widget_set_padding: + * @widget: an #NmtNewtWidget + * @pad_left: padding on the left of @widget + * @pad_top: padding on the top of @widget + * @pad_right: padding on the right of @widget + * @pad_bottom: padding on the bottom of @widget + * + * Sets the padding on @widget. + */ +void +nmt_newt_widget_set_padding (NmtNewtWidget *widget, + int pad_left, + int pad_top, + int pad_right, + int pad_bottom) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + priv->pad_left = pad_left; + priv->pad_top = pad_top; + priv->pad_right = pad_right; + priv->pad_bottom = pad_bottom; +} + +/** + * nmt_newt_widget_size_request: + * @widget: an #NmtNewtWidget + * @width: (out): on output, the widget's requested width + * @height: (out): on output, the widget's requested height + * + * Asks @widget for its requested size. If @widget is not visible, + * this will return 0, 0. If @widget has not yet been realized, it + * will be realized first. + */ +void +nmt_newt_widget_size_request (NmtNewtWidget *widget, + int *width, + int *height) +{ + if (nmt_newt_widget_get_visible (widget)) { + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + nmt_newt_widget_realize (widget); + NMT_NEWT_WIDGET_GET_CLASS (widget)->size_request (widget, width, height); + + *width += priv->pad_left + priv->pad_right; + *height += priv->pad_top + priv->pad_bottom; + } else + *width = *height = 0; +} + +/** + * nmt_newt_widget_size_allocate: + * @widget: an #NmtNewtWidget + * @x: the widget's (absolute) X coordinate + * @y: the widget's (absolute) Y coordinate + * @width: the widget's allocated width + * @height: the widget's allocated height + * + * Positions @widget at the given coordinates, with the given size. If + * @widget is not visible, this has no effect. If @widget has not yet + * been realized, it will be realized first. + * + * @x and @y are absolute coordinates (ie, relative to the screen / + * terminal window, not relative to @widget's parent). + * + * In general, the results are undefined if @width or @height is less + * than the widget's requested size. If @width or @height is larger + * than the requested size, most #NmtNewtComponents will ignore the + * extra space, but some components and most containers will expand to + * fit. + */ +void +nmt_newt_widget_size_allocate (NmtNewtWidget *widget, + int x, + int y, + int width, + int height) +{ + if (nmt_newt_widget_get_visible (widget)) { + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + nmt_newt_widget_realize (widget); + x += priv->pad_left; + y += priv->pad_top; + width -= priv->pad_left + priv->pad_right; + height -= priv->pad_top + priv->pad_bottom; + + NMT_NEWT_WIDGET_GET_CLASS (widget)->size_allocate (widget, x, y, width, height); + } +} + +/** + * nmt_newt_widget_get_focus_component: + * @widget: an #NmtNewtWidget + * + * Gets the #newtComponent that should be given the keyboard focus when + * @widget is focused. + * + * Returns: the #newtComponent to focus, or %NULL if @widget can't + * take the focus. + */ +newtComponent +nmt_newt_widget_get_focus_component (NmtNewtWidget *widget) +{ + if (!NMT_NEWT_WIDGET_GET_CLASS (widget)->get_focus_component) + return NULL; + + return NMT_NEWT_WIDGET_GET_CLASS (widget)->get_focus_component (widget); +} + +static void +nmt_newt_widget_real_activated (NmtNewtWidget *widget) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + if (priv->exit_on_activate) + nmt_newt_form_quit (nmt_newt_widget_get_form (widget)); +} + +/** + * nmt_newt_widget_activated: + * @widget: an #NmtNewtWidget + * + * Tells @widget that its #newtComponent has been activated (ie, the + * user hit "Return" on it) and emits #NmtNewtWidget::activated. + * + * If #NmtNewtWidget:exit-on-activate is set on @widget, then this + * will call nmt_newt_form_quit() on the widget's form. + */ +void +nmt_newt_widget_activated (NmtNewtWidget *widget) +{ + g_signal_emit (widget, signals[ACTIVATED], 0); +} + +/** + * nmt_newt_widget_get_exit_on_activate: + * @widget: an #NmtNewtWidget + * + * Gets @widget's #NmtNewtWidget:exit-on-activate flag, qv. + * + * Returns: @widget's #NmtNewtWidget:exit-on-activate flag + */ +gboolean +nmt_newt_widget_get_exit_on_activate (NmtNewtWidget *widget) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + return priv->exit_on_activate; +} + +/** + * nmt_newt_widget_set_exit_on_activate: + * @widget: an #NmtNewtWidget + * @exit_on_activate: whether @widget should exit on activate. + * + * Sets @widget's #NmtNewtWidget:exit-on-activate flag, qv. + */ +void +nmt_newt_widget_set_exit_on_activate (NmtNewtWidget *widget, + gboolean exit_on_activate) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + exit_on_activate = !!exit_on_activate; + if (priv->exit_on_activate != exit_on_activate) { + priv->exit_on_activate = exit_on_activate; + g_object_notify (G_OBJECT (widget), "exit-on-activate"); + } +} + +/** + * nmt_newt_widget_get_visible: + * @widget: an #NmtNewtWidget + * + * Gets @widget's #NmtNewtWidget:visible flag, qv. + * + * Returns: @widget's #NmtNewtWidget:visible flag + */ +gboolean +nmt_newt_widget_get_visible (NmtNewtWidget *widget) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + return priv->visible; +} + +/** + * nmt_newt_widget_set_visible: + * @widget: an #NmtNewtWidget + * @visible: whether @widget should be visible + * + * Sets @widget's #NmtNewtWidget:visible flag, qv. + */ +void +nmt_newt_widget_set_visible (NmtNewtWidget *widget, + gboolean visible) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + visible = !!visible; + if (priv->visible != visible) { + priv->visible = visible; + g_object_notify (G_OBJECT (widget), "visible"); + nmt_newt_widget_needs_rebuild (widget); + } +} + +/** + * nmt_newt_widget_set_parent: + * @widget: an #NmtNewtWidget + * @parent: @widget's parent + * + * Sets @widget's parent to @parent. This is used internally by + * #NmtNewtContainer implementations; you must use an appropriate + * container-specific method to actually add a widget to a container. + */ +void +nmt_newt_widget_set_parent (NmtNewtWidget *widget, + NmtNewtWidget *parent) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + g_clear_object (&priv->parent); + priv->parent = parent ? g_object_ref (parent) : NULL; + g_object_notify (G_OBJECT (widget), "parent"); +} + +/** + * nmt_newt_widget_get_parent: + * @widget: an #NmtNewtWidget + * + * Gets @widget's parent + * + * Returns: @widget's parent + */ +NmtNewtWidget * +nmt_newt_widget_get_parent (NmtNewtWidget *widget) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + return priv->parent; +} + +/** + * nmt_newt_widget_get_form: + * @widget: an #NmtNewtWidget + * + * Gets @widget's top-level form. + * + * Returns: @widget's #NmtNewtForm + */ +NmtNewtForm * +nmt_newt_widget_get_form (NmtNewtWidget *widget) +{ + while (widget) { + if (NMT_IS_NEWT_FORM (widget)) + return NMT_NEWT_FORM (widget); + widget = nmt_newt_widget_get_parent (widget); + } + + return NULL; +} + +/** + * nmt_newt_widget_get_valid: + * @widget: an #NmtNewtWidget + * + * Gets @widget's #NmtNewtWidget:valid flag, indicating whether its + * content is valid. + * + * Returns: @widget's #NmtNewtWidget:valid flag + */ +gboolean +nmt_newt_widget_get_valid (NmtNewtWidget *widget) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + return priv->valid; +} + +/** + * nmt_newt_widget_set_valid: + * @widget: an #NmtNewtWidget + * @valid: whether @widget is valid + * + * Sets @widget's #NmtNewtWidget:valid flag, indicating whether its + * content is valid. + * + * This method should be considered "protected"; if you change it, the + * widget implementation will likely just change it back at some + * point. + */ +void +nmt_newt_widget_set_valid (NmtNewtWidget *widget, + gboolean valid) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + valid = !!valid; + if (priv->valid == valid) + return; + + priv->valid = valid; + g_object_notify (G_OBJECT (widget), "valid"); +} + +/** + * nmt_newt_widget_needs_rebuilds: + * @widget: an #NmtNewtWidget + * + * Marks @widget as needing to be "rebuilt" (ie, re-realized). This is + * called automatically in some cases (such as when adding a widget to + * or removing it from a container). #NmtNewtComponent implementations + * should also call this if they need to make some change that can + * only be done by destroying their current #newtComponent and + * creating a new one. + */ +void +nmt_newt_widget_needs_rebuild (NmtNewtWidget *widget) +{ + g_signal_emit (widget, signals[NEEDS_REBUILD], 0); +} + +static void +nmt_newt_widget_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtWidget *widget = NMT_NEWT_WIDGET (object); + + switch (prop_id) { + case PROP_PARENT: + nmt_newt_widget_set_parent (widget, g_value_get_object (value)); + break; + case PROP_VISIBLE: + nmt_newt_widget_set_visible (widget, g_value_get_boolean (value)); + break; + case PROP_EXIT_ON_ACTIVATE: + nmt_newt_widget_set_exit_on_activate (widget, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_widget_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_PARENT: + g_value_set_object (value, priv->parent); + break; + case PROP_VISIBLE: + g_value_set_boolean (value, priv->visible); + break; + case PROP_VALID: + g_value_set_boolean (value, priv->valid); + break; + case PROP_EXIT_ON_ACTIVATE: + g_value_set_boolean (value, priv->exit_on_activate); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_widget_class_init (NmtNewtWidgetClass *widget_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (widget_class); + + g_type_class_add_private (widget_class, sizeof (NmtNewtWidgetPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_widget_set_property; + object_class->get_property = nmt_newt_widget_get_property; + object_class->finalize = nmt_newt_widget_finalize; + + widget_class->activated = nmt_newt_widget_real_activated; + + /* signals */ + + /** + * NmtNewtWidget::needs-rebuild: + * @widget: the #NmtNewtWidget + * + * Emitted when nmt_newt_widget_need_rebuild() is called on @widget + * or any of its children. This signal propagates up the container + * hierarchy, eventually reaching the top-level #NmtNewtForm. + */ + signals[NEEDS_REBUILD] = + g_signal_new ("needs-rebuild", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NmtNewtWidgetClass, needs_rebuild), + NULL, NULL, NULL, + G_TYPE_NONE, 0); + + /** + * NmtNewtWidget::activated: + * @widget: the #NmtNewtWidget + * + * Emitted when the widget's #newtComponent is activated. + */ + signals[ACTIVATED] = + g_signal_new ("activated", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NmtNewtWidgetClass, activated), + NULL, NULL, NULL, + G_TYPE_NONE, 0); + + /* properties */ + + /** + * NmtNewtWidget:parent: + * + * The widget's parent widget, or %NULL if it has no parent. + */ + g_object_class_install_property + (object_class, PROP_PARENT, + g_param_spec_object ("parent", "", "", + NMT_TYPE_NEWT_WIDGET, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtWidget:visible: + * + * Whether the widget is visible. Invisible widgets do not get + * realized or sized. + */ + g_object_class_install_property + (object_class, PROP_VISIBLE, + g_param_spec_boolean ("visible", "", "", + TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtWidget:valid: + * + * Whether the widget's content is considered valid. Components + * determine their own validity. A container, by default, is + * considered valid if all of its children are valid. + */ + g_object_class_install_property + (object_class, PROP_VALID, + g_param_spec_boolean ("valid", "", "", + TRUE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtWidget:exit-on-activate: + * + * If %TRUE, the widget will call nmt_newt_form_quit() on its form + * when it is activated. + */ + g_object_class_install_property + (object_class, PROP_EXIT_ON_ACTIVATE, + g_param_spec_boolean ("exit-on-activate", "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/newt/nmt-newt-widget.h b/clients/tui/newt/nmt-newt-widget.h new file mode 100644 index 00000000..a526a674 --- /dev/null +++ b/clients/tui/newt/nmt-newt-widget.h @@ -0,0 +1,118 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_WIDGET_H +#define NMT_NEWT_WIDGET_H + +#include "nmt-newt-types.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_WIDGET (nmt_newt_widget_get_type ()) +#define NMT_NEWT_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_WIDGET, NmtNewtWidget)) +#define NMT_NEWT_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_WIDGET, NmtNewtWidgetClass)) +#define NMT_IS_NEWT_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_WIDGET)) +#define NMT_IS_NEWT_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_WIDGET)) +#define NMT_NEWT_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_WIDGET, NmtNewtWidgetClass)) + +struct _NmtNewtWidget { + GInitiallyUnowned parent; + +}; + +typedef struct { + GInitiallyUnownedClass parent; + + /* signals */ + void (*needs_rebuild) (NmtNewtWidget *widget); + void (*activated) (NmtNewtWidget *widget); + + /* methods */ + void (*realize) (NmtNewtWidget *widget); + void (*unrealize) (NmtNewtWidget *widget); + + newtComponent * (*get_components) (NmtNewtWidget *widget); + NmtNewtWidget * (*find_component) (NmtNewtWidget *widget, + newtComponent co); + + void (*size_request) (NmtNewtWidget *widget, + int *width, + int *height); + void (*size_allocate) (NmtNewtWidget *widget, + int x, + int y, + int width, + int height); + + newtComponent (*get_focus_component) (NmtNewtWidget *widget); + +} NmtNewtWidgetClass; + +GType nmt_newt_widget_get_type (void); + +void nmt_newt_widget_realize (NmtNewtWidget *widget); +void nmt_newt_widget_unrealize (NmtNewtWidget *widget); +gboolean nmt_newt_widget_get_realized (NmtNewtWidget *widget); + +newtComponent *nmt_newt_widget_get_components (NmtNewtWidget *widget); + +void nmt_newt_widget_set_padding (NmtNewtWidget *widget, + int pad_left, + int pad_top, + int pad_right, + int pad_bottom); + +void nmt_newt_widget_size_request (NmtNewtWidget *widget, + int *width, + int *height); +void nmt_newt_widget_size_allocate (NmtNewtWidget *widget, + int x, + int y, + int width, + int height); + +void nmt_newt_widget_set_parent (NmtNewtWidget *widget, + NmtNewtWidget *parent); +NmtNewtWidget *nmt_newt_widget_get_parent (NmtNewtWidget *widget); + +NmtNewtForm *nmt_newt_widget_get_form (NmtNewtWidget *widget); + +gboolean nmt_newt_widget_get_visible (NmtNewtWidget *widget); +void nmt_newt_widget_set_visible (NmtNewtWidget *widget, + gboolean visible); + +newtComponent nmt_newt_widget_get_focus_component (NmtNewtWidget *widget); + +void nmt_newt_widget_activated (NmtNewtWidget *widget); +gboolean nmt_newt_widget_get_exit_on_activate (NmtNewtWidget *widget); +void nmt_newt_widget_set_exit_on_activate (NmtNewtWidget *widget, + gboolean exit_on_activate); + +gboolean nmt_newt_widget_get_valid (NmtNewtWidget *widget); + +NmtNewtWidget *nmt_newt_widget_find_component (NmtNewtWidget *widget, + newtComponent co); + +/* protected */ +void nmt_newt_widget_needs_rebuild (NmtNewtWidget *widget); +void nmt_newt_widget_set_valid (NmtNewtWidget *widget, + gboolean valid); + +G_END_DECLS + +#endif /* NMT_NEWT_WIDGET_H */ diff --git a/clients/tui/newt/nmt-newt.h b/clients/tui/newt/nmt-newt.h new file mode 100644 index 00000000..6a9c8d9f --- /dev/null +++ b/clients/tui/newt/nmt-newt.h @@ -0,0 +1,39 @@ +/* -*- 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. + */ + +#ifndef NMT_NEWT_H +#define NMT_NEWT_H + +#include "nmt-newt-button.h" +#include "nmt-newt-button-box.h" +#include "nmt-newt-checkbox.h" +#include "nmt-newt-entry.h" +#include "nmt-newt-entry-numeric.h" +#include "nmt-newt-form.h" +#include "nmt-newt-grid.h" +#include "nmt-newt-label.h" +#include "nmt-newt-listbox.h" +#include "nmt-newt-popup.h" +#include "nmt-newt-section.h" +#include "nmt-newt-separator.h" +#include "nmt-newt-stack.h" +#include "nmt-newt-textbox.h" +#include "nmt-newt-toggle-button.h" +#include "nmt-newt-utils.h" + +#endif /* NMT_NEWT_H */ diff --git a/clients/tui/nm-editor-bindings.c b/clients/tui/nm-editor-bindings.c new file mode 100644 index 00000000..9218c31f --- /dev/null +++ b/clients/tui/nm-editor-bindings.c @@ -0,0 +1,1101 @@ +/* -*- 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:nm-editor-bindings + * @short_description: #GBinding-based NM connection editor helpers + * + * nm-editor-bindings contains helper functions to bind NMSettings objects + * to connection editing widgets. The goal is that this should eventually be + * shared between nmtui, nm-connection-editor, and gnome-control-center. + */ + +#include "config.h" + +#include <arpa/inet.h> +#include <netinet/in.h> +#include <stdlib.h> +#include <string.h> + +#include "nm-editor-bindings.h" +#include "nm-gvaluearray-compat.h" + +static void +value_transform_string_int (const GValue *src_value, + GValue *dest_value) +{ + long val; + char *end; + + val = strtol (g_value_get_string (src_value), &end, 10); + if (val < G_MININT || val > G_MAXINT || *end) + return; + + g_value_set_int (dest_value, (int) val); +} + +static void +value_transform_string_uint (const GValue *src_value, + GValue *dest_value) +{ + long val; + char *end; + + val = strtol (g_value_get_string (src_value), &end, 10); + if (val < 0 || val > G_MAXUINT || *end) + return; + + g_value_set_uint (dest_value, (gint) val); +} + +void +nm_editor_bindings_init (void) +{ + /* glib registers number -> string, but not string -> number */ + g_value_register_transform_func (G_TYPE_STRING, G_TYPE_INT, value_transform_string_int); + g_value_register_transform_func (G_TYPE_STRING, G_TYPE_UINT, value_transform_string_uint); +} + +static gboolean +parse_addr_prefix (const char *text, + int family, + char **addr, + guint32 *prefix) +{ + const char *slash; + char *addrstr, *end; + gboolean valid; + + slash = strchr (text, '/'); + + if (slash) + addrstr = g_strndup (text, slash - text); + else + addrstr = g_strdup (text); + valid = nm_utils_ipaddr_valid (family, addrstr); + + if (slash) { + *prefix = strtoul (slash + 1, &end, 10); + if ( *end + || *prefix == 0 + || (family == AF_INET && *prefix > 32) + || (family == AF_INET6 && *prefix > 128)) + valid = FALSE; + } else if (prefix) { + if (family == AF_INET) + *prefix = 32; + else + *prefix = 128; + } + + if (addr && valid) + *addr = addrstr; + else + g_free (addrstr); + return valid; +} + +static gboolean +ip_addresses_with_prefix_to_strv (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + GPtrArray *addrs; + NMIPAddress *addr; + const char *addrstr; + guint32 prefix; + char **strings; + int i; + + addrs = g_value_get_boxed (source_value); + strings = g_new0 (char *, addrs->len + 1); + + for (i = 0; i < addrs->len; i++) { + addr = addrs->pdata[i]; + addrstr = nm_ip_address_get_address (addr); + prefix = nm_ip_address_get_prefix (addr); + + if (addrstr) + strings[i] = g_strdup_printf ("%s/%d", addrstr, (int) prefix); + else + strings[i] = g_strdup (""); + } + + g_value_take_boxed (target_value, strings); + return TRUE; +} + +static gboolean +ip_addresses_with_prefix_from_strv (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + int family = GPOINTER_TO_INT (user_data); + char **strings; + GPtrArray *addrs; + NMIPAddress *addr; + char *addrstr; + guint32 prefix; + int i; + + strings = g_value_get_boxed (source_value); + /* Fetch the original property value, so as to preserve their extra attributes */ + g_object_get (g_binding_get_source (binding), + g_binding_get_source_property (binding), &addrs, + NULL); + + for (i = 0; strings[i]; i++) { + if (i >= addrs->len) { + if (family == AF_INET) + addr = nm_ip_address_new (AF_INET, "0.0.0.0", 32, NULL); + else + addr = nm_ip_address_new (AF_INET6, "::", 128, NULL); + g_ptr_array_add (addrs, addr); + } else + addr = addrs->pdata[i]; + + if (!parse_addr_prefix (strings[i], family, &addrstr, &prefix)) { + g_ptr_array_unref (addrs); + return FALSE; + } + + nm_ip_address_set_address (addr, addrstr); + nm_ip_address_set_prefix (addr, prefix); + g_free (addrstr); + } + + g_ptr_array_set_size (addrs, i); + g_value_take_boxed (target_value, addrs); + return TRUE; +} + +/** + * nm_editor_bind_ip_addresses_with_prefix_to_strv: + * @family: the IP address family + * @source: the source object (eg, an #NMSettingIP4Config) + * @source_property: the property on @source to bind (eg, + * %NM_SETTING_IP4_CONFIG_ADDRESSES) + * @target: the target object (eg, an #NmtAddressList) + * @target_property: the property on @target to bind + * (eg, "strings") + * @flags: %GBindingFlags + * + * Binds the #GPtrArray-of-#NMIPAddress property @source_property on @source to + * the %G_TYPE_STRV property @target_property on @target. + * + * Each #NMIPAddress in @source_property will be converted to a string of the + * form "ip.ad.dr.ess/prefix" or "ip:ad:dr:ess/prefix" in @target_property (and + * vice versa if %G_BINDING_BIDIRECTIONAL) is specified. + */ +void +nm_editor_bind_ip_addresses_with_prefix_to_strv (int family, + gpointer source, + const gchar *source_property, + gpointer target, + const gchar *target_property, + GBindingFlags flags) +{ + g_object_bind_property_full (source, source_property, + target, target_property, + flags, + ip_addresses_with_prefix_to_strv, + ip_addresses_with_prefix_from_strv, + GINT_TO_POINTER (family), NULL); +} + +static gboolean +ip_addresses_check_and_copy (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + int family = GPOINTER_TO_INT (user_data); + char **strings; + int i; + + strings = g_value_get_boxed (source_value); + + for (i = 0; strings[i]; i++) { + if (!nm_utils_ipaddr_valid (family, strings[i])) + return FALSE; + } + + g_value_set_boxed (target_value, strings); + return TRUE; +} + +/** + * nm_editor_bind_ip_addresses_to_strv: + * @family: the IP address family + * @source: the source object (eg, an #NMSettingIP4Config) + * @source_property: the property on @source to bind (eg, + * %NM_SETTING_IP4_CONFIG_DNS) + * @target: the target object (eg, an #NmtAddressList) + * @target_property: the property on @target to bind + * (eg, "strings") + * @flags: %GBindingFlags + * + * Binds the %G_TYPE_STRV property @source_property on @source to the + * %G_TYPE_STRV property @target_property on @target, verifying that + * each string is a valid address of type @family when copying. + */ +void +nm_editor_bind_ip_addresses_to_strv (int family, + gpointer source, + const gchar *source_property, + gpointer target, + const gchar *target_property, + GBindingFlags flags) +{ + g_object_bind_property_full (source, source_property, + target, target_property, + flags, + ip_addresses_check_and_copy, + ip_addresses_check_and_copy, + GINT_TO_POINTER (family), NULL); +} + +static gboolean +ip_gateway_to_string (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + g_value_set_string (target_value, g_value_get_string (source_value)); + return TRUE; +} + +static gboolean +ip_gateway_from_string (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + int family = GPOINTER_TO_INT (user_data); + const char *gateway; + + gateway = g_value_get_string (source_value); + if (gateway && !nm_utils_ipaddr_valid (family, gateway)) + gateway = NULL; + + g_value_set_string (target_value, gateway); + return TRUE; +} + +static gboolean +ip_addresses_to_gateway (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + GPtrArray *addrs; + + addrs = g_value_get_boxed (source_value); + if (addrs->len == 0) { + g_value_set_string (target_value, NULL); + return TRUE; + } else + return FALSE; +} + +static gboolean +ip_addresses_to_sensitivity (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + GPtrArray *addrs; + + addrs = g_value_get_boxed (source_value); + g_value_set_boolean (target_value, addrs->len != 0); + return TRUE; +} + +/** + * nm_editor_bind_ip_gateway_to_string: + * @family: the IP address family + * @source: the source #NMSettingIPConfig + * @target: the target object (eg, an #NmtIPEntry) + * @target_property: the property on @target to bind (eg, "text") + * @target_sensitive_property: the "sensitivity" property on @target to bind + * @flags: %GBindingFlags + * + * Binds the #NMSettingIPConfig:gateway property on @source to the + * %G_TYPE_STRING property @target_property and %G_TYPE_BOOLEAN property + * @target_sensitive_property on @target, also taking the + * #NMSettingIPConfig:addresses property on @source into account. + * + * In particular, if @source has no static IP addresses, then @target_property + * will be set to "" and @target_sensitive_property will be set to %FALSE. + * + * If @source has at least one static IP address, then + * @target_sensitive_property will be set to %TRUE, @target_property will be + * initialized from @source's #NMSettingIPConfig:gateway, and @source will be + * updated with the value of @target_property whenever it contains a valid IP + * address. + */ +void +nm_editor_bind_ip_gateway_to_string (int family, + NMSettingIPConfig *source, + gpointer target, + const gchar *target_property, + const gchar *target_sensitive_property, + GBindingFlags flags) +{ + g_object_bind_property_full (source, "gateway", + target, target_property, + flags, + ip_gateway_to_string, + ip_gateway_from_string, + GINT_TO_POINTER (family), NULL); + g_object_bind_property_full (source, "addresses", + source, "gateway", + (flags & G_BINDING_SYNC_CREATE), + ip_addresses_to_gateway, + NULL, + NULL, NULL); + g_object_bind_property_full (source, "addresses", + target, target_sensitive_property, + (flags & G_BINDING_SYNC_CREATE), + ip_addresses_to_sensitivity, + NULL, + NULL, NULL); +} + +static gboolean +ip_route_transform_to_dest_string (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + NMIPRoute *route; + const char *addrstr; + char *string; + + route = g_value_get_boxed (source_value); + if (route) + addrstr = nm_ip_route_get_dest (route); + else + addrstr = NULL; + + if (addrstr) { + string = g_strdup_printf ("%s/%d", addrstr, (int) nm_ip_route_get_prefix (route)); + g_value_take_string (target_value, string); + } else + g_value_set_string (target_value, ""); + return TRUE; +} + +static gboolean +ip_route_transform_to_next_hop_string (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + NMIPRoute *route; + const char *addrstr; + + route = g_value_get_boxed (source_value); + if (route) { + addrstr = nm_ip_route_get_next_hop (route); + if (!addrstr) + addrstr = ""; + } else + addrstr = ""; + + g_value_set_string (target_value, addrstr); + return TRUE; +} + +static gboolean +ip_route_transform_to_metric_string (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + NMIPRoute *route; + char *string; + + route = g_value_get_boxed (source_value); + if (route && nm_ip_route_get_dest (route) && nm_ip_route_get_metric (route) != -1) { + string = g_strdup_printf ("%lu", (gulong) nm_ip_route_get_metric (route)); + g_value_take_string (target_value, string); + } else + g_value_set_string (target_value, ""); + return TRUE; +} + +static gboolean +ip_route_transform_from_dest_string (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + int family = GPOINTER_TO_INT (user_data); + NMIPRoute *route; + const char *text; + char *addrstr; + guint32 prefix; + + text = g_value_get_string (source_value); + if (!parse_addr_prefix (text, family, &addrstr, &prefix)) + return FALSE; + + /* Fetch the original property value */ + g_object_get (g_binding_get_source (binding), + g_binding_get_source_property (binding), &route, + NULL); + + nm_ip_route_set_dest (route, addrstr); + nm_ip_route_set_prefix (route, prefix); + g_free (addrstr); + + g_value_take_boxed (target_value, route); + return TRUE; +} + +static gboolean +ip_route_transform_from_next_hop_string (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + int family = GPOINTER_TO_INT (user_data); + NMIPRoute *route; + const char *text; + + text = g_value_get_string (source_value); + if (*text) { + if (!nm_utils_ipaddr_valid (family, text)) + return FALSE; + } else + text = NULL; + + /* Fetch the original property value */ + g_object_get (g_binding_get_source (binding), + g_binding_get_source_property (binding), &route, + NULL); + + nm_ip_route_set_next_hop (route, text); + + g_value_take_boxed (target_value, route); + return TRUE; +} + +static gboolean +ip_route_transform_from_metric_string (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + NMIPRoute *route; + const char *text; + gint64 metric; + + text = g_value_get_string (source_value); + if (*text) + metric = strtoul (text, NULL, 10); + else + metric = -1; + + /* Fetch the original property value */ + g_object_get (g_binding_get_source (binding), + g_binding_get_source_property (binding), &route, + NULL); + + nm_ip_route_set_metric (route, metric); + + g_value_take_boxed (target_value, route); + return TRUE; +} + +/** + * nm_editor_bind_ip_route_to_strings: + * @family: the IP address family + * @source: the source object + * @source_property: the source property + * @dest_target: the target object for the route's destionation + * @dest_target_property: the property on @dest_target + * @next_hop_target: the target object for the route's next hop + * @next_hop_target_property: the property on @next_hop_target + * @metric_target: the target object for the route's metric + * @metric_target_property: the property on @metric_target + * @flags: %GBindingFlags + * + * Binds the #NMIPRoute-valued property @source_property on @source to the + * three indicated string-valued target properties (and vice versa if + * %G_BINDING_BIDIRECTIONAL is specified). + * + * @dest_target_property should be an "address/prefix" string, as with + * nm_editor_bind_ip4_addresses_with_prefix_to_strv(). @next_hop_target_property + * is a plain IP address, and @metric_target_property is a number. + */ +void +nm_editor_bind_ip_route_to_strings (int family, + gpointer source, + const gchar *source_property, + gpointer dest_target, + const gchar *dest_target_property, + gpointer next_hop_target, + const gchar *next_hop_target_property, + gpointer metric_target, + const gchar *metric_target_property, + GBindingFlags flags) +{ + g_object_bind_property_full (source, source_property, + dest_target, dest_target_property, + flags, + ip_route_transform_to_dest_string, + ip_route_transform_from_dest_string, + GINT_TO_POINTER (family), NULL); + g_object_bind_property_full (source, source_property, + next_hop_target, next_hop_target_property, + flags, + ip_route_transform_to_next_hop_string, + ip_route_transform_from_next_hop_string, + GINT_TO_POINTER (family), NULL); + g_object_bind_property_full (source, source_property, + metric_target, metric_target_property, + flags, + ip_route_transform_to_metric_string, + ip_route_transform_from_metric_string, + GINT_TO_POINTER (family), NULL); +} + +/* Wireless security method binding */ +typedef struct { + NMConnection *connection; + NMSettingWirelessSecurity *s_wsec; + gboolean s_wsec_in_use; + + GObject *target; + char *target_property; + + gboolean updating; +} NMEditorWirelessSecurityMethodBinding; + +static const char * +get_security_type (NMEditorWirelessSecurityMethodBinding *binding) +{ + const char *key_mgmt, *auth_alg; + + if (!binding->s_wsec_in_use) + return "none"; + + key_mgmt = nm_setting_wireless_security_get_key_mgmt (binding->s_wsec); + auth_alg = nm_setting_wireless_security_get_auth_alg (binding->s_wsec); + + /* No IEEE 802.1x */ + if (!strcmp (key_mgmt, "none")) { + NMWepKeyType wep_type = nm_setting_wireless_security_get_wep_key_type (binding->s_wsec); + + if (wep_type == NM_WEP_KEY_TYPE_KEY) + return "wep-key"; + else + return "wep-passphrase"; + } + + if (!strcmp (key_mgmt, "ieee8021x")) { + if (auth_alg && !strcmp (auth_alg, "leap")) + return "leap"; + return "dynamic-wep"; + } + + if ( !strcmp (key_mgmt, "wpa-none") + || !strcmp (key_mgmt, "wpa-psk")) + return "wpa-personal"; + + if (!strcmp (key_mgmt, "wpa-eap")) + return "wpa-enterprise"; + + return NULL; +} + +static void +wireless_security_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + NMEditorWirelessSecurityMethodBinding *binding = user_data; + + if (binding->updating) + return; + + binding->updating = TRUE; + g_object_set (binding->target, + binding->target_property, get_security_type (binding), + NULL); + binding->updating = FALSE; +} + +static void +wireless_connection_changed (NMConnection *connection, + gpointer user_data) +{ + NMEditorWirelessSecurityMethodBinding *binding = user_data; + NMSettingWirelessSecurity *s_wsec; + + if (binding->updating) + return; + + s_wsec = nm_connection_get_setting_wireless_security (connection); + if ( (s_wsec && binding->s_wsec_in_use) + || (!s_wsec && !binding->s_wsec_in_use)) + return; + + binding->s_wsec_in_use = !binding->s_wsec_in_use; + wireless_security_changed (NULL, NULL, binding); +} + +static void +wireless_security_target_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + NMEditorWirelessSecurityMethodBinding *binding = user_data; + char *method; + + if (binding->updating) + return; + + g_object_get (binding->target, + binding->target_property, &method, + NULL); + + binding->updating = TRUE; + + if (!strcmp (method, "none")) { + if (!binding->s_wsec_in_use) + return; + binding->s_wsec_in_use = FALSE; + nm_connection_remove_setting (binding->connection, NM_TYPE_SETTING_WIRELESS_SECURITY); + + binding->updating = FALSE; + return; + } + + if (!binding->s_wsec_in_use) { + binding->s_wsec_in_use = TRUE; + nm_connection_add_setting (binding->connection, NM_SETTING (binding->s_wsec)); + } + + if (!strcmp (method, "wep-key")) { + g_object_set (binding->s_wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", + NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_KEY, + NULL); + } else if (!strcmp (method, "wep-passphrase")) { + g_object_set (binding->s_wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", + NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_PASSPHRASE, + NULL); + } else if (!strcmp (method, "leap")) { + g_object_set (binding->s_wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap", + NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_UNKNOWN, + NULL); + } else if (!strcmp (method, "dynamic-wep")) { + g_object_set (binding->s_wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", + NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_UNKNOWN, + NULL); + } else if (!strcmp (method, "wpa-personal")) { + g_object_set (binding->s_wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, NULL, + NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_UNKNOWN, + NULL); + } else if (!strcmp (method, "wpa-enterprise")) { + g_object_set (binding->s_wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap", + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, NULL, + NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_UNKNOWN, + NULL); + } else + g_warn_if_reached (); + + binding->updating = FALSE; +} + +static void +wireless_security_target_destroyed (gpointer user_data, + GObject *ex_target) +{ + NMEditorWirelessSecurityMethodBinding *binding = user_data; + + g_signal_handlers_disconnect_by_func (binding->s_wsec, G_CALLBACK (wireless_security_changed), binding); + g_object_unref (binding->s_wsec); + g_object_unref (binding->connection); + + g_free (binding->target_property); + + g_slice_free (NMEditorWirelessSecurityMethodBinding, binding); +} + +/** + * nm_editor_bind_wireless_security_method: + * @connection: an #NMConnection + * @s_wsec: an #NMSettingWirelessSecurity + * @target: the target widget + * @target_property: the string-valued property on @target to bind + * @flags: %GBindingFlags + * + * Binds the wireless security method on @connection to + * @target_property on @target (and vice versa if + * %G_BINDING_BIDIRECTIONAL). + * + * @target_property will be of the values "none", "wpa-personal", + * "wpa-enterprise", "wep-key", "wep-passphrase", "dynamic-wep", or + * "leap". + * + * If binding bidirectionally, @s_wsec will be automatically added to + * or removed from @connection as needed when @target_property + * changes. + */ +void +nm_editor_bind_wireless_security_method (NMConnection *connection, + NMSettingWirelessSecurity *s_wsec, + gpointer target, + const char *target_property, + GBindingFlags flags) +{ + NMEditorWirelessSecurityMethodBinding *binding; + char *notify; + + binding = g_slice_new0 (NMEditorWirelessSecurityMethodBinding); + + binding->target = target; + binding->target_property = g_strdup (target_property); + if (flags & G_BINDING_BIDIRECTIONAL) { + notify = g_strdup_printf ("notify::%s", target_property); + g_signal_connect (target, notify, G_CALLBACK (wireless_security_target_changed), binding); + g_free (notify); + } + g_object_weak_ref (target, wireless_security_target_destroyed, binding); + + binding->connection = g_object_ref (connection); + g_signal_connect (connection, NM_CONNECTION_CHANGED, + G_CALLBACK (wireless_connection_changed), binding); + binding->s_wsec_in_use = (nm_connection_get_setting_wireless_security (connection) != NULL); + + binding->s_wsec = g_object_ref (s_wsec); + g_signal_connect (s_wsec, "notify::" NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, + G_CALLBACK (wireless_security_changed), binding); + g_signal_connect (s_wsec, "notify::" NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, + G_CALLBACK (wireless_security_changed), binding); + g_signal_connect (s_wsec, "notify::" NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, + G_CALLBACK (wireless_security_changed), binding); + + if (flags & G_BINDING_SYNC_CREATE) + wireless_security_changed (NULL, NULL, binding); +} + +/* WEP key binding */ + +typedef struct { + NMSettingWirelessSecurity *s_wsec; + GObject *entry, *key_selector; + char *entry_property, *key_selector_property; + + gboolean updating; +} NMEditorWepKeyBinding; + +static void +wep_key_setting_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + NMEditorWepKeyBinding *binding = user_data; + const char *key; + int index; + + if (binding->updating) + return; + + index = nm_setting_wireless_security_get_wep_tx_keyidx (binding->s_wsec); + key = nm_setting_wireless_security_get_wep_key (binding->s_wsec, index); + + binding->updating = TRUE; + g_object_set (binding->key_selector, + binding->key_selector_property, index, + NULL); + g_object_set (binding->entry, + binding->entry_property, key, + NULL); + binding->updating = FALSE; +} + +static void +wep_key_ui_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + NMEditorWepKeyBinding *binding = user_data; + char *key; + int index; + + if (binding->updating) + return; + + g_object_get (binding->key_selector, + binding->key_selector_property, &index, + NULL); + g_object_get (binding->entry, + binding->entry_property, &key, + NULL); + + binding->updating = TRUE; + g_object_set (binding->s_wsec, + NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, index, + NM_SETTING_WIRELESS_SECURITY_WEP_KEY0, index == 0 ? key : NULL, + NM_SETTING_WIRELESS_SECURITY_WEP_KEY1, index == 1 ? key : NULL, + NM_SETTING_WIRELESS_SECURITY_WEP_KEY2, index == 2 ? key : NULL, + NM_SETTING_WIRELESS_SECURITY_WEP_KEY3, index == 3 ? key : NULL, + NULL); + binding->updating = FALSE; + + g_free (key); +} + +static void +wep_key_target_destroyed (gpointer user_data, + GObject *ex_target) +{ + NMEditorWepKeyBinding *binding = user_data; + + g_signal_handlers_disconnect_by_func (binding->s_wsec, G_CALLBACK (wep_key_setting_changed), binding); + + if (ex_target != binding->entry) { + g_signal_handlers_disconnect_by_func (binding->entry, G_CALLBACK (wep_key_ui_changed), binding); + g_object_weak_unref (binding->entry, wep_key_target_destroyed, binding); + } else { + g_signal_handlers_disconnect_by_func (binding->key_selector, G_CALLBACK (wep_key_ui_changed), binding); + g_object_weak_unref (binding->key_selector, wep_key_target_destroyed, binding); + } + + g_object_unref (binding->s_wsec); + g_free (binding->entry_property); + g_free (binding->key_selector_property); + + g_slice_free (NMEditorWepKeyBinding, binding); +} + +/** + * nm_editor_bind_wireless_security_wep_key: + * @s_wsec: an #NMSettingWirelessSecurity + * @entry: an entry widget + * @entry_property: the string-valued property on @entry to bind + * @key_selector: a pop-up widget of some sort + * @key_selector_property: the integer-valued property on + * @key_selector to bind + * @flags: %GBindingFlags + * + * Binds the "wep-tx-keyidx" property on @s_wsec to + * @key_selector_property on @key_selector, and the corresponding + * "wep-keyN" property to @entry_property on @entry (and vice versa if + * %G_BINDING_BIDIRECTIONAL). + */ +void +nm_editor_bind_wireless_security_wep_key (NMSettingWirelessSecurity *s_wsec, + gpointer entry, + const char *entry_property, + gpointer key_selector, + const char *key_selector_property, + GBindingFlags flags) +{ + NMEditorWepKeyBinding *binding; + char *notify; + + binding = g_slice_new0 (NMEditorWepKeyBinding); + binding->s_wsec = g_object_ref (s_wsec); + binding->entry = entry; + binding->entry_property = g_strdup (entry_property); + binding->key_selector = key_selector; + binding->key_selector_property = g_strdup (key_selector_property); + + g_signal_connect (s_wsec, "notify::" NM_SETTING_WIRELESS_SECURITY_WEP_KEY0, + G_CALLBACK (wep_key_setting_changed), binding); + g_signal_connect (s_wsec, "notify::" NM_SETTING_WIRELESS_SECURITY_WEP_KEY1, + G_CALLBACK (wep_key_setting_changed), binding); + g_signal_connect (s_wsec, "notify::" NM_SETTING_WIRELESS_SECURITY_WEP_KEY2, + G_CALLBACK (wep_key_setting_changed), binding); + g_signal_connect (s_wsec, "notify::" NM_SETTING_WIRELESS_SECURITY_WEP_KEY3, + G_CALLBACK (wep_key_setting_changed), binding); + + g_signal_connect (s_wsec, "notify::" NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, + G_CALLBACK (wep_key_setting_changed), binding); + + if (flags & G_BINDING_BIDIRECTIONAL) { + notify = g_strdup_printf ("notify::%s", entry_property); + g_signal_connect (entry, notify, G_CALLBACK (wep_key_ui_changed), binding); + g_free (notify); + + notify = g_strdup_printf ("notify::%s", key_selector_property); + g_signal_connect (key_selector, notify, G_CALLBACK (wep_key_ui_changed), binding); + g_free (notify); + } + + g_object_weak_ref (entry, wep_key_target_destroyed, binding); + g_object_weak_ref (key_selector, wep_key_target_destroyed, binding); + + if (flags & G_BINDING_SYNC_CREATE) + wep_key_setting_changed (NULL, NULL, binding); +} + +/* VLAN binding */ + +typedef struct { + NMSettingVlan *s_vlan; + NMSettingConnection *s_con; + + char *last_ifname_parent; + int last_ifname_id; + + gboolean updating; +} NMEditorVlanWidgetBinding; + +static gboolean +parse_interface_name (const char *ifname, + char **parent_ifname, + int *id) +{ + const char *ifname_end; + char *end; + + if (!ifname || !*ifname) + return FALSE; + + if (g_str_has_prefix (ifname, "vlan")) { + ifname_end = ifname + 4; + *id = strtoul (ifname_end, &end, 10); + if (*end || end == (char *)ifname_end || *id < 0) + return FALSE; + *parent_ifname = NULL; + return TRUE; + } + + ifname_end = strchr (ifname, '.'); + if (ifname_end) { + *id = strtoul (ifname_end + 1, &end, 10); + if (*end || end == (char *)ifname_end + 1 || *id < 0) + return FALSE; + *parent_ifname = g_strndup (ifname, ifname_end - ifname); + return TRUE; + } + + return FALSE; +} + +static void +vlan_settings_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + NMEditorVlanWidgetBinding *binding = user_data; + const char *ifname, *parent; + char *ifname_parent; + int ifname_id, id; + + if (binding->updating) + return; + + ifname = nm_setting_connection_get_interface_name (binding->s_con); + parent = nm_setting_vlan_get_parent (binding->s_vlan); + id = nm_setting_vlan_get_id (binding->s_vlan); + + if (!parse_interface_name (ifname, &ifname_parent, &ifname_id)) + return; + + /* If the id in INTERFACE_NAME changed, and ID is either unset, or was previously + * in sync with INTERFACE_NAME, then update ID. + */ + if ( id != ifname_id + && (id == binding->last_ifname_id || id == 0)) { + binding->updating = TRUE; + g_object_set (G_OBJECT (binding->s_vlan), + NM_SETTING_VLAN_ID, ifname_id, + NULL); + binding->updating = FALSE; + } + + /* If the PARENT in INTERFACE_NAME changed, and PARENT is either unset, or was + * previously in sync with INTERFACE_NAME, then update PARENT. + */ + if ( g_strcmp0 (parent, ifname_parent) != 0 + && ( g_strcmp0 (parent, binding->last_ifname_parent) == 0 + || !parent || !*parent)) { + binding->updating = TRUE; + g_object_set (G_OBJECT (binding->s_vlan), + NM_SETTING_VLAN_PARENT, ifname_parent, + NULL); + binding->updating = FALSE; + } + + g_free (binding->last_ifname_parent); + binding->last_ifname_parent = ifname_parent; + binding->last_ifname_id = ifname_id; +} + +static void +vlan_target_destroyed (gpointer user_data, + GObject *ex_target) +{ + NMEditorVlanWidgetBinding *binding = user_data; + + g_free (binding->last_ifname_parent); + g_slice_free (NMEditorVlanWidgetBinding, binding); +} + +/** + * nm_editor_bind_vlan_name: + * @s_vlan: an #NMSettingVlan + * + * Binds together several properties on @s_vlan, so that if the + * %NM_SETTING_VLAN_INTERFACE_NAME matches %NM_SETTING_VLAN_PARENT + * and %NM_SETTING_VLAN_ID in the obvious way, then changes to + * %NM_SETTING_VLAN_INTERFACE_NAME will propagate to the other + * two properties automatically. + */ +void +nm_editor_bind_vlan_name (NMSettingVlan *s_vlan, + NMSettingConnection *s_con) +{ + NMEditorVlanWidgetBinding *binding; + const char *ifname; + + binding = g_slice_new0 (NMEditorVlanWidgetBinding); + binding->s_vlan = s_vlan; + binding->s_con = s_con; + + g_signal_connect (s_con, "notify::" NM_SETTING_CONNECTION_INTERFACE_NAME, + G_CALLBACK (vlan_settings_changed), binding); + + g_object_weak_ref (G_OBJECT (s_vlan), vlan_target_destroyed, binding); + + ifname = nm_setting_connection_get_interface_name (s_con); + if (!parse_interface_name (ifname, &binding->last_ifname_parent, &binding->last_ifname_id)) { + binding->last_ifname_parent = NULL; + binding->last_ifname_id = 0; + } +} diff --git a/clients/tui/nm-editor-bindings.h b/clients/tui/nm-editor-bindings.h new file mode 100644 index 00000000..c4ed95d5 --- /dev/null +++ b/clients/tui/nm-editor-bindings.h @@ -0,0 +1,76 @@ +/* -*- 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. + */ + +#ifndef NM_EDITOR_BINDINGS_H +#define NM_EDITOR_BINDINGS_H + +#include <NetworkManager.h> + +G_BEGIN_DECLS + +void nm_editor_bindings_init (void); + +void nm_editor_bind_ip_addresses_with_prefix_to_strv (int family, + gpointer source, + const gchar *source_property, + gpointer target, + const gchar *target_property, + GBindingFlags flags); +void nm_editor_bind_ip_addresses_to_strv (int family, + gpointer source, + const gchar *source_property, + gpointer target, + const gchar *target_property, + GBindingFlags flags); + +void nm_editor_bind_ip_gateway_to_string (int family, + NMSettingIPConfig *source, + gpointer target, + const gchar *target_property, + const gchar *target_sensitive_property, + GBindingFlags flags); + +void nm_editor_bind_ip_route_to_strings (int family, + gpointer source, + const gchar *source_property, + gpointer dest_target, + const gchar *dest_target_property, + gpointer next_hop_target, + const gchar *next_hop_target_property, + gpointer metric_target, + const gchar *metric_target_property, + GBindingFlags flags); + +void nm_editor_bind_wireless_security_method (NMConnection *connection, + NMSettingWirelessSecurity *s_wsec, + gpointer target, + const char *target_property, + GBindingFlags flags); +void nm_editor_bind_wireless_security_wep_key (NMSettingWirelessSecurity *s_wsec, + gpointer entry, + const char *entry_property, + gpointer key_selector, + const char *key_selector_property, + GBindingFlags flags); + +void nm_editor_bind_vlan_name (NMSettingVlan *s_vlan, + NMSettingConnection *s_con); + +G_END_DECLS + +#endif /* NM_EDITOR_BINDINGS_H */ diff --git a/clients/tui/nm-editor-utils.c b/clients/tui/nm-editor-utils.c new file mode 100644 index 00000000..f936c959 --- /dev/null +++ b/clients/tui/nm-editor-utils.c @@ -0,0 +1,414 @@ +/* -*- 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 2012, 2013 Red Hat, Inc. + */ + +/** + * SECTION:nm-editor-utils + * @short_description: Miscellaneous connection editor utilities + * + * nm-editor-utils contains helper functions for connection editors. + * The goal is that this should eventually be shared between nmtui, + * nm-connection-editor, and gnome-control-center. + */ + +#include "config.h" + +#include <glib/gi18n.h> +#include <NetworkManager.h> + +#include "nm-editor-utils.h" +#if 0 +#include "vpn-helpers.h" + +static GSList *vpn_plugins; + +static gint +sort_vpn_plugins (gconstpointer a, gconstpointer b) +{ + NMVpnPluginUiInterface *aa = NM_VPN_PLUGIN_UI_INTERFACE (a); + NMVpnPluginUiInterface *bb = NM_VPN_PLUGIN_UI_INTERFACE (b); + char *aa_desc = NULL, *bb_desc = NULL; + int ret; + + g_object_get (aa, NM_VPN_PLUGIN_UI_INTERFACE_NAME, &aa_desc, NULL); + g_object_get (bb, NM_VPN_PLUGIN_UI_INTERFACE_NAME, &bb_desc, NULL); + + ret = g_strcmp0 (aa_desc, bb_desc); + + g_free (aa_desc); + g_free (bb_desc); + + return ret; +} +#endif + +static void +wifi_connection_setup_func (NMConnection *connection, + NMSettingConnection *s_con, + NMSetting *s_hw) +{ + g_object_set (G_OBJECT (s_hw), + NM_SETTING_WIRELESS_MODE, NM_SETTING_WIRELESS_MODE_INFRA, + NULL); +} + +static void +bond_connection_setup_func (NMConnection *connection, + NMSettingConnection *s_con, + NMSetting *s_hw) +{ + NMSettingBond *s_bond = NM_SETTING_BOND (s_hw); + const char **options, *def, *cur; + int i; + + options = nm_setting_bond_get_valid_options (s_bond); + for (i = 0; options[i]; i++) { + def = nm_setting_bond_get_option_default (s_bond, options[i]); + cur = nm_setting_bond_get_option_by_name (s_bond, options[i]); + if (g_strcmp0 (def, cur) != 0) + nm_setting_bond_add_option (s_bond, options[i], def); + } +} + +typedef void (*NMEditorNewConnectionSetupFunc) (NMConnection *connection, + NMSettingConnection *s_con, + NMSetting *s_hw); + +typedef struct { + NMEditorConnectionTypeData data; + + const char *id_format; + NMEditorNewConnectionSetupFunc connection_setup_func; + gboolean no_autoconnect; +} NMEditorConnectionTypeDataReal; + +static gint +sort_types (gconstpointer a, gconstpointer b) +{ + NMEditorConnectionTypeData *typea = *(NMEditorConnectionTypeData **)a; + NMEditorConnectionTypeData *typeb = *(NMEditorConnectionTypeData **)b; + + if (typea->virtual && !typeb->virtual) + return 1; + else if (typeb->virtual && !typea->virtual) + return -1; + + if (typea->setting_type == NM_TYPE_SETTING_VPN && + typeb->setting_type != NM_TYPE_SETTING_VPN) + return 1; + else if (typeb->setting_type == NM_TYPE_SETTING_VPN && + typea->setting_type != NM_TYPE_SETTING_VPN) + return -1; + + return g_utf8_collate (typea->name, typeb->name); +} + +/** + * nm_editor_utils_get_connection_type_list: + * + * Gets an array of information about supported connection types. The + * array is sorted in a standard presentation order (hardware types + * first, alphabetized, then virtual types, alphabetized, then VPN + * types, alphabetized). + * + * Returns: the array of connection type information + */ +NMEditorConnectionTypeData ** +nm_editor_utils_get_connection_type_list (void) +{ + GPtrArray *array; + NMEditorConnectionTypeDataReal *item; + static NMEditorConnectionTypeData **list; +#if 0 + GHashTable *vpn_plugins_hash; + gboolean have_vpn_plugins; +#endif + + if (list) + return list; + + array = g_ptr_array_new (); + + item = g_new0 (NMEditorConnectionTypeDataReal, 1); + item->data.name = _("Ethernet"); + item->data.setting_type = NM_TYPE_SETTING_WIRED; + item->data.device_type = NM_TYPE_DEVICE_ETHERNET; + item->data.virtual = FALSE; + item->id_format = _("Ethernet connection %d"); + g_ptr_array_add (array, item); + + item = g_new0 (NMEditorConnectionTypeDataReal, 1); + item->data.name = _("Wi-Fi"); + item->data.setting_type = NM_TYPE_SETTING_WIRELESS; + item->data.device_type = NM_TYPE_DEVICE_WIFI; + item->data.virtual = FALSE; + item->id_format = _("Wi-Fi connection %d"); + item->connection_setup_func = wifi_connection_setup_func; + g_ptr_array_add (array, item); + + item = g_new0 (NMEditorConnectionTypeDataReal, 1); + item->data.name = _("InfiniBand"); + item->data.setting_type = NM_TYPE_SETTING_INFINIBAND; + item->data.device_type = NM_TYPE_DEVICE_INFINIBAND; + item->data.virtual = FALSE; + item->id_format = _("InfiniBand connection %d"); + g_ptr_array_add (array, item); + +#if 0 + item = g_new0 (NMEditorConnectionTypeDataReal, 1); + item->data.name = _("Mobile Broadband"); + item->data.setting_type = NM_TYPE_SETTING_GSM; + item->data.virtual = FALSE; + item->id_format = _("Mobile broadband connection %d"); + item->no_autoconnect = TRUE; + g_ptr_array_add (array, item); +#endif + + item = g_new0 (NMEditorConnectionTypeDataReal, 1); + item->data.name = _("DSL"); + item->data.setting_type = NM_TYPE_SETTING_PPPOE; + item->data.device_type = NM_TYPE_DEVICE_ETHERNET; + item->data.virtual = FALSE; + item->id_format = _("DSL connection %d"); + item->no_autoconnect = TRUE; + g_ptr_array_add (array, item); + + item = g_new0 (NMEditorConnectionTypeDataReal, 1); + item->data.name = _("Bond"); + item->data.setting_type = NM_TYPE_SETTING_BOND; + item->data.device_type = NM_TYPE_DEVICE_BOND; + item->data.virtual = TRUE; + item->id_format = _("Bond connection %d"); + item->connection_setup_func = bond_connection_setup_func; + g_ptr_array_add (array, item); + + item = g_new0 (NMEditorConnectionTypeDataReal, 1); + item->data.name = _("Bridge"); + item->data.setting_type = NM_TYPE_SETTING_BRIDGE; + item->data.slave_setting_type = NM_TYPE_SETTING_BRIDGE_PORT; + item->data.device_type = NM_TYPE_DEVICE_BRIDGE; + item->data.virtual = TRUE; + item->id_format = _("Bridge connection %d"); + g_ptr_array_add (array, item); + + item = g_new0 (NMEditorConnectionTypeDataReal, 1); + item->data.name = _("Team"); + item->data.setting_type = NM_TYPE_SETTING_TEAM; + item->data.slave_setting_type = NM_TYPE_SETTING_TEAM_PORT; + item->data.device_type = NM_TYPE_DEVICE_TEAM; + item->data.virtual = TRUE; + item->id_format = _("Team connection %d"); + g_ptr_array_add (array, item); + + item = g_new0 (NMEditorConnectionTypeDataReal, 1); + item->data.name = _("VLAN"); + item->data.setting_type = NM_TYPE_SETTING_VLAN; + item->data.device_type = NM_TYPE_DEVICE_VLAN; + item->data.virtual = TRUE; + item->id_format = _("VLAN connection %d"); + g_ptr_array_add (array, item); + +#if 0 + /* Add "VPN" only if there are plugins */ + vpn_plugins_hash = vpn_get_plugins (NULL); + have_vpn_plugins = vpn_plugins_hash && g_hash_table_size (vpn_plugins_hash); + if (have_vpn_plugins) { + GHashTableIter iter; + gpointer name, plugin; + + item = g_new0 (NMEditorConnectionTypeDataReal, 1); + item->data.name = _("VPN"); + item->data.setting_type = NM_TYPE_SETTING_VPN; + item->data.virtual = TRUE; + item->id_format = _("VPN connection %d"); + item->no_autoconnect = TRUE; + g_ptr_array_add (array, item); + + vpn_plugins = NULL; + g_hash_table_iter_init (&iter, vpn_plugins_hash); + while (g_hash_table_iter_next (&iter, &name, &plugin)) + vpn_plugins = g_slist_prepend (vpn_plugins, plugin); + vpn_plugins = g_slist_sort (vpn_plugins, sort_vpn_plugins); + } +#endif + + g_ptr_array_sort (array, sort_types); + g_ptr_array_add (array, NULL); + + list = (NMEditorConnectionTypeData **)g_ptr_array_free (array, FALSE); + return list; +} + +static char * +get_available_connection_name (const char *format, + NMClient *client) +{ + const GPtrArray *conns; + GSList *names = NULL, *iter; + char *cname = NULL; + int i = 0; + + conns = nm_client_get_connections (client); + for (i = 0; i < conns->len; i++) { + const char *id; + + id = nm_connection_get_id (NM_CONNECTION (conns->pdata[i])); + g_assert (id); + names = g_slist_append (names, (gpointer) id); + } + + /* Find the next available unique connection name */ + for (i = 1; !cname && i < 10000; i++) { + char *temp; + gboolean found = FALSE; + + temp = g_strdup_printf (format, i); + for (iter = names; iter; iter = g_slist_next (iter)) { + if (!strcmp (iter->data, temp)) { + found = TRUE; + break; + } + } + if (!found) + cname = temp; + else + g_free (temp); + } + + g_slist_free (names); + return cname; +} + +/** + * nm_editor_utils_create_connection: + * @type: the type of the connection's primary #NMSetting + * @master: (allow-none): the connection's master, if any + * @client: an #NMClient + * + * Creates a new #NMConnection of the given type, automatically + * creating a UUID and an appropriate not-currently-in-use connection + * name, setting #NMSettingConnection:autoconnect appropriately for + * the connection type, filling in slave-related information if + * @master is not %NULL, and initializing any other mandatory-to-set + * properties to reasonable initial values. + * + * Returns: a new #NMConnection + */ +NMConnection * +nm_editor_utils_create_connection (GType type, + NMConnection *master, + NMClient *client) +{ + NMEditorConnectionTypeData **types; + NMEditorConnectionTypeDataReal *type_data = NULL; + const char *master_setting_type = NULL, *master_uuid = NULL; + GType master_type = G_TYPE_INVALID, slave_setting_type = G_TYPE_INVALID; + NMConnection *connection; + NMSettingConnection *s_con; + NMSetting *s_hw, *s_slave; + char *uuid, *id; + int i; + + if (master) { + NMSettingConnection *master_s_con; + + master_s_con = nm_connection_get_setting_connection (master); + master_setting_type = nm_setting_connection_get_connection_type (master_s_con); + master_uuid = nm_setting_connection_get_uuid (master_s_con); + master_type = nm_setting_lookup_type (master_setting_type); + } + + types = nm_editor_utils_get_connection_type_list (); + for (i = 0; types[i]; i++) { + if (types[i]->setting_type == type) + type_data = (NMEditorConnectionTypeDataReal *)types[i]; + if (types[i]->setting_type == master_type) + slave_setting_type = types[i]->slave_setting_type; + + } + if (!type_data) { + g_return_val_if_reached (NULL); + return NULL; + } + + connection = nm_simple_connection_new (); + + s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ()); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + + s_hw = g_object_new (type, NULL); + nm_connection_add_setting (connection, s_hw); + + if (slave_setting_type != G_TYPE_INVALID) { + s_slave = g_object_new (slave_setting_type, NULL); + nm_connection_add_setting (connection, s_slave); + } + + uuid = nm_utils_uuid_generate (); + id = get_available_connection_name (type_data->id_format, client); + + g_object_set (s_con, + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_ID, id, + NM_SETTING_CONNECTION_TYPE, nm_setting_get_name (s_hw), + NM_SETTING_CONNECTION_AUTOCONNECT, !type_data->no_autoconnect, + NM_SETTING_CONNECTION_MASTER, master_uuid, + NM_SETTING_CONNECTION_SLAVE_TYPE, master_setting_type, + NULL); + + g_free (uuid); + g_free (id); + + if (type_data->connection_setup_func) + type_data->connection_setup_func (connection, s_con, s_hw); + + return connection; +} + +/** + * nm_editor_utils_get_connection_type_data: + * @conn: an #NMConnection + * + * Gets the #NMEditorConnectionTypeData corresponding to + * @conn's connection type. + * + * Returns: the #NMEditorConnectionTypeData + */ +NMEditorConnectionTypeData * +nm_editor_utils_get_connection_type_data (NMConnection *conn) +{ + NMSettingConnection *s_con; + const char *conn_type; + GType conn_gtype; + NMEditorConnectionTypeData **types; + int i; + + s_con = nm_connection_get_setting_connection (conn); + g_return_val_if_fail (s_con != NULL, NULL); + + conn_type = nm_setting_connection_get_connection_type (s_con); + conn_gtype = nm_setting_lookup_type (conn_type); + g_return_val_if_fail (conn_gtype != G_TYPE_INVALID, NULL); + + types = nm_editor_utils_get_connection_type_list (); + for (i = 0; types[i]; i++) { + if (types[i]->setting_type == conn_gtype) + return types[i]; + } + + return NULL; +} diff --git a/clients/tui/nm-editor-utils.h b/clients/tui/nm-editor-utils.h new file mode 100644 index 00000000..5e402ce7 --- /dev/null +++ b/clients/tui/nm-editor-utils.h @@ -0,0 +1,43 @@ +/* -*- 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 2012, 2013 Red Hat, Inc. + */ + +#ifndef NM_EDITOR_UTILS_H +#define NM_EDITOR_UTILS_H + +#include <NetworkManager.h> + +G_BEGIN_DECLS + +typedef struct { + const char *name; + GType setting_type; + GType slave_setting_type; + GType device_type; + gboolean virtual; +} NMEditorConnectionTypeData; + +NMEditorConnectionTypeData **nm_editor_utils_get_connection_type_list (void); +NMEditorConnectionTypeData *nm_editor_utils_get_connection_type_data (NMConnection *conn); + +NMConnection *nm_editor_utils_create_connection (GType type, + NMConnection *master, + NMClient *client); + +G_END_DECLS + +#endif /* NM_EDITOR_UTILS_H */ diff --git a/clients/tui/nmt-address-list.c b/clients/tui/nmt-address-list.c new file mode 100644 index 00000000..42873c52 --- /dev/null +++ b/clients/tui/nmt-address-list.c @@ -0,0 +1,285 @@ +/* -*- 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-address-list + * @short_description: An editable list of IP addresses or hostnames + * + * #NmtAddressList is a subclass of #NmtWidgetList that contains + * entries displaying IP addresses, address/prefix strings, or + * hostnames. This is designed for binding its #NmtAddressList:strings + * property to an appropriate #NMSettingIP4Config or + * #NMSettingIP6Config property via one of the nm-editor-bindings + * functions. + */ + +#include "config.h" + +#include <arpa/inet.h> +#include <netinet/in.h> +#include <stdlib.h> +#include <string.h> + +#include <glib/gi18n-lib.h> + +#include "nmt-address-list.h" +#include "nmt-ip-entry.h" + +G_DEFINE_TYPE (NmtAddressList, nmt_address_list, NMT_TYPE_WIDGET_LIST) + +#define NMT_ADDRESS_LIST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_ADDRESS_LIST, NmtAddressListPrivate)) + +typedef struct { + NmtAddressListType list_type; + char **strings; +} NmtAddressListPrivate; + +enum { + PROP_0, + PROP_LIST_TYPE, + PROP_STRINGS, + + LAST_PROP +}; + +/** + * NmtAddressListType: + * @NMT_ADDRESS_LIST_IP4_WITH_PREFIX: IPv4 address/prefix strings + * @NMT_ADDRESS_LIST_IP4: IPv4 addresses + * @NMT_ADDRESS_LIST_IP6_WITH_PREFIX: IPv6 address/prefix strings + * @NMT_ADDRESS_LIST_IP6: IPv6 addresses + * @NMT_ADDRESS_LIST_HOSTNAME: hostnames + * + * The type of address in an #NmtAddressList + */ + +/** + * nmt_address_list_new: + * @list_type: the type of address the list will contain + * + * Creates a new #NmtAddressList + * + * Returns: a new #NmtAddressList + */ +NmtNewtWidget * +nmt_address_list_new (NmtAddressListType list_type) +{ + return g_object_new (NMT_TYPE_ADDRESS_LIST, + "list-type", list_type, + NULL); +} + +static void +nmt_address_list_init (NmtAddressList *list) +{ +} + +static gboolean +strings_transform_to_entry (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + int n = GPOINTER_TO_INT (user_data); + char **strings; + + strings = g_value_get_boxed (source_value); + if (n >= g_strv_length (strings)) + return FALSE; + + g_value_set_string (target_value, strings[n]); + return TRUE; +} + +static gboolean +strings_transform_from_entry (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + NmtAddressList *list = NMT_ADDRESS_LIST (g_binding_get_source (binding)); + NmtAddressListPrivate *priv = NMT_ADDRESS_LIST_GET_PRIVATE (list); + int n = GPOINTER_TO_INT (user_data); + + if (n >= g_strv_length (priv->strings)) + return FALSE; + + g_free (priv->strings[n]); + priv->strings[n] = g_value_dup_string (source_value); + + g_value_set_boxed (target_value, priv->strings); + return TRUE; +} + +static gboolean +hostname_filter (NmtNewtEntry *entry, + const char *text, + int ch, + int position, + gpointer user_data) +{ + return g_ascii_isalnum (ch) || ch == '.' || ch == '-'; +} + +static NmtNewtWidget * +nmt_address_list_create_widget (NmtWidgetList *list, + int num) +{ + NmtAddressListPrivate *priv = NMT_ADDRESS_LIST_GET_PRIVATE (list); + NmtNewtWidget *entry; + + if (priv->list_type == NMT_ADDRESS_LIST_IP4_WITH_PREFIX) + entry = nmt_ip_entry_new (25, AF_INET, TRUE, FALSE); + else if (priv->list_type == NMT_ADDRESS_LIST_IP4) + entry = nmt_ip_entry_new (25, AF_INET, FALSE, FALSE); + else if (priv->list_type == NMT_ADDRESS_LIST_IP6_WITH_PREFIX) + entry = nmt_ip_entry_new (25, AF_INET6, TRUE, FALSE); + else if (priv->list_type == NMT_ADDRESS_LIST_IP6) + entry = nmt_ip_entry_new (25, AF_INET6, FALSE, FALSE); + else if (priv->list_type == NMT_ADDRESS_LIST_HOSTNAME) { + entry = nmt_newt_entry_new (25, NMT_NEWT_ENTRY_NONEMPTY); + nmt_newt_entry_set_filter (NMT_NEWT_ENTRY (entry), hostname_filter, list); + } else + g_assert_not_reached (); + + g_object_bind_property_full (list, "strings", entry, "text", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, + strings_transform_to_entry, + strings_transform_from_entry, + GINT_TO_POINTER (num), NULL); + + return entry; +} + +static void +nmt_address_list_add_clicked (NmtWidgetList *list) +{ + NmtAddressListPrivate *priv = NMT_ADDRESS_LIST_GET_PRIVATE (list); + int len; + + len = priv->strings ? g_strv_length (priv->strings) : 0; + priv->strings = g_renew (char *, priv->strings, len + 2); + priv->strings[len] = g_strdup (""); + priv->strings[len + 1] = NULL; + + nmt_widget_list_set_length (list, len + 1); + g_object_notify (G_OBJECT (list), "strings"); +} + +static void +nmt_address_list_remove_clicked (NmtWidgetList *list, + int num) +{ + NmtAddressListPrivate *priv = NMT_ADDRESS_LIST_GET_PRIVATE (list); + int len; + + len = g_strv_length (priv->strings); + g_free (priv->strings[num]); + memmove (priv->strings + num, priv->strings + num + 1, (len - num) * sizeof (char *)); + + nmt_widget_list_set_length (list, len - 1); + g_object_notify (G_OBJECT (list), "strings"); +} + +static void +nmt_address_list_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtAddressListPrivate *priv = NMT_ADDRESS_LIST_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_LIST_TYPE: + priv->list_type = g_value_get_uint (value); + break; + case PROP_STRINGS: + g_strfreev (priv->strings); + priv->strings = g_value_dup_boxed (value); + if (!priv->strings) + priv->strings = g_new0 (char *, 1); + nmt_widget_list_set_length (NMT_WIDGET_LIST (object), + g_strv_length (priv->strings)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_address_list_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtAddressListPrivate *priv = NMT_ADDRESS_LIST_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_LIST_TYPE: + g_value_set_uint (value, priv->list_type); + break; + case PROP_STRINGS: + g_value_set_boxed (value, priv->strings); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_address_list_class_init (NmtAddressListClass *list_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (list_class); + NmtWidgetListClass *widget_list_class = NMT_WIDGET_LIST_CLASS (list_class); + + g_type_class_add_private (list_class, sizeof (NmtAddressListPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_address_list_set_property; + object_class->get_property = nmt_address_list_get_property; + + widget_list_class->create_widget = nmt_address_list_create_widget; + widget_list_class->add_clicked = nmt_address_list_add_clicked; + widget_list_class->remove_clicked = nmt_address_list_remove_clicked; + + /** + * NmtAddressList:list-type: + * + * The type of address the list holds. + */ + g_object_class_install_property + (object_class, PROP_LIST_TYPE, + g_param_spec_uint ("list-type", "", "", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtAddressList:strings: + * + * The strings in the list's entries. + */ + g_object_class_install_property + (object_class, PROP_STRINGS, + g_param_spec_boxed ("strings", "", "", + G_TYPE_STRV, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/nmt-address-list.h b/clients/tui/nmt-address-list.h new file mode 100644 index 00000000..df7a4f79 --- /dev/null +++ b/clients/tui/nmt-address-list.h @@ -0,0 +1,57 @@ +/* -*- 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. + */ + +#ifndef NMT_ADDRESS_LIST_H +#define NMT_ADDRESS_LIST_H + +#include "nmt-widget-list.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_ADDRESS_LIST (nmt_address_list_get_type ()) +#define NMT_ADDRESS_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_ADDRESS_LIST, NmtAddressList)) +#define NMT_ADDRESS_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_ADDRESS_LIST, NmtAddressListClass)) +#define NMT_IS_ADDRESS_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_ADDRESS_LIST)) +#define NMT_IS_ADDRESS_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_ADDRESS_LIST)) +#define NMT_ADDRESS_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_ADDRESS_LIST, NmtAddressListClass)) + +typedef struct { + NmtWidgetList parent; + +} NmtAddressList; + +typedef struct { + NmtWidgetListClass parent; + +} NmtAddressListClass; + +GType nmt_address_list_get_type (void); + +typedef enum { + NMT_ADDRESS_LIST_IP4_WITH_PREFIX, + NMT_ADDRESS_LIST_IP4, + NMT_ADDRESS_LIST_IP6_WITH_PREFIX, + NMT_ADDRESS_LIST_IP6, + NMT_ADDRESS_LIST_HOSTNAME +} NmtAddressListType; + +NmtNewtWidget *nmt_address_list_new (NmtAddressListType list_type); + +G_END_DECLS + +#endif /* NMT_ADDRESS_LIST_H */ diff --git a/clients/tui/nmt-connect-connection-list.c b/clients/tui/nmt-connect-connection-list.c new file mode 100644 index 00000000..08058066 --- /dev/null +++ b/clients/tui/nmt-connect-connection-list.c @@ -0,0 +1,701 @@ +/* -*- 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-connect-connection-list + * @short_description: Connection list for "nmtui connect" + * + * #NmtConnectConnectionList is the list of devices, connections, and + * access points displayed by "nmtui connect". + */ + +#include "config.h" + +#include <stdlib.h> +#include <glib/gi18n-lib.h> + +#include <NetworkManager.h> + +#include "nmtui.h" +#include "nmt-connect-connection-list.h" + +G_DEFINE_TYPE (NmtConnectConnectionList, nmt_connect_connection_list, NMT_TYPE_NEWT_LISTBOX) + +#define NMT_CONNECT_CONNECTION_LIST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_CONNECT_CONNECTION_LIST, NmtConnectConnectionListPrivate)) + +typedef struct { + char *name; + NMDevice *device; + + int sort_order; + + GSList *conns; +} NmtConnectDevice; + +typedef struct { + const char *name; + char *ssid; + + NMConnection *conn; + NMAccessPoint *ap; + NMDevice *device; + NMActiveConnection *active; +} NmtConnectConnection; + +typedef struct { + GSList *nmt_devices; +} NmtConnectConnectionListPrivate; + +/** + * nmt_connect_connection_list_new: + * + * Creates a new #NmtConnectConnectionList + * + * Returns: a new #NmtConnectConnectionList + */ +NmtNewtWidget * +nmt_connect_connection_list_new (void) +{ + return g_object_new (NMT_TYPE_CONNECT_CONNECTION_LIST, + "flags", NMT_NEWT_LISTBOX_SCROLL | NMT_NEWT_LISTBOX_BORDER, + "skip-null-keys", TRUE, + NULL); +} + +static void +nmt_connect_connection_list_init (NmtConnectConnectionList *list) +{ +} + +static void +nmt_connect_connection_free (NmtConnectConnection *nmtconn) +{ + g_clear_object (&nmtconn->conn); + g_clear_object (&nmtconn->ap); + g_clear_object (&nmtconn->active); + g_free (nmtconn->ssid); +} + +static void +nmt_connect_device_free (NmtConnectDevice *nmtdev) +{ + g_clear_pointer (&nmtdev->name, g_free); + g_clear_object (&nmtdev->device); + + g_slist_free_full (nmtdev->conns, (GDestroyNotify) nmt_connect_connection_free); +} + +static const char *device_sort_order[] = { + "NMDeviceEthernet", + "NMDeviceInfiniband", + "NMDeviceWifi", + NM_SETTING_VLAN_SETTING_NAME, + NM_SETTING_BOND_SETTING_NAME, + NM_SETTING_TEAM_SETTING_NAME, + NM_SETTING_BRIDGE_SETTING_NAME, + "NMDeviceModem", + "NMDeviceBt" +}; +static const int device_sort_order_len = G_N_ELEMENTS (device_sort_order); + +static int +get_sort_order_for_device (NMDevice *device) +{ + const char *type; + int i; + + type = G_OBJECT_TYPE_NAME (device); + for (i = 0; i < device_sort_order_len; i++) { + if (!strcmp (type, device_sort_order[i])) + return i; + } + + return -1; +} + +static int +get_sort_order_for_connection (NMConnection *conn) +{ + NMSettingConnection *s_con; + const char *type; + int i; + + s_con = nm_connection_get_setting_connection (conn); + type = nm_setting_connection_get_connection_type (s_con); + + for (i = 0; i < device_sort_order_len; i++) { + if (!strcmp (type, device_sort_order[i])) + return i; + } + + return -1; +} + +static int +sort_connections (gconstpointer a, + gconstpointer b) +{ + NmtConnectConnection *nmta = (NmtConnectConnection *)a; + NmtConnectConnection *nmtb = (NmtConnectConnection *)b; + + /* If nmta and nmtb both have NMConnections, sort them by timestamp */ + if (nmta->conn && nmtb->conn) { + NMSettingConnection *s_con_a, *s_con_b; + guint64 time_a, time_b; + + s_con_a = nm_connection_get_setting_connection (nmta->conn); + s_con_b = nm_connection_get_setting_connection (nmtb->conn); + + time_a = nm_setting_connection_get_timestamp (s_con_a); + time_b = nm_setting_connection_get_timestamp (s_con_b); + + return (int) (time_b - time_a); + } + + /* If one is an NMConnection and the other is an NMAccessPoint, the + * connection comes first. + */ + if (nmta->conn) + return -1; + else if (nmtb->conn) + return 1; + + g_return_val_if_fail (nmta->ap && nmtb->ap, 0); + + /* If both are access points, then sort by strength */ + return nm_access_point_get_strength (nmtb->ap) - nm_access_point_get_strength (nmta->ap); +} + +static void +add_connections_for_device (NmtConnectDevice *nmtdev, + const GPtrArray *connections) +{ + int i; + + for (i = 0; i < connections->len; i++) { + NMConnection *conn = connections->pdata[i]; + NMSettingConnection *s_con; + + s_con = nm_connection_get_setting_connection (conn); + if (nm_setting_connection_get_master (s_con)) + continue; + + if (nm_device_connection_valid (nmtdev->device, conn)) { + NmtConnectConnection *nmtconn = g_slice_new0 (NmtConnectConnection); + + nmtconn->name = nm_connection_get_id (conn); + nmtconn->device = nmtdev->device; + nmtconn->conn = g_object_ref (conn); + nmtdev->conns = g_slist_prepend (nmtdev->conns, nmtconn); + } + } +} + +/* stolen from nm-applet */ +static char * +hash_ap (NMAccessPoint *ap) +{ + unsigned char input[66]; + GBytes *ssid; + NM80211Mode mode; + guint32 flags; + guint32 wpa_flags; + guint32 rsn_flags; + + memset (&input[0], 0, sizeof (input)); + + ssid = nm_access_point_get_ssid (ap); + if (ssid) + memcpy (input, g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid)); + + mode = nm_access_point_get_mode (ap); + if (mode == NM_802_11_MODE_INFRA) + input[32] |= (1 << 0); + else if (mode == NM_802_11_MODE_ADHOC) + input[32] |= (1 << 1); + else + input[32] |= (1 << 2); + + /* Separate out no encryption, WEP-only, and WPA-capable */ + flags = nm_access_point_get_flags (ap); + wpa_flags = nm_access_point_get_wpa_flags (ap); + rsn_flags = nm_access_point_get_rsn_flags (ap); + if ( !(flags & NM_802_11_AP_FLAGS_PRIVACY) + && (wpa_flags == NM_802_11_AP_SEC_NONE) + && (rsn_flags == NM_802_11_AP_SEC_NONE)) + input[32] |= (1 << 3); + else if ( (flags & NM_802_11_AP_FLAGS_PRIVACY) + && (wpa_flags == NM_802_11_AP_SEC_NONE) + && (rsn_flags == NM_802_11_AP_SEC_NONE)) + input[32] |= (1 << 4); + else if ( !(flags & NM_802_11_AP_FLAGS_PRIVACY) + && (wpa_flags != NM_802_11_AP_SEC_NONE) + && (rsn_flags != NM_802_11_AP_SEC_NONE)) + input[32] |= (1 << 5); + else + input[32] |= (1 << 6); + + /* duplicate it */ + memcpy (&input[33], &input[0], 32); + return g_compute_checksum_for_data (G_CHECKSUM_MD5, input, sizeof (input)); +} + +static void +add_connections_for_aps (NmtConnectDevice *nmtdev, + const GPtrArray *connections) +{ + NmtConnectConnection *nmtconn; + NMConnection *conn; + NMAccessPoint *ap; + const GPtrArray *aps; + GHashTable *seen_ssids; + GBytes *ssid; + char *ap_hash; + int i, c; + + aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (nmtdev->device)); + if (!aps->len) + return; + + seen_ssids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + for (i = 0; i < aps->len; i++) { + ap = aps->pdata[i]; + + if (!nm_access_point_get_ssid (ap)) + continue; + + ap_hash = hash_ap (ap); + if (g_hash_table_contains (seen_ssids, ap_hash)) { + g_free (ap_hash); + continue; + } + g_hash_table_add (seen_ssids, ap_hash); + + nmtconn = g_slice_new0 (NmtConnectConnection); + nmtconn->device = nmtdev->device; + nmtconn->ap = g_object_ref (ap); + ssid = nm_access_point_get_ssid (ap); + if (ssid) + nmtconn->ssid = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL), + g_bytes_get_size (ssid)); + + for (c = 0; c < connections->len; c++) { + conn = connections->pdata[c]; + if ( nm_device_connection_valid (nmtdev->device, conn) + && nm_access_point_connection_valid (ap, conn)) { + nmtconn->name = nm_connection_get_id (conn); + nmtconn->conn = g_object_ref (conn); + break; + } + } + + if (!nmtconn->name) + nmtconn->name = nmtconn->ssid ? nmtconn->ssid : "<unknown>"; + + nmtdev->conns = g_slist_prepend (nmtdev->conns, nmtconn); + } + + g_hash_table_unref (seen_ssids); +} + +static GSList * +append_nmt_devices_for_devices (GSList *nmt_devices, + const GPtrArray *devices, + char **names, + const GPtrArray *connections) +{ + NmtConnectDevice *nmtdev; + NMDevice *device; + int i, sort_order; + + for (i = 0; i < devices->len; i++) { + device = devices->pdata[i]; + + sort_order = get_sort_order_for_device (device); + if (sort_order == -1) + continue; + + nmtdev = g_slice_new0 (NmtConnectDevice); + nmtdev->name = g_strdup (names[i]); + nmtdev->device = g_object_ref (device); + nmtdev->sort_order = sort_order; + + if (NM_IS_DEVICE_WIFI (device)) + add_connections_for_aps (nmtdev, connections); + else + add_connections_for_device (nmtdev, connections); + nmtdev->conns = g_slist_sort (nmtdev->conns, sort_connections); + + nmt_devices = g_slist_prepend (nmt_devices, nmtdev); + } + + return nmt_devices; +} + +static GSList * +append_nmt_devices_for_virtual_devices (GSList *nmt_devices, + const GPtrArray *connections) +{ + NmtConnectDevice *nmtdev = NULL; + int i; + GHashTable *devices_by_name; + char *name; + NMConnection *conn; + NmtConnectConnection *nmtconn; + int sort_order; + + devices_by_name = g_hash_table_new (g_str_hash, g_str_equal); + + for (i = 0; i < connections->len; i++) { + conn = connections->pdata[i]; + sort_order = get_sort_order_for_connection (conn); + if (sort_order == -1) + continue; + + name = nm_connection_get_virtual_device_description (conn); + if (name) + nmtdev = g_hash_table_lookup (devices_by_name, name); + if (nmtdev) + g_free (name); + else { + nmtdev = g_slice_new0 (NmtConnectDevice); + nmtdev->name = name ? name : g_strdup ("Unknown"); + nmtdev->sort_order = sort_order; + + g_hash_table_insert (devices_by_name, nmtdev->name, nmtdev); + nmt_devices = g_slist_prepend (nmt_devices, nmtdev); + } + + nmtconn = g_slice_new0 (NmtConnectConnection); + nmtconn->name = nm_connection_get_id (conn); + nmtconn->conn = g_object_ref (conn); + + nmtdev->conns = g_slist_insert_sorted (nmtdev->conns, nmtconn, sort_connections); + } + + g_hash_table_destroy (devices_by_name); + return nmt_devices; +} + +static GSList * +append_nmt_devices_for_vpns (GSList *nmt_devices, + const GPtrArray *connections) +{ + NmtConnectDevice *nmtdev; + int i; + NMConnection *conn; + NmtConnectConnection *nmtconn; + + nmtdev = g_slice_new0 (NmtConnectDevice); + nmtdev->name = g_strdup (_("VPN")); + nmtdev->sort_order = 100; + + for (i = 0; i < connections->len; i++) { + conn = connections->pdata[i]; + if (!nm_connection_is_type (conn, NM_SETTING_VPN_SETTING_NAME)) + continue; + + nmtconn = g_slice_new0 (NmtConnectConnection); + nmtconn->name = nm_connection_get_id (conn); + nmtconn->conn = g_object_ref (conn); + + nmtdev->conns = g_slist_insert_sorted (nmtdev->conns, nmtconn, sort_connections); + } + + if (nmtdev->conns) + nmt_devices = g_slist_prepend (nmt_devices, nmtdev); + else + nmt_connect_device_free (nmtdev); + + return nmt_devices; +} + +static int +sort_nmt_devices (gconstpointer a, + gconstpointer b) +{ + NmtConnectDevice *nmta = (NmtConnectDevice *)a; + NmtConnectDevice *nmtb = (NmtConnectDevice *)b; + + if (nmta->sort_order != nmtb->sort_order) + return nmta->sort_order - nmtb->sort_order; + + return strcmp (nmta->name, nmtb->name); +} + +static NMActiveConnection * +connection_find_ac (NMConnection *conn, + const GPtrArray *acs) +{ + NMActiveConnection *ac; + NMRemoteConnection *ac_conn; + int i; + + for (i = 0; i < acs->len; i++) { + ac = acs->pdata[i]; + ac_conn = nm_active_connection_get_connection (ac); + + if (conn == NM_CONNECTION (ac_conn)) + return ac; + } + + return NULL; +} + +static void +nmt_connect_connection_list_rebuild (NmtConnectConnectionList *list) +{ + NmtConnectConnectionListPrivate *priv = NMT_CONNECT_CONNECTION_LIST_GET_PRIVATE (list); + NmtNewtListbox *listbox = NMT_NEWT_LISTBOX (list); + const GPtrArray *devices, *acs, *connections; + int max_width; + char **names, *row, active_col; + const char *strength_col; + GSList *nmt_devices, *diter, *citer; + NmtConnectDevice *nmtdev; + NmtConnectConnection *nmtconn; + + g_slist_free_full (priv->nmt_devices, (GDestroyNotify) nmt_connect_device_free); + priv->nmt_devices = NULL; + nmt_newt_listbox_clear (listbox); + + devices = nm_client_get_devices (nm_client); + acs = nm_client_get_active_connections (nm_client); + connections = nm_client_get_connections (nm_client); + + nmt_devices = NULL; + + names = nm_device_disambiguate_names ((NMDevice **) devices->pdata, devices->len); + nmt_devices = append_nmt_devices_for_devices (nmt_devices, devices, names, connections); + g_strfreev (names); + + nmt_devices = append_nmt_devices_for_virtual_devices (nmt_devices, connections); + nmt_devices = append_nmt_devices_for_vpns (nmt_devices, connections); + + nmt_devices = g_slist_sort (nmt_devices, sort_nmt_devices); + + max_width = 0; + for (diter = nmt_devices; diter; diter = diter->next) { + nmtdev = diter->data; + for (citer = nmtdev->conns; citer; citer = citer->next) { + nmtconn = citer->data; + + max_width = MAX (max_width, nmt_newt_text_width (nmtconn->name)); + } + } + + for (diter = nmt_devices; diter; diter = diter->next) { + nmtdev = diter->data; + + if (diter != nmt_devices) + nmt_newt_listbox_append (listbox, "", NULL); + nmt_newt_listbox_append (listbox, nmtdev->name, NULL); + + for (citer = nmtdev->conns; citer; citer = citer->next) { + nmtconn = citer->data; + + if (nmtconn->conn) + nmtconn->active = connection_find_ac (nmtconn->conn, acs); + if (nmtconn->active) { + g_object_ref (nmtconn->active); + active_col = '*'; + } else + active_col = ' '; + + if (nmtconn->ap) { + guint8 strength = nm_access_point_get_strength (nmtconn->ap); + + strength_col = nm_utils_wifi_strength_bars (strength); + } else + strength_col = NULL; + + row = g_strdup_printf ("%c %s%-*s%s%s", + active_col, + nmtconn->name, + (int)(max_width - nmt_newt_text_width (nmtconn->name)), "", + strength_col ? " " : "", + strength_col ? strength_col : ""); + + nmt_newt_listbox_append (listbox, row, nmtconn); + g_free (row); + } + } + + priv->nmt_devices = nmt_devices; + + g_object_notify (G_OBJECT (listbox), "active"); + g_object_notify (G_OBJECT (listbox), "active-key"); +} + +static void +rebuild_on_property_changed (GObject *object, + GParamSpec *spec, + gpointer list) +{ + nmt_connect_connection_list_rebuild (list); +} + +static void +nmt_connect_connection_list_constructed (GObject *object) +{ + NmtConnectConnectionList *list = NMT_CONNECT_CONNECTION_LIST (object); + + g_signal_connect (nm_client, "notify::" NM_CLIENT_ACTIVE_CONNECTIONS, + G_CALLBACK (rebuild_on_property_changed), list); + g_signal_connect (nm_client, "notify::" NM_CLIENT_CONNECTIONS, + G_CALLBACK (rebuild_on_property_changed), list); + g_signal_connect (nm_client, "notify::" NM_CLIENT_DEVICES, + G_CALLBACK (rebuild_on_property_changed), list); + + nmt_connect_connection_list_rebuild (list); + + G_OBJECT_CLASS (nmt_connect_connection_list_parent_class)->constructed (object); +} + +static void +nmt_connect_connection_list_finalize (GObject *object) +{ + NmtConnectConnectionListPrivate *priv = NMT_CONNECT_CONNECTION_LIST_GET_PRIVATE (object); + + g_slist_free_full (priv->nmt_devices, (GDestroyNotify) nmt_connect_device_free); + + g_signal_handlers_disconnect_by_func (nm_client, G_CALLBACK (rebuild_on_property_changed), object); + + G_OBJECT_CLASS (nmt_connect_connection_list_parent_class)->finalize (object); +} + +static void +nmt_connect_connection_list_class_init (NmtConnectConnectionListClass *list_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (list_class); + + g_type_class_add_private (list_class, sizeof (NmtConnectConnectionListPrivate)); + + /* virtual methods */ + object_class->constructed = nmt_connect_connection_list_constructed; + object_class->finalize = nmt_connect_connection_list_finalize; +} + +/** + * nmt_connect_connection_list_get_connection: + * @list: an #NmtConnectConnectionList + * @identifier: a connection ID or UUID, or device name + * @connection: (out) (transfer none): the #NMConnection to be activated + * @device: (out) (transfer none): the #NMDevice to activate @connection on + * @specific_object: (out) (transfer none): the "specific object" to connect to + * @active: (out) (transfer none): the #NMActiveConnection corresponding + * to the selection, if any. + * + * Gets information about the indicated connection. + * + * Returns: %TRUE if there was a match, %FALSE if not. + */ +gboolean +nmt_connect_connection_list_get_connection (NmtConnectConnectionList *list, + const char *identifier, + NMConnection **connection, + NMDevice **device, + NMObject **specific_object, + NMActiveConnection **active) +{ + NmtConnectConnectionListPrivate *priv = NMT_CONNECT_CONNECTION_LIST_GET_PRIVATE (list); + GSList *diter, *citer; + NmtConnectDevice *nmtdev; + NmtConnectConnection *nmtconn = NULL; + NMConnection *conn = NULL; + + g_return_val_if_fail (identifier, FALSE); + + if (nm_utils_is_uuid (identifier)) + conn = NM_CONNECTION (nm_client_get_connection_by_uuid (nm_client, identifier)); + if (!conn) + conn = NM_CONNECTION (nm_client_get_connection_by_id (nm_client, identifier)); + + for (diter = priv->nmt_devices; diter; diter = diter->next) { + nmtdev = diter->data; + if (!nmtdev->conns) + continue; + + for (citer = nmtdev->conns; citer; citer = citer->next) { + nmtconn = citer->data; + if (conn) { + if (conn == nmtconn->conn) + goto found; + } else if (nmtconn->ssid && !strcmp (identifier, nmtconn->ssid)) + goto found; + } + + if (!conn && nmtdev->device && !strcmp (identifier, nm_device_get_ip_iface (nmtdev->device))) { + nmtconn = nmtdev->conns->data; + goto found; + } + } + + return FALSE; + + found: + if (connection) + *connection = nmtconn->conn; + if (device) + *device = nmtconn->device; + if (specific_object) + *specific_object = NM_OBJECT (nmtconn->ap); + if (active) + *active = nmtconn->active; + + return TRUE; +} + +/** + * nmt_connect_connection_list_get_selection: + * @list: an #NmtConnectConnectionList + * @connection: (out) (transfer none): the #NMConnection to be activated + * @device: (out) (transfer none): the #NMDevice to activate @connection on + * @specific_object: (out) (transfer none): the "specific object" to connect to + * @active: (out) (transfer none): the #NMActiveConnection corresponding + * to the selection, if any. + * + * Gets information about the selected row. + * + * Returns: %TRUE if there is a selection, %FALSE if not. + */ +gboolean +nmt_connect_connection_list_get_selection (NmtConnectConnectionList *list, + NMConnection **connection, + NMDevice **device, + NMObject **specific_object, + NMActiveConnection **active) +{ + NmtConnectConnection *nmtconn; + + nmtconn = nmt_newt_listbox_get_active_key (NMT_NEWT_LISTBOX (list)); + if (!nmtconn) + return FALSE; + + if (connection) + *connection = nmtconn->conn; + if (device) + *device = nmtconn->device; + if (specific_object) + *specific_object = NM_OBJECT (nmtconn->ap); + if (active) + *active = nmtconn->active; + + return TRUE; +} diff --git a/clients/tui/nmt-connect-connection-list.h b/clients/tui/nmt-connect-connection-list.h new file mode 100644 index 00000000..d4790043 --- /dev/null +++ b/clients/tui/nmt-connect-connection-list.h @@ -0,0 +1,61 @@ +/* -*- 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. + */ + +#ifndef NMT_CONNECT_CONNECTION_LIST_H +#define NMT_CONNECT_CONNECTION_LIST_H + +#include "nmt-newt.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_CONNECT_CONNECTION_LIST (nmt_connect_connection_list_get_type ()) +#define NMT_CONNECT_CONNECTION_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_CONNECT_CONNECTION_LIST, NmtConnectConnectionList)) +#define NMT_CONNECT_CONNECTION_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_CONNECT_CONNECTION_LIST, NmtConnectConnectionListClass)) +#define NMT_IS_CONNECT_CONNECTION_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_CONNECT_CONNECTION_LIST)) +#define NMT_IS_CONNECT_CONNECTION_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_CONNECT_CONNECTION_LIST)) +#define NMT_CONNECT_CONNECTION_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_CONNECT_CONNECTION_LIST, NmtConnectConnectionListClass)) + +typedef struct { + NmtNewtListbox parent; + +} NmtConnectConnectionList; + +typedef struct { + NmtNewtListboxClass parent; + +} NmtConnectConnectionListClass; + +GType nmt_connect_connection_list_get_type (void); + +NmtNewtWidget *nmt_connect_connection_list_new (void); + +gboolean nmt_connect_connection_list_get_connection (NmtConnectConnectionList *list, + const char *identifier, + NMConnection **connection, + NMDevice **device, + NMObject **specific_object, + NMActiveConnection **active); +gboolean nmt_connect_connection_list_get_selection (NmtConnectConnectionList *list, + NMConnection **connection, + NMDevice **device, + NMObject **specific_object, + NMActiveConnection **active); + +G_END_DECLS + +#endif /* NMT_CONNECT_CONNECTION_LIST_H */ diff --git a/clients/tui/nmt-device-entry.c b/clients/tui/nmt-device-entry.c new file mode 100644 index 00000000..2af5e584 --- /dev/null +++ b/clients/tui/nmt-device-entry.c @@ -0,0 +1,573 @@ +/* -*- 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-device-entry + * @short_description: #NmtNewtEntry for identifying a device + * + * #NmtDeviceEntry provides a widget for identifying a device, either + * by interface name or by hardware address. The user can enter either + * value, and the entry's #NmtDeviceEntry:interface-name or + * #NmtDeviceEntry:mac-address property will be set accordingly. If + * the entry recognizes the interface name or mac address typed in as + * matching a known #NMDevice, then it will also display the other + * property in parentheses. + * + * FIXME: #NmtDeviceEntry is currently an #NmtEditorGrid object, so that + * we can possibly eventually add a button to its "extra" field, that + * would pop up a form for selecting a device. But if we're not going + * to implement that then we should make it just an #NmtNewtEntry. + */ + +#include "config.h" + +#include <string.h> +#include <sys/socket.h> +#include <linux/if_arp.h> + +#include <glib/gi18n-lib.h> +#include <NetworkManager.h> + +#include "nmtui.h" +#include "nmt-device-entry.h" + +G_DEFINE_TYPE (NmtDeviceEntry, nmt_device_entry, NMT_TYPE_EDITOR_GRID) + +#define NMT_DEVICE_ENTRY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_DEVICE_ENTRY, NmtDeviceEntryPrivate)) + +typedef struct { + GType hardware_type; + NmtDeviceEntryDeviceFilter device_filter; + gpointer device_filter_data; + int arptype; + + char *interface_name; + char *mac_address; + + char *label; + NmtNewtEntry *entry; + NmtNewtWidget *button; + + gboolean updating; +} NmtDeviceEntryPrivate; + +enum { + PROP_0, + PROP_LABEL, + PROP_WIDTH, + PROP_HARDWARE_TYPE, + PROP_INTERFACE_NAME, + PROP_MAC_ADDRESS, + + LAST_PROP +}; + +/** + * nmt_device_entry_new: + * @label: the label for the entry + * @width: the width of the entry + * @hardware_type: the type of #NMDevice to be selected, or + * %G_TYPE_NONE if this is for a virtual device type. + * + * Creates a new #NmtDeviceEntry, for identifying a device of type + * @hardware_type. If @hardware_type is %G_TYPE_NONE (and you do not + * set a #NmtDeviceEntryDeviceFilter), then this will only allow + * specifying an interface name, not a hardware address. + * + * Returns: a new #NmtDeviceEntry. + */ +NmtNewtWidget * +nmt_device_entry_new (const char *label, + int width, + GType hardware_type) +{ + return g_object_new (NMT_TYPE_DEVICE_ENTRY, + "label", label, + "width", width, + "hardware-type", hardware_type, + NULL); +} + +static gboolean +device_entry_parse (NmtDeviceEntry *deventry, + const char *text, + char **interface_name, + char **mac_address) +{ + NmtDeviceEntryPrivate *priv = NMT_DEVICE_ENTRY_GET_PRIVATE (deventry); + guint8 buf[NM_UTILS_HWADDR_LEN_MAX]; + char **words; + int len; + + *interface_name = *mac_address = NULL; + if (!*text) + return TRUE; + + if (priv->hardware_type == G_TYPE_NONE && !priv->device_filter) { + if (nm_utils_iface_valid_name (text)) { + *interface_name = g_strdup (text); + return TRUE; + } else + return FALSE; + } + + words = g_strsplit (text, " ", -1); + if (g_strv_length (words) > 2) { + g_strfreev (words); + return FALSE; + } + + if (words[1]) { + len = strlen (words[1]); + if (len < 3 || words[1][0] != '(' || words[1][len - 1] != ')') + goto fail; + + memmove (words[1], words[1] + 1, len - 2); + words[1][len - 2] = '\0'; + } + + len = nm_utils_hwaddr_len (priv->arptype); + if ( nm_utils_hwaddr_aton (words[0], buf, len) + && (!words[1] || nm_utils_iface_valid_name (words[1]))) { + *mac_address = words[0]; + *interface_name = NULL; + g_free (words); + return TRUE; + } else if ( nm_utils_iface_valid_name (words[0]) + && (!words[1] || nm_utils_hwaddr_aton (words[1], buf, len))) { + *interface_name = words[0]; + *mac_address = NULL; + g_free (words); + return TRUE; + } + + fail: + g_strfreev (words); + return FALSE; +} + +static gboolean +device_entry_validate (NmtNewtEntry *entry, + const char *text, + gpointer user_data) +{ + NmtDeviceEntry *deventry = user_data; + char *ifname, *mac; + + if (!device_entry_parse (deventry, text, &ifname, &mac)) + return FALSE; + + g_free (ifname); + g_free (mac); + return TRUE; +} + +static NMDevice * +find_device_by_interface_name (NmtDeviceEntry *deventry, + const char *interface_name) +{ + NmtDeviceEntryPrivate *priv = NMT_DEVICE_ENTRY_GET_PRIVATE (deventry); + const GPtrArray *devices; + NMDevice *device = NULL; + int i; + + devices = nm_client_get_devices (nm_client); + for (i = 0; i < devices->len && !device; i++) { + NMDevice *candidate = devices->pdata[i]; + + if ( priv->hardware_type != G_TYPE_NONE + && !G_TYPE_CHECK_INSTANCE_TYPE (candidate, priv->hardware_type)) + continue; + + if ( priv->device_filter + && !priv->device_filter (deventry, candidate, priv->device_filter_data)) + continue; + + if (!g_strcmp0 (interface_name, nm_device_get_iface (candidate))) + device = candidate; + } + + return device; +} + +static NMDevice * +find_device_by_mac_address (NmtDeviceEntry *deventry, + const char *mac_address) +{ + NmtDeviceEntryPrivate *priv = NMT_DEVICE_ENTRY_GET_PRIVATE (deventry); + const GPtrArray *devices; + NMDevice *device = NULL; + int i; + + devices = nm_client_get_devices (nm_client); + for (i = 0; i < devices->len && !device; i++) { + NMDevice *candidate = devices->pdata[i]; + char *hwaddr; + + if ( priv->hardware_type != G_TYPE_NONE + && !G_TYPE_CHECK_INSTANCE_TYPE (candidate, priv->hardware_type)) + continue; + + if ( priv->device_filter + && !priv->device_filter (deventry, candidate, priv->device_filter_data)) + continue; + + g_object_get (G_OBJECT (candidate), "hw-address", &hwaddr, NULL); + if (hwaddr && !g_ascii_strcasecmp (mac_address, hwaddr)) + device = candidate; + g_free (hwaddr); + } + + return device; +} + +static void +update_entry (NmtDeviceEntry *deventry) +{ + NmtDeviceEntryPrivate *priv = NMT_DEVICE_ENTRY_GET_PRIVATE (deventry); + const char *ifname; + char *mac, *text; + NMDevice *ifname_device, *mac_device; + + if (priv->interface_name) { + ifname = priv->interface_name; + ifname_device = find_device_by_interface_name (deventry, priv->interface_name); + } else { + ifname = NULL; + ifname_device = NULL; + } + + if (priv->mac_address) { + mac = g_strdup (priv->mac_address); + mac_device = find_device_by_mac_address (deventry, priv->mac_address); + } else { + mac = NULL; + mac_device = NULL; + } + + if (!ifname && mac_device) + ifname = nm_device_get_iface (mac_device); + if (!mac && ifname_device && (priv->hardware_type != G_TYPE_NONE)) + g_object_get (G_OBJECT (ifname_device), "hw-address", &mac, NULL); + + if (ifname_device && mac_device && ifname_device != mac_device) { + /* Mismatch! */ + text = g_strdup_printf ("%s != %s", priv->interface_name, mac); + } else if (ifname && mac) { + if (ifname_device) + text = g_strdup_printf ("%s (%s)", ifname, mac); + else + text = g_strdup_printf ("%s (%s)", mac, ifname); + } else if (ifname) + text = g_strdup (ifname); + else if (mac) + text = g_strdup (mac); + else + text = g_strdup (""); + + priv->updating = TRUE; + g_object_set (G_OBJECT (priv->entry), "text", text, NULL); + priv->updating = FALSE; + g_free (text); + + g_free (mac); +} + +static gboolean +nmt_device_entry_set_interface_name (NmtDeviceEntry *deventry, + const char *interface_name) +{ + NmtDeviceEntryPrivate *priv = NMT_DEVICE_ENTRY_GET_PRIVATE (deventry); + + if (g_strcmp0 (interface_name, priv->interface_name) != 0) { + g_free (priv->interface_name); + priv->interface_name = g_strdup (interface_name); + + g_object_notify (G_OBJECT (deventry), "interface-name"); + return TRUE; + } else + return FALSE; +} + +static gboolean +nmt_device_entry_set_mac_address (NmtDeviceEntry *deventry, + const char *mac_address) +{ + NmtDeviceEntryPrivate *priv = NMT_DEVICE_ENTRY_GET_PRIVATE (deventry); + gboolean changed; + + if (mac_address && !priv->mac_address) { + priv->mac_address = g_strdup (mac_address); + changed = TRUE; + } else if (!mac_address && priv->mac_address) { + g_clear_pointer (&priv->mac_address, g_free); + changed = TRUE; + } else if ( mac_address && priv->mac_address + && !nm_utils_hwaddr_matches (mac_address, -1, priv->mac_address, -1)) { + g_free (priv->mac_address); + priv->mac_address = g_strdup (mac_address); + changed = TRUE; + } else + changed = FALSE; + + if (changed) + g_object_notify (G_OBJECT (deventry), "mac-address"); + return changed; +} + +static void +entry_text_changed (GObject *object, + GParamSpec *pspec, + gpointer deventry) +{ + NmtDeviceEntryPrivate *priv = NMT_DEVICE_ENTRY_GET_PRIVATE (deventry); + const char *text; + char *ifname, *mac; + + if (priv->updating) + return; + + text = nmt_newt_entry_get_text (priv->entry); + if (!device_entry_parse (deventry, text, &ifname, &mac)) + return; + + nmt_device_entry_set_interface_name (deventry, ifname); + g_free (ifname); + + nmt_device_entry_set_mac_address (deventry, mac); + g_free (mac); +} + +static void +nmt_device_entry_init (NmtDeviceEntry *deventry) +{ + NmtDeviceEntryPrivate *priv = NMT_DEVICE_ENTRY_GET_PRIVATE (deventry); + NmtNewtWidget *entry; + + priv->hardware_type = G_TYPE_NONE; + + entry = nmt_newt_entry_new (-1, 0); + priv->entry = NMT_NEWT_ENTRY (entry); + nmt_newt_entry_set_validator (priv->entry, device_entry_validate, deventry); + g_signal_connect (priv->entry, "notify::text", + G_CALLBACK (entry_text_changed), deventry); + +#if 0 + priv->button = nmt_newt_button_new (_("Select...")); + g_signal_connect (priv->button, "clicked", + G_CALLBACK (do_select_dialog), deventry); +#endif +} + +static void +nmt_device_entry_constructed (GObject *object) +{ + NmtDeviceEntryPrivate *priv = NMT_DEVICE_ENTRY_GET_PRIVATE (object); + + nmt_editor_grid_append (NMT_EDITOR_GRID (object), priv->label, NMT_NEWT_WIDGET (priv->entry), NULL); + + G_OBJECT_CLASS (nmt_device_entry_parent_class)->constructed (object); +} + +static void +nmt_device_entry_finalize (GObject *object) +{ + NmtDeviceEntryPrivate *priv = NMT_DEVICE_ENTRY_GET_PRIVATE (object); + + g_free (priv->interface_name); + g_free (priv->mac_address); + + G_OBJECT_CLASS (nmt_device_entry_parent_class)->finalize (object); +} + +/** + * NmtDeviceEntryDeviceFilter: + * @deventry: the #NmtDeviceEntry + * @device: an #NMDevice + * @user_data: user data + * + * Filter function for determining which devices can be specified + * on an entry. + * + * Returns: %TRUE if @device is acceptable for @deventry + */ + +/** + * nmt_device_entry_set_device_filter: + * @deventry: the #NmtDeviceEntry + * @filter: the filter + * @user_data: data for @filter + * + * Sets a device filter on @deventry. Only devices that pass @filter + * will be recognized by @deventry. + * + * If the entry's #NmtDeviceEntry:hardware-type is not %G_TYPE_NONE, + * then only devices that both match the hardware type and are + * accepted by the filter will be allowed. + */ +void +nmt_device_entry_set_device_filter (NmtDeviceEntry *deventry, + NmtDeviceEntryDeviceFilter filter, + gpointer user_data) +{ + NmtDeviceEntryPrivate *priv = NMT_DEVICE_ENTRY_GET_PRIVATE (deventry); + + priv->device_filter = filter; + priv->device_filter_data = user_data; +} + +static void +nmt_device_entry_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtDeviceEntry *deventry = NMT_DEVICE_ENTRY (object); + NmtDeviceEntryPrivate *priv = NMT_DEVICE_ENTRY_GET_PRIVATE (deventry); + const char *interface_name; + const char *mac_address; + + switch (prop_id) { + case PROP_LABEL: + priv->label = g_value_dup_string (value); + break; + case PROP_WIDTH: + nmt_newt_entry_set_width (priv->entry, g_value_get_int (value)); + break; + case PROP_HARDWARE_TYPE: + priv->hardware_type = g_value_get_gtype (value); + priv->arptype = (priv->hardware_type == NM_TYPE_DEVICE_INFINIBAND) ? ARPHRD_INFINIBAND : ARPHRD_ETHER; + break; + case PROP_INTERFACE_NAME: + interface_name = g_value_get_string (value); + if (nmt_device_entry_set_interface_name (deventry, interface_name)) + update_entry (deventry); + break; + case PROP_MAC_ADDRESS: + mac_address = g_value_get_string (value); + if (nmt_device_entry_set_mac_address (deventry, mac_address)) + update_entry (deventry); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_device_entry_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtDeviceEntryPrivate *priv = NMT_DEVICE_ENTRY_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_LABEL: + g_value_set_string (value, priv->label); + break; + case PROP_WIDTH: + g_value_set_int (value, nmt_newt_entry_get_width (priv->entry)); + break; + case PROP_HARDWARE_TYPE: + g_value_set_gtype (value, priv->hardware_type); + break; + case PROP_INTERFACE_NAME: + g_value_set_string (value, priv->interface_name); + break; + case PROP_MAC_ADDRESS: + g_value_set_string (value, priv->mac_address); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_device_entry_class_init (NmtDeviceEntryClass *deventry_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (deventry_class); + + g_type_class_add_private (deventry_class, sizeof (NmtDeviceEntryPrivate)); + + /* virtual methods */ + object_class->constructed = nmt_device_entry_constructed; + object_class->set_property = nmt_device_entry_set_property; + object_class->get_property = nmt_device_entry_get_property; + object_class->finalize = nmt_device_entry_finalize; + + /** + * NmtDeviceEntry:label: + * + * The entry's label + */ + g_object_class_install_property + (object_class, PROP_LABEL, + g_param_spec_string ("label", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtDeviceEntry:width: + * + * The entry's width in characters + */ + g_object_class_install_property + (object_class, PROP_WIDTH, + g_param_spec_int ("width", "", "", + -1, 80, -1, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtDeviceEntry:hardware-type: + * + * The type of #NMDevice to limit the entry to, or %G_TYPE_NONE + * if the entry is for a virtual device and should not accept + * hardware addresses. + */ + g_object_class_install_property + (object_class, PROP_HARDWARE_TYPE, + g_param_spec_gtype ("hardware-type", "", "", + G_TYPE_NONE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtDeviceEntry:interface-name: + * + * The interface name of the device identified by the entry. + */ + g_object_class_install_property + (object_class, PROP_INTERFACE_NAME, + g_param_spec_string ("interface-name", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtDeviceEntry:mac-address: + * + * The hardware address of the device identified by the entry. + */ + g_object_class_install_property + (object_class, PROP_MAC_ADDRESS, + g_param_spec_string ("mac-address", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/nmt-device-entry.h b/clients/tui/nmt-device-entry.h new file mode 100644 index 00000000..05d5d40f --- /dev/null +++ b/clients/tui/nmt-device-entry.h @@ -0,0 +1,60 @@ +/* -*- 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. + */ + +#ifndef NMT_DEVICE_ENTRY_H +#define NMT_DEVICE_ENTRY_H + +#include "nmt-editor-grid.h" + +#include <NetworkManager.h> + +G_BEGIN_DECLS + +#define NMT_TYPE_DEVICE_ENTRY (nmt_device_entry_get_type ()) +#define NMT_DEVICE_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_DEVICE_ENTRY, NmtDeviceEntry)) +#define NMT_DEVICE_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_DEVICE_ENTRY, NmtDeviceEntryClass)) +#define NMT_IS_DEVICE_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_DEVICE_ENTRY)) +#define NMT_IS_DEVICE_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_DEVICE_ENTRY)) +#define NMT_DEVICE_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_DEVICE_ENTRY, NmtDeviceEntryClass)) + +typedef struct { + NmtEditorGrid parent; + +} NmtDeviceEntry; + +typedef struct { + NmtEditorGridClass parent; + +} NmtDeviceEntryClass; + +GType nmt_device_entry_get_type (void); + +NmtNewtWidget *nmt_device_entry_new (const char *label, + int width, + GType hardware_type); + +typedef gboolean (*NmtDeviceEntryDeviceFilter) (NmtDeviceEntry *deventry, + NMDevice *device, + gpointer user_data); +void nmt_device_entry_set_device_filter (NmtDeviceEntry *deventry, + NmtDeviceEntryDeviceFilter filter, + gpointer user_data); + +G_END_DECLS + +#endif /* NMT_DEVICE_ENTRY_H */ diff --git a/clients/tui/nmt-edit-connection-list.c b/clients/tui/nmt-edit-connection-list.c new file mode 100644 index 00000000..e1b982dd --- /dev/null +++ b/clients/tui/nmt-edit-connection-list.c @@ -0,0 +1,554 @@ +/* -*- 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-edit-connection-list + * @short_description: Connection list for "nmtui edit" + * + * #NmtEditConnectionList is the list of connections displayed by + * "nmtui edit". + */ + +#include "config.h" + +#include <glib/gi18n-lib.h> + +#include "nmtui.h" +#include "nmtui-edit.h" +#include "nmt-edit-connection-list.h" +#include "nmt-editor.h" + +#include "nm-editor-utils.h" + +G_DEFINE_TYPE (NmtEditConnectionList, nmt_edit_connection_list, NMT_TYPE_NEWT_GRID) + +#define NMT_EDIT_CONNECTION_LIST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_EDIT_CONNECTION_LIST, NmtEditConnectionListPrivate)) + +typedef struct { + GSList *connections; + + gboolean grouped; + NmtEditConnectionListFilter connection_filter; + gpointer connection_filter_data; + + NmtNewtListbox *listbox; + NmtNewtButtonBox *buttons; + + NmtNewtWidget *add; + NmtNewtWidget *edit; + NmtNewtWidget *delete; + NmtNewtWidget *extra; +} NmtEditConnectionListPrivate; + +enum { + PROP_0, + + PROP_GROUPED, + PROP_CONNECTION_FILTER, + PROP_CONNECTION_FILTER_DATA, + PROP_EXTRA_WIDGET, + PROP_CONNECTIONS, + PROP_NUM_CONNECTIONS, + + LAST_PROP +}; + +enum { + ADD_CONNECTION, + EDIT_CONNECTION, + REMOVE_CONNECTION, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void add_clicked (NmtNewtButton *button, gpointer list); +static void edit_clicked (NmtNewtButton *button, gpointer list); +static void delete_clicked (NmtNewtButton *button, gpointer list); +static void listbox_activated (NmtNewtWidget *listbox, gpointer list); + +static void +nmt_edit_connection_list_init (NmtEditConnectionList *list) +{ + NmtEditConnectionListPrivate *priv = NMT_EDIT_CONNECTION_LIST_GET_PRIVATE (list); + NmtNewtWidget *listbox, *buttons; + NmtNewtGrid *grid = NMT_NEWT_GRID (list); + + listbox = g_object_new (NMT_TYPE_NEWT_LISTBOX, + "flags", NMT_NEWT_LISTBOX_SCROLL | NMT_NEWT_LISTBOX_BORDER, + "skip-null-keys", TRUE, + NULL); + priv->listbox = NMT_NEWT_LISTBOX (listbox); + nmt_newt_grid_add (grid, listbox, 0, 0); + nmt_newt_grid_set_flags (grid, listbox, + NMT_NEWT_GRID_FILL_X | NMT_NEWT_GRID_FILL_Y | + NMT_NEWT_GRID_EXPAND_X | NMT_NEWT_GRID_EXPAND_Y); + g_signal_connect (priv->listbox, "activated", G_CALLBACK (listbox_activated), list); + + buttons = nmt_newt_button_box_new (NMT_NEWT_BUTTON_BOX_VERTICAL); + priv->buttons = NMT_NEWT_BUTTON_BOX (buttons); + nmt_newt_grid_add (grid, buttons, 1, 0); + nmt_newt_widget_set_padding (buttons, 1, 1, 0, 1); + nmt_newt_grid_set_flags (grid, buttons, + NMT_NEWT_GRID_FILL_X | NMT_NEWT_GRID_FILL_Y | + NMT_NEWT_GRID_EXPAND_Y); + + priv->add = nmt_newt_button_box_add_start (priv->buttons, _("Add")); + g_signal_connect (priv->add, "clicked", G_CALLBACK (add_clicked), list); + + priv->edit = nmt_newt_button_box_add_start (priv->buttons, _("Edit...")); + g_signal_connect (priv->edit, "clicked", G_CALLBACK (edit_clicked), list); + + priv->delete = nmt_newt_button_box_add_start (priv->buttons, _("Delete")); + g_signal_connect (priv->delete, "clicked", G_CALLBACK (delete_clicked), list); +} + +static int +sort_by_timestamp (gconstpointer a, + gconstpointer b) +{ + NMSettingConnection *s_con_a, *s_con_b; + guint64 time_a, time_b; + + s_con_a = nm_connection_get_setting_connection ((NMConnection *) a); + s_con_b = nm_connection_get_setting_connection ((NMConnection *) b); + + time_a = nm_setting_connection_get_timestamp (s_con_a); + time_b = nm_setting_connection_get_timestamp (s_con_b); + + return (int) (time_b - time_a); +} + +static void nmt_edit_connection_list_rebuild (NmtEditConnectionList *list); + +static void +rebuild_on_connection_changed (NMRemoteConnection *connection, + gpointer list) +{ + nmt_edit_connection_list_rebuild (list); +} + +static void +free_connections (NmtEditConnectionList *list) +{ + NmtEditConnectionListPrivate *priv = NMT_EDIT_CONNECTION_LIST_GET_PRIVATE (list); + NMConnection *conn; + GSList *iter; + + for (iter = priv->connections; iter; iter = iter->next) { + conn = iter->data; + + g_signal_handlers_disconnect_by_func (conn, G_CALLBACK (rebuild_on_connection_changed), list); + g_object_unref (conn); + } + g_slist_free (priv->connections); + priv->connections = NULL; +} + +static void +nmt_edit_connection_list_rebuild (NmtEditConnectionList *list) +{ + NmtEditConnectionListPrivate *priv = NMT_EDIT_CONNECTION_LIST_GET_PRIVATE (list); + const GPtrArray *connections; + GSList *iter; + gboolean did_header = FALSE, did_vpn = FALSE; + NMEditorConnectionTypeData **types; + NMConnection *conn, *selected_conn; + int i, row, selected_row; + + selected_row = nmt_newt_listbox_get_active (priv->listbox); + selected_conn = nmt_newt_listbox_get_active_key (priv->listbox); + + free_connections (list); + connections = nm_client_get_connections (nm_client); + for (i = 0; i < connections->len; i++) { + conn = connections->pdata[i]; + + if ( priv->connection_filter + && !priv->connection_filter (list, conn, priv->connection_filter_data)) + continue; + + g_signal_connect (conn, NM_CONNECTION_CHANGED, + G_CALLBACK (rebuild_on_connection_changed), list); + priv->connections = g_slist_prepend (priv->connections, g_object_ref (conn)); + } + priv->connections = g_slist_sort (priv->connections, sort_by_timestamp); + g_object_notify (G_OBJECT (list), "connections"); + g_object_notify (G_OBJECT (list), "num-connections"); + + nmt_newt_component_set_sensitive (NMT_NEWT_COMPONENT (priv->edit), + priv->connections != NULL); + nmt_newt_component_set_sensitive (NMT_NEWT_COMPONENT (priv->delete), + priv->connections != NULL); + + nmt_newt_listbox_clear (priv->listbox); + + if (!priv->grouped) { + /* Just add the connections in order */ + for (iter = priv->connections, row = 0; iter; iter = iter->next, row++) { + conn = iter->data; + nmt_newt_listbox_append (priv->listbox, nm_connection_get_id (conn), conn); + if (conn == selected_conn) + selected_row = row; + } + if (selected_row >= row) + selected_row = row - 1; + nmt_newt_listbox_set_active (priv->listbox, selected_row); + + return; + } + + types = nm_editor_utils_get_connection_type_list (); + for (i = row = 0; types[i]; i++) { + if (types[i]->setting_type == NM_TYPE_SETTING_VPN) { + if (did_vpn) + continue; + did_vpn = TRUE; + } + + did_header = FALSE; + + for (iter = priv->connections; iter; iter = iter->next) { + NMSetting *setting; + char *indented; + + conn = iter->data; + setting = nm_connection_get_setting (conn, types[i]->setting_type); + if (!setting) + continue; + if (!nm_connection_is_type (conn, nm_setting_get_name (setting))) + continue; + + if (!did_header) { + nmt_newt_listbox_append (priv->listbox, types[i]->name, NULL); + if (row == selected_row) + selected_row++; + row++; + did_header = TRUE; + } + + indented = g_strdup_printf (" %s", nm_connection_get_id (conn)); + nmt_newt_listbox_append (priv->listbox, indented, conn); + g_free (indented); + + if (conn == selected_conn) + selected_row = row; + row++; + } + } + + if (selected_row >= row) + selected_row = row - 1; + nmt_newt_listbox_set_active (priv->listbox, selected_row); +} + +static void +rebuild_on_connections_changed (GObject *object, + GParamSpec *pspec, + gpointer list) +{ + nmt_edit_connection_list_rebuild (list); +} + +static void +nmt_edit_connection_list_constructed (GObject *object) +{ + NmtEditConnectionList *list = NMT_EDIT_CONNECTION_LIST (object); + NmtEditConnectionListPrivate *priv = NMT_EDIT_CONNECTION_LIST_GET_PRIVATE (list); + + if (priv->extra) + nmt_newt_button_box_add_widget_end (priv->buttons, priv->extra); + + g_signal_connect (nm_client, "notify::" NM_CLIENT_CONNECTIONS, + G_CALLBACK (rebuild_on_connections_changed), list); + + nmt_edit_connection_list_rebuild (list); + + G_OBJECT_CLASS (nmt_edit_connection_list_parent_class)->constructed (object); +} + +static void +add_clicked (NmtNewtButton *button, gpointer list) +{ + g_signal_emit (list, signals[ADD_CONNECTION], 0); +} + +static void +edit_clicked (NmtNewtButton *button, gpointer list) +{ + NmtEditConnectionListPrivate *priv = NMT_EDIT_CONNECTION_LIST_GET_PRIVATE (list); + NMConnection *connection; + + connection = nmt_newt_listbox_get_active_key (priv->listbox); + g_return_if_fail (connection != NULL); + + g_signal_emit (list, signals[EDIT_CONNECTION], 0, connection); +} + +static void +delete_clicked (NmtNewtButton *button, gpointer list) +{ + NmtEditConnectionListPrivate *priv = NMT_EDIT_CONNECTION_LIST_GET_PRIVATE (list); + NMRemoteConnection *connection; + + connection = nmt_newt_listbox_get_active_key (priv->listbox); + g_return_if_fail (connection != NULL); + + g_signal_emit (list, signals[REMOVE_CONNECTION], 0, connection); +} + +static void +listbox_activated (NmtNewtWidget *listbox, gpointer list) +{ + NmtEditConnectionListPrivate *priv = NMT_EDIT_CONNECTION_LIST_GET_PRIVATE (list); + + edit_clicked (NMT_NEWT_BUTTON (priv->edit), list); +} + +static void +nmt_edit_connection_list_finalize (GObject *object) +{ + NmtEditConnectionListPrivate *priv = NMT_EDIT_CONNECTION_LIST_GET_PRIVATE (object); + + free_connections (NMT_EDIT_CONNECTION_LIST (object)); + g_clear_object (&priv->extra); + + G_OBJECT_CLASS (nmt_edit_connection_list_parent_class)->finalize (object); +} + +static void +nmt_edit_connection_list_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtEditConnectionListPrivate *priv = NMT_EDIT_CONNECTION_LIST_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_GROUPED: + priv->grouped = g_value_get_boolean (value); + break; + case PROP_CONNECTION_FILTER: + priv->connection_filter = g_value_get_pointer (value); + break; + case PROP_CONNECTION_FILTER_DATA: + priv->connection_filter_data = g_value_get_pointer (value); + break; + case PROP_EXTRA_WIDGET: + priv->extra = g_value_get_object (value); + if (priv->extra) + g_object_ref_sink (priv->extra); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_edit_connection_list_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtEditConnectionListPrivate *priv = NMT_EDIT_CONNECTION_LIST_GET_PRIVATE (object); + GPtrArray *connections; + GSList *iter; + + switch (prop_id) { + case PROP_GROUPED: + g_value_set_boolean (value, priv->grouped); + break; + case PROP_CONNECTION_FILTER: + g_value_set_pointer (value, priv->connection_filter); + break; + case PROP_CONNECTION_FILTER_DATA: + g_value_set_pointer (value, priv->connection_filter_data); + break; + case PROP_EXTRA_WIDGET: + g_value_set_object (value, priv->extra); + break; + case PROP_CONNECTIONS: + connections = g_ptr_array_new_with_free_func (g_object_unref); + for (iter = priv->connections; iter; iter = iter->next) + g_ptr_array_add (connections, g_object_ref (iter->data)); + g_value_take_boxed (value, connections); + break; + case PROP_NUM_CONNECTIONS: + g_value_set_int (value, g_slist_length (priv->connections)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_edit_connection_list_class_init (NmtEditConnectionListClass *list_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (list_class); + + g_type_class_add_private (list_class, sizeof (NmtEditConnectionListPrivate)); + + /* virtual methods */ + object_class->constructed = nmt_edit_connection_list_constructed; + object_class->set_property = nmt_edit_connection_list_set_property; + object_class->get_property = nmt_edit_connection_list_get_property; + object_class->finalize = nmt_edit_connection_list_finalize; + + /* signals */ + + /** + * NmtEditConnectionList::add-connection: + * @list: the #NmtEditConnectionList + * + * Emitted when the user clicks the list's "Add" button. + */ + signals[ADD_CONNECTION] = + g_signal_new ("add-connection", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NmtEditConnectionListClass, add_connection), + NULL, NULL, NULL, + G_TYPE_NONE, 0); + + /** + * NmtEditConnectionList::edit-connection: + * @list: the #NmtEditConnectionList + * @connection: the connection to edit + * + * Emitted when the user clicks the list's "Edit" button, or + * hits "Return" on the listbox. + */ + signals[EDIT_CONNECTION] = + g_signal_new ("edit-connection", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NmtEditConnectionListClass, edit_connection), + NULL, NULL, NULL, + G_TYPE_NONE, 1, + NM_TYPE_CONNECTION); + + /** + * NmtEditConnectionList::remove-connection: + * @list: the #NmtEditConnectionList + * @connection: the connection to remove + * + * Emitted when the user clicks the list's "Delete" button. + */ + signals[REMOVE_CONNECTION] = + g_signal_new ("remove-connection", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NmtEditConnectionListClass, remove_connection), + NULL, NULL, NULL, + G_TYPE_NONE, 1, + NM_TYPE_CONNECTION); + + /* properties */ + + /** + * NmtEditConnectionList:grouped: + * + * If %TRUE, connections should be grouped by type, with headers + * indicating the types (as in the main connection list). If %FALSE, + * they will not be grouped (as in slave connection lists). + */ + g_object_class_install_property + (object_class, PROP_GROUPED, + g_param_spec_boolean ("grouped", "", "", + TRUE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + /** + * NmtEditConnectionListFilter: + * @list: the #NmtEditConnectionList + * @connection: an #NMConnection + * @user_data: the user data + * + * Decides whether @connection should be displayed in @list. + * + * Returns: %TRUE or %FALSE + */ + /** + * NmtEditConnectionList:connection-filter: + * + * A callback function for filtering which connections appear in + * the list. + */ + g_object_class_install_property + (object_class, PROP_CONNECTION_FILTER, + g_param_spec_pointer ("connection-filter", "", "", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtEditConnectionList:connection-filter-data: + * + * Data for the #NmtEditConnectionList:connection-filter. + */ + g_object_class_install_property + (object_class, PROP_CONNECTION_FILTER_DATA, + g_param_spec_pointer ("connection-filter-data", "", "", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + /** + * NmtEditConnectionList:extra-widget: + * + * An extra button widget to display at the bottom of the button + * box. + */ + g_object_class_install_property + (object_class, PROP_EXTRA_WIDGET, + g_param_spec_object ("extra-widget", "", "", + NMT_TYPE_NEWT_WIDGET, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + /** + * NmtEditConnectionList:connections: + * + * The list of connections in the widget. + * + * Element-Type: #NMConnection + */ + g_object_class_install_property + (object_class, PROP_CONNECTIONS, + g_param_spec_boxed ("connections", "", "", + G_TYPE_PTR_ARRAY, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NmtEditConnectionList:num-connections: + * + * The number of connections in the widget. + */ + g_object_class_install_property + (object_class, PROP_NUM_CONNECTIONS, + g_param_spec_int ("num-connections", "", "", + 0, G_MAXINT, 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/nmt-edit-connection-list.h b/clients/tui/nmt-edit-connection-list.h new file mode 100644 index 00000000..c31c0a8c --- /dev/null +++ b/clients/tui/nmt-edit-connection-list.h @@ -0,0 +1,59 @@ +/* -*- 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. + */ + +#ifndef NMT_EDIT_CONNECTION_LIST_H +#define NMT_EDIT_CONNECTION_LIST_H + +#include "nmt-newt.h" + +#include <NetworkManager.h> + +G_BEGIN_DECLS + +#define NMT_TYPE_EDIT_CONNECTION_LIST (nmt_edit_connection_list_get_type ()) +#define NMT_EDIT_CONNECTION_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_EDIT_CONNECTION_LIST, NmtEditConnectionList)) +#define NMT_EDIT_CONNECTION_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_EDIT_CONNECTION_LIST, NmtEditConnectionListClass)) +#define NMT_IS_EDIT_CONNECTION_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_EDIT_CONNECTION_LIST)) +#define NMT_IS_EDIT_CONNECTION_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_EDIT_CONNECTION_LIST)) +#define NMT_EDIT_CONNECTION_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_EDIT_CONNECTION_LIST, NmtEditConnectionListClass)) + +typedef struct { + NmtNewtGrid parent; + +} NmtEditConnectionList; + +typedef struct { + NmtNewtGridClass parent; + + /* signals */ + void (*add_connection) (NmtEditConnectionList *list); + void (*edit_connection) (NmtEditConnectionList *list, + NMConnection *connection); + void (*remove_connection) (NmtEditConnectionList *list, + NMRemoteConnection *connection); +} NmtEditConnectionListClass; + +GType nmt_edit_connection_list_get_type (void); + +typedef gboolean (*NmtEditConnectionListFilter) (NmtEditConnectionList *list, + NMConnection *connection, + gpointer user_data); + +G_END_DECLS + +#endif /* NMT_EDIT_CONNECTION_LIST_H */ diff --git a/clients/tui/nmt-editor-grid.c b/clients/tui/nmt-editor-grid.c new file mode 100644 index 00000000..118bf01d --- /dev/null +++ b/clients/tui/nmt-editor-grid.c @@ -0,0 +1,463 @@ +/* -*- 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-editor-grid + * @short_description: Grid widget for #NmtEditorPages + * + * #NmtEditorGrid is the layout grid used by #NmtEditorPages. It + * consists of a number of rows, each containing either a single + * widget that spans the entire width of the row, or else containing a + * label, a widget, and an optional extra widget. + * + * Each row of the grid can take up multiple on-screen rows, if + * its main widget is multiple rows high. The label and extra widgets + * will be top-aligned if the row is taller than they are. + * + * The #NmtEditorGrids in a form behave as though they are all in a + * "size group" together; they will all use the same column widths, + * which will be wide enough for the widest labels/widgets in any of + * the grids. #NmtEditorGrid is also specially aware of #NmtNewtSection, + * and grids inside sections will automatically take the size of the + * section border into account as well. + */ + +#include "config.h" + +#include <string.h> + +#include "nmt-editor-grid.h" + +G_DEFINE_TYPE (NmtEditorGrid, nmt_editor_grid, NMT_TYPE_NEWT_CONTAINER) + +#define NMT_EDITOR_GRID_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_EDITOR_GRID, NmtEditorGridPrivate)) + +typedef struct { + GArray *rows; + int *row_heights; + int indent; +} NmtEditorGridPrivate; + +typedef struct { + NmtNewtWidget *label; + NmtNewtWidget *widget; + NmtNewtWidget *extra; + NmtEditorGridRowFlags flags; +} NmtEditorGridRow; + +typedef struct { + int col_widths[3]; +} NmtEditorGridFormState; + +/** + * nmt_editor_grid_new: + * + * Creates a new #NmtEditorGrid + * + * Returns: a new #NmtEditorGrid + */ +NmtNewtWidget * +nmt_editor_grid_new (void) +{ + return g_object_new (NMT_TYPE_EDITOR_GRID, + NULL); +} + +static void +nmt_editor_grid_init (NmtEditorGrid *grid) +{ + NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (grid); + + priv->rows = g_array_new (FALSE, TRUE, sizeof (NmtEditorGridRow)); +} + +static void +nmt_editor_grid_finalize (GObject *object) +{ + NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (object); + + g_array_unref (priv->rows); + g_clear_pointer (&priv->row_heights, g_free); + + G_OBJECT_CLASS (nmt_editor_grid_parent_class)->finalize (object); +} + +/** + * nmt_editor_grid_append: + * @grid: the #NmtEditorGrid + * @label: (allow-none): the label text for @widget, or %NULL + * @widget: (allow-none): the (main) widget + * @extra: (allow-none): optional extra widget + * + * Adds a row to @grid. + * + * If @label and @widget are both non-%NULL, this will add a three-column row, + * containing a right-aligned #NmtNewtLabel in the first column, @widget in the + * second column, and @extra (if non-%NULL) in the third column. + * + * If either @label or @widget is %NULL, then the other column will expand into + * it. + * + * See also nmt_editor_grid_set_row_flags(). + */ +void +nmt_editor_grid_append (NmtEditorGrid *grid, + const char *label, + NmtNewtWidget *widget, + NmtNewtWidget *extra) +{ + NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (grid); + NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_editor_grid_parent_class); + NmtNewtContainer *container = NMT_NEWT_CONTAINER (grid); + NmtEditorGridRow row; + + g_return_if_fail (label != NULL || widget != NULL); + + memset (&row, 0, sizeof (row)); + + if (label && !widget) { + widget = nmt_newt_label_new (label); + label = NULL; + } + + if (label) { + row.label = nmt_newt_label_new (label); + parent_class->add (container, row.label); + } + + row.widget = widget; + parent_class->add (container, widget); + if (row.label) { + g_object_bind_property (row.widget, "valid", + row.label, "highlight", + G_BINDING_INVERT_BOOLEAN | G_BINDING_SYNC_CREATE); + } + + if (extra) { + row.extra = extra; + parent_class->add (container, extra); + } + + g_array_append_val (priv->rows, row); +} + +static int +nmt_editor_grid_find_widget (NmtEditorGrid *grid, + NmtNewtWidget *widget) +{ + NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (grid); + NmtEditorGridRow *rows = (NmtEditorGridRow *) priv->rows->data; + int i; + + for (i = 0; i < priv->rows->len; i++) { + if (rows[i].label == widget || rows[i].widget == widget || rows[i].extra == widget) + return i; + } + + return -1; +} + +/** + * NmtEditorGridRowFlags: + * @NMT_EDITOR_GRID_ROW_LABEL_ALIGN_LEFT: the row's label should be + * aligned left instead of right. + * @NMT_EDITOR_GRID_ROW_EXTRA_ALIGN_RIGHT: the row's extra widget + * should be aligned right instead of left. + * + * Flags to alter an #NmtEditorGrid row's layout. + */ + +/** + * nmt_editor_grid_set_row_flags: + * @grid: an #NmtEditorGrid + * @widget: the widget whose row you want to adjust + * @flags: the flags to set + * + * Sets flags to adjust the layout of @widget's row in @grid. + */ +void +nmt_editor_grid_set_row_flags (NmtEditorGrid *grid, + NmtNewtWidget *widget, + NmtEditorGridRowFlags flags) +{ + NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (grid); + NmtEditorGridRow *rows = (NmtEditorGridRow *) priv->rows->data; + int i; + + i = nmt_editor_grid_find_widget (grid, widget); + if (i != -1) + rows[i].flags = flags; +} + +static void +nmt_editor_grid_remove (NmtNewtContainer *container, + NmtNewtWidget *widget) +{ + NmtEditorGrid *grid = NMT_EDITOR_GRID (container); + NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (grid); + NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_editor_grid_parent_class); + NmtEditorGridRow *rows = (NmtEditorGridRow *) priv->rows->data; + int i; + + i = nmt_editor_grid_find_widget (grid, widget); + if (i != -1) { + if (rows[i].label) + parent_class->remove (container, rows[i].label); + parent_class->remove (container, rows[i].widget); + if (rows[i].extra) + parent_class->remove (container, rows[i].extra); + + g_array_remove_index (priv->rows, i); + return; + } + + // FIXME: shouldn't happen + parent_class->remove (container, widget); +} + +static newtComponent * +nmt_editor_grid_get_components (NmtNewtWidget *widget) +{ + NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (widget); + NmtEditorGridRow *rows = (NmtEditorGridRow *) priv->rows->data; + newtComponent *child_cos; + GPtrArray *cos; + int i, c; + + cos = g_ptr_array_new (); + + for (i = 0; i < priv->rows->len; i++) { + if (!nmt_newt_widget_get_visible (rows[i].widget)) + continue; + + if (rows[i].label) { + child_cos = nmt_newt_widget_get_components (rows[i].label); + g_assert (child_cos[0] && !child_cos[1]); + g_ptr_array_add (cos, child_cos[0]); + g_free (child_cos); + } + + child_cos = nmt_newt_widget_get_components (rows[i].widget); + for (c = 0; child_cos[c]; c++) + g_ptr_array_add (cos, child_cos[c]); + g_free (child_cos); + + if (rows[i].extra) { + child_cos = nmt_newt_widget_get_components (rows[i].extra); + for (c = 0; child_cos[c]; c++) + g_ptr_array_add (cos, child_cos[c]); + g_free (child_cos); + } + } + + g_ptr_array_add (cos, NULL); + return (newtComponent *) g_ptr_array_free (cos, FALSE); +} + +static NmtEditorGridFormState * +get_form_state (NmtNewtWidget *widget) +{ + NmtNewtForm *form = nmt_newt_widget_get_form (widget); + NmtEditorGridFormState *state; + + if (!form) + return NULL; + + state = g_object_get_data (G_OBJECT (form), "NmtEditorGridFormState"); + if (state) + return state; + + state = g_new0 (NmtEditorGridFormState, 1); + g_object_set_data_full (G_OBJECT (form), "NmtEditorGridFormState", state, g_free); + return state; +} + +static void +nmt_editor_grid_realize (NmtNewtWidget *widget) +{ + NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (widget); + NmtNewtWidget *parent; + + NMT_NEWT_WIDGET_CLASS (nmt_editor_grid_parent_class)->realize (widget); + + /* This is a hack, but it's the simplest way to make it work... */ + priv->indent = 0; + + parent = nmt_newt_widget_get_parent (widget); + while (parent) { + if (NMT_IS_NEWT_SECTION (parent)) { + priv->indent = 2; + break; + } + parent = nmt_newt_widget_get_parent (parent); + } +} + +static void +nmt_editor_grid_unrealize (NmtNewtWidget *widget) +{ + NmtEditorGridFormState *state = get_form_state (widget); + + if (state) + memset (state->col_widths, 0, sizeof (state->col_widths)); + + NMT_NEWT_WIDGET_CLASS (nmt_editor_grid_parent_class)->unrealize (widget); +} + +static void +nmt_editor_grid_size_request (NmtNewtWidget *widget, + int *width, + int *height) +{ + NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (widget); + NmtEditorGridRow *rows = (NmtEditorGridRow *) priv->rows->data; + NmtEditorGridFormState *state = get_form_state (widget); + gboolean add_padding = FALSE; + int i; + + g_free (priv->row_heights); + priv->row_heights = g_new0 (int, priv->rows->len); + + *height = 0; + for (i = 0; i < priv->rows->len; i++) { + int lwidth, lheight, wwidth, wheight, ewidth, eheight; + + if (!nmt_newt_widget_get_visible (rows[i].widget)) + continue; + + if (rows[i].label) { + nmt_newt_widget_size_request (rows[i].label, &lwidth, &lheight); + lwidth += priv->indent; + state->col_widths[0] = MAX (state->col_widths[0], lwidth); + + nmt_newt_widget_size_request (rows[i].widget, &wwidth, &wheight); + state->col_widths[1] = MAX (state->col_widths[1], wwidth); + priv->row_heights[i] = wheight; + + add_padding = TRUE; + } else { + nmt_newt_widget_size_request (rows[i].widget, &wwidth, &wheight); + priv->row_heights[i] = wheight; + } + + if (rows[i].extra) { + nmt_newt_widget_size_request (rows[i].extra, &ewidth, &eheight); + state->col_widths[2] = MAX (state->col_widths[2], ewidth); + priv->row_heights[i] = MAX (priv->row_heights[i], eheight); + } + + *height += priv->row_heights[i]; + } + + *width = state->col_widths[0] + state->col_widths[1] + state->col_widths[2]; + if (add_padding) + *width += 2; +} + + +static void +nmt_editor_grid_size_allocate (NmtNewtWidget *widget, + int x, + int y, + int width, + int height) +{ + NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (widget); + NmtEditorGridRow *rows = (NmtEditorGridRow *) priv->rows->data; + NmtEditorGridFormState *state = get_form_state (widget); + int col0_width, col1_width, col2_width; + int i, row; + + col0_width = state->col_widths[0] - priv->indent; + col1_width = state->col_widths[1]; + col2_width = state->col_widths[2]; + + for (i = row = 0; i < priv->rows->len; i++) { + if (!nmt_newt_widget_get_visible (rows[i].widget)) + continue; + + if (rows[i].label) { + int lwidth, lheight, lx; + + if (rows[i].flags & NMT_EDITOR_GRID_ROW_LABEL_ALIGN_LEFT) + lx = x; + else { + nmt_newt_widget_size_request (rows[i].label, &lwidth, &lheight); + lx = x + col0_width - lwidth; + } + + nmt_newt_widget_size_allocate (rows[i].label, + lx, + y + row, + col0_width, + priv->row_heights[i]); + + nmt_newt_widget_size_allocate (rows[i].widget, + x + col0_width + 1, + y + row, + col1_width, + priv->row_heights[i]); + } else { + nmt_newt_widget_size_allocate (rows[i].widget, + x, + y + row, + col0_width + col1_width + 1, + priv->row_heights[i]); + } + + if (rows[i].extra) { + int wwidth, wheight, ex; + + if (rows[i].flags & NMT_EDITOR_GRID_ROW_EXTRA_ALIGN_RIGHT) + ex = x + col0_width + col1_width + 2; + else { + nmt_newt_widget_size_request (rows[i].widget, &wwidth, &wheight); + ex = x + col0_width + wwidth + 2; + } + + nmt_newt_widget_size_allocate (rows[i].extra, + ex, + y + row, + col2_width, + priv->row_heights[i]); + } + + row += priv->row_heights[i]; + } +} + +static void +nmt_editor_grid_class_init (NmtEditorGridClass *grid_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (grid_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (grid_class); + NmtNewtContainerClass *container_class = NMT_NEWT_CONTAINER_CLASS (grid_class); + + g_type_class_add_private (grid_class, sizeof (NmtEditorGridPrivate)); + + /* virtual methods */ + object_class->finalize = nmt_editor_grid_finalize; + + widget_class->realize = nmt_editor_grid_realize; + widget_class->unrealize = nmt_editor_grid_unrealize; + widget_class->get_components = nmt_editor_grid_get_components; + widget_class->size_request = nmt_editor_grid_size_request; + widget_class->size_allocate = nmt_editor_grid_size_allocate; + + container_class->remove = nmt_editor_grid_remove; +} diff --git a/clients/tui/nmt-editor-grid.h b/clients/tui/nmt-editor-grid.h new file mode 100644 index 00000000..2ae01d71 --- /dev/null +++ b/clients/tui/nmt-editor-grid.h @@ -0,0 +1,62 @@ +/* -*- 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. + */ + +#ifndef NMT_EDITOR_GRID_H +#define NMT_EDITOR_GRID_H + +#include "nmt-newt.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_EDITOR_GRID (nmt_editor_grid_get_type ()) +#define NMT_EDITOR_GRID(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_EDITOR_GRID, NmtEditorGrid)) +#define NMT_EDITOR_GRID_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_EDITOR_GRID, NmtEditorGridClass)) +#define NMT_IS_EDITOR_GRID(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_EDITOR_GRID)) +#define NMT_IS_EDITOR_GRID_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_EDITOR_GRID)) +#define NMT_EDITOR_GRID_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_EDITOR_GRID, NmtEditorGridClass)) + +typedef struct { + NmtNewtContainer parent; + +} NmtEditorGrid; + +typedef struct { + NmtNewtContainerClass parent; + +} NmtEditorGridClass; + +GType nmt_editor_grid_get_type (void); + +typedef enum { + NMT_EDITOR_GRID_ROW_LABEL_ALIGN_LEFT = (1 << 0), + NMT_EDITOR_GRID_ROW_EXTRA_ALIGN_RIGHT = (1 << 1) +} NmtEditorGridRowFlags; + +NmtNewtWidget *nmt_editor_grid_new (void); + +void nmt_editor_grid_append (NmtEditorGrid *grid, + const char *label, + NmtNewtWidget *widget, + NmtNewtWidget *extra); +void nmt_editor_grid_set_row_flags (NmtEditorGrid *grid, + NmtNewtWidget *widget, + NmtEditorGridRowFlags flags); + +G_END_DECLS + +#endif /* NMT_EDITOR_GRID_H */ diff --git a/clients/tui/nmt-editor-page-device.c b/clients/tui/nmt-editor-page-device.c new file mode 100644 index 00000000..0a9b18e0 --- /dev/null +++ b/clients/tui/nmt-editor-page-device.c @@ -0,0 +1,131 @@ +/* -*- 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-editor-page-device + * @short_description: Abstract base class for "device" editor pages + * + * #NmtEditorPageDevice is the base class for #NmtEditorPage subclasses + * representing device-type-specific data. (Eg, #NmtPageEthernet, + * #NmtPageVlan, etc). + * + * FIXME: rename to NmtEditorPageDevice, so it doesn't sound like it's + * an actual page type. + */ + +#include "config.h" + +#include "nmt-editor-page-device.h" + +G_DEFINE_TYPE (NmtEditorPageDevice, nmt_editor_page_device, NMT_TYPE_EDITOR_PAGE) + +#define NMT_EDITOR_PAGE_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_EDITOR_PAGE_DEVICE, NmtEditorPageDevicePrivate)) + +typedef struct { + NmtDeviceEntry *device_entry; + gboolean show_by_default; +} NmtEditorPageDevicePrivate; + +enum { + PROP_0, + + PROP_DEVICE_ENTRY, + + LAST_PROP +}; + +static void +nmt_editor_page_device_init (NmtEditorPageDevice *device) +{ +} + +static void +nmt_editor_page_device_finalize (GObject *object) +{ + NmtEditorPageDevicePrivate *priv = NMT_EDITOR_PAGE_DEVICE_GET_PRIVATE (object); + + g_clear_object (&priv->device_entry); + + G_OBJECT_CLASS (nmt_editor_page_device_parent_class)->finalize (object); +} + +NmtDeviceEntry * +nmt_editor_page_device_get_device_entry (NmtEditorPageDevice *page) +{ + NmtEditorPageDevicePrivate *priv = NMT_EDITOR_PAGE_DEVICE_GET_PRIVATE (page); + + return priv->device_entry; +} + +static void +nmt_editor_page_device_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtEditorPageDevicePrivate *priv = NMT_EDITOR_PAGE_DEVICE_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_DEVICE_ENTRY: + priv->device_entry = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_editor_page_device_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtEditorPageDevicePrivate *priv = NMT_EDITOR_PAGE_DEVICE_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_DEVICE_ENTRY: + g_value_set_object (value, priv->device_entry); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_editor_page_device_class_init (NmtEditorPageDeviceClass *page_device_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (page_device_class); + + g_type_class_add_private (page_device_class, sizeof (NmtEditorPageDevicePrivate)); + + /* virtual methods */ + object_class->set_property = nmt_editor_page_device_set_property; + object_class->get_property = nmt_editor_page_device_get_property; + object_class->finalize = nmt_editor_page_device_finalize; + + /* properties */ + g_object_class_install_property + (object_class, PROP_DEVICE_ENTRY, + g_param_spec_object ("device-entry", "", "", + NMT_TYPE_DEVICE_ENTRY, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/nmt-editor-page-device.h b/clients/tui/nmt-editor-page-device.h new file mode 100644 index 00000000..f911602c --- /dev/null +++ b/clients/tui/nmt-editor-page-device.h @@ -0,0 +1,50 @@ +/* -*- 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. + */ + +#ifndef NMT_EDITOR_PAGE_DEVICE_H +#define NMT_EDITOR_PAGE_DEVICE_H + +#include "nmt-editor-page.h" +#include "nmt-device-entry.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_EDITOR_PAGE_DEVICE (nmt_editor_page_device_get_type ()) +#define NMT_EDITOR_PAGE_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_EDITOR_PAGE_DEVICE, NmtEditorPageDevice)) +#define NMT_EDITOR_PAGE_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_EDITOR_PAGE_DEVICE, NmtEditorPageDeviceClass)) +#define NMT_IS_EDITOR_PAGE_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_EDITOR_PAGE_DEVICE)) +#define NMT_IS_EDITOR_PAGE_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_EDITOR_PAGE_DEVICE)) +#define NMT_EDITOR_PAGE_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_EDITOR_PAGE_DEVICE, NmtEditorPageDeviceClass)) + +typedef struct { + NmtEditorPage parent; + +} NmtEditorPageDevice; + +typedef struct { + NmtEditorPageClass parent; + +} NmtEditorPageDeviceClass; + +GType nmt_editor_page_device_get_type (void); + +NmtDeviceEntry *nmt_editor_page_device_get_device_entry (NmtEditorPageDevice *page); + +G_END_DECLS + +#endif /* NMT_EDITOR_PAGE_DEVICE_H */ diff --git a/clients/tui/nmt-editor-page.c b/clients/tui/nmt-editor-page.c new file mode 100644 index 00000000..a46d0ed4 --- /dev/null +++ b/clients/tui/nmt-editor-page.c @@ -0,0 +1,179 @@ +/* -*- 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-editor-page: + * @short_description: An #NmtEditor "page" + * + * #NmtEditorPage is the abstract base class for #NmtEditor "pages". + * A "page" is a set of related #NmtEditorSections. + */ + +#include "config.h" + +#include <glib/gi18n-lib.h> + +#include "nmt-editor-page.h" + +G_DEFINE_ABSTRACT_TYPE (NmtEditorPage, nmt_editor_page, G_TYPE_OBJECT) + +#define NMT_EDITOR_PAGE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_EDITOR_PAGE, NmtEditorPagePrivate)) + +typedef struct { + NMConnection *connection; + GSList *sections; + +} NmtEditorPagePrivate; + +enum { + PROP_0, + + PROP_CONNECTION, + + LAST_PROP +}; + +static void +nmt_editor_page_init (NmtEditorPage *page) +{ +} + +static void +nmt_editor_page_finalize (GObject *object) +{ + NmtEditorPagePrivate *priv = NMT_EDITOR_PAGE_GET_PRIVATE (object); + + g_clear_object (&priv->connection); + g_slist_free_full (priv->sections, g_object_unref); + + G_OBJECT_CLASS (nmt_editor_page_parent_class)->finalize (object); +} + +/** + * nmt_editor_page_get_connection: + * @page: the #NmtEditorPage + * + * Gets the page's #NMConnection. + * + * Returns: (transfer none): the page's #NMConnection. + */ +NMConnection * +nmt_editor_page_get_connection (NmtEditorPage *page) +{ + NmtEditorPagePrivate *priv = NMT_EDITOR_PAGE_GET_PRIVATE (page); + + return priv->connection; +} + +/** + * nmt_editor_page_get_sections: + * @page: the #NmtEditorPage + * + * Gets the page's list of sections to display. + * + * Returns: (transfer none): the list of sections; this is the internal list + * used by the page and must not be modified or freed. + */ +GSList * +nmt_editor_page_get_sections (NmtEditorPage *page) +{ + NmtEditorPagePrivate *priv = NMT_EDITOR_PAGE_GET_PRIVATE (page); + + return priv->sections; +} + +/** + * nmt_editor_page_add_section: + * @page: the #NmtEditorPage + * @section: the #NmtEditorSection + * + * Adds a section to the page. This should only be called by #NmtEditorPage + * subclasses. + */ +void +nmt_editor_page_add_section (NmtEditorPage *page, + NmtEditorSection *section) +{ + NmtEditorPagePrivate *priv = NMT_EDITOR_PAGE_GET_PRIVATE (page); + + priv->sections = g_slist_append (priv->sections, g_object_ref_sink (section)); +} + +static void +nmt_editor_page_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtEditorPagePrivate *priv = NMT_EDITOR_PAGE_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_CONNECTION: + priv->connection = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_editor_page_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtEditorPagePrivate *priv = NMT_EDITOR_PAGE_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_CONNECTION: + g_value_set_object (value, priv->connection); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_editor_page_class_init (NmtEditorPageClass *page_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (page_class); + + g_type_class_add_private (page_class, sizeof (NmtEditorPagePrivate)); + + /* virtual methods */ + object_class->set_property = nmt_editor_page_set_property; + object_class->get_property = nmt_editor_page_get_property; + object_class->finalize = nmt_editor_page_finalize; + + /* properties */ + + /** + * NmtEditorPage:connection: + * + * The page's #NMConnection. + */ + g_object_class_install_property + (object_class, PROP_CONNECTION, + g_param_spec_object ("connection", "", "", + NM_TYPE_CONNECTION, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/nmt-editor-page.h b/clients/tui/nmt-editor-page.h new file mode 100644 index 00000000..bbc0d9e3 --- /dev/null +++ b/clients/tui/nmt-editor-page.h @@ -0,0 +1,58 @@ +/* -*- 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-2014 Red Hat, Inc. + */ + +#ifndef NMT_EDITOR_PAGE_H +#define NMT_EDITOR_PAGE_H + +#include <NetworkManager.h> + +#include "nmt-editor-grid.h" +#include "nmt-editor-section.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_EDITOR_PAGE (nmt_editor_page_get_type ()) +#define NMT_EDITOR_PAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_EDITOR_PAGE, NmtEditorPage)) +#define NMT_EDITOR_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_EDITOR_PAGE, NmtEditorPageClass)) +#define NMT_IS_EDITOR_PAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_EDITOR_PAGE)) +#define NMT_IS_EDITOR_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_EDITOR_PAGE)) +#define NMT_EDITOR_PAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_EDITOR_PAGE, NmtEditorPageClass)) + +typedef struct { + GObject parent; + +} NmtEditorPage; + +typedef struct { + GObjectClass parent; + +} NmtEditorPageClass; + +GType nmt_editor_page_get_type (void); + +NMConnection *nmt_editor_page_get_connection (NmtEditorPage *page); + +GSList *nmt_editor_page_get_sections (NmtEditorPage *page); + +/*< protected >*/ +void nmt_editor_page_add_section (NmtEditorPage *page, + NmtEditorSection *section); + +G_END_DECLS + +#endif /* NMT_EDITOR_PAGE_H */ diff --git a/clients/tui/nmt-editor-section.c b/clients/tui/nmt-editor-section.c new file mode 100644 index 00000000..ff463f7f --- /dev/null +++ b/clients/tui/nmt-editor-section.c @@ -0,0 +1,282 @@ +/* -*- 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-editor-section: + * @short_description: A section of the #NmtEditor + * + * #NmtEditorSection is the abstract base class for #NmtEditor sections. + */ + +#include "config.h" + +#include <glib/gi18n-lib.h> + +#include "nmt-editor-section.h" +#include "nmt-newt-toggle-button.h" + +G_DEFINE_TYPE (NmtEditorSection, nmt_editor_section, NMT_TYPE_NEWT_SECTION) + +#define NMT_EDITOR_SECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_EDITOR_SECTION, NmtEditorSectionPrivate)) + +typedef struct { + NmtEditorGrid *header, *body; + char *title; + NmtNewtWidget *header_widget; + NmtNewtWidget *toggle; + + gboolean show_by_default; +} NmtEditorSectionPrivate; + +enum { + PROP_0, + + PROP_TITLE, + PROP_SHOW_BY_DEFAULT, + PROP_HEADER_WIDGET, + + LAST_PROP +}; + +/** + * nmt_editor_section_new: + * @title: the section title + * @header_widget: (allow-none): the widget to show next to the title + * @show_by_default: whether the section should be open by default + * + * Creates a new #NmtEditorSection. + * + * Returns: a new #NmtEditorSection + */ +NmtEditorSection * +nmt_editor_section_new (const char *title, + NmtNewtWidget *header_widget, + gboolean show_by_default) +{ + return g_object_new (NMT_TYPE_EDITOR_SECTION, + "title", title, + "header-widget", header_widget, + "show-by-default", show_by_default, + NULL); +} + +static void +rebuild_header (NmtEditorSection *section) +{ + NmtEditorSectionPrivate *priv = NMT_EDITOR_SECTION_GET_PRIVATE (section); + + /* Removing any widget in an NmtEditorGrid removes its whole row, so we can + * remove the existing title/widget/toggle by asking to remove toggle. + */ + nmt_newt_container_remove (NMT_NEWT_CONTAINER (priv->header), priv->toggle); + + nmt_editor_grid_append (priv->header, + priv->title, + priv->header_widget, + priv->toggle); + nmt_editor_grid_set_row_flags (priv->header, + priv->toggle, + NMT_EDITOR_GRID_ROW_LABEL_ALIGN_LEFT | + NMT_EDITOR_GRID_ROW_EXTRA_ALIGN_RIGHT); +} + +static void +nmt_editor_section_init (NmtEditorSection *section) +{ + NmtEditorSectionPrivate *priv = NMT_EDITOR_SECTION_GET_PRIVATE (section); + + priv->header = NMT_EDITOR_GRID (nmt_editor_grid_new ()); + priv->body = NMT_EDITOR_GRID (nmt_editor_grid_new ()); + priv->toggle = nmt_newt_toggle_button_new (_("Hide"), _("Show")); + g_object_ref_sink (priv->toggle); + + nmt_newt_section_set_header (NMT_NEWT_SECTION (section), NMT_NEWT_WIDGET (priv->header)); + nmt_newt_section_set_body (NMT_NEWT_SECTION (section), NMT_NEWT_WIDGET (priv->body)); + + g_object_bind_property (priv->toggle, "active", + section, "open", + G_BINDING_SYNC_CREATE); +} + +static void +nmt_editor_section_finalize (GObject *object) +{ + NmtEditorSectionPrivate *priv = NMT_EDITOR_SECTION_GET_PRIVATE (object); + + g_free (priv->title); + g_clear_object (&priv->header_widget); + g_clear_object (&priv->toggle); + + G_OBJECT_CLASS (nmt_editor_section_parent_class)->finalize (object); +} + +/** + * nmt_editor_section_get_header_widget: + * @section: the #NmtEditorSection + * + * Gets the section's header widget. + * + * Returns: the section's header widget. + */ +NmtNewtWidget * +nmt_editor_section_get_header_widget (NmtEditorSection *section) +{ + NmtEditorSectionPrivate *priv = NMT_EDITOR_SECTION_GET_PRIVATE (section); + + return priv->header_widget; +} + +/** + * nmt_editor_section_get_body: + * @section: the #NmtEditorSection + * + * Gets the section's body grid, so that you can add things to it. + * + * Returns: the #NmtEditorGrid used for the section body + */ +NmtEditorGrid * +nmt_editor_section_get_body (NmtEditorSection *section) +{ + NmtEditorSectionPrivate *priv = NMT_EDITOR_SECTION_GET_PRIVATE (section); + + return priv->body; +} + +/** + * nmt_editor_section_get_title: + * @section: the #NmtEditorSection + * + * Gets the section's title. + * + * Returns: the section's title + */ +const char * +nmt_editor_section_get_title (NmtEditorSection *section) +{ + NmtEditorSectionPrivate *priv = NMT_EDITOR_SECTION_GET_PRIVATE (section); + + return priv->title; +} + +static void +nmt_editor_section_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtEditorSection *section = NMT_EDITOR_SECTION (object); + NmtEditorSectionPrivate *priv = NMT_EDITOR_SECTION_GET_PRIVATE (section); + + switch (prop_id) { + case PROP_TITLE: + priv->title = g_value_dup_string (value); + rebuild_header (section); + break; + case PROP_SHOW_BY_DEFAULT: + priv->show_by_default = g_value_get_boolean (value); + nmt_newt_toggle_button_set_active (NMT_NEWT_TOGGLE_BUTTON (priv->toggle), + priv->show_by_default); + break; + case PROP_HEADER_WIDGET: + priv->header_widget = g_value_get_object (value); + if (priv->header_widget) + g_object_ref_sink (priv->header_widget); + rebuild_header (section); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_editor_section_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtEditorSectionPrivate *priv = NMT_EDITOR_SECTION_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_TITLE: + g_value_set_string (value, priv->title); + break; + case PROP_SHOW_BY_DEFAULT: + g_value_set_boolean (value, priv->show_by_default); + break; + case PROP_HEADER_WIDGET: + g_value_set_object (value, priv->header_widget); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_editor_section_class_init (NmtEditorSectionClass *section_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (section_class); + + g_type_class_add_private (section_class, sizeof (NmtEditorSectionPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_editor_section_set_property; + object_class->get_property = nmt_editor_section_get_property; + object_class->finalize = nmt_editor_section_finalize; + + /* properties */ + + /** + * NmtEditorSection:title: + * + * The section's title. + */ + g_object_class_install_property + (object_class, PROP_TITLE, + g_param_spec_string ("title", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + /** + * NmtEditorSection:show-by-default: + * + * Whether the section should be expanded by default. + */ + g_object_class_install_property + (object_class, PROP_SHOW_BY_DEFAULT, + g_param_spec_boolean ("show-by-default", "", "", + TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NmtEditorSection:header-widget: + * + * The widget (if any) that appears between the section title and its toggle + * button. + */ + g_object_class_install_property + (object_class, PROP_HEADER_WIDGET, + g_param_spec_object ("header-widget", "", "", + NMT_TYPE_NEWT_WIDGET, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/nmt-editor-section.h b/clients/tui/nmt-editor-section.h new file mode 100644 index 00000000..67410c71 --- /dev/null +++ b/clients/tui/nmt-editor-section.h @@ -0,0 +1,56 @@ +/* -*- 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. + */ + +#ifndef NMT_EDITOR_SECTION_H +#define NMT_EDITOR_SECTION_H + +#include "nmt-newt-section.h" +#include "nmt-editor-grid.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_EDITOR_SECTION (nmt_editor_section_get_type ()) +#define NMT_EDITOR_SECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_EDITOR_SECTION, NmtEditorSection)) +#define NMT_EDITOR_SECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_EDITOR_SECTION, NmtEditorSectionClass)) +#define NMT_IS_EDITOR_SECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_EDITOR_SECTION)) +#define NMT_IS_EDITOR_SECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_EDITOR_SECTION)) +#define NMT_EDITOR_SECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_EDITOR_SECTION, NmtEditorSectionClass)) + +typedef struct { + NmtNewtSection parent; + +} NmtEditorSection; + +typedef struct { + NmtNewtSectionClass parent; + +} NmtEditorSectionClass; + +GType nmt_editor_section_get_type (void); + +NmtEditorSection *nmt_editor_section_new (const char *title, + NmtNewtWidget *header_widget, + gboolean show_by_default); + +const char *nmt_editor_section_get_title (NmtEditorSection *section); +NmtNewtWidget *nmt_editor_section_get_header_widget (NmtEditorSection *section); +NmtEditorGrid *nmt_editor_section_get_body (NmtEditorSection *section); + +G_END_DECLS + +#endif /* NMT_EDITOR_SECTION_H */ diff --git a/clients/tui/nmt-editor.c b/clients/tui/nmt-editor.c new file mode 100644 index 00000000..11fe758d --- /dev/null +++ b/clients/tui/nmt-editor.c @@ -0,0 +1,520 @@ +/* -*- 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-editor + * @short_description: Connection editing form + * + * #NmtEditor is the top-level form for editing a connection. + */ + +#include "config.h" + +#include "nmt-editor.h" + +#include <glib.h> +#include <glib/gi18n-lib.h> +#include <nm-utils.h> + +#include "nmtui.h" + +#include "nm-editor-utils.h" +#include "nmt-utils.h" + +#include "nmt-device-entry.h" +#include "nmt-mac-entry.h" +#include "nmt-mtu-entry.h" + +#include "nmt-page-bond.h" +#include "nmt-page-bridge.h" +#include "nmt-page-bridge-port.h" +#include "nmt-page-dsl.h" +#include "nmt-page-ethernet.h" +#include "nmt-page-infiniband.h" +#include "nmt-page-ip4.h" +#include "nmt-page-ip6.h" +#include "nmt-page-ppp.h" +#include "nmt-page-team.h" +#include "nmt-page-team-port.h" +#include "nmt-page-vlan.h" +#include "nmt-page-wifi.h" + +G_DEFINE_TYPE (NmtEditor, nmt_editor, NMT_TYPE_NEWT_FORM) + +#define NMT_EDITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_EDITOR, NmtEditorPrivate)) + +typedef struct { + NMConnection *orig_connection; + NMConnection *edit_connection; + + NMEditorConnectionTypeData *type_data; + + GSList *pages; + NmtNewtWidget *ok, *cancel; + gboolean running; +} NmtEditorPrivate; + +enum { + PROP_0, + PROP_CONNECTION, + PROP_TYPE_DATA, + + LAST_PROP +}; + +/** + * nmt_editor_new: + * @connection: the #NMConnection to edit + * + * Creates a new #NmtEditor to edit @connection. + * + * Returns: a new #NmtEditor + */ +NmtNewtForm * +nmt_editor_new (NMConnection *connection) +{ + NMEditorConnectionTypeData *type_data; + + type_data = nm_editor_utils_get_connection_type_data (connection); + if (!type_data) { + NMSettingConnection *s_con; + + s_con = nm_connection_get_setting_connection (connection); + if (s_con) { + nmt_newt_message_dialog (_("Could not create editor for connection '%s' of type '%s'."), + nm_connection_get_id (connection), + nm_setting_connection_get_connection_type (s_con)); + } else { + nmt_newt_message_dialog (_("Could not create editor for invalid connection '%s'."), + nm_connection_get_id (connection)); + } + + return NULL; + } + + return g_object_new (NMT_TYPE_EDITOR, + "connection", connection, + "type-data", type_data, + "title", _("Edit Connection"), + "fullscreen-vertical", TRUE, + NULL); +} + +static void +nmt_editor_init (NmtEditor *entry) +{ +} + +static void +connection_updated (GObject *connection, + GAsyncResult *result, + gpointer op) +{ + GError *error = NULL; + + nm_remote_connection_commit_changes_finish (NM_REMOTE_CONNECTION (connection), result, &error); + nmt_sync_op_complete_boolean (op, error == NULL, error); + g_clear_error (&error); +} + +static void +connection_added (GObject *client, + GAsyncResult *result, + gpointer op) +{ + NMRemoteConnection *connection; + GError *error = NULL; + + connection = nm_client_add_connection_finish (NM_CLIENT (client), result, &error); + nmt_sync_op_complete_boolean (op, error == NULL, error); + g_clear_object (&connection); + g_clear_error (&error); +} + +static void +save_connection_and_exit (NmtNewtButton *button, + gpointer user_data) +{ + NmtEditor *editor = user_data; + NmtEditorPrivate *priv = NMT_EDITOR_GET_PRIVATE (editor); + NmtSyncOp op; + GError *error = NULL; + + nm_connection_replace_settings_from_connection (priv->orig_connection, + priv->edit_connection); + + nmt_sync_op_init (&op); + if (NM_IS_REMOTE_CONNECTION (priv->orig_connection)) { + nm_remote_connection_commit_changes_async (NM_REMOTE_CONNECTION (priv->orig_connection), + TRUE, NULL, connection_updated, &op); + if (!nmt_sync_op_wait_boolean (&op, &error)) { + nmt_newt_message_dialog (_("Unable to save connection: %s"), + error->message); + g_error_free (error); + return; + } + + /* Clear secrets so they don't lay around in memory; they'll get + * requested again anyway next time the connection is edited. + */ + nm_connection_clear_secrets (priv->orig_connection); + } else { + nm_client_add_connection_async (nm_client, priv->orig_connection, TRUE, + NULL, connection_added, &op); + if (!nmt_sync_op_wait_boolean (&op, &error)) { + nmt_newt_message_dialog (_("Unable to add new connection: %s"), + error->message); + g_error_free (error); + return; + } + } + + nmt_newt_form_quit (NMT_NEWT_FORM (editor)); +} + +static void +got_secrets (GObject *object, + GAsyncResult *result, + gpointer op) +{ + GVariant *secrets; + GError *error = NULL; + + secrets = nm_remote_connection_get_secrets_finish (NM_REMOTE_CONNECTION (object), + result, &error); + if (secrets) + g_variant_ref (secrets); + nmt_sync_op_complete_pointer (op, secrets, error); + g_clear_error (&error); +} + +static NMConnection * +build_edit_connection (NMConnection *orig_connection) +{ + NMConnection *edit_connection; + GVariant *settings, *secrets; + GVariantIter iter; + const char *setting_name; + NmtSyncOp op; + + edit_connection = nm_simple_connection_new_clone (orig_connection); + + if (!NM_IS_REMOTE_CONNECTION (orig_connection)) + return edit_connection; + + settings = nm_connection_to_dbus (orig_connection, NM_CONNECTION_SERIALIZE_NO_SECRETS); + g_variant_iter_init (&iter, settings); + while (g_variant_iter_next (&iter, "{&s@a{sv}}", &setting_name, NULL)) { + nmt_sync_op_init (&op); + nm_remote_connection_get_secrets_async (NM_REMOTE_CONNECTION (orig_connection), + setting_name, NULL, got_secrets, &op); + /* FIXME: error handling */ + secrets = nmt_sync_op_wait_pointer (&op, NULL); + if (secrets) { + (void) nm_connection_update_secrets (edit_connection, setting_name, secrets, NULL); + g_variant_unref (secrets); + } + } + g_variant_unref (settings); + + return edit_connection; +} + +static gboolean +permissions_transform_to_allusers (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + char **perms = g_value_get_boxed (source_value); + + g_value_set_boolean (target_value, g_strv_length (perms) == 0); + return TRUE; +} + +static gboolean +permissions_transform_from_allusers (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + gboolean allusers = g_value_get_boolean (source_value); + char **perms = NULL; + + if (allusers) { + perms = g_new (char *, 2); + + perms[0] = g_strdup_printf ("user:%s:", g_get_user_name ()); + perms[1] = NULL; + } + g_value_take_boxed (target_value, perms); + return TRUE; +} + +static NmtNewtWidget * +add_sections_for_page (NmtEditor *editor, NmtEditorGrid *grid, NmtEditorPage *page) +{ + NmtEditorPrivate *priv = NMT_EDITOR_GET_PRIVATE (editor); + NmtNewtWidget *first_section = NULL; + const GSList *sections, *iter; + + g_return_val_if_fail (NMT_IS_EDITOR_PAGE (page), NULL); + + priv->pages = g_slist_prepend (priv->pages, page); + + sections = nmt_editor_page_get_sections (page); + for (iter = sections; iter; iter = iter->next) { + if (!first_section) + first_section = iter->data; + nmt_editor_grid_append (grid, NULL, iter->data, NULL); + } + + return first_section; +} + +static void +nmt_editor_constructed (GObject *object) +{ + NmtEditor *editor = NMT_EDITOR (object); + NmtEditorPrivate *priv = NMT_EDITOR_GET_PRIVATE (editor); + NMSettingConnection *s_con; + NmtNewtWidget *vbox, *widget, *buttons; + NmtEditorGrid *grid; + const char *deventry_label; + NmtDeviceEntry *deventry; + GType hardware_type; + const char *slave_type; + NmtEditorPage *page; + + if (G_OBJECT_CLASS (nmt_editor_parent_class)->constructed) + G_OBJECT_CLASS (nmt_editor_parent_class)->constructed (object); + + priv->edit_connection = build_edit_connection (priv->orig_connection); + + vbox = nmt_newt_grid_new (); + + s_con = nm_connection_get_setting_connection (priv->edit_connection); + + grid = NMT_EDITOR_GRID (nmt_editor_grid_new ()); + nmt_newt_grid_add (NMT_NEWT_GRID (vbox), NMT_NEWT_WIDGET (grid), 0, 0); + + /* Add the top widgets */ + + widget = nmt_newt_entry_new (40, NMT_NEWT_ENTRY_NONEMPTY); + g_object_bind_property (s_con, NM_SETTING_CONNECTION_ID, + widget, "text", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("Profile name"), widget, NULL); + + if (priv->type_data->virtual) + hardware_type = G_TYPE_NONE; + else + hardware_type = priv->type_data->device_type; + + /* For connections involving multiple network devices, clarify which one + * NMSettingConnection:interface-name refers to. + */ + if (nm_connection_is_type (priv->edit_connection, NM_SETTING_PPPOE_SETTING_NAME)) + deventry_label = _("Ethernet device"); + else + deventry_label = _("Device"); + + widget = nmt_device_entry_new (deventry_label, 40, hardware_type); + nmt_editor_grid_append (grid, NULL, widget, NULL); + deventry = NMT_DEVICE_ENTRY (widget); + g_object_bind_property (s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, + deventry, "interface-name", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + + nmt_editor_grid_append (grid, NULL, nmt_newt_separator_new (), NULL); + + /* Now add the various pages... */ + + if (nm_connection_is_type (priv->edit_connection, NM_SETTING_BOND_SETTING_NAME)) + page = nmt_page_bond_new (priv->edit_connection, deventry); + else if (nm_connection_is_type (priv->edit_connection, NM_SETTING_BRIDGE_SETTING_NAME)) + page = nmt_page_bridge_new (priv->edit_connection, deventry); + else if (nm_connection_is_type (priv->edit_connection, NM_SETTING_INFINIBAND_SETTING_NAME)) + page = nmt_page_infiniband_new (priv->edit_connection, deventry); + else if (nm_connection_is_type (priv->edit_connection, NM_SETTING_PPPOE_SETTING_NAME)) + page = nmt_page_dsl_new (priv->edit_connection, deventry); + else if (nm_connection_is_type (priv->edit_connection, NM_SETTING_TEAM_SETTING_NAME)) + page = nmt_page_team_new (priv->edit_connection, deventry); + else if (nm_connection_is_type (priv->edit_connection, NM_SETTING_VLAN_SETTING_NAME)) + page = nmt_page_vlan_new (priv->edit_connection, deventry); + else if (nm_connection_is_type (priv->edit_connection, NM_SETTING_WIRED_SETTING_NAME)) + page = nmt_page_ethernet_new (priv->edit_connection, deventry); + else if (nm_connection_is_type (priv->edit_connection, NM_SETTING_WIRELESS_SETTING_NAME)) + page = nmt_page_wifi_new (priv->edit_connection, deventry); + else + g_assert_not_reached (); + + add_sections_for_page (editor, grid, page); + nmt_editor_grid_append (grid, NULL, nmt_newt_separator_new (), NULL); + + slave_type = nm_setting_connection_get_slave_type (s_con); + if (slave_type) { + if (!strcmp (slave_type, NM_SETTING_BRIDGE_SETTING_NAME)) + add_sections_for_page (editor, grid, nmt_page_bridge_port_new (priv->edit_connection)); + else if (!strcmp (slave_type, NM_SETTING_TEAM_SETTING_NAME)) + add_sections_for_page (editor, grid, nmt_page_team_port_new (priv->edit_connection)); + } else { + NmtNewtWidget *section; + + section = add_sections_for_page (editor, grid, nmt_page_ip4_new (priv->edit_connection)); + + /* Add a separator between ip4 and ip6 that's only visible if ip4 is open */ + widget = nmt_newt_separator_new (); + g_object_bind_property (section, "open", widget, "visible", G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, NULL, widget, NULL); + + add_sections_for_page (editor, grid, nmt_page_ip6_new (priv->edit_connection)); + + nmt_editor_grid_append (grid, NULL, nmt_newt_separator_new (), NULL); + } + + /* And finally the bottom widgets */ + + widget = nmt_newt_checkbox_new (_("Automatically connect")); + g_object_bind_property (s_con, NM_SETTING_CONNECTION_AUTOCONNECT, + widget, "active", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, NULL, widget, NULL); + + widget = nmt_newt_checkbox_new (_("Available to all users")); + g_object_bind_property_full (s_con, NM_SETTING_CONNECTION_PERMISSIONS, + widget, "active", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, + permissions_transform_to_allusers, + permissions_transform_from_allusers, + NULL, NULL); + nmt_editor_grid_append (grid, NULL, widget, NULL); + + /* And the button box */ + + buttons = nmt_newt_button_box_new (NMT_NEWT_BUTTON_BOX_HORIZONTAL); + nmt_newt_grid_add (NMT_NEWT_GRID (vbox), buttons, 0, 1); + nmt_newt_widget_set_padding (buttons, 0, 1, 0, 0); + + priv->cancel = nmt_newt_button_box_add_end (NMT_NEWT_BUTTON_BOX (buttons), _("Cancel")); + nmt_newt_widget_set_exit_on_activate (priv->cancel, TRUE); + + priv->ok = nmt_newt_button_box_add_end (NMT_NEWT_BUTTON_BOX (buttons), _("OK")); + g_signal_connect (priv->ok, "clicked", G_CALLBACK (save_connection_and_exit), editor); + g_object_bind_property (NMT_NEWT_WIDGET (grid), "valid", + priv->ok, "sensitive", + G_BINDING_SYNC_CREATE); + + nmt_newt_form_set_content (NMT_NEWT_FORM (editor), vbox); +} + +static void +nmt_editor_finalize (GObject *object) +{ + NmtEditorPrivate *priv = NMT_EDITOR_GET_PRIVATE (object); + + g_clear_object (&priv->orig_connection); + g_clear_object (&priv->edit_connection); + + g_slist_free_full (priv->pages, g_object_unref); + + g_clear_object (&priv->ok); + g_clear_object (&priv->cancel); + + G_OBJECT_CLASS (nmt_editor_parent_class)->finalize (object); +} + +static void +nmt_editor_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtEditorPrivate *priv = NMT_EDITOR_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_CONNECTION: + priv->orig_connection = g_value_dup_object (value); + break; + case PROP_TYPE_DATA: + priv->type_data = g_value_get_pointer (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_editor_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtEditorPrivate *priv = NMT_EDITOR_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_CONNECTION: + g_value_set_object (value, priv->orig_connection); + break; + case PROP_TYPE_DATA: + g_value_set_pointer (value, priv->type_data); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_editor_class_init (NmtEditorClass *entry_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (entry_class); + + g_type_class_add_private (entry_class, sizeof (NmtEditorPrivate)); + + /* virtual methods */ + object_class->constructed = nmt_editor_constructed; + object_class->set_property = nmt_editor_set_property; + object_class->get_property = nmt_editor_get_property; + object_class->finalize = nmt_editor_finalize; + + /** + * NmtEditor:connection: + * + * The connection being edited. + */ + g_object_class_install_property + (object_class, PROP_CONNECTION, + g_param_spec_object ("connection", "", "", + NM_TYPE_CONNECTION, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtEditor:type-data: + * + * The #NmEditorConnectionTypeData for #NmtEditor:connection. + */ + g_object_class_install_property + (object_class, PROP_TYPE_DATA, + g_param_spec_pointer ("type-data", "", "", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/nmt-editor.h b/clients/tui/nmt-editor.h new file mode 100644 index 00000000..db10b82a --- /dev/null +++ b/clients/tui/nmt-editor.h @@ -0,0 +1,51 @@ +/* -*- 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. + */ + +#ifndef NMT_EDITOR_H +#define NMT_EDITOR_H + +#include <NetworkManager.h> + +#include "nmt-newt.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_EDITOR (nmt_editor_get_type ()) +#define NMT_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_EDITOR, NmtEditor)) +#define NMT_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_EDITOR, NmtEditorClass)) +#define NMT_IS_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_EDITOR)) +#define NMT_IS_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_EDITOR)) +#define NMT_EDITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_EDITOR, NmtEditorClass)) + +typedef struct { + NmtNewtForm parent; + +} NmtEditor; + +typedef struct { + NmtNewtFormClass parent; + +} NmtEditorClass; + +GType nmt_editor_get_type (void); + +NmtNewtForm *nmt_editor_new (NMConnection *connection); + +G_END_DECLS + +#endif /* NMT_EDITOR_H */ diff --git a/clients/tui/nmt-ip-entry.c b/clients/tui/nmt-ip-entry.c new file mode 100644 index 00000000..30c7e2e4 --- /dev/null +++ b/clients/tui/nmt-ip-entry.c @@ -0,0 +1,268 @@ +/* -*- 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-ip-entry + * @short_description: #NmtNewtEntry for IP address entry + * + * #NmtIPEntry is an #NmtNewtEntry for entering IP addresses, or IP + * address/prefix combination. It will only allow typing characters + * that are valid in an IP address, and will set its + * #NmtNewtWidget:valid property depending on whether it currently + * contains a valid IP address. + */ + +#include "config.h" + +#include <arpa/inet.h> +#include <netinet/in.h> +#include <stdlib.h> + +#include <glib/gi18n-lib.h> + +#include "nmt-ip-entry.h" + +G_DEFINE_TYPE (NmtIPEntry, nmt_ip_entry, NMT_TYPE_NEWT_ENTRY) + +#define NMT_IP_ENTRY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_IP_ENTRY, NmtIPEntryPrivate)) + +typedef struct { + int family; + gboolean prefix; + gboolean optional; + +} NmtIPEntryPrivate; + +enum { + PROP_0, + PROP_FAMILY, + PROP_PREFIX, + PROP_OPTIONAL, + + LAST_PROP +}; + +/** + * nmt_ip_entry_new: + * @width: the width of the entry + * @family: the IP address family. Eg, %AF_INET + * @prefix: whether to require a trailing "/prefix" + * @optional: whether the address is optional + * + * Creates a new #NmtIPEntry, to accept IP addresses in the indicated + * @family, or (if @prefix is %TRUE), to accept IP address/prefix combos. + * + * If @optional is %TRUE then the address is considered optional, and + * so will still be #NmtNewtWidget:valid even when it is empty. If + * @optional is %FALSE, the entry will be invalid when it is empty. + */ +NmtNewtWidget * +nmt_ip_entry_new (int width, + int family, + gboolean prefix, + gboolean optional) +{ + return g_object_new (NMT_TYPE_IP_ENTRY, + "width", width, + "family", family, + "prefix", prefix, + "optional", optional, + NULL); +} + +static gboolean +ip_entry_filter (NmtNewtEntry *entry, + const char *text, + int ch, + int position, + gpointer user_data) +{ + NmtIPEntryPrivate *priv = NMT_IP_ENTRY_GET_PRIVATE (entry); + const char *slash; + gboolean inaddr; + + if (g_ascii_isdigit (ch)) + return TRUE; + + slash = strchr (text, '/'); + if (ch == '/') + return priv->prefix && slash == NULL; + + inaddr = !slash || (position <= (slash - text)); + + if (priv->family == AF_INET) { + if (ch == '.') + return inaddr; + else + return FALSE; + } else if (priv->family == AF_INET6) { + if (g_ascii_isxdigit (ch) || ch == ':') + return inaddr; + else + return FALSE; + } else + g_return_val_if_reached (FALSE); +} + +static gboolean +ip_entry_validate (NmtNewtEntry *entry, + const char *text, + gpointer user_data) +{ + NmtIPEntryPrivate *priv = NMT_IP_ENTRY_GET_PRIVATE (entry); + guchar buf[16]; + guint32 prefix; + const char *slash; + char *addrstr, *end; + gboolean valid; + + if (!*text) + return priv->optional; + + slash = strchr (text, '/'); + + if (slash) { + if (!priv->prefix) + return FALSE; + addrstr = g_strndup (text, slash - text); + } else + addrstr = g_strdup (text); + valid = (inet_pton (priv->family, addrstr, buf) == 1); + g_free (addrstr); + + if (!valid) + return FALSE; + + if (slash) { + prefix = strtoul (slash + 1, &end, 10); + if ( *end + || prefix == 0 + || (priv->family == AF_INET && prefix > 32) + || (priv->family == AF_INET6 && prefix > 128)) + valid = FALSE; + } + + return valid; +} + +static void +nmt_ip_entry_init (NmtIPEntry *entry) +{ + nmt_newt_entry_set_filter (NMT_NEWT_ENTRY (entry), ip_entry_filter, NULL); + nmt_newt_entry_set_validator (NMT_NEWT_ENTRY (entry), ip_entry_validate, NULL); +} + +static void +nmt_ip_entry_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtIPEntryPrivate *priv = NMT_IP_ENTRY_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_FAMILY: + priv->family = g_value_get_int (value); + break; + case PROP_PREFIX: + priv->prefix = g_value_get_boolean (value); + break; + case PROP_OPTIONAL: + priv->optional = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_ip_entry_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtIPEntryPrivate *priv = NMT_IP_ENTRY_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_FAMILY: + g_value_set_int (value, priv->family); + break; + case PROP_PREFIX: + g_value_set_boolean (value, priv->prefix); + break; + case PROP_OPTIONAL: + g_value_set_boolean (value, priv->optional); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_ip_entry_class_init (NmtIPEntryClass *entry_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (entry_class); + + g_type_class_add_private (entry_class, sizeof (NmtIPEntryPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_ip_entry_set_property; + object_class->get_property = nmt_ip_entry_get_property; + + /** + * NmtIPEntry:family: + * + * The address family. Eg, %AF_INET + */ + g_object_class_install_property + (object_class, PROP_FAMILY, + g_param_spec_int ("family", "", "", + 0, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtIPEntry:prefix: + * + * If %TRUE, the entry accepts address/prefix combinations. If + * %FALSE it accepts just addresses. + */ + g_object_class_install_property + (object_class, PROP_PREFIX, + g_param_spec_boolean ("prefix", "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtIPEntry:optional: + * + * If %TRUE, the entry will be #NmtNewtWidget:valid when it is + * empty. If %FALSE, it will only be valid when it contains a + * valid address or address/prefix. + */ + g_object_class_install_property + (object_class, PROP_OPTIONAL, + g_param_spec_boolean ("optional", "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/nmt-ip-entry.h b/clients/tui/nmt-ip-entry.h new file mode 100644 index 00000000..ceb355ef --- /dev/null +++ b/clients/tui/nmt-ip-entry.h @@ -0,0 +1,52 @@ +/* -*- 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. + */ + +#ifndef NMT_IP_ENTRY_H +#define NMT_IP_ENTRY_H + +#include "nmt-newt.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_IP_ENTRY (nmt_ip_entry_get_type ()) +#define NMT_IP_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_IP_ENTRY, NmtIPEntry)) +#define NMT_IP_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_IP_ENTRY, NmtIPEntryClass)) +#define NMT_IS_IP_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_IP_ENTRY)) +#define NMT_IS_IP_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_IP_ENTRY)) +#define NMT_IP_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_IP_ENTRY, NmtIPEntryClass)) + +typedef struct { + NmtNewtEntry parent; + +} NmtIPEntry; + +typedef struct { + NmtNewtEntryClass parent; + +} NmtIPEntryClass; + +GType nmt_ip_entry_get_type (void); + +NmtNewtWidget *nmt_ip_entry_new (int width, + int family, + gboolean prefix, + gboolean optional); + +G_END_DECLS + +#endif /* NMT_IP_ENTRY_H */ diff --git a/clients/tui/nmt-mac-entry.c b/clients/tui/nmt-mac-entry.c new file mode 100644 index 00000000..6501f09a --- /dev/null +++ b/clients/tui/nmt-mac-entry.c @@ -0,0 +1,227 @@ +/* -*- 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-mac-entry + * @short_description: #NmtNewtEntry for hardware address entry + * + * #NmtMacEntry is an #NmtNewtEntry for entering hardware addresses. + * It will only allow typing characters that are valid in a hardware + * address, and will set its #NmtNewtWidget:valid property depending + * on whether it currently contains a valid hardware address. + */ + +#include "config.h" + +#include <string.h> + +#include <NetworkManager.h> + +#include "nmt-mac-entry.h" + +G_DEFINE_TYPE (NmtMacEntry, nmt_mac_entry, NMT_TYPE_NEWT_ENTRY) + +#define NMT_MAC_ENTRY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_MAC_ENTRY, NmtMacEntryPrivate)) + +typedef struct { + int mac_length; + int mac_str_length; + +} NmtMacEntryPrivate; + +enum { + PROP_0, + PROP_MAC_LENGTH, + PROP_MAC_ADDRESS, + + LAST_PROP +}; + +/** + * nmt_mac_entry_new: + * @width: the width in characters of the entry + * @mac_length: the length in bytes of the hardware address + * (either %ETH_ALEN or %INFINIBAND_ALEN) + * + * Creates a new #NmtMacEntry. + * + * Returns: a new #NmtMacEntry. + */ +NmtNewtWidget * +nmt_mac_entry_new (int width, + int mac_length) +{ + return g_object_new (NMT_TYPE_MAC_ENTRY, + "width", width, + "mac-length", mac_length, + NULL); +} + +static gboolean +mac_filter (NmtNewtEntry *entry, + const char *text, + int ch, + int position, + gpointer user_data) +{ + NmtMacEntryPrivate *priv = NMT_MAC_ENTRY_GET_PRIVATE (entry); + + if (position >= priv->mac_str_length) + return FALSE; + + return g_ascii_isxdigit (ch) || ch == ':'; +} + +static gboolean +mac_validator (NmtNewtEntry *entry, + const char *text, + gpointer user_data) +{ + NmtMacEntryPrivate *priv = NMT_MAC_ENTRY_GET_PRIVATE (entry); + const char *p; + + if (!*text) + return TRUE; + + p = text; + while ( g_ascii_isxdigit (p[0]) + && g_ascii_isxdigit (p[1]) + && p[2] == ':') + p += 3; + + if ( !g_ascii_isxdigit (p[0]) + || !g_ascii_isxdigit (p[1])) + return FALSE; + p += 2; + + if (!*p) + return (p - text == priv->mac_str_length); + + if (g_ascii_isxdigit (p[0]) && !p[1]) { + char *fixed = g_strdup_printf ("%.*s:%c", (int)(p - text), text, *p); + + nmt_newt_entry_set_text (entry, fixed); + g_free (fixed); + + /* FIXME: NmtNewtEntry doesn't correctly deal with us calling set_text() + * from inside the validator. + */ + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (entry)); + } + + return FALSE; +} + +static void +nmt_mac_entry_init (NmtMacEntry *entry) +{ + nmt_newt_entry_set_filter (NMT_NEWT_ENTRY (entry), mac_filter, NULL); + nmt_newt_entry_set_validator (NMT_NEWT_ENTRY (entry), mac_validator, NULL); +} + +static void +nmt_mac_entry_notify (GObject *object, + GParamSpec *pspec) +{ + if (G_OBJECT_CLASS (nmt_mac_entry_parent_class)->notify) + G_OBJECT_CLASS (nmt_mac_entry_parent_class)->notify (object, pspec); + + if (pspec->owner_type == NMT_TYPE_NEWT_ENTRY && !strcmp (pspec->name, "text")) + g_object_notify (object, "mac-address"); +} + +static void +nmt_mac_entry_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtMacEntryPrivate *priv = NMT_MAC_ENTRY_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_MAC_LENGTH: + priv->mac_length = g_value_get_int (value); + priv->mac_str_length = priv->mac_length * 3 - 1; + break; + case PROP_MAC_ADDRESS: + nmt_newt_entry_set_text (NMT_NEWT_ENTRY (object), g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_mac_entry_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtMacEntryPrivate *priv = NMT_MAC_ENTRY_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_MAC_LENGTH: + g_value_set_int (value, priv->mac_length); + break; + case PROP_MAC_ADDRESS: + g_value_set_string (value, nmt_newt_entry_get_text (NMT_NEWT_ENTRY (object))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_mac_entry_class_init (NmtMacEntryClass *entry_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (entry_class); + + g_type_class_add_private (entry_class, sizeof (NmtMacEntryPrivate)); + + /* virtual methods */ + object_class->notify = nmt_mac_entry_notify; + object_class->set_property = nmt_mac_entry_set_property; + object_class->get_property = nmt_mac_entry_get_property; + + /** + * NmtMacEntry:mac-length: + * + * The length in bytes of the hardware address type the entry + * accepts: either %ETH_ALEN or %INFINIBAND_ALEN. + */ + g_object_class_install_property + (object_class, PROP_MAC_LENGTH, + g_param_spec_int ("mac-length", "", "", + 0, INFINIBAND_ALEN, ETH_ALEN, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtMacEntry:mac-address: + * + * The MAC address, as a string (as with the various #NMSetting + * "mac-address" properties). + */ + g_object_class_install_property + (object_class, PROP_MAC_ADDRESS, + g_param_spec_string ("mac-address", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/nmt-mac-entry.h b/clients/tui/nmt-mac-entry.h new file mode 100644 index 00000000..2e3e6cd1 --- /dev/null +++ b/clients/tui/nmt-mac-entry.h @@ -0,0 +1,51 @@ +/* -*- 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. + */ + +#ifndef NMT_MAC_ENTRY_H +#define NMT_MAC_ENTRY_H + +#include "nm-utils.h" +#include "nmt-newt.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_MAC_ENTRY (nmt_mac_entry_get_type ()) +#define NMT_MAC_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_MAC_ENTRY, NmtMacEntry)) +#define NMT_MAC_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_MAC_ENTRY, NmtMacEntryClass)) +#define NMT_IS_MAC_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_MAC_ENTRY)) +#define NMT_IS_MAC_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_MAC_ENTRY)) +#define NMT_MAC_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_MAC_ENTRY, NmtMacEntryClass)) + +typedef struct { + NmtNewtEntry parent; + +} NmtMacEntry; + +typedef struct { + NmtNewtEntryClass parent; + +} NmtMacEntryClass; + +GType nmt_mac_entry_get_type (void); + +NmtNewtWidget *nmt_mac_entry_new (int width, + int mac_length); + +G_END_DECLS + +#endif /* NMT_MAC_ENTRY_H */ diff --git a/clients/tui/nmt-mtu-entry.c b/clients/tui/nmt-mtu-entry.c new file mode 100644 index 00000000..f599557a --- /dev/null +++ b/clients/tui/nmt-mtu-entry.c @@ -0,0 +1,192 @@ +/* -*- 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-mtu-entry + * @short_description: #NmtNewtEntry for MTU entry + * + * #NmtMtuEntry is an #NmtNewtEntry for entering MTU values. It will + * only allow typing numeric characters, and will set its + * #NmtNewtWidget:valid property depending on whether it currently + * contains a valid MTU. + * + * The entry also has an attached #NmtNewtLabel. When the entry value + * is "0", the label will read "(default)". Otherwise it reads "bytes", + * indicating the units used by the entry. + */ + +#include "config.h" + +#include <stdlib.h> + +#include <glib/gi18n-lib.h> + +#include "nmt-mtu-entry.h" + +G_DEFINE_TYPE (NmtMtuEntry, nmt_mtu_entry, NMT_TYPE_NEWT_GRID) + +#define NMT_MTU_ENTRY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_MTU_ENTRY, NmtMtuEntryPrivate)) + +typedef struct { + int mtu; + + NmtNewtEntry *entry; + NmtNewtLabel *label; + +} NmtMtuEntryPrivate; + +enum { + PROP_0, + PROP_MTU, + + LAST_PROP +}; + +/** + * nmt_mtu_entry_new: + * + * Creates a new #NmtMtuEntry + * + * Returns: a new #NmtMtuEntry + */ +NmtNewtWidget * +nmt_mtu_entry_new (void) +{ + return g_object_new (NMT_TYPE_MTU_ENTRY, NULL); +} + +static gboolean +mtu_validator (NmtNewtEntry *entry, + const char *text, + gpointer user_data) +{ + NmtMtuEntryPrivate *priv = NMT_MTU_ENTRY_GET_PRIVATE (user_data); + + if (*text && !atoi (text)) { + nmt_newt_entry_set_text (entry, ""); + text = ""; + } + + if (!*text) + nmt_newt_label_set_text (priv->label, _("(default)")); + else + nmt_newt_label_set_text (priv->label, _("bytes")); + + return TRUE; +} + +static gboolean +mtu_transform_to_text (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + int mtu = g_value_get_int (source_value); + + if (mtu) + g_value_transform (source_value, target_value); + else + g_value_set_string (target_value, ""); + return TRUE; +} + +static void +nmt_mtu_entry_init (NmtMtuEntry *entry) +{ + + NmtMtuEntryPrivate *priv = NMT_MTU_ENTRY_GET_PRIVATE (entry); + NmtNewtGrid *grid = NMT_NEWT_GRID (entry); + NmtNewtWidget *real_entry, *label; + + real_entry = nmt_newt_entry_numeric_new (10, 0, 65535); + priv->entry = NMT_NEWT_ENTRY (real_entry); + + label = nmt_newt_label_new (_("bytes")); + priv->label = NMT_NEWT_LABEL (label); + + nmt_newt_grid_add (grid, real_entry, 0, 0); + nmt_newt_grid_add (grid, label, 1, 0); + nmt_newt_widget_set_padding (label, 1, 0, 0, 0); + + nmt_newt_entry_set_validator (priv->entry, mtu_validator, entry); + g_object_bind_property_full (entry, "mtu", real_entry, "text", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, + mtu_transform_to_text, + NULL, + NULL, NULL); +} + +static void +nmt_mtu_entry_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtMtuEntryPrivate *priv = NMT_MTU_ENTRY_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_MTU: + priv->mtu = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_mtu_entry_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtMtuEntryPrivate *priv = NMT_MTU_ENTRY_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_MTU: + g_value_set_int (value, priv->mtu); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_mtu_entry_class_init (NmtMtuEntryClass *entry_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (entry_class); + + g_type_class_add_private (entry_class, sizeof (NmtMtuEntryPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_mtu_entry_set_property; + object_class->get_property = nmt_mtu_entry_get_property; + + /** + * NmtMtuEntry:mtu: + * + * The contents of the entry, as a number. + */ + g_object_class_install_property + (object_class, PROP_MTU, + g_param_spec_int ("mtu", "", "", + 0, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/nmt-mtu-entry.h b/clients/tui/nmt-mtu-entry.h new file mode 100644 index 00000000..dfe416d0 --- /dev/null +++ b/clients/tui/nmt-mtu-entry.h @@ -0,0 +1,49 @@ +/* -*- 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. + */ + +#ifndef NMT_MTU_ENTRY_H +#define NMT_MTU_ENTRY_H + +#include "nmt-newt.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_MTU_ENTRY (nmt_mtu_entry_get_type ()) +#define NMT_MTU_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_MTU_ENTRY, NmtMtuEntry)) +#define NMT_MTU_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_MTU_ENTRY, NmtMtuEntryClass)) +#define NMT_IS_MTU_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_MTU_ENTRY)) +#define NMT_IS_MTU_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_MTU_ENTRY)) +#define NMT_MTU_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_MTU_ENTRY, NmtMtuEntryClass)) + +typedef struct { + NmtNewtGrid parent; + +} NmtMtuEntry; + +typedef struct { + NmtNewtGridClass parent; + +} NmtMtuEntryClass; + +GType nmt_mtu_entry_get_type (void); + +NmtNewtWidget *nmt_mtu_entry_new (void); + +G_END_DECLS + +#endif /* NMT_MTU_ENTRY_H */ diff --git a/clients/tui/nmt-page-bond.c b/clients/tui/nmt-page-bond.c new file mode 100644 index 00000000..b043b513 --- /dev/null +++ b/clients/tui/nmt-page-bond.c @@ -0,0 +1,437 @@ +/* -*- 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-page-bond + * @short_description: The editor page for Bond connections + * + * Note that this is fairly different from most of the other editor + * pages, because #NMSettingBond doesn't have properties, so we + * can't just use #GBinding. + */ + +#include "config.h" + +#include <glib.h> +#include <glib/gi18n-lib.h> + +#include "nmt-page-bond.h" + +#include "nmt-address-list.h" +#include "nmt-slave-list.h" + +G_DEFINE_TYPE (NmtPageBond, nmt_page_bond, NMT_TYPE_EDITOR_PAGE_DEVICE) + +#define NMT_PAGE_BOND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_PAGE_BOND, NmtPageBondPrivate)) + +typedef enum { + NMT_PAGE_BOND_MONITORING_UNKNOWN = -1, + NMT_PAGE_BOND_MONITORING_MII = 0, + NMT_PAGE_BOND_MONITORING_ARP = 1, +} NmtPageBondMonitoringMode; + +typedef struct { + NmtSlaveList *slaves; + + NmtNewtPopup *mode; + NmtNewtEntry *primary; + NmtNewtPopup *monitoring; + NmtNewtEntry *miimon; + NmtNewtEntry *updelay; + NmtNewtEntry *downdelay; + NmtNewtEntry *arp_interval; + NmtAddressList *arp_ip_target; + + NmtPageBondMonitoringMode monitoring_mode; + + NMSettingBond *s_bond; + GType slave_type; + gboolean updating; +} NmtPageBondPrivate; + +NmtEditorPage * +nmt_page_bond_new (NMConnection *conn, + NmtDeviceEntry *deventry) +{ + return g_object_new (NMT_TYPE_PAGE_BOND, + "connection", conn, + "device-entry", deventry, + NULL); +} + +static void +nmt_page_bond_init (NmtPageBond *bond) +{ + NmtPageBondPrivate *priv = NMT_PAGE_BOND_GET_PRIVATE (bond); + + priv->monitoring_mode = NMT_PAGE_BOND_MONITORING_UNKNOWN; + priv->slave_type = G_TYPE_NONE; +} + +static NmtNewtPopupEntry bond_mode[] = { + { N_("Round-robin"), "balance-rr" }, + { N_("Active Backup"), "active-backup" }, + { N_("XOR"), "balance-xor" }, + { N_("Broadcast"), "broadcast" }, + { N_("802.3ad"), "802.3ad" }, + { N_("Adaptive Transmit Load Balancing (tlb)"), "balance-tlb" }, + { N_("Adaptive Load Balancing (alb)"), "balance-alb" }, + { NULL, NULL } +}; + +/* NB: the ordering/numbering here corresponds to NmtPageBondMonitoringMode */ +static NmtNewtPopupEntry bond_monitoring[] = { + { N_("MII (recommended)"), "mii" }, + { N_("ARP"), "arp" }, + { NULL, NULL } +}; + +static void +bond_options_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + NMSettingBond *s_bond = NM_SETTING_BOND (object); + NmtPageBond *bond = NMT_PAGE_BOND (user_data); + NmtPageBondPrivate *priv = NMT_PAGE_BOND_GET_PRIVATE (bond); + const char *val; + char **ips; + + if (priv->updating) + return; + + priv->updating = TRUE; + + val = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_MODE); + nmt_newt_popup_set_active_id (priv->mode, val); + + if (!strcmp (val, "active-backup")) { + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->primary), TRUE); + val = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_PRIMARY); + nmt_newt_entry_set_text (priv->primary, val); + } else + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->primary), FALSE); + + if (priv->monitoring_mode == NMT_PAGE_BOND_MONITORING_UNKNOWN) { + val = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL); + if (val && strcmp (val, "0") != 0) + priv->monitoring_mode = NMT_PAGE_BOND_MONITORING_ARP; + else + priv->monitoring_mode = NMT_PAGE_BOND_MONITORING_MII; + } + nmt_newt_popup_set_active (priv->monitoring, priv->monitoring_mode); + + if (priv->monitoring_mode == NMT_PAGE_BOND_MONITORING_MII) { + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->miimon), TRUE); + val = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_MIIMON); + nmt_newt_entry_set_text (priv->miimon, val); + + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->updelay), TRUE); + val = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_UPDELAY); + nmt_newt_entry_set_text (priv->updelay, val); + + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->downdelay), TRUE); + val = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY); + nmt_newt_entry_set_text (priv->downdelay, val); + + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->arp_interval), FALSE); + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->arp_ip_target), FALSE); + } else { + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->arp_interval), TRUE); + val = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL); + nmt_newt_entry_set_text (priv->arp_interval, val); + + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->arp_ip_target), TRUE); + val = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET); + ips = g_strsplit (val, ",", -1); + g_object_set (G_OBJECT (priv->arp_ip_target), + "strings", ips, + NULL); + g_strfreev (ips); + + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->miimon), FALSE); + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->updelay), FALSE); + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->downdelay), FALSE); + } + + priv->updating = FALSE; +} + +static void +slaves_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + NmtPageBond *bond = NMT_PAGE_BOND (user_data); + NmtPageBondPrivate *priv = NMT_PAGE_BOND_GET_PRIVATE (bond); + GPtrArray *slaves; + + g_object_get (object, "connections", &slaves, NULL); + if (slaves->len == 0) { + if (priv->slave_type == G_TYPE_NONE) + return; + priv->slave_type = G_TYPE_NONE; + } else { + NMConnection *slave = slaves->pdata[0]; + + if (priv->slave_type != G_TYPE_NONE) + return; + + if (nm_connection_is_type (slave, NM_SETTING_INFINIBAND_SETTING_NAME)) + priv->slave_type = NM_TYPE_SETTING_INFINIBAND; + else + priv->slave_type = NM_TYPE_SETTING_WIRED; + } + + if (priv->slave_type == NM_TYPE_SETTING_INFINIBAND) { + nmt_newt_popup_set_active_id (priv->mode, "active-backup"); + nmt_newt_component_set_sensitive (NMT_NEWT_COMPONENT (priv->mode), FALSE); + } else + nmt_newt_component_set_sensitive (NMT_NEWT_COMPONENT (priv->mode), TRUE); +} + +#define WIDGET_CHANGED_FUNC(widget, func, option) \ +static void \ +widget ## _widget_changed (GObject *object, \ + GParamSpec *pspec, \ + gpointer user_data) \ +{ \ + NmtPageBond *bond = NMT_PAGE_BOND (user_data); \ + NmtPageBondPrivate *priv = NMT_PAGE_BOND_GET_PRIVATE (bond); \ + \ + if (priv->updating) \ + return; \ + \ + priv->updating = TRUE; \ + nm_setting_bond_add_option (priv->s_bond, option, func (priv->widget)); \ + priv->updating = FALSE; \ +} + +WIDGET_CHANGED_FUNC (primary, nmt_newt_entry_get_text, NM_SETTING_BOND_OPTION_PRIMARY) +WIDGET_CHANGED_FUNC (miimon, nmt_newt_entry_get_text, NM_SETTING_BOND_OPTION_MIIMON) +WIDGET_CHANGED_FUNC (updelay, nmt_newt_entry_get_text, NM_SETTING_BOND_OPTION_UPDELAY) +WIDGET_CHANGED_FUNC (downdelay, nmt_newt_entry_get_text, NM_SETTING_BOND_OPTION_DOWNDELAY) +WIDGET_CHANGED_FUNC (arp_interval, nmt_newt_entry_get_text, NM_SETTING_BOND_OPTION_ARP_INTERVAL) + +static void +mode_widget_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + NmtPageBond *bond = NMT_PAGE_BOND (user_data); + NmtPageBondPrivate *priv = NMT_PAGE_BOND_GET_PRIVATE (bond); + const char *mode; + + if (priv->updating) + return; + + mode = nmt_newt_popup_get_active_id (priv->mode); + priv->updating = TRUE; + nm_setting_bond_add_option (priv->s_bond, NM_SETTING_BOND_OPTION_MODE, mode); + priv->updating = FALSE; + + if (!strcmp (mode, "balance-tlb") || !strcmp (mode, "balance-alb")) { + nmt_newt_popup_set_active (priv->monitoring, NMT_PAGE_BOND_MONITORING_MII); + nmt_newt_component_set_sensitive (NMT_NEWT_COMPONENT (priv->monitoring), FALSE); + } else + nmt_newt_component_set_sensitive (NMT_NEWT_COMPONENT (priv->monitoring), TRUE); + + if (!strcmp (mode, "active-backup")) { + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->primary), TRUE); + nm_setting_bond_add_option (priv->s_bond, NM_SETTING_BOND_OPTION_PRIMARY, + nmt_newt_entry_get_text (priv->primary)); + } else { + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->primary), FALSE); + nm_setting_bond_remove_option (priv->s_bond, NM_SETTING_BOND_OPTION_PRIMARY); + } +} + +static void +monitoring_widget_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + NmtPageBond *bond = NMT_PAGE_BOND (user_data); + NmtPageBondPrivate *priv = NMT_PAGE_BOND_GET_PRIVATE (bond); + + if (priv->updating) + return; + + priv->monitoring_mode = nmt_newt_popup_get_active (priv->monitoring); + if (priv->monitoring_mode == NMT_PAGE_BOND_MONITORING_MII) { + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->miimon), TRUE); + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->updelay), TRUE); + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->downdelay), TRUE); + + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->arp_interval), FALSE); + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->arp_ip_target), FALSE); + } else { + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->arp_interval), TRUE); + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->arp_ip_target), TRUE); + + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->miimon), FALSE); + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->updelay), FALSE); + nmt_newt_widget_set_visible (NMT_NEWT_WIDGET (priv->downdelay), FALSE); + } +} + +static void +arp_ip_target_widget_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + NmtPageBond *bond = NMT_PAGE_BOND (user_data); + NmtPageBondPrivate *priv = NMT_PAGE_BOND_GET_PRIVATE (bond); + char **ips, *target; + + if (priv->updating) + return; + + g_object_get (G_OBJECT (priv->arp_ip_target), + "strings", &ips, + NULL); + target = g_strjoinv (",", ips); + + priv->updating = TRUE; + nm_setting_bond_add_option (priv->s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET, target); + priv->updating = FALSE; + + g_free (target); + g_strfreev (ips); +} + +static gboolean +bond_connection_type_filter (GType connection_type, + gpointer user_data) +{ + NmtPageBond *bond = user_data; + NmtPageBondPrivate *priv = NMT_PAGE_BOND_GET_PRIVATE (bond); + + if ( priv->slave_type != NM_TYPE_SETTING_WIRED + && connection_type == NM_TYPE_SETTING_INFINIBAND) + return TRUE; + if ( priv->slave_type != NM_TYPE_SETTING_INFINIBAND + && connection_type == NM_TYPE_SETTING_WIRED) + return TRUE; + + return FALSE; +} + +static void +nmt_page_bond_constructed (GObject *object) +{ + NmtPageBond *bond = NMT_PAGE_BOND (object); + NmtPageBondPrivate *priv = NMT_PAGE_BOND_GET_PRIVATE (bond); + NmtEditorSection *section; + NmtEditorGrid *grid; + NMSettingBond *s_bond; + NmtNewtWidget *widget, *label; + NMConnection *conn; + + conn = nmt_editor_page_get_connection (NMT_EDITOR_PAGE (bond)); + s_bond = nm_connection_get_setting_bond (conn); + if (!s_bond) { + nm_connection_add_setting (conn, nm_setting_bond_new ()); + s_bond = nm_connection_get_setting_bond (conn); + } + priv->s_bond = s_bond; + + section = nmt_editor_section_new (_("BOND"), NULL, TRUE); + grid = nmt_editor_section_get_body (section); + + widget = nmt_newt_separator_new (); + nmt_editor_grid_append (grid, _("Slaves"), widget, NULL); + nmt_editor_grid_set_row_flags (grid, widget, NMT_EDITOR_GRID_ROW_LABEL_ALIGN_LEFT); + + widget = nmt_slave_list_new (conn, bond_connection_type_filter, bond); + g_signal_connect (widget, "notify::connections", + G_CALLBACK (slaves_changed), bond); + nmt_editor_grid_append (grid, NULL, widget, NULL); + priv->slaves = NMT_SLAVE_LIST (widget); + + widget = nmt_newt_popup_new (bond_mode); + g_signal_connect (widget, "notify::active-id", + G_CALLBACK (mode_widget_changed), bond); + nmt_editor_grid_append (grid, _("Mode"), widget, NULL); + priv->mode = NMT_NEWT_POPUP (widget); + + widget = nmt_newt_entry_new (40, 0); + g_signal_connect (widget, "notify::text", + G_CALLBACK (primary_widget_changed), bond); + nmt_editor_grid_append (grid, _("Primary"), widget, NULL); + priv->primary = NMT_NEWT_ENTRY (widget); + + widget = nmt_newt_popup_new (bond_monitoring); + g_signal_connect (widget, "notify::active", + G_CALLBACK (monitoring_widget_changed), bond); + nmt_editor_grid_append (grid, _("Link monitoring"), widget, NULL); + priv->monitoring = NMT_NEWT_POPUP (widget); + + widget = nmt_newt_entry_numeric_new (10, 0, G_MAXINT); + g_signal_connect (widget, "notify::text", + G_CALLBACK (miimon_widget_changed), bond); + label = nmt_newt_label_new (C_("milliseconds", "ms")); + nmt_editor_grid_append (grid, _("Monitoring frequency"), widget, label); + priv->miimon = NMT_NEWT_ENTRY (widget); + + widget = nmt_newt_entry_numeric_new (10, 0, G_MAXINT); + g_signal_connect (widget, "notify::text", + G_CALLBACK (updelay_widget_changed), bond); + label = nmt_newt_label_new (C_("milliseconds", "ms")); + nmt_editor_grid_append (grid, _("Link up delay"), widget, label); + priv->updelay = NMT_NEWT_ENTRY (widget); + + widget = nmt_newt_entry_numeric_new (10, 0, G_MAXINT); + g_signal_connect (widget, "notify::text", + G_CALLBACK (downdelay_widget_changed), bond); + label = nmt_newt_label_new (C_("milliseconds", "ms")); + nmt_editor_grid_append (grid, _("Link down delay"), widget, label); + priv->downdelay = NMT_NEWT_ENTRY (widget); + + widget = nmt_newt_entry_numeric_new (10, 0, G_MAXINT); + g_signal_connect (widget, "notify::text", + G_CALLBACK (arp_interval_widget_changed), bond); + label = nmt_newt_label_new (C_("milliseconds", "ms")); + nmt_editor_grid_append (grid, _("Monitoring frequency"), widget, label); + priv->arp_interval = NMT_NEWT_ENTRY (widget); + + widget = nmt_address_list_new (NMT_ADDRESS_LIST_IP4); + g_signal_connect (widget, "notify::strings", + G_CALLBACK (arp_ip_target_widget_changed), bond); + nmt_editor_grid_append (grid, _("ARP targets"), widget, NULL); + priv->arp_ip_target = NMT_ADDRESS_LIST (widget); + + g_signal_connect (s_bond, "notify::" NM_SETTING_BOND_OPTIONS, + G_CALLBACK (bond_options_changed), bond); + bond_options_changed (G_OBJECT (s_bond), NULL, bond); + slaves_changed (G_OBJECT (priv->slaves), NULL, bond); + + nmt_editor_page_add_section (NMT_EDITOR_PAGE (bond), section); + + G_OBJECT_CLASS (nmt_page_bond_parent_class)->constructed (object); +} + +static void +nmt_page_bond_class_init (NmtPageBondClass *bond_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (bond_class); + + g_type_class_add_private (bond_class, sizeof (NmtPageBondPrivate)); + + object_class->constructed = nmt_page_bond_constructed; +} diff --git a/clients/tui/nmt-page-bond.h b/clients/tui/nmt-page-bond.h new file mode 100644 index 00000000..b77477db --- /dev/null +++ b/clients/tui/nmt-page-bond.h @@ -0,0 +1,50 @@ +/* -*- 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. + */ + +#ifndef NMT_PAGE_BOND_H +#define NMT_PAGE_BOND_H + +#include "nmt-editor-page-device.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_PAGE_BOND (nmt_page_bond_get_type ()) +#define NMT_PAGE_BOND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_PAGE_BOND, NmtPageBond)) +#define NMT_PAGE_BOND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_PAGE_BOND, NmtPageBondClass)) +#define NMT_IS_PAGE_BOND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_PAGE_BOND)) +#define NMT_IS_PAGE_BOND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_PAGE_BOND)) +#define NMT_PAGE_BOND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_PAGE_BOND, NmtPageBondClass)) + +typedef struct { + NmtEditorPageDevice parent; + +} NmtPageBond; + +typedef struct { + NmtEditorPageDeviceClass parent; + +} NmtPageBondClass; + +GType nmt_page_bond_get_type (void); + +NmtEditorPage *nmt_page_bond_new (NMConnection *conn, + NmtDeviceEntry *deventry); + +G_END_DECLS + +#endif /* NMT_PAGE_BOND_H */ diff --git a/clients/tui/nmt-page-bridge-port.c b/clients/tui/nmt-page-bridge-port.c new file mode 100644 index 00000000..c9ef14ed --- /dev/null +++ b/clients/tui/nmt-page-bridge-port.c @@ -0,0 +1,95 @@ +/* -*- 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-page-bridge-port + * @short_description: The editor page for Bridge ports + */ + +#include "config.h" + +#include <glib.h> +#include <glib/gi18n-lib.h> + +#include "nmt-page-bridge-port.h" + +G_DEFINE_TYPE (NmtPageBridgePort, nmt_page_bridge_port, NMT_TYPE_EDITOR_PAGE) + +NmtEditorPage * +nmt_page_bridge_port_new (NMConnection *conn) +{ + return g_object_new (NMT_TYPE_PAGE_BRIDGE_PORT, + "connection", conn, + NULL); +} + +static void +nmt_page_bridge_port_init (NmtPageBridgePort *bridge) +{ +} + +static void +nmt_page_bridge_port_constructed (GObject *object) +{ + NmtPageBridgePort *bridge = NMT_PAGE_BRIDGE_PORT (object); + NmtEditorSection *section; + NmtEditorGrid *grid; + NMSettingBridgePort *s_port; + NmtNewtWidget *widget; + NMConnection *conn; + + conn = nmt_editor_page_get_connection (NMT_EDITOR_PAGE (bridge)); + s_port = nm_connection_get_setting_bridge_port (conn); + if (!s_port) { + nm_connection_add_setting (conn, nm_setting_bridge_port_new ()); + s_port = nm_connection_get_setting_bridge_port (conn); + } + + section = nmt_editor_section_new (_("BRIDGE PORT"), NULL, TRUE); + grid = nmt_editor_section_get_body (section); + + widget = nmt_newt_entry_numeric_new (10, 0, 63); + g_object_bind_property (s_port, NM_SETTING_BRIDGE_PORT_PRIORITY, + widget, "text", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("Priority"), widget, NULL); + + widget = nmt_newt_entry_numeric_new (10, 1, 65535); + g_object_bind_property (s_port, NM_SETTING_BRIDGE_PORT_PATH_COST, + widget, "text", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("Path cost"), widget, NULL); + + widget = nmt_newt_checkbox_new (_("Hairpin mode")); + g_object_bind_property (s_port, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, + widget, "active", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, NULL, widget, NULL); + + nmt_editor_page_add_section (NMT_EDITOR_PAGE (bridge), section); + + G_OBJECT_CLASS (nmt_page_bridge_port_parent_class)->constructed (object); +} + +static void +nmt_page_bridge_port_class_init (NmtPageBridgePortClass *bridge_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (bridge_class); + + object_class->constructed = nmt_page_bridge_port_constructed; +} diff --git a/clients/tui/nmt-page-bridge-port.h b/clients/tui/nmt-page-bridge-port.h new file mode 100644 index 00000000..c566dbc0 --- /dev/null +++ b/clients/tui/nmt-page-bridge-port.h @@ -0,0 +1,49 @@ +/* -*- 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. + */ + +#ifndef NMT_PAGE_BRIDGE_PORT_H +#define NMT_PAGE_BRIDGE_PORT_H + +#include "nmt-editor-page.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_PAGE_BRIDGE_PORT (nmt_page_bridge_port_get_type ()) +#define NMT_PAGE_BRIDGE_PORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_PAGE_BRIDGE_PORT, NmtPageBridgePort)) +#define NMT_PAGE_BRIDGE_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_PAGE_BRIDGE_PORT, NmtPageBridgePortClass)) +#define NMT_IS_PAGE_BRIDGE_PORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_PAGE_BRIDGE_PORT)) +#define NMT_IS_PAGE_BRIDGE_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_PAGE_BRIDGE_PORT)) +#define NMT_PAGE_BRIDGE_PORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_PAGE_BRIDGE_PORT, NmtPageBridgePortClass)) + +typedef struct { + NmtEditorPage parent; + +} NmtPageBridgePort; + +typedef struct { + NmtEditorPageClass parent; + +} NmtPageBridgePortClass; + +GType nmt_page_bridge_port_get_type (void); + +NmtEditorPage *nmt_page_bridge_port_new (NMConnection *conn); + +G_END_DECLS + +#endif /* NMT_PAGE_BRIDGE_PORT_H */ diff --git a/clients/tui/nmt-page-bridge.c b/clients/tui/nmt-page-bridge.c new file mode 100644 index 00000000..460be60b --- /dev/null +++ b/clients/tui/nmt-page-bridge.c @@ -0,0 +1,150 @@ +/* -*- 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-page-bridge + * @short_description: The editor page for Bridge connections + */ + +#include "config.h" + +#include <glib.h> +#include <glib/gi18n-lib.h> + +#include "nmt-page-bridge.h" + +#include "nmt-address-list.h" +#include "nmt-slave-list.h" + +G_DEFINE_TYPE (NmtPageBridge, nmt_page_bridge, NMT_TYPE_EDITOR_PAGE_DEVICE) + +NmtEditorPage * +nmt_page_bridge_new (NMConnection *conn, + NmtDeviceEntry *deventry) +{ + return g_object_new (NMT_TYPE_PAGE_BRIDGE, + "connection", conn, + "device-entry", deventry, + NULL); +} + +static void +nmt_page_bridge_init (NmtPageBridge *bridge) +{ +} + +static gboolean +bridge_connection_type_filter (GType connection_type, + gpointer user_data) +{ + return ( connection_type == NM_TYPE_SETTING_WIRED + || connection_type == NM_TYPE_SETTING_WIRELESS + || connection_type == NM_TYPE_SETTING_VLAN); +} + +static void +nmt_page_bridge_constructed (GObject *object) +{ + NmtPageBridge *bridge = NMT_PAGE_BRIDGE (object); + NmtEditorSection *section; + NmtEditorGrid *grid; + NMSettingBridge *s_bridge; + NmtNewtWidget *widget, *label, *stp; + NMConnection *conn; + + conn = nmt_editor_page_get_connection (NMT_EDITOR_PAGE (bridge)); + s_bridge = nm_connection_get_setting_bridge (conn); + if (!s_bridge) { + nm_connection_add_setting (conn, nm_setting_bridge_new ()); + s_bridge = nm_connection_get_setting_bridge (conn); + } + + section = nmt_editor_section_new (_("BRIDGE"), NULL, TRUE); + grid = nmt_editor_section_get_body (section); + + widget = nmt_newt_separator_new (); + nmt_editor_grid_append (grid, _("Slaves"), widget, NULL); + nmt_editor_grid_set_row_flags (grid, widget, NMT_EDITOR_GRID_ROW_LABEL_ALIGN_LEFT); + + widget = nmt_slave_list_new (conn, bridge_connection_type_filter, bridge); + nmt_editor_grid_append (grid, NULL, widget, NULL); + + widget = nmt_newt_entry_numeric_new (10, 0, 1000000); + g_object_bind_property (s_bridge, NM_SETTING_BRIDGE_AGEING_TIME, + widget, "text", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + label = nmt_newt_label_new (_("seconds")); + nmt_editor_grid_append (grid, _("Aging time"), widget, label); + + widget = stp = nmt_newt_checkbox_new (_("Enable STP (Spanning Tree Protocol)")); + g_object_bind_property (s_bridge, NM_SETTING_BRIDGE_STP, + widget, "active", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, NULL, widget, NULL); + + widget = nmt_newt_entry_numeric_new (10, 0, G_MAXINT); + g_object_bind_property (s_bridge, NM_SETTING_BRIDGE_PRIORITY, + widget, "text", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + g_object_bind_property (s_bridge, NM_SETTING_BRIDGE_STP, + widget, "sensitive", + G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("Priority"), widget, NULL); + + widget = nmt_newt_entry_numeric_new (10, 2, 30); + g_object_bind_property (s_bridge, NM_SETTING_BRIDGE_FORWARD_DELAY, + widget, "text", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + g_object_bind_property (s_bridge, NM_SETTING_BRIDGE_STP, + widget, "sensitive", + G_BINDING_SYNC_CREATE); + label = nmt_newt_label_new (_("seconds")); + nmt_editor_grid_append (grid, _("Forward delay"), widget, label); + + widget = nmt_newt_entry_numeric_new (10, 1, 10); + g_object_bind_property (s_bridge, NM_SETTING_BRIDGE_HELLO_TIME, + widget, "text", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + g_object_bind_property (s_bridge, NM_SETTING_BRIDGE_STP, + widget, "sensitive", + G_BINDING_SYNC_CREATE); + label = nmt_newt_label_new (_("seconds")); + nmt_editor_grid_append (grid, _("Hello time"), widget, label); + + widget = nmt_newt_entry_numeric_new (10, 6, 40); + g_object_bind_property (s_bridge, NM_SETTING_BRIDGE_MAX_AGE, + widget, "text", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + g_object_bind_property (s_bridge, NM_SETTING_BRIDGE_STP, + widget, "sensitive", + G_BINDING_SYNC_CREATE); + label = nmt_newt_label_new (_("seconds")); + nmt_editor_grid_append (grid, _("Max age"), widget, label); + + nmt_editor_page_add_section (NMT_EDITOR_PAGE (bridge), section); + + G_OBJECT_CLASS (nmt_page_bridge_parent_class)->constructed (object); +} + +static void +nmt_page_bridge_class_init (NmtPageBridgeClass *bridge_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (bridge_class); + + object_class->constructed = nmt_page_bridge_constructed; +} diff --git a/clients/tui/nmt-page-bridge.h b/clients/tui/nmt-page-bridge.h new file mode 100644 index 00000000..60cbdea2 --- /dev/null +++ b/clients/tui/nmt-page-bridge.h @@ -0,0 +1,50 @@ +/* -*- 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. + */ + +#ifndef NMT_PAGE_BRIDGE_H +#define NMT_PAGE_BRIDGE_H + +#include "nmt-editor-page-device.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_PAGE_BRIDGE (nmt_page_bridge_get_type ()) +#define NMT_PAGE_BRIDGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_PAGE_BRIDGE, NmtPageBridge)) +#define NMT_PAGE_BRIDGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_PAGE_BRIDGE, NmtPageBridgeClass)) +#define NMT_IS_PAGE_BRIDGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_PAGE_BRIDGE)) +#define NMT_IS_PAGE_BRIDGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_PAGE_BRIDGE)) +#define NMT_PAGE_BRIDGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_PAGE_BRIDGE, NmtPageBridgeClass)) + +typedef struct { + NmtEditorPageDevice parent; + +} NmtPageBridge; + +typedef struct { + NmtEditorPageDeviceClass parent; + +} NmtPageBridgeClass; + +GType nmt_page_bridge_get_type (void); + +NmtEditorPage *nmt_page_bridge_new (NMConnection *conn, + NmtDeviceEntry *deventry); + +G_END_DECLS + +#endif /* NMT_PAGE_BRIDGE_H */ diff --git a/clients/tui/nmt-page-dsl.c b/clients/tui/nmt-page-dsl.c new file mode 100644 index 00000000..e8894d1a --- /dev/null +++ b/clients/tui/nmt-page-dsl.c @@ -0,0 +1,141 @@ +/* -*- 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 2014 Red Hat, Inc. + */ + +/** + * SECTION:nmt-page-dsl + * @short_description: The editor page for DSL connections + */ + +#include "config.h" + +#include <glib.h> +#include <glib/gi18n-lib.h> + +#include "nmt-page-dsl.h" +#include "nmt-page-ethernet.h" +#include "nmt-page-ppp.h" +#include "nmt-password-fields.h" + +G_DEFINE_TYPE (NmtPageDsl, nmt_page_dsl, NMT_TYPE_EDITOR_PAGE_DEVICE) + +#define NMT_PAGE_DSL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_PAGE_DSL, NmtPageDslPrivate)) + +typedef struct { + NmtEditorPage *ethernet_page, *ppp_page; + +} NmtPageDslPrivate; + +NmtEditorPage * +nmt_page_dsl_new (NMConnection *conn, + NmtDeviceEntry *deventry) +{ + return g_object_new (NMT_TYPE_PAGE_DSL, + "connection", conn, + "device-entry", deventry, + NULL); +} + +static void +nmt_page_dsl_init (NmtPageDsl *dsl) +{ +} + +static NmtEditorSection * +build_dsl_section (NmtPageDsl *dsl, NMSettingPppoe *s_pppoe) +{ + NmtEditorSection *section; + NmtEditorGrid *grid; + NmtNewtWidget *widget; + + section = nmt_editor_section_new (_("DSL"), NULL, TRUE); + grid = nmt_editor_section_get_body (section); + + widget = nmt_newt_entry_new (40, 0); + nmt_editor_grid_append (grid, _("Username"), widget, NULL); + g_object_bind_property (s_pppoe, NM_SETTING_PPPOE_USERNAME, + widget, "text", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + + widget = nmt_password_fields_new (40, NMT_PASSWORD_FIELDS_SHOW_PASSWORD); + g_object_bind_property (s_pppoe, NM_SETTING_PPPOE_PASSWORD, + widget, "password", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + nmt_editor_grid_append (grid, _("Password"), widget, NULL); + + widget = nmt_newt_entry_new (40, 0); + nmt_editor_grid_append (grid, _("Service"), widget, NULL); + g_object_bind_property (s_pppoe, NM_SETTING_PPPOE_SERVICE, + widget, "text", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + + return section; +} + +static void +nmt_page_dsl_constructed (GObject *object) +{ + NmtPageDsl *dsl = NMT_PAGE_DSL (object); + NmtPageDslPrivate *priv = NMT_PAGE_DSL_GET_PRIVATE (dsl); + NMConnection *conn; + NMSettingPppoe *s_pppoe; + NmtEditorSection *section; + const GSList *sections, *iter; + + conn = nmt_editor_page_get_connection (NMT_EDITOR_PAGE (dsl)); + s_pppoe = nm_connection_get_setting_pppoe (conn); + if (!s_pppoe) { + nm_connection_add_setting (conn, nm_setting_pppoe_new ()); + s_pppoe = nm_connection_get_setting_pppoe (conn); + } + + section = build_dsl_section (dsl, s_pppoe); + nmt_editor_page_add_section (NMT_EDITOR_PAGE (dsl), section); + + priv->ethernet_page = nmt_page_ethernet_new (conn, nmt_editor_page_device_get_device_entry (NMT_EDITOR_PAGE_DEVICE (dsl))); + sections = nmt_editor_page_get_sections (priv->ethernet_page); + for (iter = sections; iter; iter = iter->next) + nmt_editor_page_add_section (NMT_EDITOR_PAGE (dsl), iter->data); + + priv->ppp_page = nmt_page_ppp_new (conn); + sections = nmt_editor_page_get_sections (priv->ppp_page); + for (iter = sections; iter; iter = iter->next) + nmt_editor_page_add_section (NMT_EDITOR_PAGE (dsl), iter->data); + + G_OBJECT_CLASS (nmt_page_dsl_parent_class)->constructed (object); +} + +static void +nmt_page_dsl_finalize (GObject *object) +{ + NmtPageDsl *dsl = NMT_PAGE_DSL (object); + NmtPageDslPrivate *priv = NMT_PAGE_DSL_GET_PRIVATE (dsl); + + g_clear_object (&priv->ethernet_page); + g_clear_object (&priv->ppp_page); + + G_OBJECT_CLASS (nmt_page_dsl_parent_class)->finalize (object); +} + +static void +nmt_page_dsl_class_init (NmtPageDslClass *dsl_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (dsl_class); + + object_class->constructed = nmt_page_dsl_constructed; + object_class->finalize = nmt_page_dsl_finalize; +} diff --git a/clients/tui/nmt-page-dsl.h b/clients/tui/nmt-page-dsl.h new file mode 100644 index 00000000..b938ead2 --- /dev/null +++ b/clients/tui/nmt-page-dsl.h @@ -0,0 +1,50 @@ +/* -*- 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. + */ + +#ifndef NMT_PAGE_DSL_H +#define NMT_PAGE_DSL_H + +#include "nmt-editor-page-device.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_PAGE_DSL (nmt_page_dsl_get_type ()) +#define NMT_PAGE_DSL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_PAGE_DSL, NmtPageDsl)) +#define NMT_PAGE_DSL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_PAGE_DSL, NmtPageDslClass)) +#define NMT_IS_PAGE_DSL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_PAGE_DSL)) +#define NMT_IS_PAGE_DSL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_PAGE_DSL)) +#define NMT_PAGE_DSL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_PAGE_DSL, NmtPageDslClass)) + +typedef struct { + NmtEditorPageDevice parent; + +} NmtPageDsl; + +typedef struct { + NmtEditorPageDeviceClass parent; + +} NmtPageDslClass; + +GType nmt_page_dsl_get_type (void); + +NmtEditorPage *nmt_page_dsl_new (NMConnection *conn, + NmtDeviceEntry *deventry); + +G_END_DECLS + +#endif /* NMT_PAGE_DSL_H */ diff --git a/clients/tui/nmt-page-ethernet.c b/clients/tui/nmt-page-ethernet.c new file mode 100644 index 00000000..cf4ef2c4 --- /dev/null +++ b/clients/tui/nmt-page-ethernet.c @@ -0,0 +1,99 @@ +/* -*- 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-page-ethernet + * @short_description: The editor page for Ethernet connections + */ + +#include "config.h" + +#include <glib.h> +#include <glib/gi18n-lib.h> + +#include "nmt-page-ethernet.h" +#include "nmt-mac-entry.h" +#include "nmt-mtu-entry.h" + +G_DEFINE_TYPE (NmtPageEthernet, nmt_page_ethernet, NMT_TYPE_EDITOR_PAGE_DEVICE) + +NmtEditorPage * +nmt_page_ethernet_new (NMConnection *conn, + NmtDeviceEntry *deventry) +{ + return g_object_new (NMT_TYPE_PAGE_ETHERNET, + "connection", conn, + "device-entry", deventry, + NULL); +} + +static void +nmt_page_ethernet_init (NmtPageEthernet *ethernet) +{ +} + +static void +nmt_page_ethernet_constructed (GObject *object) +{ + NmtPageEthernet *ethernet = NMT_PAGE_ETHERNET (object); + NmtDeviceEntry *deventry; + NmtEditorSection *section; + NmtEditorGrid *grid; + NMSettingWired *s_wired; + NmtNewtWidget *widget; + NMConnection *conn; + + conn = nmt_editor_page_get_connection (NMT_EDITOR_PAGE (ethernet)); + s_wired = nm_connection_get_setting_wired (conn); + if (!s_wired) { + nm_connection_add_setting (conn, nm_setting_wired_new ()); + s_wired = nm_connection_get_setting_wired (conn); + } + + deventry = nmt_editor_page_device_get_device_entry (NMT_EDITOR_PAGE_DEVICE (object)); + g_object_bind_property (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, + deventry, "mac-address", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + + section = nmt_editor_section_new (_("ETHERNET"), NULL, FALSE); + grid = nmt_editor_section_get_body (section); + + widget = nmt_mac_entry_new (40, ETH_ALEN); + g_object_bind_property (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, + widget, "mac-address", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("Cloned MAC address"), widget, NULL); + + widget = nmt_mtu_entry_new (); + g_object_bind_property (s_wired, NM_SETTING_WIRED_MTU, + widget, "mtu", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("MTU"), widget, NULL); + + nmt_editor_page_add_section (NMT_EDITOR_PAGE (ethernet), section); + + G_OBJECT_CLASS (nmt_page_ethernet_parent_class)->constructed (object); +} + +static void +nmt_page_ethernet_class_init (NmtPageEthernetClass *ethernet_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (ethernet_class); + + object_class->constructed = nmt_page_ethernet_constructed; +} diff --git a/clients/tui/nmt-page-ethernet.h b/clients/tui/nmt-page-ethernet.h new file mode 100644 index 00000000..bdf3d677 --- /dev/null +++ b/clients/tui/nmt-page-ethernet.h @@ -0,0 +1,50 @@ +/* -*- 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. + */ + +#ifndef NMT_PAGE_ETHERNET_H +#define NMT_PAGE_ETHERNET_H + +#include "nmt-editor-page-device.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_PAGE_ETHERNET (nmt_page_ethernet_get_type ()) +#define NMT_PAGE_ETHERNET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_PAGE_ETHERNET, NmtPageEthernet)) +#define NMT_PAGE_ETHERNET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_PAGE_ETHERNET, NmtPageEthernetClass)) +#define NMT_IS_PAGE_ETHERNET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_PAGE_ETHERNET)) +#define NMT_IS_PAGE_ETHERNET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_PAGE_ETHERNET)) +#define NMT_PAGE_ETHERNET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_PAGE_ETHERNET, NmtPageEthernetClass)) + +typedef struct { + NmtEditorPageDevice parent; + +} NmtPageEthernet; + +typedef struct { + NmtEditorPageDeviceClass parent; + +} NmtPageEthernetClass; + +GType nmt_page_ethernet_get_type (void); + +NmtEditorPage *nmt_page_ethernet_new (NMConnection *conn, + NmtDeviceEntry *deventry); + +G_END_DECLS + +#endif /* NMT_PAGE_ETHERNET_H */ diff --git a/clients/tui/nmt-page-infiniband.c b/clients/tui/nmt-page-infiniband.c new file mode 100644 index 00000000..f39b0b84 --- /dev/null +++ b/clients/tui/nmt-page-infiniband.c @@ -0,0 +1,110 @@ +/* -*- 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-page-infiniband + * @short_description: The editor page for InfiniBand connections + */ + +#include "config.h" + +#include <glib.h> +#include <glib/gi18n-lib.h> + +#include "nmt-page-infiniband.h" +#include "nmt-mtu-entry.h" + +G_DEFINE_TYPE (NmtPageInfiniband, nmt_page_infiniband, NMT_TYPE_EDITOR_PAGE_DEVICE) + +NmtEditorPage * +nmt_page_infiniband_new (NMConnection *conn, + NmtDeviceEntry *deventry) +{ + return g_object_new (NMT_TYPE_PAGE_INFINIBAND, + "connection", conn, + "device-entry", deventry, + NULL); +} + +static void +nmt_page_infiniband_init (NmtPageInfiniband *infiniband) +{ +} + +static NmtNewtPopupEntry transport_mode[] = { + { N_("Datagram"), "datagram" }, + { N_("Connected"), "connected" }, + { NULL, NULL } +}; + +static void +nmt_page_infiniband_constructed (GObject *object) +{ + NmtPageInfiniband *infiniband = NMT_PAGE_INFINIBAND (object); + NmtDeviceEntry *deventry; + NmtEditorSection *section; + NmtEditorGrid *grid; + NMSettingInfiniband *s_ib; + NmtNewtWidget *widget; + NMConnection *conn; + + conn = nmt_editor_page_get_connection (NMT_EDITOR_PAGE (infiniband)); + s_ib = nm_connection_get_setting_infiniband (conn); + if (!s_ib) { + nm_connection_add_setting (conn, nm_setting_infiniband_new ()); + s_ib = nm_connection_get_setting_infiniband (conn); + } + /* initialize 'transport-mode' if it is NULL */ + if (!nm_setting_infiniband_get_transport_mode (s_ib)) { + g_object_set (G_OBJECT (s_ib), + NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram", + NULL); + } + + deventry = nmt_editor_page_device_get_device_entry (NMT_EDITOR_PAGE_DEVICE (object)); + g_object_bind_property (s_ib, NM_SETTING_INFINIBAND_MAC_ADDRESS, + deventry, "mac-address", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + + section = nmt_editor_section_new (_("INFINIBAND"), NULL, TRUE); + grid = nmt_editor_section_get_body (section); + + widget = nmt_newt_popup_new (transport_mode); + g_object_bind_property (s_ib, NM_SETTING_INFINIBAND_TRANSPORT_MODE, + widget, "active-id", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("Transport mode"), widget, NULL); + + widget = nmt_mtu_entry_new (); + g_object_bind_property (s_ib, NM_SETTING_INFINIBAND_MTU, + widget, "mtu", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("MTU"), widget, NULL); + + nmt_editor_page_add_section (NMT_EDITOR_PAGE (infiniband), section); + + G_OBJECT_CLASS (nmt_page_infiniband_parent_class)->constructed (object); +} + +static void +nmt_page_infiniband_class_init (NmtPageInfinibandClass *infiniband_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (infiniband_class); + + object_class->constructed = nmt_page_infiniband_constructed; +} diff --git a/clients/tui/nmt-page-infiniband.h b/clients/tui/nmt-page-infiniband.h new file mode 100644 index 00000000..f51e0874 --- /dev/null +++ b/clients/tui/nmt-page-infiniband.h @@ -0,0 +1,50 @@ +/* -*- 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. + */ + +#ifndef NMT_PAGE_INFINIBAND_H +#define NMT_PAGE_INFINIBAND_H + +#include "nmt-editor-page-device.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_PAGE_INFINIBAND (nmt_page_infiniband_get_type ()) +#define NMT_PAGE_INFINIBAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_PAGE_INFINIBAND, NmtPageInfiniband)) +#define NMT_PAGE_INFINIBAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_PAGE_INFINIBAND, NmtPageInfinibandClass)) +#define NMT_IS_PAGE_INFINIBAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_PAGE_INFINIBAND)) +#define NMT_IS_PAGE_INFINIBAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_PAGE_INFINIBAND)) +#define NMT_PAGE_INFINIBAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_PAGE_INFINIBAND, NmtPageInfinibandClass)) + +typedef struct { + NmtEditorPageDevice parent; + +} NmtPageInfiniband; + +typedef struct { + NmtEditorPageDeviceClass parent; + +} NmtPageInfinibandClass; + +GType nmt_page_infiniband_get_type (void); + +NmtEditorPage *nmt_page_infiniband_new (NMConnection *conn, + NmtDeviceEntry *deventry); + +G_END_DECLS + +#endif /* NMT_PAGE_INFINIBAND_H */ diff --git a/clients/tui/nmt-page-ip4.c b/clients/tui/nmt-page-ip4.c new file mode 100644 index 00000000..df3f0b64 --- /dev/null +++ b/clients/tui/nmt-page-ip4.c @@ -0,0 +1,202 @@ +/* -*- 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-page-ip4 + * @short_description: The editor page for IP4 configuration + */ + +#include "config.h" + +#include <stdlib.h> + +#include <glib.h> +#include <glib/gi18n-lib.h> + +#include "nmt-page-ip4.h" +#include "nmt-ip-entry.h" +#include "nmt-address-list.h" +#include "nmt-route-editor.h" + +#include "nm-editor-bindings.h" + +G_DEFINE_TYPE (NmtPageIP4, nmt_page_ip4, NMT_TYPE_EDITOR_PAGE) + +static NmtNewtPopupEntry ip4methods[] = { + { N_("Disabled"), NM_SETTING_IP4_CONFIG_METHOD_DISABLED }, + { N_("Automatic"), NM_SETTING_IP4_CONFIG_METHOD_AUTO }, + { N_("Link-Local"), NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL }, + { N_("Manual"), NM_SETTING_IP4_CONFIG_METHOD_MANUAL }, + { N_("Shared"), NM_SETTING_IP4_CONFIG_METHOD_SHARED }, + { NULL, NULL } +}; + +NmtEditorPage * +nmt_page_ip4_new (NMConnection *conn) +{ + return g_object_new (NMT_TYPE_PAGE_IP4, + "connection", conn, + NULL); +} + +static void +nmt_page_ip4_init (NmtPageIP4 *ip4) +{ +} + +static void +edit_routes (NmtNewtButton *button, + gpointer user_data) +{ + NMSetting *s_ip4 = user_data; + NmtNewtForm *form; + + form = nmt_route_editor_new (s_ip4); + nmt_newt_form_run_sync (form); + g_object_unref (form); +} + +static gboolean +ip4_routes_transform_to_description (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + GPtrArray *routes; + char *text; + + routes = g_value_get_boxed (source_value); + if (!routes || !routes->len) + text = g_strdup (_("(No custom routes)")); + else { + text = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, + "One custom route", + "%d custom routes", + routes->len), + routes->len); + } + + g_value_take_string (target_value, text); + return TRUE; +} + +static void +nmt_page_ip4_constructed (GObject *object) +{ + NmtPageIP4 *ip4 = NMT_PAGE_IP4 (object); + gboolean show_by_default; + NmtEditorSection *section; + NmtEditorGrid *grid; + NMSettingIPConfig *s_ip4; + NmtNewtWidget *widget, *button; + NMConnection *conn; + + conn = nmt_editor_page_get_connection (NMT_EDITOR_PAGE (ip4)); + s_ip4 = nm_connection_get_setting_ip4_config (conn); + if (!s_ip4) { + s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new (); + g_object_set (G_OBJECT (s_ip4), + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, + NULL); + nm_connection_add_setting (conn, (NMSetting *) s_ip4); + } + + widget = nmt_newt_popup_new (ip4methods); + g_object_bind_property (s_ip4, NM_SETTING_IP_CONFIG_METHOD, + widget, "active-id", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + + if (!g_strcmp0 (nm_setting_ip_config_get_method (s_ip4), NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) + show_by_default = TRUE; + else if (nm_setting_ip_config_get_num_addresses (s_ip4)) + show_by_default = TRUE; + else + show_by_default = FALSE; + + section = nmt_editor_section_new (_("IPv4 CONFIGURATION"), widget, show_by_default); + grid = nmt_editor_section_get_body (section); + + widget = nmt_address_list_new (NMT_ADDRESS_LIST_IP4_WITH_PREFIX); + nm_editor_bind_ip_addresses_with_prefix_to_strv (AF_INET, + s_ip4, NM_SETTING_IP_CONFIG_ADDRESSES, + widget, "strings", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("Addresses"), widget, NULL); + + widget = nmt_ip_entry_new (25, AF_INET, FALSE, TRUE); + nm_editor_bind_ip_gateway_to_string (AF_INET, + s_ip4, + widget, "text", "sensitive", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("Gateway"), widget, NULL); + + widget = nmt_address_list_new (NMT_ADDRESS_LIST_IP4); + nm_editor_bind_ip_addresses_to_strv (AF_INET, + s_ip4, NM_SETTING_IP_CONFIG_DNS, + widget, "strings", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("DNS servers"), widget, NULL); + + widget = nmt_address_list_new (NMT_ADDRESS_LIST_HOSTNAME); + g_object_bind_property (s_ip4, NM_SETTING_IP_CONFIG_DNS_SEARCH, + widget, "strings", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("Search domains"), widget, NULL); + + nmt_editor_grid_append (grid, NULL, nmt_newt_separator_new (), NULL); + + widget = g_object_new (NMT_TYPE_NEWT_LABEL, + "text", "", + "style", NMT_NEWT_LABEL_PLAIN, + NULL); + g_object_bind_property_full (s_ip4, NM_SETTING_IP_CONFIG_ROUTES, + widget, "text", + G_BINDING_SYNC_CREATE, + ip4_routes_transform_to_description, + NULL, NULL, NULL); + button = nmt_newt_button_new (_("Edit...")); + g_signal_connect (button, "clicked", G_CALLBACK (edit_routes), s_ip4); + nmt_editor_grid_append (grid, _("Routing"), widget, button); + + widget = nmt_newt_checkbox_new (_("Never use this network for default route")); + g_object_bind_property (s_ip4, NM_SETTING_IP_CONFIG_NEVER_DEFAULT, + widget, "active", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + nmt_editor_grid_append (grid, NULL, widget, NULL); + + nmt_editor_grid_append (grid, NULL, nmt_newt_separator_new (), NULL); + + widget = nmt_newt_checkbox_new (_("Require IPv4 addressing for this connection")); + g_object_bind_property (s_ip4, NM_SETTING_IP_CONFIG_MAY_FAIL, + widget, "active", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL | + G_BINDING_INVERT_BOOLEAN); + nmt_editor_grid_append (grid, NULL, widget, NULL); + + nmt_editor_page_add_section (NMT_EDITOR_PAGE (ip4), section); + + G_OBJECT_CLASS (nmt_page_ip4_parent_class)->constructed (object); +} + +static void +nmt_page_ip4_class_init (NmtPageIP4Class *ip4_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (ip4_class); + + object_class->constructed = nmt_page_ip4_constructed; +} diff --git a/clients/tui/nmt-page-ip4.h b/clients/tui/nmt-page-ip4.h new file mode 100644 index 00000000..e3c5a003 --- /dev/null +++ b/clients/tui/nmt-page-ip4.h @@ -0,0 +1,49 @@ +/* -*- 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. + */ + +#ifndef NMT_PAGE_IP4_H +#define NMT_PAGE_IP4_H + +#include "nmt-editor-page.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_PAGE_IP4 (nmt_page_ip4_get_type ()) +#define NMT_PAGE_IP4(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_PAGE_IP4, NmtPageIP4)) +#define NMT_PAGE_IP4_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_PAGE_IP4, NmtPageIP4Class)) +#define NMT_IS_PAGE_IP4(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_PAGE_IP4)) +#define NMT_IS_PAGE_IP4_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_PAGE_IP4)) +#define NMT_PAGE_IP4_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_PAGE_IP4, NmtPageIP4Class)) + +typedef struct { + NmtEditorPage parent; + +} NmtPageIP4; + +typedef struct { + NmtEditorPageClass parent; + +} NmtPageIP4Class; + +GType nmt_page_ip4_get_type (void); + +NmtEditorPage *nmt_page_ip4_new (NMConnection *conn); + +G_END_DECLS + +#endif /* NMT_PAGE_IP4_H */ diff --git a/clients/tui/nmt-page-ip6.c b/clients/tui/nmt-page-ip6.c new file mode 100644 index 00000000..1513dbfa --- /dev/null +++ b/clients/tui/nmt-page-ip6.c @@ -0,0 +1,200 @@ +/* -*- 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-page-ip6 + * @short_description: The editor page for IP6 configuration + */ + +#include "config.h" + +#include <stdlib.h> + +#include <glib.h> +#include <glib/gi18n-lib.h> + +#include "nmt-page-ip6.h" +#include "nmt-ip-entry.h" +#include "nmt-address-list.h" +#include "nmt-route-editor.h" + +#include "nm-editor-bindings.h" + +G_DEFINE_TYPE (NmtPageIP6, nmt_page_ip6, NMT_TYPE_EDITOR_PAGE) + +static NmtNewtPopupEntry ip6methods[] = { + { N_("Ignore"), NM_SETTING_IP6_CONFIG_METHOD_IGNORE }, + { N_("Automatic"), NM_SETTING_IP6_CONFIG_METHOD_AUTO }, + { N_("Automatic (DHCP-only)"), NM_SETTING_IP6_CONFIG_METHOD_DHCP }, + { N_("Link-Local"), NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL }, + { N_("Manual"), NM_SETTING_IP6_CONFIG_METHOD_MANUAL }, + { NULL, NULL } +}; + +NmtEditorPage * +nmt_page_ip6_new (NMConnection *conn) +{ + return g_object_new (NMT_TYPE_PAGE_IP6, + "connection", conn, + NULL); +} + +static void +nmt_page_ip6_init (NmtPageIP6 *ip6) +{ +} + +static void +edit_routes (NmtNewtButton *button, + gpointer user_data) +{ + NMSetting *s_ip6 = user_data; + NmtNewtForm *form; + + form = nmt_route_editor_new (s_ip6); + nmt_newt_form_run_sync (form); + g_object_unref (form); +} + +static gboolean +ip6_routes_transform_to_description (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + GPtrArray *routes; + char *text; + + routes = g_value_get_boxed (source_value); + if (!routes || !routes->len) + text = g_strdup (_("(No custom routes)")); + else { + text = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, + "One custom route", + "%d custom routes", + routes->len), + routes->len); + } + + g_value_take_string (target_value, text); + return TRUE; +} + +static void +nmt_page_ip6_constructed (GObject *object) +{ + NmtPageIP6 *ip6 = NMT_PAGE_IP6 (object); + gboolean show_by_default; + NmtEditorSection *section; + NmtEditorGrid *grid; + NMSettingIPConfig *s_ip6; + NmtNewtWidget *widget, *button; + NMConnection *conn; + + conn = nmt_editor_page_get_connection (NMT_EDITOR_PAGE (ip6)); + s_ip6 = nm_connection_get_setting_ip6_config (conn); + if (!s_ip6) { + s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new (); + g_object_set (G_OBJECT (s_ip6), + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NULL); + nm_connection_add_setting (conn, (NMSetting *) s_ip6); + } + + widget = nmt_newt_popup_new (ip6methods); + g_object_bind_property (s_ip6, NM_SETTING_IP_CONFIG_METHOD, + widget, "active-id", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + + if (!g_strcmp0 (nm_setting_ip_config_get_method (s_ip6), NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) + show_by_default = TRUE; + else if (nm_setting_ip_config_get_num_addresses (s_ip6)) + show_by_default = TRUE; + else + show_by_default = FALSE; + + section = nmt_editor_section_new (_("IPv6 CONFIGURATION"), widget, show_by_default); + grid = nmt_editor_section_get_body (section); + + widget = nmt_address_list_new (NMT_ADDRESS_LIST_IP6_WITH_PREFIX); + nm_editor_bind_ip_addresses_with_prefix_to_strv (AF_INET6, + s_ip6, NM_SETTING_IP_CONFIG_ADDRESSES, + widget, "strings", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("Addresses"), widget, NULL); + + widget = nmt_ip_entry_new (25, AF_INET6, FALSE, TRUE); + nm_editor_bind_ip_gateway_to_string (AF_INET6, + s_ip6, + widget, "text", "sensitive", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("Gateway"), widget, NULL); + + widget = nmt_address_list_new (NMT_ADDRESS_LIST_IP6); + nm_editor_bind_ip_addresses_to_strv (AF_INET6, + s_ip6, NM_SETTING_IP_CONFIG_DNS, + widget, "strings", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("DNS servers"), widget, NULL); + + widget = nmt_address_list_new (NMT_ADDRESS_LIST_HOSTNAME); + g_object_bind_property (s_ip6, NM_SETTING_IP_CONFIG_DNS_SEARCH, + widget, "strings", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("Search domains"), widget, NULL); + + widget = g_object_new (NMT_TYPE_NEWT_LABEL, + "text", "", + "style", NMT_NEWT_LABEL_PLAIN, + NULL); + g_object_bind_property_full (s_ip6, NM_SETTING_IP_CONFIG_ROUTES, + widget, "text", + G_BINDING_SYNC_CREATE, + ip6_routes_transform_to_description, + NULL, NULL, NULL); + button = nmt_newt_button_new (_("Edit...")); + g_signal_connect (button, "clicked", G_CALLBACK (edit_routes), s_ip6); + nmt_editor_grid_append (grid, _("Routing"), widget, button); + + widget = nmt_newt_checkbox_new (_("Never use this network for default route")); + g_object_bind_property (s_ip6, NM_SETTING_IP_CONFIG_NEVER_DEFAULT, + widget, "active", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + nmt_editor_grid_append (grid, NULL, widget, NULL); + + nmt_editor_grid_append (grid, NULL, nmt_newt_separator_new (), NULL); + + widget = nmt_newt_checkbox_new (_("Require IPv6 addressing for this connection")); + g_object_bind_property (s_ip6, NM_SETTING_IP_CONFIG_MAY_FAIL, + widget, "active", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL | + G_BINDING_INVERT_BOOLEAN); + nmt_editor_grid_append (grid, NULL, widget, NULL); + + nmt_editor_page_add_section (NMT_EDITOR_PAGE (ip6), section); + + G_OBJECT_CLASS (nmt_page_ip6_parent_class)->constructed (object); +} + +static void +nmt_page_ip6_class_init (NmtPageIP6Class *ip6_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (ip6_class); + + object_class->constructed = nmt_page_ip6_constructed; +} diff --git a/clients/tui/nmt-page-ip6.h b/clients/tui/nmt-page-ip6.h new file mode 100644 index 00000000..498261e1 --- /dev/null +++ b/clients/tui/nmt-page-ip6.h @@ -0,0 +1,49 @@ +/* -*- 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. + */ + +#ifndef NMT_PAGE_IP6_H +#define NMT_PAGE_IP6_H + +#include "nmt-editor-page.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_PAGE_IP6 (nmt_page_ip6_get_type ()) +#define NMT_PAGE_IP6(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_PAGE_IP6, NmtPageIP6)) +#define NMT_PAGE_IP6_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_PAGE_IP6, NmtPageIP6Class)) +#define NMT_IS_PAGE_IP6(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_PAGE_IP6)) +#define NMT_IS_PAGE_IP6_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_PAGE_IP6)) +#define NMT_PAGE_IP6_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_PAGE_IP6, NmtPageIP6Class)) + +typedef struct { + NmtEditorPage parent; + +} NmtPageIP6; + +typedef struct { + NmtEditorPageClass parent; + +} NmtPageIP6Class; + +GType nmt_page_ip6_get_type (void); + +NmtEditorPage *nmt_page_ip6_new (NMConnection *conn); + +G_END_DECLS + +#endif /* NMT_PAGE_IP6_H */ diff --git a/clients/tui/nmt-page-ppp.c b/clients/tui/nmt-page-ppp.c new file mode 100644 index 00000000..cec36549 --- /dev/null +++ b/clients/tui/nmt-page-ppp.c @@ -0,0 +1,288 @@ +/* -*- 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 2014 Red Hat, Inc. + */ + +/** + * SECTION:nmt-page-ppp + * @short_description: The editor page for PPP configuration + */ + +#include "config.h" + +#include <stdlib.h> + +#include <glib.h> +#include <glib/gi18n-lib.h> + +#include "nmt-page-ppp.h" +#include "nmt-newt-section.h" +#include "nmt-newt-separator.h" + +G_DEFINE_TYPE (NmtPagePpp, nmt_page_ppp, NMT_TYPE_EDITOR_PAGE) + +typedef struct { + guint32 lcp_echo_failure; + guint32 lcp_echo_interval; +} NmtPagePppPrivate; + +#define NMT_PAGE_PPP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_PAGE_PPP, NmtPagePppPrivate)) + +NmtEditorPage * +nmt_page_ppp_new (NMConnection *conn) +{ + return g_object_new (NMT_TYPE_PAGE_PPP, + "connection", conn, + NULL); +} + +static void +nmt_page_ppp_init (NmtPagePpp *ppp) +{ +} + +static gboolean +transform_lcp_echo_properties_to_checkbox (GBinding *binding, + const GValue *from_value, + GValue *to_value, + gpointer user_data) +{ + NMSettingPpp *s_ppp = NM_SETTING_PPP (g_binding_get_source (binding)); + + if ( nm_setting_ppp_get_lcp_echo_interval (s_ppp) != 0 + && nm_setting_ppp_get_lcp_echo_failure (s_ppp) != 0) + g_value_set_boolean (to_value, TRUE); + else + g_value_set_boolean (to_value, FALSE); + + return TRUE; +} + +static gboolean +transform_checkbox_to_lcp_echo_interval (GBinding *binding, + const GValue *from_value, + GValue *to_value, + gpointer user_data) +{ + NmtPagePpp *ppp = user_data; + NmtPagePppPrivate *priv = NMT_PAGE_PPP_GET_PRIVATE (ppp); + + if (g_value_get_boolean (from_value)) + g_value_set_uint (to_value, priv->lcp_echo_interval); + else + g_value_set_uint (to_value, 0); + + return TRUE; +} + +static gboolean +transform_checkbox_to_lcp_echo_failure (GBinding *binding, + const GValue *from_value, + GValue *to_value, + gpointer user_data) +{ + NmtPagePpp *ppp = user_data; + NmtPagePppPrivate *priv = NMT_PAGE_PPP_GET_PRIVATE (ppp); + + if (g_value_get_boolean (from_value)) + g_value_set_uint (to_value, priv->lcp_echo_failure); + else + g_value_set_uint (to_value, 0); + + return TRUE; +} + +static void +nmt_page_ppp_constructed (GObject *object) +{ + NmtPagePpp *ppp = NMT_PAGE_PPP (object); + NmtPagePppPrivate *priv = NMT_PAGE_PPP_GET_PRIVATE (ppp); + NmtEditorSection *section; + NmtEditorGrid *grid; + NMSettingPpp *s_ppp; + NmtNewtWidget *widget, *use_mppe; + NmtNewtGrid *auth_grid, *mppe_grid; + NmtNewtSection *auth_section, *mppe_section; + NMConnection *conn; + + conn = nmt_editor_page_get_connection (NMT_EDITOR_PAGE (ppp)); + s_ppp = nm_connection_get_setting_ppp (conn); + if (s_ppp) { + priv->lcp_echo_interval = nm_setting_ppp_get_lcp_echo_interval (s_ppp); + priv->lcp_echo_failure = nm_setting_ppp_get_lcp_echo_failure (s_ppp); + } else { + s_ppp = (NMSettingPpp *) nm_setting_ppp_new (); + nm_connection_add_setting (conn, (NMSetting *) s_ppp); + + priv->lcp_echo_interval = 30; + priv->lcp_echo_failure = 5; + } + + section = nmt_editor_section_new (_("PPP CONFIGURATION"), NULL, TRUE); + grid = nmt_editor_section_get_body (section); + + /* Auth methods */ + widget = nmt_newt_section_new (FALSE); + auth_section = NMT_NEWT_SECTION (widget); + g_object_set (auth_section, "open", TRUE, NULL); + nmt_editor_grid_append (grid, NULL, widget, NULL); + + widget = nmt_newt_label_new (_("Allowed authentication methods:")); + nmt_newt_section_set_header (auth_section, widget); + + widget = nmt_newt_grid_new (); + auth_grid = NMT_NEWT_GRID (widget); + nmt_newt_section_set_body (auth_section, widget); + + widget = nmt_newt_checkbox_new (_("EAP")); + g_object_bind_property (s_ppp, NM_SETTING_PPP_REFUSE_EAP, + widget, "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_INVERT_BOOLEAN | + G_BINDING_SYNC_CREATE); + nmt_newt_grid_add (auth_grid, widget, 0, 0); + + widget = nmt_newt_checkbox_new (_("PAP")); + g_object_bind_property (s_ppp, NM_SETTING_PPP_REFUSE_PAP, + widget, "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_INVERT_BOOLEAN | + G_BINDING_SYNC_CREATE); + nmt_newt_grid_add (auth_grid, widget, 0, 1); + + widget = nmt_newt_checkbox_new (_("CHAP")); + g_object_bind_property (s_ppp, NM_SETTING_PPP_REFUSE_CHAP, + widget, "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_INVERT_BOOLEAN | + G_BINDING_SYNC_CREATE); + nmt_newt_grid_add (auth_grid, widget, 0, 2); + + widget = nmt_newt_checkbox_new (_("MSCHAPv2")); + g_object_bind_property (s_ppp, NM_SETTING_PPP_REFUSE_MSCHAPV2, + widget, "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_INVERT_BOOLEAN | + G_BINDING_SYNC_CREATE); + nmt_newt_grid_add (auth_grid, widget, 0, 3); + + widget = nmt_newt_checkbox_new (_("MSCHAP")); + g_object_bind_property (s_ppp, NM_SETTING_PPP_REFUSE_MSCHAP, + widget, "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_INVERT_BOOLEAN | + G_BINDING_SYNC_CREATE); + nmt_newt_grid_add (auth_grid, widget, 0, 4); + + nmt_editor_grid_append (grid, NULL, nmt_newt_separator_new (), NULL); + + /* MPPE */ + widget = nmt_newt_section_new (FALSE); + mppe_section = NMT_NEWT_SECTION (widget); + g_object_set (mppe_section, "open", TRUE, NULL); + nmt_editor_grid_append (grid, NULL, widget, NULL); + + widget = nmt_newt_checkbox_new (_("Use point-to-point encryption (MPPE)")); + g_object_bind_property (s_ppp, NM_SETTING_PPP_REQUIRE_MPPE, + widget, "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + use_mppe = widget; + nmt_newt_section_set_header (mppe_section, widget); + + widget = nmt_newt_grid_new (); + mppe_grid = NMT_NEWT_GRID (widget); + nmt_newt_section_set_body (mppe_section, widget); + + widget = nmt_newt_checkbox_new (_("Require 128-bit encryption")); + g_object_bind_property (use_mppe, "active", + widget, "sensitive", + G_BINDING_SYNC_CREATE); + g_object_bind_property (s_ppp, NM_SETTING_PPP_REQUIRE_MPPE_128, + widget, "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + nmt_newt_grid_add (mppe_grid, widget, 0, 0); + + widget = nmt_newt_checkbox_new (_("Use stateful MPPE")); + g_object_bind_property (use_mppe, "active", + widget, "sensitive", + G_BINDING_SYNC_CREATE); + g_object_bind_property (s_ppp, NM_SETTING_PPP_MPPE_STATEFUL, + widget, "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + nmt_newt_grid_add (mppe_grid, widget, 0, 1); + + nmt_editor_grid_append (grid, NULL, nmt_newt_separator_new (), NULL); + + widget = nmt_newt_checkbox_new (_("Allow BSD data compression")); + g_object_bind_property (s_ppp, NM_SETTING_PPP_NOBSDCOMP, + widget, "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_INVERT_BOOLEAN | + G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, NULL, widget, NULL); + + widget = nmt_newt_checkbox_new (_("Allow Deflate data compression")); + g_object_bind_property (s_ppp, NM_SETTING_PPP_NODEFLATE, + widget, "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_INVERT_BOOLEAN | + G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, NULL, widget, NULL); + + widget = nmt_newt_checkbox_new (_("Use TCP header compression")); + g_object_bind_property (s_ppp, NM_SETTING_PPP_NO_VJ_COMP, + widget, "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_INVERT_BOOLEAN | + G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, NULL, widget, NULL); + + nmt_editor_grid_append (grid, NULL, nmt_newt_separator_new (), NULL); + + widget = nmt_newt_checkbox_new (_("Send PPP echo packets")); + g_object_bind_property_full (s_ppp, NM_SETTING_PPP_LCP_ECHO_INTERVAL, + widget, "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE, + transform_lcp_echo_properties_to_checkbox, + transform_checkbox_to_lcp_echo_interval, + ppp, NULL); + g_object_bind_property_full (s_ppp, NM_SETTING_PPP_LCP_ECHO_FAILURE, + widget, "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE, + transform_lcp_echo_properties_to_checkbox, + transform_checkbox_to_lcp_echo_failure, + ppp, NULL); + nmt_editor_grid_append (grid, NULL, widget, NULL); + + nmt_editor_page_add_section (NMT_EDITOR_PAGE (ppp), section); + + G_OBJECT_CLASS (nmt_page_ppp_parent_class)->constructed (object); +} + +static void +nmt_page_ppp_class_init (NmtPagePppClass *ppp_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (ppp_class); + + g_type_class_add_private (object_class, sizeof (NmtPagePppPrivate)); + + object_class->constructed = nmt_page_ppp_constructed; +} diff --git a/clients/tui/nmt-page-ppp.h b/clients/tui/nmt-page-ppp.h new file mode 100644 index 00000000..79103232 --- /dev/null +++ b/clients/tui/nmt-page-ppp.h @@ -0,0 +1,49 @@ +/* -*- 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 2014 Red Hat, Inc. + */ + +#ifndef NMT_PAGE_PPP_H +#define NMT_PAGE_PPP_H + +#include "nmt-editor-page.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_PAGE_PPP (nmt_page_ppp_get_type ()) +#define NMT_PAGE_PPP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_PAGE_PPP, NmtPagePpp)) +#define NMT_PAGE_PPP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_PAGE_PPP, NmtPagePppClass)) +#define NMT_IS_PAGE_PPP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_PAGE_PPP)) +#define NMT_IS_PAGE_PPP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_PAGE_PPP)) +#define NMT_PAGE_PPP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_PAGE_PPP, NmtPagePppClass)) + +typedef struct { + NmtEditorPage parent; + +} NmtPagePpp; + +typedef struct { + NmtEditorPageClass parent; + +} NmtPagePppClass; + +GType nmt_page_ppp_get_type (void); + +NmtEditorPage *nmt_page_ppp_new (NMConnection *conn); + +G_END_DECLS + +#endif /* NMT_PAGE_PPP_H */ diff --git a/clients/tui/nmt-page-team-port.c b/clients/tui/nmt-page-team-port.c new file mode 100644 index 00000000..645dc9d3 --- /dev/null +++ b/clients/tui/nmt-page-team-port.c @@ -0,0 +1,129 @@ +/* -*- 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-page-team-port + * @short_description: The editor page for Team ports. + */ + +#include "config.h" + +#include <glib.h> +#include <glib/gi18n-lib.h> + +#include "nmt-page-team-port.h" + +G_DEFINE_TYPE (NmtPageTeamPort, nmt_page_team_port, NMT_TYPE_EDITOR_PAGE) + +#define NMT_PAGE_TEAM_PORT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_PAGE_TEAM_PORT, NmtPageTeamPortPrivate)) + +typedef struct { + NMSettingTeamPort *s_port; + +} NmtPageTeamPortPrivate; + +NmtEditorPage * +nmt_page_team_port_new (NMConnection *conn) +{ + return g_object_new (NMT_TYPE_PAGE_TEAM_PORT, + "connection", conn, + NULL); +} + +static void +nmt_page_team_port_init (NmtPageTeamPort *team) +{ +} + +static void +edit_clicked (NmtNewtButton *button, + gpointer user_data) +{ + NmtPageTeamPort *team = user_data; + NmtPageTeamPortPrivate *priv = NMT_PAGE_TEAM_PORT_GET_PRIVATE (team); + const char *config; + char *new_config; + + config = nm_setting_team_port_get_config (priv->s_port); + if (!config) + config = ""; + + new_config = nmt_newt_edit_string (config); + + if (new_config && !*new_config) + g_clear_pointer (&new_config, g_free); + g_object_set (G_OBJECT (priv->s_port), + NM_SETTING_TEAM_PORT_CONFIG, new_config, + NULL); + g_free (new_config); +} + +static void +nmt_page_team_port_constructed (GObject *object) +{ + NmtPageTeamPort *team = NMT_PAGE_TEAM_PORT (object); + NmtPageTeamPortPrivate *priv = NMT_PAGE_TEAM_PORT_GET_PRIVATE (team); + NmtEditorSection *section; + NmtNewtGrid *grid; + NMSettingTeamPort *s_port; + NmtNewtWidget *widget; + NMConnection *conn; + + conn = nmt_editor_page_get_connection (NMT_EDITOR_PAGE (team)); + s_port = nm_connection_get_setting_team_port (conn); + if (!s_port) { + nm_connection_add_setting (conn, nm_setting_team_port_new ()); + s_port = nm_connection_get_setting_team_port (conn); + } + priv->s_port = s_port; + + section = nmt_editor_section_new (_("TEAM PORT"), NULL, TRUE); + + widget = nmt_newt_grid_new (); + nmt_editor_grid_append (nmt_editor_section_get_body (section), NULL, widget, NULL); + + grid = NMT_NEWT_GRID (widget); + + widget = nmt_newt_label_new (_("JSON configuration")); + nmt_newt_grid_add (grid, widget, 0, 2); + + widget = nmt_newt_textbox_new (NMT_NEWT_TEXTBOX_SCROLLABLE | NMT_NEWT_TEXTBOX_SET_BACKGROUND, 60); + g_object_bind_property (s_port, NM_SETTING_TEAM_PORT_CONFIG, + widget, "text", + G_BINDING_SYNC_CREATE); + nmt_newt_grid_add (grid, widget, 0, 3); + nmt_newt_widget_set_padding (widget, 2, 0, 2, 1); + + widget = nmt_newt_button_new (_("Edit...")); + g_signal_connect (widget, "clicked", G_CALLBACK (edit_clicked), team); + nmt_newt_grid_add (grid, widget, 0, 4); + + nmt_editor_page_add_section (NMT_EDITOR_PAGE (team), section); + + G_OBJECT_CLASS (nmt_page_team_port_parent_class)->constructed (object); +} + +static void +nmt_page_team_port_class_init (NmtPageTeamPortClass *team_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (team_class); + + g_type_class_add_private (team_class, sizeof (NmtPageTeamPortPrivate)); + + object_class->constructed = nmt_page_team_port_constructed; +} diff --git a/clients/tui/nmt-page-team-port.h b/clients/tui/nmt-page-team-port.h new file mode 100644 index 00000000..2d8fa121 --- /dev/null +++ b/clients/tui/nmt-page-team-port.h @@ -0,0 +1,49 @@ +/* -*- 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. + */ + +#ifndef NMT_PAGE_TEAM_PORT_H +#define NMT_PAGE_TEAM_PORT_H + +#include "nmt-editor-page-device.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_PAGE_TEAM_PORT (nmt_page_team_port_get_type ()) +#define NMT_PAGE_TEAM_PORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_PAGE_TEAM_PORT, NmtPageTeamPort)) +#define NMT_PAGE_TEAM_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_PAGE_TEAM_PORT, NmtPageTeamPortClass)) +#define NMT_IS_PAGE_TEAM_PORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_PAGE_TEAM_PORT)) +#define NMT_IS_PAGE_TEAM_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_PAGE_TEAM_PORT)) +#define NMT_PAGE_TEAM_PORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_PAGE_TEAM_PORT, NmtPageTeamPortClass)) + +typedef struct { + NmtEditorPage parent; + +} NmtPageTeamPort; + +typedef struct { + NmtEditorPageClass parent; + +} NmtPageTeamPortClass; + +GType nmt_page_team_port_get_type (void); + +NmtEditorPage *nmt_page_team_port_new (NMConnection *conn); + +G_END_DECLS + +#endif /* NMT_PAGE_TEAM_PORT_H */ diff --git a/clients/tui/nmt-page-team.c b/clients/tui/nmt-page-team.c new file mode 100644 index 00000000..e520b02a --- /dev/null +++ b/clients/tui/nmt-page-team.c @@ -0,0 +1,193 @@ +/* -*- 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-page-team + * @short_description: The editor page for Team connections + */ + +#include "config.h" + +#include <glib.h> +#include <glib/gi18n-lib.h> + +#include "nmt-page-team.h" + +#include "nmt-slave-list.h" + +G_DEFINE_TYPE (NmtPageTeam, nmt_page_team, NMT_TYPE_EDITOR_PAGE_DEVICE) + +#define NMT_PAGE_TEAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_PAGE_TEAM, NmtPageTeamPrivate)) + +typedef struct { + NmtSlaveList *slaves; + + NMSettingTeam *s_team; + GType slave_type; + +} NmtPageTeamPrivate; + +NmtEditorPage * +nmt_page_team_new (NMConnection *conn, + NmtDeviceEntry *deventry) +{ + return g_object_new (NMT_TYPE_PAGE_TEAM, + "connection", conn, + "device-entry", deventry, + NULL); +} + +static void +nmt_page_team_init (NmtPageTeam *team) +{ + NmtPageTeamPrivate *priv = NMT_PAGE_TEAM_GET_PRIVATE (team); + + priv->slave_type = G_TYPE_NONE; +} + +static void +slaves_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + NmtPageTeam *team = NMT_PAGE_TEAM (user_data); + NmtPageTeamPrivate *priv = NMT_PAGE_TEAM_GET_PRIVATE (team); + GPtrArray *slaves; + + g_object_get (object, "connections", &slaves, NULL); + if (slaves->len == 0) { + priv->slave_type = G_TYPE_NONE; + } else if (priv->slave_type == G_TYPE_NONE) { + NMConnection *slave = slaves->pdata[0]; + + if (nm_connection_is_type (slave, NM_SETTING_INFINIBAND_SETTING_NAME)) + priv->slave_type = NM_TYPE_SETTING_INFINIBAND; + else + priv->slave_type = NM_TYPE_SETTING_WIRED; + } +} + +static gboolean +team_connection_type_filter (GType connection_type, + gpointer user_data) +{ + NmtPageTeam *team = user_data; + NmtPageTeamPrivate *priv = NMT_PAGE_TEAM_GET_PRIVATE (team); + + if (priv->slave_type != NM_TYPE_SETTING_WIRED) { + if (connection_type == NM_TYPE_SETTING_INFINIBAND) + return TRUE; + } + if (priv->slave_type != NM_TYPE_SETTING_INFINIBAND) { + if ( connection_type == NM_TYPE_SETTING_WIRED + || connection_type == NM_TYPE_SETTING_WIRELESS + || connection_type == NM_TYPE_SETTING_VLAN) + return TRUE; + } + + return FALSE; +} + +static void +edit_clicked (NmtNewtButton *button, + gpointer user_data) +{ + NmtPageTeam *team = user_data; + NmtPageTeamPrivate *priv = NMT_PAGE_TEAM_GET_PRIVATE (team); + const char *config; + char *new_config; + + config = nm_setting_team_get_config (priv->s_team); + if (!config) + config = ""; + + new_config = nmt_newt_edit_string (config); + + if (new_config && !*new_config) + g_clear_pointer (&new_config, g_free); + g_object_set (G_OBJECT (priv->s_team), + NM_SETTING_TEAM_CONFIG, new_config, + NULL); + g_free (new_config); +} + +static void +nmt_page_team_constructed (GObject *object) +{ + NmtPageTeam *team = NMT_PAGE_TEAM (object); + NmtPageTeamPrivate *priv = NMT_PAGE_TEAM_GET_PRIVATE (team); + NmtEditorSection *section; + NmtNewtGrid *grid; + NMSettingTeam *s_team; + NmtNewtWidget *widget; + NMConnection *conn; + + conn = nmt_editor_page_get_connection (NMT_EDITOR_PAGE (team)); + s_team = nm_connection_get_setting_team (conn); + if (!s_team) { + nm_connection_add_setting (conn, nm_setting_team_new ()); + s_team = nm_connection_get_setting_team (conn); + } + priv->s_team = s_team; + + section = nmt_editor_section_new (_("TEAM"), NULL, TRUE); + + widget = nmt_newt_grid_new (); + nmt_editor_grid_append (nmt_editor_section_get_body (section), NULL, widget, NULL); + + grid = NMT_NEWT_GRID (widget); + + widget = nmt_newt_label_new (_("Slaves")); + nmt_newt_grid_add (grid, widget, 0, 0); + + widget = nmt_slave_list_new (conn, team_connection_type_filter, team); + g_signal_connect (widget, "notify::connections", + G_CALLBACK (slaves_changed), team); + nmt_newt_grid_add (grid, widget, 0, 1); + nmt_newt_widget_set_padding (widget, 0, 0, 0, 1); + priv->slaves = NMT_SLAVE_LIST (widget); + slaves_changed (G_OBJECT (priv->slaves), NULL, team); + + widget = nmt_newt_label_new (_("JSON configuration")); + nmt_newt_grid_add (grid, widget, 0, 2); + + widget = nmt_newt_textbox_new (NMT_NEWT_TEXTBOX_SCROLLABLE | NMT_NEWT_TEXTBOX_SET_BACKGROUND, 60); + g_object_bind_property (s_team, NM_SETTING_TEAM_CONFIG, + widget, "text", + G_BINDING_SYNC_CREATE); + nmt_newt_grid_add (grid, widget, 0, 3); + nmt_newt_widget_set_padding (widget, 2, 0, 2, 1); + + widget = nmt_newt_button_new (_("Edit...")); + g_signal_connect (widget, "clicked", G_CALLBACK (edit_clicked), team); + nmt_newt_grid_add (grid, widget, 0, 4); + + nmt_editor_page_add_section (NMT_EDITOR_PAGE (team), section); + + G_OBJECT_CLASS (nmt_page_team_parent_class)->constructed (object); +} + +static void +nmt_page_team_class_init (NmtPageTeamClass *team_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (team_class); + + g_type_class_add_private (team_class, sizeof (NmtPageTeamPrivate)); + + object_class->constructed = nmt_page_team_constructed; +} diff --git a/clients/tui/nmt-page-team.h b/clients/tui/nmt-page-team.h new file mode 100644 index 00000000..2d8bf07a --- /dev/null +++ b/clients/tui/nmt-page-team.h @@ -0,0 +1,50 @@ +/* -*- 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. + */ + +#ifndef NMT_PAGE_TEAM_H +#define NMT_PAGE_TEAM_H + +#include "nmt-editor-page-device.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_PAGE_TEAM (nmt_page_team_get_type ()) +#define NMT_PAGE_TEAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_PAGE_TEAM, NmtPageTeam)) +#define NMT_PAGE_TEAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_PAGE_TEAM, NmtPageTeamClass)) +#define NMT_IS_PAGE_TEAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_PAGE_TEAM)) +#define NMT_IS_PAGE_TEAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_PAGE_TEAM)) +#define NMT_PAGE_TEAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_PAGE_TEAM, NmtPageTeamClass)) + +typedef struct { + NmtEditorPageDevice parent; + +} NmtPageTeam; + +typedef struct { + NmtEditorPageDeviceClass parent; + +} NmtPageTeamClass; + +GType nmt_page_team_get_type (void); + +NmtEditorPage *nmt_page_team_new (NMConnection *conn, + NmtDeviceEntry *deventry); + +G_END_DECLS + +#endif /* NMT_PAGE_TEAM_H */ diff --git a/clients/tui/nmt-page-vlan.c b/clients/tui/nmt-page-vlan.c new file mode 100644 index 00000000..9b9c8f52 --- /dev/null +++ b/clients/tui/nmt-page-vlan.c @@ -0,0 +1,158 @@ +/* -*- 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-page-vlan + * @short_description: The editor page for VLAN connections + */ + +#include "config.h" + +#include <glib.h> +#include <glib/gi18n-lib.h> + +#include "nm-editor-bindings.h" + +#include "nmt-page-vlan.h" +#include "nmt-device-entry.h" +#include "nmt-mac-entry.h" +#include "nmt-mtu-entry.h" + +G_DEFINE_TYPE (NmtPageVlan, nmt_page_vlan, NMT_TYPE_EDITOR_PAGE_DEVICE) + +#define NMT_PAGE_VLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_PAGE_VLAN, NmtPageVlanPrivate)) + +typedef struct { + NMSettingWired *s_wired; + +} NmtPageVlanPrivate; + +NmtEditorPage * +nmt_page_vlan_new (NMConnection *conn, + NmtDeviceEntry *deventry) +{ + return g_object_new (NMT_TYPE_PAGE_VLAN, + "connection", conn, + "device-entry", deventry, + NULL); +} + +static void +nmt_page_vlan_init (NmtPageVlan *vlan) +{ +} + +static gboolean +vlan_device_filter (NmtDeviceEntry *deventry, + NMDevice *device, + gpointer user_data) +{ + // FIXME + return NM_IS_DEVICE_ETHERNET (device); +} + +static void +nmt_page_vlan_constructed (GObject *object) +{ + NmtPageVlan *vlan = NMT_PAGE_VLAN (object); + NmtPageVlanPrivate *priv = NMT_PAGE_VLAN_GET_PRIVATE (vlan); + NmtEditorSection *section; + NmtEditorGrid *grid; + NMSettingWired *s_wired; + NMSettingVlan *s_vlan; + NmtNewtWidget *widget, *parent, *id_entry; + NMConnection *conn; + + conn = nmt_editor_page_get_connection (NMT_EDITOR_PAGE (vlan)); + s_vlan = nm_connection_get_setting_vlan (conn); + if (!s_vlan) { + nm_connection_add_setting (conn, nm_setting_vlan_new ()); + s_vlan = nm_connection_get_setting_vlan (conn); + } + s_wired = nm_connection_get_setting_wired (conn); + if (!s_wired) { + /* It makes things simpler if we always have a NMSettingWired; + * we'll hold a ref on one, and add it to and remove it from + * the connection as needed. + */ + s_wired = NM_SETTING_WIRED (nm_setting_wired_new ()); + } + priv->s_wired = g_object_ref_sink (s_wired); + + section = nmt_editor_section_new (_("VLAN"), NULL, TRUE); + grid = nmt_editor_section_get_body (section); + + nm_editor_bind_vlan_name (s_vlan, nm_connection_get_setting_connection (conn)); + + widget = parent = nmt_device_entry_new (_("Parent"), 40, G_TYPE_NONE); + nmt_device_entry_set_device_filter (NMT_DEVICE_ENTRY (widget), + vlan_device_filter, vlan); + g_object_bind_property (s_vlan, NM_SETTING_VLAN_PARENT, + widget, "interface-name", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + g_object_bind_property (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, + widget, "mac-address", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, NULL, widget, NULL); + + widget = id_entry = nmt_newt_entry_numeric_new (8, 0, 4095); + g_object_bind_property (s_vlan, NM_SETTING_VLAN_ID, + widget, "text", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("VLAN id"), widget, NULL); + + nmt_editor_grid_append (grid, NULL, nmt_newt_separator_new (), NULL); + + widget = nmt_mac_entry_new (40, ETH_ALEN); + g_object_bind_property (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, + widget, "mac-address", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("Cloned MAC address"), widget, NULL); + + widget = nmt_mtu_entry_new (); + g_object_bind_property (s_wired, NM_SETTING_WIRED_MTU, + widget, "mtu", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("MTU"), widget, NULL); + + nmt_editor_page_add_section (NMT_EDITOR_PAGE (vlan), section); + + G_OBJECT_CLASS (nmt_page_vlan_parent_class)->constructed (object); +} + +static void +nmt_page_vlan_finalize (GObject *object) +{ + NmtPageVlanPrivate *priv = NMT_PAGE_VLAN_GET_PRIVATE (object); + + g_clear_object (&priv->s_wired); + + G_OBJECT_CLASS (nmt_page_vlan_parent_class)->finalize (object); +} + +static void +nmt_page_vlan_class_init (NmtPageVlanClass *vlan_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (vlan_class); + + g_type_class_add_private (vlan_class, sizeof (NmtPageVlanPrivate)); + + /* virtual methods */ + object_class->constructed = nmt_page_vlan_constructed; + object_class->finalize = nmt_page_vlan_finalize; +} diff --git a/clients/tui/nmt-page-vlan.h b/clients/tui/nmt-page-vlan.h new file mode 100644 index 00000000..db7c4098 --- /dev/null +++ b/clients/tui/nmt-page-vlan.h @@ -0,0 +1,50 @@ +/* -*- 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. + */ + +#ifndef NMT_PAGE_VLAN_H +#define NMT_PAGE_VLAN_H + +#include "nmt-editor-page-device.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_PAGE_VLAN (nmt_page_vlan_get_type ()) +#define NMT_PAGE_VLAN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_PAGE_VLAN, NmtPageVlan)) +#define NMT_PAGE_VLAN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_PAGE_VLAN, NmtPageVlanClass)) +#define NMT_IS_PAGE_VLAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_PAGE_VLAN)) +#define NMT_IS_PAGE_VLAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_PAGE_VLAN)) +#define NMT_PAGE_VLAN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_PAGE_VLAN, NmtPageVlanClass)) + +typedef struct { + NmtEditorPageDevice parent; + +} NmtPageVlan; + +typedef struct { + NmtEditorPageDeviceClass parent; + +} NmtPageVlanClass; + +GType nmt_page_vlan_get_type (void); + +NmtEditorPage *nmt_page_vlan_new (NMConnection *conn, + NmtDeviceEntry *deventry); + +G_END_DECLS + +#endif /* NMT_PAGE_VLAN_H */ diff --git a/clients/tui/nmt-page-wifi.c b/clients/tui/nmt-page-wifi.c new file mode 100644 index 00000000..9cd20abf --- /dev/null +++ b/clients/tui/nmt-page-wifi.c @@ -0,0 +1,400 @@ +/* -*- 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-page-wifi + * @short_description: The editor page for Wi-Fi connections + * + * #NmtPageWifi is the editor page for Wi-Fi connections, which + * includes both #NMSettingWireless and #NMSettingWirelessSecurity + * properties. + */ + +#include "config.h" + +#include <stdlib.h> + +#include <glib.h> +#include <glib/gi18n-lib.h> + +#include "nmt-page-wifi.h" +#include "nmt-mac-entry.h" +#include "nmt-mtu-entry.h" +#include "nmt-password-fields.h" + +#include "nm-editor-bindings.h" + +G_DEFINE_TYPE (NmtPageWifi, nmt_page_wifi, NMT_TYPE_EDITOR_PAGE_DEVICE) + +#define NMT_PAGE_WIFI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_PAGE_WIFI, NmtPageWifiPrivate)) + +typedef struct { + NMSettingWirelessSecurity *s_wsec; + +} NmtPageWifiPrivate; + +NmtEditorPage * +nmt_page_wifi_new (NMConnection *conn, + NmtDeviceEntry *deventry) +{ + return g_object_new (NMT_TYPE_PAGE_WIFI, + "connection", conn, + "device-entry", deventry, + NULL); +} + +static void +nmt_page_wifi_init (NmtPageWifi *wifi) +{ +} + +static NmtNewtPopupEntry wifi_mode[] = { + { NC_("Wi-Fi", "Client"), NM_SETTING_WIRELESS_MODE_INFRA }, + { N_("Access Point"), NM_SETTING_WIRELESS_MODE_AP }, + { N_("Ad-Hoc Network"), NM_SETTING_WIRELESS_MODE_ADHOC }, + { NULL, NULL } +}; + +static NmtNewtPopupEntry wifi_band[] = { + { NC_("Wi-Fi", "Automatic"), NULL }, + /* 802.11a Wi-Fi network */ + { N_("A (5 GHz)"), "a" }, + /* 802.11b / 802.11g Wi-Fi network */ + { N_("B/G (2.4 GHz)"), "bg" }, + { NULL, NULL } +}; + +static NmtNewtPopupEntry wifi_security[] = { + { NC_("Wi-Fi security", "None"), "none" }, + { N_("WPA & WPA2 Personal"), "wpa-personal" }, + { N_("WPA & WPA2 Enterprise"), "wpa-enterprise" }, + { N_("WEP 40/128-bit Key (Hex or ASCII)"), "wep-key" }, + { N_("WEP 128-bit Passphrase"), "wep-passphrase" }, + { N_("Dynamic WEP (802.1x)"), "dynamic-wep" }, + { N_("LEAP"), "leap" }, + { NULL, NULL } +}; + +static NmtNewtPopupEntry wep_index[] = { + { NC_("WEP key index", "1 (Default)"), "1" }, + { NC_("WEP key index", "2"), "2" }, + { NC_("WEP key index", "3"), "3" }, + { NC_("WEP key index", "4"), "4" }, + { NULL, NULL } +}; + +static NmtNewtPopupEntry wep_auth[] = { + { N_("Open System"), "open" }, + { N_("Shared Key"), "shared" }, + { NULL, NULL } +}; + +static gboolean +mode_transform_to_band_visibility (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + if (!g_strcmp0 (g_value_get_string (source_value), NM_SETTING_WIRELESS_MODE_INFRA)) + g_value_set_boolean (target_value, FALSE); + else + g_value_set_boolean (target_value, TRUE); + return TRUE; +} + +static gboolean +band_transform_to_channel_visibility (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + g_value_set_boolean (target_value, g_value_get_string (source_value) != NULL); + return TRUE; +} + +static gboolean +ssid_transform_to_entry (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + GBytes *ssid; + char *utf8; + + ssid = g_value_get_boxed (source_value); + if (ssid) + utf8 = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL), + g_bytes_get_size (ssid)); + else + utf8 = g_strdup (""); + g_value_take_string (target_value, utf8); + return TRUE; +} + +static gboolean +ssid_transform_from_entry (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + NMSettingWireless *s_wireless = user_data; + const char *text; + GBytes *old_ssid, *ssid; + char *utf8; + + text = g_value_get_string (source_value); + + old_ssid = nm_setting_wireless_get_ssid (s_wireless); + if (old_ssid) + utf8 = nm_utils_ssid_to_utf8 (g_bytes_get_data (old_ssid, NULL), + g_bytes_get_size (old_ssid)); + else + utf8 = g_strdup (""); + + if (!g_strcmp0 (text, utf8)) { + g_free (utf8); + return FALSE; + } + g_free (utf8); + + ssid = g_bytes_new (text, strlen (text)); + g_value_take_boxed (target_value, ssid); + return TRUE; +} + +static void +nmt_page_wifi_constructed (GObject *object) +{ + NmtPageWifiPrivate *priv = NMT_PAGE_WIFI_GET_PRIVATE (object); + NmtPageWifi *wifi = NMT_PAGE_WIFI (object); + NmtDeviceEntry *deventry; + NmtEditorSection *section; + NmtEditorGrid *grid; + NMSettingWireless *s_wireless; + NMSettingWirelessSecurity *s_wsec; + NmtNewtWidget *widget, *hbox, *subgrid; + NmtNewtWidget *mode, *band, *security, *entry; + NmtNewtStack *stack; + NMConnection *conn; + + conn = nmt_editor_page_get_connection (NMT_EDITOR_PAGE (wifi)); + s_wireless = nm_connection_get_setting_wireless (conn); + if (!s_wireless) { + nm_connection_add_setting (conn, nm_setting_wireless_new ()); + s_wireless = nm_connection_get_setting_wireless (conn); + } + + s_wsec = nm_connection_get_setting_wireless_security (conn); + if (!s_wsec) { + /* It makes things simpler if we always have a + * NMSettingWirelessSecurity; we'll hold a ref on one, and add + * it to and remove it from the connection as needed. + */ + s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ()); + } + priv->s_wsec = g_object_ref_sink (s_wsec); + + deventry = nmt_editor_page_device_get_device_entry (NMT_EDITOR_PAGE_DEVICE (object)); + g_object_bind_property (s_wireless, NM_SETTING_WIRELESS_MAC_ADDRESS, + deventry, "mac-address", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + + section = nmt_editor_section_new (_("WI-FI"), NULL, TRUE); + grid = nmt_editor_section_get_body (section); + + widget = nmt_newt_entry_new (40, NMT_NEWT_ENTRY_NONEMPTY); + g_object_bind_property_full (s_wireless, NM_SETTING_WIRELESS_SSID, + widget, "text", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, + ssid_transform_to_entry, + ssid_transform_from_entry, + s_wireless, NULL); + nmt_editor_grid_append (grid, _("SSID"), widget, NULL); + + widget = nmt_newt_popup_new (wifi_mode); + g_object_bind_property (s_wireless, NM_SETTING_WIRELESS_MODE, + widget, "active-id", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("Mode"), widget, NULL); + mode = widget; + + hbox = nmt_newt_grid_new (); + widget = nmt_newt_popup_new (wifi_band); + g_object_bind_property (s_wireless, NM_SETTING_WIRELESS_BAND, + widget, "active-id", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_newt_grid_add (NMT_NEWT_GRID (hbox), widget, 0, 0); + band = widget; + + widget = nmt_newt_entry_numeric_new (10, 0, 255); + g_object_bind_property (s_wireless, NM_SETTING_WIRELESS_CHANNEL, + widget, "text", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_newt_grid_add (NMT_NEWT_GRID (hbox), widget, 1, 0); + nmt_newt_widget_set_padding (widget, 1, 0, 0, 0); + + g_object_bind_property_full (band, "active-id", widget, "visible", + G_BINDING_SYNC_CREATE, + band_transform_to_channel_visibility, + NULL, NULL, NULL); + g_object_bind_property_full (mode, "active-id", hbox, "visible", + G_BINDING_SYNC_CREATE, + mode_transform_to_band_visibility, + NULL, NULL, NULL); + nmt_editor_grid_append (grid, _("Channel"), hbox, NULL); + + nmt_editor_grid_append (grid, NULL, nmt_newt_separator_new (), NULL); + + widget = nmt_newt_popup_new (wifi_security); + nmt_editor_grid_append (grid, _("Security"), widget, NULL); + security = widget; + + widget = nmt_newt_stack_new (); + stack = NMT_NEWT_STACK (widget); + + /* none */ + subgrid = nmt_editor_grid_new (); + nmt_newt_stack_add (stack, "none", subgrid); + + /* wpa-personal */ + subgrid = nmt_editor_grid_new (); + widget = nmt_password_fields_new (40, NMT_PASSWORD_FIELDS_SHOW_PASSWORD); + g_object_bind_property (s_wsec, NM_SETTING_WIRELESS_SECURITY_PSK, + widget, "password", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + nmt_editor_grid_append (NMT_EDITOR_GRID (subgrid), _("Password"), widget, NULL); + nmt_newt_stack_add (stack, "wpa-personal", subgrid); + + /* "wpa-enterprise" */ + // FIXME + widget = nmt_newt_label_new (_("(No support for wpa-enterprise yet...)")); + nmt_newt_stack_add (stack, "wpa-enterprise", widget); + + /* wep-key */ + subgrid = nmt_editor_grid_new (); + + widget = entry = nmt_password_fields_new (40, NMT_PASSWORD_FIELDS_SHOW_PASSWORD); + nmt_editor_grid_append (NMT_EDITOR_GRID (subgrid), _("Key"), widget, NULL); + + widget = nmt_newt_popup_new (wep_index); + nmt_editor_grid_append (NMT_EDITOR_GRID (subgrid), _("WEP index"), widget, NULL); + + nm_editor_bind_wireless_security_wep_key (s_wsec, + entry, "password", + widget, "active", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + + widget = nmt_newt_popup_new (wep_auth); + nmt_editor_grid_append (NMT_EDITOR_GRID (subgrid), _("Authentication"), widget, NULL); + + nmt_newt_stack_add (stack, "wep-key", subgrid); + + /* wep-passphrase */ + subgrid = nmt_editor_grid_new (); + + widget = entry = nmt_password_fields_new (40, NMT_PASSWORD_FIELDS_SHOW_PASSWORD); + nmt_editor_grid_append (NMT_EDITOR_GRID (subgrid), _("Password"), widget, NULL); + + widget = nmt_newt_popup_new (wep_index); + nmt_editor_grid_append (NMT_EDITOR_GRID (subgrid), _("WEP index"), widget, NULL); + + nm_editor_bind_wireless_security_wep_key (s_wsec, + entry, "password", + widget, "active", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + + widget = nmt_newt_popup_new (wep_auth); + nmt_editor_grid_append (NMT_EDITOR_GRID (subgrid), _("Authentication"), widget, NULL); + + nmt_newt_stack_add (stack, "wep-passphrase", subgrid); + + /* "dynamic-wep" */ + // FIXME + widget = nmt_newt_label_new (_("(No support for dynamic-wep yet...)")); + nmt_newt_stack_add (stack, "dynamic-wep", widget); + + /* leap */ + subgrid = nmt_editor_grid_new (); + + widget = nmt_newt_entry_new (40, NMT_NEWT_ENTRY_NONEMPTY); + nmt_editor_grid_append (NMT_EDITOR_GRID (subgrid), _("Username"), widget, NULL); + g_object_bind_property (s_wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, + widget, "text", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + + widget = nmt_password_fields_new (40, NMT_PASSWORD_FIELDS_SHOW_PASSWORD); + g_object_bind_property (s_wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, + widget, "password", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + nmt_editor_grid_append (NMT_EDITOR_GRID (subgrid), _("Password"), widget, NULL); + + nmt_newt_stack_add (stack, "leap", subgrid); + + nmt_editor_grid_append (grid, NULL, NMT_NEWT_WIDGET (stack), NULL); + g_object_bind_property (security, "active-id", + stack, "active-id", + G_BINDING_SYNC_CREATE); + nm_editor_bind_wireless_security_method (conn, s_wsec, security, "active-id", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + + nmt_editor_grid_append (grid, NULL, nmt_newt_separator_new (), NULL); + + widget = nmt_mac_entry_new (40, ETH_ALEN); + g_object_bind_property (s_wireless, NM_SETTING_WIRELESS_BSSID, + widget, "mac-address", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("BSSID"), widget, NULL); + + widget = nmt_mac_entry_new (40, ETH_ALEN); + g_object_bind_property (s_wireless, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, + widget, "mac-address", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("Cloned MAC address"), widget, NULL); + + widget = nmt_mtu_entry_new (); + g_object_bind_property (s_wireless, NM_SETTING_WIRELESS_MTU, + widget, "mtu", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append (grid, _("MTU"), widget, NULL); + + nmt_editor_page_add_section (NMT_EDITOR_PAGE (wifi), section); + + G_OBJECT_CLASS (nmt_page_wifi_parent_class)->constructed (object); +} + +static void +nmt_page_wifi_finalize (GObject *object) +{ + NmtPageWifiPrivate *priv = NMT_PAGE_WIFI_GET_PRIVATE (object); + + g_clear_object (&priv->s_wsec); + + G_OBJECT_CLASS (nmt_page_wifi_parent_class)->finalize (object); +} + + +static void +nmt_page_wifi_class_init (NmtPageWifiClass *wifi_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (wifi_class); + + g_type_class_add_private (wifi_class, sizeof (NmtPageWifiPrivate)); + + object_class->constructed = nmt_page_wifi_constructed; + object_class->finalize = nmt_page_wifi_finalize; +} diff --git a/clients/tui/nmt-page-wifi.h b/clients/tui/nmt-page-wifi.h new file mode 100644 index 00000000..7ce50584 --- /dev/null +++ b/clients/tui/nmt-page-wifi.h @@ -0,0 +1,50 @@ +/* -*- 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. + */ + +#ifndef NMT_PAGE_WIFI_H +#define NMT_PAGE_WIFI_H + +#include "nmt-editor-page-device.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_PAGE_WIFI (nmt_page_wifi_get_type ()) +#define NMT_PAGE_WIFI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_PAGE_WIFI, NmtPageWifi)) +#define NMT_PAGE_WIFI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_PAGE_WIFI, NmtPageWifiClass)) +#define NMT_IS_PAGE_WIFI(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_PAGE_WIFI)) +#define NMT_IS_PAGE_WIFI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_PAGE_WIFI)) +#define NMT_PAGE_WIFI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_PAGE_WIFI, NmtPageWifiClass)) + +typedef struct { + NmtEditorPageDevice parent; + +} NmtPageWifi; + +typedef struct { + NmtEditorPageDeviceClass parent; + +} NmtPageWifiClass; + +GType nmt_page_wifi_get_type (void); + +NmtEditorPage *nmt_page_wifi_new (NMConnection *conn, + NmtDeviceEntry *deventry); + +G_END_DECLS + +#endif /* NMT_PAGE_WIFI_H */ diff --git a/clients/tui/nmt-password-dialog.c b/clients/tui/nmt-password-dialog.c new file mode 100644 index 00000000..aeece121 --- /dev/null +++ b/clients/tui/nmt-password-dialog.c @@ -0,0 +1,345 @@ +/* -*- 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-password-dialog + * @short_description: A password dialog + * + * #NmtPasswordDialog is the password dialog used to get connection + * secrets when activating a connection. + */ + +#include "config.h" + +#include <glib/gi18n-lib.h> + +#include "nmt-password-dialog.h" +#include "nm-secret-agent-simple.h" +#include "nmtui.h" + +G_DEFINE_TYPE (NmtPasswordDialog, nmt_password_dialog, NMT_TYPE_NEWT_FORM) + +#define NMT_PASSWORD_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_PASSWORD_DIALOG, NmtPasswordDialogPrivate)) + +typedef struct { + char *request_id; + char *prompt; + GPtrArray *secrets; + GPtrArray *entries; + + NmtNewtWidget *ok, *cancel; + NmtNewtWidget *last_entry; + NmtNewtWidget *secret_grid; + + gboolean succeeded; +} NmtPasswordDialogPrivate; + +enum { + PROP_0, + PROP_REQUEST_ID, + PROP_PROMPT, + PROP_SECRETS, + + LAST_PROP +}; + +/** + * nmt_password_dialog_new: + * @request_id: the request ID from the #NMSecretAgentSimple + * @title: the dialog title + * @prompt: the prompt text to display + * @secrets: (element-type #NMSecretAgentSimpleSecret): the secrets requested + * + * Creates a new #NmtPasswordDialog to request passwords from + * the user. + * + * Returns: a new #NmtPasswordDialog. + */ +NmtNewtForm * +nmt_password_dialog_new (const char *request_id, + const char *title, + const char *prompt, + GPtrArray *secrets) +{ + return g_object_new (NMT_TYPE_PASSWORD_DIALOG, + "request-id", request_id, + "title", title, + "prompt", prompt, + "secrets", secrets, + "escape-exits", TRUE, + NULL); +} + +static void +nmt_password_dialog_init (NmtPasswordDialog *dialog) +{ + NmtPasswordDialogPrivate *priv = NMT_PASSWORD_DIALOG_GET_PRIVATE (dialog); + + priv->entries = g_ptr_array_new (); +} + +static void +maybe_save_input_and_exit (NmtNewtWidget *widget, + gpointer dialog) +{ + NmtPasswordDialogPrivate *priv = NMT_PASSWORD_DIALOG_GET_PRIVATE (dialog); + int i; + + /* This gets invoked when the user types Return in the final entry, + * but the form may not be fully valid in that case. + */ + if (!nmt_newt_widget_get_valid (priv->secret_grid)) + return; + + priv->succeeded = TRUE; + + for (i = 0; i < priv->secrets->len; i++) { + NMSecretAgentSimpleSecret *secret = priv->secrets->pdata[i]; + + g_free (secret->value); + g_object_get (priv->entries->pdata[i], "text", &secret->value, NULL); + } + + nmt_newt_form_quit (nmt_newt_widget_get_form (widget)); +} + +static void +nmt_password_dialog_constructed (GObject *object) +{ + NmtPasswordDialog *dialog = NMT_PASSWORD_DIALOG (object); + NmtPasswordDialogPrivate *priv = NMT_PASSWORD_DIALOG_GET_PRIVATE (dialog); + NmtNewtWidget *widget; + NmtNewtGrid *grid, *secret_grid; + NmtNewtButtonBox *bbox; + int i; + + widget = nmt_newt_grid_new (); + nmt_newt_form_set_content (NMT_NEWT_FORM (dialog), widget); + grid = NMT_NEWT_GRID (widget); + + widget = nmt_newt_textbox_new (0, 60); + nmt_newt_textbox_set_text (NMT_NEWT_TEXTBOX (widget), priv->prompt); + nmt_newt_grid_add (grid, widget, 0, 0); + + widget = nmt_newt_grid_new (); + nmt_newt_grid_add (grid, widget, 0, 1); + nmt_newt_widget_set_padding (widget, 0, 1, 0, 1); + priv->secret_grid = widget; + secret_grid = NMT_NEWT_GRID (widget); + + for (i = 0; i < priv->secrets->len; i++) { + NMSecretAgentSimpleSecret *secret = priv->secrets->pdata[i]; + NmtNewtEntryFlags flags; + + widget = nmt_newt_label_new (secret->name); + nmt_newt_grid_add (secret_grid, widget, 0, i); + nmt_newt_widget_set_padding (widget, 4, 0, 1, 0); + + flags = NMT_NEWT_ENTRY_NONEMPTY; + if (secret->password) + flags |= NMT_NEWT_ENTRY_PASSWORD; + widget = nmt_newt_entry_new (30, flags); + nmt_newt_grid_add (secret_grid, widget, 1, i); + g_ptr_array_add (priv->entries, widget); + + if (i == priv->secrets->len - 1) { + priv->last_entry = widget; + g_signal_connect (widget, "activated", + G_CALLBACK (maybe_save_input_and_exit), dialog); + } + } + + widget = nmt_newt_button_box_new (NMT_NEWT_BUTTON_BOX_HORIZONTAL); + nmt_newt_grid_add (grid, widget, 0, 2); + bbox = NMT_NEWT_BUTTON_BOX (widget); + + priv->cancel = nmt_newt_button_box_add_end (NMT_NEWT_BUTTON_BOX (bbox), _("Cancel")); + nmt_newt_widget_set_exit_on_activate (priv->cancel, TRUE); + + priv->ok = nmt_newt_button_box_add_end (NMT_NEWT_BUTTON_BOX (bbox), _("OK")); + g_signal_connect (priv->ok, "activated", + G_CALLBACK (maybe_save_input_and_exit), dialog); + g_object_bind_property (priv->secret_grid, "valid", + priv->ok, "sensitive", + G_BINDING_SYNC_CREATE); + + G_OBJECT_CLASS (nmt_password_dialog_parent_class)->constructed (object); +} + +static void +nmt_password_dialog_finalize (GObject *object) +{ + NmtPasswordDialogPrivate *priv = NMT_PASSWORD_DIALOG_GET_PRIVATE (object); + + g_free (priv->request_id); + g_free (priv->prompt); + g_clear_pointer (&priv->entries, g_ptr_array_unref); + g_clear_pointer (&priv->secrets, g_ptr_array_unref); + + G_OBJECT_CLASS (nmt_password_dialog_parent_class)->finalize (object); +} + +static void +nmt_password_dialog_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtPasswordDialogPrivate *priv = NMT_PASSWORD_DIALOG_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_REQUEST_ID: + priv->request_id = g_value_dup_string (value); + break; + case PROP_PROMPT: + priv->prompt = g_value_dup_string (value); + break; + case PROP_SECRETS: + priv->secrets = g_value_dup_boxed (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_password_dialog_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtPasswordDialogPrivate *priv = NMT_PASSWORD_DIALOG_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_REQUEST_ID: + g_value_set_string (value, priv->request_id); + break; + case PROP_PROMPT: + g_value_set_string (value, priv->prompt); + break; + case PROP_SECRETS: + g_value_set_boxed (value, priv->secrets); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_password_dialog_class_init (NmtPasswordDialogClass *dialog_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (dialog_class); + + g_type_class_add_private (dialog_class, sizeof (NmtPasswordDialogPrivate)); + + /* virtual methods */ + object_class->constructed = nmt_password_dialog_constructed; + object_class->set_property = nmt_password_dialog_set_property; + object_class->get_property = nmt_password_dialog_get_property; + object_class->finalize = nmt_password_dialog_finalize; + + /** + * NmtPasswordDialog:request-id: + * + * The request ID from the #NMSecretAgentSimple + */ + g_object_class_install_property + (object_class, PROP_REQUEST_ID, + g_param_spec_string ("request-id", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtPasswordDialog:prompt: + * + * The prompt text. + */ + g_object_class_install_property + (object_class, PROP_PROMPT, + g_param_spec_string ("prompt", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtPasswordDialog:secrets: + * + * The array of request secrets + * + * Element-Type: #NMSecretAgentSimpleSecret. + */ + g_object_class_install_property + (object_class, PROP_SECRETS, + g_param_spec_boxed ("secrets", "", "", + G_TYPE_PTR_ARRAY, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} + +/** + * nmt_password_dialog_succeeded: + * @dialog: the #NmtPasswordDialog + * + * After the dialog has exited, returns %TRUE if the user clicked + * "OK", %FALSE if "Cancel". + * + * Returns: whether the dialog succeeded. + */ +gboolean +nmt_password_dialog_succeeded (NmtPasswordDialog *dialog) +{ + NmtPasswordDialogPrivate *priv = NMT_PASSWORD_DIALOG_GET_PRIVATE (dialog); + + return priv->succeeded; +} + +/** + * nmt_password_dialog_get_request_id: + * @dialog: the #NmtPasswordDialog + * + * Gets the dialog's request ID. + * + * Returns: the dialog's request ID. + */ +const char * +nmt_password_dialog_get_request_id (NmtPasswordDialog *dialog) +{ + NmtPasswordDialogPrivate *priv = NMT_PASSWORD_DIALOG_GET_PRIVATE (dialog); + + return priv->request_id; +} + +/** + * nmt_password_dialog_get_secrets: + * @dialog: the #NmtPasswordDialog + * + * Gets the dialog's secrets array. + * + * Returns: (transfer none): the dialog's secrets array. + */ +GPtrArray * +nmt_password_dialog_get_secrets (NmtPasswordDialog *dialog) +{ + NmtPasswordDialogPrivate *priv = NMT_PASSWORD_DIALOG_GET_PRIVATE (dialog); + + return priv->secrets; +} diff --git a/clients/tui/nmt-password-dialog.h b/clients/tui/nmt-password-dialog.h new file mode 100644 index 00000000..36c9f51e --- /dev/null +++ b/clients/tui/nmt-password-dialog.h @@ -0,0 +1,57 @@ +/* -*- 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. + */ + +#ifndef NMT_PASSWORD_DIALOG_H +#define NMT_PASSWORD_DIALOG_H + +#include "nmt-newt.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_PASSWORD_DIALOG (nmt_password_dialog_get_type ()) +#define NMT_PASSWORD_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_PASSWORD_DIALOG, NmtPasswordDialog)) +#define NMT_PASSWORD_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_PASSWORD_DIALOG, NmtPasswordDialogClass)) +#define NMT_IS_PASSWORD_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_PASSWORD_DIALOG)) +#define NMT_IS_PASSWORD_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_PASSWORD_DIALOG)) +#define NMT_PASSWORD_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_PASSWORD_DIALOG, NmtPasswordDialogClass)) + +typedef struct { + NmtNewtForm parent; + +} NmtPasswordDialog; + +typedef struct { + NmtNewtFormClass parent; + +} NmtPasswordDialogClass; + +GType nmt_password_dialog_get_type (void); + +NmtNewtForm *nmt_password_dialog_new (const char *request_id, + const char *title, + const char *prompt, + GPtrArray *secrets); + +gboolean nmt_password_dialog_succeeded (NmtPasswordDialog *dialog); + +const char *nmt_password_dialog_get_request_id (NmtPasswordDialog *dialog); +GPtrArray *nmt_password_dialog_get_secrets (NmtPasswordDialog *dialog); + +G_END_DECLS + +#endif /* NMT_PASSWORD_DIALOG_H */ diff --git a/clients/tui/nmt-password-fields.c b/clients/tui/nmt-password-fields.c new file mode 100644 index 00000000..7ef037b9 --- /dev/null +++ b/clients/tui/nmt-password-fields.c @@ -0,0 +1,319 @@ +/* -*- 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-password-fields + * @short_description: Widgets for password-related data + * + * #NmtPasswordFields provides an entry to type a password into, followed + * optionally by an "Ask for this password every time" checkbox and/or a + * "Show password" checkbox that toggles whether the password is visible. + */ + +#include "config.h" + +#include <glib/gi18n-lib.h> + +#include "nmt-password-fields.h" + +G_DEFINE_TYPE (NmtPasswordFields, nmt_password_fields, NMT_TYPE_NEWT_GRID) + +#define NMT_PASSWORD_FIELDS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_PASSWORD_FIELDS, NmtPasswordFieldsPrivate)) + +typedef struct { + NmtPasswordFieldsExtras extras; + + NmtNewtEntry *entry; + NmtNewtCheckbox *always_ask; + NmtNewtCheckbox *show_password; + + char *init_password; + +} NmtPasswordFieldsPrivate; + +enum { + PROP_0, + PROP_WIDTH, + PROP_EXTRAS, + PROP_PASSWORD, + PROP_ALWAYS_ASK, + PROP_SHOW_PASSWORD, + + LAST_PROP +}; + +/** + * NmtPasswordFieldsExtras: + * @NMT_PASSWORD_FIELDS_ALWAYS_ASK: show an "Always ask" checkbox + * @NMT_PASSWORD_FIELDS_SHOW_PASSWORD: show a "Show password" checkbox + * + * Extra widgets to include in an #NmtPasswordFields + */ + +/** + * nmt_password_fields_new: + * @width: width in characters of the password entry + * @extras: extra widgets to show + * + * Creates a new #NmtPasswordFields + * + * Returns: a new #NmtPasswordFields + */ +NmtNewtWidget * +nmt_password_fields_new (int width, + NmtPasswordFieldsExtras extras) +{ + return g_object_new (NMT_TYPE_PASSWORD_FIELDS, + "width", width, + "extras", extras, + NULL); +} + +static void +nmt_password_fields_set_password (NmtPasswordFields *fields, + const char *password) +{ + NmtPasswordFieldsPrivate *priv = NMT_PASSWORD_FIELDS_GET_PRIVATE (fields); + + if (!g_strcmp0 (password, nmt_newt_entry_get_text (priv->entry))) + return; + + nmt_newt_entry_set_text (priv->entry, password); + g_object_notify (G_OBJECT (fields), "password"); +} + +static const char * +nmt_password_fields_get_password (NmtPasswordFields *fields) +{ + NmtPasswordFieldsPrivate *priv = NMT_PASSWORD_FIELDS_GET_PRIVATE (fields); + + return nmt_newt_entry_get_text (priv->entry); +} + +static void +always_ask_changed (GObject *object, + GParamSpec *pspec, + gpointer fields) +{ + g_object_notify (fields, "always-ask"); +} + +static void +show_password_changed (GObject *object, + GParamSpec *pspec, + gpointer fields) +{ + g_object_notify (fields, "show-password"); +} + +static void +nmt_password_fields_init (NmtPasswordFields *fields) +{ + NmtPasswordFieldsPrivate *priv = NMT_PASSWORD_FIELDS_GET_PRIVATE (fields); + + priv->entry = NMT_NEWT_ENTRY (nmt_newt_entry_new (-1, 0)); + priv->always_ask = NMT_NEWT_CHECKBOX (nmt_newt_checkbox_new (_("Ask for this password every time"))); + priv->show_password = NMT_NEWT_CHECKBOX (nmt_newt_checkbox_new (_("Show password"))); +} + +static void +nmt_password_fields_constructed (GObject *object) +{ + NmtPasswordFieldsPrivate *priv = NMT_PASSWORD_FIELDS_GET_PRIVATE (object); + NmtNewtGrid *grid = NMT_NEWT_GRID (object); + + nmt_newt_grid_add (grid, NMT_NEWT_WIDGET (priv->entry), 0, 0); + + if (priv->extras & NMT_PASSWORD_FIELDS_ALWAYS_ASK) { + nmt_newt_grid_add (grid, NMT_NEWT_WIDGET (priv->always_ask), 0, 1); + g_signal_connect (priv->always_ask, "notify::active", + G_CALLBACK (always_ask_changed), object); + } else + g_clear_object (&priv->always_ask); + + if (priv->extras & NMT_PASSWORD_FIELDS_SHOW_PASSWORD) { + nmt_newt_grid_add (grid, NMT_NEWT_WIDGET (priv->show_password), 0, 2); + g_signal_connect (priv->show_password, "notify::active", + G_CALLBACK (show_password_changed), object); + g_object_bind_property (priv->show_password, "active", + priv->entry, "password", + G_BINDING_INVERT_BOOLEAN | G_BINDING_SYNC_CREATE); + } else + g_clear_object (&priv->show_password); + + g_object_bind_property (priv->entry, "text", + object, "password", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + + G_OBJECT_CLASS (nmt_password_fields_parent_class)->constructed (object); +} + +static void +nmt_password_fields_finalize (GObject *object) +{ + NmtPasswordFieldsPrivate *priv = NMT_PASSWORD_FIELDS_GET_PRIVATE (object); + + if (priv->always_ask) { + g_signal_handlers_disconnect_by_func (priv->always_ask, + G_CALLBACK (always_ask_changed), object); + } + if (priv->show_password) { + g_signal_handlers_disconnect_by_func (priv->show_password, + G_CALLBACK (show_password_changed), object); + } + + G_OBJECT_CLASS (nmt_password_fields_parent_class)->finalize (object); +} + +static void +nmt_password_fields_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtPasswordFields *fields = NMT_PASSWORD_FIELDS (object); + NmtPasswordFieldsPrivate *priv = NMT_PASSWORD_FIELDS_GET_PRIVATE (fields); + + switch (prop_id) { + case PROP_WIDTH: + nmt_newt_entry_set_width (priv->entry, g_value_get_int (value)); + break; + case PROP_EXTRAS: + priv->extras = g_value_get_uint (value); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (fields)); + break; + case PROP_PASSWORD: + nmt_password_fields_set_password (fields, g_value_get_string (value)); + break; + case PROP_ALWAYS_ASK: + if (priv->always_ask) + nmt_newt_checkbox_set_active (priv->always_ask, g_value_get_boolean (value)); + break; + case PROP_SHOW_PASSWORD: + if (priv->show_password) + nmt_newt_checkbox_set_active (priv->show_password, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_password_fields_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtPasswordFields *entry = NMT_PASSWORD_FIELDS (object); + NmtPasswordFieldsPrivate *priv = NMT_PASSWORD_FIELDS_GET_PRIVATE (entry); + + switch (prop_id) { + case PROP_WIDTH: + g_value_set_int (value, nmt_newt_entry_get_width (priv->entry)); + break; + case PROP_EXTRAS: + g_value_set_uint (value, priv->extras); + break; + case PROP_PASSWORD: + g_value_set_string (value, nmt_password_fields_get_password (entry)); + break; + case PROP_ALWAYS_ASK: + if (priv->always_ask) + g_value_set_boolean (value, nmt_newt_checkbox_get_active (priv->always_ask)); + break; + case PROP_SHOW_PASSWORD: + if (priv->show_password) + g_value_set_boolean (value, nmt_newt_checkbox_get_active (priv->show_password)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_password_fields_class_init (NmtPasswordFieldsClass *entry_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (entry_class); + + g_type_class_add_private (entry_class, sizeof (NmtPasswordFieldsPrivate)); + + /* virtual methods */ + object_class->constructed = nmt_password_fields_constructed; + object_class->set_property = nmt_password_fields_set_property; + object_class->get_property = nmt_password_fields_get_property; + object_class->finalize = nmt_password_fields_finalize; + + /** + * NmtPasswordFields:width: + * + * The width in characters of the password entry + */ + g_object_class_install_property + (object_class, PROP_WIDTH, + g_param_spec_int ("width", "", "", + -1, 80, -1, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtPasswordFields:extras: + * + * The extra widgets to show + */ + g_object_class_install_property + (object_class, PROP_EXTRAS, + g_param_spec_uint ("extras", "", "", + 0, 0xFFFF, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtPasswordFields:password: + * + * The entered password. + */ + g_object_class_install_property + (object_class, PROP_PASSWORD, + g_param_spec_string ("password", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtPasswordFields:always-ask: + * + * The current state of the "Always ask" checkbox. + */ + g_object_class_install_property + (object_class, PROP_ALWAYS_ASK, + g_param_spec_boolean ("always-ask", "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtPasswordFields:show-password: + * + * The current state of the "Show password" checkbox. + */ + g_object_class_install_property + (object_class, PROP_SHOW_PASSWORD, + g_param_spec_boolean ("show-password", "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/nmt-password-fields.h b/clients/tui/nmt-password-fields.h new file mode 100644 index 00000000..2ef830aa --- /dev/null +++ b/clients/tui/nmt-password-fields.h @@ -0,0 +1,55 @@ +/* -*- 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. + */ + +#ifndef NMT_PASSWORD_FIELDS_H +#define NMT_PASSWORD_FIELDS_H + +#include "nmt-newt.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_PASSWORD_FIELDS (nmt_password_fields_get_type ()) +#define NMT_PASSWORD_FIELDS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_PASSWORD_FIELDS, NmtPasswordFields)) +#define NMT_PASSWORD_FIELDS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_PASSWORD_FIELDS, NmtPasswordFieldsClass)) +#define NMT_IS_PASSWORD_FIELDS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_PASSWORD_FIELDS)) +#define NMT_IS_PASSWORD_FIELDS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_PASSWORD_FIELDS)) +#define NMT_PASSWORD_FIELDS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_PASSWORD_FIELDS, NmtPasswordFieldsClass)) + +typedef struct { + NmtNewtGrid parent; + +} NmtPasswordFields; + +typedef struct { + NmtNewtGridClass parent; + +} NmtPasswordFieldsClass; + +GType nmt_password_fields_get_type (void); + +typedef enum { + NMT_PASSWORD_FIELDS_ALWAYS_ASK = (1 << 0), + NMT_PASSWORD_FIELDS_SHOW_PASSWORD = (1 << 1), +} NmtPasswordFieldsExtras; + +NmtNewtWidget *nmt_password_fields_new (int width, + NmtPasswordFieldsExtras extras); + +G_END_DECLS + +#endif /* NMT_PASSWORD_FIELDS_H */ diff --git a/clients/tui/nmt-route-editor.c b/clients/tui/nmt-route-editor.c new file mode 100644 index 00000000..77bbec76 --- /dev/null +++ b/clients/tui/nmt-route-editor.c @@ -0,0 +1,210 @@ +/* -*- 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-route-editor + * @short_description: Route editing dialog + * + * #NmtRouteEditor implements a form for editing IPv4 or IPv6 routes. + * This was implemented as a separate dialog because it seemed too + * wide to fit into the main window. + */ + +#include "config.h" + +#include <glib.h> +#include <glib/gi18n-lib.h> + +#include "nmt-route-editor.h" +#include "nmt-route-table.h" + +G_DEFINE_TYPE (NmtRouteEditor, nmt_route_editor, NMT_TYPE_NEWT_FORM) + +#define NMT_ROUTE_EDITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_ROUTE_EDITOR, NmtRouteEditorPrivate)) + +typedef struct { + NMSetting *orig_setting; + NMSetting *edit_setting; + +} NmtRouteEditorPrivate; + +enum { + PROP_0, + PROP_SETTING, + + LAST_PROP +}; + +/** + * nmt_route_editor_new: + * @setting: the #NMSettingIP4Config or #NMSettingIP6Config to edit + * + * Creates a new #NmtRouteEditor to edit the routes in @setting + * + * Returns: a new #NmtRouteEditor + */ +NmtNewtForm * +nmt_route_editor_new (NMSetting *setting) +{ + return g_object_new (NMT_TYPE_ROUTE_EDITOR, + "setting", setting, + NULL); +} + +static void +nmt_route_editor_init (NmtRouteEditor *entry) +{ +} + +static void +save_routes_and_exit (NmtNewtButton *button, + gpointer user_data) +{ + NmtRouteEditor *editor = user_data; + NmtRouteEditorPrivate *priv = NMT_ROUTE_EDITOR_GET_PRIVATE (editor); + GPtrArray *routes; + + g_object_get (priv->edit_setting, + NM_SETTING_IP_CONFIG_ROUTES, &routes, + NULL); + g_object_set (priv->orig_setting, + NM_SETTING_IP_CONFIG_ROUTES, routes, + NULL); + g_ptr_array_unref (routes); + + nmt_newt_form_quit (NMT_NEWT_FORM (editor)); +} + +static void +nmt_route_editor_constructed (GObject *object) +{ + NmtRouteEditor *editor = NMT_ROUTE_EDITOR (object); + NmtRouteEditorPrivate *priv = NMT_ROUTE_EDITOR_GET_PRIVATE (editor); + NmtNewtWidget *vbox, *routes, *buttons, *ok, *cancel; + + if (G_OBJECT_CLASS (nmt_route_editor_parent_class)->constructed) + G_OBJECT_CLASS (nmt_route_editor_parent_class)->constructed (object); + + if (NM_IS_SETTING_IP4_CONFIG (priv->edit_setting)) + routes = nmt_route_table_new (AF_INET); + else + routes = nmt_route_table_new (AF_INET6); + g_object_bind_property (priv->edit_setting, NM_SETTING_IP_CONFIG_ROUTES, + routes, "routes", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + + vbox = nmt_newt_grid_new (); + nmt_newt_grid_add (NMT_NEWT_GRID (vbox), routes, 0, 0); + + buttons = nmt_newt_grid_new (); + nmt_newt_grid_add (NMT_NEWT_GRID (vbox), buttons, 0, 1); + nmt_newt_widget_set_padding (buttons, 0, 1, 0, 0); + + cancel = g_object_ref_sink (nmt_newt_button_new (_("Cancel"))); + nmt_newt_widget_set_exit_on_activate (cancel, TRUE); + nmt_newt_grid_add (NMT_NEWT_GRID (buttons), cancel, 0, 0); + nmt_newt_grid_set_flags (NMT_NEWT_GRID (buttons), cancel, + NMT_NEWT_GRID_EXPAND_X | NMT_NEWT_GRID_ANCHOR_RIGHT | + NMT_NEWT_GRID_FILL_Y); + + ok = g_object_ref_sink (nmt_newt_button_new (_("OK"))); + g_signal_connect (ok, "clicked", G_CALLBACK (save_routes_and_exit), editor); + nmt_newt_grid_add (NMT_NEWT_GRID (buttons), ok, 1, 0); + nmt_newt_widget_set_padding (ok, 1, 0, 0, 0); + g_object_bind_property (routes, "valid", + ok, "sensitive", + G_BINDING_SYNC_CREATE); + + nmt_newt_form_set_content (NMT_NEWT_FORM (editor), vbox); +} + +static void +nmt_route_editor_finalize (GObject *object) +{ + NmtRouteEditorPrivate *priv = NMT_ROUTE_EDITOR_GET_PRIVATE (object); + + g_clear_object (&priv->orig_setting); + g_clear_object (&priv->edit_setting); + + G_OBJECT_CLASS (nmt_route_editor_parent_class)->finalize (object); +} + +static void +nmt_route_editor_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtRouteEditorPrivate *priv = NMT_ROUTE_EDITOR_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_SETTING: + priv->orig_setting = g_value_dup_object (value); + priv->edit_setting = nm_setting_duplicate (priv->orig_setting); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_route_editor_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtRouteEditorPrivate *priv = NMT_ROUTE_EDITOR_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_SETTING: + g_value_set_object (value, priv->edit_setting); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_route_editor_class_init (NmtRouteEditorClass *entry_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (entry_class); + + g_type_class_add_private (entry_class, sizeof (NmtRouteEditorPrivate)); + + /* virtual methods */ + object_class->constructed = nmt_route_editor_constructed; + object_class->set_property = nmt_route_editor_set_property; + object_class->get_property = nmt_route_editor_get_property; + object_class->finalize = nmt_route_editor_finalize; + + /** + * NmtRouteEditor:setting: + * + * The #NMSettingIP4Config or #NMSettingIP6Config whose routes are + * being edited. + */ + g_object_class_install_property + (object_class, PROP_SETTING, + g_param_spec_object ("setting", "", "", + NM_TYPE_SETTING, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/nmt-route-editor.h b/clients/tui/nmt-route-editor.h new file mode 100644 index 00000000..9882c713 --- /dev/null +++ b/clients/tui/nmt-route-editor.h @@ -0,0 +1,51 @@ +/* -*- 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. + */ + +#ifndef NMT_ROUTE_EDITOR_H +#define NMT_ROUTE_EDITOR_H + +#include <NetworkManager.h> + +#include "nmt-newt.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_ROUTE_EDITOR (nmt_route_editor_get_type ()) +#define NMT_ROUTE_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_ROUTE_EDITOR, NmtRouteEditor)) +#define NMT_ROUTE_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_ROUTE_EDITOR, NmtRouteEditorClass)) +#define NMT_IS_ROUTE_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_ROUTE_EDITOR)) +#define NMT_IS_ROUTE_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_ROUTE_EDITOR)) +#define NMT_ROUTE_EDITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_ROUTE_EDITOR, NmtRouteEditorClass)) + +typedef struct { + NmtNewtForm parent; + +} NmtRouteEditor; + +typedef struct { + NmtNewtFormClass parent; + +} NmtRouteEditorClass; + +GType nmt_route_editor_get_type (void); + +NmtNewtForm *nmt_route_editor_new (NMSetting *setting); + +G_END_DECLS + +#endif /* NMT_ROUTE_EDITOR_H */ diff --git a/clients/tui/nmt-route-entry.c b/clients/tui/nmt-route-entry.c new file mode 100644 index 00000000..3a875520 --- /dev/null +++ b/clients/tui/nmt-route-entry.c @@ -0,0 +1,291 @@ +/* -*- 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-route-entry + * @short_description: A set of widgets describing a single route. + * + * #NmtRouteEntry provides a set of three entry widgets, for entering + * a network/prefix, a next hop, and a metric. + * + * This is used as a building block by #NmtRouteTable. + */ + +#include "config.h" + +#include <arpa/inet.h> +#include <netinet/in.h> +#include <stdlib.h> + +#include <glib/gi18n-lib.h> +#include <NetworkManager.h> + +#include "nmt-route-entry.h" +#include "nmt-ip-entry.h" + +#include "nm-editor-bindings.h" + +G_DEFINE_TYPE (NmtRouteEntry, nmt_route_entry, NMT_TYPE_NEWT_GRID) + +#define NMT_ROUTE_ENTRY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_ROUTE_ENTRY, NmtRouteEntryPrivate)) + +typedef struct { + NmtNewtWidget *dest, *next_hop, *metric; + + int family; + int ip_entry_width, metric_entry_width; + NMIPRoute *route; +} NmtRouteEntryPrivate; + +enum { + PROP_0, + PROP_FAMILY, + PROP_IP_ENTRY_WIDTH, + PROP_METRIC_ENTRY_WIDTH, + PROP_ROUTE, + + LAST_PROP +}; + +/** + * nmt_route_entry_new: + * @family: the address family, eg %AF_INET + * @ip_entry_width: the width in characters for the IP address entries + * @metric_entry_width: the width in characters for the metric entry + * + * Creates a new #NmtRouteEntry + * + * Returns: a new #NmtRouteEntry + */ +NmtNewtWidget * +nmt_route_entry_new (int family, + int ip_entry_width, + int metric_entry_width) +{ + return g_object_new (NMT_TYPE_ROUTE_ENTRY, + "family", family, + "ip-entry-width", ip_entry_width, + "metric-entry-width", metric_entry_width, + NULL); +} + +static void +nmt_route_entry_init (NmtRouteEntry *entry) +{ +} + +static gboolean +entry_validity_transform_to_warning_label (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + if (g_value_get_boolean (source_value)) + g_value_set_string (target_value, " "); + else + g_value_set_string (target_value, "!"); + return TRUE; +} + +static NmtNewtWidget * +create_warning_label (NmtNewtWidget *entry) +{ + NmtNewtWidget *label; + + label = g_object_new (NMT_TYPE_NEWT_LABEL, + "highlight", TRUE, + NULL); + g_object_bind_property_full (entry, "valid", + label, "text", + G_BINDING_SYNC_CREATE, + entry_validity_transform_to_warning_label, + NULL, NULL, NULL); + return label; +} + +static void +nmt_route_entry_constructed (GObject *object) +{ + NmtRouteEntryPrivate *priv = NMT_ROUTE_ENTRY_GET_PRIVATE (object); + NmtNewtGrid *grid = NMT_NEWT_GRID (object); + NmtNewtWidget *warning_label; + + priv->dest = nmt_ip_entry_new (priv->ip_entry_width, priv->family, TRUE, FALSE); + priv->next_hop = nmt_ip_entry_new (priv->ip_entry_width, priv->family, FALSE, TRUE); + priv->metric = nmt_newt_entry_numeric_new (priv->metric_entry_width, 0, 65535); + + nmt_newt_grid_add (grid, priv->dest, 0, 0); + warning_label = create_warning_label (priv->dest); + nmt_newt_grid_add (grid, warning_label, 1, 0); + + nmt_newt_grid_add (grid, priv->next_hop, 2, 0); + nmt_newt_widget_set_padding (priv->next_hop, 1, 0, 0, 0); + warning_label = create_warning_label (priv->next_hop); + nmt_newt_grid_add (grid, warning_label, 3, 0); + + nmt_newt_grid_add (grid, priv->metric, 4, 0); + nmt_newt_widget_set_padding (priv->metric, 1, 0, 0, 0); + + nm_editor_bind_ip_route_to_strings (priv->family, + object, "route", + priv->dest, "text", + priv->next_hop, "text", + priv->metric, "text", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + + G_OBJECT_CLASS (nmt_route_entry_parent_class)->constructed (object); +} + +static newtComponent +nmt_route_entry_get_focus_component (NmtNewtWidget *widget) +{ + NmtRouteEntryPrivate *priv = NMT_ROUTE_ENTRY_GET_PRIVATE (widget); + + return nmt_newt_widget_get_focus_component (priv->dest); +} + +static void +nmt_route_entry_finalize (GObject *object) +{ + NmtRouteEntryPrivate *priv = NMT_ROUTE_ENTRY_GET_PRIVATE (object); + + g_clear_pointer (&priv->route, nm_ip_route_unref); + + G_OBJECT_CLASS (nmt_route_entry_parent_class)->finalize (object); +} + +static void +nmt_route_entry_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtRouteEntryPrivate *priv = NMT_ROUTE_ENTRY_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_FAMILY: + priv->family = g_value_get_int (value); + break; + case PROP_IP_ENTRY_WIDTH: + priv->ip_entry_width = g_value_get_int (value); + break; + case PROP_METRIC_ENTRY_WIDTH: + priv->metric_entry_width = g_value_get_int (value); + break; + case PROP_ROUTE: + if (priv->route) + nm_ip_route_unref (priv->route); + priv->route = g_value_dup_boxed (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_route_entry_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtRouteEntryPrivate *priv = NMT_ROUTE_ENTRY_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_FAMILY: + g_value_set_int (value, priv->family); + break; + case PROP_IP_ENTRY_WIDTH: + g_value_set_int (value, priv->ip_entry_width); + break; + case PROP_METRIC_ENTRY_WIDTH: + g_value_set_int (value, priv->metric_entry_width); + break; + case PROP_ROUTE: + g_value_set_boxed (value, priv->route); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_route_entry_class_init (NmtRouteEntryClass *entry_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (entry_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (entry_class); + + g_type_class_add_private (entry_class, sizeof (NmtRouteEntryPrivate)); + + /* virtual methods */ + object_class->constructed = nmt_route_entry_constructed; + object_class->set_property = nmt_route_entry_set_property; + object_class->get_property = nmt_route_entry_get_property; + object_class->finalize = nmt_route_entry_finalize; + + widget_class->get_focus_component = nmt_route_entry_get_focus_component; + + /** + * NmtRouteEntry:family: + * + * The address family of the route, eg, %AF_INET + */ + g_object_class_install_property + (object_class, PROP_FAMILY, + g_param_spec_int ("family", "", "", + 0, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtRouteEntry:ip-entry-width: + * + * The width in characters of the IP address entries + */ + g_object_class_install_property + (object_class, PROP_IP_ENTRY_WIDTH, + g_param_spec_int ("ip-entry-width", "", "", + 0, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtRouteEntry:metric-entry-width: + * + * The width in characters of the metric entry + */ + g_object_class_install_property + (object_class, PROP_METRIC_ENTRY_WIDTH, + g_param_spec_int ("metric-entry-width", "", "", + 0, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtRouteEntry:route: + * + * The contents of the entries, as an #NMIPRoute. + */ + g_object_class_install_property + (object_class, PROP_ROUTE, + g_param_spec_boxed ("route", "", "", + nm_ip_route_get_type (), + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/nmt-route-entry.h b/clients/tui/nmt-route-entry.h new file mode 100644 index 00000000..d37b14cd --- /dev/null +++ b/clients/tui/nmt-route-entry.h @@ -0,0 +1,51 @@ +/* -*- 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. + */ + +#ifndef NMT_ROUTE_ENTRY_H +#define NMT_ROUTE_ENTRY_H + +#include "nmt-newt.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_ROUTE_ENTRY (nmt_route_entry_get_type ()) +#define NMT_ROUTE_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_ROUTE_ENTRY, NmtRouteEntry)) +#define NMT_ROUTE_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_ROUTE_ENTRY, NmtRouteEntryClass)) +#define NMT_IS_ROUTE_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_ROUTE_ENTRY)) +#define NMT_IS_ROUTE_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_ROUTE_ENTRY)) +#define NMT_ROUTE_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_ROUTE_ENTRY, NmtRouteEntryClass)) + +typedef struct { + NmtNewtGrid parent; + +} NmtRouteEntry; + +typedef struct { + NmtNewtGridClass parent; + +} NmtRouteEntryClass; + +GType nmt_route_entry_get_type (void); + +NmtNewtWidget *nmt_route_entry_new (int family, + int ip_entry_width, + int metric_entry_width); + +G_END_DECLS + +#endif /* NMT_ROUTE_ENTRY_H */ diff --git a/clients/tui/nmt-route-table.c b/clients/tui/nmt-route-table.c new file mode 100644 index 00000000..523d8ee3 --- /dev/null +++ b/clients/tui/nmt-route-table.c @@ -0,0 +1,334 @@ +/* -*- 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-route-table + * @short_description: An editable list of IP4 or IP6 routes + * + * #NmtRouteTable implements a list of #NmtRouteEntry, plus headers, + * and buttons to add and remove entries. + */ + +#include "config.h" + +#include <arpa/inet.h> +#include <netinet/in.h> +#include <stdlib.h> + +#include <glib/gi18n-lib.h> +#include <NetworkManager.h> + +#include "nmt-route-table.h" +#include "nmt-route-entry.h" +#include "nmt-widget-list.h" + +G_DEFINE_TYPE (NmtRouteTable, nmt_route_table, NMT_TYPE_NEWT_GRID) + +#define NMT_ROUTE_TABLE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_ROUTE_TABLE, NmtRouteTablePrivate)) + +typedef struct { + int family; + + int ip_entry_width; + int metric_entry_width; + + GPtrArray *routes; + NmtNewtWidget *list; +} NmtRouteTablePrivate; + +enum { + PROP_0, + PROP_FAMILY, + PROP_ROUTES, + + LAST_PROP +}; + +/** + * nmt_route_table_new: + * @family: the address family, eg %AF_INET + * + * Creates a new #NmtRouteTable + * + * Returns: a new #NmtRouteTable + */ +NmtNewtWidget * +nmt_route_table_new (int family) +{ + return g_object_new (NMT_TYPE_ROUTE_TABLE, + "family", family, + NULL); +} + +static gboolean +route_list_transform_to_route (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + NmtRouteTable *table = NMT_ROUTE_TABLE (g_binding_get_source (binding)); + NmtRouteTablePrivate *priv = NMT_ROUTE_TABLE_GET_PRIVATE (table); + int n = GPOINTER_TO_INT (user_data); + NMIPRoute *route; + + if (n >= priv->routes->len) + return FALSE; + + route = priv->routes->pdata[n]; + g_value_set_boxed (target_value, route); + return TRUE; +} + +static gboolean +route_list_transform_from_route (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + NmtRouteTable *table = NMT_ROUTE_TABLE (g_binding_get_source (binding)); + NmtRouteTablePrivate *priv = NMT_ROUTE_TABLE_GET_PRIVATE (table); + int n = GPOINTER_TO_INT (user_data); + GPtrArray *routes; + NMIPRoute *route; + + if (n >= priv->routes->len) + return FALSE; + route = priv->routes->pdata[n]; + + routes = priv->routes; + priv->routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_route_unref); + + if (route) + nm_ip_route_unref (route); + routes->pdata[n] = g_value_dup_boxed (source_value); + + g_value_take_boxed (target_value, routes); + return TRUE; +} + +static NmtNewtWidget * +create_route_entry (NmtWidgetList *list, + int num, + gpointer table) +{ + NmtRouteTablePrivate *priv = NMT_ROUTE_TABLE_GET_PRIVATE (table); + NmtNewtWidget *entry; + + entry = nmt_route_entry_new (priv->family, + priv->ip_entry_width, + priv->metric_entry_width); + + g_object_bind_property_full (table, "routes", + entry, "route", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, + route_list_transform_to_route, + route_list_transform_from_route, + GINT_TO_POINTER (num), NULL); + return entry; +} + +static void +add_route (NmtWidgetList *list, + gpointer table) +{ + NmtRouteTablePrivate *priv = NMT_ROUTE_TABLE_GET_PRIVATE (table); + NMIPRoute *route; + + if (priv->family == AF_INET) + route = nm_ip_route_new (AF_INET, "0.0.0.0", 32, NULL, 0, NULL); + else + route = nm_ip_route_new (AF_INET6, "::", 128, NULL, 0, NULL); + g_ptr_array_add (priv->routes, route); + nmt_widget_list_set_length (list, priv->routes->len); + g_object_notify (table, "routes"); +} + +static void +remove_route (NmtWidgetList *list, + int num, + gpointer table) +{ + NmtRouteTablePrivate *priv = NMT_ROUTE_TABLE_GET_PRIVATE (table); + NMIPRoute *route; + + if (num >= priv->routes->len) + return; + + route = priv->routes->pdata[num]; + g_ptr_array_remove_index (priv->routes, num); + nmt_widget_list_set_length (list, priv->routes->len); + + g_object_notify (table, "routes"); +} + +static void +nmt_route_table_init (NmtRouteTable *table) +{ + NmtRouteTablePrivate *priv = NMT_ROUTE_TABLE_GET_PRIVATE (table); + NmtNewtWidget *header, *empty; + NmtNewtWidget *dest_prefix_label, *next_hop_label, *metric_label; + int dest_prefix_width, next_hop_width, metric_width; + char *text; + + priv->routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_route_unref); + + header = nmt_newt_grid_new (); + + text = g_strdup_printf ("%s/%s", _("Destination"), _("Prefix")); + dest_prefix_width = nmt_newt_text_width (text); + dest_prefix_label = g_object_new (NMT_TYPE_NEWT_LABEL, + "text", text, + "style", NMT_NEWT_LABEL_PLAIN, + NULL); + g_free (text); + nmt_newt_grid_add (NMT_NEWT_GRID (header), dest_prefix_label, 0, 0); + + text = _("Next Hop"); + next_hop_label = g_object_new (NMT_TYPE_NEWT_LABEL, + "text", text, + "style", NMT_NEWT_LABEL_PLAIN, + NULL); + next_hop_width = nmt_newt_text_width (text); + nmt_newt_grid_add (NMT_NEWT_GRID (header), next_hop_label, 1, 0); + + text = _("Metric"); + metric_label = g_object_new (NMT_TYPE_NEWT_LABEL, + "text", text, + "style", NMT_NEWT_LABEL_PLAIN, + NULL); + metric_width = nmt_newt_text_width (text); + nmt_newt_grid_add (NMT_NEWT_GRID (header), metric_label, 2, 0); + + priv->ip_entry_width = MAX (20, MAX (dest_prefix_width, next_hop_width)); + priv->metric_entry_width = MAX (7, metric_width); + + nmt_newt_widget_set_padding (dest_prefix_label, + 0, 0, priv->ip_entry_width - dest_prefix_width, 0); + nmt_newt_widget_set_padding (next_hop_label, + 2, 0, priv->ip_entry_width - next_hop_width, 0); + nmt_newt_widget_set_padding (metric_label, + 2, 0, priv->metric_entry_width - metric_width, 0); + + nmt_newt_grid_add (NMT_NEWT_GRID (table), header, 0, 0); + + empty = nmt_newt_label_new (_("No custom routes are defined.")); + priv->list = nmt_widget_list_new (create_route_entry, table, NULL, empty); + g_signal_connect (priv->list, "add-clicked", G_CALLBACK (add_route), table); + g_signal_connect (priv->list, "remove-clicked", G_CALLBACK (remove_route), table); + nmt_newt_grid_add (NMT_NEWT_GRID (table), priv->list, 0, 1); +} + +static void +nmt_route_table_finalize (GObject *object) +{ + NmtRouteTablePrivate *priv = NMT_ROUTE_TABLE_GET_PRIVATE (object); + + g_ptr_array_unref (priv->routes); + + G_OBJECT_CLASS (nmt_route_table_parent_class)->finalize (object); +} + +static void +nmt_route_table_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtRouteTablePrivate *priv = NMT_ROUTE_TABLE_GET_PRIVATE (object); + GPtrArray *array; + int i; + + switch (prop_id) { + case PROP_FAMILY: + priv->family = g_value_get_int (value); + break; + case PROP_ROUTES: + array = g_value_get_boxed (value); + g_ptr_array_set_size (priv->routes, 0); + for (i = 0; i < array->len; i++) { + nm_ip_route_ref (array->pdata[i]); + g_ptr_array_add (priv->routes, array->pdata[i]); + } + nmt_widget_list_set_length (NMT_WIDGET_LIST (priv->list), priv->routes->len); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_route_table_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtRouteTablePrivate *priv = NMT_ROUTE_TABLE_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_FAMILY: + g_value_set_int (value, priv->family); + break; + case PROP_ROUTES: + g_value_set_boxed (value, priv->routes); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_route_table_class_init (NmtRouteTableClass *table_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (table_class); + + g_type_class_add_private (table_class, sizeof (NmtRouteTablePrivate)); + + /* virtual methods */ + object_class->set_property = nmt_route_table_set_property; + object_class->get_property = nmt_route_table_get_property; + object_class->finalize = nmt_route_table_finalize; + + /** + * NmtRouteTable:family: + * + * The network address family of the routes, eg %AF_INET + */ + g_object_class_install_property + (object_class, PROP_FAMILY, + g_param_spec_int ("family", "", "", + -1, G_MAXINT, -1, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtRouteTable:routes: + * + * The array of routes, suitable for binding to #NMSettingIP4Config:routes + * or #NMSettingIP6Config:routes. + * + * Element-type: NMIPRoute + */ + g_object_class_install_property + (object_class, PROP_ROUTES, + g_param_spec_boxed ("routes", "", "", + G_TYPE_PTR_ARRAY, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/nmt-route-table.h b/clients/tui/nmt-route-table.h new file mode 100644 index 00000000..217bf40d --- /dev/null +++ b/clients/tui/nmt-route-table.h @@ -0,0 +1,49 @@ +/* -*- 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. + */ + +#ifndef NMT_ROUTE_TABLE_H +#define NMT_ROUTE_TABLE_H + +#include "nmt-newt.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_ROUTE_TABLE (nmt_route_table_get_type ()) +#define NMT_ROUTE_TABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_ROUTE_TABLE, NmtRouteTable)) +#define NMT_ROUTE_TABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_ROUTE_TABLE, NmtRouteTableClass)) +#define NMT_IS_ROUTE_TABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_ROUTE_TABLE)) +#define NMT_IS_ROUTE_TABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_ROUTE_TABLE)) +#define NMT_ROUTE_TABLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_ROUTE_TABLE, NmtRouteTableClass)) + +typedef struct { + NmtNewtGrid parent; + +} NmtRouteTable; + +typedef struct { + NmtNewtGridClass parent; + +} NmtRouteTableClass; + +GType nmt_route_table_get_type (void); + +NmtNewtWidget *nmt_route_table_new (int family); + +G_END_DECLS + +#endif /* NMT_ROUTE_TABLE_H */ diff --git a/clients/tui/nmt-slave-list.c b/clients/tui/nmt-slave-list.c new file mode 100644 index 00000000..9c8596f7 --- /dev/null +++ b/clients/tui/nmt-slave-list.c @@ -0,0 +1,266 @@ +/* -*- 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-slave-list: + * @short_description: An editable list of a connection's slaves + * + * #NmtSlaveList implements an #NmtEditConnectionList for the + * slaves of a connection. + */ + +#include "config.h" + +#include <glib/gi18n-lib.h> +#include <NetworkManager.h> + +#include "nmt-slave-list.h" + +G_DEFINE_TYPE (NmtSlaveList, nmt_slave_list, NMT_TYPE_EDIT_CONNECTION_LIST) + +#define NMT_SLAVE_LIST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_SLAVE_LIST, NmtSlaveListPrivate)) + +typedef struct { + NMConnection *master; + const char *master_type, *master_uuid; + + NmtAddConnectionTypeFilter type_filter; + gpointer type_filter_data; +} NmtSlaveListPrivate; + +enum { + PROP_0, + PROP_MASTER, + PROP_TYPE_FILTER, + PROP_TYPE_FILTER_DATA, + + LAST_PROP +}; + +static gboolean nmt_slave_list_connection_filter (NmtEditConnectionList *list, + NMConnection *connection, + gpointer user_data); + +/** + * nmt_slave_list_new: + * @master: the master #NMConnection whose slaves are being listed + * @type_filter: (allow-none): a function to limit the availble slave types + * @type_filter_data: (allow-none): data for @type_filter. + * + * Creates a new #NmtSlaveList. + * + * If @type_filter is non-%NULL, it will be used to limit the connection + * types that are available when the user clicks on the "Add" button to add + * a new slave. If the @type_filter filters the list down to only a single + * connection type, then the user will not be presented with a connection-type + * dialog, and will instead be immediately taken to an editor window for the + * new slave after clicking "Add". + * + * Returns: a new #NmtSlaveList. + */ +NmtNewtWidget * +nmt_slave_list_new (NMConnection *master, + NmtAddConnectionTypeFilter type_filter, + gpointer type_filter_data) +{ + return g_object_new (NMT_TYPE_SLAVE_LIST, + "master", master, + "type-filter", type_filter, + "type-filter-data", type_filter_data, + "grouped", FALSE, + "connection-filter", nmt_slave_list_connection_filter, + NULL); +} + +static void +nmt_slave_list_init (NmtSlaveList *list) +{ +} + +static void +nmt_slave_list_finalize (GObject *object) +{ + NmtSlaveListPrivate *priv = NMT_SLAVE_LIST_GET_PRIVATE (object); + + g_object_unref (priv->master); + + G_OBJECT_CLASS (nmt_slave_list_parent_class)->finalize (object); +} + +static gboolean +nmt_slave_list_connection_filter (NmtEditConnectionList *list, + NMConnection *connection, + gpointer user_data) +{ + NmtSlaveListPrivate *priv = NMT_SLAVE_LIST_GET_PRIVATE (list); + NMSettingConnection *s_con; + const char *master, *master_ifname, *slave_type; + + s_con = nm_connection_get_setting_connection (connection); + g_return_val_if_fail (s_con != NULL, FALSE); + + slave_type = nm_setting_connection_get_slave_type (s_con); + if (g_strcmp0 (slave_type, priv->master_type) != 0) + return FALSE; + + master = nm_setting_connection_get_master (s_con); + if (!master) + return FALSE; + + master_ifname = nm_connection_get_interface_name (priv->master); + if (g_strcmp0 (master, master_ifname) != 0 && g_strcmp0 (master, priv->master_uuid) != 0) + return FALSE; + + return TRUE; +} + +static void +nmt_slave_list_add_connection (NmtEditConnectionList *list) +{ + NmtSlaveListPrivate *priv = NMT_SLAVE_LIST_GET_PRIVATE (list); + + nmt_add_connection_full (_("Select the type of slave connection you wish to add."), NULL, + priv->master, priv->type_filter, priv->type_filter_data); +} + +static void +nmt_slave_list_edit_connection (NmtEditConnectionList *list, + NMConnection *connection) +{ + nmt_edit_connection (connection); +} + +static void +nmt_slave_list_remove_connection (NmtEditConnectionList *list, + NMRemoteConnection *connection) +{ + nmt_remove_connection (connection); +} + +static void +nmt_slave_list_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtSlaveListPrivate *priv = NMT_SLAVE_LIST_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_MASTER: + priv->master = g_value_dup_object (value); + if (priv->master) { + NMSettingConnection *s_con = nm_connection_get_setting_connection (priv->master); + + priv->master_type = nm_setting_connection_get_connection_type (s_con); + priv->master_uuid = nm_setting_connection_get_uuid (s_con); + } + break; + case PROP_TYPE_FILTER: + priv->type_filter = g_value_get_pointer (value); + break; + case PROP_TYPE_FILTER_DATA: + priv->type_filter_data = g_value_get_pointer (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_slave_list_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtSlaveListPrivate *priv = NMT_SLAVE_LIST_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_MASTER: + g_value_set_object (value, priv->master); + break; + case PROP_TYPE_FILTER: + g_value_set_pointer (value, priv->type_filter); + break; + case PROP_TYPE_FILTER_DATA: + g_value_set_pointer (value, priv->type_filter_data); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_slave_list_class_init (NmtSlaveListClass *list_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (list_class); + NmtEditConnectionListClass *connection_list_class = NMT_EDIT_CONNECTION_LIST_CLASS (list_class); + + g_type_class_add_private (list_class, sizeof (NmtSlaveListPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_slave_list_set_property; + object_class->get_property = nmt_slave_list_get_property; + object_class->finalize = nmt_slave_list_finalize; + + connection_list_class->add_connection = nmt_slave_list_add_connection; + connection_list_class->edit_connection = nmt_slave_list_edit_connection; + connection_list_class->remove_connection = nmt_slave_list_remove_connection; + + /** + * NmtSlaveList:master: + * + * The master #NMConnection whose slaves are being displayed. + */ + g_object_class_install_property + (object_class, PROP_MASTER, + g_param_spec_object ("master", "", "", + NM_TYPE_CONNECTION, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtSlaveList:type-filter: + * + * If non-%NULL, this will be used to limit the connection types + * that are available when the user clicks on the "Add" button to + * add a new slave. If the filter filters the list down to only a + * single connection type, then the user will not be presented + * with a connection-type dialog, and will instead be immediately + * taken to an editor window for the new slave after clicking + * "Add". + */ + g_object_class_install_property + (object_class, PROP_TYPE_FILTER, + g_param_spec_pointer ("type-filter", "", "", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtSlaveList:type-filter-data: + * + * User data passed to #NmtSlaveList:type-filter + */ + g_object_class_install_property + (object_class, PROP_TYPE_FILTER_DATA, + g_param_spec_pointer ("type-filter-data", "", "", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/nmt-slave-list.h b/clients/tui/nmt-slave-list.h new file mode 100644 index 00000000..d10cd3a7 --- /dev/null +++ b/clients/tui/nmt-slave-list.h @@ -0,0 +1,52 @@ +/* -*- 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. + */ + +#ifndef NMT_SLAVE_LIST_H +#define NMT_SLAVE_LIST_H + +#include "nmt-edit-connection-list.h" +#include "nmtui-edit.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_SLAVE_LIST (nmt_slave_list_get_type ()) +#define NMT_SLAVE_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_SLAVE_LIST, NmtSlaveList)) +#define NMT_SLAVE_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_SLAVE_LIST, NmtSlaveListClass)) +#define NMT_IS_SLAVE_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_SLAVE_LIST)) +#define NMT_IS_SLAVE_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_SLAVE_LIST)) +#define NMT_SLAVE_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_SLAVE_LIST, NmtSlaveListClass)) + +typedef struct { + NmtEditConnectionList parent; + +} NmtSlaveList; + +typedef struct { + NmtEditConnectionListClass parent; + +} NmtSlaveListClass; + +GType nmt_slave_list_get_type (void); + +NmtNewtWidget *nmt_slave_list_new (NMConnection *master, + NmtAddConnectionTypeFilter type_filter, + gpointer type_filter_data); + +G_END_DECLS + +#endif /* NMT_SLAVE_LIST_H */ diff --git a/clients/tui/nmt-utils.c b/clients/tui/nmt-utils.c new file mode 100644 index 00000000..f2bf70db --- /dev/null +++ b/clients/tui/nmt-utils.c @@ -0,0 +1,151 @@ +/* -*- 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-utils + * @short_description: Miscellaneous nmtui-specific utilities + */ + +#include "config.h" + +#include <string.h> + +#include "nmt-utils.h" + +/** + * NmtSyncOp: + * + * A helper object used when synchronously waiting for an asynchronous + * operation to complete. + * + * The caller first does: + * + * |[ + * NmtSyncOp op; + * + * nmt_sync_op_init (&op); + * ]| + * + * It then passes the op as the user_data to the async operation's + * callback function, and then calls nmt_sync_op_wait_boolean() or + * nmt_sync_op_wait_pointer() to wait for the result. + * + * When the async callback is invoked, it should call + * nmt_sync_op_complete_boolean() or nmt_sync_op_complete_pointer() to + * return a result or an error to the caller. + * + * There is no free/clear function; any memory that needs to be freed + * will have been returned to the caller from + * nmt_sync_op_wait_boolean() or nmt_sync_op_wait_pointer(), so there + * is nothing left that needs to be freed. + */ + +typedef struct { + gpointer result; + GError *error; + gpointer complete; +} NmtSyncOpReal; + +/** + * nmt_sync_op_init: + * @op: pointer to a stack-allocated #NmtSyncOp + * + * Initializes @op before use. + */ +void +nmt_sync_op_init (NmtSyncOp *op) +{ + memset (op, 0, sizeof (*op)); +} + +/** + * nmt_sync_op_wait_boolean: + * @op: the #NmtSyncOp + * @error: return location for a #GError + * + * This runs the main loop until @op's operation returns, and then + * returns the result or error. + * + * Returns: the result of the operation. + */ +gboolean +nmt_sync_op_wait_boolean (NmtSyncOp *op, + GError **error) +{ + return GPOINTER_TO_UINT (nmt_sync_op_wait_pointer (op, error)); +} + +/** + * nmt_sync_op_complete_boolean: + * @op: the #NmtSyncOp + * @result: the result of the operation + * @error: (allow-none): the error, or %NULL + * + * Completes @op and returns @result and/or @error to the caller. + */ +void +nmt_sync_op_complete_boolean (NmtSyncOp *op, + gboolean result, + GError *error) +{ + nmt_sync_op_complete_pointer (op, GUINT_TO_POINTER (result), error); +} + +/** + * nmt_sync_op_wait_pointer: + * @op: the #NmtSyncOp + * @error: return location for a #GError + * + * This runs the main loop until @op's operation returns, and then + * returns the result or error. + * + * Returns: the result of the operation. + */ +gpointer +nmt_sync_op_wait_pointer (NmtSyncOp *op, + GError **error) +{ + NmtSyncOpReal *real = (NmtSyncOpReal *)op; + + while (!real->complete) + g_main_context_iteration (NULL, TRUE); + + if (real->error) + g_propagate_error (error, real->error); + return real->result; +} + +/** + * nmt_sync_op_complete_pointer: + * @op: the #NmtSyncOp + * @result: the result of the operation + * @error: (allow-none): the error, or %NULL + * + * Completes @op and returns @result and/or @error to the caller. + */ +void +nmt_sync_op_complete_pointer (NmtSyncOp *op, + gpointer result, + GError *error) +{ + NmtSyncOpReal *real = (NmtSyncOpReal *)op; + + real->result = result; + real->error = error ? g_error_copy (error) : NULL; + real->complete = GUINT_TO_POINTER (TRUE); +} diff --git a/clients/tui/nmt-utils.h b/clients/tui/nmt-utils.h new file mode 100644 index 00000000..7e24fcab --- /dev/null +++ b/clients/tui/nmt-utils.h @@ -0,0 +1,46 @@ +/* -*- 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. + */ + +#ifndef NMT_UTILS_H +#define NMT_UTILS_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +typedef struct { + gpointer private[3]; +} NmtSyncOp; + +void nmt_sync_op_init (NmtSyncOp *op); + +gboolean nmt_sync_op_wait_boolean (NmtSyncOp *op, + GError **error); +void nmt_sync_op_complete_boolean (NmtSyncOp *op, + gboolean result, + GError *error); + +gpointer nmt_sync_op_wait_pointer (NmtSyncOp *op, + GError **error); +void nmt_sync_op_complete_pointer (NmtSyncOp *op, + gpointer result, + GError *error); + +G_END_DECLS + +#endif /* NMT_UTILS_H */ diff --git a/clients/tui/nmt-widget-list.c b/clients/tui/nmt-widget-list.c new file mode 100644 index 00000000..9159ed98 --- /dev/null +++ b/clients/tui/nmt-widget-list.c @@ -0,0 +1,496 @@ +/* -*- 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-widget-list + * @short_description: A list of widgets, with Add and Remove buttons + * + * #NmtWidgetList presents a homogeneous list of widgets, with "Remove" + * buttons next to each one, and an "Add" button at the button to add + * new ones. + * + * It is the base class for #NmtAddressList, and is used internally by + * #NmtRouteTable. + * + * FIXME: The way this works is sort of weird. + */ + +#include "config.h" + +#include <arpa/inet.h> +#include <netinet/in.h> +#include <stdlib.h> +#include <string.h> + +#include <glib/gi18n-lib.h> + +#include "nmt-widget-list.h" +#include "nmt-newt.h" + +G_DEFINE_TYPE (NmtWidgetList, nmt_widget_list, NMT_TYPE_NEWT_GRID) + +#define NMT_WIDGET_LIST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_WIDGET_LIST, NmtWidgetListPrivate)) + +typedef struct { + int length; + + NmtWidgetListCallback create_callback; + gpointer user_data; + GDestroyNotify destroy_notify; + + NmtNewtWidget *empty_widget; + + GPtrArray *widgets; + GPtrArray *remove_buttons; + + NmtNewtWidget *add_button; + GBinding *add_sensitivity; +} NmtWidgetListPrivate; + +enum { + PROP_0, + PROP_CREATE_CALLBACK, + PROP_USER_DATA, + PROP_DESTROY_NOTIFY, + PROP_EMPTY_WIDGET, + PROP_LENGTH, + + LAST_PROP +}; + +enum { + ADD_CLICKED, + REMOVE_CLICKED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void add_clicked (NmtNewtButton *button, gpointer user_data); +static void remove_clicked (NmtNewtButton *button, gpointer user_data); + +/** + * NmtWidgetListCallback: + * @list: the #NmtWidgetList + * @n: the number of the widget being added + * @user_data: the callback's user data + * + * Called by #NmtWidgetList to ask for a new widget to be created. + * + * Note that the widget is not created to go with any particular + * value, but rather is created to be at a certain spot in the list. + * When an element is deleted from the list, it is actually always + * the last widget in the list that is removed, but it is assumed + * that the widget list is bound to some array-valued property, and + * so when an element is deleted from that array, the widgets will + * all update themselves automatically when the array changes. + * + * Returns: a new widget for the list + */ + +/** + * nmt_widget_list_new: + * @create_callback: callback to create new widgets + * @user_data: user data for @create_callback + * @destroy_notify: #GDestroyNotify for @user_data + * @empty_widget: (allow-none): a widget to display when there are + * no "real" widgets in the list. + * + * Creates a new #NmtWidgetList. + * + * Returns: a new #NmtWidgetList. + */ +NmtNewtWidget * +nmt_widget_list_new (NmtWidgetListCallback create_callback, + gpointer user_data, + GDestroyNotify destroy_notify, + NmtNewtWidget *empty_widget) +{ + return g_object_new (NMT_TYPE_WIDGET_LIST, + "create-callback", create_callback, + "user-data", user_data, + "destroy-notify", destroy_notify, + "empty-widget", empty_widget, + NULL); +} + +static void +nmt_widget_list_init (NmtWidgetList *list) +{ + NmtWidgetListPrivate *priv = NMT_WIDGET_LIST_GET_PRIVATE (list); + + priv->widgets = g_ptr_array_new (); + priv->remove_buttons = g_ptr_array_new (); + + priv->add_button = nmt_newt_button_new (_("Add...")); + g_signal_connect (priv->add_button, "clicked", + G_CALLBACK (add_clicked), list); + nmt_newt_grid_add (NMT_NEWT_GRID (list), priv->add_button, 0, 0); +} + +static void +nmt_widget_list_constructed (GObject *object) +{ + NmtWidgetListPrivate *priv = NMT_WIDGET_LIST_GET_PRIVATE (object); + + if (priv->length == 0 && priv->empty_widget) { + nmt_newt_widget_set_visible (priv->empty_widget, TRUE); + nmt_newt_grid_move (NMT_NEWT_GRID (object), priv->add_button, 0, 1); + } + + G_OBJECT_CLASS (nmt_widget_list_parent_class)->constructed (object); +} + +static void +nmt_widget_list_finalize (GObject *object) +{ + NmtWidgetListPrivate *priv = NMT_WIDGET_LIST_GET_PRIVATE (object); + + g_ptr_array_unref (priv->widgets); + g_ptr_array_unref (priv->remove_buttons); + + if (priv->user_data && priv->destroy_notify) + priv->destroy_notify (priv->user_data); + + g_clear_object (&priv->empty_widget); + + G_OBJECT_CLASS (nmt_widget_list_parent_class)->finalize (object); +} + +static void +ensure_widgets (NmtWidgetList *list) +{ + NmtWidgetListPrivate *priv = NMT_WIDGET_LIST_GET_PRIVATE (list); + NmtNewtWidget *widget, *button, *focus; + gboolean was_empty; + NmtNewtForm *form; + int i; + + was_empty = priv->widgets->len == 0; + + if (priv->length < priv->widgets->len) { + /* remove excess widgets */ + for (i = priv->length; i < priv->widgets->len; i++) { + nmt_newt_container_remove (NMT_NEWT_CONTAINER (list), priv->widgets->pdata[i]); + nmt_newt_container_remove (NMT_NEWT_CONTAINER (list), priv->remove_buttons->pdata[i]); + } + g_ptr_array_set_size (priv->widgets, priv->length); + g_ptr_array_set_size (priv->remove_buttons, priv->length); + + } else if (priv->length > priv->widgets->len) { + /* add new widgets */ + for (i = priv->widgets->len; i < priv->length; i++) { + widget = NMT_WIDGET_LIST_GET_CLASS (list)->create_widget (list, i); + + nmt_newt_grid_add (NMT_NEWT_GRID (list), widget, 0, i); + g_ptr_array_add (priv->widgets, widget); + + button = nmt_newt_button_new (_("Remove")); + g_signal_connect (button, "clicked", + G_CALLBACK (remove_clicked), list); + + nmt_newt_grid_add (NMT_NEWT_GRID (list), button, 1, i); + nmt_newt_widget_set_padding (button, 1, 0, 0, 0); + g_ptr_array_add (priv->remove_buttons, button); + } + + } else + return; + + if (priv->widgets->len == 0 && priv->empty_widget) { + nmt_newt_widget_set_visible (priv->empty_widget, TRUE); + nmt_newt_grid_move (NMT_NEWT_GRID (list), priv->add_button, 0, 1); + } else { + if (was_empty && priv->empty_widget) + nmt_newt_widget_set_visible (priv->empty_widget, FALSE); + nmt_newt_grid_move (NMT_NEWT_GRID (list), priv->add_button, 0, priv->length); + } + + form = nmt_newt_widget_get_form (NMT_NEWT_WIDGET (list)); + if (form) { + if (priv->widgets->len) { + if (was_empty) + focus = priv->widgets->pdata[0]; + else + focus = priv->widgets->pdata[priv->widgets->len - 1]; + } else + focus = priv->add_button; + nmt_newt_form_set_focus (form, focus); + } + + g_clear_object (&priv->add_sensitivity); + if (priv->widgets->len) { + widget = priv->widgets->pdata[priv->widgets->len - 1]; + priv->add_sensitivity = g_object_bind_property (widget, "valid", + priv->add_button, "sensitive", + G_BINDING_SYNC_CREATE); + g_object_add_weak_pointer (G_OBJECT (priv->add_sensitivity), + (gpointer *)&priv->add_sensitivity); + } else + nmt_newt_component_set_sensitive (NMT_NEWT_COMPONENT (priv->add_button), TRUE); +} + +static void +add_clicked (NmtNewtButton *button, gpointer list) +{ + g_signal_emit (G_OBJECT (list), signals[ADD_CLICKED], 0, NULL); +} + +static void +remove_clicked (NmtNewtButton *button, gpointer list) +{ + NmtWidgetListPrivate *priv = NMT_WIDGET_LIST_GET_PRIVATE (list); + int i; + + for (i = 0; i < priv->remove_buttons->len; i++) { + if (priv->remove_buttons->pdata[i] == (gpointer)button) + break; + } + g_return_if_fail (i < priv->remove_buttons->len); + + g_signal_emit (G_OBJECT (list), signals[REMOVE_CLICKED], 0, i, NULL); +} + +static NmtNewtWidget * +nmt_widget_list_real_create_widget (NmtWidgetList *list, + int n) +{ + NmtWidgetListPrivate *priv = NMT_WIDGET_LIST_GET_PRIVATE (list); + + g_return_val_if_fail (priv->create_callback != NULL, NULL); + + return priv->create_callback (list, n, priv->user_data); +} + +/** + * nmt_widget_list_get_length: + * @list: the #NmtNewtWidgetList + * + * Gets the number of widgets in the list. + * + * Returns: the number of widgets in the list. + */ +int +nmt_widget_list_get_length (NmtWidgetList *list) +{ + NmtWidgetListPrivate *priv = NMT_WIDGET_LIST_GET_PRIVATE (list); + + return priv->length; +} + +/** + * nmt_widget_list_set_length: + * @list: the #NmtNewtWidgetList + * @length: the new length + * + * Changes the number of widgets in the list. Widgets will be added or + * deleted as necessary. + */ +void +nmt_widget_list_set_length (NmtWidgetList *list, + int length) +{ + NmtWidgetListPrivate *priv = NMT_WIDGET_LIST_GET_PRIVATE (list); + + if (priv->length != length) { + priv->length = length; + g_object_notify (G_OBJECT (list), "length"); + } + + ensure_widgets (list); +} + +static void +nmt_widget_list_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtWidgetListPrivate *priv = NMT_WIDGET_LIST_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_CREATE_CALLBACK: + priv->create_callback = g_value_get_pointer (value); + break; + case PROP_USER_DATA: + priv->user_data = g_value_get_pointer (value); + break; + case PROP_DESTROY_NOTIFY: + priv->destroy_notify = g_value_get_pointer (value); + break; + case PROP_LENGTH: + priv->length = g_value_get_int (value); + ensure_widgets (NMT_WIDGET_LIST (object)); + break; + case PROP_EMPTY_WIDGET: + priv->empty_widget = g_value_get_object (value); + if (priv->empty_widget) { + g_object_ref_sink (priv->empty_widget); + nmt_newt_grid_add (NMT_NEWT_GRID (object), priv->empty_widget, 0, 0); + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_widget_list_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtWidgetListPrivate *priv = NMT_WIDGET_LIST_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_CREATE_CALLBACK: + g_value_set_pointer (value, priv->create_callback); + break; + case PROP_USER_DATA: + g_value_set_pointer (value, priv->user_data); + break; + case PROP_DESTROY_NOTIFY: + g_value_set_pointer (value, priv->destroy_notify); + break; + case PROP_LENGTH: + g_value_set_int (value, priv->length); + break; + case PROP_EMPTY_WIDGET: + g_value_set_object (value, priv->empty_widget); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_widget_list_class_init (NmtWidgetListClass *list_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (list_class); + + g_type_class_add_private (list_class, sizeof (NmtWidgetListPrivate)); + + /* virtual methods */ + object_class->constructed = nmt_widget_list_constructed; + object_class->set_property = nmt_widget_list_set_property; + object_class->get_property = nmt_widget_list_get_property; + object_class->finalize = nmt_widget_list_finalize; + + list_class->create_widget = nmt_widget_list_real_create_widget; + + /* signals */ + + /** + * NmtNewtWidget::add-clicked: + * @list: the #NmtNewtWidgetList + * + * Emitted when the user clicks the "Add" button. The caller can + * decide whether or not to add a new widget, and call + * nmt_widget_list_set_length() with the new length if so. + * + * FIXME: the "Add" button should be insensitive if it's + * not going to work. + */ + signals[ADD_CLICKED] = + g_signal_new ("add-clicked", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NmtWidgetListClass, add_clicked), + NULL, NULL, NULL, + G_TYPE_NONE, 0); + /** + * NmtNewtWidget::remove-clicked: + * @list: the #NmtNewtWidgetList + * @n: the widget being removed + * + * Emitted when the user clicks one of the "Remove" buttons. The + * caller can decide whether or not to remove the widget, and + * call nmt_widget_list_set_length() with the new length if so. + * + * FIXME: the "Remove" button should be insensitive if it's not + * going to work. + */ + signals[REMOVE_CLICKED] = + g_signal_new ("remove-clicked", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NmtWidgetListClass, remove_clicked), + NULL, NULL, NULL, + G_TYPE_NONE, 1, G_TYPE_INT); + + /* properties */ + + /** + * NmtWidgetList:create-callback: + * + * Callback called to create a new widget. + */ + g_object_class_install_property + (object_class, PROP_CREATE_CALLBACK, + g_param_spec_pointer ("create-callback", "", "", + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtWidgetList:user-data: + * + * User data for #NmtWidgetList:create-callback + */ + g_object_class_install_property + (object_class, PROP_USER_DATA, + g_param_spec_pointer ("user-data", "", "", + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtWidgetList:destroy-notify: + * + * #GDestroyNotify for #NmtWidgetList:user-data + */ + g_object_class_install_property + (object_class, PROP_DESTROY_NOTIFY, + g_param_spec_pointer ("destroy-notify", "", "", + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtWidgetList:length: + * + * The length of the widget list; changing this value will add or + * remove widgets from the list. + */ + g_object_class_install_property + (object_class, PROP_LENGTH, + g_param_spec_int ("length", "", "", + 0, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtWidgetList:empty-widget: + * + * If non-%NULL, this widget will be displayed when there are + * no "real" widgets in the list. + */ + g_object_class_install_property + (object_class, PROP_EMPTY_WIDGET, + g_param_spec_object ("empty-widget", "", "", + NMT_TYPE_NEWT_WIDGET, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} diff --git a/clients/tui/nmt-widget-list.h b/clients/tui/nmt-widget-list.h new file mode 100644 index 00000000..7dbeb215 --- /dev/null +++ b/clients/tui/nmt-widget-list.h @@ -0,0 +1,69 @@ +/* -*- 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. + */ + +#ifndef NMT_WIDGET_LIST_H +#define NMT_WIDGET_LIST_H + +#include "nmt-newt-grid.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_WIDGET_LIST (nmt_widget_list_get_type ()) +#define NMT_WIDGET_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_WIDGET_LIST, NmtWidgetList)) +#define NMT_WIDGET_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_WIDGET_LIST, NmtWidgetListClass)) +#define NMT_IS_WIDGET_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_WIDGET_LIST)) +#define NMT_IS_WIDGET_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_WIDGET_LIST)) +#define NMT_WIDGET_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_WIDGET_LIST, NmtWidgetListClass)) + +typedef struct { + NmtNewtGrid parent; + +} NmtWidgetList; + +typedef struct { + NmtNewtGridClass parent; + + /* signals */ + void (*add_clicked) (NmtWidgetList *list); + void (*remove_clicked) (NmtWidgetList *list, + int n); + + /* methods */ + NmtNewtWidget * (*create_widget) (NmtWidgetList *list, + int n); + +} NmtWidgetListClass; + +GType nmt_widget_list_get_type (void); + +typedef NmtNewtWidget * (*NmtWidgetListCallback) (NmtWidgetList *list, + int n, + gpointer user_data); + +NmtNewtWidget *nmt_widget_list_new (NmtWidgetListCallback create_callback, + gpointer user_data, + GDestroyNotify destroy_notify, + NmtNewtWidget *empty_widget); + +int nmt_widget_list_get_length (NmtWidgetList *list); +void nmt_widget_list_set_length (NmtWidgetList *list, + int length); + +G_END_DECLS + +#endif /* NMT_WIDGET_LIST_H */ diff --git a/clients/tui/nmtui-connect.c b/clients/tui/nmtui-connect.c new file mode 100644 index 00000000..438915d2 --- /dev/null +++ b/clients/tui/nmtui-connect.c @@ -0,0 +1,365 @@ +/* -*- 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:nmtui-connect + * @short_description: nm-applet-like functionality + * + * nmtui-connect implements activating and deactivating #NMConnections, + * including presenting a password dialog if necessary. + */ + +#include "config.h" + +#include <stdlib.h> + +#include <glib/gi18n-lib.h> + +#include "nmt-newt.h" + +#include "nmtui.h" +#include "nmtui-connect.h" +#include "nmt-connect-connection-list.h" +#include "nmt-password-dialog.h" +#include "nm-secret-agent-simple.h" +#include "nmt-utils.h" + +static void +secrets_requested (NMSecretAgentSimple *agent, + const char *request_id, + const char *title, + const char *msg, + GPtrArray *secrets, + gpointer user_data) +{ + NmtNewtForm *form; + + form = nmt_password_dialog_new (request_id, title, msg, secrets); + nmt_newt_form_run_sync (form); + + if (nmt_password_dialog_succeeded (NMT_PASSWORD_DIALOG (form))) + nm_secret_agent_simple_response (agent, request_id, secrets); + else + nm_secret_agent_simple_response (agent, request_id, NULL); + + g_object_unref (form); +} + +static void +connect_cancelled (NmtNewtForm *form, + gpointer user_data) +{ + NmtSyncOp *op = user_data; + GError *error = NULL; + + error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled"); + nmt_sync_op_complete_boolean (op, FALSE, error); + g_clear_error (&error); +} + +static void +activate_ac_state_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + NmtSyncOp *op = user_data; + NMActiveConnectionState state; + GError *error = NULL; + + state = nm_active_connection_get_state (NM_ACTIVE_CONNECTION (object)); + if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING) + return; + + if (state != NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { + error = g_error_new_literal (NM_CLIENT_ERROR, NM_CLIENT_ERROR_FAILED, + _("Activation failed")); + } + + nmt_sync_op_complete_boolean (op, error == NULL, error); + g_clear_error (&error); +} + +static void +activate_callback (GObject *client, + GAsyncResult *result, + gpointer user_data) +{ + NmtSyncOp *op = user_data; + NMActiveConnection *ac; + GError *error = NULL; + + ac = nm_client_activate_connection_finish (NM_CLIENT (client), result, &error); + if (error) + nmt_sync_op_complete_pointer (op, NULL, error); + else + nmt_sync_op_complete_pointer (op, ac, NULL); +} + +static void +add_and_activate_callback (GObject *client, + GAsyncResult *result, + gpointer user_data) +{ + NmtSyncOp *op = user_data; + NMActiveConnection *ac; + GError *error = NULL; + + ac = nm_client_add_and_activate_connection_finish (NM_CLIENT (client), result, &error); + if (error) + nmt_sync_op_complete_pointer (op, NULL, error); + else + nmt_sync_op_complete_pointer (op, ac, NULL); +} + +static void +activate_connection (NMConnection *connection, + NMDevice *device, + NMObject *specific_object) +{ + NmtNewtForm *form; + NMSecretAgentOld *agent; + NmtNewtWidget *label; + NmtSyncOp op; + const char *specific_object_path; + NMActiveConnection *ac; + GError *error = NULL; + + form = g_object_new (NMT_TYPE_NEWT_FORM, + "escape-exits", TRUE, + NULL); + label = nmt_newt_label_new (_("Connecting...")); + nmt_newt_form_set_content (form, label); + + agent = nm_secret_agent_simple_new ("nmtui"); + if (agent) { + if (connection) { + nm_secret_agent_simple_enable (NM_SECRET_AGENT_SIMPLE (agent), + nm_object_get_path (NM_OBJECT (connection))); + } + g_signal_connect (agent, "request-secrets", G_CALLBACK (secrets_requested), NULL); + } + + specific_object_path = specific_object ? nm_object_get_path (specific_object) : NULL; + + /* There's no way to cancel an nm_client_activate_connection() / + * nm_client_add_and_activate_connection() call, so we always let them + * complete, even if the user hits Esc; they shouldn't normally take long + * to complete anyway. + */ + + nmt_sync_op_init (&op); + if (connection) { + nm_client_activate_connection_async (nm_client, + connection, device, specific_object_path, + NULL, activate_callback, &op); + } else { + nm_client_add_and_activate_connection_async (nm_client, + NULL, device, specific_object_path, + NULL, add_and_activate_callback, &op); + } + + nmt_newt_form_show (form); + + ac = nmt_sync_op_wait_pointer (&op, &error); + if (!ac) { + nmt_newt_message_dialog (_("Could not activate connection: %s"), error->message); + g_clear_error (&error); + goto done; + } else if (nm_active_connection_get_state (ac) == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { + /* Already active */ + goto done; + } else if (!nmt_newt_widget_get_realized (NMT_NEWT_WIDGET (form))) { + /* User already hit Esc */ + goto done; + } + + if (!connection) { + connection = NM_CONNECTION (nm_active_connection_get_connection (ac)); + if (connection) { + nm_secret_agent_simple_enable (NM_SECRET_AGENT_SIMPLE (agent), + nm_object_get_path (NM_OBJECT (connection))); + } + } + + /* Now wait for the connection to actually reach the ACTIVATED state, + * allowing the user to cancel if it takes too long. + */ + + nmt_sync_op_init (&op); + + g_signal_connect (form, "quit", G_CALLBACK (connect_cancelled), &op); + g_signal_connect (ac, "notify::" NM_ACTIVE_CONNECTION_STATE, + G_CALLBACK (activate_ac_state_changed), &op); + + if (!nmt_sync_op_wait_boolean (&op, &error)) { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + nmt_newt_message_dialog (_("Could not activate connection: %s"), error->message); + g_clear_error (&error); + } + + g_signal_handlers_disconnect_by_func (form, G_CALLBACK (connect_cancelled), &op); + g_signal_handlers_disconnect_by_func (ac, G_CALLBACK (activate_ac_state_changed), &op); + + done: + if (nmt_newt_widget_get_realized (NMT_NEWT_WIDGET (form))) + nmt_newt_form_quit (form); + g_object_unref (form); + + nm_secret_agent_old_unregister (agent, NULL, NULL); + g_object_unref (agent); +} + +static void +listbox_activated (NmtNewtListbox *listbox, + gpointer user_data) +{ + NmtConnectConnectionList *list = NMT_CONNECT_CONNECTION_LIST (listbox); + NMConnection *connection; + NMDevice *device; + NMObject *specific_object; + NMActiveConnection *ac; + + if (!nmt_connect_connection_list_get_selection (list, + &connection, + &device, + &specific_object, + &ac)) + return; + + if (ac) + nm_client_deactivate_connection (nm_client, ac, NULL, NULL); + else + activate_connection (connection, device, specific_object); +} + +static void +activate_clicked (NmtNewtButton *button, + gpointer listbox) +{ + listbox_activated (listbox, NULL); +} + +static void +listbox_active_changed (GObject *object, + GParamSpec *pspec, + gpointer button) +{ + NmtConnectConnectionList *list = NMT_CONNECT_CONNECTION_LIST (object); + static const char *activate, *deactivate; + static int deactivate_padding, activate_padding; + NMActiveConnection *ac; + gboolean has_selection; + + if (G_UNLIKELY (activate == NULL)) { + int activate_width, deactivate_width; + + activate = _("Activate"); + activate_width = nmt_newt_text_width (activate); + deactivate = _("Deactivate"); + deactivate_width = nmt_newt_text_width (deactivate); + + activate_padding = MAX (0, deactivate_width - activate_width); + deactivate_padding = MAX (0, activate_width - deactivate_width); + } + + has_selection = nmt_connect_connection_list_get_selection (list, NULL, NULL, NULL, &ac); + + nmt_newt_component_set_sensitive (button, has_selection); + if (has_selection && ac) { + nmt_newt_button_set_label (button, deactivate); + nmt_newt_widget_set_padding (button, 0, 0, deactivate_padding, 0); + } else { + nmt_newt_button_set_label (button, activate); + nmt_newt_widget_set_padding (button, 0, 0, activate_padding, 0); + } +} + +static NmtNewtForm * +nmt_connect_connection_list (void) +{ + int screen_width, screen_height; + NmtNewtForm *form; + NmtNewtWidget *list, *activate, *quit, *bbox, *grid; + + newtGetScreenSize (&screen_width, &screen_height); + + form = g_object_new (NMT_TYPE_NEWT_FORM, + "y", 2, + "height", screen_height - 4, + "escape-exits", TRUE, + NULL); + + grid = nmt_newt_grid_new (); + + list = nmt_connect_connection_list_new (); + nmt_newt_grid_add (NMT_NEWT_GRID (grid), list, 0, 0); + nmt_newt_grid_set_flags (NMT_NEWT_GRID (grid), list, + NMT_NEWT_GRID_FILL_X | NMT_NEWT_GRID_FILL_Y | + NMT_NEWT_GRID_EXPAND_X | NMT_NEWT_GRID_EXPAND_Y); + g_signal_connect (list, "activated", G_CALLBACK (listbox_activated), NULL); + + bbox = nmt_newt_button_box_new (NMT_NEWT_BUTTON_BOX_VERTICAL); + nmt_newt_grid_add (NMT_NEWT_GRID (grid), bbox, 1, 0); + nmt_newt_widget_set_padding (bbox, 1, 1, 0, 1); + + activate = nmt_newt_button_box_add_start (NMT_NEWT_BUTTON_BOX (bbox), _("Activate")); + g_signal_connect (list, "notify::active", G_CALLBACK (listbox_active_changed), activate); + listbox_active_changed (G_OBJECT (list), NULL, activate); + g_signal_connect (activate, "clicked", G_CALLBACK (activate_clicked), list); + + quit = nmt_newt_button_box_add_end (NMT_NEWT_BUTTON_BOX (bbox), _("Quit")); + nmt_newt_widget_set_exit_on_activate (quit, TRUE); + + nmt_newt_form_set_content (form, grid); + return form; +} + +static NmtNewtForm * +nmt_connect_connection (const char *identifier) +{ + NmtNewtWidget *list; + NMConnection *connection; + NMDevice *device; + NMObject *specific_object; + NMActiveConnection *ac; + + list = nmt_connect_connection_list_new (); + if (!nmt_connect_connection_list_get_connection (NMT_CONNECT_CONNECTION_LIST (list), + identifier, + &connection, + &device, + &specific_object, + &ac)) + nmt_newt_message_dialog (_("No such connection '%s'"), identifier); + else if (ac) + nmt_newt_message_dialog (_("Connection is already active")); + else + activate_connection (connection, device, specific_object); + g_object_unref (list); + + return NULL; +} + +NmtNewtForm * +nmtui_connect (int argc, char **argv) +{ + if (argc == 2) + return nmt_connect_connection (argv[1]); + else + return nmt_connect_connection_list (); +} diff --git a/clients/tui/nmtui-connect.h b/clients/tui/nmtui-connect.h new file mode 100644 index 00000000..8310ac38 --- /dev/null +++ b/clients/tui/nmtui-connect.h @@ -0,0 +1,28 @@ +/* -*- 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. + */ + +#ifndef NMTUI_CONNECT_H +#define NMTUI_CONNECT_H + +G_BEGIN_DECLS + +NmtNewtForm *nmtui_connect (int argc, char **argv); + +G_END_DECLS + +#endif /* NMTUI_CONNECT_H */ diff --git a/clients/tui/nmtui-edit.c b/clients/tui/nmtui-edit.c new file mode 100644 index 00000000..0c3206da --- /dev/null +++ b/clients/tui/nmtui-edit.c @@ -0,0 +1,577 @@ +/* -*- 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:nmtui-edit + * @short_description: nm-connection-editor-like functionality + * + * nmtui-edit implements editing #NMConnections. + */ + +#include "config.h" + +#include <stdlib.h> + +#include <glib/gi18n-lib.h> +#include <NetworkManager.h> + +#include "nmtui.h" +#include "nmtui-edit.h" +#include "nmt-edit-connection-list.h" +#include "nmt-editor.h" +#include "nmt-utils.h" + +#include "nm-editor-utils.h" + +static void +list_add_connection (NmtEditConnectionList *list, + gpointer form) +{ + nmt_add_connection (); + nmt_newt_form_set_focus (form, NMT_NEWT_WIDGET (list)); +} + +static void +list_edit_connection (NmtEditConnectionList *list, + NMConnection *connection, + gpointer form) +{ + nmt_edit_connection (connection); + nmt_newt_form_set_focus (form, NMT_NEWT_WIDGET (list)); +} + +static void +list_remove_connection (NmtEditConnectionList *list, + NMRemoteConnection *connection, + gpointer form) +{ + nmt_remove_connection (connection); + nmt_newt_form_set_focus (form, NMT_NEWT_WIDGET (list)); +} + +static gboolean +edit_connection_list_filter (NmtEditConnectionList *list, + NMConnection *connection, + gpointer user_data) +{ + NMSettingConnection *s_con; + const char *master, *slave_type; + const char *uuid, *ifname; + const GPtrArray *conns; + int i; + gboolean found_master = FALSE; + + s_con = nm_connection_get_setting_connection (connection); + g_return_val_if_fail (s_con != NULL, FALSE); + + master = nm_setting_connection_get_master (s_con); + if (!master) + return TRUE; + slave_type = nm_setting_connection_get_slave_type (s_con); + if ( g_strcmp0 (slave_type, NM_SETTING_BOND_SETTING_NAME) != 0 + && g_strcmp0 (slave_type, NM_SETTING_TEAM_SETTING_NAME) != 0 + && g_strcmp0 (slave_type, NM_SETTING_BRIDGE_SETTING_NAME) != 0) + return TRUE; + + conns = nm_client_get_connections (nm_client); + for (i = 0; i < conns->len; i++) { + NMConnection *candidate = conns->pdata[i]; + + uuid = nm_connection_get_uuid (candidate); + ifname = nm_connection_get_interface_name (candidate); + if (!g_strcmp0 (master, uuid) || !g_strcmp0 (master, ifname)) { + found_master = TRUE; + break; + } + } + + return !found_master; +} + +static NmtNewtForm * +nmt_edit_main_connection_list (void) +{ + int screen_width, screen_height; + NmtNewtForm *form; + NmtNewtWidget *quit, *list; + + newtGetScreenSize (&screen_width, &screen_height); + + form = g_object_new (NMT_TYPE_NEWT_FORM, + "y", 2, + "height", screen_height - 4, + "escape-exits", TRUE, + NULL); + + quit = nmt_newt_button_new (_("Quit")); + nmt_newt_widget_set_exit_on_activate (quit, TRUE); + + list = g_object_new (NMT_TYPE_EDIT_CONNECTION_LIST, + "extra-widget", quit, + "connection-filter", edit_connection_list_filter, + NULL); + + g_signal_connect (list, "add-connection", + G_CALLBACK (list_add_connection), form); + g_signal_connect (list, "edit-connection", + G_CALLBACK (list_edit_connection), form); + g_signal_connect (list, "remove-connection", + G_CALLBACK (list_remove_connection), form); + + nmt_newt_form_set_content (form, list); + return form; +} + +#define NMT_TYPE_ADD_CONNECTION (nmt_add_connection_get_type ()) +#define NMT_ADD_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_ADD_CONNECTION, NmtAddConnection)) +#define NMT_IS_ADD_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_ADD_CONNECTION)) + +typedef NmtNewtForm NmtAddConnection; +typedef NmtNewtFormClass NmtAddConnectionClass; + +GType nmt_add_connection_get_type (void); + +G_DEFINE_TYPE (NmtAddConnection, nmt_add_connection, NMT_TYPE_NEWT_FORM) + +#define NMT_ADD_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_ADD_CONNECTION, NmtAddConnectionPrivate)) + +typedef struct { + NmtNewtTextbox *textbox; + NmtNewtListbox *listbox; + + char *primary_text; + char *secondary_text; + NMConnection *master; + NmtAddConnectionTypeFilter type_filter; + gpointer type_filter_data; + + gboolean single_type; +} NmtAddConnectionPrivate; + +enum { + PROP_0, + + PROP_PRIMARY_TEXT, + PROP_SECONDARY_TEXT, + PROP_MASTER, + PROP_TYPE_FILTER, + PROP_TYPE_FILTER_DATA, + + LAST_PROP +}; + +static void +create_connection (NmtNewtWidget *widget, gpointer list) +{ + NmtAddConnectionPrivate *priv = NMT_ADD_CONNECTION_GET_PRIVATE (list); + GType type = (GType) GPOINTER_TO_SIZE (nmt_newt_listbox_get_active_key (priv->listbox)); + NMConnection *connection; + + connection = nm_editor_utils_create_connection (type, priv->master, nm_client); + nmt_edit_connection (connection); + g_object_unref (connection); + + nmt_newt_form_quit (list); +} + +static void +nmt_add_connection_init (NmtAddConnection *form) +{ + NmtAddConnectionPrivate *priv = NMT_ADD_CONNECTION_GET_PRIVATE (form); + NmtNewtWidget *textbox, *listbox, *button; + NmtNewtGrid *grid, *buttons; + + grid = NMT_NEWT_GRID (nmt_newt_grid_new ()); + + textbox = nmt_newt_textbox_new (0, 60); + priv->textbox = NMT_NEWT_TEXTBOX (textbox); + nmt_newt_grid_add (grid, textbox, 0, 0); + + listbox = nmt_newt_listbox_new (5, NMT_NEWT_LISTBOX_SCROLL); + priv->listbox = NMT_NEWT_LISTBOX (listbox); + g_signal_connect (priv->listbox, "activated", G_CALLBACK (create_connection), form); + nmt_newt_grid_add (grid, listbox, 0, 1); + nmt_newt_widget_set_padding (listbox, 0, 1, 0, 0); + nmt_newt_grid_set_flags (grid, listbox, NMT_NEWT_GRID_EXPAND_X); + + // FIXME: VPN description textbox + + buttons = NMT_NEWT_GRID (nmt_newt_grid_new ()); + nmt_newt_grid_add (grid, NMT_NEWT_WIDGET (buttons), 0, 2); + nmt_newt_widget_set_padding (NMT_NEWT_WIDGET (buttons), 0, 1, 0, 0); + + button = g_object_ref_sink (nmt_newt_button_new (_("Cancel"))); + nmt_newt_widget_set_exit_on_activate (button, TRUE); + nmt_newt_grid_add (NMT_NEWT_GRID (buttons), button, 0, 0); + nmt_newt_widget_set_padding (button, 0, 0, 1, 0); + nmt_newt_grid_set_flags (NMT_NEWT_GRID (buttons), button, + NMT_NEWT_GRID_EXPAND_X | NMT_NEWT_GRID_ANCHOR_RIGHT | + NMT_NEWT_GRID_FILL_Y); + + button = g_object_ref_sink (nmt_newt_button_new (_("Create"))); + g_signal_connect (button, "clicked", G_CALLBACK (create_connection), form); + nmt_newt_grid_add (NMT_NEWT_GRID (buttons), button, 1, 0); + + nmt_newt_form_set_content (NMT_NEWT_FORM (form), NMT_NEWT_WIDGET (grid)); +} + +static void +nmt_add_connection_constructed (GObject *object) +{ + NmtAddConnectionPrivate *priv = NMT_ADD_CONNECTION_GET_PRIVATE (object); + NMEditorConnectionTypeData **types; + char *text; + int i, num_types; + + if (priv->secondary_text) { + text = g_strdup_printf ("%s\n\n%s", + priv->primary_text, + priv->secondary_text); + } else + text = g_strdup (priv->primary_text); + nmt_newt_textbox_set_text (priv->textbox, text); + g_free (text); + + types = nm_editor_utils_get_connection_type_list (); + for (i = num_types = 0; types[i]; i++) { + if (priv->type_filter && !priv->type_filter (types[i]->setting_type, priv->type_filter_data)) + continue; + nmt_newt_listbox_append (priv->listbox, types[i]->name, + GSIZE_TO_POINTER (types[i]->setting_type)); + num_types++; + } + + if (num_types == 1) + priv->single_type = TRUE; + + G_OBJECT_CLASS (nmt_add_connection_parent_class)->constructed (object); +} + +static void +nmt_add_connection_show (NmtNewtForm *form) +{ + NmtAddConnectionPrivate *priv = NMT_ADD_CONNECTION_GET_PRIVATE (form); + + if (priv->single_type) { + nmt_newt_listbox_set_active (priv->listbox, 0); + create_connection (NMT_NEWT_WIDGET (priv->listbox), g_object_ref (form)); + } else + NMT_NEWT_FORM_CLASS (nmt_add_connection_parent_class)->show (form); +} + +static void +nmt_add_connection_finalize (GObject *object) +{ + NmtAddConnectionPrivate *priv = NMT_ADD_CONNECTION_GET_PRIVATE (object); + + g_free (priv->primary_text); + g_free (priv->secondary_text); + g_clear_object (&priv->master); + + G_OBJECT_CLASS (nmt_add_connection_parent_class)->finalize (object); +} + +static void +nmt_add_connection_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtAddConnectionPrivate *priv = NMT_ADD_CONNECTION_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_PRIMARY_TEXT: + priv->primary_text = g_value_dup_string (value); + break; + case PROP_SECONDARY_TEXT: + priv->secondary_text = g_value_dup_string (value); + break; + case PROP_MASTER: + priv->master = g_value_dup_object (value); + break; + case PROP_TYPE_FILTER: + priv->type_filter = g_value_get_pointer (value); + break; + case PROP_TYPE_FILTER_DATA: + priv->type_filter_data = g_value_get_pointer (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_add_connection_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtAddConnectionPrivate *priv = NMT_ADD_CONNECTION_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_PRIMARY_TEXT: + g_value_set_string (value, priv->primary_text); + break; + case PROP_SECONDARY_TEXT: + g_value_set_string (value, priv->secondary_text); + break; + case PROP_MASTER: + g_value_set_object (value, priv->master); + break; + case PROP_TYPE_FILTER: + g_value_set_pointer (value, priv->type_filter); + break; + case PROP_TYPE_FILTER_DATA: + g_value_set_pointer (value, priv->type_filter_data); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_add_connection_class_init (NmtAddConnectionClass *add_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (add_class); + NmtNewtFormClass *form_class = NMT_NEWT_FORM_CLASS (add_class); + + g_type_class_add_private (add_class, sizeof (NmtAddConnectionPrivate)); + + /* virtual methods */ + object_class->constructed = nmt_add_connection_constructed; + object_class->set_property = nmt_add_connection_set_property; + object_class->get_property = nmt_add_connection_get_property; + object_class->finalize = nmt_add_connection_finalize; + + form_class->show = nmt_add_connection_show; + + g_object_class_install_property + (object_class, PROP_PRIMARY_TEXT, + g_param_spec_string ("primary-text", "", "", + _("Select the type of connection you wish to create."), + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property + (object_class, PROP_SECONDARY_TEXT, + g_param_spec_string ("secondary-text", "", "", +#if 0 + _("If you are creating a VPN, and the VPN connection you " + "wish to create does not appear in the list, you may " + "not have the correct VPN plugin installed."), +#else + NULL, +#endif + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property + (object_class, PROP_MASTER, + g_param_spec_object ("master", "", "", + NM_TYPE_CONNECTION, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property + (object_class, PROP_TYPE_FILTER, + g_param_spec_pointer ("type-filter", "", "", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property + (object_class, PROP_TYPE_FILTER_DATA, + g_param_spec_pointer ("type-filter-data", "", "", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} + +void +nmt_add_connection (void) +{ + NmtNewtForm *form; + + form = g_object_new (NMT_TYPE_ADD_CONNECTION, + "title", _("New Connection"), + NULL); + nmt_newt_form_show (form); + g_object_unref (form); +} + +void +nmt_add_connection_full (const char *primary_text, + const char *secondary_text, + NMConnection *master, + NmtAddConnectionTypeFilter type_filter, + gpointer type_filter_data) +{ + NmtNewtForm *form; + + form = g_object_new (NMT_TYPE_ADD_CONNECTION, + "title", _("New Connection"), + "primary-text", primary_text, + "secondary-text", secondary_text, + "master", master, + "type-filter", type_filter, + "type-filter-data", type_filter_data, + NULL); + nmt_newt_form_show (form); + g_object_unref (form); +} + +void +nmt_edit_connection (NMConnection *connection) +{ + NmtNewtForm *editor; + + editor = nmt_editor_new (connection); + if (!editor) + return; + + nmt_newt_form_show (editor); + g_object_unref (editor); +} + +typedef struct { + NmtSyncOp op; + gboolean got_callback, got_signal; + NMRemoteConnection *connection; +} ConnectionDeleteData; + +static void +connection_deleted_callback (GObject *connection, + GAsyncResult *result, + gpointer user_data) +{ + ConnectionDeleteData *data = user_data; + GError *error = NULL; + + if (!nm_remote_connection_delete_finish (data->connection, result, &error)) { + nmt_newt_message_dialog (_("Unable to delete connection: %s"), + error->message); + } else + data->got_callback = TRUE; + + if (error || (data->got_callback && data->got_signal)) + nmt_sync_op_complete_boolean (&data->op, error == NULL, error); + g_clear_error (&error); +} + +static void +connection_removed_signal (NMClient *client, + NMRemoteConnection *connection, + gpointer user_data) +{ + ConnectionDeleteData *data = user_data; + + if (connection == data->connection) { + data->got_signal = TRUE; + if (data->got_callback && data->got_signal) + nmt_sync_op_complete_boolean (&data->op, TRUE, NULL); + } +} + +static void +remove_one_connection (NMRemoteConnection *connection) +{ + ConnectionDeleteData data; + GError *error = NULL; + + data.got_callback = data.got_signal = FALSE; + nmt_sync_op_init (&data.op); + + data.connection = connection; + g_signal_connect (nm_client, NM_CLIENT_CONNECTION_REMOVED, + G_CALLBACK (connection_removed_signal), &data); + nm_remote_connection_delete_async (connection, NULL, connection_deleted_callback, &data); + + if (!nmt_sync_op_wait_boolean (&data.op, &error)) { + nmt_newt_message_dialog (_("Could not delete connection '%s': %s"), + nm_connection_get_id (NM_CONNECTION (connection)), + error->message); + g_error_free (error); + } + + g_signal_handlers_disconnect_by_func (nm_client, G_CALLBACK (connection_removed_signal), &data); +} + +void +nmt_remove_connection (NMRemoteConnection *connection) +{ + const GPtrArray *all_conns; + GSList *slaves, *iter; + int i; + NMRemoteConnection *slave; + NMSettingConnection *s_con; + const char *uuid, *iface, *master; + int choice; + + choice = nmt_newt_choice_dialog (_("Cancel"), + _("Delete"), + _("Are you sure you want to delete the connection '%s'?"), + nm_connection_get_id (NM_CONNECTION (connection))); + if (choice == 1) + return; + + g_object_ref (connection); + remove_one_connection (connection); + + uuid = nm_connection_get_uuid (NM_CONNECTION (connection)); + iface = nm_connection_get_interface_name (NM_CONNECTION (connection)); + + all_conns = nm_client_get_connections (nm_client); + slaves = NULL; + for (i = 0; i < all_conns->len; i++) { + slave = all_conns->pdata[i]; + s_con = nm_connection_get_setting_connection (NM_CONNECTION (slave)); + master = nm_setting_connection_get_master (s_con); + if (master) { + if (!g_strcmp0 (master, uuid) || !g_strcmp0 (master, iface)) + slaves = g_slist_prepend (slaves, g_object_ref (slave)); + } + } + + for (iter = slaves; iter; iter = iter->next) + remove_one_connection (iter->data); + g_slist_free_full (slaves, g_object_unref); + + g_object_unref (connection); +} + +NmtNewtForm * +nmtui_edit (int argc, char **argv) +{ + NMConnection *conn = NULL; + + if (argc == 2) { + if (nm_utils_is_uuid (argv[1])) + conn = NM_CONNECTION (nm_client_get_connection_by_uuid (nm_client, argv[1])); + if (!conn) + conn = NM_CONNECTION (nm_client_get_connection_by_id (nm_client, argv[1])); + + if (!conn) { + nmt_newt_message_dialog ("%s: no such connection '%s'\n", argv[0], argv[1]); + return NULL; + } + + return nmt_editor_new (conn); + } else + return nmt_edit_main_connection_list (); +} diff --git a/clients/tui/nmtui-edit.h b/clients/tui/nmtui-edit.h new file mode 100644 index 00000000..dae91cfa --- /dev/null +++ b/clients/tui/nmtui-edit.h @@ -0,0 +1,44 @@ +/* -*- 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. + */ + +#ifndef NMTUI_EDIT_H +#define NMTUI_EDIT_H + +#include "nmt-newt.h" + +G_BEGIN_DECLS + +typedef gboolean (*NmtAddConnectionTypeFilter) (GType connection_type, + gpointer user_data); + +NmtNewtForm *nmtui_edit (int argc, char **argv); + +void nmt_add_connection (void); +void nmt_add_connection_full (const char *primary_text, + const char *secondary_text, + NMConnection *master, + NmtAddConnectionTypeFilter type_filter, + gpointer type_filter_data); + +void nmt_edit_connection (NMConnection *connection); + +void nmt_remove_connection (NMRemoteConnection *connection); + +G_END_DECLS + +#endif /* NMTUI_EDIT_H */ diff --git a/clients/tui/nmtui-hostname.c b/clients/tui/nmtui-hostname.c new file mode 100644 index 00000000..23de95b8 --- /dev/null +++ b/clients/tui/nmtui-hostname.c @@ -0,0 +1,128 @@ +/* -*- 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:nmtui-hostname + * @short_description: hostname-setting functionality + * + * nmtui-hostname implements the "set hostname" functionality + */ + +#include "config.h" + +#include <glib/gi18n-lib.h> + +#include "nmt-newt.h" + +#include "nmtui.h" +#include "nmtui-hostname.h" +#include "nmt-utils.h" + +static char * +nmtui_hostname_run_dialog (void) +{ + NmtNewtForm *form; + NmtNewtWidget *widget, *ok, *cancel; + NmtNewtGrid *grid; + NmtNewtEntry *entry; + NmtNewtButtonBox *bbox; + char *hostname, *ret = NULL; + + form = g_object_new (NMT_TYPE_NEWT_FORM, + "title", _("Set Hostname"), + "escape-exits", TRUE, + NULL); + + widget = nmt_newt_grid_new (); + nmt_newt_form_set_content (form, widget); + grid = NMT_NEWT_GRID (widget); + + widget = nmt_newt_label_new (_("Hostname")); + nmt_newt_grid_add (grid, widget, 0, 0); + + widget = nmt_newt_entry_new (40, 0); + nmt_newt_widget_set_exit_on_activate (widget, TRUE); + nmt_newt_grid_add (grid, widget, 1, 0); + nmt_newt_widget_set_padding (widget, 1, 0, 0, 0); + entry = NMT_NEWT_ENTRY (widget); + + widget = nmt_newt_button_box_new (NMT_NEWT_BUTTON_BOX_HORIZONTAL); + nmt_newt_grid_add (grid, widget, 1, 1); + nmt_newt_widget_set_padding (widget, 0, 1, 0, 0); + bbox = NMT_NEWT_BUTTON_BOX (widget); + + cancel = nmt_newt_button_box_add_end (bbox, _("Cancel")); + nmt_newt_widget_set_exit_on_activate (cancel, TRUE); + ok = nmt_newt_button_box_add_end (bbox, _("OK")); + nmt_newt_widget_set_exit_on_activate (ok, TRUE); + + g_object_get (G_OBJECT (nm_client), + NM_CLIENT_HOSTNAME, &hostname, + NULL); + nmt_newt_entry_set_text (entry, hostname); + g_free (hostname); + + widget = nmt_newt_form_run_sync (form); + if (widget == (NmtNewtWidget *)entry || widget == ok) + ret = g_strdup (nmt_newt_entry_get_text (entry)); + + g_object_unref (form); + return ret; +} + +static void +hostname_set (GObject *object, + GAsyncResult *result, + gpointer op) +{ + GError *error = NULL; + + nm_client_save_hostname_finish (NM_CLIENT (object), result, &error); + nmt_sync_op_complete_boolean (op, error == NULL, error); + g_clear_error (&error); +} + +NmtNewtForm * +nmtui_hostname (int argc, char **argv) +{ + const char *hostname; + char *tmp = NULL; + NmtSyncOp op; + GError *error = NULL; + + if (argc == 2) + hostname = argv[1]; + else + hostname = tmp = nmtui_hostname_run_dialog (); + + if (hostname) { + nmt_sync_op_init (&op); + nm_client_save_hostname_async (nm_client, hostname, NULL, hostname_set, &op); + if (nmt_sync_op_wait_boolean (&op, &error)) { + /* Translators: this indicates the result. ie, "I have set the hostname to ..." */ + nmt_newt_message_dialog (_("Set hostname to '%s'"), hostname); + } else { + nmt_newt_message_dialog (_("Unable to set hostname: %s"), error->message); + g_error_free (error); + } + + g_free (tmp); + } + + return NULL; +} diff --git a/clients/tui/nmtui-hostname.h b/clients/tui/nmtui-hostname.h new file mode 100644 index 00000000..a14bc699 --- /dev/null +++ b/clients/tui/nmtui-hostname.h @@ -0,0 +1,28 @@ +/* -*- 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. + */ + +#ifndef NMTUI_HOSTNAME_H +#define NMTUI_HOSTNAME_H + +G_BEGIN_DECLS + +NmtNewtForm *nmtui_hostname (int argc, char **argv); + +G_END_DECLS + +#endif /* NMTUI_HOSTNAME_H */ diff --git a/clients/tui/nmtui.c b/clients/tui/nmtui.c new file mode 100644 index 00000000..0fac98eb --- /dev/null +++ b/clients/tui/nmtui.c @@ -0,0 +1,293 @@ +/* -*- 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:nmtui + * @short_description: nmtui toplevel + * + * The top level of nmtui. Exists mostly just to call nmtui_connect(), + * nmtui_edit(), and nmtui_hostname(). + */ + +#include "config.h" + +#include <locale.h> +#include <stdlib.h> +#include <string.h> + +#include <glib.h> +#include <glib/gi18n-lib.h> + +#include <NetworkManager.h> + +#include "nmt-newt.h" +#include "nm-editor-bindings.h" + +#include "nmtui.h" +#include "nmtui-edit.h" +#include "nmtui-connect.h" +#include "nmtui-hostname.h" + +NMClient *nm_client; +static GMainLoop *loop; + +typedef NmtNewtForm * (*NmtuiSubprogram) (int argc, char **argv); + +static const struct { + const char *name, *shortcut, *arg; + const char *display_name; + NmtuiSubprogram func; +} subprograms[] = { + { "edit", "nmtui-edit", N_("connection"), + N_("Edit a connection"), + nmtui_edit }, + { "connect", "nmtui-connect", N_("connection"), + N_("Activate a connection"), + nmtui_connect }, + { "hostname", "nmtui-hostname", N_("new hostname"), + N_("Set system hostname"), + nmtui_hostname } +}; +static const int num_subprograms = G_N_ELEMENTS (subprograms); + +static void +quit_func (int argc, char **argv) +{ + nmtui_quit (); +} + +static NmtNewtForm * +nmtui_main (int argc, char **argv) +{ + NmtNewtForm *form; + NmtNewtWidget *widget, *ok; + NmtNewtGrid *grid; + NmtNewtListbox *listbox; + NmtNewtButtonBox *bbox; + NmtuiSubprogram subprogram = NULL; + int i; + + form = g_object_new (NMT_TYPE_NEWT_FORM, + "title", _("NetworkManager TUI"), + "escape-exits", TRUE, + NULL); + + widget = nmt_newt_grid_new (); + nmt_newt_form_set_content (form, widget); + grid = NMT_NEWT_GRID (widget); + + widget = nmt_newt_label_new (_("Please select an option")); + nmt_newt_grid_add (grid, widget, 0, 0); + + widget = g_object_new (NMT_TYPE_NEWT_LISTBOX, + "height", num_subprograms + 2, + "skip-null-keys", TRUE, + NULL); + nmt_newt_grid_add (grid, widget, 0, 1); + nmt_newt_widget_set_padding (widget, 0, 1, 0, 1); + nmt_newt_widget_set_exit_on_activate (widget, TRUE); + listbox = NMT_NEWT_LISTBOX (widget); + + for (i = 0; i < num_subprograms; i++) { + nmt_newt_listbox_append (listbox, _(subprograms[i].display_name), + subprograms[i].func); + } + nmt_newt_listbox_append (listbox, "", NULL); + nmt_newt_listbox_append (listbox, _("Quit"), quit_func); + + widget = nmt_newt_button_box_new (NMT_NEWT_BUTTON_BOX_HORIZONTAL); + nmt_newt_grid_add (grid, widget, 0, 2); + bbox = NMT_NEWT_BUTTON_BOX (widget); + + ok = nmt_newt_button_box_add_end (bbox, _("OK")); + nmt_newt_widget_set_exit_on_activate (ok, TRUE); + + widget = nmt_newt_form_run_sync (form); + if (widget) + subprogram = nmt_newt_listbox_get_active_key (listbox); + g_object_unref (form); + + if (subprogram) + return subprogram (argc, argv); + else + return NULL; +} + +/** + * nmtui_quit: + * + * Causes nmtui to exit. + */ +void +nmtui_quit (void) +{ + g_main_loop_quit (loop); +} + +static void +usage (void) +{ + const char *argv0 = g_get_prgname (); + const char *usage_str = _("Usage"); + int i; + + for (i = 0; i < num_subprograms; i++) { + if (!strcmp (argv0, subprograms[i].shortcut)) { + g_printerr ("%s: %s [%s]\n", usage_str, argv0, _(subprograms[i].arg)); + exit (1); + } + } + + g_printerr ("%s: nmtui\n", usage_str); + for (i = 0; i < num_subprograms; i++) { + g_printerr ("%*s nmtui %s [%s]\n", + nmt_newt_text_width (usage_str), " ", + subprograms[i].name, + _(subprograms[i].arg)); + } + exit (1); +} + +typedef struct { + NmtuiSubprogram subprogram; + int argc; + char **argv; +} NmtuiStartupData; + +static void +toplevel_form_quit (NmtNewtForm *form, + gpointer user_data) +{ + nmtui_quit (); +} + +static gboolean +idle_run_subprogram (gpointer user_data) +{ + NmtuiStartupData *data = user_data; + NmtNewtForm *form; + + form = data->subprogram (data->argc, data->argv); + if (form) { + g_signal_connect (form, "quit", G_CALLBACK (toplevel_form_quit), NULL); + nmt_newt_form_show (form); + g_object_unref (form); + } else + nmtui_quit (); + + return FALSE; +} + +gboolean sleep_on_startup = FALSE; +gboolean noinit = FALSE; + +GOptionEntry entries[] = { + { "sleep", 's', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &sleep_on_startup, + "Sleep on startup", NULL }, + { "noinit", 'n', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &noinit, + "Don't initialize newt", NULL }, + { NULL } +}; + +int +main (int argc, char **argv) +{ + GOptionContext *opts; + GError *error = NULL; + NmtuiStartupData startup_data; + const char *prgname; + int i; + + setlocale (LC_ALL, ""); + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + opts = g_option_context_new (NULL); + g_option_context_add_main_entries (opts, entries, NULL); + + if (!g_option_context_parse (opts, &argc, &argv, &error)) { + g_printerr ("%s: %s: %s\n", + argv[0], + _("Could not parse arguments"), + error->message); + exit (1); + } + g_option_context_free (opts); + + nm_editor_bindings_init (); + + nm_client = nm_client_new (NULL, &error); + if (!nm_client) { + g_printerr (_("Could not contact NetworkManager: %s.\n"), error->message); + g_error_free (error); + exit (1); + } + if (!nm_client_get_nm_running (nm_client)) { + g_printerr ("%s\n", _("NetworkManager is not running.")); + exit (1); + } + + if (sleep_on_startup) + sleep (5); + + startup_data.subprogram = NULL; + prgname = g_get_prgname (); + if (g_str_has_prefix (prgname, "lt-")) + prgname += 3; + if (!strcmp (prgname, "nmtui")) { + if (argc > 1) { + for (i = 0; i < num_subprograms; i++) { + if (!strcmp (argv[1], subprograms[i].name)) { + argc--; + argv[0] = (char *) subprograms[i].shortcut; + memmove (&argv[1], &argv[2], argc * sizeof (char *)); + startup_data.subprogram = subprograms[i].func; + break; + } + } + } else + startup_data.subprogram = nmtui_main; + } else { + for (i = 0; i < num_subprograms; i++) { + if (!strcmp (prgname, subprograms[i].shortcut)) { + startup_data.subprogram = subprograms[i].func; + break; + } + } + } + if (!startup_data.subprogram) + usage (); + + if (!noinit) + nmt_newt_init (); + + startup_data.argc = argc; + startup_data.argv = argv; + g_idle_add (idle_run_subprogram, &startup_data); + loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (loop); + g_main_loop_unref (loop); + + if (!noinit) + nmt_newt_finished (); + + g_object_unref (nm_client); + + return 0; +} diff --git a/clients/tui/nmtui.h b/clients/tui/nmtui.h new file mode 100644 index 00000000..aada9719 --- /dev/null +++ b/clients/tui/nmtui.h @@ -0,0 +1,32 @@ +/* -*- 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. + */ + +#ifndef NMTUI_H +#define NMTUI_H + +#include <NetworkManager.h> + +G_BEGIN_DECLS + +extern NMClient *nm_client; + +void nmtui_quit (void); + +G_END_DECLS + +#endif /* NMTUI_H */ |