From 45f88636b4b260e2eebf7722615416f02df526b3 Mon Sep 17 00:00:00 2001 From: Kichan Kwon Date: Mon, 14 May 2018 17:14:09 +0900 Subject: [PATCH 2/5] Initial source Change-Id: I22b9a4f8d1082d85290ddc51c50bd816e433d98e Signed-off-by: Kichan Kwon --- .gitignore | 19 + LICENSE | 203 +++++ Makefile.am | 195 +++++ autogen.sh | 21 + configure.ac | 153 ++++ packaging/system-recovery.manifest | 5 + packaging/system-recovery.spec | 116 +++ src/fonts/font-10x18.h | 216 ++++++ src/librui/common.h | 49 ++ src/librui/fbdev.h | 46 ++ src/librui/graphics-fbdev-common.c | 87 +++ src/librui/graphics-fbdev.c | 157 ++++ src/librui/graphics-tdm.c | 101 +++ src/librui/graphics.c | 495 ++++++++++++ src/librui/graphics.h | 155 ++++ src/librui/input-events.c | 309 ++++++++ src/librui/input-events.h | 59 ++ src/librui/resources.c | 534 +++++++++++++ src/librui/rui-description.c | 32 + src/librui/rui-description.h | 44 ++ src/librui/rui-image.h | 67 ++ src/librui/rui-images.c | 153 ++++ src/librui/rui-menu.c | 106 +++ src/librui/rui-menu.h | 68 ++ src/librui/rui-progress-bar.c | 68 ++ src/librui/rui-progress-bar.h | 48 ++ src/librui/rui-ruler.h | 42 + src/librui/rui-rulers.c | 36 + src/librui/rui.c | 119 +++ src/librui/rui.h | 72 ++ src/librui/tdm-if.c | 360 +++++++++ src/librui/tdm-if.h | 69 ++ src/shared/log.c | 414 ++++++++++ src/shared/log.h | 71 ++ src/system-recovery/.gitignore | 2 + src/system-recovery/50-system-recovery-sprd.list | 24 + src/system-recovery/50-system-recovery.list.m4.in | 44 ++ src/system-recovery/process-util.c | 90 +++ src/system-recovery/process-util.h | 34 + src/system-recovery/recovery-action-set.in | 18 + src/system-recovery/recovery-headless.c | 68 ++ src/system-recovery/recovery-init.in | 79 ++ src/system-recovery/recovery-main.c | 125 +++ src/system-recovery/recovery-rui-skin.h | 136 ++++ src/system-recovery/recovery-rui.c | 854 +++++++++++++++++++++ src/system-recovery/res-util/README.txt | 13 + src/system-recovery/res-util/interlace-frames.py | 56 ++ src/system-recovery/res-util/make-anim.sh | 7 + src/system-recovery/res-util/make-menu-title.sh | 10 + src/system-recovery/res-util/tizen-anim1src.png | Bin 0 -> 18641 bytes src/system-recovery/res-util/tizen-anim2src.png | Bin 0 -> 18676 bytes src/system-recovery/res-util/tizen-anim3src.png | Bin 0 -> 18560 bytes src/system-recovery/res-util/tizen-anim4src.png | Bin 0 -> 18601 bytes src/system-recovery/res-util/tizen-anim5src.png | Bin 0 -> 18628 bytes src/system-recovery/res/images/12x22.png | Bin 0 -> 13815 bytes src/system-recovery/res/images/18x32.png | Bin 0 -> 23763 bytes src/system-recovery/res/images/font.png | Bin 0 -> 13815 bytes .../res/images/menu-title-480x800.png | Bin 0 -> 1941 bytes .../res/images/menu-title-720x1280.png | Bin 0 -> 2797 bytes src/system-recovery/res/images/menu-title.png | Bin 0 -> 1941 bytes src/system-recovery/res/images/tizen-anim.png | Bin 0 -> 30353 bytes src/system-recovery/res/images/warning.png | Bin 0 -> 8182 bytes src/system-recovery/system-recovery.cfg.m4.in | 285 +++++++ src/system-recovery/system-recovery.h | 46 ++ 64 files changed, 6580 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile.am create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 packaging/system-recovery.manifest create mode 100644 packaging/system-recovery.spec create mode 100644 src/fonts/font-10x18.h create mode 100644 src/librui/common.h create mode 100644 src/librui/fbdev.h create mode 100644 src/librui/graphics-fbdev-common.c create mode 100644 src/librui/graphics-fbdev.c create mode 100644 src/librui/graphics-tdm.c create mode 100644 src/librui/graphics.c create mode 100644 src/librui/graphics.h create mode 100644 src/librui/input-events.c create mode 100644 src/librui/input-events.h create mode 100644 src/librui/resources.c create mode 100644 src/librui/rui-description.c create mode 100644 src/librui/rui-description.h create mode 100644 src/librui/rui-image.h create mode 100644 src/librui/rui-images.c create mode 100644 src/librui/rui-menu.c create mode 100644 src/librui/rui-menu.h create mode 100644 src/librui/rui-progress-bar.c create mode 100644 src/librui/rui-progress-bar.h create mode 100644 src/librui/rui-ruler.h create mode 100644 src/librui/rui-rulers.c create mode 100644 src/librui/rui.c create mode 100644 src/librui/rui.h create mode 100755 src/librui/tdm-if.c create mode 100755 src/librui/tdm-if.h create mode 100644 src/shared/log.c create mode 100644 src/shared/log.h create mode 100644 src/system-recovery/.gitignore create mode 100644 src/system-recovery/50-system-recovery-sprd.list create mode 100644 src/system-recovery/50-system-recovery.list.m4.in create mode 100644 src/system-recovery/process-util.c create mode 100644 src/system-recovery/process-util.h create mode 100755 src/system-recovery/recovery-action-set.in create mode 100644 src/system-recovery/recovery-headless.c create mode 100644 src/system-recovery/recovery-init.in create mode 100644 src/system-recovery/recovery-main.c create mode 100644 src/system-recovery/recovery-rui-skin.h create mode 100644 src/system-recovery/recovery-rui.c create mode 100644 src/system-recovery/res-util/README.txt create mode 100755 src/system-recovery/res-util/interlace-frames.py create mode 100755 src/system-recovery/res-util/make-anim.sh create mode 100755 src/system-recovery/res-util/make-menu-title.sh create mode 100644 src/system-recovery/res-util/tizen-anim1src.png create mode 100644 src/system-recovery/res-util/tizen-anim2src.png create mode 100644 src/system-recovery/res-util/tizen-anim3src.png create mode 100644 src/system-recovery/res-util/tizen-anim4src.png create mode 100644 src/system-recovery/res-util/tizen-anim5src.png create mode 100644 src/system-recovery/res/images/12x22.png create mode 100644 src/system-recovery/res/images/18x32.png create mode 100644 src/system-recovery/res/images/font.png create mode 100644 src/system-recovery/res/images/menu-title-480x800.png create mode 100644 src/system-recovery/res/images/menu-title-720x1280.png create mode 100644 src/system-recovery/res/images/menu-title.png create mode 100644 src/system-recovery/res/images/tizen-anim.png create mode 100644 src/system-recovery/res/images/warning.png create mode 100644 src/system-recovery/system-recovery.cfg.m4.in create mode 100644 src/system-recovery/system-recovery.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5cf9594 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +*.cache +*.swp + +/build-aux +/m4 +/build_* + +aclocal.m4 +config.h +config.h.in +config.log +config.status +configure +debugfiles.list +debuglinks.list +debugsources.list +documentation.list +initrd-recovery.manifest +Makefile.in diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9fe66f6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,203 @@ +Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..20f3675 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,195 @@ +ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} + +SUBDIRS = . + +initrd_recovery_libexecdir=$(INITRD_RECOVERY_LIBEXEC_DIR) +initrd_recovery_datadir=$(INITRD_RECOVERY_DATA_DIR) +initrd_recovery_install_dropindir=$(INITRD_RECOVERY_INSTALL_DROPIN_DIR) + +DEFAULT_CFLAGS = \ + $(LIBSYSTEM_CFLAGS) \ + $(OUR_CFLAGS) + +DEFAULT_LDFLAGS = \ + $(LIBSYSTEM_LDFLAGS) \ + $(OUR_LDFLAGS) + +DEFAULT_LIBS = \ + $(LIBSYSTEM_LIBS) \ + libinitrd-recovery-shared.la + +AM_CPPFLAGS = \ + -include $(top_builddir)/config.h \ + -I $(top_srcdir)/src \ + -I $(top_srcdir)/src/shared \ + $(DEFAULT_CFLAGS) + +AM_CFLAGS = $(DEFAULT_CFLAGS) +AM_LDFLAGS = $(DEFAULT_LDFLAGS) +AM_LIBS = $(DEFAULT_LIBS) + +CLEANFILES = +EXTRA_DIST = + +lib_LTLIBRARIES = +noinst_LTLIBRARIES = + +bin_PROGRAMS = + +initrd_recovery_install_dropin_DATA = + +# ------------------------------------------------------------------------------ +noinst_LTLIBRARIES += \ + libinitrd-recovery-shared.la + +libinitrd_recovery_shared_la_SOURCES = \ + src/shared/log.c \ + src/shared/log.h + +libinitrd_recovery_shared_la_CFLAGS = \ + $(AM_CFLAGS) + +libinitrd_recovery_shared_la_LIBADD = \ + $(LIBSYSTEM_LIBS) + +# ------------------------------------------------------------------------------ +if RECOVERY_GUI +noinst_LTLIBRARIES += \ + librui.la + +librui_la_SOURCES = \ + src/librui/graphics.c \ + src/librui/input-events.c \ + src/librui/resources.c \ + src/librui/rui-description.c \ + src/librui/rui-images.c \ + src/librui/rui-menu.c \ + src/librui/rui-progress-bar.c \ + src/librui/rui-rulers.c \ + src/librui/rui.c + +if HAVE_TDM +librui_la_SOURCES += \ + src/librui/graphics-tdm.c \ + src/librui/tdm-if.c +else +librui_la_SOURCES += \ + src/librui/graphics-fbdev-common.c \ + src/librui/graphics-fbdev.c +endif + +librui_la_CFLAGS = \ + $(LIBPNG_CFLAGS) \ + $(LIBTDM_CFLAGS) \ + $(VCONF_INTERNAL_KEYS) \ + $(AM_CFLAGS) \ + -I $(top_srcdir)/src/librui \ + -I $(top_srcdir)/src/fonts + +librui_la_LIBADD = \ + $(LIBPNG_LIBS) \ + $(LIBTDM_LIBS) \ + $(AM_LIBS) +endif + +# ------------------------------------------------------------------------------ +system_recovery_datadir = $(SYSTEM_RECOVERY_DATA_DIR) +system_recovery_imagedir = $(SYSTEM_RECOVERY_IMAGE_DIR) +system_recovery_libexecdir = $(SYSTEM_RECOVERY_LIBEXEC_DIR) + +system_recovery_SOURCES = \ + src/system-recovery/recovery-main.c + +system_recovery_CFLAGS = \ + $(AM_CFLAGS) \ + -DSYSTEM_RECOVERY_CONFIG_FILE=\""${system_recovery_datadir}/system-recovery.cfg"\" \ + $(LIBCONFIG_CFLAGS) \ + -I $(top_srcdir)/src/system-recovery + +system_recovery_LDADD = \ + $(AM_LIBS) \ + $(LIBCONFIG_LIBS) + +if RECOVERY_GUI +system_recovery_SOURCES += \ + src/system-recovery/process-util.c \ + src/system-recovery/recovery-rui.c + +system_recovery_CFLAGS += \ + -I $(librui_la_CFLAGS) \ + -I $(top_srcdir)/src/librui + +system_recovery_LDADD += \ + librui.la + +system_recovery_image_DATA = \ + src/system-recovery/res/images/font.png \ + src/system-recovery/res/images/menu-title.png \ + src/system-recovery/res/images/tizen-anim.png \ + src/system-recovery/res/images/warning.png + +initrd_recovery_install_dropin_DATA += \ + src/system-recovery/50-system-recovery-sprd.list + +else + +system_recovery_SOURCES += \ + src/system-recovery/recovery-headless.c +endif + +system_recovery_libexec_PROGRAMS = \ + system-recovery + +system_recovery_data_DATA = \ + src/system-recovery/system-recovery.cfg + +system_recovery_libexec_SCRIPTS = \ + src/system-recovery/recovery-init + +sbin_SCRIPTS = \ + src/system-recovery/recovery-action-set + +initrd_recovery_install_dropin_DATA += \ + src/system-recovery/50-system-recovery.list + +EXTRA_DIST += \ + src/system-recovery/50-system-recovery.list.m4 \ + src/system-recovery/recovery-init.in \ + src/system-recovery/recovery-action-set.in \ + src/system-recovery/system-recovery.cfg.m4.in + +CLEANFILES += \ + src/system-recovery/50-system-recovery.list \ + src/system-recovery/recovery-init \ + src/system-recovery/system-recovery.cfg.m4 \ + src/system-recovery/recovery-action-set + +# ------------------------------------------------------------------------------ +substitutions = \ + '|PACKAGE_VERSION=$(PACKAGE_VERSION)|' \ + '|PACKAGE_NAME=$(PACKAGE_NAME)|' \ + '|PACKAGE_URL=$(PACKAGE_URL)|' \ + '|includedir=$(includedir)|' \ + '|VERSION=$(VERSION)|' \ + '|MKDIR_P=$(MKDIR_P)|' \ + '|INITRD_RECOVERY_INSTALL_DROPIN_DIR=$(INITRD_RECOVERY_INSTALL_DROPIN_DIR)|' \ + '|INITRD_RECOVERY_LIBEXEC_DIR=$(INITRD_RECOVERY_LIBEXEC_DIR)|' \ + '|SYSTEM_RECOVERY_IMAGE_DIR=$(SYSTEM_RECOVERY_IMAGE_DIR)|' \ + '|SYSTEM_RECOVERY_LIBEXEC_DIR=$(SYSTEM_RECOVERY_LIBEXEC_DIR)|' \ + '|SYSTEM_RECOVERY_DATA_DIR=$(SYSTEM_RECOVERY_DATA_DIR)|' \ + '|SYSTEM_RECOVERY_ACTION_FILE=$(SYSTEM_RECOVERY_ACTION_FILE)|' \ + '|RECOVERY_GUI=$(RECOVERY_GUI)|' + +SED_PROCESS = \ + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ + $(SED) $(subst '|,-e 's|@,$(subst =,\@|,$(subst |',|g',$(substitutions)))) \ + < $< > $@ + +src/%: src/%.in Makefile + $(SED_PROCESS) + +src/%: src/%.m4 + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_M4)$(M4) -P $(M4_DEFINES) < $< > $@ + +install-exec-hook: $(INSTALL_EXEC_HOOKS) diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..968bc8e --- /dev/null +++ b/autogen.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +set -e + +if [ -f .git/hooks/pre-commit.sample ] && [ ! -f .git/hooks/pre-commit ]; then + # This part is allowed to fail + cp -p .git/hooks/pre-commit.sample .git/hooks/pre-commit && \ + chmod +x .git/hooks/pre-commit && \ + echo "Activated pre-commit hook." || : +fi + +# README and INSTALL are required by automake, but may be deleted by +# clean up rules. to get automake to work, simply touch these here, +# they will be regenerated from their corresponding *.in files by +# ./configure anyway. +touch README INSTALL + +# Make sure m4 directory exist +mkdir -p m4 + +autoreconf --force --install --verbose || exit $? diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..23f1b2c --- /dev/null +++ b/configure.ac @@ -0,0 +1,153 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.69]) +AC_INIT([initrd-recovery], [2.1.1], [walyong.cho@samsung.com]) + +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_AUX_DIR([build-aux]) + +AC_USE_SYSTEM_EXTENSIONS +AC_SYS_LARGEFILE +AC_PREFIX_DEFAULT([/usr]) +AM_INIT_AUTOMAKE([foreign subdir-objects]) + +LT_PREREQ(2.2) +LT_INIT([disable-static]) + +# Checks for programs. +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +AC_PROG_MKDIR_P +AC_PATH_PROG([M4], [m4]) + +# Checks for libraries. + +# Checks for header files. +AC_CHECK_HEADERS([fcntl.h limits.h mntent.h stdint.h stdlib.h string.h sys/ioctl.h sys/mount.h unistd.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_CHECK_HEADER_STDBOOL +AC_C_INLINE +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_TYPE_UINT32_T + +# Checks for library functions. +AC_FUNC_FORK +AC_FUNC_GETMNTENT +AC_FUNC_MALLOC +AC_FUNC_MMAP +AC_CHECK_FUNCS([dup2 getmntent memset munmap strcasecmp strchr strdup strerror strrchr strstr]) + +# ------------------------------------------------------------------------------ +our_cflags=" \ + -g -O2 \ + -Werror \ + -fpie" + +our_ldflags=" \ + -Wl,--as-needed \ + -Wl,--no-undefined \ + -Wl,--gc-sections \ + -Wl,-z,relro \ + -Wl,-z,now \ + -pie" + +AC_SUBST([OUR_CFLAGS], "$our_cflags") +AC_SUBST([OUR_LDFLAGS], "$our_ldflags") + +M4_DEFINES= +# ------------------------------------------------------------------------------ +AC_ARG_WITH([tdm], + AS_HELP_STRING([--without-tdm], [disable TDM/TBM graphical backend (default: test)])) +PKG_CHECK_MODULES([LIBCONFIG], + [libconfig >= 1.6], + have_libconfig=yes, + have_libconfig=no) + +if test "x$have_libconfig" = "xno"; then + AC_MSG_ERROR([libconfig not found]) +fi + +AC_ARG_ENABLE([recovery-gui], + AS_HELP_STRING([--disable-recovery-gui], [disable recovery gui mode]), + [case "${enableval}" in + yes) enable_recovery_gui=yes ;; + no) enable_recovery_gui=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-recovery-gui) ;; + esac], + enable_recovery_gui=yes) + +have_libtdm=no +if test "x$enable_recovery_gui" == "xyes"; then + M4_DEFINES="$M4_DEFINES -DRECOVERY_GUI" + AC_SUBST([OUR_CFLAGS], "$OUR_CFLAGS -DRECOVERY_GUI") + PKG_CHECK_MODULES(LIBPNG, [libpng]) + if test "x$with_tdm" != "xno"; then + PKG_CHECK_MODULES(LIBTDM, + [libtdm >= 1.7.0], + [AC_DEFINE(HAVE_TDM, 1, [Define if using TDM/TBM graphical backend]) + have_libtdm=yes]) + if test "x$with_tdm" = "xyes" -a "x$have_libtdm" = "xno"; then + AC_MSG_ERROR([--with-tdm has been specified but libtdm is not available.]) + fi + fi + RECOVERY_GUI="GUI" +else + RECOVERY_GUI="NO" +fi + +AC_SUBST([RECOVERY_GUI]) +AM_CONDITIONAL([RECOVERY_GUI], [test "x$enable_recovery_gui" != "xno"]) +AM_CONDITIONAL([HAVE_TDM], [test "x$have_libtdm" = "xyes"]) + +SYSTEM_RECOVERY_DATA_DIR="${datadir}/system-recovery" +AC_DEFINE_UNQUOTED([SYSTEM_RECOVERY_DATA_DIR], ["$SYSTEM_RECOVERY_DATA_DIR"], "Directory where data for system-recovery UI are stored") +AC_SUBST([SYSTEM_RECOVERY_DATA_DIR]) + +SYSTEM_RECOVERY_IMAGE_DIR="${datadir}/system-recovery/res/images" +AC_DEFINE_UNQUOTED([SYSTEM_RECOVERY_IMAGE_DIR], ["$SYSTEM_RECOVERY_IMAGE_DIR"], "Directory where images for system-recovery UI are stored") +AC_SUBST([SYSTEM_RECOVERY_IMAGE_DIR]) + +RUI_IMAGES_DIR="${SYSTEM_RECOVERY_IMAGE_DIR}" +AC_DEFINE_UNQUOTED([RUI_IMAGES_DIR], ["$RUI_IMAGES_DIR"], "Directory where images for system-recovery UI are stored") + +SYSTEM_RECOVERY_LIBEXEC_DIR="${libexecdir}/system-recovery" +AC_DEFINE_UNQUOTED([SYSTEM_RECOVERY_LIBEXEC_DIR], ["$SYSTEM_RECOVERY_LIBEXEC_DIR"], "Directory where sub-programmes for system-recovery UI are stored") +AC_SUBST([SYSTEM_RECOVERY_LIBEXEC_DIR]) + +SYSTEM_RECOVERY_ACTION_FILE="/opt/.recovery.action" +AC_DEFINE_UNQUOTED([SYSTEM_RECOVERY_ACTION_FILE], ["$SYSTEM_RECOVERY_ACTION_FILE"], "File where recovery action is stored") +AC_SUBST([SYSTEM_RECOVERY_ACTION_FILE]) + +INITRD_RECOVERY_DATA_DIR="${datadir}/initrd-recovery" +AC_DEFINE_UNQUOTED([INITRD_RECOVERY_DATA_DIR], ["$INITRD_RECOVERY_DATA_DIR"], "Directory where data for recovery initrd are stored") +AC_SUBST([INITRD_RECOVERY_DATA_DIR]) + +INITRD_RECOVERY_INSTALL_DROPIN_DIR="${INITRD_RECOVERY_DATA_DIR}/initrd.list.d" +AC_DEFINE_UNQUOTED([INITRD_RECOVERY_INSTALL_DROPIN_DIR], ["$INITRD_RECOVERY_INSTALL_DROPIN_DIR"], "Directory where configuration drop-in files for recovery initrd are stored") +AC_SUBST([INITRD_RECOVERY_INSTALL_DROPIN_DIR]) + +INITRD_RECOVERY_LIBEXEC_DIR="${libexecdir}/initrd-recovery" +AC_DEFINE_UNQUOTED([INITRD_RECOVERY_LIBEXEC_DIR], ["$INITRD_RECOVERY_LIBEXEC_DIR"], "Directory where sub-progremmes for recovery initrd are stored") +AC_SUBST([INITRD_RECOVERY_LIBEXEC_DIR]) + +# ------------------------------------------------------------------------------ +AC_SUBST(M4_DEFINES) + +# ------------------------------------------------------------------------------ +AC_CONFIG_FILES([Makefile]) + +AC_OUTPUT +AC_MSG_RESULT([ + $PACKAGE_NAME $VERSION + ===================== + prefix: ${prefix} + recovery gui mode: ${enable_recovery_gui} + with TDM: ${have_libtdm} + OUR CFLAGS: ${OUR_CFLAGS} ${CFLAGS} +]) diff --git a/packaging/system-recovery.manifest b/packaging/system-recovery.manifest new file mode 100644 index 0000000..2a0cec5 --- /dev/null +++ b/packaging/system-recovery.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/system-recovery.spec b/packaging/system-recovery.spec new file mode 100644 index 0000000..4742d1e --- /dev/null +++ b/packaging/system-recovery.spec @@ -0,0 +1,116 @@ +Name: system-recovery +Summary: System recovery +Version: 0.2.0 +Release: 0 +Group: System/Utilities +License: Apache-2.0 +ExclusiveArch: %{arm} + +Source0: %{name}-%{version}.tar.gz +Source1001: system-recovery.manifest + +BuildRequires: autoconf +BuildRequires: automake +BuildRequires: libtool +BuildRequires: pkgconfig(libconfig) +BuildRequires: pkgconfig(libtdm) +BuildRequires: pkgconfig(libpng) + +Requires: initrd-recovery +Requires: system-recovery-compat = %{version}-%{release} +Recommends: system-recovery-non_gui = %{version}-%{release} + +%description +A simple initrd menu for system recovery. + +# non_gui profile: common, wearable +%package non_gui +Summary: system-recovery without gui +Provides: system-recovery-compat = %{version}-%{release} +Conflicts: system-recovery-gui +%description non_gui +system-recovery package without gui + +# gui profile: mobile +%package gui +Summary: system-recovery with gui +Provides: system-recovery-compat = %{version}-%{release} +Conflicts: system-recovery-non_gui +%description gui +system-recovery package with gui + +# Configuration for mkinitrd-recovery, one package per target +%package sprd +Summary: mkinitrd-recovery configuration file for spreadtrum platform +Group: System/Utilities +License: Apache-2.0 +Requires: system-recovery-gui +%description sprd +mkinitrd-recovery configuration file for spreadtrum platform + +%prep +%setup -q + +%build +cp %{SOURCE1001} . +%autogen + +# common, wearalbe: without gui +mkdir -p build_non_gui +ln -nfs ../%{_configure} build_non_gui +pushd build_non_gui +%configure \ + --disable-recovery-gui \ + --srcdir=../ +make %{?_smp_mflags} +popd + +# mobile: with gui +mkdir -p build_gui +ln -nfs ../%{_configure} build_gui +pushd build_gui +%configure \ + --srcdir=../ +make %{?_smp_mflags} +popd + +%install +# common, wearable +pushd build_non_gui +%make_install +mv %{buildroot}%{_libexecdir}/system-recovery/system-recovery \ + %{buildroot}%{_libexecdir}/system-recovery/system-recovery.non_gui \ + +mv %{buildroot}%{_datadir}/initrd-recovery/initrd.list.d/50-system-recovery.list \ + %{buildroot}%{_datadir}/initrd-recovery/initrd.list.d/50-system-recovery-non_gui.list +popd + +# mobile +pushd build_gui +%make_install +mv %{buildroot}%{_libexecdir}/system-recovery/system-recovery \ + %{buildroot}%{_libexecdir}/system-recovery/system-recovery.gui \ + +mv %{buildroot}%{_datadir}/initrd-recovery/initrd.list.d/50-system-recovery.list \ + %{buildroot}%{_datadir}/initrd-recovery/initrd.list.d/50-system-recovery-gui.list +popd + +%files +%defattr(-,root,root,-) +%manifest system-recovery.manifest +%license LICENSE +%{_datadir}/system-recovery/system-recovery.cfg +%{_libexecdir}/system-recovery/recovery-init +%{_sbindir}/recovery-action-set + +%files non_gui +%{_datadir}/initrd-recovery/initrd.list.d/50-system-recovery-non_gui.list +%{_libexecdir}/system-recovery/system-recovery.non_gui + +%files gui +%{_datadir}/initrd-recovery/initrd.list.d/50-system-recovery-gui.list +%{_datadir}/system-recovery/res/images/*.png +%{_libexecdir}/system-recovery/system-recovery.gui + +%files sprd +%{_datadir}/initrd-recovery/initrd.list.d/50-system-recovery-sprd.list diff --git a/src/fonts/font-10x18.h b/src/fonts/font-10x18.h new file mode 100644 index 0000000..1b3d86f --- /dev/null +++ b/src/fonts/font-10x18.h @@ -0,0 +1,216 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +struct { + unsigned width; + unsigned height; + unsigned cwidth; + unsigned cheight; + unsigned char rundata[2973]; +} font = { + .width = 960, + .height = 18, + .cwidth = 10, + .cheight = 18, + .rundata = { + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x55, 0x82, 0x06, 0x82, 0x02, 0x82, 0x10, 0x82, + 0x11, 0x83, 0x08, 0x82, 0x0a, 0x82, 0x04, 0x82, 0x46, 0x82, 0x08, 0x82, 0x07, 0x84, 0x06, + 0x84, 0x0a, 0x81, 0x03, 0x88, 0x04, 0x84, 0x04, 0x88, 0x04, 0x84, 0x06, 0x84, 0x1e, 0x81, + 0x0e, 0x81, 0x0a, 0x84, 0x06, 0x84, 0x07, 0x82, 0x05, 0x85, 0x07, 0x84, 0x04, 0x86, 0x04, + 0x88, 0x02, 0x88, 0x04, 0x84, 0x04, 0x82, 0x04, 0x82, 0x02, 0x88, 0x05, 0x86, 0x01, 0x82, + 0x04, 0x82, 0x02, 0x82, 0x08, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x04, 0x84, 0x04, + 0x86, 0x06, 0x84, 0x04, 0x86, 0x06, 0x84, 0x04, 0x88, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, + 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, + 0x88, 0x03, 0x86, 0x0e, 0x86, 0x06, 0x82, 0x11, 0x82, 0x10, 0x82, 0x18, 0x82, 0x0f, 0x84, + 0x0d, 0x82, 0x1c, 0x82, 0x09, 0x84, 0x7f, 0x16, 0x84, 0x05, 0x82, 0x05, 0x84, 0x07, 0x83, + 0x02, 0x82, 0x19, 0x82, 0x06, 0x82, 0x02, 0x82, 0x06, 0x82, 0x01, 0x82, 0x03, 0x86, 0x04, + 0x83, 0x02, 0x82, 0x03, 0x82, 0x01, 0x82, 0x07, 0x82, 0x09, 0x82, 0x06, 0x82, 0x3e, 0x82, + 0x04, 0x84, 0x06, 0x83, 0x06, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x08, 0x82, 0x03, + 0x82, 0x09, 0x82, 0x02, 0x82, 0x09, 0x82, 0x03, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, + 0x1c, 0x82, 0x0e, 0x82, 0x08, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x05, 0x84, 0x04, + 0x82, 0x02, 0x82, 0x05, 0x82, 0x02, 0x82, 0x03, 0x82, 0x03, 0x82, 0x03, 0x82, 0x08, 0x82, + 0x09, 0x82, 0x02, 0x82, 0x03, 0x82, 0x04, 0x82, 0x05, 0x82, 0x0a, 0x82, 0x03, 0x82, 0x04, + 0x82, 0x02, 0x82, 0x08, 0x82, 0x04, 0x82, 0x02, 0x83, 0x03, 0x82, 0x03, 0x82, 0x02, 0x82, + 0x03, 0x82, 0x03, 0x82, 0x04, 0x82, 0x02, 0x82, 0x03, 0x82, 0x03, 0x82, 0x04, 0x82, 0x02, + 0x82, 0x06, 0x82, 0x05, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, + 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x08, 0x82, 0x03, 0x82, 0x08, 0x82, 0x0c, + 0x82, 0x05, 0x84, 0x11, 0x82, 0x0f, 0x82, 0x18, 0x82, 0x0e, 0x82, 0x02, 0x82, 0x0c, 0x82, + 0x1c, 0x82, 0x0b, 0x82, 0x7f, 0x15, 0x82, 0x08, 0x82, 0x08, 0x82, 0x05, 0x82, 0x01, 0x82, + 0x01, 0x82, 0x19, 0x82, 0x06, 0x82, 0x02, 0x82, 0x06, 0x82, 0x01, 0x82, 0x02, 0x82, 0x01, + 0x82, 0x01, 0x82, 0x02, 0x82, 0x01, 0x82, 0x01, 0x82, 0x03, 0x82, 0x01, 0x82, 0x07, 0x82, + 0x08, 0x82, 0x08, 0x82, 0x3d, 0x82, 0x03, 0x82, 0x02, 0x82, 0x04, 0x84, 0x05, 0x82, 0x04, + 0x82, 0x02, 0x82, 0x04, 0x82, 0x06, 0x83, 0x03, 0x82, 0x08, 0x82, 0x04, 0x81, 0x09, 0x82, + 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x1a, 0x82, 0x10, 0x82, 0x06, 0x82, 0x04, + 0x82, 0x02, 0x82, 0x04, 0x82, 0x03, 0x82, 0x02, 0x82, 0x03, 0x82, 0x03, 0x82, 0x03, 0x82, + 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x08, 0x82, 0x08, 0x82, 0x04, 0x82, 0x02, + 0x82, 0x04, 0x82, 0x05, 0x82, 0x0a, 0x82, 0x03, 0x82, 0x03, 0x82, 0x03, 0x82, 0x08, 0x83, + 0x02, 0x83, 0x02, 0x83, 0x03, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, + 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x05, 0x82, 0x05, 0x82, + 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x03, 0x82, 0x02, 0x82, 0x04, + 0x82, 0x02, 0x82, 0x09, 0x82, 0x03, 0x82, 0x08, 0x82, 0x0c, 0x82, 0x04, 0x82, 0x02, 0x82, + 0x11, 0x82, 0x0e, 0x82, 0x18, 0x82, 0x0e, 0x82, 0x02, 0x82, 0x0c, 0x82, 0x0b, 0x82, 0x0b, + 0x82, 0x02, 0x82, 0x0b, 0x82, 0x4d, 0x82, 0x45, 0x82, 0x08, 0x82, 0x08, 0x82, 0x05, 0x82, + 0x02, 0x83, 0x1a, 0x82, 0x07, 0x81, 0x02, 0x81, 0x07, 0x82, 0x01, 0x82, 0x02, 0x82, 0x01, + 0x82, 0x05, 0x82, 0x01, 0x84, 0x04, 0x82, 0x01, 0x82, 0x07, 0x82, 0x08, 0x82, 0x08, 0x82, + 0x06, 0x82, 0x02, 0x82, 0x06, 0x82, 0x28, 0x82, 0x04, 0x82, 0x02, 0x82, 0x03, 0x82, 0x01, + 0x82, 0x05, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x05, 0x84, 0x03, 0x82, 0x08, 0x82, + 0x0d, 0x82, 0x03, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x19, 0x82, 0x12, 0x82, 0x05, + 0x82, 0x04, 0x82, 0x02, 0x82, 0x02, 0x84, 0x03, 0x82, 0x02, 0x82, 0x03, 0x82, 0x03, 0x82, + 0x03, 0x82, 0x08, 0x82, 0x04, 0x82, 0x02, 0x82, 0x08, 0x82, 0x08, 0x82, 0x08, 0x82, 0x04, + 0x82, 0x05, 0x82, 0x0a, 0x82, 0x03, 0x82, 0x03, 0x82, 0x03, 0x82, 0x08, 0x83, 0x02, 0x83, + 0x02, 0x84, 0x02, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, + 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x0b, 0x82, 0x05, 0x82, 0x04, 0x82, 0x02, 0x82, + 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x03, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x08, + 0x82, 0x04, 0x82, 0x09, 0x82, 0x0b, 0x82, 0x03, 0x82, 0x04, 0x82, 0x20, 0x82, 0x18, 0x82, + 0x0e, 0x82, 0x10, 0x82, 0x0b, 0x82, 0x0b, 0x82, 0x02, 0x82, 0x0b, 0x82, 0x4d, 0x82, 0x45, + 0x82, 0x08, 0x82, 0x08, 0x82, 0x26, 0x82, 0x10, 0x88, 0x01, 0x82, 0x01, 0x82, 0x06, 0x83, + 0x01, 0x82, 0x04, 0x84, 0x08, 0x81, 0x08, 0x82, 0x0a, 0x82, 0x05, 0x82, 0x02, 0x82, 0x06, + 0x82, 0x28, 0x82, 0x03, 0x82, 0x04, 0x82, 0x05, 0x82, 0x0b, 0x82, 0x08, 0x82, 0x04, 0x82, + 0x01, 0x82, 0x03, 0x82, 0x08, 0x82, 0x0d, 0x82, 0x03, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, + 0x82, 0x18, 0x82, 0x06, 0x88, 0x06, 0x82, 0x04, 0x82, 0x04, 0x82, 0x02, 0x82, 0x01, 0x85, + 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x03, 0x82, 0x03, 0x82, 0x08, 0x82, 0x04, 0x82, 0x02, + 0x82, 0x08, 0x82, 0x08, 0x82, 0x08, 0x82, 0x04, 0x82, 0x05, 0x82, 0x0a, 0x82, 0x03, 0x82, + 0x02, 0x82, 0x04, 0x82, 0x08, 0x88, 0x02, 0x84, 0x02, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, + 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x0b, 0x82, + 0x05, 0x82, 0x04, 0x82, 0x03, 0x82, 0x02, 0x82, 0x03, 0x82, 0x04, 0x82, 0x04, 0x84, 0x06, + 0x84, 0x08, 0x82, 0x05, 0x82, 0x09, 0x82, 0x0b, 0x82, 0x2b, 0x82, 0x18, 0x82, 0x0e, 0x82, + 0x10, 0x82, 0x1c, 0x82, 0x0b, 0x82, 0x4d, 0x82, 0x45, 0x82, 0x08, 0x82, 0x08, 0x82, 0x26, + 0x82, 0x11, 0x82, 0x01, 0x82, 0x03, 0x82, 0x01, 0x82, 0x09, 0x82, 0x06, 0x82, 0x12, 0x82, + 0x0a, 0x82, 0x06, 0x84, 0x07, 0x82, 0x27, 0x82, 0x04, 0x82, 0x04, 0x82, 0x05, 0x82, 0x0b, + 0x82, 0x07, 0x82, 0x04, 0x82, 0x02, 0x82, 0x03, 0x82, 0x01, 0x83, 0x04, 0x82, 0x01, 0x83, + 0x08, 0x82, 0x05, 0x82, 0x02, 0x82, 0x03, 0x82, 0x04, 0x82, 0x05, 0x83, 0x07, 0x83, 0x05, + 0x82, 0x16, 0x82, 0x08, 0x82, 0x03, 0x82, 0x01, 0x82, 0x01, 0x82, 0x02, 0x82, 0x04, 0x82, + 0x02, 0x82, 0x02, 0x82, 0x04, 0x82, 0x08, 0x82, 0x04, 0x82, 0x02, 0x82, 0x08, 0x82, 0x08, + 0x82, 0x08, 0x82, 0x04, 0x82, 0x05, 0x82, 0x0a, 0x82, 0x03, 0x82, 0x02, 0x82, 0x04, 0x82, + 0x08, 0x82, 0x01, 0x82, 0x01, 0x82, 0x02, 0x82, 0x01, 0x82, 0x01, 0x82, 0x02, 0x82, 0x04, + 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x03, 0x82, + 0x0a, 0x82, 0x05, 0x82, 0x04, 0x82, 0x03, 0x82, 0x02, 0x82, 0x03, 0x82, 0x01, 0x82, 0x01, + 0x82, 0x04, 0x84, 0x06, 0x84, 0x08, 0x82, 0x05, 0x82, 0x0a, 0x82, 0x0a, 0x82, 0x23, 0x85, + 0x03, 0x82, 0x01, 0x83, 0x06, 0x85, 0x05, 0x83, 0x01, 0x82, 0x04, 0x84, 0x04, 0x86, 0x05, + 0x85, 0x01, 0x81, 0x02, 0x82, 0x01, 0x83, 0x05, 0x84, 0x09, 0x84, 0x02, 0x82, 0x03, 0x82, + 0x06, 0x82, 0x05, 0x81, 0x01, 0x82, 0x01, 0x82, 0x03, 0x82, 0x01, 0x83, 0x06, 0x84, 0x04, + 0x82, 0x01, 0x83, 0x06, 0x83, 0x01, 0x82, 0x02, 0x82, 0x01, 0x84, 0x04, 0x86, 0x03, 0x86, + 0x04, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, + 0x82, 0x02, 0x82, 0x04, 0x82, 0x03, 0x87, 0x05, 0x82, 0x08, 0x82, 0x08, 0x82, 0x26, 0x82, + 0x11, 0x82, 0x01, 0x82, 0x04, 0x86, 0x07, 0x82, 0x05, 0x83, 0x12, 0x82, 0x0a, 0x82, 0x04, + 0x88, 0x02, 0x88, 0x0c, 0x88, 0x10, 0x82, 0x04, 0x82, 0x04, 0x82, 0x05, 0x82, 0x0a, 0x82, + 0x06, 0x83, 0x04, 0x82, 0x03, 0x82, 0x03, 0x83, 0x02, 0x82, 0x03, 0x83, 0x02, 0x82, 0x07, + 0x82, 0x06, 0x84, 0x05, 0x82, 0x02, 0x83, 0x05, 0x83, 0x07, 0x83, 0x04, 0x82, 0x18, 0x82, + 0x06, 0x82, 0x04, 0x82, 0x01, 0x82, 0x01, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x86, 0x04, + 0x82, 0x08, 0x82, 0x04, 0x82, 0x02, 0x86, 0x04, 0x86, 0x04, 0x82, 0x02, 0x84, 0x02, 0x88, + 0x05, 0x82, 0x0a, 0x82, 0x03, 0x85, 0x05, 0x82, 0x08, 0x82, 0x01, 0x82, 0x01, 0x82, 0x02, + 0x82, 0x01, 0x82, 0x01, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x03, 0x82, 0x03, 0x82, + 0x04, 0x82, 0x02, 0x82, 0x03, 0x82, 0x05, 0x84, 0x07, 0x82, 0x05, 0x82, 0x04, 0x82, 0x03, + 0x82, 0x02, 0x82, 0x03, 0x82, 0x01, 0x82, 0x01, 0x82, 0x05, 0x82, 0x08, 0x82, 0x08, 0x82, + 0x06, 0x82, 0x0a, 0x82, 0x0a, 0x82, 0x22, 0x82, 0x03, 0x82, 0x02, 0x83, 0x02, 0x82, 0x04, + 0x82, 0x03, 0x82, 0x03, 0x82, 0x02, 0x83, 0x03, 0x82, 0x02, 0x82, 0x05, 0x82, 0x06, 0x82, + 0x03, 0x83, 0x02, 0x83, 0x02, 0x82, 0x06, 0x82, 0x0b, 0x82, 0x02, 0x82, 0x02, 0x82, 0x07, + 0x82, 0x05, 0x88, 0x02, 0x83, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x03, 0x83, 0x02, 0x82, + 0x04, 0x82, 0x02, 0x83, 0x03, 0x83, 0x02, 0x82, 0x02, 0x82, 0x04, 0x82, 0x04, 0x82, 0x06, + 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x03, 0x82, 0x02, 0x82, + 0x03, 0x82, 0x04, 0x82, 0x08, 0x82, 0x02, 0x84, 0x09, 0x82, 0x09, 0x84, 0x23, 0x82, 0x11, + 0x82, 0x01, 0x82, 0x06, 0x82, 0x01, 0x82, 0x05, 0x82, 0x05, 0x82, 0x01, 0x82, 0x11, 0x82, + 0x0a, 0x82, 0x06, 0x84, 0x07, 0x82, 0x26, 0x82, 0x05, 0x82, 0x04, 0x82, 0x05, 0x82, 0x08, + 0x83, 0x09, 0x82, 0x03, 0x82, 0x03, 0x82, 0x09, 0x82, 0x02, 0x82, 0x04, 0x82, 0x05, 0x82, + 0x06, 0x82, 0x02, 0x82, 0x05, 0x83, 0x01, 0x82, 0x17, 0x82, 0x16, 0x82, 0x06, 0x82, 0x05, + 0x82, 0x01, 0x82, 0x01, 0x82, 0x02, 0x88, 0x02, 0x82, 0x03, 0x82, 0x03, 0x82, 0x08, 0x82, + 0x04, 0x82, 0x02, 0x82, 0x08, 0x82, 0x08, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x05, + 0x82, 0x0a, 0x82, 0x03, 0x82, 0x02, 0x82, 0x04, 0x82, 0x08, 0x82, 0x01, 0x82, 0x01, 0x82, + 0x02, 0x82, 0x02, 0x84, 0x02, 0x82, 0x04, 0x82, 0x02, 0x86, 0x04, 0x82, 0x04, 0x82, 0x02, + 0x86, 0x09, 0x82, 0x06, 0x82, 0x05, 0x82, 0x04, 0x82, 0x04, 0x84, 0x04, 0x82, 0x01, 0x82, + 0x01, 0x82, 0x04, 0x84, 0x07, 0x82, 0x07, 0x82, 0x07, 0x82, 0x0b, 0x82, 0x09, 0x82, 0x27, + 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x08, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, + 0x04, 0x82, 0x06, 0x82, 0x03, 0x82, 0x03, 0x82, 0x04, 0x82, 0x05, 0x82, 0x0b, 0x82, 0x02, + 0x82, 0x01, 0x82, 0x08, 0x82, 0x05, 0x82, 0x01, 0x82, 0x01, 0x82, 0x02, 0x82, 0x04, 0x82, + 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x03, 0x82, 0x07, + 0x82, 0x0a, 0x82, 0x06, 0x82, 0x04, 0x82, 0x03, 0x82, 0x02, 0x82, 0x03, 0x82, 0x04, 0x82, + 0x04, 0x84, 0x04, 0x82, 0x04, 0x82, 0x07, 0x82, 0x06, 0x82, 0x08, 0x82, 0x08, 0x82, 0x26, + 0x82, 0x0f, 0x88, 0x05, 0x82, 0x01, 0x82, 0x05, 0x82, 0x05, 0x82, 0x02, 0x82, 0x01, 0x82, + 0x0d, 0x82, 0x0a, 0x82, 0x05, 0x82, 0x02, 0x82, 0x06, 0x82, 0x26, 0x82, 0x05, 0x82, 0x04, + 0x82, 0x05, 0x82, 0x07, 0x82, 0x0c, 0x82, 0x02, 0x88, 0x08, 0x82, 0x02, 0x82, 0x04, 0x82, + 0x05, 0x82, 0x05, 0x82, 0x04, 0x82, 0x08, 0x82, 0x18, 0x82, 0x14, 0x82, 0x07, 0x82, 0x05, + 0x82, 0x01, 0x84, 0x03, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x08, 0x82, + 0x04, 0x82, 0x02, 0x82, 0x08, 0x82, 0x08, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x05, + 0x82, 0x0a, 0x82, 0x03, 0x82, 0x02, 0x82, 0x04, 0x82, 0x08, 0x82, 0x01, 0x82, 0x01, 0x82, + 0x02, 0x82, 0x02, 0x84, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x08, 0x82, 0x04, 0x82, 0x02, + 0x82, 0x02, 0x82, 0x0a, 0x82, 0x05, 0x82, 0x05, 0x82, 0x04, 0x82, 0x04, 0x84, 0x04, 0x82, + 0x01, 0x82, 0x01, 0x82, 0x04, 0x84, 0x07, 0x82, 0x07, 0x82, 0x07, 0x82, 0x0b, 0x82, 0x09, + 0x82, 0x22, 0x87, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x08, 0x82, 0x04, 0x82, 0x02, 0x88, + 0x04, 0x82, 0x06, 0x82, 0x03, 0x82, 0x03, 0x82, 0x04, 0x82, 0x05, 0x82, 0x0b, 0x82, 0x02, + 0x84, 0x09, 0x82, 0x05, 0x82, 0x01, 0x82, 0x01, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, + 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x03, 0x82, 0x08, 0x86, 0x05, + 0x82, 0x06, 0x82, 0x04, 0x82, 0x03, 0x82, 0x02, 0x82, 0x03, 0x82, 0x01, 0x82, 0x01, 0x82, + 0x05, 0x82, 0x05, 0x82, 0x04, 0x82, 0x06, 0x82, 0x07, 0x82, 0x08, 0x82, 0x08, 0x82, 0x26, + 0x82, 0x10, 0x82, 0x01, 0x82, 0x07, 0x82, 0x01, 0x82, 0x04, 0x82, 0x01, 0x83, 0x02, 0x82, + 0x03, 0x83, 0x0f, 0x82, 0x08, 0x82, 0x06, 0x82, 0x02, 0x82, 0x06, 0x82, 0x25, 0x82, 0x07, + 0x82, 0x02, 0x82, 0x06, 0x82, 0x06, 0x82, 0x07, 0x82, 0x04, 0x82, 0x07, 0x82, 0x09, 0x82, + 0x02, 0x82, 0x04, 0x82, 0x04, 0x82, 0x06, 0x82, 0x04, 0x82, 0x08, 0x82, 0x19, 0x82, 0x05, + 0x88, 0x05, 0x82, 0x08, 0x82, 0x05, 0x82, 0x02, 0x82, 0x04, 0x82, 0x04, 0x82, 0x02, 0x82, + 0x04, 0x82, 0x02, 0x82, 0x08, 0x82, 0x04, 0x82, 0x02, 0x82, 0x08, 0x82, 0x08, 0x82, 0x04, + 0x82, 0x02, 0x82, 0x04, 0x82, 0x05, 0x82, 0x05, 0x82, 0x03, 0x82, 0x03, 0x82, 0x03, 0x82, + 0x03, 0x82, 0x08, 0x82, 0x04, 0x82, 0x02, 0x82, 0x03, 0x83, 0x02, 0x82, 0x04, 0x82, 0x02, + 0x82, 0x08, 0x82, 0x01, 0x82, 0x01, 0x82, 0x02, 0x82, 0x03, 0x82, 0x09, 0x82, 0x05, 0x82, + 0x05, 0x82, 0x04, 0x82, 0x04, 0x84, 0x04, 0x83, 0x02, 0x83, 0x03, 0x82, 0x02, 0x82, 0x06, + 0x82, 0x06, 0x82, 0x08, 0x82, 0x0c, 0x82, 0x08, 0x82, 0x21, 0x82, 0x04, 0x82, 0x02, 0x82, + 0x04, 0x82, 0x02, 0x82, 0x08, 0x82, 0x04, 0x82, 0x02, 0x82, 0x0a, 0x82, 0x06, 0x82, 0x03, + 0x82, 0x03, 0x82, 0x04, 0x82, 0x05, 0x82, 0x0b, 0x82, 0x02, 0x85, 0x08, 0x82, 0x05, 0x82, + 0x01, 0x82, 0x01, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, + 0x82, 0x02, 0x82, 0x04, 0x82, 0x03, 0x82, 0x0d, 0x82, 0x04, 0x82, 0x06, 0x82, 0x04, 0x82, + 0x04, 0x84, 0x04, 0x82, 0x01, 0x82, 0x01, 0x82, 0x05, 0x82, 0x05, 0x82, 0x04, 0x82, 0x05, + 0x82, 0x08, 0x82, 0x08, 0x82, 0x08, 0x82, 0x38, 0x82, 0x01, 0x82, 0x04, 0x82, 0x01, 0x82, + 0x01, 0x82, 0x04, 0x84, 0x01, 0x82, 0x01, 0x82, 0x03, 0x82, 0x10, 0x82, 0x08, 0x82, 0x30, + 0x83, 0x06, 0x82, 0x07, 0x82, 0x02, 0x82, 0x06, 0x82, 0x05, 0x82, 0x08, 0x82, 0x04, 0x82, + 0x07, 0x82, 0x03, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x04, 0x82, 0x06, 0x82, 0x04, + 0x82, 0x03, 0x81, 0x04, 0x82, 0x1a, 0x82, 0x10, 0x82, 0x10, 0x82, 0x08, 0x82, 0x04, 0x82, + 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x08, + 0x82, 0x08, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x05, 0x82, 0x05, 0x82, 0x03, 0x82, + 0x03, 0x82, 0x03, 0x82, 0x03, 0x82, 0x08, 0x82, 0x04, 0x82, 0x02, 0x82, 0x03, 0x83, 0x02, + 0x82, 0x04, 0x82, 0x02, 0x82, 0x08, 0x82, 0x02, 0x84, 0x02, 0x82, 0x03, 0x82, 0x03, 0x82, + 0x04, 0x82, 0x05, 0x82, 0x05, 0x82, 0x04, 0x82, 0x05, 0x82, 0x05, 0x83, 0x02, 0x83, 0x03, + 0x82, 0x02, 0x82, 0x06, 0x82, 0x05, 0x82, 0x09, 0x82, 0x0c, 0x82, 0x08, 0x82, 0x21, 0x82, + 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x08, 0x82, 0x04, 0x82, 0x02, 0x82, 0x0a, + 0x82, 0x07, 0x85, 0x04, 0x82, 0x04, 0x82, 0x05, 0x82, 0x0b, 0x82, 0x02, 0x82, 0x02, 0x82, + 0x07, 0x82, 0x05, 0x82, 0x01, 0x82, 0x01, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, + 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x03, 0x82, 0x0d, 0x82, 0x04, 0x82, + 0x06, 0x82, 0x04, 0x82, 0x04, 0x84, 0x04, 0x82, 0x01, 0x82, 0x01, 0x82, 0x04, 0x84, 0x04, + 0x82, 0x04, 0x82, 0x04, 0x82, 0x09, 0x82, 0x08, 0x82, 0x08, 0x82, 0x26, 0x82, 0x10, 0x82, + 0x01, 0x82, 0x05, 0x86, 0x04, 0x82, 0x01, 0x82, 0x01, 0x82, 0x01, 0x83, 0x01, 0x84, 0x10, + 0x82, 0x06, 0x82, 0x1d, 0x83, 0x11, 0x83, 0x05, 0x82, 0x09, 0x84, 0x07, 0x82, 0x05, 0x82, + 0x09, 0x82, 0x02, 0x82, 0x08, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, + 0x82, 0x08, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x06, 0x83, 0x07, 0x83, 0x09, 0x82, + 0x0e, 0x82, 0x0a, 0x82, 0x06, 0x82, 0x03, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x82, 0x03, + 0x82, 0x04, 0x82, 0x02, 0x82, 0x03, 0x82, 0x03, 0x82, 0x03, 0x82, 0x08, 0x82, 0x09, 0x82, + 0x02, 0x83, 0x02, 0x82, 0x04, 0x82, 0x05, 0x82, 0x06, 0x82, 0x01, 0x82, 0x04, 0x82, 0x04, + 0x82, 0x02, 0x82, 0x08, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x03, 0x82, 0x02, 0x82, + 0x03, 0x82, 0x09, 0x82, 0x02, 0x82, 0x03, 0x82, 0x04, 0x82, 0x03, 0x82, 0x02, 0x82, 0x06, + 0x82, 0x06, 0x82, 0x02, 0x82, 0x06, 0x82, 0x05, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, + 0x05, 0x82, 0x05, 0x82, 0x09, 0x82, 0x0d, 0x82, 0x07, 0x82, 0x21, 0x82, 0x04, 0x82, 0x02, + 0x83, 0x02, 0x82, 0x04, 0x82, 0x03, 0x82, 0x03, 0x82, 0x02, 0x83, 0x03, 0x82, 0x03, 0x82, + 0x04, 0x82, 0x06, 0x82, 0x08, 0x82, 0x04, 0x82, 0x05, 0x82, 0x0b, 0x82, 0x02, 0x82, 0x03, + 0x82, 0x06, 0x82, 0x05, 0x82, 0x01, 0x82, 0x01, 0x82, 0x02, 0x82, 0x04, 0x82, 0x03, 0x82, + 0x02, 0x82, 0x03, 0x83, 0x02, 0x82, 0x04, 0x82, 0x02, 0x83, 0x03, 0x82, 0x07, 0x82, 0x04, + 0x82, 0x04, 0x82, 0x02, 0x82, 0x03, 0x82, 0x02, 0x83, 0x05, 0x82, 0x05, 0x88, 0x03, 0x82, + 0x02, 0x82, 0x04, 0x82, 0x02, 0x83, 0x03, 0x82, 0x0a, 0x82, 0x08, 0x82, 0x08, 0x82, 0x26, + 0x82, 0x1c, 0x82, 0x06, 0x82, 0x02, 0x83, 0x03, 0x84, 0x02, 0x82, 0x10, 0x82, 0x04, 0x82, + 0x1e, 0x83, 0x11, 0x83, 0x05, 0x82, 0x0a, 0x82, 0x05, 0x88, 0x02, 0x88, 0x04, 0x84, 0x09, + 0x82, 0x05, 0x84, 0x06, 0x84, 0x05, 0x82, 0x09, 0x84, 0x06, 0x84, 0x07, 0x83, 0x07, 0x83, + 0x0a, 0x81, 0x0e, 0x81, 0x0b, 0x82, 0x07, 0x85, 0x03, 0x82, 0x04, 0x82, 0x02, 0x86, 0x06, + 0x84, 0x04, 0x86, 0x04, 0x88, 0x02, 0x82, 0x0a, 0x84, 0x01, 0x81, 0x02, 0x82, 0x04, 0x82, + 0x02, 0x88, 0x04, 0x83, 0x05, 0x82, 0x04, 0x82, 0x02, 0x88, 0x02, 0x82, 0x04, 0x82, 0x02, + 0x82, 0x04, 0x82, 0x04, 0x84, 0x04, 0x82, 0x0a, 0x85, 0x03, 0x82, 0x04, 0x82, 0x04, 0x84, + 0x07, 0x82, 0x07, 0x84, 0x07, 0x82, 0x05, 0x82, 0x04, 0x82, 0x02, 0x82, 0x04, 0x82, 0x05, + 0x82, 0x05, 0x88, 0x03, 0x86, 0x09, 0x82, 0x03, 0x86, 0x22, 0x85, 0x01, 0x81, 0x02, 0x82, + 0x01, 0x83, 0x06, 0x85, 0x05, 0x83, 0x01, 0x82, 0x04, 0x85, 0x05, 0x82, 0x07, 0x86, 0x03, + 0x82, 0x04, 0x82, 0x02, 0x88, 0x08, 0x82, 0x02, 0x82, 0x04, 0x82, 0x02, 0x88, 0x02, 0x82, + 0x01, 0x82, 0x01, 0x82, 0x02, 0x82, 0x04, 0x82, 0x04, 0x84, 0x04, 0x82, 0x01, 0x83, 0x06, + 0x83, 0x01, 0x82, 0x03, 0x82, 0x08, 0x86, 0x06, 0x84, 0x05, 0x83, 0x01, 0x82, 0x05, 0x82, + 0x06, 0x82, 0x02, 0x82, 0x03, 0x82, 0x04, 0x82, 0x04, 0x83, 0x01, 0x82, 0x03, 0x87, 0x06, + 0x84, 0x05, 0x82, 0x05, 0x84, 0x7f, 0x15, 0x83, 0x7f, 0x14, 0x83, 0x7f, 0x5e, 0x82, 0x7f, + 0x05, 0x89, 0x47, 0x82, 0x04, 0x82, 0x17, 0x82, 0x03, 0x82, 0x34, 0x82, 0x0e, 0x82, 0x4e, + 0x82, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x0a, 0x82, 0x04, 0x82, 0x17, 0x82, 0x03, 0x82, + 0x34, 0x82, 0x0e, 0x82, 0x48, 0x82, 0x04, 0x82, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x0a, + 0x82, 0x04, 0x82, 0x17, 0x82, 0x03, 0x82, 0x34, 0x82, 0x0e, 0x82, 0x49, 0x82, 0x02, 0x82, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x0c, 0x86, 0x19, 0x85, 0x35, 0x82, 0x0e, 0x82, 0x4a, + 0x84, 0x3f, + 0x00, + } +}; diff --git a/src/librui/common.h b/src/librui/common.h new file mode 100644 index 0000000..72ce978 --- /dev/null +++ b/src/librui/common.h @@ -0,0 +1,49 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef UNUSED +#define UNUSED __attribute__((unused)) +#endif /* UNUSED */ + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#endif /* ARRAY_SIZE */ + +#if __STDC_VERSION__ < 199901L +#if __GNUC__ >= 2 +#define __func__ __FUNCTION__ +#else +#define __func__ "" +#endif +#endif + +#define ASSERT_ARRAYS_EQUAL_LENGTH(a1, a2) \ + _Static_assert(ARRAY_SIZE(a1) == ARRAY_SIZE(a2), \ + "Arrays " #a1 " and " #a2 " must have equal length."); + +#ifdef __cplusplus +} +#endif diff --git a/src/librui/fbdev.h b/src/librui/fbdev.h new file mode 100644 index 0000000..2949820 --- /dev/null +++ b/src/librui/fbdev.h @@ -0,0 +1,46 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2007 The Android Open Source Project + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +#include "graphics.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + int fd, + displayed_buffer; + gr_surface gr_draw; + GRSurface gr_framebuffer[2]; + struct fb_var_screeninfo vi; + struct fb_fix_screeninfo fi; +} fbdev_common; + +bool fbdev_init_common(gr_backend *backend); +bool fbdev_exit_common(gr_backend *backend); + +#ifdef __cplusplus +} +#endif diff --git a/src/librui/graphics-fbdev-common.c b/src/librui/graphics-fbdev-common.c new file mode 100644 index 0000000..4e23054 --- /dev/null +++ b/src/librui/graphics-fbdev-common.c @@ -0,0 +1,87 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "fbdev.h" +#include "common.h" +#include "graphics.h" + +bool fbdev_init_common(gr_backend *backend) +{ + fbdev_common *fb = (fbdev_common *)backend->data; + + memset(fb->gr_framebuffer, 0, sizeof(fb->gr_framebuffer)); + + fb->fd = open("/dev/fb0", O_RDWR); + if (fb->fd < 0) { + perror("Cannot open fb0"); + return false; + } + + if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vi) < 0) { + perror("Failed to get fb0 info"); + backend->exit(backend); + return false; + } + + if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->fi) < 0) { + printf("Failed to get fb0 fix info"); + return false; + } + + /* If you have a device that has other BPP patches welcome... */ + if (fb->vi.bits_per_pixel != 32) { + printf("Non-32-bit framebuffers not supported yet. Sorry.\n"); + backend->exit(backend); + return false; + } + + fb->gr_framebuffer[0].width = fb->vi.xres; + fb->gr_framebuffer[0].height = fb->vi.yres; + fb->gr_framebuffer[0].pixel_bytes = fb->vi.bits_per_pixel / 8; + fb->gr_framebuffer[0].row_bytes = fb->gr_framebuffer[0].width * fb->gr_framebuffer[0].pixel_bytes; + memcpy(fb->gr_framebuffer + 1, fb->gr_framebuffer, sizeof(GRSurface)); + fb->gr_draw = fb->gr_framebuffer + 1; + return true; +} + +bool fbdev_exit_common(gr_backend *backend) +{ + fbdev_common *fb = (fbdev_common *)backend->data; + + fb->gr_framebuffer[0].data = NULL; + fb->gr_framebuffer[1].data = NULL; + fb->gr_draw = NULL; + + if (fb->fd != -1 && close(fb->fd) < 0) { + perror("Can't close framebuffer descriptor"); + return false; + } + + fb->fd = -1; + return true; +} diff --git a/src/librui/graphics-fbdev.c b/src/librui/graphics-fbdev.c new file mode 100644 index 0000000..c0211c9 --- /dev/null +++ b/src/librui/graphics-fbdev.c @@ -0,0 +1,157 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 The Android Open Source Project + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "fbdev.h" +#include "common.h" +#include "graphics.h" + +static gr_surface fbdev_init(gr_backend *); +static gr_surface fbdev_flip(gr_backend *); +static bool fbdev_exit(gr_backend *); + +fbdev_common fb_data = { + .fd = -1, + .displayed_buffer = 0, + .gr_draw = NULL +}; + +static gr_backend fbdev_backend = { + .init = fbdev_init, + .flip = fbdev_flip, + .exit = fbdev_exit, + .data = (void *)&fb_data +}; + +gr_backend *open_fbdev(void) +{ + return &fbdev_backend; +} + +static void fbdev_blank(gr_backend *backend, bool blank) +{ + int ret; + fbdev_common *fb = (fbdev_common *)backend->data; + + ret = ioctl(fb->fd, FBIOBLANK, blank ? FB_BLANK_POWERDOWN : + FB_BLANK_UNBLANK); + if (ret < 0) + perror("ioctl(): blank"); +} + +static void set_displayed_framebuffer(fbdev_common *fb, unsigned int n) +{ + if (n > 1) + return; + + if (n == 0) + fb->vi.yoffset = 0; + else + fb->vi.yoffset = fb->vi.yres; + + if (ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi) < 0) + perror("Active fb swap failed"); + + fb->displayed_buffer = n; +} + +static gr_surface fbdev_init(gr_backend *backend) +{ + size_t bufsize; + size_t bufsize_for_mmap; + int nr_buffer; + + fbdev_common *fb = (fbdev_common *)backend->data; + + if (!fbdev_init_common(backend)) + return NULL; + + nr_buffer = fb->vi.yres_virtual / fb->vi.yres; + printf("Frame buffer nr = %d\n", nr_buffer); + + bufsize = fb->fi.line_length * fb->vi.yres; + //TODO : Based on Kernel code, following code is right. + // : However, it is strange because of bufsize > bufsize_for_mmap + // : It should be re-checked later with other kernel's framebuffer. + bufsize_for_mmap = fb->vi.xres * fb->vi.yres * fb->vi.bits_per_pixel / 8; + + fb->gr_framebuffer[0].data = mmap(0, bufsize_for_mmap * nr_buffer, + PROT_READ | PROT_WRITE, MAP_SHARED, + fb->fd, 0); + + if (fb->gr_framebuffer[0].data == MAP_FAILED) { + perror("Failed to mmap video memory"); + fbdev_exit(backend); + return NULL; + } + + fb->gr_framebuffer[1].data = fb->gr_framebuffer[0].data + bufsize; + gr_fill_alpha(&fb->gr_framebuffer[0]); + memcpy(fb->gr_framebuffer[1].data, fb->gr_framebuffer[0].data, + bufsize); + set_displayed_framebuffer(fb, 0); + + printf("Framebuffer: %dx%d, %d BPP\n", fb->gr_draw->width, + fb->gr_draw->height, fb->vi.bits_per_pixel); + + fbdev_blank(backend, true); + fbdev_blank(backend, false); + return fb->gr_draw; +} + +static gr_surface fbdev_flip(gr_backend *backend) +{ + fbdev_common *fb = (fbdev_common *)backend->data; + + /* Change gr_draw to point to the buffer currently displayed, + * then flip the driver so we're displaying the other buffer + * instead. */ + fb->gr_draw = fb->gr_framebuffer + fb->displayed_buffer; + set_displayed_framebuffer(fb, 1 - fb->displayed_buffer); + return fb->gr_draw; +} + +static bool fbdev_exit(gr_backend *backend) +{ + fbdev_common *fb = (fbdev_common *)backend->data; + size_t bufsize = fb->vi.xres * fb->vi.yres * fb->vi.bits_per_pixel / 8; + + /* Unmap double buffer */ + if (fb->gr_framebuffer[0].data && + munmap(fb->gr_framebuffer[0].data, bufsize * 2) < 0) { + perror("Failed to unmmap video memory"); + return false; + } + + return fbdev_exit_common(backend); +} diff --git a/src/librui/graphics-tdm.c b/src/librui/graphics-tdm.c new file mode 100644 index 0000000..0cbe536 --- /dev/null +++ b/src/librui/graphics-tdm.c @@ -0,0 +1,101 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil -*- + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "graphics.h" +#include "tdm-if.h" + +static gr_surface tdm_init(gr_backend *); +static gr_surface tdm_flip(gr_backend *); +static bool tdm_exit(gr_backend *); + +struct _tdm_data { + GRSurface gr_framebuffer; +}; + +static struct _tdm_data tdm_data; + +static gr_backend tdm_backend = { + .init = tdm_init, + .flip = tdm_flip, + .exit = tdm_exit, + .data = (void*)&tdm_data, +}; + +gr_backend *open_tdm(void) +{ + return &tdm_backend; +} + +gr_surface tdm_init(gr_backend *backend) +{ + struct _tdm_data *data = (struct _tdm_data*)backend->data; + gr_surface gr_draw = (gr_surface)&data->gr_framebuffer; + + if (tdm_if_display_init() < 0) + return NULL; + + tdm_if_lcd_off(); + + gr_draw->width = tdm_if_display_width(); + gr_draw->height = tdm_if_display_height(); + gr_draw->pixel_bytes = 4; /* XXX */ + gr_draw->row_bytes = tdm_if_display_stride(); + gr_draw->data = malloc(tdm_if_display_bufsize()); + if (gr_draw->data == NULL) + return NULL; + + tdm_if_lcd_on(); + return gr_draw; +} + +gr_surface tdm_flip(gr_backend *backend) +{ + struct _tdm_data *data = (struct _tdm_data*)backend->data; + gr_surface gr_draw = (gr_surface)&data->gr_framebuffer; + + tdm_if_buffer_update(gr_draw->data); + tdm_if_display_update(); + + return gr_draw; +} + +bool tdm_exit(gr_backend *backend) +{ + struct _tdm_data *data = (struct _tdm_data*)backend->data; + gr_surface gr_draw = (gr_surface)&data->gr_framebuffer; + + tdm_if_display_deinit(); + + if (gr_draw->data != NULL) + free(gr_draw->data); + + return true; +} diff --git a/src/librui/graphics.c b/src/librui/graphics.c new file mode 100644 index 0000000..f564ab5 --- /dev/null +++ b/src/librui/graphics.c @@ -0,0 +1,495 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2007 The Android Open Source Project + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "graphics.h" +#include "rui-image.h" +#include "font-10x18.h" + +#include "config.h" + +typedef struct { + gr_surface texture; + int cwidth; + int cheight; +} GRFont; + +static GRFont *gr_font = NULL; +static gr_backend *g_backend = NULL; + +static color gr_current_color = WHITE; +static gr_surface gr_draw = NULL; + +static bool outside(int x, int y) +{ + return x < 0 || x >= gr_draw->width || y < 0 || y >= gr_draw->height; +} + +int gr_get_font_cwidth(void) +{ + return gr_font->cwidth; +} + +int gr_get_font_cheight(void) +{ + return gr_font->cheight; +} + +void gr_set_color(color c) +{ + gr_current_color = c; +} + +void gr_draw_rectangle(int x, int y, int width, int height) +{ + int i, j; + unsigned char *dst_p, *first_line; + color *px; + + if (outside(x, y) || outside(x + width - 1, y + height - 1)) + return; + + dst_p = gr_draw->data + y * gr_draw->row_bytes + + x * gr_draw->pixel_bytes; + + for (i = 0, px = (color *)dst_p; i < width; i++) + *px++ = gr_current_color; + + first_line = dst_p; + dst_p += gr_draw->row_bytes; + for (j = 1; j < height; j++, dst_p += gr_draw->row_bytes) + memcpy(dst_p, first_line, width * gr_draw->pixel_bytes); +} + +void gr_clear(void) +{ + gr_draw_rectangle(0, 0, gr_draw->width, gr_draw->height); +} + +/* Set Alpha component of pixels to 255 to make overlay visible. */ +void gr_fill_alpha(gr_surface gr) +{ + int i, j; + unsigned char *dst_p, *first_line; + color *px; + + dst_p = gr->data; + for (i = 0, px = (color *)dst_p; i < gr->width; i++) + *px++ = BLACK; + + first_line = dst_p; + dst_p += gr->row_bytes; + for (j = 1; j < gr->height; j++, dst_p += gr->row_bytes) + memcpy(dst_p, first_line, gr->width * gr->pixel_bytes); +} + +static void gr_blit(gr_surface source, int sx, int sy, int w, int h, int dx, int dy) +{ + int i; + unsigned char *src_p, *dst_p; + + if (!source) + return; + + if (gr_draw->pixel_bytes != source->pixel_bytes) { + printf("%s: source has wrong format: %d bytes per pixel\n", + __func__, source->pixel_bytes); + return; + } + + if (outside(dx, dy) || outside(dx + w - 1, dy + h - 1)) + return; + + src_p = source->data + sy * source->row_bytes + + sx * source->pixel_bytes; + dst_p = gr_draw->data + dy * gr_draw->row_bytes + + dx * gr_draw->pixel_bytes; + + for (i = 0; i < h; ++i) { + memcpy(dst_p, src_p, w * source->pixel_bytes); + src_p += source->row_bytes; + dst_p += gr_draw->row_bytes; + } +} + +/* RGB + Alpha */ +static void gr_blend_rgba(gr_surface source, int w, int h, unsigned char *src_p, + unsigned char *dst_p) +{ + int i, j; + + for (j = 0; j < h; j++) { + color *sx = (color *)src_p; + color *px = (color *)dst_p; + + for (i = 0; i < w; i++) { + unsigned char r = sx->r, g = sx->g, b = sx->b, + a = sx->a; + + if (a == 255) { + *px++ = *sx; + } else { + px->r = (px->r * (255 - a) + r * a) / 255; + px->g = (px->g * (255 - a) + g * a) / 255; + px->b = (px->b * (255 - a) + b * a) / 255; + px->a = 255; + } + } + + src_p += source->row_bytes; + dst_p += gr_draw->row_bytes; + } +} + +/* RGB: Using current color's Alpha as alpha */ +static void gr_blend_rgb(gr_surface source, int w, int h, unsigned char *src_p, + unsigned char *dst_p) +{ + int i, j; + + for (j = 0; j < h; j++) { + color *sx = (color *)src_p; + color *px = (color *)dst_p; + + for (i = 0; i < w; i++) { + unsigned char r = sx->r, g = sx->g, b = sx->b; + + if (gr_current_color.a == 255) { + *px = *sx; + px->a = 255; + px++; + } else { + px->r = (px->r * (255 - gr_current_color.a) + + r * gr_current_color.a) / 255; + px->g = (px->g * (255 - gr_current_color.a) + + g * gr_current_color.a) / 255; + px->b = (px->b * (255 - gr_current_color.a) + + b * gr_current_color.a) / 255; + px->a = 255; + px++; + } + } + + src_p += source->row_bytes; + dst_p += gr_draw->row_bytes; + } +} + +/* Grayscale + Alpha */ +static void gr_blend_ga(gr_surface source, int w, int h, unsigned char *src_p, + unsigned char *dst_p) +{ + int i, j; + + for (j = 0; j < h; j++) { + unsigned char *sx = src_p; + color *px = (color *)dst_p; + + for (i = 0; i < w; i++) { + unsigned char gr = *sx++, a = *sx++; + + if (a == 255) { + px->r = gr; + px->g = gr; + px->b = gr; + px->a = 255; + px++; + } else { + px->r = (px->r * (255 - a) + gr * a) / 255; + px->g = (px->g * (255 - a) + gr * a) / 255; + px->b = (px->b * (255 - a) + gr * a) / 255; + px->a = 255; + ++px; + } + } + + src_p += source->row_bytes; + dst_p += gr_draw->row_bytes; + } +} + +/* Grayscale. + * Using image as Alpha channel and current color for foreground. */ +static void gr_blend_g(gr_surface source, int w, int h, unsigned char *src_p, + unsigned char *dst_p) +{ + int i, j; + + for (j = 0; j < h; j++) { + unsigned char *sx = src_p; + color *px = (color *)dst_p; + + for (i = 0; i < w; i++) { + unsigned char a = *sx++; + + if (gr_current_color.a < 255) + a = ((int)a * gr_current_color.a) / 255; + + if (a == 255) { + *px = gr_current_color; + px++; + } else { + px->r = (px->r * (255 - a) + + gr_current_color.r * a) / 255; + px->g = (px->g * (255 - a) + + gr_current_color.g * a) / 255; + px->b = (px->b * (255 - a) + + gr_current_color.b * a) / 255; + px->a = 255; + ++px; + } + } + + src_p += source->row_bytes; + dst_p += gr_draw->row_bytes; + } +} + +static void gr_blend(gr_surface source, int sx, int sy, int w, int h, int dx, int dy) +{ + unsigned char *src_p, *dst_p; + + if (!source) + return; + + if (outside(dx, dy) || outside(dx + w - 1, dy + h - 1)) + return; + + src_p = source->data + sy * source->row_bytes + + sx * source->pixel_bytes; + dst_p = gr_draw->data + dy * gr_draw->row_bytes + + dx * gr_draw->pixel_bytes; + + if (source->pixel_bytes == 4) + gr_blend_rgba(source, w, h, src_p, dst_p); + else if (source->pixel_bytes == 3) + gr_blend_rgb(source, w, h, src_p, dst_p); + else if (source->pixel_bytes == 2) + gr_blend_ga(source, w, h, src_p, dst_p); + else if (source->pixel_bytes == 1) + gr_blend_g(source, w, h, src_p, dst_p); + else + printf("%s: source has wrong format: %d bytes per pixel\n", + __func__, source->pixel_bytes); +} + +void gr_text(int x, int y, const char *s, gr_font_style style) +{ + GRFont *font = gr_font; + unsigned int off; + int start_x = x; + + if (!font->texture || !s) + return; + + if (gr_current_color.a == 0) + return; + + if (style == GR_FONT_BOLD && font->texture->height == font->cheight) + style = GR_FONT_REGULAR; /* No bold font in image */ + + while ((off = *s++)) { + unsigned char *src_p, *dst_p; + + if (off == '\n') { + x = start_x; + y += font->cheight; + continue; + } + + if (outside(x, y) || + outside(x + font->cwidth - 1, y + font->cheight - 1)) + continue; + + off -= 32; + if (off >= 96) + off = '_' - 32; /* Replacement for unknown symbols */ + + src_p = font->texture->data + off * font->cwidth + + (style == GR_FONT_BOLD ? + font->cheight * font->texture->row_bytes : 0); + dst_p = gr_draw->data + y * gr_draw->row_bytes + + x * gr_draw->pixel_bytes; + gr_blend_g(font->texture, font->cwidth, font->cheight, src_p, + dst_p); + + x += font->cwidth; + } +} + +static void gr_align_surface(gr_surface surface, int *posX, int *posY, + gr_align_horizontal xalign, gr_align_vertical yalign, + int offset_x, int offset_y) +{ + if (xalign == GR_ALIGN_LEFT) + *posX = 0; + else if (xalign == GR_ALIGN_CENTER) + *posX = (gr_fb_width() - gr_get_width(surface)) / 2; + else + *posX = gr_fb_width() - gr_get_width(surface); + + if (yalign == GR_ALIGN_TOP) + *posY = 0; + else if (yalign == GR_ALIGN_MIDDLE) + *posY = (gr_fb_height() - gr_get_height(surface)) / 2; + else + *posY = gr_fb_height() - gr_get_height(surface); + + *posX += offset_x; + *posY += offset_y; +} + +void gr_blend_image_aligned(gr_surface source, gr_align_horizontal xalign, + gr_align_vertical yalign, int offset_x, int offset_y) +{ + int posX, posY; + + gr_align_surface(source, &posX, &posY, xalign, yalign, offset_x, + offset_y); + gr_blend(source, 0, 0, gr_get_width(source), gr_get_height(source), + posX, posY); +} + +void gr_blit_image_aligned(gr_surface source, gr_align_horizontal xalign, + gr_align_vertical yalign, int offset_x, int offset_y) +{ + int posX, posY; + + gr_align_surface(source, &posX, &posY, xalign, yalign, offset_x, + offset_y); + gr_blit(source, 0, 0, gr_get_width(source), gr_get_height(source), + posX, posY); +} + +unsigned int gr_get_width(gr_surface surface) +{ + if (!surface) + return 0; + + return surface->width; +} + +unsigned int gr_get_height(gr_surface surface) +{ + if (!surface) + return 0; + + return surface->height; +} + +static void gr_init_font(void) +{ + int res; + + gr_font = calloc(sizeof(*gr_font), 1); + if (gr_font == NULL) { + printf("%s:%d: Memory allocation has failed.", __FILE__, __LINE__); + return; + } + + res = res_create_image_surface(RUI_IMAGES_DIR "/font.png", + &(gr_font->texture), GR_WITH_ALPHA); + if (res == 0) { + /* The font image should be a 96x2 array of character images. + * The columns are the printable ASCII characters 0x20 - 0x7f. + * The top row is regular text; the bottom row is bold. */ + gr_font->cwidth = gr_font->texture->width / 96; + gr_font->cheight = gr_font->texture->height / 2; + } else { + unsigned char *bits, *in, data; + + printf("Failed to read font: res=%d\n", res); + + /* fall back to the compiled-in font. */ + gr_font->texture = malloc(sizeof(*gr_font->texture)); + if (gr_font->texture == NULL) { + printf("%s:%d: Memory allocation has failed.", __FILE__, __LINE__); + free(gr_font); + return; + } + gr_font->texture->width = font.width; + gr_font->texture->height = font.height; + gr_font->texture->row_bytes = font.width; + gr_font->texture->pixel_bytes = 1; + + bits = malloc(font.width * font.height); + gr_font->texture->data = (void *)bits; + + in = font.rundata; + while ((data = *in++)) { + memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f); + bits += (data & 0x7f); + } + + gr_font->cwidth = font.cwidth; + gr_font->cheight = font.cheight; + } +} + +void gr_flip(void) +{ + gr_draw = g_backend->flip(g_backend); +} + +bool gr_init(void) +{ + gr_init_font(); + +#ifdef HAVE_TDM + g_backend = open_tdm(); +#else + g_backend = open_fbdev(); +#endif + gr_draw = g_backend->init(g_backend); + if (gr_draw == NULL) + return false; + + gr_flip(); + gr_flip(); + + return true; +} + +void gr_exit(void) +{ + g_backend->exit(g_backend); +} + +int gr_fb_width(void) +{ + return gr_draw->width; +} + +int gr_fb_height(void) +{ + return gr_draw->height; +} diff --git a/src/librui/graphics.h b/src/librui/graphics.h new file mode 100644 index 0000000..a768462 --- /dev/null +++ b/src/librui/graphics.h @@ -0,0 +1,155 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2007 The Android Open Source Project + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +#include "config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + int width; + int height; + int row_bytes; + int pixel_bytes; + unsigned char *data; +} GRSurface; + +typedef GRSurface *gr_surface; + +typedef struct gr_backend { + /* Initializes the backend and returns a gr_surface to draw into. */ + gr_surface(*init)(struct gr_backend *); + + /* Causes the current drawing surface (returned by the most recent + * call to flip() or init()) to be displayed, and returns a new + * drawing surface. */ + gr_surface(*flip)(struct gr_backend *); + + /* Device cleanup when drawing is done. */ + bool (*exit)(struct gr_backend *); + + void *data; /* Private data for graphics backend */ +} gr_backend; + +#ifdef HAVE_TDM /* BGRA */ +typedef struct { + unsigned char b, g, r, a; +} color; + +gr_backend *open_tdm(void); + +#else /* RGBA */ +typedef struct { + unsigned char r, g, b, a; +} color; + +gr_backend *open_fbdev(void); +#endif + +#define BLACK (color) { .r = 0, .g = 0, .b = 0, .a = 255 } +#define RED (color) { .r = 255, .g = 0, .b = 0, .a = 255 } +#define GREEN (color) { .r = 0, .g = 255, .b = 0, .a = 255 } +#define YELLOW (color) { .r = 255, .g = 255, .b = 0, .a = 255 } +#define BLUE (color) { .r = 0, .g = 0, .b = 255, .a = 255 } +#define MAGENTA (color) { .r = 255, .g = 0, .b = 255, .a = 255 } +#define CYAN (color) { .r = 0, .g = 255, .b = 255, .a = 255 } +#define WHITE (color) { .r = 255, .g = 255, .b = 255, .a = 255 } + +bool gr_init(void); +void gr_exit(void); + +int gr_fb_width(void); +int gr_fb_height(void); + +void gr_flip(void); + +void gr_fill_alpha(gr_surface gr); +void gr_clear(); /* Clear entire surface to current color */ +void gr_set_color(color c); /* Set current color */ +void gr_draw_rectangle(int x, int y, int width, int height); + +typedef enum { + GR_FONT_REGULAR, + GR_FONT_BOLD +} gr_font_style; + +void gr_text(int x, int y, const char *s, gr_font_style style); +int gr_get_font_cwidth(void); +int gr_get_font_cheight(void); + +typedef enum { + GR_ALIGN_LEFT, + GR_ALIGN_CENTER, + GR_ALIGN_RIGHT +} gr_align_horizontal; + +typedef enum { + GR_ALIGN_TOP, + GR_ALIGN_MIDDLE, + GR_ALIGN_BOTTOM +} gr_align_vertical; + +void gr_blit_image_aligned(gr_surface source, gr_align_horizontal xalign, + gr_align_vertical yalign, int offset_x, + int offset_y); +void gr_blend_image_aligned(gr_surface source, gr_align_horizontal xalign, + gr_align_vertical yalign, int offset_x, + int offset_y); + +unsigned int gr_get_width(gr_surface surface); +unsigned int gr_get_height(gr_surface surface); + +typedef enum { + GR_WITHOUT_ALPHA, + GR_WITH_ALPHA +} gr_img_type; + +/* Load a single display surface from a PNG image. */ +int res_create_image_surface(const char *name, gr_surface *pSurface, + gr_img_type img_type); + +/* Load an array of display surfaces from a single PNG image. The PNG + * should have a "Frames" text chunk whose value is the number of + * frames this image represents. The pixel data itself is interlaced + * by row. */ +int res_create_anim_image_surfaces(const char *name, int *frames, + gr_surface **pSurface, + gr_img_type img_type); + +/* Load part of a grayscale PNG image that is the first match for the + * given locale. The image is expected to be a composite of multiple + * translations of the same text, with special added rows that encode + * the subimages' size and intended locale in the pixel data. */ +int res_create_localized_alpha_surface(const char *name, const char *locale, + gr_surface *pSurface); + +/* Free a surface allocated by any of the res_create_*_surface() + * functions. */ +void res_free_surface(gr_surface surface); + +#ifdef __cplusplus +} +#endif diff --git a/src/librui/input-events.c b/src/librui/input-events.c new file mode 100644 index 0000000..325391c --- /dev/null +++ b/src/librui/input-events.c @@ -0,0 +1,309 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2007 The Android Open Source Project + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _POSIX_C_SOURCE 200809L + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "input-events.h" + +#define MAX_INPUTS 32 + +#define BITS_PER_LONG (sizeof(unsigned long) * 8) +#define BITS_TO_LONGS(x) (((x) + BITS_PER_LONG - 1) / BITS_PER_LONG) + +#define test_bit(bit, array) \ + ((array)[(bit) / BITS_PER_LONG] & (1 << ((bit) % BITS_PER_LONG))) + +static struct pollfd ev_fds[MAX_INPUTS]; + +static unsigned ev_count = 0; + +static unsigned signalfd_idx = -1; +static unsigned timerfd_idx = -1; + +#define IS_SIGNAL_EVENT(x) (x == signalfd_idx) +#define IS_TIMER_EVENT(x) (x == timerfd_idx) + +static bool ev_signal_init(void) +{ + sigset_t mask; + + if (ev_count >= MAX_INPUTS) + return false; + + sigemptyset(&mask); + sigaddset(&mask, SIGINT); + if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) { + perror("sigprocmask"); + return false; + } + + ev_fds[ev_count].fd = signalfd(-1, &mask, 0); + ev_fds[ev_count].events = POLLIN; + if (ev_fds[ev_count].fd == -1) { + perror("signalfd"); + return false; + } + signalfd_idx = ev_count++; + + return true; +} + +static bool ev_timer_init(void) +{ + int fd; + struct itimerspec timer_spec = { + .it_interval = {TIMER_INTERVAL, 0}, + .it_value = {0, 1}, + }; + + if (ev_count >= MAX_INPUTS) + return false; + + fd = timerfd_create(CLOCK_REALTIME, 0); + if (fd < 0) { + perror("timerfd_create"); + return false; + } + + timerfd_settime(fd, 0, &timer_spec, NULL); + ev_fds[ev_count].fd = fd; + ev_fds[ev_count].events = POLLIN; + timerfd_idx = ev_count++; + + return true; +} + +static bool ev_input_init(void) +{ + DIR *dir; + struct dirent *de; + int fd; + int t = ev_count; + + dir = opendir("/dev/input"); + if (!dir) { + printf("Can't open directory \"/dev/input\".\n"); + return false; + } + + while ((de = readdir(dir))) { + unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; + + /* fprintf(stderr,"/dev/input/%s\n", de->d_name);*/ + if (strncmp(de->d_name, "event", 5)) + continue; + + fd = openat(dirfd(dir), de->d_name, O_RDONLY); + if (fd < 0) + continue; + + /* read the evbits of the input device */ + if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) < 0) { + close(fd); + continue; + } + + /* TODO: add ability to specify event masks. For now, just + * assume that only EV_KEY and EV_REL event types are ever + * needed. */ + if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits)) { + close(fd); + continue; + } + + ev_fds[ev_count].fd = fd; + ev_fds[ev_count].events = POLLIN; + ev_count++; + if (ev_count == MAX_INPUTS) + break; + } + + closedir(dir); + if (ev_count == t) { + printf("No input devices found.\n"); + return false; + } + + return true; +} + +bool ev_init(void) +{ + return ev_input_init() && ev_signal_init() && ev_timer_init(); +} + +void ev_exit(void) +{ + while (ev_count > 0) + close(ev_fds[--ev_count].fd); +} + +static user_action last_action = ACTION_NONE; +static time_t event_start = 0; + +static void ev_input_longpress_check(input_callback callback) +{ + if (event_start && time(NULL) - event_start >= LONGPRESS_TIME) { + callback(last_action, ACTION_TYPE_LONGPRESS); + event_start = time(NULL); /* Restarting the event */ + } +} + +static bool ev_input_process(struct input_event *ev, input_callback callback) +{ + user_action action = ACTION_NONE; + + ev_input_longpress_check(callback); + + if (!ev) { /* Timeout */ + callback(ACTION_NONE, ACTION_TYPE_IDLE); + return true; + } + + if (ev->type == EV_SYN) + return true; + else if (ev->type == EV_KEY && ev->code <= KEY_MAX) { + switch (ev->code) { + case KEY_DOWN: + case KEY_VOLUMEDOWN: + action = ACTION_DOWN; + break; + case KEY_UP: + case KEY_VOLUMEUP: + action = ACTION_UP; + break; + case KEY_ENTER: + case KEY_POWER: + action = ACTION_CONFIRM; + break; + case KEY_MENU: + action = ACTION_HOME; + break; + case KEY_PHONE: + action = ACTION_MENU; + break; + case KEY_BACK: + action = ACTION_BACK; + break; + default: + /* printf("Unknown key %d.\n", ev->code);*/ + break; + } + + if (action != ACTION_NONE) { + if (ev->value == 1) { + last_action = action; + event_start = time(NULL); + } else if (action == last_action) { + last_action = ACTION_NONE; + event_start = 0; + } + + if (callback) + callback(action, ev->value == 1 ? + ACTION_TYPE_BEGIN : + ACTION_TYPE_END); + } + } else if (ev->type == EV_REL) { /* Relative event */ + + } else if (ev->type == EV_ABS) { /* Absolute event */ + + } + + return true; +} + +static int ev_wait(int timeout) +{ + int ret; + + if ((ret = poll(ev_fds, ev_count, timeout)) < 0) + perror("poll()"); + + return ret; +} + +bool ev_dispatch(input_callback callback) +{ + int r; + unsigned n; + + r = ev_wait(DISPATCH_TIMEOUT); + if (r < 0) + return false; + else if (r == 0) /* Timeout */ + return ev_input_process(NULL, callback); + + for (n = 0; n < ev_count; n++) + if (ev_fds[n].revents & POLLIN) { + int r; + struct input_event ev; + + if (IS_SIGNAL_EVENT(n)) { /* signalfd */ + struct signalfd_siginfo fdsi; + r = read(ev_fds[n].fd, &fdsi, sizeof(fdsi)); + if (r != sizeof(fdsi)) { + perror("read"); + return false; + } + if (fdsi.ssi_signo == SIGINT) + return false; + continue; + } + + if (IS_TIMER_EVENT(n)) { + uint64_t exp; + + r = read(ev_fds[n].fd, &exp, sizeof(exp)); + if (r != sizeof(exp)) { + perror("read"); + return false; + } + + callback(ACTION_TIMEOUT, ACTION_TYPE_TIMER); + continue; + } + + r = read(ev_fds[n].fd, &ev, sizeof(ev)); + if (r != sizeof(ev)) + continue; + + if (!ev_input_process(&ev, callback)) + return false; + } + + return true; +} diff --git a/src/librui/input-events.h b/src/librui/input-events.h new file mode 100644 index 0000000..b07f996 --- /dev/null +++ b/src/librui/input-events.h @@ -0,0 +1,59 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define DISPATCH_TIMEOUT (1 * 1000) /* One second */ +#define LONGPRESS_TIME 3 /* Seconds */ +#define TIMER_INTERVAL 1 /* Seconds */ + +typedef enum { + ACTION_NONE, + ACTION_DOWN, + ACTION_UP, + ACTION_CONFIRM, + ACTION_HOME, + ACTION_MENU, + ACTION_BACK, + ACTION_TIMEOUT, +} user_action; + +typedef enum { + ACTION_TYPE_IDLE, + ACTION_TYPE_BEGIN, + ACTION_TYPE_END, + ACTION_TYPE_LONGPRESS, + ACTION_TYPE_TIMER, +} user_action_type; + +typedef void (*input_callback)(user_action action, + user_action_type action_type); + +bool ev_init(void); +bool ev_dispatch(input_callback callback); +void ev_exit(void); + +#ifdef __cplusplus +} +#endif diff --git a/src/librui/resources.c b/src/librui/resources.c new file mode 100644 index 0000000..cd579f4 --- /dev/null +++ b/src/librui/resources.c @@ -0,0 +1,534 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2007 The Android Open Source Project + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "graphics.h" + +extern char *locale; + +#define SURFACE_DATA_ALIGNMENT 8 + +static gr_surface malloc_surface(size_t data_size) +{ + gr_surface surface; + unsigned char *temp; + + temp = malloc(sizeof(GRSurface) + data_size + SURFACE_DATA_ALIGNMENT); + if (!temp) + return NULL; + + surface = (gr_surface)temp; + surface->data = temp + sizeof(GRSurface) + (SURFACE_DATA_ALIGNMENT - + (sizeof(GRSurface) % SURFACE_DATA_ALIGNMENT)); + return surface; +} + +static int open_png(const char *name, + png_structp *png_ptr, + png_infop *info_ptr, + png_uint_32 *width, + png_uint_32 *height, + png_byte *channels) +{ + unsigned char header[8]; + int result = 0, color_type, bit_depth; + size_t bytesRead; + FILE *fp; + + fp = fopen(name, "rb"); + if (fp == NULL) { + result = -1; + goto exit2; + } + + bytesRead = fread(header, 1, sizeof(header), fp); + if (bytesRead != sizeof(header)) { + result = -2; + goto exit2; + } + + if (png_sig_cmp(header, 0, sizeof(header))) { + result = -3; + goto exit2; + } + + *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, + NULL); + if (!*png_ptr) { + result = -4; + goto exit1; + } + + *info_ptr = png_create_info_struct(*png_ptr); + if (!*info_ptr) { + png_destroy_read_struct(png_ptr, NULL, NULL); + result = -5; + goto exit2; + } + + if (setjmp(png_jmpbuf(*png_ptr))) { + result = -6; + goto exit1; + } + + png_init_io(*png_ptr, fp); + png_set_sig_bytes(*png_ptr, sizeof(header)); + png_read_info(*png_ptr, *info_ptr); + + png_get_IHDR(*png_ptr, *info_ptr, width, height, &bit_depth, + &color_type, NULL, NULL, NULL); + + *channels = png_get_channels(*png_ptr, *info_ptr); + + if (bit_depth == 8 && *channels == 3 && + color_type == PNG_COLOR_TYPE_RGB) { + /* 8-bit RGB: great, nothing to do. */ + } else if (bit_depth == 8 && *channels == 4 && + color_type == PNG_COLOR_TYPE_RGB_ALPHA) { + /* 8-bit RGB with alpha: great, nothing to do. */ + } else if (bit_depth == 8 && *channels == 2 && + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { + /* 8-bit gray with alpha: great, nothing to do. */ + } else if (bit_depth == 8 && *channels == 1 && + color_type == PNG_COLOR_TYPE_GRAY) { + /* 8-bit gray with: great, nothing to do. */ + } else if (bit_depth < 8 && *channels == 2 && + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { + /* 1-, 2- or 4-bit gray with alpha: expand to 8-bit gray. */ + png_set_expand_gray_1_2_4_to_8(*png_ptr); + } else if (bit_depth < 8 && *channels == 1 && + color_type == PNG_COLOR_TYPE_GRAY) { + /* 1-, 2- or 4-bit gray: expand to 8-bit gray. */ + png_set_expand_gray_1_2_4_to_8(*png_ptr); + } else if (bit_depth <= 8 && *channels == 1 && + color_type == PNG_COLOR_TYPE_PALETTE) { + int color_num; + png_colorp palette; + + if (png_get_PLTE(*png_ptr, *info_ptr, &palette, + &color_num)) { + int i, rgb = 0; + + for (i = 0; i < color_num; i++) + if (palette[i].red != palette[i].green || + palette[i].red != palette[i].blue) { + rgb = 1; + break; + } + + if (!rgb) { + png_set_rgb_to_gray_fixed(*png_ptr, 1, -1, -1); + *channels = 1; + } else + *channels = 3; + + /* paletted images: expand to 8-bit RGB. */ + png_set_palette_to_rgb(*png_ptr); + + /* Expand paletted or RGB images with transparency to full + * alpha channels so the data will be available as RGBA + * quartets. */ + if (*channels == 3 && + png_get_valid(*png_ptr, *info_ptr, PNG_INFO_tRNS)) { + png_set_tRNS_to_alpha(*png_ptr); + *channels = 4; + } + } + } else { + fprintf(stderr, + "RUI doesn't support PNG depth %d channels %d " + "color_type %d of image \"%s\"\n", + bit_depth, *channels, color_type, name); + result = -7; + goto exit1; + } + + return result; + +exit1: + if (result < 0) + png_destroy_read_struct(png_ptr, info_ptr, NULL); + +exit2: + if (fp != NULL) + fclose(fp); + + return result; +} + +/* "display" surfaces are transformed into the framebuffer's required + * pixel format (currently only RGBX is supported) at load time, so + * gr_blit() can be nothing more than a memcpy() for each row. The + * next two functions are the only ones that know anything about the + * framebuffer pixel format; they need to be modified if the + * framebuffer format changes (but nothing else should). */ + +/* Allocate and return a gr_surface sufficient for storing an image of + * the indicated size in the framebuffer pixel format. */ +static gr_surface init_display_surface(png_uint_32 width, png_uint_32 height, int channels) +{ + gr_surface surface; + + if (!(surface = malloc_surface(width * height * channels))) + return NULL; + + surface->width = width; + surface->height = height; + surface->row_bytes = width * channels; + surface->pixel_bytes = channels; + + return surface; +} + +/* Copy 'input_row' to 'output_row', transforming it to the + * framebuffer pixel format. The input format depends on the value of + * 'channels': + * + * 1 - input is 8-bit grayscale + * 2 - input is 8-bit grayscale + 8-bit alpha + * 3 - input is 24-bit RGB + * 4 - input is 32-bit RGBA/RGBX + * + * 'width' is the number of pixels in the row. */ +static void transform_rgb_to_draw(unsigned char *input_row, + unsigned char *output_row, + int channels, + int width) +{ + int x; + unsigned char *ip = input_row, *op = output_row; + + switch (channels) { + case 1: /* expand gray level to RGBX */ + for (x = 0; x < width; x++) { + *op++ = *ip; + *op++ = *ip; + *op++ = *ip++; + *op++ = 0xff; + } + + break; + case 2: /* expand gray level plus alpha to RGBX */ + for (x = 0; x < width; ++x) { + *op++ = *ip; + *op++ = *ip; + *op++ = *ip++; + *op++ = *ip++; + } + + break; + case 3: /* expand RGBA to RGBX */ + for (x = 0; x < width; ++x) { + *op++ = *ip++; + *op++ = *ip++; + *op++ = *ip++; + *op++ = 0xff; + } + + break; + case 4: /* copy RGBA to RGBX */ + memcpy(output_row, input_row, width * 4); + break; + } +} + +int res_create_anim_image_surfaces(const char *name, int *frames, + gr_surface **pSurface, gr_img_type img_type) +{ + int result = 0, i, num_text; + unsigned char *p_row = NULL; + unsigned int y; + gr_surface *surface = NULL; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + png_uint_32 width, height; + png_byte channels; + png_textp text; + + *pSurface = NULL; + *frames = -1; + + result = open_png(name, &png_ptr, &info_ptr, &width, &height, + &channels); + if (result < 0) { + printf("Can't load image \"%s\": %d.\n", name, result); + return result; + } + + *frames = 1; + + if (png_get_text(png_ptr, info_ptr, &text, &num_text)) + for (i = 0; i < num_text; i++) + if (text[i].key && !strcmp(text[i].key, "Frames") && + text[i].text) { + *frames = atoi(text[i].text); + break; + } + + if (*frames <= 0) { + printf("Bad frame count (%d)\n", *frames); + result = -9; + goto exit; + } + + if (height % *frames || height < *frames) { + printf("Bad image height (%d) for frame count (%d)\n", + (int)height, *frames); + result = -9; + goto exit; + } + + if (!(surface = malloc(*frames * sizeof(gr_surface)))) { + result = -8; + goto exit; + } + + for (i = 0; i < *frames; i++) + if (!(surface[i] = init_display_surface(width, + height / *frames, + (img_type == GR_WITH_ALPHA ? + channels : 4)))) { + result = -8; + goto exit; + } + + if (img_type == GR_WITHOUT_ALPHA) + p_row = malloc(width * channels); + + for (y = 0; y < height; y++) { + int frame = y % *frames; + unsigned char *p_dst = surface[frame]->data + (y / *frames) * + surface[frame]->row_bytes; + + if (img_type == GR_WITH_ALPHA) + png_read_row(png_ptr, p_dst, NULL); + else { + png_read_row(png_ptr, p_row, NULL); + transform_rgb_to_draw(p_row, p_dst, channels, width); + } + } + + if (img_type == GR_WITHOUT_ALPHA) + free(p_row); + + *pSurface = (gr_surface *)surface; + +exit: + if (png_get_io_ptr(png_ptr)) + fclose((FILE *)png_get_io_ptr(png_ptr)); + + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + + if (result < 0 && surface) { + for (i = 0; i < *frames; i++) + if (surface[i]) + free(surface[i]); + + free(surface); + } + + return result; +} + +int res_create_image_surface(const char *name, gr_surface *pSurface, + gr_img_type img_type) +{ + gr_surface surface = NULL; + int result = 0; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + png_uint_32 width, height; + png_byte channels; + unsigned char *p_row = NULL; + unsigned int y; + + *pSurface = NULL; + + result = open_png(name, &png_ptr, &info_ptr, &width, &height, + &channels); + if (result < 0) { + printf("Can't load image \"%s\": %d.\n", name, result); + return result; + } + + if (!(surface = init_display_surface(width, height, + (img_type == GR_WITH_ALPHA ? + channels : 4)))) { + result = -8; + goto exit; + } + + if (img_type == GR_WITHOUT_ALPHA) + p_row = malloc(width * channels); + + for (y = 0; y < height; y++) { + unsigned char *p_dst = surface->data + y * surface->row_bytes; + + if (img_type == GR_WITH_ALPHA) + png_read_row(png_ptr, p_dst, NULL); + else { + png_read_row(png_ptr, p_row, NULL); + transform_rgb_to_draw(p_row, p_dst, channels, width); + } + } + + if (img_type == GR_WITHOUT_ALPHA) + free(p_row); + + *pSurface = surface; +exit: + if (png_get_io_ptr(png_ptr)) + fclose((FILE *)png_get_io_ptr(png_ptr)); + + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + + return result; +} + +#if 0 /* Currently unneeded */ +static int matches_locale(const char *loc, const char *locale) +{ + int i; + + if (locale == NULL) + return 0; + + if (!strcmp(loc, locale)) + return 1; + + /* if loc does *not* have an underscore, and it matches the start + * of locale, and the next character in locale *is* an underscore, + * that's a match. For instance, loc == "en" matches locale == + * "en_US". */ + + for (i = 0; loc[i] != 0 && loc[i] != '_'; ++i) + ; + + if (loc[i] == '_') + return 0; + + return (!strncmp(locale, loc, i) && locale[i] == '_'); +} + +int res_create_localized_alpha_surface(const char *name, const char *locale, + gr_surface *pSurface) +{ + gr_surface surface = NULL; + int result = 0; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + png_uint_32 width, height; + png_byte channels; + unsigned char *row; + png_uint_32 y; + + *pSurface = NULL; + + if (locale == NULL) { + surface = malloc_surface(0); + surface->width = 0; + surface->height = 0; + surface->row_bytes = 0; + surface->pixel_bytes = 1; + goto exit; + } + + result = open_png(name, &png_ptr, &info_ptr, &width, &height, + &channels); + if (result < 0) { + printf("Can't load image \"%s\": %d.\n", name, result); + return result; + } + + if (channels != 1) { + result = -7; + goto exit; + } + + row = malloc(width); + for (y = 0; y < height; ++y) { + int w, h; + char *loc; + + png_read_row(png_ptr, row, NULL); + w = (row[1] << 8) | row[0]; + h = (row[3] << 8) | row[2]; + loc = (char *)row + 5; + + if (y + 1 + h >= height || matches_locale(loc, locale)) { + int i; + + printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, + (int)y); + + surface = malloc_surface(w * h); + if (surface == NULL) { + result = -8; + goto exit; + } + + surface->width = w; + surface->height = h; + surface->row_bytes = w; + surface->pixel_bytes = 1; + + for (i = 0; i < h; i++, y++) { + png_read_row(png_ptr, row, NULL); + memcpy(surface->data + i * w, row, w); + } + + *pSurface = (gr_surface)surface; + break; + } else { + int i; + + for (i = 0; i < h; i++, y++) + png_read_row(png_ptr, row, NULL); + } + } + +exit: + if (png_get_io_ptr(png_ptr)) + fclose((FILE *)png_get_io_ptr(png_ptr)); + + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + if (result < 0 && surface != NULL) + free(surface); + + return result; +} +#endif /* 0 Currently unneeded */ + +void res_free_surface(gr_surface surface) +{ + free(surface); +} diff --git a/src/librui/rui-description.c b/src/librui/rui-description.c new file mode 100644 index 0000000..c906499 --- /dev/null +++ b/src/librui/rui-description.c @@ -0,0 +1,32 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "graphics.h" +#include "rui-description.h" + +void rui_description_draw(rui_description *d) +{ + if (!d) + return; + + gr_set_color(d->style->c_title); + gr_text(d->pos_x, d->pos_y, d->title, GR_FONT_BOLD); + gr_set_color(d->style->c_text); + gr_text(d->pos_x, d->pos_y + gr_get_font_cheight(), d->text, + GR_FONT_BOLD); +} diff --git a/src/librui/rui-description.h b/src/librui/rui-description.h new file mode 100644 index 0000000..293ac3c --- /dev/null +++ b/src/librui/rui-description.h @@ -0,0 +1,44 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "graphics.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + color c_title; + color c_text; +} rui_description_style; + +typedef struct { + int pos_x; + int pos_y; + rui_description_style *style; + const char *title; + const char *text; +} rui_description; + +void rui_description_draw(rui_description *d); + +#ifdef __cplusplus +} +#endif diff --git a/src/librui/rui-image.h b/src/librui/rui-image.h new file mode 100644 index 0000000..bd7408f --- /dev/null +++ b/src/librui/rui-image.h @@ -0,0 +1,67 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "graphics.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + RUI_IMAGE_NONE = -1 +} rui_image_id; + +typedef enum { + RUI_ANIMATION_NONE = -1 +} rui_animation_id; + +typedef struct { + const char *fname; + color c_bg; + gr_align_horizontal align_hor; + gr_align_vertical align_ver; + int offset_x, + offset_y; + gr_img_type img_type; + gr_surface surface; +} rui_image; + +typedef struct { + const char *fname; + color c_bg; + gr_align_horizontal align_hor; + gr_align_vertical align_ver; + int frames_num, + current_frame; + int offset_x, + offset_y; + gr_img_type img_type; + gr_surface *surfaces; +} rui_animation; + +void rui_images_init(rui_image *images, int images_num, + rui_animation *animations, int animations_num); +void rui_images_exit(void); +void rui_images_draw(void); +void rui_animations_draw(void); + +#ifdef __cplusplus +} +#endif diff --git a/src/librui/rui-images.c b/src/librui/rui-images.c new file mode 100644 index 0000000..b5b0998 --- /dev/null +++ b/src/librui/rui-images.c @@ -0,0 +1,153 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "rui.h" +#include "common.h" +#include "graphics.h" +#include "rui-image.h" + +static rui_image *rui_images = NULL; +static rui_animation *rui_animations = NULL; +static int rui_images_num = 0, rui_animations_num = 0; + +void rui_images_draw(void) +{ + size_t i = 0; + rui_screen *cs; + rui_image_id img_id; + + cs = get_current_screen(); + if (!cs->images) + return; + + while ((img_id = cs->images[i]) != RUI_IMAGE_NONE) { + rui_image *img = &rui_images[img_id]; + + if (!img->surface) { + i++; + continue; + } + + if (img->img_type == GR_WITH_ALPHA) { + gr_set_color(img->c_bg); + gr_blend_image_aligned(img->surface, img->align_hor, + img->align_ver, img->offset_x, + img->offset_y); + } else + gr_blit_image_aligned(img->surface, img->align_hor, + img->align_ver, img->offset_x, + img->offset_y); + + i++; + } +} + +void rui_animations_draw(void) +{ + int i = 0; + rui_screen *cs; + rui_animation_id anim_id; + + cs = get_current_screen(); + if (!cs->animations) + return; + + while ((anim_id = cs->animations[i]) != RUI_ANIMATION_NONE) { + rui_animation *anim = &rui_animations[anim_id]; + + if (!anim->surfaces) { + i++; + continue; + } + + if (anim->img_type == GR_WITH_ALPHA) { + gr_set_color(anim->c_bg); + gr_blend_image_aligned(anim->surfaces[anim->current_frame], + anim->align_hor, + anim->align_ver, + anim->offset_x, + anim->offset_y); + } else + gr_blit_image_aligned(anim->surfaces[anim->current_frame], + anim->align_hor, + anim->align_ver, + anim->offset_x, + anim->offset_y); + + i++; + if (++anim->current_frame >= anim->frames_num) + anim->current_frame = 0; + } +} + +void rui_images_init(rui_image *images, + int images_num, + rui_animation *animations, + int animations_num) +{ + int i; + + rui_images = images; + rui_images_num = images_num; + rui_animations = animations; + rui_animations_num = animations_num; + + for (i = 0; i < rui_images_num; i++) + if (res_create_image_surface(rui_images[i].fname, + &rui_images[i].surface, + rui_images[i].img_type) < 0) + rui_images[i].surface = NULL; + + for (i = 0; i < rui_animations_num; i++) + if (res_create_anim_image_surfaces(rui_animations[i].fname, + &rui_animations[i].frames_num, + &rui_animations[i].surfaces, + rui_animations[i].img_type) < 0) + rui_animations[i].surfaces = NULL; +} + +void rui_images_exit(void) +{ + int i; + + for (i = 0; i < rui_images_num; i++) + if (rui_images[i].surface) { + res_free_surface(rui_images[i].surface); + rui_images[i].surface = NULL; + } + + rui_images = NULL; + rui_images_num = 0; + + for (i = 0; i < rui_animations_num; i++) + if (rui_animations[i].surfaces) { + int j; + + for (j = 0; j < rui_animations[i].frames_num; j++) + res_free_surface(rui_animations[i].surfaces[j]); + + free(rui_animations[i].surfaces); + rui_animations[i].surfaces = NULL; + } + + rui_animations = NULL; + rui_animations_num = 0; +} diff --git a/src/librui/rui-menu.c b/src/librui/rui-menu.c new file mode 100644 index 0000000..fb7698f --- /dev/null +++ b/src/librui/rui-menu.c @@ -0,0 +1,106 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "rui.h" +#include "graphics.h" +#include "rui-menu.h" + +static void rui_menu_draw_item(int i, rui_menu *m) +{ + gr_set_color((i == m->item_selected) ? m->style->c_bg_selected : + m->style->c_bg_unselected); + gr_draw_rectangle(m->pos_x, + m->pos_y + i * (m->style->item_height + + m->style->item_spacing), + gr_fb_width() - m->pos_x, m->style->item_height); + + gr_set_color((i == m->item_selected) ? m->style->c_text_selected : + m->style->c_text_unselected); + gr_text(m->style->text_pos_x, + m->pos_y + + i * (m->style->item_height + m->style->item_spacing) + + (m->style->item_height - gr_get_font_cheight()) / 2, + m->items[i], + (i == m->item_selected) ? GR_FONT_BOLD : GR_FONT_REGULAR); +} + +void rui_menu_draw(rui_menu *menu) +{ + int i; + + if (!menu) + return; + + for (i = 0; i < menu->items_num; i++) + rui_menu_draw_item(i, menu); +} + +int rui_menu_cursor_up(rui_menu *menu) +{ + if (!menu) + return 0; /* Don't need to repaint */ + + if (--menu->item_selected < 0) + menu->item_selected = menu->items_num - 1; + + return 1; /* Need repaint */ +} + +int rui_menu_cursor_down(rui_menu *menu) +{ + if (!menu) + return 0; /* Don't need to repaint */ + + if (++menu->item_selected >= menu->items_num) + menu->item_selected = 0; + + return 1; /* Need repaint */ +} + +int rui_menu_action_run(rui_menu *menu) +{ + int item_selected; + int ret; + + if (!menu || !menu->actions) + return 0; /* Don't need to repaint */ + + item_selected = menu->item_selected; + rui_screen_switch(menu->actions[item_selected].screen_switch_to); + if (menu->actions[item_selected].action_handler) { + ret = system(menu->actions[item_selected].action_handler); + if (ret < 0) + return ret; + + if (menu->actions[item_selected].exit_after_action) + exit(0); + } + + return 1; /* Repaint unconditionally. Just in case. */ +} + +void rui_menu_init(rui_menu *menu) +{ + if (!menu) + return; + + if (menu->item_default != RUI_MENU_ITEM_DO_NOT_CHANGE) + menu->item_selected = menu->item_default; +} diff --git a/src/librui/rui-menu.h b/src/librui/rui-menu.h new file mode 100644 index 0000000..1bb051a --- /dev/null +++ b/src/librui/rui-menu.h @@ -0,0 +1,68 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "graphics.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + int item_height, + item_spacing, + text_pos_x; + color c_bg_selected, + c_bg_unselected, + c_text_selected, + c_text_unselected; +} rui_menu_style; + +typedef enum { + RUI_MENU_ITEM_DO_NOT_CHANGE = -1 +} rui_menu_item_id; + +struct rui_menu_t; + +typedef struct { + int screen_switch_to; + const char *action_handler; + int exit_after_action; +} rui_menu_action; + +typedef struct rui_menu_t { + rui_menu_style *style; + int pos_x, + pos_y, + items_num, + item_selected, + item_default; + const char **items; + rui_menu_action *actions; +} rui_menu; + +void rui_menu_draw(rui_menu *menu); +int rui_menu_cursor_up(rui_menu *menu); +int rui_menu_cursor_down(rui_menu *menu); +int rui_menu_action_run(rui_menu *menu); +void rui_menu_init(rui_menu *menu); + +#ifdef __cplusplus +} +#endif diff --git a/src/librui/rui-progress-bar.c b/src/librui/rui-progress-bar.c new file mode 100644 index 0000000..80fbfdb --- /dev/null +++ b/src/librui/rui-progress-bar.c @@ -0,0 +1,68 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rui.h" +#include "graphics.h" +#include "rui-progress-bar.h" + +void rui_progress_bar_draw(rui_progress_bar *b) +{ + int width, progress_width; + + if (!b) + return; + + gr_set_color(b->style->c_border); + width = gr_fb_width() - 2 * b->pos_x; + /* Draw progress bar symmetrically to center. */ + gr_draw_rectangle(b->pos_x, b->pos_y, width, b->height); + progress_width = b->progress * + (width - 2 * b->style->border_width) / 100; + + if (b->progress != 0) { /* Draw bar. */ + gr_set_color(b->style->c_bar); + gr_draw_rectangle(b->pos_x + b->style->border_width, + b->pos_y + b->style->border_width, + progress_width, + b->height - 2 * b->style->border_width); + } + + if (b->progress != 100) { /* Draw background. */ + gr_set_color(b->style->c_background); + gr_draw_rectangle(b->pos_x + b->style->border_width + + progress_width, + b->pos_y + b->style->border_width, + width - 2 * b->style->border_width - + progress_width, + b->height - 2 * b->style->border_width); + } +} + +int rui_progress_bar_get_progress(rui_progress_bar *b) +{ + return b->progress; +} + +/* Set progress value for progress bar on the current screen. */ +void rui_progress_bar_set_progress(rui_progress_bar *b, int progress) +{ + if (!b || progress < 0 || progress > 100) + return; + + b->progress = progress; +} diff --git a/src/librui/rui-progress-bar.h b/src/librui/rui-progress-bar.h new file mode 100644 index 0000000..def59f8 --- /dev/null +++ b/src/librui/rui-progress-bar.h @@ -0,0 +1,48 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "graphics.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + color c_background, + c_border, + c_bar; + int border_width; +} rui_progress_bar_style; + +typedef struct { + int pos_x, + pos_y, + height, + progress; /* 0 - 100 */ + rui_progress_bar_style *style; +} rui_progress_bar; + +void rui_progress_bar_draw(rui_progress_bar *b); +int rui_progress_bar_get_progress(rui_progress_bar *b); +void rui_progress_bar_set_progress(rui_progress_bar *b, int progress); + +#ifdef __cplusplus +} +#endif diff --git a/src/librui/rui-ruler.h b/src/librui/rui-ruler.h new file mode 100644 index 0000000..1c4aa09 --- /dev/null +++ b/src/librui/rui-ruler.h @@ -0,0 +1,42 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "graphics.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + color c_ruler; +} rui_ruler_style; + +typedef struct { + int pos_x, + pos_y, + height; + rui_ruler_style *style; +} rui_ruler; + +void rui_rulers_draw(rui_ruler *rulers); + +#ifdef __cplusplus +} +#endif diff --git a/src/librui/rui-rulers.c b/src/librui/rui-rulers.c new file mode 100644 index 0000000..2f67995 --- /dev/null +++ b/src/librui/rui-rulers.c @@ -0,0 +1,36 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "graphics.h" +#include "rui-ruler.h" + +void rui_rulers_draw(rui_ruler *rulers) +{ + rui_ruler *r = rulers; + + while (r) { + if (!r->style) + break; + + gr_set_color(r->style->c_ruler); + /* Draw ruler symmetrically to center. */ + gr_draw_rectangle(r->pos_x, r->pos_y, + gr_fb_width() - 2 * r->pos_x, r->height); + r++; + } +} diff --git a/src/librui/rui.c b/src/librui/rui.c new file mode 100644 index 0000000..0954853 --- /dev/null +++ b/src/librui/rui.c @@ -0,0 +1,119 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "rui.h" +#include "common.h" +#include "rui-menu.h" +#include "graphics.h" +#include "rui-image.h" +#include "rui-ruler.h" +#include "input-events.h" +#include "rui-description.h" + +static rui_screen *rui_screens = NULL; +static int rui_screens_num = 0, rui_current_screen = 0; + +rui_screen * get_current_screen(void) +{ + return &rui_screens[rui_current_screen]; +} + +int get_current_screen_id(void) +{ + return rui_current_screen; +} + +void rui_draw(void) +{ + rui_screen *cs; + + cs = get_current_screen(); + if (cs->style) + gr_set_color(cs->style->c_background); + gr_clear(); + rui_images_draw(); + rui_animations_draw(); + + if (cs->rulers) + rui_rulers_draw(cs->rulers); + + if (cs->menu) + rui_menu_draw(cs->menu); + + if (cs->description) + rui_description_draw(cs->description); + + if (cs->progress_bar) + rui_progress_bar_draw(cs->progress_bar); + + if (cs->draw) + cs->draw(); + + gr_flip(); +} + +/* Returns need_repaint */ +bool rui_screen_switch(int screen) +{ + if (screen == RUI_SCREEN_CURRENT || screen == get_current_screen_id()) + return false; /* Don't need to repaint */ + + if (screen == RUI_SCREEN_BACK) { + rui_screen *cs; + + cs = get_current_screen(); + return rui_screen_switch(cs->screen_back); + } + + rui_current_screen = screen; + if (rui_screens[screen].menu) + rui_menu_init(rui_screens[screen].menu); + + if (rui_screens[screen].progress_bar) + rui_progress_bar_set_progress( + rui_screens[screen].progress_bar, 0); + + if (rui_screens[screen].on_enter) + rui_screens[screen].on_enter(); + + return true; /* Need to repaint */ +} + +bool rui_init(rui_screen *screens, int screens_num, int current_screen, + rui_image *images, int images_num, + rui_animation *animations, int animations_num) +{ + if (!gr_init()) + return false; + + rui_screens = screens; + rui_screens_num = screens_num; + rui_current_screen = current_screen; + rui_images_init(images, images_num, animations, animations_num); + return true; +} + +void rui_exit(void) +{ + rui_images_exit(); + gr_exit(); +} diff --git a/src/librui/rui.h b/src/librui/rui.h new file mode 100644 index 0000000..765092b --- /dev/null +++ b/src/librui/rui.h @@ -0,0 +1,72 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "graphics.h" +#include "rui-menu.h" +#include "rui-image.h" +#include "rui-ruler.h" +#include "rui-description.h" +#include "rui-progress-bar.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*rui_screen_on_enter)(void); +typedef void (*rui_screen_draw)(void); + +typedef struct { + color c_background; +} rui_screen_style; + +typedef enum { + RUI_SCREEN_BACK = -2, + RUI_SCREEN_CURRENT = -1 +} rui_screen_id; + +typedef struct { + rui_screen_style *style; + rui_menu *menu; + rui_description *description; + rui_ruler *rulers; + rui_progress_bar *progress_bar; + int *images; + rui_animation_id *animations; + int rulers_num; + rui_screen_on_enter on_enter; + rui_screen_draw draw; + int screen_back; + int allow_force_reboot; +} rui_screen; + +bool rui_init(rui_screen *screens, int screens_num, int current_screen, + rui_image *images, int images_num, + rui_animation *animations, int animations_num); +void rui_exit(void); +void rui_draw(void); +bool rui_screen_switch(int screen); /* Returns need_repaint */ +rui_screen *get_current_screen(void); +int get_current_screen_id(void); + +#ifdef __cplusplus +} +#endif diff --git a/src/librui/tdm-if.c b/src/librui/tdm-if.c new file mode 100755 index 0000000..7f2371b --- /dev/null +++ b/src/librui/tdm-if.c @@ -0,0 +1,360 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil -*- + * + * system-recovery + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Based on tdm-if.c from tota-ua. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tdm-if.h" + +#define LOGD(format, ...) printf("[TDM-IF] " format "\n", ##__VA_ARGS__) + +#define C(b, m) (((b) >> (m)) & 0xFF) +#define B(c, s) ((((unsigned int)(c)) & 0xff) << (s)) +#define FOURCC(a, b, c, d) (B(d, 24) | B(c, 16) | B(b, 8) | B(a, 0)) +#define FOURCC_STR(id) C(id, 0), C(id, 8), C(id, 16), C(id, 24) +#define FOURCC_ID(str) FOURCC(((char*)str)[0], ((char*)str)[1], ((char*)str)[2], ((char*)str)[3]) + +static tdm_if_disp s_st_disp; + +static void tdm_if_display_commit_handler_cb(tdm_output *output, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, + void *user_data) +{ + LOGD("commit_handle_cb!!"); + + return ; +} + +int tdm_if_display_init(void) +{ + const tdm_output_mode *output_modes, *preferred_mode; + tdm_info_layer layer_info; + tdm_layer_capability layer_caps; + tdm_output_conn_status conn_status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED; + tdm_output_type output_type = TDM_OUTPUT_TYPE_Unknown; + tdm_output *output = NULL; + int buf_cnt; + tdm_error err = TDM_ERROR_NONE; + tdm_if_disp *st_disp = &s_st_disp; + int i, j; + int layer_count = 0; + int output_count = 0; + + LOGD("START"); + + st_disp->disp = tdm_display_init(&err); + if (!st_disp->disp) { + LOGD("failed to init tdm_display. error num = %d", err); + goto exit; + } + + err = tdm_display_get_fd(st_disp->disp, &st_disp->tdm_fd); + if (err != TDM_ERROR_NONE) { + LOGD("failed to get tdm fd. error num = %d", err); + goto exit; + } + + st_disp->drm_fd = tdm_helper_get_fd("TDM_DRM_MASTER_FD"); + if (st_disp->drm_fd == -1) { + LOGD("failed to get tdm fd. error num = %d", err); + goto exit; + } + + err = tdm_display_get_output_count(st_disp->disp, &output_count); + if (err != TDM_ERROR_NONE) { + LOGD("failed to get output count. error num = %d", err); + goto exit; + } + + if (output_count < 1) { + LOGD("insufficient number of outputs"); + goto exit; + } + + for (i = 0; i < output_count; i++) { + output = tdm_display_get_output(st_disp->disp, i, &err); + if (err != TDM_ERROR_NONE) { + LOGD("failed to get outout. error num = %d", err); + goto exit; + } + + err = tdm_output_get_output_type(output, &output_type); + if (err != TDM_ERROR_NONE) { + LOGD("failed to get output type. error num = %d", err); + goto exit; + } + + err = tdm_output_get_conn_status(output, &conn_status); + if (err != TDM_ERROR_NONE) { + LOGD("failed to get output connection status. error num = %d", err); + goto exit; + } + + LOGD("output_type=%d conn_status=%d", output_type, conn_status); + if ((output_type == TDM_OUTPUT_TYPE_LVDS) || + (output_type == TDM_OUTPUT_TYPE_DSI)) { + int cnt = 0; + err = tdm_output_get_available_modes(output, &output_modes, &cnt); + if (err != TDM_ERROR_NONE) { + LOGD("failed to get output available modes. error num = %d", err); + goto exit; + } + LOGD("%d output modes available", cnt); + + preferred_mode = output_modes; + for (j = 0; j < cnt; j++) { + if (output_modes[i].type & TDM_OUTPUT_MODE_TYPE_PREFERRED) { + preferred_mode = &output_modes[i]; + break; + } + } + + /* GET MODE INFO */ + st_disp->output = output; + st_disp->width = preferred_mode->hdisplay; + st_disp->height = preferred_mode->vdisplay; + + err = tdm_output_set_mode(st_disp->output, preferred_mode); + if (err != TDM_ERROR_NONE) { + LOGD("unable to set mode: \"%s\"", preferred_mode->name); + goto exit; + } + + /* informational */ + unsigned int width_mm = 0; + unsigned int height_mm = 0; + err = tdm_output_get_physical_size(output, &width_mm, &height_mm); + LOGD("TDM_OUTPUT_MODE:name[%s] mode:wh[%d %d] mm[%d %d]", + preferred_mode->name, st_disp->width, st_disp->height, width_mm, height_mm); + + break; + } + } + + /* SET LAYER */ + err = tdm_output_get_layer_count(st_disp->output, &layer_count); + if (err != TDM_ERROR_NONE) { + LOGD("failed to get number of layers"); + goto exit; + } + if (layer_count < 1) { + LOGD("insufficient number of layers: %d", layer_count); + goto exit; + } + + for (i = 0; i < layer_count; i++) { + st_disp->layer = tdm_output_get_layer(st_disp->output, i, &err); + if (err != TDM_ERROR_NONE) { + LOGD("failed to get layer: %d", i); + goto exit; + } + + err = tdm_layer_get_capabilities(st_disp->layer, &layer_caps); + if (err != TDM_ERROR_NONE) { + LOGD("failed to get layer capabilities: %d", i); + goto exit; + } + + if ((layer_caps & TDM_LAYER_CAPABILITY_PRIMARY) && + (layer_caps & TDM_LAYER_CAPABILITY_GRAPHIC)) + break; + } + + layer_info.src_config.size.h = st_disp->width; + layer_info.src_config.size.v = st_disp->height; + layer_info.src_config.pos.x = 0; + layer_info.src_config.pos.y = 0; + layer_info.src_config.pos.w = st_disp->width; + layer_info.src_config.pos.h = st_disp->height; + layer_info.src_config.format = TBM_FORMAT_ARGB8888; + layer_info.dst_pos.x = 0; + layer_info.dst_pos.y = 0; + layer_info.dst_pos.w = st_disp->width; + layer_info.dst_pos.h = st_disp->height; + layer_info.transform = TDM_TRANSFORM_NORMAL; + + err = tdm_layer_set_info(st_disp->layer, &layer_info); + if (err != TDM_ERROR_NONE) { + LOGD("failed to get output layer. error num = %d", err); + goto exit; + } + + for (buf_cnt = 0; buf_cnt < MAX_BUF; buf_cnt++) { + tbm_surface_error_e e; + tbm_surface_info_s si; + + st_disp->surf[buf_cnt] = tbm_surface_internal_create_with_flags(st_disp->width, + st_disp->height, + TBM_FORMAT_ARGB8888, + TBM_BO_SCANOUT); + e = get_last_result(); + if (e != TBM_SURFACE_ERROR_NONE || + !st_disp->surf[buf_cnt]){ + LOGD("failed to create tbm_surface!"); + goto exit; + } + + e = tbm_surface_get_info(st_disp->surf[buf_cnt], &si); + if (e != TBM_SURFACE_ERROR_NONE) { + LOGD("failed to get info for tbm_surface!"); + goto exit; + } + + LOGD("surface created: %dx%d %c%c%c%c bpp:%d size:%d planes:%d stride:%d", + si.width, si.height, + FOURCC_STR(si.format), + si.bpp, si.size, si.num_planes, + si.planes[0].stride); + + if (si.num_planes != 1) { + LOGD("unsupported number of planes: %d", si.num_planes); + goto exit; + } + st_disp->buffer_size = si.planes[0].size; + st_disp->stride = si.planes[0].stride; + } + + + st_disp->current_buf_id = 0; + + for (i = 0; i < MAX_BUF; i++) { + tdm_if_buffer_update(NULL); + tdm_if_display_update(); + } + + LOGD("DONE"); + return 0; +exit: + tdm_if_display_deinit(); + return -1; +} + +void tdm_if_display_deinit(void) +{ + int buf_cnt = 0; + tdm_if_disp *st_disp = &s_st_disp; + + tdm_if_lcd_off(); + + if (st_disp->disp != NULL) { + /* RELEASE RESOURCE */ + for (buf_cnt = 0; buf_cnt < MAX_BUF; buf_cnt++) { + if (st_disp->surf[buf_cnt] != NULL) + tbm_surface_destroy(st_disp->surf[buf_cnt]); + } + + tdm_display_deinit(st_disp->disp); + st_disp->disp = NULL; + } +} + +int tdm_if_display_width(void) +{ + tdm_if_disp *st_disp = &s_st_disp; + return st_disp->width; +} + +int tdm_if_display_height(void) +{ + tdm_if_disp *st_disp = &s_st_disp; + return st_disp->height; +} + +int tdm_if_display_bufsize(void) +{ + tdm_if_disp *st_disp = &s_st_disp; + return st_disp->buffer_size; +} + +int tdm_if_display_stride(void) +{ + tdm_if_disp *st_disp = &s_st_disp; + return st_disp->stride; +} + +void tdm_if_buffer_update(unsigned char *buffer) +{ + tdm_if_disp *st_disp = &s_st_disp; + int buf_cnt = st_disp->current_buf_id; + tbm_surface_info_s tbm_surface_info; + tbm_surface_error_e err; + uint32_t *surface; + + err = tbm_surface_map(st_disp->surf[buf_cnt], TBM_SURF_OPTION_WRITE, &tbm_surface_info); + if (err != TBM_SURFACE_ERROR_NONE) { + LOGD("tbm_surface_map failed!"); + return; + } + + surface = (uint32_t*)tbm_surface_info.planes[0].ptr; + + if (buffer == NULL) + memset(surface, 0, st_disp->buffer_size); + else + memcpy(surface, buffer, st_disp->buffer_size); + + tbm_surface_unmap(st_disp->surf[buf_cnt]); +} + +void tdm_if_display_update(void) +{ + /* DISPLAY UPDATE */ + int buf_cnt = 0; + tdm_if_disp *st_disp = &s_st_disp; + + buf_cnt = st_disp->current_buf_id; + st_disp->current_buf_id = (st_disp->current_buf_id + 1)%MAX_BUF; + + tdm_layer_set_buffer(st_disp->layer, st_disp->surf[buf_cnt]); + + // TODO: sync or async?? + tdm_output_commit(st_disp->output, 1, tdm_if_display_commit_handler_cb, st_disp); +} + +void tdm_if_lcd_on(void) +{ + tdm_if_disp *st_disp = &s_st_disp; + + LOGD("DPMS ON!"); + tdm_output_set_dpms(st_disp->output, TDM_OUTPUT_DPMS_ON); +} + +void tdm_if_lcd_off(void) +{ + tdm_if_disp *st_disp = &s_st_disp; + + LOGD("DPMS OFF!"); + tdm_output_set_dpms(st_disp->output, TDM_OUTPUT_DPMS_OFF); +} diff --git a/src/librui/tdm-if.h b/src/librui/tdm-if.h new file mode 100755 index 0000000..9c92e7d --- /dev/null +++ b/src/librui/tdm-if.h @@ -0,0 +1,69 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil -*- + * + * system-recovery + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Based on tdm-if.h from tota-ua. + */ + +#ifndef __TDM_IF_H__ +#define __TDM_IF_H__ + +#include +#include +#include +#include +#include + +#define MAX_BUF 2 +#define RGB32_BPP 32 +#define RGB32_PITCH 4 + +typedef struct _tdm_if_disp { + tdm_display *disp; + tdm_output *output; + tdm_layer *layer; + int tdm_fd; + int drm_fd; + tbm_surface_h surf[MAX_BUF]; + int buffer_size; + int width; + int height; + int stride; + int current_buf_id; +} tdm_if_disp; + +typedef enum { + FRONT_BUFFER = 0, + BACK_BUFFER +} BUFFER_TYPE; + +extern tdm_if_disp s_disp; + +int tdm_if_display_init(void); +void tdm_if_display_deinit(void); +void tdm_if_display_update(void); +int tdm_if_display_width(void); +int tdm_if_display_height(void); +int tdm_if_display_bufsize(void); +int tdm_if_display_stride(void); + +void tdm_if_buffer_update(unsigned char *buffer); + +void tdm_if_lcd_on(void); +void tdm_if_lcd_off(void); + +#endif /* __TDM_IF_H__ */ diff --git a/src/shared/log.c b/src/shared/log.c new file mode 100644 index 0000000..fd08409 --- /dev/null +++ b/src/shared/log.c @@ -0,0 +1,414 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * libsystem + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" + +#define FILEBUF 1024 + +static inline void __cleanup_free_func(void *p) +{ + free(*(void**) p); +} + +static inline bool isempty(const char *p) +{ + return !p || !p[0]; +} + +#define _cleanup_(x) __attribute__((cleanup(x))) + +#define _cleanup_free_ _cleanup_(__cleanup_free_func) + +#define new(t, n) ((t*) malloc(sizeof(t) * (n))) + +#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \ + for ((state) = NULL, (word) = split((s), &(length), (separator), &(state)); (word); (word) = split((s), &(length), (separator), &(state))) + +#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0) + +static FILE *log_f[LOG_TYPE_MAX]; +static int stdout_bak = -1; +static int stderr_bak = -1; + +static int log_level = LOG_DEBUG; + +static const char const *log_priority_name[] = { + [LOG_ALERT] = "alert", + [LOG_CRIT] = "crit", + [LOG_DEBUG] = "debug", + [LOG_EMERG] = "emerg", + [LOG_ERR] = "err", + [LOG_INFO] = "info", + [LOG_NOTICE] = "notice", + [LOG_WARNING] = "warning" +}; + +void set_log_level(int level) +{ + log_level = level; +} + +int get_log_level(void) +{ + return log_level; +} + +static bool __quote_complete(char *str, size_t l, char q) +{ + char *s, *s2; + + assert(str); + + if (!l) + return true; + + s = strchr(str, q); + if (!s || (s - str) > l) + return true; + + s = strchr(s + 1, q); + if (!s || (s - str) > l) + return false; + + s2 = strchr(s + 1, q); + if (!s2 || (s2 - str) > l) + return true; + + return __quote_complete(s + 1, l - (s + 1 - str), q); +} + +#define QUOTES "\"\'" +static bool quote_complete(char *str, size_t l) +{ + char quotes[] = QUOTES; + int i; + + assert(str); + + if (!l) + return true; + + for (i = 0; quotes[i]; i++) { + if (!__quote_complete(str, l, quotes[i])) + return false; + } + + return true; +} + +static char *split(const char *c, size_t *l, const char *separator, char **state) +{ + bool separator_include_quotes; + char *current; + size_t s; + + assert(c); + assert(l); + assert(separator); + assert(state); + + current = *state ? *state : (char *) c; + if (!*current || *c == 0) + return NULL; + + *l = 0; + separator_include_quotes = !!strspn(separator, QUOTES); + current += strspn(current, separator); + + while ((s = strcspn(current + *l, separator))) { + *l += s; + if (separator_include_quotes || + quote_complete(current, *l)) + break; + (*l)++; + } + + *state = current + *l; + + return (char *) current; +} + +static int stdpath_dup_and_backup(FILE *f) +{ + int r, fd; + + stdout_bak = dup(STDOUT_FILENO); + stderr_bak = dup(STDERR_FILENO); + + fd = fileno(f); + r = dup2(fd, STDOUT_FILENO); + if (r < 0) + return -errno; + + r = dup2(fd, STDERR_FILENO); + if (r < 0) + return -errno; + + return 0; +} + +static int stdpath_restore(void) +{ + int r; + + if (stdout_bak >= 0) { + r = dup2(stdout_bak, STDOUT_FILENO); + if (r < 0) + return -errno; + + close(stdout_bak); + stdout_bak = -1; + } + + if (stderr_bak >= 0) { + r = dup2(stderr_bak, STDERR_FILENO); + if (r < 0) + return -errno; + + close(stderr_bak); + stderr_bak = -1; + } + + return 0; +} + +int log_open(enum log_mask log_set, const char *path) +{ + int r; + + if (log_set & LOG_MASK_FILE) { + assert(path); + + log_f[LOG_TYPE_FILE] = fopen(path, "w+"); + if (!log_f[LOG_TYPE_FILE]) + return -errno; + + /* If standard output/error were not set, redirect + * standard output/error to log file */ + if (!(log_set & LOG_MASK_STANDARD)) { + r = stdpath_dup_and_backup(log_f[LOG_TYPE_FILE]); + if (r < 0) + return r; + } + } + + if (log_set & LOG_MASK_KMSG) { + log_f[LOG_TYPE_KMSG] = fopen("/dev/kmsg", "we"); + if (!log_f[LOG_TYPE_KMSG]) + return -errno; + + /* If standard output/error or log file were not set, + * redirect standard output/error to kmsg */ + if (!(log_set & LOG_MASK_STANDARD) && + !(log_set & LOG_MASK_FILE)) { + r = stdpath_dup_and_backup(log_f[LOG_TYPE_KMSG]); + if (r < 0) + return r; + } + } + + return 0; +} + +int log_close(void) +{ + enum log_type type; + + for (type = 0; type < LOG_TYPE_MAX; type++) { + if (type == LOG_TYPE_STANDARD || !log_f[type]) + continue; + + fclose(log_f[type]); + log_f[type] = NULL; + } + + return stdpath_restore(); +} + +static int _log_write( + int level, + const char *file, + int line, + const char *func, + const char *format, + va_list ap) +{ + char buff[LINE_MAX]; + enum log_type type; + + vsnprintf(buff, LINE_MAX, format, ap); + + for (type = 0; type < LOG_TYPE_MAX; type++) { + if (type != LOG_TYPE_STANDARD && !log_f[type]) + continue; + + switch (type) { + case LOG_TYPE_STANDARD: + fprintf(level <= LOG_ERR ? stderr : stdout, + "%s\n", buff); + break; + case LOG_TYPE_FILE: + fprintf(log_f[LOG_TYPE_FILE], + "%-8s: %s\n", log_priority_name[level], buff); + fflush(log_f[LOG_TYPE_FILE]); + break; + case LOG_TYPE_KMSG: + fprintf(log_f[LOG_TYPE_KMSG], + "initrd: %s\n", buff); + break; + default: + break; + } + } + + return 0; +} + +int log_write( + int level, + const char*file, + int line, + const char *func, + const char *format, ...) +{ + va_list ap; + int r; + + va_start(ap, format); + r = _log_write(level, file, line, func, format, ap); + va_end(ap); + + return r; +} + +int log_move(const char *to) +{ + _cleanup_free_ char *buf = NULL; + FILE *w = NULL; + size_t len; + int r; + + assert(to); + + if (!log_f[LOG_TYPE_FILE]) + return 0; + + buf = new(char, FILEBUF); + if (!buf) { + r = -ENOMEM; + goto error; + } + + w = fopen(to, "a+"); + if (!w) { + r = -errno; + goto error; + } + + r = fseek(log_f[LOG_TYPE_FILE], 0, SEEK_SET); + if (r < 0) { + r = -errno; + goto error; + } + + r = fflush(log_f[LOG_TYPE_FILE]); + if (r < 0) { + r = -errno; + goto error; + } + + while ((len = fread(buf, sizeof(char), FILEBUF, log_f[LOG_TYPE_FILE])) > 0) { + if (fwrite(buf, sizeof(char), len, w) != len) { + r = -errno; + goto error; + } + } + + fclose(log_f[LOG_TYPE_FILE]); + log_f[LOG_TYPE_FILE] = w; + + r = stdpath_dup_and_backup(log_f[LOG_TYPE_FILE]); + if (r < 0) + goto error; + + return 0; + +error: + if (w) + fclose(w); + + log_dbg("Failed to move log: %d\n", errno); + + return r; +} + +enum log_mask parse_log_type(const char *type) +{ + char *word, *state; + enum log_mask mask = 0; + size_t l; + + if (!type) + return LOG_MASK_INVALID; + + FOREACH_WORD_SEPARATOR(word, l, type, "+", state) { + + if (strncaseeq(word, "standard", l)) + mask |= LOG_MASK_STANDARD; + else if (strncaseeq(word, "file", l)) + mask |= LOG_MASK_FILE; + else if (strncaseeq(word, "kmsg", l)) + mask |= LOG_MASK_KMSG; + else + return LOG_MASK_INVALID; + } + + return mask; +} + +int config_parse_log_type( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + int ltype, + const char *rvalue, + void *data) +{ + + enum log_mask *mask = data; + + if (isempty(rvalue)) + return 0; + + *mask = parse_log_type(rvalue); + + return *mask == LOG_MASK_INVALID ? -EINVAL : 0; +} diff --git a/src/shared/log.h b/src/shared/log.h new file mode 100644 index 0000000..ce26b1e --- /dev/null +++ b/src/shared/log.h @@ -0,0 +1,71 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * libsystem + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +enum log_type { + LOG_TYPE_INVALID = -1, + LOG_TYPE_STANDARD = 0, + LOG_TYPE_FILE, + LOG_TYPE_KMSG, + LOG_TYPE_MAX +}; + +enum log_mask { + LOG_MASK_INVALID = -1, + LOG_MASK_STANDARD = 1 << LOG_TYPE_STANDARD, + LOG_MASK_FILE = 1 << LOG_TYPE_FILE, + LOG_MASK_KMSG = 1 << LOG_TYPE_KMSG, +}; + +#define log_full(level, ...) \ + do { \ + log_write((level), __FILE__, __LINE__, __func__, __VA_ARGS__); \ + } while (0) + +void set_log_level(int level); +int get_log_level(void); +int log_open(enum log_mask log_set, const char *path); +int log_close(void); +int log_write(int level, const char*file, int line, const char *func, const char *format, ...); +int log_move(const char *to); +enum log_mask parse_log_type(const char *type); +int config_parse_log_type(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data); + +#define log_dbg(format, ...) \ + do { \ + if (get_log_level() >= LOG_DEBUG) \ + log_full(LOG_DEBUG, format, ##__VA_ARGS__); \ + } while (0) + +#define log_err(format, ...) \ + do { \ + if (get_log_level() >= LOG_ERR) \ + log_full(LOG_ERR, format, ##__VA_ARGS__); \ + } while (0) + +#define log_info(format, ...) \ + do { \ + if (get_log_level() >= LOG_INFO) \ + log_full(LOG_INFO, format, ##__VA_ARGS__); \ + } while (0) diff --git a/src/system-recovery/.gitignore b/src/system-recovery/.gitignore new file mode 100644 index 0000000..9cda7ea --- /dev/null +++ b/src/system-recovery/.gitignore @@ -0,0 +1,2 @@ +/50-system-recovery.list +/recovery-init \ No newline at end of file diff --git a/src/system-recovery/50-system-recovery-sprd.list b/src/system-recovery/50-system-recovery-sprd.list new file mode 100644 index 0000000..6b30709 --- /dev/null +++ b/src/system-recovery/50-system-recovery-sprd.list @@ -0,0 +1,24 @@ +# ---- Target contents ----------------------------------------------------- # +DIRECTORIES=" +/usr/lib/bufmgr +/usr/lib/tdm +" + +DIR_SYMLINKS=" +" + +MVWITHLIBS=" +" + +WITHLIBS=" +/usr/lib/bufmgr/libtbm_sprd.so.0.0.0 +/usr/lib/tdm/libtdm-sprd.so +" + +# LinkFileName:Target +SYMLINKS=" +/usr/lib/bufmgr/libtbm_default.so:libtbm_sprd.so +/usr/lib/bufmgr/libtbm_sprd.so.0:libtbm_sprd.so.0.0.0 +/usr/lib/bufmgr/libtbm_sprd.so:libtbm_sprd.so.0.0.0 +/usr/lib/tdm/libtdm-default.so:libtdm-sprd.so +" diff --git a/src/system-recovery/50-system-recovery.list.m4.in b/src/system-recovery/50-system-recovery.list.m4.in new file mode 100644 index 0000000..a8e3344 --- /dev/null +++ b/src/system-recovery/50-system-recovery.list.m4.in @@ -0,0 +1,44 @@ +# ---- Target contents ----------------------------------------------------- # +DIRECTORIES=" +/dev +/etc +/proc +/smack +/sys +/system +/tmp +/usr/bin +/usr/lib +/usr/sbin +" + +MVWITHLIBS=" +@SYSTEM_RECOVERY_LIBEXEC_DIR@/recovery-init +@INITRD_RECOVERY_LIBEXEC_DIR@/minireboot +m4_ifdef(`RECOVERY_GUI', +`@SYSTEM_RECOVERY_IMAGE_DIR@/font.png +@SYSTEM_RECOVERY_IMAGE_DIR@/menu-title.png +@SYSTEM_RECOVERY_IMAGE_DIR@/tizen-anim.png +@SYSTEM_RECOVERY_IMAGE_DIR@/warning.png') +m4_ifdef(`RECOVERY_GUI', `@SYSTEM_RECOVERY_LIBEXEC_DIR@/system-recovery.gui', `@SYSTEM_RECOVERY_LIBEXEC_DIR@/system-recovery.non_gui') +" + +WITHLIBS=" +/usr/bin/bash +/usr/bin/mount +/usr/bin/sync +/usr/bin/touch +/usr/bin/umount +/usr/sbin/blkid +/usr/bin/ls +/usr/sbin/agetty +" + +VERBATIMS=" +@SYSTEM_RECOVERY_DATA_DIR@/system-recovery.cfg +" + +# LinkFileName:Target +SYMLINKS=" +/sbin/recovery-init:@SYSTEM_RECOVERY_LIBEXEC_DIR@/recovery-init +" diff --git a/src/system-recovery/process-util.c b/src/system-recovery/process-util.c new file mode 100644 index 0000000..a5a34b9 --- /dev/null +++ b/src/system-recovery/process-util.c @@ -0,0 +1,90 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _POSIX_SOURCE + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "process-util.h" +#include "system-recovery.h" /* For LOGD */ + +int process_exec(process_exec_type sync, char *argv[]) +{ + pid_t pid; + struct sigaction act, oldact; + int r = 0; + + if (!argv) + return -EINVAL; + + /* Use default signal handler */ + act.sa_handler = SIG_DFL; + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + + if (sigaction(SIGCHLD, &act, &oldact) < 0) + return -errno; + + pid = fork(); + if (pid < 0) { /* Error */ + LOGD("Failed to fork\n"); + r = -errno; + } else if (!pid) { /* Child */ + int i; + + for (i = 0; i < _NSIG; i++) + signal(i, SIG_DFL); + + r = execv(argv[0], (char **)argv); + if (r < 0) + exit(EXIT_FAILURE); + } else { /* Parent */ + int status; + + if (sync == PROCESS_NON_WAIT) + return pid; + + /* Wait for child */ + if (waitpid(pid, &status, 0) != -1) { + if (WIFEXITED(status)) { /* Terminated normally */ + LOGD("%d terminated by exit(%d)\n", pid, + WEXITSTATUS(status)); + return WEXITSTATUS(status); + } else if (WIFSIGNALED(status)) + LOGD("%d terminated by signal %d\n", pid, + WTERMSIG(status)); + else if (WIFSTOPPED(status)) + LOGD("%d stopped by signal %d\n", pid, + WSTOPSIG(status)); + } else + LOGD("%d waitpid() failed - %d\n", pid, errno); + } + + if (sigaction(SIGCHLD, &oldact, NULL) < 0) + LOGD("failed to restore sigaction\n"); + + return r; +} diff --git a/src/system-recovery/process-util.h b/src/system-recovery/process-util.h new file mode 100644 index 0000000..016c51a --- /dev/null +++ b/src/system-recovery/process-util.h @@ -0,0 +1,34 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + PROCESS_NON_WAIT, + PROCESS_WAIT_CHILD +} process_exec_type; + +int process_exec(process_exec_type sync, char *argv[]); + +#ifdef __cplusplus +} +#endif diff --git a/src/system-recovery/recovery-action-set.in b/src/system-recovery/recovery-action-set.in new file mode 100755 index 0000000..a6ddf8c --- /dev/null +++ b/src/system-recovery/recovery-action-set.in @@ -0,0 +1,18 @@ +#!/bin/sh + +CONFIG_FILE="@SYSTEM_RECOVERY_DATA_DIR@/system-recovery.cfg" +ACTION_FILE="@SYSTEM_RECOVERY_ACTION_FILE@" + +actions=`cat $CONFIG_FILE | sed -ne '/^action_handlers[[:space:]]*=[[:space:]]*{/,/}/ p' | sed -ne 's/[[:space:]]*\(.*\)[[:space:]]*=[[:space:]]*\".*/\1/ p'` + +for a in ${actions} +do + if [ "$a" = "${1}" ] + then + echo "${1}" > $ACTION_FILE + echo "Action changed to ${1}" + exit + fi +done + +echo "Action ${1} is not specified in configuration." diff --git a/src/system-recovery/recovery-headless.c b/src/system-recovery/recovery-headless.c new file mode 100644 index 0000000..e07035c --- /dev/null +++ b/src/system-recovery/recovery-headless.c @@ -0,0 +1,68 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "log.h" +#include "system-recovery.h" + +static char *get_action_from_config(config_t *cfg) +{ + config_setting_t *node; + const char *action; + + node = config_lookup(cfg, "headless_action"); + if (!node) + return NULL; + + action = config_setting_get_string(node); + + return strdup(action); +} + +int recovery_headless(config_t *cfg) +{ + config_setting_t *node; + + node = config_lookup(cfg, "action_handlers"); + if (!node) + return -ENOENT; + + char *action = get_action_from_cmdline(); + if (!action) + action = get_action_from_file(); + if (!action) + action = get_action_from_config(cfg); + if (!action) + return -ENOENT; + + const char *handler; + int r = config_setting_lookup_string(node, action, &handler); + free(action); + + if (r == CONFIG_FALSE) + return -ENOENT; + + return system(handler); +} diff --git a/src/system-recovery/recovery-init.in b/src/system-recovery/recovery-init.in new file mode 100644 index 0000000..bdf5338 --- /dev/null +++ b/src/system-recovery/recovery-init.in @@ -0,0 +1,79 @@ +#!/bin/sh + +SYSTEM_RECOVERY_GUI="@SYSTEM_RECOVERY_LIBEXEC_DIR@/system-recovery.gui" +SYSTEM_RECOVERY_NON_GUI="@SYSTEM_RECOVERY_LIBEXEC_DIR@/system-recovery.non_gui" +FAKE_ROOT=/system + +MOUNT="/usr/bin/mount" +BLKID="/usr/sbin/blkid" +REBOOT="@INITRD_RECOVERY_LIBEXEC_DIR@/minireboot" +SYNC="/usr/bin/sync" +UMOUNT="/usr/bin/umount" + +#------------------------------------------------ +# get partition id +#------------------------------------------------ +get_partition_id() { + PART_ROOTFS=$("$BLKID" --match-token PARTLABEL=ROOTFS -o device || "$BLKID" --match-token LABEL=rootfs -o device) + PART_SYSTEM_DATA=$("$BLKID" --match-token PARTLABEL=SYSTEM-DATA -o device || "$BLKID" --match-token LABEL=system-data -o device) + PART_USER=$("$BLKID" --match-token PARTLABEL=USER -o device || "$BLKID" --match-token LABEL=user -o device) +} + +#------------------------------------------------ +# mount_partitions +#------------------------------------------------ +mount_partitions() { + echo "mount partitions" + get_partition_id + + "$MOUNT" -t ext4 ${PART_ROOTFS} ${FAKE_ROOT} -o ro + "$MOUNT" -t ext4 ${PART_SYSTEM_DATA} ${FAKE_ROOT}/opt + "$MOUNT" -t ext4 ${PART_USER} ${FAKE_ROOT}/opt/usr + + "$MOUNT" -t proc none ${FAKE_ROOT}/proc + "$MOUNT" -t sysfs none ${FAKE_ROOT}/sys + "$MOUNT" -t smackfs smackfs ${FAKE_ROOT}/sys/fs/smackfs + "$MOUNT" -t devtmpfs devtmpfs ${FAKE_ROOT}/dev + "$MOUNT" -t devpts devpts ${FAKE_ROOT}/dev/pts + "$MOUNT" -t tmpfs tmpfs ${FAKE_ROOT}/tmp -o mode=1777,smackfsroot=* +} + +#------------------------------------------------ +# umount_partitions +#------------------------------------------------ +umount_partitions() { + echo "umount partitions" + "$SYNC" + + "$UMOUNT" ${FAKE_ROOT}/opt/usr + "$UMOUNT" ${FAKE_ROOT}/opt + "$UMOUNT" ${FAKE_ROOT} +} + +#------------------------------------------------ +# do_reboot +#------------------------------------------------ +do_reboot() { + echo "Reboot" + "$SYNC" + "$REBOOT" + while [ 1 ] + do + sleep 1 + echo "." + done +} + +#------------------------------------------------ +# system-recovery initrc +#------------------------------------------------ +echo "Starting system recovery." +mount_partitions + +# For debugging - It should be deleted on Release +/sbin/agetty -l /bin/sh -n --keep-baud 115200,38400,9600 ttyS1 linux & + +[ -x "${SYSTEM_RECOVERY_GUI}" ] && "${SYSTEM_RECOVERY_GUI}" || "${SYSTEM_RECOVERY_NON_GUI}" + +umount_partitions +do_reboot diff --git a/src/system-recovery/recovery-main.c b/src/system-recovery/recovery-main.c new file mode 100644 index 0000000..dd30ce9 --- /dev/null +++ b/src/system-recovery/recovery-main.c @@ -0,0 +1,125 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _POSIX_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include // for COMMAND_LINE_SIZE + +#include "system-recovery.h" + +void sys_power_reboot(void) +{ + reboot(RB_AUTOBOOT); +} + +#define KERNEL_CMDLINE_KEY "tizen.recovery" +#define ACTION_BUFFER_SIZE 256 +#define _STR(x) #x +#define STR(x) _STR(x) + +// looks for tizen.recovery= key in kernel command line +char *get_action_from_cmdline(void) +{ + FILE *fp; + char cmdline[COMMAND_LINE_SIZE]; + int len; + + fp = fopen("/proc/cmdline", "r"); + if (!fp) + return NULL; + + char *p = fgets(cmdline, sizeof cmdline, fp); + fclose(fp); + if (!p) + return NULL; + + const char *prefix = KERNEL_CMDLINE_KEY "="; + p = strstr(cmdline, prefix); + if (!p) + return NULL; + p += strlen(prefix); + + for (len = 0; *(p + len) != 0 && !isspace(*(p + len)); ++len) + ; /* skip */ + + return strndup(p, len); +} + +char *get_action_from_file(void) +{ + FILE *fp; + char buf[ACTION_BUFFER_SIZE]; + int ret; + + fp = fopen(SYSTEM_RECOVERY_ACTION_FILE, "r"); + if (!fp) { + LOGD("Could not open recovery action file\n"); + return NULL; + } + + ret = fscanf(fp, "%" STR(ACTION_BUFFER_SIZE) "s", buf); + fclose(fp); + if (unlink(SYSTEM_RECOVERY_ACTION_FILE) < 0) + LOGD("Could not unlink recovery action file: %m\n"); + + if (ret != 1) + return NULL; + + return strndup(buf, ACTION_BUFFER_SIZE); +} + +int main(void) +{ + config_t cfg; + int ret; + + LOGD("[main] recovery started.\n"); + + config_init(&cfg); + ret = config_read_file(&cfg, SYSTEM_RECOVERY_CONFIG_FILE); + if (ret == CONFIG_FALSE) { + LOGD("Can't read config file"); + return 1; + } + +#ifdef RECOVERY_GUI + ret = recovery_gui(&cfg); +#else + ret = recovery_headless(&cfg); +#endif + + LOGD("[main] recovery finished.\n"); + config_destroy(&cfg); + + return ret; +} diff --git a/src/system-recovery/recovery-rui-skin.h b/src/system-recovery/recovery-rui-skin.h new file mode 100644 index 0000000..fe2df56 --- /dev/null +++ b/src/system-recovery/recovery-rui-skin.h @@ -0,0 +1,136 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "graphics.h" + +#define RUI_COLOR_BACKGROUND BLACK +#define RUI_COLOR_TITLE (color) { .r = 27, .g = 199, .b = 204, .a = 255 } +#define RUI_COLOR_RULER RUI_COLOR_TITLE + +#define RUI_COLOR_MENU_BG_SELECTED RUI_COLOR_TITLE +#define RUI_COLOR_MENU_BG_UNSELECTED BLACK +#define RUI_COLOR_MENU_TEXT_SELECTED WHITE +#define RUI_COLOR_MENU_TEXT_UNSELECTED WHITE + +#define RUI_COLOR_DESCRIPTION_TITLE RUI_COLOR_TITLE +#define RUI_COLOR_DESCRIPTION_TEXT WHITE + +#define RUI_COLOR_PROGRESS_BAR_BAR YELLOW +#define RUI_COLOR_PROGRESS_BAR_BORDER RUI_COLOR_TITLE +#define RUI_COLOR_PROGRESS_BAR_BACKGROUND BLACK + +#ifdef FEATURE_DISPLAY_720X1280 +#define RUI_MENU_ITEM_HEIGHT 60 +#define RUI_MENU_ITEM_SPACING 8 +#define RUI_MENU_TEXT_POS_X 15 + +#define RUI_COMMON_MENU_POS_X 0 + +#define RUI_MAIN_MENU_POS_X RUI_COMMON_MENU_POS_X +#define RUI_MAIN_MENU_POS_Y 100 + +#define RUI_REBOOT_MENU_POS_X RUI_COMMON_MENU_POS_X +#define RUI_REBOOT_MENU_POS_Y 480 + +#define RUI_SAFE_MENU_POS_X RUI_COMMON_MENU_POS_X +#define RUI_SAFE_MENU_POS_Y 480 + +#define RUI_FACTORY_MENU_POS_X RUI_COMMON_MENU_POS_X +#define RUI_FACTORY_MENU_POS_Y 480 + +#define RUI_SD_RESTORE_MENU_POS_X RUI_COMMON_MENU_POS_X +#define RUI_SD_RESTORE_MENU_POS_Y 480 + +#define RUI_MAIN_SCREEN_DESCRIPTION_POS_X 15 +#define RUI_MAIN_SCREEN_DESCRIPTION_POS_Y 480 + +#define RUI_COMMON_SCREEN_DESCRIPTION_POS_X 15 +#define RUI_COMMON_SCREEN_DESCRIPTION_POS_Y 100 + +#define RUI_RULER_HEIGHT 2 + +#define RUI_RULER_TOP_POS_X 0 +#define RUI_RULER_TOP_POS_Y 80 +#define RUI_MAIN_SCREEN_RULER_POS_Y 420 + +#define RUI_PROGRESS_BAR_BORDER_WIDTH 1 +#define RUI_PROGRESS_BAR_HEIGHT 20 + +#define RUI_SD_RESTORE_RUN_SCREEN_PROGRESS_BAR_POS_X 5 +#define RUI_SD_RESTORE_RUN_SCREEN_PROGRESS_BAR_POS_Y 600 + +#else +#define RUI_MENU_ITEM_HEIGHT 50 +#define RUI_MENU_ITEM_SPACING 5 +#define RUI_MENU_TEXT_POS_X 5 + +#define RUI_COMMON_MENU_POS_X 0 + +#define RUI_MAIN_MENU_POS_X RUI_COMMON_MENU_POS_X +#define RUI_MAIN_MENU_POS_Y 100 + +#define RUI_REBOOT_MENU_POS_X RUI_COMMON_MENU_POS_X +#define RUI_REBOOT_MENU_POS_Y 160 + +#define RUI_SAFE_MENU_POS_X RUI_COMMON_MENU_POS_X +#define RUI_SAFE_MENU_POS_Y 240 + +#define RUI_FACTORY_MENU_POS_X RUI_COMMON_MENU_POS_X +#define RUI_FACTORY_MENU_POS_Y 240 + +#define RUI_SD_RESTORE_MENU_POS_X RUI_COMMON_MENU_POS_X +#define RUI_SD_RESTORE_MENU_POS_Y 240 + +#define RUI_MAIN_SCREEN_DESCRIPTION_POS_X 5 +#define RUI_MAIN_SCREEN_DESCRIPTION_POS_Y 372 + +#define RUI_COMMON_SCREEN_DESCRIPTION_POS_X 5 +#define RUI_COMMON_SCREEN_DESCRIPTION_POS_Y 100 + +#define RUI_RULER_HEIGHT 2 + +#define RUI_RULER_TOP_POS_X 0 +#define RUI_RULER_TOP_POS_Y 60 +#define RUI_MAIN_SCREEN_RULER_POS_Y 347 + +#define RUI_PROGRESS_BAR_BORDER_WIDTH 1 +#define RUI_PROGRESS_BAR_HEIGHT 20 + +#define RUI_SD_RESTORE_RUN_SCREEN_PROGRESS_BAR_POS_X 5 +#define RUI_SD_RESTORE_RUN_SCREEN_PROGRESS_BAR_POS_Y 600 +#endif + +#define RUI_REBOOT_SCREEN_DESCRIPTION_POS_X RUI_COMMON_SCREEN_DESCRIPTION_POS_X +#define RUI_REBOOT_SCREEN_DESCRIPTION_POS_Y RUI_COMMON_SCREEN_DESCRIPTION_POS_Y + +#define RUI_SAFE_SCREEN_DESCRIPTION_POS_X RUI_COMMON_SCREEN_DESCRIPTION_POS_X +#define RUI_SAFE_SCREEN_DESCRIPTION_POS_Y RUI_COMMON_SCREEN_DESCRIPTION_POS_Y + +#define RUI_FACTORY_SCREEN_DESCRIPTION_POS_X RUI_COMMON_SCREEN_DESCRIPTION_POS_X +#define RUI_FACTORY_SCREEN_DESCRIPTION_POS_Y RUI_COMMON_SCREEN_DESCRIPTION_POS_Y + +#define RUI_FACTORY_RUN_SCREEN_DESCRIPTION_POS_X RUI_COMMON_SCREEN_DESCRIPTION_POS_X +#define RUI_FACTORY_RUN_SCREEN_DESCRIPTION_POS_Y RUI_COMMON_SCREEN_DESCRIPTION_POS_Y + +#define RUI_SD_RESTORE_SCREEN_DESCRIPTION_POS_X RUI_COMMON_SCREEN_DESCRIPTION_POS_X +#define RUI_SD_RESTORE_SCREEN_DESCRIPTION_POS_Y RUI_COMMON_SCREEN_DESCRIPTION_POS_Y + +#define RUI_SD_RESTORE_RUN_SCREEN_DESCRIPTION_POS_X RUI_COMMON_SCREEN_DESCRIPTION_POS_X +#define RUI_SD_RESTORE_RUN_SCREEN_DESCRIPTION_POS_Y RUI_COMMON_SCREEN_DESCRIPTION_POS_Y diff --git a/src/system-recovery/recovery-rui.c b/src/system-recovery/recovery-rui.c new file mode 100644 index 0000000..0deefad --- /dev/null +++ b/src/system-recovery/recovery-rui.c @@ -0,0 +1,854 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include "rui.h" +#include "common.h" +#include "config.h" +#include "rui-menu.h" +#include "graphics.h" +#include "log.h" +#include "rui-image.h" +#include "rui-ruler.h" +#include "input-events.h" +#include "rui-description.h" +#include "system-recovery.h" +#include "rui-progress-bar.h" +#include "recovery-rui-skin.h" +#include "process-util.h" + +/* if user does not do anything, default action will be taken after this timeout*/ +#define DEFAULT_ACTION_TIMEOUT 4 + +#define BUFFER_SIZE 512 + +bool volatile running = true; +static const char *original_description = NULL; +static char description_buffer[BUFFER_SIZE]; +static char *rui_default_action = NULL; +static const char *rui_default_handler = NULL; + +static int timer_count = 0; +static bool user_idle = true; + +static void timeout_handler(rui_screen *cs) +{ + int ret; + + if (rui_default_action && user_idle) { + if (!original_description) { + original_description = cs->description->text; + cs->description->text = description_buffer; + } + + snprintf(description_buffer, BUFFER_SIZE, + "%s\nDefault action (%s) will be taken after %d seconds", + original_description, rui_default_action, + DEFAULT_ACTION_TIMEOUT - timer_count/TIMER_INTERVAL); + + if (timer_count/TIMER_INTERVAL == DEFAULT_ACTION_TIMEOUT) { + ret = system(rui_default_handler); + if (ret < 0) + LOGD("Could not run action: %s\n", rui_default_handler); + } + } + + if (original_description && !user_idle) { + cs->description->text = original_description; + original_description = NULL; + } + + timer_count++; +} + +void recovery_rui_input_callback(user_action action, user_action_type action_type) +{ + int need_repaint = 1; + rui_screen *cs; + + /* We interested only in button downs, long presses and idle events */ + if (action_type != ACTION_TYPE_BEGIN && + action_type != ACTION_TYPE_LONGPRESS && + action_type != ACTION_TYPE_IDLE && + action_type != ACTION_TYPE_TIMER) + return; + + cs = get_current_screen(); + if (action_type != ACTION_TYPE_TIMER && + action_type != ACTION_TYPE_IDLE && + user_idle) { + user_idle = false; + timeout_handler(cs); + } + + if (action == ACTION_DOWN && cs->menu) + rui_menu_cursor_down(cs->menu); + else if (action == ACTION_UP && cs->menu) + rui_menu_cursor_up(cs->menu); + else if (cs->allow_force_reboot && + action == ACTION_CONFIRM && + action_type == ACTION_TYPE_LONGPRESS) + sys_power_reboot(); + else if ((action == ACTION_CONFIRM || action == ACTION_HOME) && + cs->menu) + rui_menu_action_run(cs->menu); + else if (action == ACTION_BACK) + rui_screen_switch(RUI_SCREEN_BACK); + else if (action == ACTION_TIMEOUT) + timeout_handler(cs); + else if (action != ACTION_NONE || action_type != ACTION_TYPE_IDLE || + !cs->animations) + need_repaint = 0; + + if (need_repaint) + rui_draw(); +} + +static struct { + const char **rui_screens; + const char **rui_menus; + const char **rui_animations; + const char **rui_images; + const char **rui_colors; + const char **rui_screen_styles; + const char **rui_menu_styles; + const char **rui_ruler_styles; + const char **rui_rulers; + const char **rui_description_styles; + const char **rui_descriptions; + const char **rui_action_handlers; +} rui_config_labels; + +static rui_screen *rui_screens = NULL; +static rui_menu *rui_menus = NULL; +static rui_screen_style *rui_screen_styles = NULL; +static rui_menu_style *rui_menu_styles = NULL; +static rui_ruler_style *rui_ruler_styles = NULL; +static rui_animation *rui_animations = NULL; +static rui_image *rui_images = NULL; +static color *rui_colors = NULL; +static rui_ruler **rui_rulers = NULL; +static rui_description_style *rui_description_styles = NULL; +static rui_description *rui_descriptions = NULL; +static const char **rui_action_handlers = NULL; + +/* naive search */ +int find_string(const char **list, const char *s) +{ + int i; + + if (!list) + return -EINVAL; + + for (i = 0; list[i]; ++i) + if (strcmp(list[i], s) == 0) + return i; + + return -ENOENT; +} + +static inline int _rui_lookup_setting(config_setting_t *root, const char **labels, const char *name) +{ + const char *value; + int ret; + + ret = config_setting_lookup_string(root, name, &value); + if (ret == CONFIG_FALSE) + return -1; + + return find_string(labels, value); +} + +#define rui_lookup_setting(root, list, out, field) do { \ + int _idx = _rui_lookup_setting(root, rui_config_labels.list, #field); \ + if (_idx < 0 || !list) { \ + (out)->field = NULL; \ + log_dbg("Could not find setting %s.%s", #out, #field); \ + } else \ + (out)->field = &list[_idx]; \ + } while (0) + +#define rui_lookup_setting_value(root, list, out, field) do { \ + int _idx = _rui_lookup_setting(root, rui_config_labels.list, #field); \ + if (_idx < 0 || !list) \ + log_dbg("Could not find setting %s.%s", #out, #field); \ + else \ + out->field = list[_idx]; \ + } while (0) + +static inline int ascii_hex(char c) +{ + switch (c) { + case '0' ... '9': + return c - '0'; + case 'A' ... 'F': + return c - 'A' + 10; + case 'a' ... 'f': + return c - 'a' + 10; + } + + return 0; +} + +static inline char get_hex_byte(const char *s) +{ + return 16 * ascii_hex(s[0]) + ascii_hex(s[1]); +} + +static int color_entry_parse(config_setting_t *root, void *data) +{ + color *c = data; + const char *str; + + str = config_setting_get_string(root); + if (!str) + return -ENOENT; + + if (strlen(str) == 9 && str[0] == '#') { + c->r = get_hex_byte(str + 1); + c->g = get_hex_byte(str + 3); + c->b = get_hex_byte(str + 5); + c->a = get_hex_byte(str + 7); + + return 0; + } + + return -ENOTSUP; +} + +struct str2int_map { + const char *key; + int value; +}; + +static int map_find(const char *key, struct str2int_map *map) +{ + int i; + + for (i = 0; map[i].key; ++i) + if (strcmp(key, map[i].key) == 0) + return map[i].value; + + return -1; +} + +static struct str2int_map align_hor_map[] = { + {"left", GR_ALIGN_LEFT}, + {"center", GR_ALIGN_CENTER}, + {"right", GR_ALIGN_RIGHT}, + {NULL, 0} +}; + +static struct str2int_map align_ver_map[] = { + {"top", GR_ALIGN_TOP}, + {"middle", GR_ALIGN_MIDDLE}, + {"bottom", GR_ALIGN_BOTTOM}, + {NULL, 0} +}; + +static struct str2int_map img_type_map[] = { + {"no-alpha", GR_WITHOUT_ALPHA}, + {"alpha", GR_WITH_ALPHA}, + {NULL, 0} +}; + +static int image_entry_parse(config_setting_t *root, void *data) +{ + rui_image *image = data; + const char *value; + int ret; + + ret = config_setting_lookup_string(root, "fname", &image->fname); + if (ret == CONFIG_FALSE) + return -1; + + rui_lookup_setting_value(root, rui_colors, image, c_bg); + + ret = config_setting_lookup_string(root, "align_hor", &value); + image->align_hor = map_find(value, align_hor_map); + + ret = config_setting_lookup_string(root, "align_ver", &value); + image->align_ver = map_find(value, align_ver_map); + + config_setting_lookup_int(root, "offset_x", &image->offset_x); + config_setting_lookup_int(root, "offset_y", &image->offset_y); + + ret = config_setting_lookup_string(root, "img_type", &value); + image->img_type = map_find(value, img_type_map); + + image->surface = NULL; + + return 0; +} + +static int animation_entry_parse(config_setting_t *root, void *data) +{ + rui_animation *animation = data; + const char *value; + int ret; + + ret = config_setting_lookup_string(root, "fname", &animation->fname); + if (ret == CONFIG_FALSE) + return -1; + + rui_lookup_setting_value(root, rui_colors, animation, c_bg); + + ret = config_setting_lookup_string(root, "align_hor", &value); + animation->align_hor = map_find(value, align_hor_map); + + ret = config_setting_lookup_string(root, "align_ver", &value); + animation->align_ver = map_find(value, align_ver_map); + + config_setting_lookup_int(root, "offset_x", &animation->offset_x); + config_setting_lookup_int(root, "offset_y", &animation->offset_y); + config_setting_lookup_int(root, "frames_num", &animation->frames_num); + config_setting_lookup_int(root, "icurrent_frame", &animation->frames_num); + + ret = config_setting_lookup_string(root, "img_type", &value); + animation->img_type = map_find(value, img_type_map); + + animation->surfaces = NULL; + + return 0; +} + +static int get_screen_id(config_setting_t *root, const char *key) +{ + int ret; + static const char *special_labels[] = { + "", + "CURRENT", + "BACK", + }; + + ret = _rui_lookup_setting(root, + rui_config_labels.rui_screens, key); + if (ret != -ENOENT) + return ret; + + ret = _rui_lookup_setting(root, special_labels, key); + if (ret < 0) { + log_err("Could not get screen id"); + return RUI_SCREEN_CURRENT; + } else { + return -ret; + } +} + +static int menu_entry_parse(config_setting_t *root, void *data) +{ + config_setting_t *actions, *node; + rui_menu *menu = data; + int i; + int ret; + + rui_lookup_setting(root, rui_menu_styles, menu, style); + + config_setting_lookup_int(root, "pos_x", &menu->pos_x); + config_setting_lookup_int(root, "pos_y", &menu->pos_y); + config_setting_lookup_int(root, "item_selected", &menu->item_selected); + config_setting_lookup_int(root, "item_default", &menu->item_default); + + actions = config_setting_get_member(root, "actions"); + if (!actions) + return 0; + + menu->items_num = config_setting_length(actions); + menu->items = calloc(menu->items_num, sizeof(*menu->items)); + menu->actions = calloc(menu->items_num, sizeof(*menu->actions)); + if (!menu->items || !menu->actions) { + ret = -ENOMEM; + goto err; + } + + for (i = 0; i < menu->items_num; ++i) { + node = config_setting_get_elem(actions, i); + if (!node) { + log_err("Could not get next setting"); + ret = -ENOMEM; + goto err; + } + + config_setting_lookup_string(node, "label", &menu->items[i]); + menu->actions[i].screen_switch_to = get_screen_id(node, "screen_switch_to"); + config_setting_lookup_int(node, "exit_after_action", &menu->actions[i].exit_after_action); + rui_lookup_setting_value(node, rui_action_handlers, (&menu->actions[i]), action_handler); + } + + return 0; + +err: + free(menu->items); + free(menu->actions); + return ret; +} + +static int description_style_entry_parse(config_setting_t *root, void *data) +{ + rui_description_style *style = data; + rui_lookup_setting_value(root, rui_colors, style, c_title); + rui_lookup_setting_value(root, rui_colors, style, c_text); + + return 0; +} + +static int description_entry_parse(config_setting_t *root, void *data) +{ + rui_description *desc = data; + + config_setting_lookup_int(root, "pos_x", &desc->pos_x); + config_setting_lookup_int(root, "pos_y", &desc->pos_y); + rui_lookup_setting(root, rui_description_styles, desc, style); + config_setting_lookup_string(root, "title", &desc->title); + config_setting_lookup_string(root, "text", &desc->text); + + return 0; +} + +static int labels_list_parse(config_setting_t *root, int **out, + const char *name, const char **labels) +{ + int i; + int num; + int *list; + config_setting_t *elem, *node; + const char *value; + + node = config_setting_get_member(root, name); + if (!node) + return 0; + + num = config_setting_length(node); + if (num < 0) + return -EINVAL; + + list = calloc(num + 1, sizeof(*list)); + if (!list) + return -ENOMEM; + + for (i = 0; i < num; ++i) { + elem = config_setting_get_elem(node, i); + if (!elem) + goto err_nomem; + + value = config_setting_get_string(elem); + if (!value) + goto err_nomem; + + list[i] = find_string(labels, value); + } + + list[num] = -1; + + *out = list; + return 0; + +err_nomem: + free(list); + return -ENOMEM; +} + +static int screen_entry_parse(config_setting_t *root, void *data) +{ + rui_screen *screen = data; + + rui_lookup_setting(root, rui_screen_styles, screen, style); + rui_lookup_setting(root, rui_menus, screen, menu); + rui_lookup_setting_value(root, rui_rulers, screen, rulers); + rui_lookup_setting(root, rui_descriptions, screen, description); + + labels_list_parse(root, &screen->images, "images", + rui_config_labels.rui_images); + labels_list_parse(root, &screen->animations, "animations", + rui_config_labels.rui_animations); + + screen->screen_back = get_screen_id(root, "screen_back"); + config_setting_lookup_int(root, "allow_force_reboot", &screen->allow_force_reboot); + + /* + screen->progress_bar = NULL; + screen->on_enter = NULL; + screen->draw = NULL; + */ + + return 0; +} + +static int ruler_entry_parse(config_setting_t *root, void *data) +{ + rui_ruler *ruler = *(rui_ruler **)data; + config_setting_t *node; + int num; + int i; + + num = config_setting_length(root); + if (num < 0) + return -EINVAL; + + for (i = 0; i < num; ++i) { + node = config_setting_get_elem(root, i); + if (!node) + return -ENOMEM; + + config_setting_lookup_int(node, "pos_x", &ruler[i].pos_x); + config_setting_lookup_int(node, "pos_y", &ruler[i].pos_y); + config_setting_lookup_int(node, "height", &ruler[i].height); + rui_lookup_setting(node, rui_ruler_styles, &ruler[i], style); + } + + return 0; +} + +static int ruler_entry_init(config_setting_t *root, void *data) +{ + rui_ruler **out = data; + rui_ruler *ruler; + int num; + + num = config_setting_length(root); + if (num < 0) + return -EINVAL; + + ruler = calloc(num + 1, sizeof(*ruler)); + if (!ruler) + return -ENOMEM; + + *out = ruler; + return 0; +} + +static int screen_style_entry_parse(config_setting_t *root, void *data) +{ + rui_screen_style *style = data; + + rui_lookup_setting_value(root, rui_colors, style, c_background); + + return 0; +} + +static int menu_style_entry_parse(config_setting_t *root, void *data) +{ + rui_menu_style *style = data; + + config_setting_lookup_int(root, "item_height", &style->item_height); + config_setting_lookup_int(root, "item_spacing", &style->item_spacing); + config_setting_lookup_int(root, "text_pos_x", &style->text_pos_x); + rui_lookup_setting_value(root, rui_colors, style, c_bg_selected); + rui_lookup_setting_value(root, rui_colors, style, c_bg_unselected); + rui_lookup_setting_value(root, rui_colors, style, c_text_selected); + rui_lookup_setting_value(root, rui_colors, style, c_text_unselected); + + return 0; +} + +static int ruler_style_entry_parse(config_setting_t *root, void *data) +{ + rui_ruler_style *style = data; + + rui_lookup_setting_value(root, rui_colors, style, c_ruler); + + return 0; +} + +static int action_handler_entry_parse(config_setting_t *root, void *data) +{ + const char **handler = data; + + *handler = config_setting_get_string(root); + return 0; +} + +static int rui_config_group_init(config_t *cfg, const char *group_name, + int (*entry_init)(config_setting_t *root, void *out), + void **out, size_t entry_size, const char ***labels) +{ + int num, i; + config_setting_t *root, *node; + char *data; + const char **labels_data; + int ret; + + root = config_lookup(cfg, group_name); + if (!root) { + log_err("Could not find %s group in config", group_name); + return -ENOENT; + } + + num = config_setting_length(root); + if (num <= 0) + return 0; + + data = calloc(num, entry_size); + labels_data = calloc(num + 1, sizeof(*labels_data)); + if (!data || !labels_data) { + log_err("Could not allocate memory"); + ret = -ENOMEM; + goto err; + } + + for (i = 0; i < num; ++i) { + node = config_setting_get_elem(root, i); + if (!node) { + log_err("Could not get next setting"); + ret = -ENOMEM; + goto err; + } + + labels_data[i] = config_setting_name(node); + + if (entry_init) { + ret = entry_init(node, data + i * entry_size); + if (ret < 0) + goto err; + } + } + + *out = data; + *labels = labels_data; + return num; + +err: + free(data); + free(labels_data); + return ret; +} + +static int rui_config_group_parse(config_t *cfg, const char *group_name, + int (*entry_parse)(config_setting_t *root, void *out), + char *data, size_t entry_size) +{ + int num, i; + config_setting_t *root, *node; + int ret; + + root = config_lookup(cfg, group_name); + if (!root) { + log_err("Could not find %s group in config", group_name); + return -ENOENT; + } + + num = config_setting_length(root); + if (num <= 0) + return 0; + + for (i = 0; i < num; ++i) { + node = config_setting_get_elem(root, i); + if (!node) { + log_err("Could not get next setting"); + ret = -ENOMEM; + goto err; + } + + ret = entry_parse(node, data + i * entry_size); + if (ret < 0) + goto err; + } + + return num; + +err: + return ret; +} + +bool recovery_rui_init(config_t *cfg) +{ + int main_screen_n = 0; + int i; + +#define DECLARE_GROUP(n, g, h) { \ + .name = n, \ + .out = (void **)&g, \ + .entry_size = sizeof(*g), \ + .entry_init = NULL, \ + .entry_parse = h, \ + .labels = &rui_config_labels.g \ +} + +#define DECLARE_GROUP_INIT(n, g, i, h) { \ + .name = n, \ + .out = (void **)&g, \ + .entry_size = sizeof(*g), \ + .entry_init = i, \ + .entry_parse = h, \ + .labels = &rui_config_labels.g \ +} + + static struct { + const char *name; + void **out; + size_t entry_size; + int (*entry_init)(config_setting_t *root, void *out); + int (*entry_parse)(config_setting_t *root, void *out); + const char ***labels; + + int num; + } groups[] = { + DECLARE_GROUP("screens", rui_screens, screen_entry_parse), + DECLARE_GROUP("images", rui_images, image_entry_parse), + DECLARE_GROUP("animations", rui_animations, animation_entry_parse), + DECLARE_GROUP("action_handlers", rui_action_handlers, action_handler_entry_parse), + DECLARE_GROUP("menus", rui_menus, menu_entry_parse), + DECLARE_GROUP("colors", rui_colors, color_entry_parse), + DECLARE_GROUP("menu_styles", rui_menu_styles, menu_style_entry_parse), + DECLARE_GROUP("screen_styles", rui_screen_styles, screen_style_entry_parse), + DECLARE_GROUP("ruler_styles", rui_ruler_styles, ruler_style_entry_parse), + DECLARE_GROUP_INIT("rulers", rui_rulers, ruler_entry_init, ruler_entry_parse), + DECLARE_GROUP("description_styles", rui_description_styles, description_style_entry_parse), + DECLARE_GROUP("descriptions", rui_descriptions, description_entry_parse), + {NULL} + + }; +#undef DECLARE_GROUP +#undef DECLARE_GROUP_INIT + + for (i = 0; groups[i].name; ++i) + groups[i].num = rui_config_group_init(cfg, groups[i].name, groups[i].entry_init, + groups[i].out, groups[i].entry_size, groups[i].labels); + + for (i = 0; groups[i].name; ++i) + groups[i].num = rui_config_group_parse(cfg, groups[i].name, groups[i].entry_parse, + *(char **)groups[i].out, groups[i].entry_size); + + return rui_init(rui_screens, groups[0].num, + main_screen_n, + rui_images, groups[1].num, + rui_animations, groups[2].num); +} + +void cleanup_menus() +{ + int i; + if (!rui_menus) + return; + + for (i = 0; rui_config_labels.rui_menus[i]; ++i) { + free(rui_menus[i].items); + free(rui_menus[i].actions); + } +} + +void cleanup_rulers() +{ + int i; + if (!rui_rulers) + return; + + for (i = 0; rui_config_labels.rui_rulers[i]; ++i) + free(rui_rulers[i]); +} + +void cleanup_screens() +{ + int i; + if (!rui_screens) + return; + + for (i = 0; rui_config_labels.rui_screens[i]; ++i) + free(rui_screens[i].images); +} + +void recovery_rui_exit(void) +{ + rui_exit(); + + cleanup_screens(); + free(rui_screens); + cleanup_menus(); + free(rui_menus); + free(rui_screen_styles); + free(rui_menu_styles); + free(rui_ruler_styles); + free(rui_animations); + free(rui_images); + free(rui_colors); + cleanup_rulers(); + free(rui_rulers); + free(rui_descriptions); + + free(rui_config_labels.rui_screens); + free(rui_config_labels.rui_menus); + free(rui_config_labels.rui_screen_styles); + free(rui_config_labels.rui_menu_styles); + free(rui_config_labels.rui_ruler_styles); + free(rui_config_labels.rui_animations); + free(rui_config_labels.rui_images); + free(rui_config_labels.rui_colors); + free(rui_config_labels.rui_rulers); + free(rui_config_labels.rui_descriptions); + + free(rui_default_action); +} + + +int recovery_gui(config_t *cfg) +{ +#ifdef HAVE_TDM + /* These should be set externally */ + + /* + * Under normal circumstances XDG_RUNTIME_DIR is set during + * session setup (login). On initrd there is no session. This + * is used in libwayland-server and there is no default value. + */ + setenv("XDG_RUNTIME_DIR", "/run", 1); + + /* Tell TBM to work without an external wayland display manager. */ + setenv("TBM_DISPLAY_SERVER", "1", 1); +#endif + + if (!recovery_rui_init(cfg)) { + LOGD("Can't initialize GUI.\n"); + return 1; + } + + rui_default_action = get_action_from_cmdline(); + if (!rui_default_action) + rui_default_action = get_action_from_file(); + + if (rui_default_action) { + int idx = find_string(rui_config_labels.rui_action_handlers, rui_default_action); + if (idx < 0) { + LOGD("Invalid action: %s\n", rui_default_action); + free(rui_default_action); + rui_default_action = NULL; + } else + rui_default_handler = rui_action_handlers[idx]; + } + + if (!ev_init()) { + LOGD("Can't initialize input subsystem.\n"); + recovery_rui_exit(); + return 1; + } + + rui_draw(); + + while (running) + if (!ev_dispatch(recovery_rui_input_callback)) + break; + + ev_exit(); + recovery_rui_exit(); + + return 0; +} diff --git a/src/system-recovery/res-util/README.txt b/src/system-recovery/res-util/README.txt new file mode 100644 index 0000000..e79d127 --- /dev/null +++ b/src/system-recovery/res-util/README.txt @@ -0,0 +1,13 @@ +This directory contains some source files for images used by system-recovery +framebuffer GUI. + +The menu title image can be generated by ./make-menu-title.sh shell-script. +The required font SamsungSans_Md.ttf can be found +in magnolia/framework/graphics/all-fonts-slp project. + +It is possible to draw menu title by using fixed-width font but +label typed with TrueType font looks better. + +To draw progress animation system-recovery uses interlaced PNG-image +with all frames combined. For making tizen-anim.png you can use ./make-anim.sh +shell-script which uses ./interlace-frames.py python-script. diff --git a/src/system-recovery/res-util/interlace-frames.py b/src/system-recovery/res-util/interlace-frames.py new file mode 100755 index 0000000..d8b11df --- /dev/null +++ b/src/system-recovery/res-util/interlace-frames.py @@ -0,0 +1,56 @@ +#!/usr/bin/python +# +# Copyright (C) 2014 The Android Open Source Project +# Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Script to take a set of frames (PNG files) for a recovery animation +and turn it into a single output image which contains the input frames +interlaced by row. Run with the names of all the input frames on the +command line, in order, followed by the name of the output file.""" + +import sys +try: + import Image + import PngImagePlugin +except ImportError: + print "This script requires the Python Imaging Library to be installed." + sys.exit(1) + +frames = [Image.open(fn).convert("RGBA") for fn in sys.argv[1:-1]] +assert len(frames) > 0, "Must have at least one input frame." +sizes = set() +for fr in frames: + sizes.add(fr.size) + +assert len(sizes) == 1, "All input images must have the same size." +w, h = sizes.pop() +N = len(frames) + +out = Image.new("RGBA", (w, h * N)) +for j in range(h): + for i in range(w): + for fn, f in enumerate(frames): + out.putpixel((i, j * N + fn), f.getpixel((i, j))) + +# When loading this image, the graphics library expects to find a text +# chunk that specifies how many frames this animation represents. If +# you post-process the output of this script with some kind of +# optimizer tool (eg pngcrush or zopflipng) make sure that your +# optimizer preserves this text chunk. + +meta = PngImagePlugin.PngInfo() +meta.add_text("Frames", str(N)) + +out.save(sys.argv[-1], pnginfo=meta) diff --git a/src/system-recovery/res-util/make-anim.sh b/src/system-recovery/res-util/make-anim.sh new file mode 100755 index 0000000..a169dbe --- /dev/null +++ b/src/system-recovery/res-util/make-anim.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +FNAME="../res/system-recovery/images/tizen-anim.png" +SRCIMG="./tizen-anim?src.png" + +./interlace-frames.py $SRCIMG "$FNAME" +optipng -o 7 "$FNAME" diff --git a/src/system-recovery/res-util/make-menu-title.sh b/src/system-recovery/res-util/make-menu-title.sh new file mode 100755 index 0000000..5c194cb --- /dev/null +++ b/src/system-recovery/res-util/make-menu-title.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +FNAME="../res/system-recovery/images/menu-title.png" +TEXT="Tizen system recovery" +FONTSIZE=46 +FONT="./SamsungSans_Md.ttf" + +convert -background black -fill white -font "$FONT" -pointsize $FONTSIZE label:"$TEXT" "$FNAME" + +optipng -o 7 "$FNAME" diff --git a/src/system-recovery/res-util/tizen-anim1src.png b/src/system-recovery/res-util/tizen-anim1src.png new file mode 100644 index 0000000000000000000000000000000000000000..54995eb4542d091ed45b5bc7048eac26037e254b GIT binary patch literal 18641 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 literal 0 HcmV?d00001 diff --git a/src/system-recovery/res-util/tizen-anim2src.png b/src/system-recovery/res-util/tizen-anim2src.png new file mode 100644 index 0000000000000000000000000000000000000000..43533a336d76521784e204bd897a1381fee62de3 GIT binary patch literal 18676 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

g|epH327Rt*}W#%B9dO0>Ff0KNp{HpAR zGyg6ny9b+pyJ=Mb7z#$QaRA8-^PC`+X;GC7M#cA{nSS;6G{X@A$k+=~^N&Uq9Vvxa z2gAx-!Q1y|Zb{u}XYm0LB|62Fo;xApni&UG2 zXTxKC8dsIozc(A-6~oxjydmX||}>wmt8f z!(~m9n;!m0w|!+Dvsht*j&>Yg5Gu_Yi&Gt(VnRKy*QGs-usnad6W{yy?~lP5m0OL) zVBC*#3BXu@IGRR%(c_-H6BbxLIx$61Z~I1JWRw@e%lw6u6M&jt9C6 z9N;hbUU4M=6pK=m5va#-y1~5XBc`GNie}g?7{PUQV`5^C-+Jq<)d#>8+xI}%7MU<_ z{oejJu8|k{xsS)4Lj92drV0XcG$B+j z|1Uhb15N0ZvMQfL-3b>0#3vD?zlBjgDtILm-36yw!g*bRpX*lHi{vQHCm%Ku!5Tod zgE(&zX@9WzU3sqv0VoC|1U=4&-f_nrA5}XAT)1%$47@NCK3u=&?%UVF>nBP<8x5y4liRE+I#vpe{n*uCW&}5`{C5Af;XSLDx#w; zL5TW$3qY}L`*lyZ*S4z5C;#jNFE_hp-p{69X7B;3oAPP4oFG?C zMmH#z_@P^iI@+T{&WDzblH?eVtebqboX}MSK=XB51ZQIzfyYfan^nfCI%a}gT-EtR z-kRRK_#~dcWc>k+_&VOJK&y--_NO5&*d^zt$!>liFH#k|=6Fg5mGGlG@4RzpwNpUe zKHabz2DEJktY}}I*MBH^{j+_(8$RFTg9MrB!^DCZMDVUQM>H!&!WvGcB|b=v^T2@i z4Ori{^`To z(ge@xFZkp1NGy z@WT(obI(0jJr&Tnh`->;Jr`CkS=j5ar{2sNyW|GjawRB0|FEFgZ#<`s879^SAFfMK zB&Zc5BXkN}d`=2n-#G&=ZC=~uZv?~R23TeMKL?aMn>1+>kq=ZBfR6D3N8)~G(GVFK z85vb}5z`;}_Imtr&o;k+@o+*8qFJg$bDv+;edy7bH-S5@%7i9$FtA5URE!Ep!3eJt zq+o>lhtb!(eZqtZldG)>=55A@3t`mIf$+~4UW!SGi+x&=rH4}M)Pp*8>%%E67LJuD zQ0$k%>ro&X6)pq)lgxUFkQ5&SaWP(f@^}icdTj z<{FJ_gG%VH%8S_WvG3NQC27Yy0wf4@3h>~NXDqm1E#pSX_~ZZk(DR{Bn=~jWv`52a zh7rQTwr$%cb?@GtRcip9?YWmY(*lN{E(nq;ZOiY5cs;x8=U90EO4CXA)%XSZsY0C#k62>n_m!I2YrmLG@!GE~KjzW@IF4YOv=I&%Pg z@tG&#fye&}&%gBQ!wE6UpOcf5lW3S-nrIje8c>HnaGE9#AqTN62rDy{;s1S%P+VJ{ zfyxO$JjPjND4!F?NAT}diDOmoud5!S-@J7>C7~C}7&QPaI4%EB=pHrw@RCwLbjeJF zKliQ&9$y|DM+hk=h%ml2apJ^V&L{;G+kdA_jV&!MniCrvJA{t6RRqEaqu`td4I0!g@4(^v_U#K&K)xJ80r|Wi&c3MZ2>ErM`r#X#^$fa_y#5j# zMZhA6%ha5JC@uNJ_}nkV8n5(ZE_nxR%uii5i`ECRtH^CA5fa3f| z{JWQy_c2|(B|p1PglGHXoWU^xM;ulq9e!hn-!gl%nx#&@Cet#-#73 z#Ps%w6YkD>_O;3I$i(qyrUHuXt+(E)Ra#p51FB#PZj!kg@`q7#HRO-x;?IY3LReAo zglQ%I%`Wt}E7H(kj939f%ts)6?^fh**Lq^f1}@=p_P-FC*BU;#cDJJz^A`#=Br&q!3g8T2G10+9zO1R9ywt~*DDb~)dzyYJq6+n@0O@-}DA9H3E|=ps#? zJo!_E?`nd82PiZVgd9XSlUxOnad*7v%PaFe&`GxeSV1M+fyYsOS;fX*r;0Wj~?0Y`*P5Nhy$oj@(!v7%{eX4Zl0uI_c_14wP^)TzL0&TyGV z{@j3S7)uaRkRnFP{5ipHshSExI0^s81aa8ginPOr4~JC1a?ZcNnoP16)$S1l z?(d|A+$?k7P)ylW62k4c-z;%d)rz(wM~;*kghV>W)(?MtUzGJXmC3tf6iqAP7f^Hf z#UM!$0Lbh=8zhaQt@b6R6`D8I0!`mu?@q|e<(iUpfc_F@#B?^f}Qi#_(SVN z#Q`B9d~^SYIJ-7*_3VL%^Wrk6$~ltNwtxi0N_RVmrKK9Y*k1nNfy>VwepV`=*k;b0 z2_r|2geg;|)IkVeKv>4mn9pJYTTI!wLFl4<^Kf6+QPoF9(=N_-;>3xn@&QGK{13u+ zHH z&Uyf?EAgNIz+HFU1=FTY>x0ltL6h8+%rb#U5b+>|N6I3Ej(p&6xJ?EXUy=#0s+NZ<`VoK0~dDf_j#Kpxfyx|TdvgV$2H76S|b!N z1dz>9_1;WPP3`WCmU)1}bA={+_u@r-m8yT~y{c>&N!xtDNTG`m#)Wv?gXlZZ>%`fI zQGb9QA`<6RJm!QbBKVk_J7`x&Q95xsNnvoHx7sPOVbu)WentX_<`~9}8wb;;Prnb< z@JWO)nFlJoCq;m89Zv0?Pm!!j04tJ)DTg}Vhtn&xoHFNdJ7i$36;Ff!Evy=b0L=*< z3r-ap=9s!)diwg+Z<6^%jRlZ5Dv}&AVgwaCEIgx)#UM-aqmNzP_Vu_?T-j5*9udLO~rXR9w!xs27!p?`5>xeFEq=ibzt*?f`UpVqTQ5G^k2f0QC57TX4|6xn(edCK7;=K`|Hb}eDXMXHV>c+SyG)6@6FHu&(o63Hb-fHGB%h4%46rf-<*`eY<< z|FCRXlCEV@07JCKA012cGdM&eVEHvL!K3?$4FEO$#%yK+sG36oi_6AqK1tSVbFOcv zf>x@+fQ#zE>!aJ~`>uqUwSodtJm*->G-5%!c2hi!K7Nu+@NH$OoO5)CGW|XVt|1I_ zQN>ycE8I7%L1I;1tFsEgrk@73&Td z3(EC{OHQ*;p9y8Yu_elE>)xUDTSWm34dG;j;WpJAG}EsMrq^8d^RcW2WebMTR7K%^ zGSe~w!ry15J_N8n{AcWiV2+s-v6*!1 zAb=$VU;`b%vYJ?#Bf`grM(RcC>06*y>npg2ciI)?ZU+;$+x3XQ5SH?f}>s0 z{|hLe2&rCrE&`|;fJv$do~eM`55$QfL_;oe2hdrM=nOQt$tCzG(#2^jZrgd}$dM-_ z`R)iGZ0ny2t-m-q4KLy?0D&hKh#*QXrqnG`mRP`iOYWdj{p%$^4@g@R1<-8mzRdAz zntTA2tgc`5_sra%744eKs%G~I`7%A|gp$v?68ZzlXbzuZ`F-YVgh=tJdK5eaeLyFG zp;S*Ck(5#_1RvcKjDFu7G`Zz|U@tvZcXPi~`XT;`7qVH%q_SiTCJzuQ@PLqkhoFgc zs!|ca{2CA7#b4#YPgm7~i@Jy3O2bt@y=i+-S`dTPc7AS=7KB%1ri*~IvjF^%U-ecy70D-C(vr5LV z27Ex%_cMYJANUJOVfOeo(B*TDb)LE`&F>(|(odYe zvT6ryk#Y!F@s!_r4r(Q%UDZ(;qYB$orK2;(iLi0&O96ky*5I`zf?}W;i`@cGWy|asYgA9wgvu8`U zII0msRLf9usUiM%bb0s0nyG;ORux@@Y^=c(Az9|M649ggh<5% zr(sO_V=!b%=lJM#1e#GARK*c(W@Cu_=U8JE#L?d?Ut3c;p!Q9uCZp; z06G*90}TSOYXc8Faj74U=A6=dHfSm?F24Pqd+wQx4aScjUoFn%)!!FWS6vn^ZsqwF z*X}mDiC?p+WYK3G;}Xz}!;&uXH3z_9Yf52WhZutJK0FC8*~+QHM!O=IB7Bb5F2IT) zTO)%Cy&}BlgXSI#ILHjY*iD91-!Y!!!`-lM6DLkwRhe$J)BK~p9%r*%lh5E(~2$$&yF&Yx@z32F_^LR!r)QcFVdC#1^;&qGP`nDA`g&04NLjKMjMA zXFJLecVI1?EGSyK@}7xTzAs4(&X9K9I^SVD+WJhW%Qw_dvh{+fnw0d(CEkJ>qktne z_+eIC4-8-DdmB%}=t!eoUERRm7t9rtt7j0fj_6oiX2K(7?FwiB*dYbr=9nMhcz*Hp z2k)IQ`k!x1hez+c`HX?*)HqL41omZm(9Jx`gg9hL*`TSP2E2@?w;0QqE2soHaPY82QT ziYCE1cs}+Zgl9j1w`|qm&6YCUyjk6bU%EwPDU;xPe0lWC{kqW6Zg@4+IDlLMP5zt?g6PXWAj8-uA?5{%uV{R?IP z5t}k;F2$tIG)$=bKy0Qs)D225C0o=RLL(jsX&4RRd;3z)n(H#5TYSTFie8-YF+4Ep znll`t&O-PM3p9Q^dm3MM#8dGQD&V@QSu)fZ1;j7E4*|%CB-#xEt)kJcuzzmq zJraYyb^OPM*4G|Sl-ZoYZ8P=zbJy?O1MSW``;;$?MS>|=QjG#I3xS!7477Grw@4r= z>#jKCZZ)bv(n=7x0~q0+kbxbImDs*oGTU`tBHJ>vb@3Xh!8r#EKWGooosQ9V`rH2l X`U|cOKq%s}00000NkvXXu0mjfh7i^M literal 0 HcmV?d00001 diff --git a/src/system-recovery/res-util/tizen-anim3src.png b/src/system-recovery/res-util/tizen-anim3src.png new file mode 100644 index 0000000000000000000000000000000000000000..e9498730bb6f9a27f3420189e0f59da09a9f99c2 GIT binary patch literal 18560 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 LNkvXXu0mjfXg1lw literal 0 HcmV?d00001 diff --git a/src/system-recovery/res-util/tizen-anim4src.png b/src/system-recovery/res-util/tizen-anim4src.png new file mode 100644 index 0000000000000000000000000000000000000000..bcd8c35fb9911caeaa961e5699164520ff12f1ad GIT binary patch literal 18601 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 literal 0 HcmV?d00001 diff --git a/src/system-recovery/res/images/18x32.png b/src/system-recovery/res/images/18x32.png new file mode 100644 index 0000000000000000000000000000000000000000..aa7064ef74a329f052c365b07ed41667af058035 GIT binary patch literal 23763 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

-IUlD% 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 O0000Er$hNFUnbT>!~ytH&9ozmSY2uMgse0=-I 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 literal 0 HcmV?d00001 diff --git a/src/system-recovery/res/images/menu-title-480x800.png b/src/system-recovery/res/images/menu-title-480x800.png new file mode 100644 index 0000000000000000000000000000000000000000..213c766188cbf870c7aa4ad4b555f4aaf8ce7c62 GIT binary patch literal 1941 zcmZ`)dpr|*8~?d9v6h@%I#Z6hq(-cT3|q*h$&eOeW-*%FGPh&Gjwt1t%WB7(6VXL< z6HZKuT+(7&hbT#DrsL8yqMY{beLtV~kN1!FpXdABzTfBbd7eL>bH3glFb%i{004$R z;OYl}5?0~wSg$bP28TYb0M+Bp1ZM#57DLyLty9E?;RpN(05G-#z{~;QnU=PI9=wTNGXRM^l$~>W}z_}07wen)tN|p zJI9XpB}Q!Nm75#xu>Zps{nj&NGap*Rx)F6Xt%l>}MjUprzI~l|sbVh&jo=?LU-a{@ zp%$f$98x1JW=3hapuhOKRPULzg*PySp&7qGb2zz)ar{sNCuY zLKBCaz^3{~VlYo~$s4nRSskW9rUuZy*E8Wiv8KkxR5}e7!xro7_*AI~FfJT+V>M5C z6+&i5Lvkg;vgZq14hAW8qR`s_>M&9pPo9H;-;Po>J-UBIL%=)v2JjA9tkJ7!p+S83 zahiLgkPJ3umN|~W!M9hf1G(HKLc_|7kB+(;AWxY&Io06=E_ua4C@cBj-KIRI4#Q!@ z$W*QO>O9PpD(G}3f7yJn_vsgk3ENPYY+{Bn64Dav**I2QG1H~-NW#F(%*z9&wW6g> zUq}-ES^u?2-My?ie%R5?yT^Q@RhhL-wyJ>hKA{03j$SWilJ%geDj?gu)iwMU&AS4+bFy91)F=H z1%sjP9_n7$j-1wO0nEDXFc86?HTT6Dn4>j@_XihmP8!gQiCC8~TZ#3B?h?p*U=?wF}$uQX&5j3P=BbHjy z#0eA*l8th8e3T!|pUl1a+S%v!88ex-)Oek88_%of;QlOntzG1^Y$d9+qzzK;@<#CY z@elS7Jp-%>8G$D+Sk)2C?X)C>lz?Oh$;@A$bGSyC$WgcEC7a&bb><@~PTH8Q z>mTGzka-Ydjzkn)GN_Lbe%gfIeqFfXp^UkV*Pk!_C2$g< zjogL3Jo~9bv9)sPBjMt$n1@xh@70ylqhd|mr&}4QhRHbnA>C^C!IMn?)xV?T^{uS+ zdXI4|c}!L54Z9WPM9Rgu{tq#*RO>&VWx$FR$5SiIYElJFQZ-cen{5Dm2u!=c7hhgz z9m!D9Ks=Pyl|^3-2nmk`fu5|)s&Z7KsB6)mA#;~5KkL49WntR>ty|(V5F7_c0Bt7zTFJ(E6!?}XQ!n2`gcyDaM`hHeqYTJ<>4uXFr zNS!3<&m|Tb4DI~jcNdd2Sb+K`@iu=gG>$#cc--BA71sar*!)KJ>ag0iO3Co&0&cV; zbJ{=D(stq%-0B6i>v~9wMXuR&j-8QT-{s%cNizzy%5CquAfF-i>WG8XP^3Y0y%J)Q zJ#_(CQ36z4p5QDDebOFh1RJ~154;{JUag9>F*AAE+)}A`ryha0(!k5Utfwwz5B^wK zwt77@baA$R#!2yyOq1LKlc>j%BJ9KI5efik)Nb2dD4SjAJw!Ch9&K%p+GCEw*rQN; zk57r9r^&hV QE{ZmQck^~_bfIMb3#AQl)Bpeg literal 0 HcmV?d00001 diff --git a/src/system-recovery/res/images/menu-title-720x1280.png b/src/system-recovery/res/images/menu-title-720x1280.png new file mode 100644 index 0000000000000000000000000000000000000000..ef8aaff6ff2d5375acc61d2b52ab67573e8276a5 GIT binary patch literal 2797 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 literal 0 HcmV?d00001 diff --git a/src/system-recovery/res/images/menu-title.png b/src/system-recovery/res/images/menu-title.png new file mode 100644 index 0000000000000000000000000000000000000000..213c766188cbf870c7aa4ad4b555f4aaf8ce7c62 GIT binary patch literal 1941 zcmZ`)dpr|*8~?d9v6h@%I#Z6hq(-cT3|q*h$&eOeW-*%FGPh&Gjwt1t%WB7(6VXL< z6HZKuT+(7&hbT#DrsL8yqMY{beLtV~kN1!FpXdABzTfBbd7eL>bH3glFb%i{004$R z;OYl}5?0~wSg$bP28TYb0M+Bp1ZM#57DLyLty9E?;RpN(05G-#z{~;QnU=PI9=wTNGXRM^l$~>W}z_}07wen)tN|p zJI9XpB}Q!Nm75#xu>Zps{nj&NGap*Rx)F6Xt%l>}MjUprzI~l|sbVh&jo=?LU-a{@ zp%$f$98x1JW=3hapuhOKRPULzg*PySp&7qGb2zz)ar{sNCuY zLKBCaz^3{~VlYo~$s4nRSskW9rUuZy*E8Wiv8KkxR5}e7!xro7_*AI~FfJT+V>M5C z6+&i5Lvkg;vgZq14hAW8qR`s_>M&9pPo9H;-;Po>J-UBIL%=)v2JjA9tkJ7!p+S83 zahiLgkPJ3umN|~W!M9hf1G(HKLc_|7kB+(;AWxY&Io06=E_ua4C@cBj-KIRI4#Q!@ z$W*QO>O9PpD(G}3f7yJn_vsgk3ENPYY+{Bn64Dav**I2QG1H~-NW#F(%*z9&wW6g> zUq}-ES^u?2-My?ie%R5?yT^Q@RhhL-wyJ>hKA{03j$SWilJ%geDj?gu)iwMU&AS4+bFy91)F=H z1%sjP9_n7$j-1wO0nEDXFc86?HTT6Dn4>j@_XihmP8!gQiCC8~TZ#3B?h?p*U=?wF}$uQX&5j3P=BbHjy z#0eA*l8th8e3T!|pUl1a+S%v!88ex-)Oek88_%of;QlOntzG1^Y$d9+qzzK;@<#CY z@elS7Jp-%>8G$D+Sk)2C?X)C>lz?Oh$;@A$bGSyC$WgcEC7a&bb><@~PTH8Q z>mTGzka-Ydjzkn)GN_Lbe%gfIeqFfXp^UkV*Pk!_C2$g< zjogL3Jo~9bv9)sPBjMt$n1@xh@70ylqhd|mr&}4QhRHbnA>C^C!IMn?)xV?T^{uS+ zdXI4|c}!L54Z9WPM9Rgu{tq#*RO>&VWx$FR$5SiIYElJFQZ-cen{5Dm2u!=c7hhgz z9m!D9Ks=Pyl|^3-2nmk`fu5|)s&Z7KsB6)mA#;~5KkL49WntR>ty|(V5F7_c0Bt7zTFJ(E6!?}XQ!n2`gcyDaM`hHeqYTJ<>4uXFr zNS!3<&m|Tb4DI~jcNdd2Sb+K`@iu=gG>$#cc--BA71sar*!)KJ>ag0iO3Co&0&cV; zbJ{=D(stq%-0B6i>v~9wMXuR&j-8QT-{s%cNizzy%5CquAfF-i>WG8XP^3Y0y%J)Q zJ#_(CQ36z4p5QDDebOFh1RJ~154;{JUag9>F*AAE+)}A`ryha0(!k5Utfwwz5B^wK zwt77@baA$R#!2yyOq1LKlc>j%BJ9KI5efik)Nb2dD4SjAJw!Ch9&K%p+GCEw*rQN; zk57r9r^&hV QE{ZmQck^~_bfIMb3#AQl)Bpeg literal 0 HcmV?d00001 diff --git a/src/system-recovery/res/images/tizen-anim.png b/src/system-recovery/res/images/tizen-anim.png new file mode 100644 index 0000000000000000000000000000000000000000..a2e8f0b09b9048253fd469a1787b50d801e49fa5 GIT binary patch literal 30353 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

XZ;G zNQjBPwEjl^LupR^tYFcfuO%Emq>>qo-+FRN7#&1SRjwo?kP8h2%#VQ0 zSf)e0P!l4H-VGkn?3Q|3A>wl@Br_eJmn)9&o&1Vt&&7-<|6emHhjvCklVc%d$BlVO zdU`hX*-N_Ht~j;qv+(V0Vw<%mCMIUg&)W-mpFt?`p&a~rSoJBkYx~kOVs~G~JZ;g( zAx`z*+}+lFG_ zhJ0U_bi7v|7D18>-4&yg@Zu-P6bEJz?&3rwXa=ey^Hm*+SH8X?WKnl6ry5@o^y9+A zQOKqK)a(D;1AAuyIy|64;2o16kjSeMCl4hFo%oCi^*#H2=r`navQ9i_lqI=^%k%Pj zO6y#xEFhzGbcU9u4Id&wSd)c~#6*m3|0aA|98pfahxPjoq3(FI zMwryBce7q9g61O{CB4!4nPF-99II4C@kO$1t8ul(oqJi;n69x8Ejls^M7i}Bo@&UU zM!MRuld3Qw^OUnYz+F4?#57=N`@7!4Qi(T7K-#i1TG235H`(JB(B0bm)91Nz ztqPPCWLiibc51QvJVQBOO*r&&=a)VJ?emhpC_to-(9p&|C)jZ`)d}-r^6ch z$1P~bnxX-UNnl1jREd{*VjZ@Z=$(`7*dKGMZ&(%_YR$rp%1Gc3<94pU-dUnT zRCU~dx$aK*IVWc{$npH?a*^@HZl0NMw~tHGU3-zBeb`Bj`493<^R6hBV}a}Ur-ZcR zH9K}^w-2O{)A~Uiw7u|~6TN*r{q22Fbt^L$GkMas^aK6^=NZ27%Z9_(9bJYE-gUpr z?-LUf{LBVTTy~Pss$s-`-lwg`p}Mpa`;4=E3K>yJ{BoSHZigP*ha(}r;2vNy|Twytq^PJ z+FtVPO~lz83D6q^YPoox`#{IBcVFqWKQ-V{Z&^ED9ywK{yte zpcV_5mrtpUIi!E&ZmS@^6Pst0fn#j5=Xa0685$hcxyZ{5EQ6VtF6)UZQ_;_1qP=JH z*s9tvY}K-c*-(5|V@V|$-1awsYUJ#k9483JwJfqlXvV4Ht3ADk%)_7H=b6qfoFfE0 zPuGsif>Fh>tB1P-_dY#^RQa>AVfipU+||h+(l^+x6Y8>ns=aG2#Sp3DjotQ{J~s1K9S0W575Td?^)b@P!}5`<2cLso_5cSp;M#l zp!{%y_+5Z-)H?z59q&v}g*g1S7i>e1he-8<3mxV8eWU8bFbdl1_i)aaIyboLnt49Vf zc9X!|A@$(hV+aZk`0?Q^Z;s( zqBj#LYdx@+yMOL*S@1K6=Q-0u4I_! z&UdBThi|#(Su^JCw(%1Q6b|YB8nm>E;wTUY5c&W#6r~3KjHM4z*4UbwC%Z!a+0Dnv zZiFyc7beBWFMM=dT4h+R8K*OK3Kty@e>c6{VvHL&;|J9fRSg4$fc`hjs}v6E{bCU; zvuGdss~=(9T)i{}jrvAp`{laj8SEsK>oO_<)dNw>lGncS{y8YlpoJ=wi^`VAutp2B z@x8Rf^NgJHw5I#y$7t71vfI8Q>@C#nf6WY!3Hv)9PuhvmV2rVQUHZ>;#k}O3=-30e zdvT6yInPdw!pd+7tV7{&?zrQ&GR$UyL+kS4Ew9N2qEhw7-MwPx( z4XJq3vVvtL=)^kQzHYoi>#A+kY5-9#!}U07G^F2gd-A7Z#}&OJr=Y-?Hu51?XvjkC zzwIJ!PTl_8nY|du4ne|SoUf-1$kuYDpOY5Qjg4%Jh;I75X_1s%=G_AOL$&otN*CE% zu_|QK^N!2BnY>fTG48P4y)(&e5(-$X_D|NVy)3zxD zog2j;_K$ruDmhOVWhFVjHkW&o#MtO7u0auKx4#xoJ&@ue>g(%Y!^Uv#*1t|JcKJVU z4nU<)?8vu!9)m~@b!E@QZT%RZ!cx4D`>sg(3bZOLjf|Lux1fD`!^l7n=m9&g9Zy>_ z-RIr2hZPvQZe|#e%rr1T?iei3a)S*=<;W=*m-Up~1k%S@+SHaC8xhB=&2yyKNp z=wvz;hJ_cvl)jFb2*U)?r~YdIugeR7NiqB!l$t-+0n{rr`uVoR$~}y3#bus;qn~MdPlP0v+me##(e8QKez~bM8NC32 z-*=6F#~TnPKyqLpDBfMme@A<27mMZ}r_?wzM>lCl(PsX09!cTs#Rjbd_53_j`%0y1 zV|vx!44$c*uB^(01L(~GY;mtcm>fQ+ITQ}Gm!1)kMV~2dyJ(+!_C!s<=y=6942pX7PdnK-v+4yVYik1G#8DNV8*iN?YdERUW0l*?K_s z>q>92Um6crzFdI^{d-1L+$by5D^R~fhRUlahQBFxIG%XG9F_`2ng*r0Z-u8E_ zRE86n%C`=yZP%*XKvKJzg2C5bHKJM#Ps!c1;)J`GoR6jNhIL?bzreOJ zHTz9`Z=NJ{g~`BiH)H@634m8ODWY=q*HGbE4BCP`JQJg-h~!`AoKbPo-ba~bk^wvb zrYv`!BEzN(h|u+~3H!zjxW;aj?M)2O)B`kd<wD zC8Xaph9Jaq!=pNWPtG?GHOVj&Oh0>bBlQi3+?E}~h1?Jptt}Pp+b}Qc8`iLGF1Vi0 zSUtkCiDdSc@JG)k3MvggbZm2Y^b3@shk&g+47TI*D@NWw;-kMhTcH4ec7VSRuh8>& z{}imbVteypHK&2}%3>e!OG@=|0Ujbz3DswzFFzpaqCbMi zzj)IjY!G%di*V2{`qlJVazu=H^-c;R#oC+8)u?P#&`H*($YFt88`78hxUgVUXF>Pf zwmoGoh}aLv=c0H2+53dlQ4%EaZjk1MWKP`7B$ME8ewd?9p#XR6 zOHo`*%zjok8RBH~ikpDZd7T(Vcj%gyIKWZxbmN7s$v0KHoybfim=NLdvGL_YYA~3- zR&+w`do`W&%}l^Zdma2-ggAf)02m)1|B0Kl4;CFLo@k{oqF;YCz?tNxg3reBb9sG<(SJU?$Hibf=WgMKP6hrB;|A!PA7yVcUugAWS}>qsIx zT5WHh-RKR`34A&qb{WLh`CEJmamZp1km=P8&|M^~s>{^aiQ_c0G4-fgRKp;P%}nn% zeiksI)xhN1cRE{fTW4wL5d?6cg8)n3NlyvRgtcO~AsR)k_$`%*^G-u_#bKg-ZpDBs z>&g^!2TlJ;!be&@_}oJ*L#Khyk0t%3V599Vf_O5a*Gd_1?uQEG`K;~TyE_uu?XBdL z6ashyKQc>y^p;1g6DN&%hm$s}6Gb5#RZUIk$D892l!H)mP8rJCL=F;6aauFhlB3zQsnXVq>5X~lFr*L}f`&)1L zDp#e<7S2_NaV^27P1b-Y+>QS!G2^$#upKSdoxPdSlU`?*(GZSqa2 zvt{=pq@3;cF{mkQsO-AYbw*Omd-D!etYeuVI!BBk2-lkwAFm%go&~dx?=_i{XfU?z zB33o^wDy}gh%8>@h!*3euNS z>ut(JX=d%2=WNNc7`+2}uW$8t@)6&t`C@*ijw5&#_l=<(lk^@Nm4qoG@gKp9tTqvsRK*Pa}BKh*ZtvN4p z;?V^j*Q+HJO+;yZ@tr0~M2NL?VXY?SiL}^CIDySXg-Sh86}O6XB;+LpS+S<1*8~g{Tlz z$0G*OiJc8bDyo1q(ENY-x}Jx-$xiF3L)PWtTjb}$qMZEf`@LQjL3Ar|$h{Q0n~1YB>w zOBsHPYuP$!1GZ$n#{*2sM#7LxBKGEE_T;NOMx7bPpvCrFyRfz(k&;!}Ba(RypW{QF zOf9#%)2gWYzMV*8zy04MClKBH-zr=f5Y5)!5+$zJHZ zc#|f={$45JUobwwm6n_#@ZY*wkg=?7_3P^CFlhU6B{WY`T~C}B@kZ?(4pOYM$AB{) zYZWQ$NdMi_?M5GF))RNnuqbjsS5>BqPnn!D2rxLvLOF#P!7uPP}BM*ofk3uqA)r7fw%E zC%Cs@$U~f#H)sGY zSX0Lpmo0BK;tvaPd+Z+!;VLU3t#i==)x;n($XkLNujwzJS;wHBnIU5vwolJghX!>!Y^ z-d7x_=Ke`wi(!Z&D=_)JKi@YWM?~rgU}bqZheF%#uU~{!-H;ZAsq5ya{p0^eM3fre zW2L;@l(HvPuAtx8jkWhRLhV4*2tN8Pqi>RW2UCGy`@I9g85VuVFDERrfA3lv?fW$l zuGc1xiD%(mv{wY>5@@Wqf+dh$>Xw-CF1|eC4lAZM_OPIQdAW#a95WxvxqGBo>y^_Qsy z=m+TRTA;*09WQWUaD;S{g5SuCxzCtPZB9>3zz>Wyo}1UQD^wd1RN8$pfKAZS1kDA7 z)CXpLCR61NA0VAM$S0jACu@L_>P+2H(DP_f&~0a=vU$xH(W&EH=D*JoUTh@S=Rv)w zB%(A5TWzqst?D2O%Y3jy8tL<;k|AiokjfcOAoz{6FsOfw-TE;ojG8N0E!`12HTkJba$07(^265Sv_KiK64J4>04{p9YDyEx zXlaT0Tue7wT({#C-7p{(?C*MZjoK5E>$wm1{mttckLLB!c=Z6C!nytPT;Z<&BJpA` z4#C8Q@1l9=W)r9w4``(qF+(l9(6InFMPQ@^$TFH`0O7dfn5Gd^$j%w2 z89j8oZeJ1xBFKfX#-Tvka4CJABq?}mO!1LwoAN-?(5-1ABN+e>G~mAFV0`sVvNq5- zYzhV>1(QmkJ!2H!Z*|@>t$X5UsnW?d+jdUuWIy~h- zY@J=j*7%t!cf&E#6`RbdUX|gEGrWvxUS9=A2p-Df<81%@wX?JDp^IG)Q_f76<=m|Ds|%w>WT|IM@)Q#)T%=z@&0S4@gBUwtz`)8# zmY51ah!7-fb4pTMrJ3#2;=UuM(V3B_QKQ@VIlZUG+s^>HAiRF_C{C{URmbLg(+St=&_aL|ltQUoBO zeOsz?9|{(wr^=|^`%CEicSeD~b=$W8$Y1}Httz_#CpoL`q55r3zI>;Y3T4Le9jI(l z;n$RS6WJUJw>KO))4`@dRNyA}kMG z-wFXiuw(2ZfbUZL9lw&|Cy7QS^7`6^Qej9affC|rQ%;0#TOGSj86}zQRz(f&6^!Ds z;8NFJVDrKeKScvHSJk5WT|1l}67JdI-c|^|9(8sWFH9_dx3RLqUxrLYWBL&>GLPN6apbg?oi4sO;FX=7H3MoyvGMq4qy64#z-_zPe=^d)-k&cA z<{&aJn;`hqvlOe+9*0q2Jpf&poUbzPe5!BYJJCiW+TQ@-x^fnOVm4aY*%CCQh6 z(oZ#23fWFJB>67NI#`c>Xq{X#4>BgF{N^Jyns(BN?*7l1Pp{OzQ`$ zdJg+g({6Uru(PwnI(6M!|39++R0`c;UGocCV#TDoYtM8ZP72l9`gHG$6s_D z5_KC1(&4VT>7sp9|5w#pFhte1UBg4kP(yb&(jk)4jS5J2D@gYsHNenFm#8#|ba$uH zhzJtWT|)^FuhbUOpS+RQAE-}xphr&@F7@N(wd>~ki!DbsZ;$ln$Ge-PF0QEV=$elvRUpu+eF{I3zd|JNQ7+c&Qkrn=d7YL z_J8Ibf4}l6Wk)Gxiq!L2lM08^Xw}KgvX9+*VwXa4ietM-%#C_nnrwAkYOx*qb+m>R0InJ#6PHBC{-}DNsO26otB`su5>uUR5&>-KxIZ4F`(p-}#$*MaU zvf-336usnXo#E*8CI!q3O>?DLf3xMzR@LCcGbp)c%_|oFY0^N zq#i+Ezm~FmyMA%elIu;c>GbhNiZS!(I}T~hSii}b%JB23;8i%;=pbi5Dv+{$mw)@uS#JL1kj{wuX6 zo6ch@cuRq)yJDv+pGP-hdSHO=#Bo+Hz-D^O`DHbeVBaSSwlD~OQ#aCBli%Z@>Vg^E z)gPs~E`s@?nzakajX7m@&!Wb+GcH4*w+WX!>&FC#{x~!BN)`b$KT+EVw)$@9TlxpZ zKXdsVs*ck3vIFXw+oR=*Gql7=|l+sJ_w=<|Ty*mAYX?MLiCuF8rqr6-c~e(XfMlTAOw z;+7P8zwpWVLhjw;Y!xhl`cHT%3|b)=Pj$&@DE z%oPFqg&m#11f0P6P(<}e;p?e$(yv}MJCJ0lL;$;0E!7bJ;lvD6vCuC^s}PE9;O~%$ zkX;e0?SHOt?=126@g+}Om@j!*%A=lDgPB#sV57&K{I1O;?6lhtBOUpzg;vcQiVr?2 zn9;jGk(=t2&o3zB5l|#grb-w$n^3L&&nlfmXF(*k{^g}JJ>OpsfvyTh!e#LNr~HsV zqB#CykALzFN}qPE^!HL8Dn?4(+`OHy-lvPNG_9E(0#Sigx@gC%{s$rZsw>}5F z%&`PhlERXb`(b7kEKJZJhfkPTI$hAqwmn+Gho$)P;N`=>(~CY8dNNMIo?v>3=nD4U zvpBN((OOjXo3~Q3OYz?>jBH%Cm6S#|Re=8)_W0M0Gl`LqFZg=r=Y}Q0vPI^Y*4pj& zKJu{!Wfr2X%8K?E!I4>*{+SQHx=7f>lc0-`N5m1)qPXz+TOKa?xr*?~Ylzc}6HMnI zZR&h&_z(oM7a;%v_7bIsYFm|sp}`*B`0pjIhhs44KrgR^%C=kf`;= z{u`OajeOR_t3w=JSOKtc`HGi1hD<=YCiT>w;KFjb;~=*C>fWeHPiSR})MOua;DBt< zeXOaO@Rsvd;cWsPJv|ZuVItjQNcJ&(w7+Cme`zKz()VcjN0uTfcugtA=|WBtxpfEH z4|p-%_x&gjPctJ9v`0rqB$nOgR}TgSCe562?`E{;_FQ{$#MH^U_T0G0irIt5+H8^M zetdd}{W=rX2bW})FAz*8YwbHyzu@2eW+3U|pC5q$c8cAxrup9Lf%JT?k_oOeRH_3q zimbbV%&ioZ&90uYP$00I9s4qaQ{L%~8*p=jLYh0lp}&C%^#&6xpP zuoFSM`T^@E>a;99mFbq)pZQvH>dw~Mcq60A@b;5YkZBefgbvT z=ud93rvq`nPd7&?gtxm(=k-V4Ks0jTv!Azg>}s=2Fe0`#WEFPWrCi?Oc8W>;0asi* z@v{pzM1A`&ES^@x5K6ja;Qc_B3wCsIutR8B%s%j`x33SfGQqc=^pugZOIU(A7&JgP zfY)S4MGJw~mPE&8CMPGi*-dc^6L~cGU7dl6IqPx@%_?c&#iMdUL*3MGY405A%YG{u zDYJ0%R-+K^E*~Pxp-5SpbaE5WMtR+yCTQ8Ds$(~wQ>c&~X&Nwz^S`ta`LBdGyFo@Y ze|}5KAmB%>n-o&cNhp@KhNfYK8=*C*NQ9wnNiVoju5L65Ioq3c08KM6OPX({Dc<*J zoQw3a5#@J6buBrO_b-GCvuHtdVUaSzo#=hJMBs(dIP#oyJy#4whw(Dd@ch}4k)a_Y zx55Lv{upY(rsW)%H{PAe3geSt#Jd4U`;v42r90p|B6?7qx4(Zz+?+3TSC2|ymAC!gzLVYTV}wgU z7<9X3@Ug&`%bvrNsM(}iwVyN0=Fe>u6#5dwj(-Wmx`=fLp;F#APj2VS#4!q8R%BoC zU4GWK)Xr6gxEZUwM5oou5Xm(rC0u;x@o-2?&OU4NX^4=wP_ept*e@=NrM_M27MJ1B z=6!%VuF0bYLqBLr{yVv$0X1yjtX75(HpgFlb(Qse%R76V4YSyYn(me3Qjv{}Gzz7A zTq?B7);2>nv>#xbK+%+bl=q2dy2hzju0ER8;gElI(1_luj5aEFtj= zpY;nVgbsZitE(GL%^+oYK|J$rubbT4+q+h$Q{#svUfVfj!%66k=dg}%sE(`X%T;3S zuGeXeFHyPjIlbzaW!JPhO1X8OyzlKgRW3F^?kp0x^W7NUQJc0U`_osb@q>Vwmko!6 zDhG2qrCdD1a-?|VSW3!eJr*3-jV7;6#PG!Y^mZq^2zvZZXyNwNA1t_^vaxc*z_ihn zLL<|+qXD-9B*_QOTU%QSAF`D6mhoKAKN#WNX`5=QON|uKe!*{{6eb&2WQm08%M`Twv^6;6ffBeyWy>FP7L#)U^YftM`Ul z&nps>hc2YbB7+0*j65PSKOVJT9^#(QO}zW>GaxRIF9wr@!E6Q(B)TEuD175Qg;>%g zI?PWoXdO~^1ywK8t$pQV!jb7oP-_ph5yQWqOa5{jrTr5X_jw^>nmsMncA}v3OFZM- zs7K~q@SorXYbxaUiX@vPm#Av#6W3wy##M;RRxqjGVSG#Me6yDrNc^c_3%;r1tn6j; zA&)}?9&M}A@7%L`d$QJT?sANeTN#9WK?NKm`htP7h23{MNZCbiRSojjYX+OQtNi~$ zaX)?sKM*h;@6G6BH93PU|S9E&C8ujduCBfbWyw*H>N|7y*&R^v@@Ym{*6j5JA4iDeo}ffzT`VW zrjw#^%Q^t;@`Z~wj*aPOhO@(no84vF$K}~=jVMWGn{Rykodz|A%_E6EJ5>;2*d!^& zaW@fRu?0O~Butj;MJ4R%^M7Di7EODmiT~bv#8%|rLz8t-Cu)Nq4xENB&yLV+y#NQH zB{xf?Oj*B*=~oqD035w~m7ZFLA5>eDaopOz9I@T_$BzX>e<*acPA!KI=G-TqDLkw{ zIXSVztFtx2cdKP*XZsSV2h*d5^TUJ{7FQ%Wxwr(gB)+*Ub_6n(MlYK1^y3=DMn+XxR>-DAHe%Kf?~6bf!jzb}BDOL3;bjKnVuxuYK=uy> zJa!a-mY)^oSO{?`UAfwf#tf*vI_Q1+YZ7Z=T*$;CMVcw1s-NqPbCCMip+l$`x4Mea z_6O|UW;@sK)|B-!u>!7tC#$jau;yP;TOqu@D-5zKl}nV3xAoxY9^pdC@^YR?4xvoi@2?`0VD>WB7l*39+k&TE{8;~+v5m! z*@BUtY&1Qn$jYKC!Yq4sZR%kMk7ETT4;--Wx6U_ykr~}YRDy|jGYFzvMo&YAjR2~V zTj>hOzfEs6+Ah7iT)NQgPcqrThcz$64)$t~+L(4kdz-O%zVYO?Dl4~K_f6CC>T6(a z6Wn|fFf#NthVh^5q9c)33YTs+>&TB$P_Q<(IVea;kH903>teq%>f!|*9`AnfpoW&# zYB+icmwPSTg`{nN@X}|op77JYG!CYZaG2xdp!f#JE@*UxZzw;``Z9V}nIgF5Hk&5m znOn+VCnXv&5MU3m8e(q`>O{gjzJQ>`l1r{*&_SP=R9fQiI&&2;OK*0y(1`p54E+A$ z>NEoM;gKytG_52J&{KVs%wq7zrhiHjp_(&WfVvdh;0_6qfp{3Df@q$5*U74X3Fugp zZ~MsapvG!t#tci6T}3jejTFYTaol9sC;Y11BL8ZkBWox{B=c_@a{o-eao;c=@`9p= zE}iMSTY{@$m7B2<{6d@9_Ud%boiWlPTmt`#n2IGNw!Wl?nq~kx@p^232XKj=s_W#$ zz4?s{;9w&mlNP9|q!BY>$o25yp;l)YN^a_lKKu?`HG$00dda=u*7Bvj+1H`5-Yl%z zShSYo?P>Yc^mE*8c{yrEo;$t&um{r7N}ERxdgF_vc=NmD?PlSP<;5_bmXX%nCl61m zdnEtka`D&*bh-I0AFD*KGDvp%2{*Uno0l(NVnHlkzuxB7`f@`+K;SQt9?)J>a}rK5 z3H@x&2jyhcJph8j@UXSUk>8KDm_|aUmHiAps{GmmarlfjGq$Co#n`v{2j#yLPYt^& z5IVeYETwNzIV2z$BAlU+ZH$imEx~qB{mFP|7y3VXuKhIVh|g=^sNv+B>f1dviOW3W z>H>Y0sjwLbM^~Rk3u--IrH$>ksdkp3kpgwWqHItXVx!_W;F>sZ!!^5)2mO9vn2VSd zjin>HG$3y?Apy4v7Z@)rZ3y1vVvjHBD93fKsPdAnB9M4kQ$Mx}KHlk`U|%bGU?RxY zn#>(VbAUcR(8M=-^Hpgv2EVZ=$LQ<7cff%eR##i9y^q(nl|$iO=OSQeQ+>BFmzDgA zT;Bdmwh@iFQJd8l>NeTd7aHIW8_-KZhk}~s_MP>P`DffOn`mOcgJjLfCUA5Kx_dAD zdUt46(Bx~JOW)OZZYtP1*fp36ipo>;FA_YW>5kQ)$792--T7^?P{0+I2v~7#aioDt zSaUBGuO@=9Jq7wK;)t=tjW|IbZPXSdFmMV|dW*v^k|>LXx*vTmHuA+XycZv^p=+Tr zeQvaY&BGb}D@Cc@{X4R57f{)c*Vn$A-?uzWt7B{^v);T{OjJ3_H ztlDF&BG}nB_}67)FYbI4y`;G+e23Cu(@0ZN;2Xb4 z+jay2YK6XuLPG{7s|dVfPd)pz92t8`29%PJC_EN;r0|Hr%CXfWT5Rg(HVbi~dvao1 z5U>yzGVpT+@z5}3bx;EV9b`CCPHG??F!7wkHJqG zpu=7Q{eqIn;0Vg-QbUm?vVFblhXCo*FK}2Y>^;BpVn^jgr%F#hZHFZB4h~sVA&Rl_ zF$KvU-}oFnnYh-8J4%o}<^kWmx$R3qmfo?}gFsox!#;3@nm`y2bB#7Ow( z)kPrWG>kiPuM~_&Ql;|_7GE5NOeA88P50k$u(Jozezm9D zlEkCiEIs8v@7j4N+^Ie`jZOk9f4ieq$}ysPih0p+w6=H{!eI(Ab#bXgS^#KmzsN*f zS1&$me(EaJ$ldL)zdc!$JbXv%8tl&WRbhXM1S#|M+SdOJ;m5^(=i#qFiPO`#Gs;hvNiCkrO>1rJ3PYw&HEVL}VND6c(_cDrp?DK}*WT<8Qy<*R_ z6LoQ%+F^aQpYJ0v9eO3QDCMJdtxo>5>!EaRAwqsg3TVi)SHDPCz|l}y8H%liw&YqC zd!Gu^-xupY1b?A~EgiEn4&L%)pL!D}x(wL&f`)88SPa{P{7w6wgay>uGf}Qm&!eWUv zgp`c9wB;p;3w2LKhQu#HeFoB7vzaCW6+t4Smy>X?1ciU;ouSvI6Q{M9ZEFXaF}-$$tsh#ge;E8h${X*zfp3q#jiIu4rlPn%Mhw zFJTPTz7Wft6HBzktX5w^?yq;yRo7v(ZbuPF0R^72GT4k6op%saQ9$28IH23nZ+SN` zIEb@msIJ~I=_Jx6boP6v{0}BYwXiJT?tWL;esC)w0llMAf@h5gevPjKv)MP^lq|$tD7CUU)o)3U3yRVFMoSi#Pm>RZfY7lz!tb>|VzB z8{i#gW3JrDssg!H#t3=|;*Qw@MKffv}ct0lZ%9@54 z>Q7H26L_d5fZlWB40uiNR&a8Qa`IqUE+w=!aXtEwT!km_ zN|2McSMkeHB;rF{iB5Nx=BVzyI`|Jnk;PW8lO74T(?bI#iR0vTq~a`*y0>*hlV}$~ zyjI8sa4Q5SF{cHxi#d3_!mR~~Xz?rJYlLFgY2VVyB(Af5SpON7n5VtD!!NNe^c|jO zA&^Ys=Uq|IL|9~FLIe?RYP#+zYDmaDG*YM#`#ke}aIuE?U)+*PUC(2Emi@7Eun0*+ z@c*(3@K$)lsYS<6)k$1tP2Hd8fLqy>{KeZ=Hh><~&9KUOtt$ko2?_le$GsM;$NUCq zb=6%%L{+FPkUM#kn1PXLEj;ZP?lS@=3N39$ng5~iX3X=Z2ex5~5Oh;#r9tTqDk`4fU&XErVD4v^@PECXsZ#$1j+&GeiOgKNF0D)#Mo#`;nG?oiE8BH$HbC zgAW(t4|ihe55IPnEG`VvFs@!|tfY3>T#ZSUxg5x!LiKIAra=CA4s=-8+aJAtA;A$9 zBPjmhrT*KmV{1`4d{91CN@=u<%sF?32>u;XZ(6s8#np|DJF!ygw5oe?3Gmhxx1jL$ zVEW5%wAnV#Q~9#k6NzVcmcWAHp>%NBs<|NfwoyINd~6d{(2R`LexnehPI+^4)*!vE zMz3x9+JW39E4wH?yRFF=BC~p6Ngf)@-?itm6KXU>MZfJtXEj2K7t6nh* z6jNc=hhl;=%&ID0>o^;Zm%ealnoLvZK{oiR)aL*(rL&n^2i@Lwr64vDbzs9U6Q?Zw zw=Nfdpy)~+=e&I_#ZadeP^~%7drVO;g;j$68<@zO{Po2Nc{bO^=j=`7*;Rf* zZi;_@vT_GJCh%nbw1|L-C#u=_oSR1YHK_NvX#`ciQQRQ)WP1>yP+r!H^t91l8^9$9 zOeW79MUTH7ofPL)Zjjy@xU`CJxU_o9k(LsHs?xM@)%2lLe)IapRv)*z`H-M8sSoZxB|2ndA@jCWW1ue9G;&|=8f@H z$9J#s{Ka7P9ET#$#WrZiwrgDKz<>ih$)7T~iPn!KwQGu$sSCK@!#A`A+d0)FYBT(E za4vF?amF+5NtXFnzKkx!B~cXPEa5Cr9q}w;bQ>0CG&(&4G)<>H@J43*OVH-N?^nw^ zVW_;kyuvPR*$#nc&u_tOKDJe;s1wAXi=(Rix}6BR*PVC zC}cG|l0Ly(WsF>A-*JfTlWiwHKC|m$pLXwl2g>=zRR*h#J%_>d(6R+4dDO%c-j9ZF zql1_4=%Ki+m+S9&9p@Ty-(X})-%{fAO=AWAH!@=a zcz8B%)YQL+!Kh#7a~|9%qom-&3h)}uz!|M-t#E|~BB!w<`_1@exD!VcQ6#gEiaR6K z;6o{`TniH1)&w_cWCh`r2gKRzn=U^MT7F=FO=0&%LKTpqH7H2A9*)YOHHv+JG4-E> z>`2a<@vj$RIZVa8G(n{I1El3AL}dwd35lE_K_s)}&p|7)NEcg`j_L*`)<8rephxlQ z?Nkz|u8+FTZ==Zt%zDD{`>pD-4uq^5q1B&C?cSYp(tQWfeiL>08ls&0w=3O|gjsa8 z?MAh+z=obwlUj>K@^;Qo{82p)wzqr%;jJRry&977SerKQ=zXN~R^45qyESttKQS_4 z;6GuYm8+Hyue3QFa~M-o*Vb3LM^d0EL$F2rs}3$5XB;{oCREYJrE+I8mcSO-CSUH6 z_8-%WzH((3d_ts=GTcv?(157`p3S%6z4=k6uA#ri*2>Zy7Fm5WEVR(#xZD!~+p%;V z;l3^)(vny1i!v-^8@H44@jJ%U%YWAyMPeG)5dL@O56HMrj*fnqoZ2z(;p2We<01a{j-af&Z%3r~Db3U_egtx^i4-42kWPxQ z_L3WzPzpD@s6T}@TRo6TpyUQgpgNCzK15tt|5OhJYMsMXMpS1M31eKXcC`MT>(f!L zgV;WwHt@BZRz&=c?i;^{@5P||W}4Tp7M3M|`O}|l&x!|I!@4>yIy*LI2Lu$IMZ_%7 z?URCrnJ}5WB_zH7OuPEkR-@R+_RqN62kV2E7anIGN6xX$ekhTq#XN|BvE{I*jN&o0 zXqeB~282v2-28i&ABSW|#?1Ay%1G3h>byNU0i{QYpt$hi}(|5W^p%RCO@ z#;m*gs-fNENg`i93{{-Ao8%-q^DoXrEs(!JPC^DU2^f&vp|VD{>1Pgpde`z;6fCf0 zQ{2vpT$Vr@HYt~Ek%280dfk}WCRHe`_+d7eRuH!fL-M)D1{@~9_rwftX{%1d9#-<) zRMthA`5q$fO+iGdy4%X(fJeg`o`0w_wzJlwiiD`37mb37$S;yG!Gg(dgqQ{(a0l9h+!94K#tK9%t|!jCIMIJbjyk?u*#~qS4U@ z#1V|GF!gkPTtw5of7Q;^I(aF^r>q|HbKp(Rt$+m1jvv6F=JMJ2=(Py+gXOWb+wl$Q zm?i_H40ehu7q4}urrQ*+JpMI*i3^hukX?Mqt+supJ`Qe2k&}Yd(*yEr_zjX;&oO?s z76jj1yYt(}u}s&;uzrWs{-(0;LNqiv}xKu)T@Z;M-XdsA>j7X zW{hoK&1xbEU=fs6c96CUQoH`6EGS&E*-2_ zzNo0CbtOj3GvM}eW31e?{f(DIn7=88z-ZLk#;IM4w{#C_xuW-Danb-zE{=euD2dPi z5Q6vqY=ulq2ppcDBEX>BFsrQqP97dVdXGg?99$`J4K4(cy>wt!h)=-gcq^H!Bf6VY z6r#lJ^hV}_FBEJJ_((Dp7#e@W!O!XI?u6?ub#x-L_0a}K7X5(+U}Y!X#pkLGN-MfJ z$!bH%{^F`D1?Eeo9A^B%1GEIXb6Hw^^fr5>$;2%nt^Ap>H{QhJlg1$pEy?P725mN5 z^Ipc+fjPXw(tX;J56%{ghplw*ka-XH?0(@nG39Y6XMWh=aZvwHdsmehNYi=Mf@ab_25{!8=1GliYWuUKH=eq&X7Q?fmYlk9v5Du|3WDRAdqu!J$JEq zl4%In^OKPah+}W7ztpU7wWLZ)CFXA0Da$A27(oAb#$wH)^{L?xUtKMx)1o*nDK})- z5#wQpU@b8*=2{linzC(z%{r5lm>dL}#orsEy$5+JBQ;2@`v|MQI2`dipY!f+H}OHI zX}bAMh}>2jfQ`WVMcVF28Wi?BIVg|xuDrT^v=aL4Uu(K8bT)aNaNcX3jqZ7LW)V<+ zC&&p3R_%uY?qTA}Q!OE^%c0@ydi$%cBB|Z+HjZmin@y+FW~;|a=0-8T_`d#6B3YSi zP9FrWawBf`cd~O%I>fww`7PiaJpD~-Bza5!FF`2^E0jZGq_H0T4Bsh6VhHOxRUeqt zmO^lDylmV!0c5iIRVA3ewrfZ|uj_12P|oKLZ>vYe(az`Z=swu2%uIGl(!oa+i*bj^ znqM2R-eLbO(-Uz!7Qflu!BTH8ZDimmo00(r-6*^b?k8kKsEHpVHn{2W1y=`TKj@7v zz54+9cKG6X#AT)`9Fga)9n9WJa8}TU_Wtn!nP2}rZp+>GiP5fL+&SRRw*N{6aR0Pm zcAw4lIf9C=89AuL$QVP(JlqIFX(-o_<=D~QvSHbXmtO!jRub32!HD`ym#P@Mqg_-B z)$B$$_zv;OhgAIZn;l|tzCJS?fi&UXTV5;~m{Sw0-r1x9xg`>(HN^kdZX|+%5!ZDq zd(rkC29N(07|CLHOwGKhZF0fRpc{#|#@^oYdan|Fp=JHyBPM)$tk^>3%@`wGuhf&Q zk0{6~9r!^#GaMn7`uX1YUm{=LVfxk*JXpB;B*_WgOa8QYCPw>b*9I&_pr|Va9-=KS z1(;LiIHmnU^L3v2-;MI8-oW{@WpRJMBAVJV2BSg51ycEG`XVy(l5D-}OR)GkZ8- zu6F+?n89`UeiCy*J;^)xkkTqwv0aDH?&Yfw4~bYI_&H*7;TptIwpr_Q_3cc1=hRK^ zHva=JNZ;@d`BVE(9SxbMcb3slHq}495q42}&VcEy^(ed$w&?uzt2V)0gi1V}EAdd? zk-ccwxsL8aWU*_Om+yq;K&H>RWy5(B$8(ztL^tHXeeA-UHk*xi9(fcwZvIpUeUJFx zX(H?xtJ;y?IfUHa(g-2rr*RJ>Q-EI2FT5rLRUJ4!$lsCkXTSz^FKIF)4SclU*T|Wo zcC_9ImOI08fj*DM)Q_j06o~^w$JKI9c(LamzIJFxXN!?RQj0E_<#2!hFYU zt}5eH0ZcMghAhM6?x@5_@Q%s4q?xFCYGI5EbP9vWR*}tlP>73GSnjY2T{jWWWTd08 z&Ng_r-tt>Gf5H#R;uU9B*`<8NPXF)eX{Byv-<$T8FNu|wFT~|k>8-U0Q9xk3&4zDs zp?bR?r<#fcgP(v4e&?XM8^u|>XzRk`84di6yMgzDTZNhTa;u>qW+)2cfa3fj%fwPOz@{?Mv_vS+IdZovc{jUHsV-AF= z2)f$WL6K7bd2_*hojc=T(G7~@QaB_wZKTBbVxe=&J|_D@-`FdsaW>bSxjc9kDIz^> zf1hJnwC}=4x>~h~C*MeNjc4%t@qSZHevX#or8iQI<3i@&CdP~!*Y|i9A4XF98HR^6 zvjoilGE5t;eKCUr-v(cWz1ogtDzcv$t9HY@+%c@RTh(lz98&4n*#m48@9T_? z2VlCZTN3pVpVlQ%IHtWA!+4ITb_HM-wvWdJ79H4CfT~>ZsSv4Q=tXQr;s$M@obSBr zrZqQMuK5rnivuviP0&OfME?xe@6(njs7}_bfDwhdg~-u?E>Z`nGv;sw#|9CAcA|pH zt!BQPg=ueE(p4w);^+DV!Ozh|F|88ys^?z?O893nBfmLkiDdvQ^#6KW@eGDM>SccF zWGVDl=f_zBLy@1Nb|wWmk`hPe0c!cY8g-J2S*Q4e0qF(ALr>bj@3 uEGHF2A}#8OODJlDL+;^P?de%N1 literal 0 HcmV?d00001 diff --git a/src/system-recovery/res/images/warning.png b/src/system-recovery/res/images/warning.png new file mode 100644 index 0000000000000000000000000000000000000000..d5916962d412d53df54e6ea3719ff8b99a4ae402 GIT binary patch literal 8182 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 Tfu;Wz^hgRaD$wc=Cc*y)-!HxG literal 0 HcmV?d00001 diff --git a/src/system-recovery/system-recovery.cfg.m4.in b/src/system-recovery/system-recovery.cfg.m4.in new file mode 100644 index 0000000..664c272 --- /dev/null +++ b/src/system-recovery/system-recovery.cfg.m4.in @@ -0,0 +1,285 @@ +// -*- mode: conf; indent-tabs-mode: nil -*- + +m4_define(`confirm_action',`({ + label = "Yes"; + action_handler = "$1"; + exit_after_action = $2; + },{ + label = "No"; + screen_switch_to = "BACK"; + })')m4_dnl + +action_handlers = { + reboot = "reboot -f"; + factory-reset = "touch -f /opt/.factoryreset"; + safeboot = "touch -f /opt/etc/.safeboot"; +} + +headless_action = "factory-reset"; + +colors = { + background = "#000000ff"; + title = "#1bc7ccff"; + ruler = "#1bc7ccff"; + white = "#ffffffff"; +}; + +ruler_styles = { + common = { + c_ruler = "ruler"; + }; +}; + +menu_styles = { + common = { + item_height = 80; + item_spacing = 8; + text_pos_x = 15; + c_bg_selected = "title"; + c_bg_unselected = "background"; + c_text_selected = "white"; + c_text_unselected = "white"; + }; +}; + +screen_styles = { + common = { + c_background = "background"; + }; +}; + +description_styles = { + common = { + c_title = "title"; + c_text = "white"; + }; +}; + +rulers = { + main = ( + { + pos_x = 0; + pos_y = 80; + height = 2; + style = "common"; + }, { + pos_x = 0; + pos_y = 420; + height = 2; + style = "common"; + }); + + confirm = ( + { + pos_x = 0; + pos_y = 80; + height = 2; + style = "common"; + }); +}; + +images = { + background_default = { + fname = "@SYSTEM_RECOVERY_IMAGE_DIR@/warning.png"; + c_bg = "background"; // reference to colors + align_hor = "center"; + align_ver = "bottom"; + offset_x = 0; + offset_y = 0; + img_type = "alpha"; // alt: "no-alpha"; + // surface = ; + }; + menu_title = { + fname = "@SYSTEM_RECOVERY_IMAGE_DIR@/menu-title.png"; + c_bg = "title"; + align_hor = "center"; + align_ver = "top"; + offset_x = 0; + offset_y = 20; + img_type = "no-alpha"; // alt: "no-alpha"; + // surface = ; + }; +}; + +animations = { + working = { + fname = "@SYSTEM_RECOVERY_IMAGE_DIR@/tizen-anim.png"; + c_bg = "background"; + align_hor = "center"; + align_ver = "middle"; + offset_x = 0; + offset_y = 0; + frames_num = 0; + current_frame = 0; + img_type = "no-alpha"; // alt: "no-alpha"; + // surface = ; + }; +}; + +menus = { + main = { + pos_x = 0; // use M4 macros + pos_y = 100; // use M4 macros + style = "common"; + // item_selected = ; + // item_default = ; + actions = ({ + label = "Reboot system now"; + screen_switch_to = "reboot"; + // action_handler = ; + },{ + label = "Safe mode"; + screen_switch_to = "safe"; + // action_handler = ; + },{ + label = "Phone reinitialisation"; + screen_switch_to = "factory"; + // action_handler = ; + }); + }; + reboot = { + pos_x = 0; // use M4 macros + pos_y = 480; // use M4 macros + style = "common"; + item_selected = 1; + item_default = 1; + actions = confirm_action(`reboot', 0); + }; + safe = { + pos_x = 0; // use M4 macros + pos_y = 480; // use M4 macros + style = "common"; + item_selected = 1; + item_default = 1; + actions = confirm_action(`safeboot', 1); + }; + factory = { + pos_x = 0; // use M4 macros + pos_y = 480; // use M4 macros + style = "common"; + item_selected = 1; + item_default = 1; + actions = ({ + label = "Yes"; + screen_switch_to = "factory-run"; + action_handler = "factory-reset"; + exit_after_action = 1; + },{ + label = "No"; + screen_switch_to = "BACK"; + }); + }; +}; + +descriptions = { + main = { + pos_x = 15; + pos_y = 480; + style = "common"; + title = "Controls:"; + text = "Volume Up/Down to move menu cursor\n" + "Power button to select"; + }; + + reboot = { + pos_x = 15; + pos_y = 100; + title = "The phone will be restarted."; + text = "Continue?"; + style = "common"; + }; + + safe = { + pos_x = 15; + pos_y = 100; + title = "Safe mode:", + text = "The phone will be started in safe mode.\n" + "Home screen will be changed to default\n" + "setting and just allow a user to use\n" + "only preloaded applications.\n" + "Continue?"; + style = "common"; + }; + + factory = { + pos_x = 15; + pos_y = 100; + title = "Factory reset (except SD-card)"; + text = "This will erase all data from your\n" + "phone's internal storage, including\n" + "settings of downloaded and preloaded\n" + "applications and system configuration.\n" + "Continue?"; + style = "common"; + }; + + factory-run = { + pos_x = 15; + pos_y = 100; + style = "common"; + title = "Restoring settings to factory default."; + text = "Please wait. Do not turn off.\n" + "(Hold power button for 3 seconds\n" + "to reboot the device. Not recommended.)"; + } +}; + +screens = { + main = { + style = "common"; + menu = "main"; + rulers = "main"; + description = "main"; + // progress_bar = ; + images = ("background_default", "menu_title"); + // animations = ; + // on_enter = ; + // draw = ; + screen_back = "CURRENT"; + }; + reboot = { + style = "common"; + menu = "reboot"; + description = "reboot" + rulers = "confirm" ; + // progress_bar = ; + images = ("background_default", "menu_title"); + // animations = ; + // on_enter = ; + // draw = ; + screen_back = "main"; + }; + safe = { + style = "common"; + menu = "safe"; + description = "safe"; + rulers = "confirm"; + // progress_bar = ; + images = ("background_default", "menu_title"); + // animations = ; + // on_enter = ; + // draw = ; + screen_back = "main"; + }; + factory = { + style = "common"; + menu = "factory"; + description = "factory"; + rulers = "confirm"; + // progress_bar = ; + images = ("background_default", "menu_title"); + // animations = ; + // on_enter = ; + // draw = ; + screen_back = "main"; + }; + factory-run = { + style = "common"; + description = "factory-run"; + rulers = "confirm"; + images = ("background_default", "menu_title"); + animations = ("working"); + screen_back = "main"; + allow_force_reboot = 1; + }; +}; diff --git a/src/system-recovery/system-recovery.h b/src/system-recovery/system-recovery.h new file mode 100644 index 0000000..b75ade8 --- /dev/null +++ b/src/system-recovery/system-recovery.h @@ -0,0 +1,46 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define LOGD printf +#define FILE_IO_BUF_SIZE 128 + +#define ROOT_MOUNT_DIR "/system" +#define INITRD_MOUNT_DIR "/system/mnt/initrd-recovery" + +int pivot_root(const char *new_root, const char *put_old); + +void sys_power_reboot(void); + +int recovery_gui(config_t *cfg); +int recovery_headless(config_t *cfg); +char *get_action_from_cmdline(void); +char *get_action_from_file(void); + +#ifdef __cplusplus +} +#endif -- 2.7.4 From 6a2fb1ede6322c313c1763ee442b528d3723f4df Mon Sep 17 00:00:00 2001 From: Kichan Kwon Date: Mon, 11 Jun 2018 10:33:50 +0900 Subject: [PATCH 3/5] release : 0.3.0 Change-Id: Ia24b47673f4295652c5a512490f2ebdd1c570b41 Signed-off-by: Kichan Kwon --- packaging/system-recovery.spec | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packaging/system-recovery.spec b/packaging/system-recovery.spec index 4742d1e..fcbe199 100644 --- a/packaging/system-recovery.spec +++ b/packaging/system-recovery.spec @@ -1,6 +1,6 @@ Name: system-recovery Summary: System recovery -Version: 0.2.0 +Version: 0.3.0 Release: 0 Group: System/Utilities License: Apache-2.0 @@ -17,8 +17,8 @@ BuildRequires: pkgconfig(libtdm) BuildRequires: pkgconfig(libpng) Requires: initrd-recovery -Requires: system-recovery-compat = %{version}-%{release} -Recommends: system-recovery-non_gui = %{version}-%{release} +Requires: %{name}-compat = %{version}-%{release} +Recommends: %{name}-non_gui = %{version}-%{release} %description A simple initrd menu for system recovery. @@ -26,16 +26,16 @@ A simple initrd menu for system recovery. # non_gui profile: common, wearable %package non_gui Summary: system-recovery without gui -Provides: system-recovery-compat = %{version}-%{release} -Conflicts: system-recovery-gui +Provides: %{name}-compat = %{version}-%{release} +Conflicts: %{name}-gui %description non_gui system-recovery package without gui # gui profile: mobile %package gui Summary: system-recovery with gui -Provides: system-recovery-compat = %{version}-%{release} -Conflicts: system-recovery-non_gui +Provides: %{name}-compat = %{version}-%{release} +Conflicts: %{name}-non_gui %description gui system-recovery package with gui @@ -44,7 +44,7 @@ system-recovery package with gui Summary: mkinitrd-recovery configuration file for spreadtrum platform Group: System/Utilities License: Apache-2.0 -Requires: system-recovery-gui +Requires: %{name}-gui %description sprd mkinitrd-recovery configuration file for spreadtrum platform -- 2.7.4 From b4479fc4b037edb5123b397e25d746564cecd49f Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Thu, 18 Apr 2019 11:50:35 +0200 Subject: [PATCH 4/5] recovery-action-set: set default PATH Suggested by Security team. Change-Id: I0ca221986644882dd359f671b2e7689b3f6332dd --- src/system-recovery/recovery-action-set.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/system-recovery/recovery-action-set.in b/src/system-recovery/recovery-action-set.in index a6ddf8c..7bcf9e7 100755 --- a/src/system-recovery/recovery-action-set.in +++ b/src/system-recovery/recovery-action-set.in @@ -1,5 +1,7 @@ #!/bin/sh +PATH=/bin:/usr/bin + CONFIG_FILE="@SYSTEM_RECOVERY_DATA_DIR@/system-recovery.cfg" ACTION_FILE="@SYSTEM_RECOVERY_ACTION_FILE@" -- 2.7.4 From 63972caf76777e94b5f01be2a99c5893002d0174 Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Wed, 21 Aug 2019 13:59:04 +0200 Subject: [PATCH 5/5] recovery-action-set: set PATH exactly as security team requires Change-Id: I3604f3c153b1138989805a6f5575849fdcb5310a --- src/system-recovery/recovery-action-set.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/system-recovery/recovery-action-set.in b/src/system-recovery/recovery-action-set.in index 7bcf9e7..67c36d2 100755 --- a/src/system-recovery/recovery-action-set.in +++ b/src/system-recovery/recovery-action-set.in @@ -1,6 +1,6 @@ #!/bin/sh -PATH=/bin:/usr/bin +PATH=/bin:/usr/bin:/sbin:/usr/sbin CONFIG_FILE="@SYSTEM_RECOVERY_DATA_DIR@/system-recovery.cfg" ACTION_FILE="@SYSTEM_RECOVERY_ACTION_FILE@" -- 2.7.4