From mboxrd@z Thu Jan 1 00:00:00 1970 Delivery-date: Fri, 14 Jun 2024 12:56:25 +0200 Received: from metis.whiteo.stw.pengutronix.de ([2a0a:edc0:2:b01:1d::104]) by lore.white.stw.pengutronix.de with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1sI4bZ-005t6D-0x for lore@lore.pengutronix.de; Fri, 14 Jun 2024 12:56:25 +0200 Received: from localhost ([127.0.0.1] helo=metis.whiteo.stw.pengutronix.de) by metis.whiteo.stw.pengutronix.de with esmtp (Exim 4.92) (envelope-from ) id 1sI4bY-0000mH-2h; Fri, 14 Jun 2024 12:56:24 +0200 Received: from mail-ve1eur01on2058.outbound.protection.outlook.com ([40.107.14.58] helo=EUR01-VE1-obe.outbound.protection.outlook.com) by metis.whiteo.stw.pengutronix.de with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1sI4Po-00006n-10; Fri, 14 Jun 2024 12:44:17 +0200 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=I+XxT8u0MySGKExEAbgF7fwo/NpMGUaBWJvY2bcv76WL+kguHATr+2daw6qOrUjTN2W/s8t9xV7/yfid6i0IG9N1stUmCM0OAk2cFYPVPySfBxSK2cFa5OIF+yP1KdLyDs4PpQ0b44Lvjnw+nZldNOPoo8SlXOWJK9FYr3z3R5h3z3Tj4YPBCgaKC5wYVJv16BDlPKgXijAZgauUEK9P+GpojQEFugFj46hWd+MiXNdytYoW3MXIf0ECgDD7G6vG+85QPjJaxACS0lLFGi0ec47Pu7dacq6+BswWiWnrIuXxJxiPI/IX5QqRLNnCApY/3ZSuUxWc/WUa2kaCPfjEtg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=fMn9vKVlrsIkHLHqcmAz/sLy66PspQ5twZ5RangRaWU=; b=RLJKuuV3Omn423Yr03vEIUK474RQTKFk1lmDlJTvSEmPQEH6oiZ5h8tVCjqNVbcNcTzUPJ7H0kdkVMBQz6Z4bcRr0kMAVxgQ/0D1rlHtSFqalqJch2LKAQ8kz5R17yCrZPPWDxoWpulFxMF+HUo+KSr/cmcw2rA2MPQdyK+lHUcz9hgNLVJEOgmOpEJQCuexkPeulvcs3yb1tS045SMNPfVSGdq+MFOpuPIYstANFK/y8PXrJsl70SegmhEgf4X8W1uE5740eIIgtp2DvEPJpWvXY/EtSj659WdjV5XVct1uAly1F0wGJNtgRwUy/osGxLx+I0gKGYNiqKorQtd9nQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=leica-geosystems.com.cn; dmarc=pass action=none header.from=leica-geosystems.com.cn; dkim=pass header.d=leica-geosystems.com.cn; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=leica-geosystems.com.cn; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=fMn9vKVlrsIkHLHqcmAz/sLy66PspQ5twZ5RangRaWU=; b=CBdhpfv9g0eLKNKRPIHUxvTHvF0PQzI1jFC0tvhV+HXwVaiXG1kR3DROw514j0kGUpRzGLlv+mCAYSDzbeDCEYSSloajwYNKJ9rZHcVLgxZUk8tQ17wPgccq+arvmXNvjYiZt19KPUw94wnMh6TGMM+XFeCCwFDz5anKbkxD49o= Received: from AS8PR06MB7432.eurprd06.prod.outlook.com (2603:10a6:20b:319::19) by AM9PR06MB7347.eurprd06.prod.outlook.com (2603:10a6:20b:2ca::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7677.25; Fri, 14 Jun 2024 10:44:13 +0000 Received: from AS8PR06MB7432.eurprd06.prod.outlook.com ([fe80::6e12:7988:eb22:7e30]) by AS8PR06MB7432.eurprd06.prod.outlook.com ([fe80::6e12:7988:eb22:7e30%6]) with mapi id 15.20.7677.024; Fri, 14 Jun 2024 10:44:12 +0000 From: LI Qingwu To: LI Qingwu , "oss-tools@pengutronix.de" , "m.felsch@pengutronix.de" Thread-Topic: [OSS-Tools] [PATCH platsch V4 4/4] Add spinner executable for boot animation and text show Thread-Index: AQHavjx9ewMWDxSC0Uyt+JoNnJwxmbHHElDQ Date: Fri, 14 Jun 2024 10:44:12 +0000 Message-ID: References: <20240614092308.1429018-1-Qing-wu.Li@leica-geosystems.com.cn> <20240614092308.1429018-4-Qing-wu.Li@leica-geosystems.com.cn> In-Reply-To: <20240614092308.1429018-4-Qing-wu.Li@leica-geosystems.com.cn> Accept-Language: zh-CN, en-US Content-Language: zh-CN X-MS-Has-Attach: X-MS-TNEF-Correlator: authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=leica-geosystems.com.cn; x-ms-publictraffictype: Email x-ms-traffictypediagnostic: AS8PR06MB7432:EE_|AM9PR06MB7347:EE_ x-ms-office365-filtering-correlation-id: 6ffdda6c-7bb3-43cb-9f2f-08dc8c5eede1 x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam: BCL:0; ARA:13230037|366013|376011|1800799021|38070700015; x-microsoft-antispam-message-info: =?us-ascii?Q?BjvYtyDOgZurAUxPVA8aXB9TgTfpxVawYGZXiDZzxeNl+pIdAQiqmg/wnjgq?= =?us-ascii?Q?D5EtO3oiZQ6kBL3epZaMZYEJoxJWTOmMCmQ/3g0BSVPNVYGJF68LfU9jSdXg?= =?us-ascii?Q?noroJM7BKUt1Qx01dut9jPQx1hOdRNY9Ukg2IMac4ZQ/B3xjwbMnhVqUUkrU?= =?us-ascii?Q?wow1gEDu0/iYwWR9orBK9FrvuOk5NLU2m5QwIVdXrMETPnFvridsahic/uwW?= =?us-ascii?Q?Db23TnJAQBse3G41D7F2smBRcgEzn0+gcPvTHxb0M2xkJZmQyNKazQsOBf9b?= =?us-ascii?Q?yGoLaXV2D4TmGQrkJAqFVsBANG3UbflCrRhtisCgfDSkrl+TxiwuJQSvSKiO?= =?us-ascii?Q?icS+xI3nP3xZ5ELvH1xl+3qwDLeW5C2C8vwQjCLVmZXJ2wwThYgPv7iahk6u?= =?us-ascii?Q?BcG+UWMKL6ooPWQLgsG7FNQwpj6s69hHMTqHyTZodukZt7W06XPDyEuyP2GA?= =?us-ascii?Q?zC0oE+4ugjFXHNx/FUJybcvu0y9ke9D1oaV+lZANSifrUt9zAniYlFCiVMHg?= =?us-ascii?Q?WdXUb4fzSGr7VRF/WLF29NORR85jNjvkIuQKgNevJrxEjm6Qsi4xue0JZ98d?= =?us-ascii?Q?8Q6NXw1VhL3wOykYZMWVJbujG0XL8G3MGB5yjB/UDIKLppukT9xRoMFNPod/?= =?us-ascii?Q?oNfVsOqKm63xfkLwCHZNOC/jjTyZ4SiLRnS93Z/T2mUDCf/IN767+WPJnvNd?= =?us-ascii?Q?XUuZMNhi4L1cJ0s/POK+EQ72Kdik2EGHtQx+nT21d7CjgpNyR9lyeXT9VG7M?= =?us-ascii?Q?g78K5vw8GF2OhQI/1SEMwYbExuOHHjz2mBWHviQKubWBvhwfwRcaEayrP1O7?= =?us-ascii?Q?TFtgjoipy72wMOxysBmkK6Wczh0uXLpXopEqExuQtXNrCFIuRPEgM6uSwkZT?= =?us-ascii?Q?qE0d+ApItXeQVR1xpnXJRnrTeuHIs2pXMFCVctN6ek2IROaAs/JJAMMD5ZFX?= =?us-ascii?Q?VH22FBE4dTJkDkhMMO8SMfXs2sSTd8t5wy/CE6VzdZUa/v0vjijTvyBteIUB?= =?us-ascii?Q?DRcyZQcFqNORS8IIcjesFx2S12jcvuU54mVTgBcYjlzfVox3TL7KtHeakyCq?= =?us-ascii?Q?0SUtaqP8ro2IYZzzZoxNdDp0dGRm4tZLd/4+o68tuzT7D1bEn5fAqpCVUUX5?= =?us-ascii?Q?FeQQjEbqQ/ha6F73Lao0Xk3NtoAII5MaOuQhD7CCtdekAmIST+JS2jsJx6Pp?= =?us-ascii?Q?XkHTsNGIlvaenRc8A7J/U+YuuJ9pNlaLRJ1iFu4jE3/SVg31CEs5ErPDbW7V?= =?us-ascii?Q?O+hHIFJo5Etk8EUjhJujxOyAEMhlZFxPt7OqSxvWwoommGJ4ivrnr/xlSeKb?= =?us-ascii?Q?hBSj5jB8DUYkEKffJ/Zw/yf2iRILXEt9pLNARktqbzVFtt6u3KYS2hf5fuL4?= =?us-ascii?Q?a8XdFBI=3D?= x-forefront-antispam-report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:AS8PR06MB7432.eurprd06.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230037)(366013)(376011)(1800799021)(38070700015); DIR:OUT; SFP:1101; x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?us-ascii?Q?TsQymY1E2XodhCWSqT3j7yLwGAdDyY5JcpkrN5fAPFW4aYa2zFzud/k+ow+W?= =?us-ascii?Q?geffLNNpMCuWG6+k4c/T+4/YmSMK+iWsRORKkRRhlRqHGqhowCHf0AOBYMxr?= =?us-ascii?Q?ASe93mzcFEMKsX8tFlMtoVzYzUcbl2/mXWFL/Uu8sxzRQy7lGL43HggTBjW4?= =?us-ascii?Q?kEUBXz85Icnx5bsx9sizbd16JmgT+aPGAVQFXJbtmKalc2MW0sPBxMqRmmWm?= =?us-ascii?Q?FwU6yyY9zxFo6Ly1mVg0JqINsDGolymtqQk0d5heujdi5jNBkDTOqekn8U5f?= =?us-ascii?Q?ZIdINp0zVoyMy+82sbQ5BdpMHnyJqC8D9VyOH6+V7X6BatsEIGhIn5BDyj9l?= =?us-ascii?Q?fvXSmRPpa9jTP5Y7vM0VjEcviC9HgozManbfvqohrD4Dqj0Xegmt5T5iCgB6?= =?us-ascii?Q?CjAcSPy7P0DDjAtfXB5pqSWtxrZGMkmmIqGm/+P1xBS7FfWMYQdaFJ2bfFh7?= =?us-ascii?Q?9diERMHe1on2qSaHXHkmMsZSK4ejCju1nHlPCGncVZ4weBRPH5FXoKKEpol5?= =?us-ascii?Q?WDqba0n6ToItu5iLEcDVX17VDdCJVgpFeujeQM1GSz/nxXP7QUCtSfMERd6M?= =?us-ascii?Q?LnXsopzrqaCCmZoDJg/CRWLzxiSRR7ZRg+/RAujfuFQblLcdFWrZmmDzuC/B?= =?us-ascii?Q?EBsEIUQKpsu6Mx/kDqb8D3pbrGFrJ032o3cf0NFhG8Hqr00j9ySS7H428SsK?= =?us-ascii?Q?h0ggxZWlJ7CRmJyUC5hme9n8h8Z+0hYpZTTZ3RrNgM6fcspTWjYVdXQl3alR?= =?us-ascii?Q?+JaaZ7nwUf9xvcmDatcCeaTnFJoZqfpnSw6xdkCaQYi5HzWYOUly+A6FIAAP?= =?us-ascii?Q?lyScg+n8ahFm56iukjQYMf6KBoow8GPA4IrEROcbE8kuHw1mHS1UF1dUzilp?= =?us-ascii?Q?2wZFQ74VGCQtDg9SMHOixKTTnYLcBKxqdutxMs6hvLCzvtpiquEnaM6ERxPY?= =?us-ascii?Q?N6kCipdN5QCNP+MJeWHcZ+4YVO5uQfxP72GSE5KrzRmoOeQOTqnOsAhoWUFn?= =?us-ascii?Q?0kZcgX56amb03xVa3mxXA9dly3wO3ne59gCbwwYp/kfwvdku4ol4R0+Cf6ny?= =?us-ascii?Q?wTydYZjRsdO3ODEwS6gUOoIiZDxlm7/47F68l8JTAlHb8aKe7F0ijxj90N3A?= =?us-ascii?Q?04ndxSMB70iXFz+G6HRsIz2cznTvKe5MvUSjzUN+fpbkj8Q8my0gNR5qD3I1?= =?us-ascii?Q?DxlLCJ5o0mnN8LshSK554BNiqAvhpOVWysldLGjtfghQ3d59Cf/lKhx2zxar?= =?us-ascii?Q?xEvSTLctN8U2z1jFyOn1fJ+Rc4oZqSTsuvbeDA45tHUqtTxYYslhAG5us4Bg?= =?us-ascii?Q?OZJyXD+nVclF/buNno2m2pr32FtpioCBwcXHXlU46sENOmmRL2lnKFxYCnEy?= =?us-ascii?Q?cBwMOsKh8CD/H/gpEajFXPCX6jMt9ut+FdVCB3VwrOwfsUmZZ8428jYDYi19?= =?us-ascii?Q?1kRmQB6QPp3perOZoN167Z4XyC7H/im5eXLIdJaVVoaomLpwECxWNIifCxU1?= =?us-ascii?Q?fsDngnYnabGcBgxeTTb6xhRuK7xpcT7IZ10fzDGLm+t+V3jNL6dh816di2P5?= =?us-ascii?Q?vYJv/cNOTBIMYEmY/NdMu+p4geaHpx0DzR6CNjE2aSTUD1fqglRotE7GMEXB?= =?us-ascii?Q?fLgmc+xbhTP/BZlT07c8uDw=3D?= Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-OriginatorOrg: leica-geosystems.com.cn X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: AS8PR06MB7432.eurprd06.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 6ffdda6c-7bb3-43cb-9f2f-08dc8c5eede1 X-MS-Exchange-CrossTenant-originalarrivaltime: 14 Jun 2024 10:44:12.5021 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 1b16ab3e-b8f6-4fe3-9f3e-2db7fe549f6a X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: gfu3OQuGb/i8G7fmPe090jZwrePZxAY9InHCaQsk67vQ4Vz8+Egp+LhZScbNChefDzml1xz2Y+OwQHnfs4eismZRoR692jBH2+b5rb5yfV5Pm9bIydmCD6OrQSqxNW/O X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM9PR06MB7347 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on metis.whiteo.stw.pengutronix.de X-Spam-Level: X-Spam-Status: No, score=-2.8 required=4.0 tests=AWL,BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_MSPIKE_H2,SPF_HELO_PASS, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.2 X-Mailman-Approved-At: Fri, 14 Jun 2024 12:56:20 +0200 Subject: Re: [OSS-Tools] [PATCH platsch V4 4/4] Add spinner executable for boot animation and text show X-BeenThere: oss-tools@pengutronix.de X-Mailman-Version: 2.1.29 Precedence: list List-Id: Pengutronix Public Open-Source-Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "OSS-Tools" X-SA-Exim-Connect-IP: 127.0.0.1 X-SA-Exim-Mail-From: oss-tools-bounces@pengutronix.de X-SA-Exim-Scanned: No (on metis.whiteo.stw.pengutronix.de); SAEximRunCond expanded to false Hi everyone, Hi Marco, Please also review this patch, the overall of the idea of the animations is= OK or not? > -----Original Message----- > From: LI Qingwu > Sent: Friday, June 14, 2024 5:23 PM > To: LI Qingwu ; > oss-tools@pengutronix.de; m.felsch@pengutronix.de > Subject: [OSS-Tools] [PATCH platsch V4 4/4] Add spinner executable for bo= ot > animation and text show >=20 > This commit introduces a new executable, spinner, > which supports two types of animations for boot sequences: > 1 static PNG and text support. > 2 rotates square PNG images per frame > 3 shows a sequence of square images from a strip of PNG images. >=20 > Signed-off-by: LI Qingwu > --- > README.rst | 37 ++++++ > meson.build | 24 ++++ > meson_options.txt | 1 + > spinner.c | 299 > ++++++++++++++++++++++++++++++++++++++++++++++ > spinner_conf.c | 67 +++++++++++ > spinner_conf.h | 33 +++++ > 6 files changed, 461 insertions(+) > create mode 100644 meson_options.txt > create mode 100644 spinner.c > create mode 100644 spinner_conf.c > create mode 100644 spinner_conf.h >=20 > diff --git a/README.rst b/README.rst > index f1c0812..a0f7f7e 100644 > --- a/README.rst > +++ b/README.rst > @@ -149,3 +149,40 @@ Compiling Instructions >=20 > meson setup build > meson compile -C build > + > + > +Spinner - Splash Screen with Animation > +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > + > +The `spinner` executable is designed to provide boot animations. It supp= orts > two types of animations: > + > +1. **static PNG and text support**: Show a static png image and text. > +1. **Square PNG Rotation Animation**: Rotates a square PNG image. > +2. **Sequence Move Rectangle Animation**: Displays a sequence of square > images from a strip of PNG images. > + > +spinner Configuration > +--------------------- > + > +The configuration for the `spinner` executable is read from a > +configuration file, with a default path of `/usr/share/platsch/spinner.c= onf`. > +The directory of the configuration file can be set via the `platsch_dire= ctory` > environment variable. > + > + > +spinner Configuration > +--------------------- > + > +Here is a sample of a configuration file (`spinner.conf`): > + > +.. code-block:: ini > + > + symbol=3D"/usr/share/platsch/Spinner.png" > + fps=3D20 > + text=3D"" > + text_x=3D350 > + text_y=3D400 > + text_font=3D"Sans" > + text_size=3D30 > + > +Set text to empty if you don't want to display any text. > +Set the symbol to empty if you don't want to display any animation. > +The background image is indicated by ``--directory`` and ``--basename``. > diff --git a/meson.build b/meson.build > index 4c2ad7b..46413a0 100644 > --- a/meson.build > +++ b/meson.build > @@ -10,3 +10,27 @@ libplatsch =3D static_library('libplatsch', > install: true, > include_directories: include_directories('.') > ) > + > +# Create the spinner executable if SPINNER true if > +get_option('SPINNER') > + spinner_dep =3D [ > + dependency('cairo', required: true), > + dependency('libdrm', required: true) > + ] > + > + spinner_src =3D [ > + 'spinner.c', > + 'spinner_conf.c' > + ] > + > + args =3D ['-DSPINNER'] > + > + executable('spinner', > + spinner_src, > + dependencies: spinner_dep, > + link_with: libplatsch, > + c_args: args, > + install: true, > + include_directories: include_directories('.') > + ) > +endif > diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 i= ndex > 0000000..d1149fe > --- /dev/null > +++ b/meson_options.txt > @@ -0,0 +1 @@ > +option('SPINNER', type: 'boolean', value: false, description: 'Enable > +spinner build') > diff --git a/spinner.c b/spinner.c > new file mode 100644 > index 0000000..ef9ee6b > --- /dev/null > +++ b/spinner.c > @@ -0,0 +1,299 @@ > + > +#include > +#include > +#include > + > +#include "libplatsch.h" > +#include "spinner_conf.h" > + > +typedef struct spinner { > + cairo_format_t fmt; > + cairo_surface_t *background_surface; > + cairo_surface_t *symbol_surface; > + cairo_surface_t *drawing_surface; > + cairo_t *cr_background; > + cairo_t *cr_drawing; > + cairo_t *disp_cr; > + int background_height; > + int background_width; > + int display_height; > + int display_width; > + int symbol_height; > + int symbol_width; > + struct modeset_dev *dev; > + struct spinner *next; > +} spinner_t; > + > +void on_draw_Sequence_animation(cairo_t *cr, spinner_t *data) { > + static int current_frame; > + int num_frames =3D data->symbol_width / data->symbol_height; > + int frame_width =3D data->symbol_height; > + > + cairo_set_source_surface(cr, data->background_surface, 0, 0); > + cairo_paint(cr); > + > + cairo_save(cr); > + > + cairo_translate(cr, data->display_width / 2, data->display_height / > +2); > + > + cairo_set_source_surface(cr, data->symbol_surface, > + -frame_width / 2 - current_frame * frame_width, > -frame_width / 2); > + > + cairo_rectangle(cr, -frame_width / 2, -frame_width / 2, frame_width, > frame_width); > + cairo_clip(cr); > + cairo_paint(cr); > + > + cairo_restore(cr); > + > + current_frame =3D (current_frame + 1) % num_frames; } > + > +void on_draw_rotation_animation(cairo_t *cr, spinner_t *data) { > + static float angle =3D 0.0; > + > + cairo_set_source_surface(cr, data->background_surface, 0, 0); > + cairo_paint(cr); > + cairo_save(cr); > + cairo_translate(cr, data->background_width / 2, data->background_height > / 2); > + cairo_rotate(cr, angle); > + cairo_translate(cr, -data->symbol_width / 2, -data->symbol_height / 2); > + cairo_set_source_surface(cr, data->symbol_surface, 0, 0); > + cairo_paint(cr); > + cairo_restore(cr); > + angle +=3D 0.1; > + if (angle > 2 * M_PI) > + angle =3D 0.0; > +} > + > +static uint32_t convert_to_cairo_format(uint32_t format) { > + switch (format) { > + case DRM_FORMAT_RGB565: > + return CAIRO_FORMAT_RGB16_565; > + case DRM_FORMAT_XRGB8888: > + return CAIRO_FORMAT_ARGB32; > + } > + return CAIRO_FORMAT_INVALID; > +} > + > +static void cairo_draw_text(cairo_t *cr, Config config) { > + if (strlen(config.text) > 0) { > + cairo_select_font_face(cr, config.text_font, > CAIRO_FONT_SLANT_NORMAL, > + CAIRO_FONT_WEIGHT_NORMAL); > + cairo_set_font_size(cr, (double)config.text_size); > + cairo_move_to(cr, config.text_x, config.text_y); > + cairo_set_source_rgb(cr, 0, 0, 0); > + cairo_show_text(cr, config.text); > + } > +} > + > +static int cairo_create_display_surface(struct modeset_dev *dev, > +spinner_t *spinner_node) { > + cairo_surface_t *disp_surface =3D cairo_image_surface_create_for_data( > + dev->map, convert_to_cairo_format(dev->format->format), > dev->width, dev->height, > + dev->stride); > + if (cairo_surface_status(disp_surface)) { > + error("Failed to create cairo surface\n"); > + return EXIT_FAILURE; > + } > + spinner_node->display_width =3D > cairo_image_surface_get_width(disp_surface); > + spinner_node->display_height =3D > cairo_image_surface_get_height(disp_surface); > + spinner_node->fmt =3D cairo_image_surface_get_format(disp_surface); > + spinner_node->disp_cr =3D cairo_create(disp_surface); > + return EXIT_SUCCESS; > +} > + > +// create a surface and paint background image static int > +cairo_create_background_surface(spinner_t *spinner_node, Config config, > const char *dir, > + const char *base) > +{ > + char filename[128]; > + int ret; > + > + ret =3D snprintf(filename, sizeof(filename), "%s/%s.png", dir, base); > + if (ret >=3D sizeof(filename)) { > + error("Failed to fit filename into buffer\n"); > + return EXIT_FAILURE; > + } > + > + spinner_node->background_surface =3D cairo_image_surface_create( > + spinner_node->fmt, spinner_node->display_width, > spinner_node->display_height); > + if (cairo_surface_status(spinner_node->background_surface)) { > + error("Failed to create background surface\n"); > + return EXIT_FAILURE; > + } > + > + cairo_surface_t *bk_img_surface =3D > +cairo_image_surface_create_from_png(filename); > + > + if (cairo_surface_status(bk_img_surface)) { > + error("Failed to create cairo surface from %s\n", filename); > + return EXIT_FAILURE; > + } > + > + int image_width =3D cairo_image_surface_get_width(bk_img_surface); > + int image_height =3D cairo_image_surface_get_height(bk_img_surface); > + double scale_x =3D (double)spinner_node->display_width / image_width; > + double scale_y =3D (double)spinner_node->display_height / image_height; > + > + spinner_node->cr_background =3D > cairo_create(spinner_node->background_surface); > + cairo_scale(spinner_node->cr_background, scale_x, scale_y); > + cairo_set_source_surface(spinner_node->cr_background, bk_img_surface, > +0, 0); > + > + spinner_node->background_width =3D > + > cairo_image_surface_get_width(spinner_node->background_surface); > + spinner_node->background_height =3D > + > cairo_image_surface_get_height(spinner_node->background_surface); > + > + cairo_paint(spinner_node->cr_background); > + cairo_draw_text(spinner_node->cr_background, config); > + return EXIT_SUCCESS; > +} > + > +static int cairo_create_symbol_surface(spinner_t *spinner_node, Config > +config) { > + if (strlen(config.symbol) =3D=3D 0) > + return EXIT_FAILURE; > + > + spinner_node->symbol_surface =3D > cairo_image_surface_create_from_png(config.symbol); > + if (cairo_surface_status(spinner_node->symbol_surface)) { > + error("Failed loading %s\n", config.symbol); > + spinner_node->symbol_surface =3D NULL; > + return EXIT_FAILURE; > + } > + spinner_node->symbol_width =3D > cairo_image_surface_get_width(spinner_node->symbol_surface); > + spinner_node->symbol_height =3D > cairo_image_surface_get_height(spinner_node->symbol_surface); > + return EXIT_SUCCESS; > +} > + > +int main(int argc, char *argv[]) > +{ > + bool pid1 =3D getpid() =3D=3D 1; > + char filename[128]; > + Config config =3D DEFAULT_CONFIG; > + const char *base =3D "splash"; > + const char *dir =3D "/usr/share/platsch"; > + const char *env; > + int ret; > + long elapsed_time; > + > + spinner_t *spinner_list =3D NULL, *spinner_node =3D NULL, *spinner_iter= =3D > NULL; > + struct modeset_dev *iter; > + struct timeval start, end; > + > + env =3D getenv("platsch_directory"); > + if (env) > + dir =3D env; > + > + env =3D getenv("platsch_basename"); > + if (env) > + base =3D env; > + > + ret =3D snprintf(filename, sizeof(filename), "%s/spinner.conf", dir); > + if (ret >=3D sizeof(filename)) { > + error("Failed to fit filename\n"); > + return EXIT_FAILURE; > + } > + > + parseConfig(filename, &config); > + > + struct modeset_dev *modeset_list =3D init(); > + > + if (!modeset_list) { > + error("Failed to initialize modeset\n"); > + return EXIT_FAILURE; > + } > + > + for (iter =3D modeset_list; iter; iter =3D iter->next) { > + spinner_node =3D (spinner_t *)malloc(sizeof(spinner_t)); > + if (!spinner_node) { > + error("Failed to allocate memory for spinner_node\n"); > + return EXIT_FAILURE; > + } > + memset(spinner_node, 0, sizeof(*spinner_node)); > + > + if (cairo_create_display_surface(iter, spinner_node)) > + return EXIT_FAILURE; > + > + if (cairo_create_background_surface(spinner_node, config, dir, base)) > + return EXIT_FAILURE; > + > + cairo_create_symbol_surface(spinner_node, config); > + > + spinner_node->drawing_surface =3D cairo_image_surface_create( > + spinner_node->fmt, spinner_node->display_width, > spinner_node->display_height); > + if (cairo_surface_status(spinner_node->drawing_surface)) { > + error("Failed to create drawing surface\n"); > + return EXIT_FAILURE; > + } > + // create cairo context for drawing surface to avoid frlickering > + spinner_node->cr_drawing =3D > cairo_create(spinner_node->drawing_surface); > + // draw static image with text as first frame > + cairo_set_source_surface(spinner_node->disp_cr, > spinner_node->background_surface, 0, > + 0); > + cairo_paint(spinner_node->disp_cr); > + update_display(iter); > + > + spinner_node->next =3D spinner_list; > + spinner_list =3D spinner_node; > + } > + > + char **initsargv; > + > + ret =3D fork(); > + if (ret < 0) > + error("failed to fork for init: %m\n"); > + else if (ret =3D=3D 0) > + /* > + * Always fork to make sure that got the required > + * resources for drawing the animation in the child. > + */ > + goto drawing; > + > + if (pid1) { > + initsargv =3D calloc(sizeof(argv[0]), argc + 1); > + > + if (!initsargv) { > + error("failed to allocate argv for init\n"); > + return EXIT_FAILURE; > + } > + memcpy(initsargv, argv, argc * sizeof(argv[0])); > + initsargv[0] =3D "/sbin/init"; > + initsargv[argc] =3D NULL; > + > + execv("/sbin/init", initsargv); > + > + error("failed to exec init: %m\n"); > + > + return EXIT_FAILURE; > + } > + return 0; > + > +drawing: > + while (true) { > + gettimeofday(&start, NULL); > + for (spinner_iter =3D spinner_list; spinner_iter; spinner_iter =3D > spinner_iter->next) { > + if (spinner_node->symbol_surface =3D=3D NULL) > + usleep(1000000 / config.fps); > + if (spinner_node->symbol_width / spinner_node->symbol_height > > 2) > + on_draw_Sequence_animation(spinner_iter->cr_drawing, > spinner_iter); > + else > + on_draw_rotation_animation(spinner_iter->cr_drawing, > spinner_iter); > + > + cairo_set_source_surface(spinner_iter->disp_cr, > + spinner_iter->drawing_surface, 0, 0); > + cairo_paint(spinner_iter->disp_cr); > + } > + gettimeofday(&end, NULL); > + elapsed_time =3D > + (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - > +start.tv_usec); > + > + long sleep_time =3D (1000000 / config.fps) - elapsed_time; > + > + if (sleep_time > 0) > + usleep(sleep_time); > + } > + redirect_stdfd(); > +} > diff --git a/spinner_conf.c b/spinner_conf.c new file mode 100644 index > 0000000..491b1c3 > --- /dev/null > +++ b/spinner_conf.c > @@ -0,0 +1,67 @@ > +#include "spinner_conf.h" > +#include > + > +int parseConfig(const char *filename, Config *config) { > + char *value_end; > + char *value_start; > + char key[MAX_LINE_LENGTH]; > + char line[MAX_LINE_LENGTH]; > + char value[MAX_LINE_LENGTH]; > + FILE *file; > + > + file =3D fopen(filename, "r"); > + if (file =3D=3D NULL) { > + fprintf(stderr, "Unable to open file: %s\n", filename); > + return -EFAULT; > + } > + > + while (fgets(line, sizeof(line), file)) { > + if (strlen(line) > MAX_LINE_LENGTH) { > + fprintf(stderr, "conf string too long\n"); > + continue; > + } > + if (line[0] !=3D '#' && sscanf(line, "%[^=3D]=3D%[^\n]", key, value) = =3D=3D 2) { > + value_start =3D strchr(line, '=3D') + 1; > + value_end =3D line + strlen(line) - 1; > + > + while (isspace(*value_start)) > + value_start++; > + while (isspace(*value_end) || *value_end =3D=3D '"') > + value_end--; > + > + if (*value_start =3D=3D '"') > + value_start++; > + if (*value_end =3D=3D '"') > + value_end--; > + > + if (value_end < value_start) { > + memset(value, 0, sizeof(value)); > + continue; > + } else { > + strncpy(value, value_start, value_end - value_start + 1); > + value[value_end - value_start + 1] =3D '\0'; > + value[sizeof(value) - 1] =3D '\0'; > + } > + value[MAX_LINE_LENGTH - 1] =3D '\0'; > + > + if (strcmp(key, "symbol") =3D=3D 0) { > + strncpy(config->symbol, value, MAX_LINE_LENGTH); > + } else if (strcmp(key, "text") =3D=3D 0) { > + strncpy(config->text, value, MAX_LINE_LENGTH); > + } else if (strcmp(key, "fps") =3D=3D 0) { > + config->fps =3D atoi(value); > + } else if (strcmp(key, "text_x") =3D=3D 0) { > + config->text_x =3D atoi(value); > + } else if (strcmp(key, "text_y") =3D=3D 0) { > + config->text_y =3D atoi(value); > + } else if (strcmp(key, "text_font") =3D=3D 0) { > + strncpy(config->text_font, value, MAX_LINE_LENGTH); > + } else if (strcmp(key, "text_size") =3D=3D 0) { > + config->text_size =3D atoi(value); > + } > + } > + } > + fclose(file); > + return 0; > +} > diff --git a/spinner_conf.h b/spinner_conf.h new file mode 100644 index > 0000000..4f8501b > --- /dev/null > +++ b/spinner_conf.h > @@ -0,0 +1,33 @@ > +#include > +#include > +#include > +#include > + > +#ifndef __SPINNER_CONF_H__ > +#define __SPINNER_CONF_H__ > + > + > +#define MAX_LINE_LENGTH 128 > + > +typedef struct { > + char symbol[MAX_LINE_LENGTH]; > + int fps; > + int text_x; > + int text_y; > + char text_font[MAX_LINE_LENGTH]; > + int text_size; > + char text[MAX_LINE_LENGTH]; > +} Config; > + > +int parseConfig(const char *filename, Config *config); > + > +#define DEFAULT_CONFIG { \ > + .symbol =3D "", \ > + .fps =3D 20, \ > + .text_x =3D 0, \ > + .text_y =3D 0, \ > + .text_font =3D "Sans", \ > + .text_size =3D 30, \ > + .text =3D "" \ > +} > +#endif > -- > 2.34.1