├── LICENSE ├── README.md ├── app ├── .gitignore ├── README.md ├── backlight.cpp ├── backlight.h ├── backlight.rules ├── easylist.txt ├── main.cpp ├── screenshots │ └── adblock.jpg └── shell.pro ├── lib └── systemd │ └── system │ └── cutiepi-shell.service ├── opt └── cutiepi-shell │ ├── AutoScroller.qml │ ├── BlurPanel.qml │ ├── FactoryMode.qml │ ├── Font Awesome 5 Free-Solid-900.otf │ ├── NetworkManager.qml │ ├── PowerOffMenu.qml │ ├── SettingView.qml │ ├── SuggestionContainer.qml │ ├── TimeZoneDialog.qml │ ├── WallpaperDialog.qml │ ├── WebView.qml │ ├── assets │ ├── data_sounds_effects_wav_Dock.wav │ ├── data_sounds_effects_wav_Undock.wav │ └── mic-test.sh │ ├── cutiepi-shell │ ├── icons │ ├── audio-volume-high-symbolic.svg │ ├── audio-volume-low-symbolic.svg │ ├── audio-volume-medium-symbolic.svg │ ├── audio-volume-muted-symbolic.svg │ ├── battery-caution-charging-symbolic.svg │ ├── battery-caution-symbolic.svg │ ├── battery-empty-charging-symbolic.svg │ ├── battery-empty-symbolic.svg │ ├── battery-full-charged-symbolic.svg │ ├── battery-full-charging-symbolic.svg │ ├── battery-full-symbolic.svg │ ├── battery-good-charging-symbolic.svg │ ├── battery-good-symbolic.svg │ ├── battery-low-charging-symbolic.svg │ ├── battery-low-symbolic.svg │ ├── battery-missing-symbolic.svg │ ├── favicon.png │ ├── logo.png │ ├── network-wireless-acquiring-symbolic.svg │ ├── network-wireless-connected-symbolic.svg │ ├── network-wireless-encrypted-symbolic.svg │ ├── network-wireless-signal-excellent-symbolic.svg │ ├── network-wireless-signal-good-symbolic.svg │ ├── network-wireless-signal-none-symbolic.svg │ ├── network-wireless-signal-ok-symbolic.svg │ ├── network-wireless-signal-weak-symbolic.svg │ └── terminal-512.png │ ├── kms.conf │ ├── layouts │ └── en_US │ │ ├── CtrlKey.qml │ │ ├── EscKey.qml │ │ ├── TabKey.qml │ │ ├── WSpaceKey.qml │ │ ├── dialpad.qml │ │ ├── digits.qml │ │ ├── handwriting.qml │ │ ├── main.qml │ │ ├── numbers.qml │ │ └── symbols.qml │ ├── shell.qml │ ├── tabControl.js │ └── timezone.txt ├── screenshots ├── cutiepi-shell-heroshot.png ├── settings.png ├── sidetab.png ├── terminal.png └── wifi.png └── systray ├── images ├── battery-caution-symbolic.svg ├── battery-empty-symbolic.svg ├── battery-full-charged-symbolic.svg ├── battery-full-symbolic.svg ├── battery-good-symbolic.svg └── battery-low-symbolic.svg ├── main.cpp ├── main.qml ├── qml.qrc └── systray.pro /README.md: -------------------------------------------------------------------------------- 1 | ## CutiePi shell 2 | 3 | A mobile UI for Raspberry Pi OS. 4 | 5 | ![](screenshots/cutiepi-shell-heroshot.png) 6 | 7 | CutiePi shell is a mobile UI built for [CutiePi tablet](https://cutiepi.io) project. Check out the [demo video](https://www.youtube.com/watch?v=ivkR3tvci1Q) 8 | 9 | ## Features 10 | 11 | * Lockscreen with sleep/wake button events handling 12 | * Web browser, terminal emulator, and on-screen keyboard 13 | * Built-in adblocker, using ABP-compatible filters 14 | * Side-tab for multitasking 15 | * WiFi configurator 16 | * Battery charging status and level reading (through UART) 17 | * Orientation sensor support (accelerometer and gyroscope) 18 | 19 | Cutiepi shell is written entirely in Qt using EGLFS QPA, and can be ported to [Wayland](https://github.com/cutiepi-io/cutiepi-shell/tree/wayland) or other platform and distributions with EGL support. 20 | 21 | ### Screenshots 22 | 23 | | ![](screenshots/sidetab.png) | ![](screenshots/wifi.png) | 24 | | ------------- | ------------- | 25 | | ![](screenshots/terminal.png) | ![](screenshots/settings.png) | 26 | 27 | ## Dependencies 28 | 29 | - [Qt](http://download.qt.io/official_releases/qt/5.12/) `5.12` or later version 30 | - [Yat](https://github.com/jorgen/yat) for terminal emulator 31 | - [nemo-qml-plugin-dbus](https://github.com/sailfishos/nemo-qml-plugin-dbus.git) for DBus signals 32 | - [libconnman-qt](https://git.sailfishos.org/mer-core/libconnman-qt) and [ConnMan](https://01.org/connman) for WiFi configuration 33 | - [CutiePi firmware](https://github.com/cutiepi-io/cutiepi-firmware) and [middleware plugins](https://github.com/cutiepi-io/cutiepi-middleware) for battery and sleep/wake button related functions 34 | - [ad-block](https://github.com/brave/ad-block) and [easylist](https://easylist.to/easylist/easylist.txt) for adblocker (optional) 35 | 36 | ## License 37 | 38 | * CutiePi shell sources are licensed under the terms of the GNU General Public License version 3 or, at your option, any later version. 39 | * And all documentations are licensed under a Creative Commons BY-SA 4.0 international license. 40 | * This project uses [Font Awesome](https://fontawesome.com/license/free) fonts, which is licensed under `SIL OFL 1.1 License`. 41 | 42 | * Icons are from the `gnome-user-docs` package with following copyright information `Copyright: Copyright (C) 2010 - 2014 Shaun McCance`, and licensed under `CC-BY-3.0`. 43 | * Wallpapers are designed by [Even Wu](https://twitter.com/evenwu1978) licensed under CC-BY 44 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | third_party 2 | .DS_Store -------------------------------------------------------------------------------- /app/README.md: -------------------------------------------------------------------------------- 1 | # A Minimal QtWebEngine Web Browser with Adblocker 2 | 3 | ![](screenshots/adblock.jpg) 4 | 5 | ## How Does It Work 6 | 7 | This is a minimal `network filter` implementation using `QWebEngineUrlRequestInterceptor` and `QtWebEngine`, with filters from [easylist](https://easylist.to/easylist/easylist.txt). The parser is currently using `ad-block` from Brave, but alternatives would be needed in the future. 8 | 9 | Reference: 10 | - https://adblockplus.org/blog/investigating-filter-matching-algorithms 11 | - https://brave.com/improved-ad-blocker-performance/ 12 | 13 | ### Dependencies 14 | 15 | - Qt 5.10+ with `QtWebEngine` module 16 | - ABP-style parser from Brave's [ad-block](https://github.com/brave/ad-block) C++ library 17 | 18 | Checkout the following 3 repositories: 19 | 20 | git clone https://github.com/brave/ad-block.git third_party/ad-block 21 | git clone https://github.com/brave/hashset-cpp.git third_party/hashset-cpp 22 | git clone https://github.com/brave/bloom-filter-cpp.git third_party/bloom-filter-cpp 23 | 24 | And copy all `*.h` and `*.cc` to `third_party/ad-block`: 25 | 26 | cp third_party/hashset-cpp/{*.cc,*.h} third_party/ad-block/ 27 | cp third_party/bloom-filter-cpp/{*.cpp,*.h} third_party/ad-block/ 28 | 29 | ### Build Instructions 30 | 31 | qmake DEFINES+=USE_ADBLOCK 32 | make 33 | 34 | ## Copyright & License 35 | 36 | Copyright © 2021 Penk Chen 37 | 38 | - This project is licensed under GPL 3+, see the file LICENSE for details. 39 | 40 | - The Brave dependencies are licensed under MPL, which is unmodified and not included or redistribued in this project. It should be handled according to the [Initial Distribution of MPL-licensed Files As Part Of an (L)GPL-licensed Project](https://www.mozilla.org/en-US/MPL/2.0/combining-mpl-and-gpl/) guidelines. 41 | -------------------------------------------------------------------------------- /app/backlight.cpp: -------------------------------------------------------------------------------- 1 | #include "backlight.h" 2 | 3 | Backlight::Backlight(): QObject() 4 | { 5 | /* find valid backlight path; search here: */ 6 | m_path = "/sys/class/backlight/"; 7 | 8 | QDir dir(m_path); 9 | if (!dir.isEmpty()) { 10 | QFileInfoList list = dir.entryInfoList(); 11 | m_path = list.at(2).absoluteFilePath(); 12 | m_backlightOK = true; 13 | } else { 14 | m_backlightOK = false; 15 | } 16 | 17 | m_maxBrightness = getMaxBrightness(); 18 | 19 | /* set lockBrightness to about half maxBrightness, 20 | * unlockBrightness to full maxBrightness 21 | * and blankBrightness to 0 22 | * until they are set to their final values 23 | */ 24 | m_lockBrightness = m_maxBrightness >> 1; 25 | m_unlockBrightness = m_maxBrightness; 26 | m_brightness = getBrightness(); 27 | m_blankBrightness = 0; 28 | m_blankEnable = true; 29 | 30 | setBLEnable(1); 31 | } 32 | 33 | 34 | void Backlight::setLockBrightness(int brightness) 35 | { 36 | /* restrict brightness to 0 <-> maxBrightness */ 37 | if (brightness < 0 || brightness > m_maxBrightness) { 38 | if (brightness < 0) 39 | brightness = 0; 40 | else 41 | brightness = m_maxBrightness; 42 | } 43 | 44 | m_lockBrightness = brightness; 45 | 46 | return; 47 | } 48 | 49 | 50 | void Backlight::setUnlockBrightness(int brightness) 51 | { 52 | /* restrict brightness to 0 <-> maxBrightness */ 53 | if (brightness < 0 || brightness > m_maxBrightness) { 54 | if (brightness < 0) 55 | brightness = 0; 56 | else 57 | brightness = m_maxBrightness; 58 | } 59 | 60 | m_unlockBrightness = brightness; 61 | 62 | return; 63 | } 64 | 65 | 66 | void Backlight::setBlankBrightness(int brightness) 67 | { 68 | /* restrict brightness to 0 <-> maxBrightness */ 69 | if (brightness < 0 || brightness > m_maxBrightness) { 70 | if (brightness < 0) 71 | brightness = 0; 72 | else 73 | brightness = m_maxBrightness; 74 | } 75 | 76 | m_blankBrightness = brightness; 77 | 78 | return; 79 | } 80 | 81 | 82 | void Backlight::setBlankPowerOff(bool enable) 83 | { 84 | m_blankEnable = enable; 85 | return; 86 | } 87 | 88 | 89 | int Backlight::getMaxBrightness() 90 | { 91 | int maxBrightness; 92 | 93 | if (m_backlightOK == false) 94 | return 0; 95 | 96 | QFile blFile(m_path + "/max_brightness"); 97 | 98 | if (!blFile.open(QIODevice::ReadOnly | QIODevice::Text)) 99 | return 0; 100 | char buffer[6]; 101 | qint64 linelength = blFile.readLine(buffer, sizeof(buffer)); 102 | if (linelength < 0) 103 | return 0; 104 | QString br_max(buffer); 105 | maxBrightness = br_max.toInt(); 106 | 107 | if (maxBrightness != m_maxBrightness) { 108 | m_maxBrightness = maxBrightness; 109 | emit maxBrightnessChanged(); 110 | } 111 | 112 | return m_maxBrightness; 113 | } 114 | 115 | 116 | int Backlight::getBrightness() 117 | { 118 | int brightness; 119 | 120 | if (m_backlightOK == false) 121 | return 0; 122 | 123 | QFile blFile(m_path + "/brightness"); 124 | 125 | if (!blFile.open(QIODevice::ReadOnly | QIODevice::Text)) 126 | return 0; 127 | char buffer[6]; 128 | qint64 linelength = blFile.readLine(buffer, sizeof(buffer)); 129 | if (linelength < 0) 130 | return 0; 131 | QString br_max(buffer); 132 | brightness = br_max.toInt(); 133 | 134 | if (brightness != m_brightness) { 135 | m_brightness = brightness; 136 | emit brightnessChanged(); 137 | } 138 | 139 | return m_brightness; 140 | } 141 | 142 | 143 | void Backlight::setBrightness(int brightness) 144 | { 145 | if (m_backlightOK == false) 146 | return; 147 | 148 | // restrict brightness to 0 <-> maxBrightness 149 | if (brightness < 0 || brightness > m_maxBrightness) { 150 | if (brightness < 0) 151 | brightness = 0; 152 | else 153 | brightness = m_maxBrightness; 154 | } 155 | 156 | qDebug() << "setting brightness to " << brightness; 157 | 158 | QFile blFile(m_path + "/brightness"); 159 | 160 | if (!blFile.open(QIODevice::WriteOnly | QIODevice::Text)) 161 | return; 162 | 163 | blFile.write(QString::number(brightness).toLocal8Bit()); 164 | blFile.close(); 165 | 166 | /* read back the real current value */ 167 | getBrightness(); 168 | return; 169 | } 170 | 171 | 172 | void Backlight::lock() 173 | { 174 | setBrightness(m_lockBrightness); 175 | setBLEnable(1); 176 | return; 177 | } 178 | 179 | 180 | void Backlight::unlock() 181 | { 182 | setBrightness(m_unlockBrightness); 183 | setBLEnable(1); 184 | return; 185 | } 186 | 187 | 188 | void Backlight::blank() 189 | { 190 | setBrightness(0); 191 | if (m_blankEnable) 192 | setBLEnable(0); 193 | else 194 | setBLEnable(1); 195 | return; 196 | } 197 | 198 | 199 | void Backlight::unblank() 200 | { 201 | setBLEnable(1); 202 | usleep(100000); 203 | setBrightness(m_lockBrightness); 204 | return; 205 | } 206 | 207 | 208 | void Backlight::setBLEnable(int value) 209 | { 210 | if (m_backlightOK == false) 211 | return; 212 | 213 | if (value > 1 || value < 0) { 214 | return; 215 | } 216 | 217 | /* invert the value because bl_power is currently inverted */ 218 | if (value == 0) 219 | value = 1; 220 | else 221 | value = 0; 222 | 223 | qDebug() << "set bl_power to " << value; 224 | 225 | QFile bl_powerFile(m_path + "/bl_power"); 226 | 227 | if (!bl_powerFile.open(QIODevice::WriteOnly | QIODevice::Text)) 228 | return; 229 | 230 | bl_powerFile.write(QString::number(value).toLocal8Bit()); 231 | bl_powerFile.close(); 232 | return; 233 | } 234 | -------------------------------------------------------------------------------- /app/backlight.h: -------------------------------------------------------------------------------- 1 | #ifndef BACKLIGHT_H 2 | #define BACKLIGHT_H 3 | 4 | // The Backlight class is constructed the following way: 5 | // There is no statemachine inside Backlight, we only get notified 6 | // about state transistions via signals and act accordingly. 7 | // After creating the Backlight class it does not change anything 8 | // until you call one of the four transition slots. 9 | // 10 | // blank() 11 | // +------------------------------------------------------+ 12 | // | | 13 | // | | 14 | // +-------+--------------------------+ v 15 | // | | unblank() +----------------------------------------------------+ 16 | // | LOCKED +<---------------------+ | 17 | // | backlight = ON | | BLANKED | 18 | // | brightness = m_lockBrightness | | backlight = OFF (if setBlankPowerOff is enabled) | 19 | // | | | brightness = m_blankBrightness | 20 | // +-+--------------+-----------------+ | | 21 | // | ^ +----------------------------------------------------+ 22 | // | | 23 | // | | lock() 24 | // | unlock() | 25 | // | | 26 | // | +-------+---------------------------+ 27 | // +----->+ | 28 | // | UNLOCKED | 29 | // | backlight = ON | 30 | // | brightness = m_unlockBrightness | 31 | // | | 32 | // +-----------------------------------+ 33 | 34 | #define QT_NO_DEBUG_OUTPUT 1 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | class Backlight : public QObject 43 | { 44 | Q_OBJECT 45 | Q_PROPERTY( int brightness READ getBrightness WRITE setBrightness NOTIFY brightnessChanged FINAL ) 46 | 47 | // We don't want to be able to change the maxBrightness from QML, hence the read only maxBrightness 48 | // Further, notice that maxBrightness is not an instance variable. 49 | Q_PROPERTY( int maxBrightness READ getMaxBrightness NOTIFY maxBrightnessChanged FINAL ) 50 | 51 | public: 52 | explicit Backlight(); 53 | 54 | int getBrightness(); 55 | void setBrightness(int brightness); 56 | int getMaxBrightness(); 57 | 58 | void setLockBrightness(int brightness); 59 | void setUnlockBrightness(int brightness); 60 | void setBlankBrightness(int brightness); 61 | void setBlankPowerOff(bool enable); 62 | 63 | public slots: 64 | void lock(); 65 | void unlock(); 66 | void blank(); 67 | void unblank(); 68 | 69 | signals: 70 | void brightnessChanged(); 71 | void maxBrightnessChanged(); 72 | 73 | private: 74 | int m_maxBrightness; 75 | int m_brightness; 76 | int m_blankBrightness; 77 | int m_lockBrightness; 78 | int m_unlockBrightness; 79 | bool m_blankEnable; 80 | QString m_path; 81 | bool m_backlightOK; 82 | 83 | void setBLEnable(int value); 84 | }; 85 | 86 | 87 | #endif // BACKLIGHT_H 88 | 89 | -------------------------------------------------------------------------------- /app/backlight.rules: -------------------------------------------------------------------------------- 1 | ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="rpi_backlight", RUN+="/bin/chgrp video /sys/class/backlight/%k/brightness" 2 | ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="rpi_backlight", RUN+="/bin/chmod g+w /sys/class/backlight/%k/brightness" 3 | ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="rpi_backlight", RUN+="/bin/chgrp video /sys/class/backlight/%k/bl_power" 4 | ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="rpi_backlight", RUN+="/bin/chmod g+w /sys/class/backlight/%k/bl_power" 5 | -------------------------------------------------------------------------------- /app/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2021 Penk Chen 3 | 4 | This file is part of CutiePi shell of the CutiePi project. 5 | 6 | CutiePi shell is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | CutiePi shell is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with CutiePi shell. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "backlight.h" 31 | 32 | #ifdef USE_ADBLOCK 33 | #include "third_party/ad-block/ad_block_client.h" 34 | 35 | class RequestInterceptor : public QWebEngineUrlRequestInterceptor 36 | { 37 | Q_OBJECT 38 | public: 39 | RequestInterceptor(QObject *parent = nullptr) : QWebEngineUrlRequestInterceptor(parent) 40 | { 41 | QThread *thread = QThread::create([this]{ 42 | QFile file("/opt/cutiepi-shell/easylist.txt"); 43 | QString easyListTxt; 44 | 45 | if(!file.exists()) { 46 | qDebug() << "No easylist.txt file found."; 47 | } else { 48 | if (file.open(QIODevice::ReadOnly | QIODevice::Text)){ 49 | easyListTxt = file.readAll(); 50 | } 51 | file.close(); 52 | client.parse(easyListTxt.toStdString().c_str()); 53 | } 54 | }); 55 | thread->start(); 56 | } 57 | 58 | void interceptRequest(QWebEngineUrlRequestInfo &info) 59 | { 60 | if (client.matches(info.requestUrl().toString().toStdString().c_str(), 61 | FONoFilterOption, info.requestUrl().host().toStdString().c_str())) { 62 | //qDebug() << "Blocked: " << info.requestUrl(); 63 | info.block(true); 64 | } 65 | } 66 | 67 | private: 68 | AdBlockClient client; 69 | }; 70 | #endif 71 | 72 | int main(int argc, char *argv[]) 73 | { 74 | qputenv("QT_QPA_PLATFORM", "xcb"); 75 | qputenv("DISPLAY", ":0.0"); 76 | qputenv("QT_IM_MODULE", "qtvirtualkeyboard"); 77 | qputenv("QT_XCB_GL_INTEGRATION", "xcb_egl"); 78 | qputenv("QML_XHR_ALLOW_FILE_READ", "1"); 79 | 80 | qputenv("QTWEBENGINE_DIALOG_SET", "QtQuickControls2"); 81 | qputenv("XDG_RUNTIME_DIR", "/run/user/1000"); 82 | qputenv("DBUS_SESSION_BUS_ADDRESS", "unix:path=/run/user/1000/bus"); 83 | 84 | QtWebEngine::initialize(); 85 | QApplication app(argc, argv); 86 | //QGuiApplication::setOverrideCursor(QCursor(Qt::BlankCursor)); 87 | app.setOrganizationName("CutiePi"); 88 | app.setOrganizationDomain("cutiepi.io"); 89 | app.setApplicationName("Shell"); 90 | 91 | QQmlApplicationEngine engine; 92 | 93 | Backlight backlight; 94 | engine.rootContext()->setContextProperty("backlight", &backlight); 95 | 96 | #ifdef USE_ADBLOCK 97 | RequestInterceptor interceptor; 98 | QQuickWebEngineProfile adblockProfile; 99 | adblockProfile.setUrlRequestInterceptor(&interceptor); 100 | //adblockProfile.setHttpUserAgent("Mozilla/5.0 (X11; CrOS aarch64 13816.82.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.218 Safari/537.36"); 101 | adblockProfile.setStorageName("Profile"); 102 | adblockProfile.setOffTheRecord(false); 103 | engine.rootContext()->setContextProperty("adblockProfile", &adblockProfile); 104 | #endif 105 | 106 | engine.load("file:///opt/cutiepi-shell/shell.qml"); 107 | return app.exec(); 108 | } 109 | 110 | #include "main.moc" -------------------------------------------------------------------------------- /app/screenshots/adblock.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutiepi-io/cutiepi-shell/caadfe099e6bad05d97e33a06789020e9326a2bd/app/screenshots/adblock.jpg -------------------------------------------------------------------------------- /app/shell.pro: -------------------------------------------------------------------------------- 1 | TARGET = shell 2 | TEMPLATE = app 3 | QT += qml quick webengine widgets 4 | 5 | SOURCES += main.cpp \ 6 | backlight.cpp 7 | 8 | HEADERS += backlight.h 9 | 10 | contains(DEFINES, USE_ADBLOCK) { 11 | SOURCES += third_party/ad-block/ad_block_client.cc \ 12 | third_party/ad-block/no_fingerprint_domain.cc \ 13 | third_party/ad-block/filter.cc \ 14 | third_party/ad-block/protocol.cc \ 15 | third_party/ad-block/context_domain.cc \ 16 | third_party/ad-block/cosmetic_filter.cc \ 17 | third_party/bloom-filter-cpp/BloomFilter.cpp \ 18 | third_party/hashset-cpp/hash_set.cc \ 19 | third_party/hashset-cpp/hashFn.cc 20 | 21 | HEADERS += third_party/ad-block/ad_block_client.h 22 | } 23 | -------------------------------------------------------------------------------- /lib/systemd/system/cutiepi-shell.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=CutiePi Shell 3 | After=systemd-user-sessions.service 4 | 5 | [Service] 6 | User=pi 7 | WorkingDirectory=/home/pi 8 | ExecStart=/opt/cutiepi-shell/cutiepi-shell 9 | Restart=always 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/AutoScroller.qml: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the Qt Virtual Keyboard module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:GPL$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see https://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at https://www.qt.io/contact-us. 16 | ** 17 | ** GNU General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU 19 | ** General Public License version 3 or (at your option) any later version 20 | ** approved by the KDE Free Qt Foundation. The licenses are as published by 21 | ** the Free Software Foundation and appearing in the file LICENSE.GPL3 22 | ** included in the packaging of this file. Please review the following 23 | ** information to ensure the GNU General Public License requirements will 24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 25 | ** 26 | ** $QT_END_LICENSE$ 27 | ** 28 | ****************************************************************************/ 29 | 30 | import QtQuick 2.0 31 | import QtQuick.VirtualKeyboard 2.1 32 | 33 | Item { 34 | 35 | property var innerFlickable 36 | property var outerFlickable 37 | property var inputItem: InputContext.priv.inputItem 38 | 39 | onInputItemChanged: { 40 | innerFlickable = null 41 | outerFlickable = null 42 | if (inputItem !== null) { 43 | var parent_ = inputItem.parent 44 | while (parent_) { 45 | if (parent_.maximumFlickVelocity) { 46 | if (innerFlickable) { 47 | outerFlickable = parent_ 48 | break 49 | } else { 50 | innerFlickable = parent_ 51 | } 52 | } 53 | parent_ = parent_.parent 54 | } 55 | delayedLoading.restart() 56 | } 57 | } 58 | 59 | function ensureVisible(flickable) { 60 | if (Qt.inputMethod.visible && inputItem && flickable && flickable.visible && flickable.interactive) { 61 | 62 | var verticallyFlickable = (flickable.flickableDirection === Flickable.HorizontalAndVerticalFlick || flickable.flickableDirection === Flickable.VerticalFlick 63 | || (flickable.flickableDirection === Flickable.AutoFlickDirection && flickable.contentHeight > flickable.height)) 64 | var horizontallyFlickable = (flickable.flickableDirection === Flickable.HorizontalAndVerticalFlick || flickable.flickableDirection === Flickable.HorizontalFlick 65 | || (flickable.flickableDirection === Flickable.AutoFlickDirection && flickable.contentWidth > flickable.width)) 66 | 67 | if ((!verticallyFlickable && !horizontallyFlickable) || !inputItem.hasOwnProperty("cursorRectangle")) 68 | return 69 | 70 | var cursorRectangle = flickable.contentItem.mapFromItem(inputItem, inputItem.cursorRectangle.x, inputItem.cursorRectangle.y) 71 | 72 | var oldContentY = flickable.contentY 73 | if (verticallyFlickable) { 74 | var scrollMarginVertical = (flickable && flickable.scrollMarginVertical) ? flickable.scrollMarginVertical : 10 75 | if (flickable.contentY >= cursorRectangle.y - scrollMarginVertical) 76 | flickable.contentY = Math.max(0, cursorRectangle.y - scrollMarginVertical) 77 | else if (flickable.contentY + flickable.height <= cursorRectangle.y + inputItem.cursorRectangle.height + scrollMarginVertical) 78 | flickable.contentY = Math.min(flickable.contentHeight - flickable.height, cursorRectangle.y + inputItem.cursorRectangle.height - flickable.height + scrollMarginVertical) 79 | } 80 | if (horizontallyFlickable) { 81 | var scrollMarginHorizontal = (flickable && flickable.scrollMarginHorizontal) ? flickable.scrollMarginHorizontal : 10 82 | if (flickable.contentX >= cursorRectangle.x - scrollMarginHorizontal) 83 | flickable.contentX = Math.max(0, cursorRectangle.x - scrollMarginHorizontal) 84 | else if (flickable.contentX + flickable.width <= cursorRectangle.x + inputItem.cursorRectangle.width + scrollMarginHorizontal) 85 | flickable.contentX = Math.min(flickable.contentWidth - flickable.width, cursorRectangle.x + inputItem.cursorRectangle.width - flickable.width + scrollMarginHorizontal) 86 | } 87 | } 88 | } 89 | Timer { 90 | id: delayedLoading 91 | interval: 10 92 | onTriggered: { 93 | ensureVisible(innerFlickable) 94 | ensureVisible(outerFlickable) 95 | } 96 | } 97 | Connections { 98 | ignoreUnknownSignals: true 99 | target: Qt.inputMethod 100 | onAnimatingChanged: if (inputItem && !Qt.inputMethod.animating) delayedLoading.restart() 101 | onKeyboardRectangleChanged: if (inputItem) delayedLoading.restart() 102 | onCursorRectangleChanged: if (inputItem && inputItem.activeFocus) delayedLoading.restart() 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/BlurPanel.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtGraphicalEffects 1.15 3 | 4 | Rectangle { 5 | property Item target 6 | radius: 22 7 | color: '#989897' 8 | clip: true 9 | 10 | ShaderEffectSource { 11 | id: effectSource 12 | sourceItem: target 13 | anchors.fill: parent 14 | sourceRect: Qt.rect(root.width - width, targetY, width, height) 15 | clip: true 16 | } 17 | 18 | FastBlur { 19 | id: blur 20 | anchors.fill: effectSource 21 | source: effectSource 22 | radius: 22 23 | } 24 | 25 | ColorOverlay { 26 | anchors.fill: blur 27 | source: blur 28 | color: '#8A323232' // alpha + rgb 29 | } 30 | } -------------------------------------------------------------------------------- /opt/cutiepi-shell/FactoryMode.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtMultimedia 5.15 3 | import QtQuick.Controls 2.15 4 | 5 | Rectangle { 6 | anchors.fill: parent 7 | color: 'lightgray' 8 | 9 | Row { 10 | anchors.fill: parent 11 | anchors.margins: 100 12 | spacing: 50 13 | 14 | Column { 15 | width: parent.width/2 16 | spacing: 10 17 | Text { text: "Charging status: " + ( view.batteryCharging ? "true" : "false" ); font.pointSize: 14 } 18 | Text { text: "Measured voltage: " + (mcuInfo.battery/1000).toFixed(3); font.pointSize: 14 } 19 | Text { text: "Orientation: " + view.orientation; font.pointSize: 14 } 20 | 21 | MediaPlayer { 22 | id: mediaplayer 23 | source: 'gst-pipeline: libcamerasrc ! video/x-raw,width=1920,height=1080,framerate=30/1 ! videoconvert ! qtvideosink' 24 | autoPlay: true 25 | } 26 | 27 | VideoOutput { 28 | width: 400; height: 300 29 | source: mediaplayer 30 | } 31 | 32 | Row { 33 | spacing: 20; 34 | Text { text: "Microphone/Speaker: "; font.pointSize: 14 } 35 | Button { 36 | text: "Test"; onClicked: process.start("/opt/cutiepi-shell/assets/mic-test.sh", []); 37 | } 38 | } 39 | } 40 | } 41 | 42 | Rectangle { 43 | id: rebootButton 44 | width: 280 45 | height: 50 46 | color: 'darkgray' 47 | anchors { 48 | right: finishTest.left 49 | rightMargin: 20 50 | bottom: parent.bottom 51 | bottomMargin: 100 52 | } 53 | radius: 6 54 | Text { 55 | anchors.centerIn: parent; 56 | text: "Reboot"; 57 | font.pointSize: xcbFontSizeAdjustment + 8; color: 'white' 58 | } 59 | MouseArea { 60 | anchors.fill: parent 61 | onClicked: { 62 | process.start("sudo", [ "reboot" ]); 63 | } 64 | } 65 | } 66 | 67 | Rectangle { 68 | id: finishTest 69 | width: 280 70 | height: 50 71 | color: finishTestMouseArea.enabled ? '#4875E2' : 'darkgray' 72 | anchors { 73 | right: parent.right 74 | bottom: parent.bottom 75 | margins: 100 76 | } 77 | radius: 6 78 | Text { 79 | anchors.centerIn: parent; 80 | text: finishTestMouseArea.enabled ? "Done" : "Test Finished" ; 81 | font.pointSize: xcbFontSizeAdjustment + 8; color: 'white' 82 | } 83 | MouseArea { 84 | id: finishTestMouseArea 85 | anchors.fill: parent 86 | onClicked: { 87 | settings.setValue("untested", "false") 88 | enabled = false 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/Font Awesome 5 Free-Solid-900.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutiepi-io/cutiepi-shell/caadfe099e6bad05d97e33a06789020e9326a2bd/opt/cutiepi-shell/Font Awesome 5 Free-Solid-900.otf -------------------------------------------------------------------------------- /opt/cutiepi-shell/PowerOffMenu.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | Item { 4 | id: switchOff 5 | visible: ( root.state == "switchoff" ) 6 | anchors.fill: parent 7 | z: 7 8 | Rectangle { 9 | id: switchoffContainer 10 | anchors.fill: parent 11 | color: "#3B4252" 12 | 13 | Rectangle{ 14 | id: switchoffSlider 15 | width: 480 16 | height: 110 17 | radius: 55 18 | anchors.top: parent.top 19 | anchors.topMargin: 100 20 | anchors.horizontalCenter: parent.horizontalCenter 21 | color: "#81A1C1" 22 | Text { 23 | anchors.centerIn: parent 24 | color: "white" 25 | leftPadding: 55 26 | text: "Slide to power off" 27 | font.pointSize: xcbFontSizeAdjustment + 12; 28 | } 29 | 30 | Rectangle { 31 | id: switchoffThumb 32 | height: 100 33 | width: 100 34 | radius: 50 35 | anchors.verticalCenter: parent.verticalCenter 36 | x: 5 37 | color: "#ECEFF4" 38 | 39 | MouseArea { 40 | id: switchoffMouseArea 41 | anchors.fill: parent 42 | drag.target: switchoffThumb 43 | drag.axis: Drag.XAxis 44 | drag.minimumX: 5 45 | drag.maximumX: switchoffSlider.width - switchoffThumb.width - 5 46 | 47 | onReleased: { 48 | if(switchoffThumb.x < 290) 49 | resetSwitchoffThumb.start(); 50 | } 51 | } 52 | 53 | Text { anchors.centerIn: parent; 54 | text: "\uf011"; font.family: fontAwesome.name 55 | font.pointSize: xcbFontSizeAdjustment + 12 56 | } 57 | 58 | NumberAnimation { 59 | id: resetSwitchoffThumb 60 | target: switchoffThumb 61 | properties: "x" 62 | to: 5 63 | easing.type: Easing.InOutQuad 64 | duration: 200 65 | } 66 | 67 | onXChanged: { 68 | if(switchoffThumb.x >= (switchoffSlider.width - switchoffThumb.width - 10)){ 69 | switchoffThumb.x = 5; 70 | switchoffScreen = false; 71 | process.start("sudo", ["poweroff"]); 72 | } 73 | } 74 | } 75 | } 76 | 77 | Rectangle { 78 | id: cancelSwitchOff 79 | width: 100 80 | height: 100 81 | radius: 50 82 | anchors.horizontalCenter: parent.horizontalCenter 83 | anchors.bottom: parent.bottom 84 | anchors.bottomMargin: 150 85 | color: "#ECEFF4" 86 | Text { 87 | anchors.centerIn: parent 88 | color: "black" 89 | text: "\uf00d" 90 | font.family: fontAwesome.name 91 | font.pointSize: xcbFontSizeAdjustment + 12 92 | Text { text: "Cancel"; anchors.top: parent.bottom; anchors.topMargin: 40; 93 | font.pointSize: xcbFontSizeAdjustment + 12; 94 | anchors.horizontalCenter: parent.horizontalCenter; color: 'white' } 95 | } 96 | MouseArea { 97 | anchors.fill: parent 98 | onClicked: { 99 | switchoffScreen = false 100 | } 101 | } 102 | } 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/SuggestionContainer.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | 3 | Item { 4 | id: suggestionContainer 5 | 6 | property alias historyListView: historyListView 7 | 8 | width: root.portraitMode ? 400 : urlBar.width 9 | height: suggestionDialog.height + 55 10 | anchors { top: urlBar.bottom; topMargin: -8 - xcbFontSizeAdjustment; left: urlBar.left; } 11 | visible: (urlText.focus && historyModel.count > 0) && root.state !== "setting" 12 | z: 3 13 | 14 | Rectangle { 15 | id: suggestionDialog 16 | color: "#ececec" 17 | radius: 5 18 | anchors.centerIn: parent 19 | width: root.portraitMode ? 400 : urlBar.width 20 | height: (historyModel.count > 3) ? ((historyModel.count <= 6) ? historyModel.count * 50 : 410) : 180 21 | anchors { top: parent.top; topMargin: 50; left: parent.left; } 22 | visible: (urlText.focus && historyModel.count > 0) && root.state !== "setting" 23 | 24 | Text { // caret-up 25 | anchors.top: parent.top 26 | anchors.topMargin: xcbFontSizeAdjustment + -32 27 | anchors.left: parent.horizontalCenter 28 | anchors.leftMargin: root.portraitMode ? - (urlBar.width/2) : -20 29 | font { family: fontAwesome.name; pointSize: xcbFontSizeAdjustment + 25 } 30 | text: "\uF0D8"; 31 | color: "#ECEFF4" 32 | } 33 | 34 | ListView { 35 | id: historyListView 36 | anchors.fill: parent 37 | anchors.topMargin: 20 38 | anchors.bottomMargin: 15 39 | clip: true 40 | model: historyModel 41 | delegate: historyDelegate 42 | 43 | Component { 44 | id: historyDelegate 45 | Rectangle { 46 | color: "transparent" 47 | height: 50 48 | width: historyListView.visible ? historyListView.width : 0 49 | Text { 50 | anchors { 51 | top: parent.top; left: parent.left; right: parent.right 52 | margins: 6; leftMargin: 10; 53 | } 54 | text: ''+ model.title +'' 55 | font.pointSize: xcbFontSizeAdjustment + 8 56 | elide: Text.ElideRight 57 | } 58 | Text { 59 | anchors { 60 | top: parent.top; left: parent.left; right: parent.right 61 | margins: 8; 62 | topMargin: 30; leftMargin: 10; 63 | } 64 | color: "#3e3e3e" 65 | text: model.url 66 | font.pointSize: xcbFontSizeAdjustment + 6 67 | elide: Text.ElideMiddle 68 | } 69 | MouseArea { 70 | anchors.fill: parent; 71 | onClicked: view.loadUrlWrapper(model.url) 72 | } 73 | } 74 | } 75 | highlight: Rectangle { 76 | color: '#d4d4d4' 77 | } 78 | highlightMoveDuration: 2 79 | } // end of historyListView 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/TimeZoneDialog.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Controls 2.15 3 | 4 | Dialog { 5 | width: 360 6 | height: 360 7 | visible: false 8 | signal timeZoneSelected(string text) 9 | modal: true 10 | anchors.centerIn: parent 11 | property alias rotation: container.rotation 12 | Item { 13 | id: container 14 | anchors.fill: parent 15 | ListView { 16 | id: listView 17 | anchors.fill: parent 18 | clip: true 19 | model: listModel 20 | delegate: Rectangle { 21 | width: 360 22 | height: 30 23 | clip: true 24 | Text { text: model.name; font.pointSize: xcbFontSizeAdjustment + 8 } 25 | MouseArea { 26 | anchors.fill: parent 27 | onClicked: timeZoneSelected(model.name) 28 | } 29 | } 30 | } 31 | } 32 | ListModel { id: listModel } 33 | Component.onCompleted: { 34 | var xhr = new XMLHttpRequest(); 35 | xhr.open("GET", "./timezone.txt", true); 36 | xhr.onreadystatechange = function() 37 | { 38 | if (xhr.readyState == xhr.DONE) { 39 | var response = xhr.responseText.split("\n"); 40 | for (var i=0; i < response.length; i++) { 41 | listModel.append( { "name": response[i]} ); 42 | } 43 | listView.forceLayout() 44 | } 45 | } 46 | xhr.send(); 47 | } 48 | } -------------------------------------------------------------------------------- /opt/cutiepi-shell/WallpaperDialog.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Controls 2.15 3 | import Qt.labs.folderlistmodel 2.15 4 | 5 | Dialog { 6 | width: 360 7 | height: 360 8 | visible: false 9 | signal wallpaperSelected(string fileName) 10 | modal: true 11 | property alias rotation: container.rotation 12 | Item { 13 | id: container 14 | anchors.fill: parent 15 | ListView { 16 | id: listView 17 | anchors.fill: parent 18 | clip: true 19 | model: folderModel 20 | delegate: Rectangle { 21 | width: 360 22 | height: 30 23 | clip: true 24 | Text { text: fileName; font.pointSize: xcbFontSizeAdjustment + 8 } 25 | MouseArea { 26 | anchors.fill: parent 27 | onClicked: { wallpaperSelected(folderModel.folder + fileName) } 28 | } 29 | } 30 | } 31 | } 32 | FolderListModel { 33 | id: folderModel 34 | nameFilters: ["*.jpg", "*.png"] 35 | folder: "file:///usr/share/rpd-wallpaper/" 36 | showDirs: false 37 | } 38 | } -------------------------------------------------------------------------------- /opt/cutiepi-shell/WebView.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtWebEngine 1.7 3 | 4 | WebEngineView { 5 | id: webView 6 | anchors.fill: parent 7 | anchors.topMargin: 85 8 | z: 2 9 | 10 | signal openTab(string url) 11 | signal openNewTab(string url) 12 | 13 | profile: ((typeof(adblockProfile) !== "undefined") && 14 | view.systemSettings.value("enableAdblocker", true)) ? adblockProfile : defaultProfile 15 | 16 | function updateProfile() { 17 | webView.profile = ((typeof(adblockProfile) !== "undefined") && 18 | view.systemSettings.value("enableAdblocker", true)) ? adblockProfile : defaultProfile 19 | } 20 | 21 | WebEngineProfile { 22 | id: defaultProfile 23 | //httpUserAgent: "Mozilla/5.0 (X11; CrOS aarch64 13816.82.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.218 Safari/537.36" 24 | storageName: "Profile" 25 | offTheRecord: false 26 | } 27 | 28 | onNewViewRequested: function(request) { 29 | if (!request.userInitiated) { 30 | console.log('block popup') 31 | } else if (request.destination === WebEngineView.NewViewInTab) { 32 | openNewTab(request.requestedUrl) 33 | } else { 34 | openTab(request.requestedUrl) 35 | } 36 | console.log(JSON.stringify(request)) 37 | } 38 | 39 | onContextMenuRequested: function(request) { 40 | //console.log(request.mediaUrl, request.mediaType); 41 | if (request.x !== 0 && String(request.mediaUrl).length !== 0) { 42 | contextMenu.linkUrl = request.mediaUrl 43 | contextMenu.x = request.x; contextMenu.y = request.y; 44 | contextMenu.visible = true 45 | } 46 | request.accepted = true; 47 | } 48 | 49 | MouseArea { 50 | id: webViewOverlay 51 | anchors.fill: parent 52 | enabled: contextMenu.visible 53 | z: 3 54 | onClicked: { contextMenu.visible = false } 55 | } 56 | 57 | Rectangle { 58 | id: contextMenu 59 | z: 4 60 | visible: false 61 | color: "#2E3440" 62 | width: 300 63 | height: 250 64 | property string linkUrl: "" 65 | MouseArea { anchors.fill: parent; onClicked: parent.visible = false } 66 | radius: 15 67 | Column { 68 | anchors.fill: parent 69 | spacing: 10 70 | Rectangle { 71 | width: parent.width 72 | height: 50 73 | color: 'transparent' 74 | Text { 75 | width: parent.width 76 | text: contextMenu.linkUrl 77 | wrapMode: Text.WrapAnywhere 78 | color: "#ECEFF4" 79 | font.pointSize: 6 80 | anchors { 81 | top: parent.top; left: parent.left; right: parent.right; 82 | margins: 20; topMargin: 10 83 | } 84 | } 85 | } 86 | 87 | Rectangle { 88 | width: parent.width 89 | height: 50 90 | color: 'transparent' 91 | Text { 92 | anchors.centerIn: parent 93 | text: "Open" 94 | color: "#ECEFF4" 95 | font.pointSize: 10 96 | } 97 | MouseArea { 98 | anchors.fill: parent 99 | onClicked: { 100 | contextMenu.visible = false 101 | webView.openTab(contextMenu.linkUrl); 102 | } 103 | } 104 | } 105 | Rectangle { 106 | width: parent.width 107 | height: 50 108 | color: 'transparent' 109 | Text { 110 | anchors.centerIn: parent 111 | text: "Open in New Tab" 112 | color: "#ECEFF4" 113 | font.pointSize: 10 114 | } 115 | MouseArea { 116 | anchors.fill: parent 117 | onClicked: { 118 | contextMenu.visible = false 119 | webView.openNewTab(contextMenu.linkUrl); 120 | } 121 | } 122 | } 123 | Rectangle { 124 | width: parent.width 125 | height: 50 126 | color: 'transparent' 127 | Text { 128 | anchors.centerIn: parent 129 | text: "Copy" 130 | color: "#ECEFF4" 131 | font.pointSize: 10 132 | } 133 | MouseArea { 134 | anchors.fill: parent 135 | onClicked: { 136 | contextMenu.visible = false 137 | } 138 | } 139 | } 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/assets/data_sounds_effects_wav_Dock.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutiepi-io/cutiepi-shell/caadfe099e6bad05d97e33a06789020e9326a2bd/opt/cutiepi-shell/assets/data_sounds_effects_wav_Dock.wav -------------------------------------------------------------------------------- /opt/cutiepi-shell/assets/data_sounds_effects_wav_Undock.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutiepi-io/cutiepi-shell/caadfe099e6bad05d97e33a06789020e9326a2bd/opt/cutiepi-shell/assets/data_sounds_effects_wav_Undock.wav -------------------------------------------------------------------------------- /opt/cutiepi-shell/assets/mic-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | pactl -- set-source-volume 1 240% 4 | arecord -d 3 -f cd > /tmp/test.wav 5 | paplay /tmp/test.wav 6 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/cutiepi-shell: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export XDG_RUNTIME_DIR="/run/user/1000" 4 | export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus" 5 | 6 | export QT_QPA_PLATFORM=eglfs 7 | export QT_QPA_EGLFS_INTEGRATION=eglfs_kms 8 | export QT_IM_MODULE=qtvirtualkeyboard 9 | 10 | #export QT_VIRTUALKEYBOARD_LAYOUT_PATH=/opt/cutiepi-shell/layouts/ 11 | #export QT_QPA_EGLFS_KMS_CONFIG=/opt/cutiepi-shell/kms.conf 12 | 13 | if [ ! "`systemctl is-active connman`" == "active" ]; then 14 | sudo service connman start 15 | fi 16 | 17 | rfkill unblock all 18 | sudo cpufreq-set -g ondemand 19 | 20 | #/opt/qt5/bin/qmlscene /opt/cutiepi-shell/shell.qml 21 | /opt/cutiepi-shell/shell -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/audio-volume-high-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Gnome Symbolic Icon Theme 6 | 7 | 8 | 9 | image/svg+xml 10 | 11 | Gnome Symbolic Icon Theme 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/audio-volume-low-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/audio-volume-medium-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/audio-volume-muted-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/battery-caution-charging-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/battery-caution-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/battery-empty-charging-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/battery-empty-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | Used when multiple batteries are installed and one is completely empty. 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/battery-full-charged-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/battery-full-charging-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/battery-full-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/battery-good-charging-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/battery-good-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/battery-low-charging-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/battery-low-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/battery-missing-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutiepi-io/cutiepi-shell/caadfe099e6bad05d97e33a06789020e9326a2bd/opt/cutiepi-shell/icons/favicon.png -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutiepi-io/cutiepi-shell/caadfe099e6bad05d97e33a06789020e9326a2bd/opt/cutiepi-shell/icons/logo.png -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/network-wireless-acquiring-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/network-wireless-connected-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/network-wireless-encrypted-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/network-wireless-signal-excellent-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Gnome Symbolic Icon Theme 6 | 7 | 8 | 9 | image/svg+xml 10 | 11 | Gnome Symbolic Icon Theme 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/network-wireless-signal-good-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/network-wireless-signal-none-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/network-wireless-signal-ok-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/network-wireless-signal-weak-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | Gnome Symbolic Icon Theme 11 | 12 | 13 | 14 | 15 | 16 | 17 | Gnome Symbolic Icon Theme 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/icons/terminal-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutiepi-io/cutiepi-shell/caadfe099e6bad05d97e33a06789020e9326a2bd/opt/cutiepi-shell/icons/terminal-512.png -------------------------------------------------------------------------------- /opt/cutiepi-shell/kms.conf: -------------------------------------------------------------------------------- 1 | { 2 | "device": "/dev/dri/card1", 3 | "hwcursor" : false, 4 | "outputs": [ 5 | { "name": "DSI1", "mode": "800x1280", "primary": true }, 6 | { "name": "Composite1", "mode": "off" } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/layouts/en_US/CtrlKey.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.VirtualKeyboard 2.1 3 | import QtQuick.VirtualKeyboard.Styles 2.1 4 | 5 | BaseKey { 6 | key: Qt.ControlModifier // not working this way 7 | showPreview: false 8 | functionKey: true 9 | repeat: true 10 | noModifier: true 11 | weight: 154 12 | keyPanelDelegate: KeyPanel { 13 | id: ctrlKeyPanel 14 | property real keyBackgroundMargin: Math.round(13 * keyboard.style.scaleHint) 15 | Rectangle { 16 | radius: 5 17 | color: "#1e1b18" 18 | anchors.fill: ctrlKeyPanel 19 | anchors.margins: keyBackgroundMargin 20 | Text { 21 | id: ctrlKeyText 22 | text: "Ctrl" 23 | clip: true 24 | fontSizeMode: Text.HorizontalFit 25 | horizontalAlignment: Text.AlignHCenter 26 | verticalAlignment: Text.AlignVCenter 27 | color: "white" 28 | font { 29 | family: keyboard.style.fontFamily 30 | weight: Font.Normal 31 | pixelSize: 44 * keyboard.style.scaleHint 32 | } 33 | anchors.fill: parent 34 | anchors.margins: Math.round(42 * keyboard.style.scaleHint) 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/layouts/en_US/EscKey.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.VirtualKeyboard 2.1 3 | import QtQuick.VirtualKeyboard.Styles 2.1 4 | 5 | BaseKey { 6 | key: Qt.Key_Escape 7 | displayText: "Esc" 8 | showPreview: false 9 | functionKey: true 10 | noModifier: true 11 | //onClicked: { InputContext.inputEngine.virtualKeyClick(Qt.Key_Escape, "", 0, 0); console.log('Esc') } 12 | keyPanelDelegate: KeyPanel { 13 | id: escKeyPanel 14 | property real keyBackgroundMargin: Math.round(13 * keyboard.style.scaleHint) 15 | Rectangle { 16 | radius: 5 17 | color: "#1e1b18" 18 | anchors.fill: escKeyPanel 19 | anchors.margins: keyBackgroundMargin 20 | Text { 21 | id: escKeyText 22 | text: "Esc" 23 | clip: true 24 | fontSizeMode: Text.HorizontalFit 25 | horizontalAlignment: Text.AlignHCenter 26 | verticalAlignment: Text.AlignVCenter 27 | color: "white" 28 | font { 29 | family: keyboard.style.fontFamily 30 | weight: Font.Normal 31 | pixelSize: 44 * keyboard.style.scaleHint 32 | } 33 | anchors.fill: parent 34 | anchors.margins: Math.round(42 * keyboard.style.scaleHint) 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /opt/cutiepi-shell/layouts/en_US/TabKey.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.VirtualKeyboard 2.1 3 | import QtQuick.VirtualKeyboard.Styles 2.1 4 | 5 | BaseKey { 6 | key: Qt.Key_Tab 7 | displayText: "Tab" 8 | showPreview: false 9 | weight: 250 10 | functionKey: true 11 | noModifier: true 12 | keyPanelDelegate: KeyPanel { 13 | id: tabKeyPanel 14 | property real keyBackgroundMargin: Math.round(13 * keyboard.style.scaleHint) 15 | Rectangle { 16 | radius: 5 17 | color: "#1e1b18" 18 | anchors.fill: tabKeyPanel 19 | anchors.margins: keyBackgroundMargin 20 | Text { 21 | id: tabKeyText 22 | text: "Tab" 23 | clip: true 24 | fontSizeMode: Text.HorizontalFit 25 | horizontalAlignment: Text.AlignHCenter 26 | verticalAlignment: Text.AlignVCenter 27 | color: "white" 28 | font { 29 | family: keyboard.style.fontFamily 30 | weight: Font.Normal 31 | pixelSize: 44 * keyboard.style.scaleHint 32 | } 33 | anchors.fill: parent 34 | anchors.margins: Math.round(42 * keyboard.style.scaleHint) 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/layouts/en_US/WSpaceKey.qml: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the Qt Virtual Keyboard module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:GPL$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see https://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at https://www.qt.io/contact-us. 16 | ** 17 | ** GNU General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU 19 | ** General Public License version 3 or (at your option) any later version 20 | ** approved by the KDE Free Qt Foundation. The licenses are as published by 21 | ** the Free Software Foundation and appearing in the file LICENSE.GPL3 22 | ** included in the packaging of this file. Please review the following 23 | ** information to ensure the GNU General Public License requirements will 24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 25 | ** 26 | ** $QT_END_LICENSE$ 27 | ** 28 | ****************************************************************************/ 29 | 30 | import QtQuick 2.0 31 | import QtQuick.VirtualKeyboard 2.1 32 | import QtQuick.VirtualKeyboard.Styles 2.1 33 | 34 | /*! 35 | \qmltype SpaceKey 36 | \inqmlmodule QtQuick.VirtualKeyboard 37 | \ingroup qtvirtualkeyboard-qml 38 | \inherits Key 39 | 40 | \brief Space key for keyboard layouts. 41 | 42 | This key emits a space for input method processing. 43 | */ 44 | 45 | Key { 46 | text: " " 47 | displayText: "Space" 48 | repeat: true 49 | showPreview: false 50 | key: Qt.Key_Space 51 | keyPanelDelegate: KeyPanel { 52 | id: spaceKeyPanel 53 | Rectangle { 54 | id: spaceKeyBackground 55 | radius: 5 56 | color: "#35322f" 57 | anchors.fill: spaceKeyPanel 58 | anchors.margins: Math.round(13 * keyboard.style.scaleHint) 59 | Text { 60 | id: spaceKeyText 61 | text: "Space" 62 | color: "white" 63 | anchors.centerIn: parent 64 | font { 65 | family: keyboard.style.fontFamily 66 | weight: Font.Normal 67 | pixelSize: 48 * keyboard.style.scaleHint 68 | } 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/layouts/en_US/dialpad.qml: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the Qt Virtual Keyboard module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:GPL$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see https://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at https://www.qt.io/contact-us. 16 | ** 17 | ** GNU General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU 19 | ** General Public License version 3 or (at your option) any later version 20 | ** approved by the KDE Free Qt Foundation. The licenses are as published by 21 | ** the Free Software Foundation and appearing in the file LICENSE.GPL3 22 | ** included in the packaging of this file. Please review the following 23 | ** information to ensure the GNU General Public License requirements will 24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 25 | ** 26 | ** $QT_END_LICENSE$ 27 | ** 28 | ****************************************************************************/ 29 | 30 | import QtQuick 2.0 31 | import QtQuick.Layouts 1.0 32 | import QtQuick.VirtualKeyboard 2.1 33 | 34 | KeyboardLayout { 35 | inputMethod: PlainInputMethod {} 36 | inputMode: InputEngine.Numeric 37 | 38 | KeyboardColumn { 39 | Layout.fillWidth: false 40 | Layout.fillHeight: true 41 | Layout.alignment: Qt.AlignHCenter 42 | Layout.preferredWidth: height 43 | KeyboardRow { 44 | Key { 45 | key: Qt.Key_1 46 | text: "1" 47 | } 48 | Key { 49 | key: Qt.Key_2 50 | text: "2" 51 | } 52 | Key { 53 | key: Qt.Key_3 54 | text: "3" 55 | } 56 | BackspaceKey {} 57 | } 58 | KeyboardRow { 59 | Key { 60 | key: Qt.Key_4 61 | text: "4" 62 | } 63 | Key { 64 | key: Qt.Key_5 65 | text: "5" 66 | } 67 | Key { 68 | key: Qt.Key_6 69 | text: "6" 70 | } 71 | Key { 72 | text: " " 73 | displayText: "\u2423" 74 | repeat: true 75 | showPreview: false 76 | key: Qt.Key_Space 77 | } 78 | } 79 | KeyboardRow { 80 | Key { 81 | key: Qt.Key_7 82 | text: "7" 83 | } 84 | Key { 85 | key: Qt.Key_8 86 | text: "8" 87 | } 88 | Key { 89 | key: Qt.Key_9 90 | text: "9" 91 | } 92 | HideKeyboardKey {} 93 | } 94 | KeyboardRow { 95 | Key { 96 | key: Qt.Key_Asterisk 97 | displayText: "*+" 98 | text: "*" 99 | alternativeKeys: "*+" 100 | } 101 | Key { 102 | key: Qt.Key_0 103 | text: "0" 104 | } 105 | Key { 106 | text: "#" 107 | key: Qt.Key_NumberSign 108 | } 109 | EnterKey {} 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/layouts/en_US/digits.qml: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the Qt Virtual Keyboard module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:GPL$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see https://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at https://www.qt.io/contact-us. 16 | ** 17 | ** GNU General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU 19 | ** General Public License version 3 or (at your option) any later version 20 | ** approved by the KDE Free Qt Foundation. The licenses are as published by 21 | ** the Free Software Foundation and appearing in the file LICENSE.GPL3 22 | ** included in the packaging of this file. Please review the following 23 | ** information to ensure the GNU General Public License requirements will 24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 25 | ** 26 | ** $QT_END_LICENSE$ 27 | ** 28 | ****************************************************************************/ 29 | 30 | import QtQuick 2.0 31 | import QtQuick.Layouts 1.0 32 | import QtQuick.VirtualKeyboard 2.1 33 | 34 | KeyboardLayout { 35 | inputMethod: PlainInputMethod {} 36 | inputMode: InputEngine.Numeric 37 | 38 | KeyboardColumn { 39 | Layout.fillWidth: false 40 | Layout.fillHeight: true 41 | Layout.alignment: Qt.AlignHCenter 42 | Layout.preferredWidth: height 43 | KeyboardRow { 44 | Key { 45 | key: Qt.Key_7 46 | text: "7" 47 | } 48 | Key { 49 | key: Qt.Key_8 50 | text: "8" 51 | } 52 | Key { 53 | key: Qt.Key_9 54 | text: "9" 55 | } 56 | BackspaceKey {} 57 | } 58 | KeyboardRow { 59 | Key { 60 | key: Qt.Key_4 61 | text: "4" 62 | } 63 | Key { 64 | key: Qt.Key_5 65 | text: "5" 66 | } 67 | Key { 68 | key: Qt.Key_6 69 | text: "6" 70 | } 71 | Key { 72 | text: " " 73 | displayText: "\u2423" 74 | repeat: true 75 | showPreview: false 76 | key: Qt.Key_Space 77 | } 78 | } 79 | KeyboardRow { 80 | Key { 81 | key: Qt.Key_1 82 | text: "1" 83 | } 84 | Key { 85 | key: Qt.Key_2 86 | text: "2" 87 | } 88 | Key { 89 | key: Qt.Key_3 90 | text: "3" 91 | } 92 | HideKeyboardKey {} 93 | } 94 | KeyboardRow { 95 | ChangeLanguageKey { 96 | customLayoutsOnly: true 97 | } 98 | Key { 99 | key: Qt.Key_0 100 | text: "0" 101 | } 102 | Key { 103 | // The decimal key, if it is not "," then we fallback to 104 | // "." in case it is an unhandled different result 105 | key: Qt.locale().decimalPoint === "," ? Qt.Key_Comma : Qt.Key_Period 106 | text: Qt.locale().decimalPoint === "," ? "," : "." 107 | } 108 | EnterKey {} 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/layouts/en_US/handwriting.qml: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the Qt Virtual Keyboard module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:GPL$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see https://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at https://www.qt.io/contact-us. 16 | ** 17 | ** GNU General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU 19 | ** General Public License version 3 or (at your option) any later version 20 | ** approved by the KDE Free Qt Foundation. The licenses are as published by 21 | ** the Free Software Foundation and appearing in the file LICENSE.GPL3 22 | ** included in the packaging of this file. Please review the following 23 | ** information to ensure the GNU General Public License requirements will 24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 25 | ** 26 | ** $QT_END_LICENSE$ 27 | ** 28 | ****************************************************************************/ 29 | 30 | import QtQuick 2.0 31 | import QtQuick.Layouts 1.0 32 | import QtQuick.VirtualKeyboard 2.3 33 | 34 | KeyboardLayout { 35 | function createInputMethod() { 36 | return Qt.createQmlObject('import QtQuick 2.0; import QtQuick.VirtualKeyboard 2.3; HandwritingInputMethod {}', parent) 37 | } 38 | sharedLayouts: ['symbols'] 39 | inputMode: InputEngine.Latin 40 | 41 | KeyboardRow { 42 | Layout.preferredHeight: 3 43 | KeyboardColumn { 44 | Layout.preferredWidth: bottomRow.width - hideKeyboardKey.width 45 | KeyboardRow { 46 | TraceInputKey { 47 | objectName: "hwrInputArea" 48 | patternRecognitionMode: InputEngine.HandwritingRecoginition 49 | } 50 | } 51 | } 52 | KeyboardColumn { 53 | Layout.preferredWidth: hideKeyboardKey.width 54 | KeyboardRow { 55 | BackspaceKey {} 56 | } 57 | KeyboardRow { 58 | EnterKey {} 59 | } 60 | KeyboardRow { 61 | ShiftKey { } 62 | } 63 | } 64 | } 65 | KeyboardRow { 66 | id: bottomRow 67 | Layout.preferredHeight: 1 68 | keyWeight: 154 69 | InputModeKey { 70 | weight: 217 71 | } 72 | ChangeLanguageKey { 73 | weight: 154 74 | customLayoutsOnly: true 75 | } 76 | HandwritingModeKey { 77 | weight: 154 78 | } 79 | SpaceKey { 80 | weight: 864 81 | } 82 | Key { 83 | key: Qt.Key_Apostrophe 84 | text: "'" 85 | alternativeKeys: "<>()#%&*/\\\"'=+-_" 86 | } 87 | Key { 88 | key: Qt.Key_Period 89 | text: "." 90 | alternativeKeys: ":;,.?!" 91 | } 92 | HideKeyboardKey { 93 | id: hideKeyboardKey 94 | weight: 204 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /opt/cutiepi-shell/layouts/en_US/numbers.qml: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the Qt Virtual Keyboard module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:GPL$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see https://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at https://www.qt.io/contact-us. 16 | ** 17 | ** GNU General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU 19 | ** General Public License version 3 or (at your option) any later version 20 | ** approved by the KDE Free Qt Foundation. The licenses are as published by 21 | ** the Free Software Foundation and appearing in the file LICENSE.GPL3 22 | ** included in the packaging of this file. Please review the following 23 | ** information to ensure the GNU General Public License requirements will 24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 25 | ** 26 | ** $QT_END_LICENSE$ 27 | ** 28 | ****************************************************************************/ 29 | 30 | import QtQuick 2.0 31 | import QtQuick.Layouts 1.0 32 | import QtQuick.VirtualKeyboard 2.1 33 | 34 | KeyboardLayout { 35 | inputMethod: PlainInputMethod {} 36 | inputMode: InputEngine.Numeric 37 | 38 | KeyboardRow { 39 | Layout.fillWidth: false 40 | Layout.fillHeight: true 41 | Layout.alignment: Qt.AlignHCenter 42 | KeyboardColumn { 43 | Layout.fillWidth: false 44 | Layout.fillHeight: true 45 | Layout.preferredWidth: parent.height / 4 * 3 46 | KeyboardRow { 47 | Key { 48 | key: Qt.Key_ParenLeft 49 | text: "(" 50 | } 51 | Key { 52 | key: Qt.Key_ParenRight 53 | text: ")" 54 | } 55 | Key { 56 | key: Qt.Key_Comma 57 | text: "," 58 | } 59 | } 60 | KeyboardRow { 61 | Key { 62 | key: Qt.Key_division 63 | text: "\u00F7" 64 | } 65 | Key { 66 | key: Qt.Key_multiply 67 | text: "\u00D7" 68 | } 69 | Key { 70 | key: Qt.Key_Plus 71 | text: "+" 72 | } 73 | } 74 | KeyboardRow { 75 | Key { 76 | key: Qt.Key_AsciiCircum 77 | text: "^" 78 | } 79 | Key { 80 | key: Qt.Key_Slash 81 | text: "/" 82 | } 83 | Key { 84 | key: Qt.Key_Minus 85 | text: "-" 86 | } 87 | } 88 | KeyboardRow { 89 | Key { 90 | key: 0x221A 91 | text: "√" 92 | } 93 | Key { 94 | key: Qt.Key_Percent 95 | text: "%" 96 | } 97 | Key { 98 | key: Qt.Key_Asterisk 99 | text: "*" 100 | } 101 | } 102 | } 103 | KeyboardColumn { 104 | Layout.fillWidth: false 105 | Layout.fillHeight: true 106 | Layout.preferredWidth: parent.height / 8 107 | KeyboardRow { 108 | FillerKey {} 109 | } 110 | } 111 | KeyboardColumn { 112 | Layout.fillWidth: false 113 | Layout.fillHeight: true 114 | Layout.preferredWidth: parent.height 115 | KeyboardRow { 116 | Key { 117 | key: Qt.Key_7 118 | text: "7" 119 | } 120 | Key { 121 | key: Qt.Key_8 122 | text: "8" 123 | } 124 | Key { 125 | key: Qt.Key_9 126 | text: "9" 127 | } 128 | BackspaceKey {} 129 | } 130 | KeyboardRow { 131 | Key { 132 | key: Qt.Key_4 133 | text: "4" 134 | } 135 | Key { 136 | key: Qt.Key_5 137 | text: "5" 138 | } 139 | Key { 140 | key: Qt.Key_6 141 | text: "6" 142 | } 143 | Key { 144 | text: " " 145 | displayText: "\u2423" 146 | repeat: true 147 | showPreview: false 148 | key: Qt.Key_Space 149 | } 150 | } 151 | KeyboardRow { 152 | Key { 153 | key: Qt.Key_1 154 | text: "1" 155 | } 156 | Key { 157 | key: Qt.Key_2 158 | text: "2" 159 | } 160 | Key { 161 | key: Qt.Key_3 162 | text: "3" 163 | } 164 | HideKeyboardKey {} 165 | } 166 | KeyboardRow { 167 | ChangeLanguageKey { 168 | customLayoutsOnly: true 169 | } 170 | Key { 171 | key: Qt.Key_0 172 | text: "0" 173 | } 174 | Key { 175 | key: Qt.Key_Period 176 | text: "." 177 | alternativeKeys: ".," 178 | } 179 | EnterKey {} 180 | } 181 | } 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /screenshots/cutiepi-shell-heroshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutiepi-io/cutiepi-shell/caadfe099e6bad05d97e33a06789020e9326a2bd/screenshots/cutiepi-shell-heroshot.png -------------------------------------------------------------------------------- /screenshots/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutiepi-io/cutiepi-shell/caadfe099e6bad05d97e33a06789020e9326a2bd/screenshots/settings.png -------------------------------------------------------------------------------- /screenshots/sidetab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutiepi-io/cutiepi-shell/caadfe099e6bad05d97e33a06789020e9326a2bd/screenshots/sidetab.png -------------------------------------------------------------------------------- /screenshots/terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutiepi-io/cutiepi-shell/caadfe099e6bad05d97e33a06789020e9326a2bd/screenshots/terminal.png -------------------------------------------------------------------------------- /screenshots/wifi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutiepi-io/cutiepi-shell/caadfe099e6bad05d97e33a06789020e9326a2bd/screenshots/wifi.png -------------------------------------------------------------------------------- /systray/images/battery-caution-symbolic.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /systray/images/battery-empty-symbolic.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /systray/images/battery-full-charged-symbolic.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /systray/images/battery-full-symbolic.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /systray/images/battery-good-symbolic.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /systray/images/battery-low-symbolic.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /systray/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 7 | QApplication app(argc, argv); 8 | QQmlApplicationEngine engine; 9 | engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); 10 | return app.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /systray/main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import McuInfo 1.0 3 | import Process 1.0 4 | import QtSensors 5.11 5 | import Qt.labs.platform 1.1 6 | 7 | Item { 8 | property bool batteryCharging: false 9 | property bool screenLocked: false 10 | property bool powerOffButton: false 11 | 12 | property real pitch: 0.0 13 | property real roll: 0.0 14 | readonly property double radians_to_degrees: 180 / Math.PI 15 | 16 | property variant orientation: 270 17 | 18 | property variant batteryPercentage: "" 19 | property variant meanVol: "" 20 | property variant queue: [] 21 | 22 | Component.onCompleted: { 23 | mcuInfo.start(); 24 | } 25 | 26 | function turnScreenOn() { setScreenBrightness(100) } 27 | function turnScreenOff() { setScreenBrightness(0) } 28 | function setScreenBrightness(val) { process.start("/opt/cutiepi-shell/assets/setBrightness", [val]); } 29 | 30 | onOrientationChanged: { 31 | process.start("rotate-screen", [orientation]); 32 | } 33 | 34 | onScreenLockedChanged: { 35 | if (screenLocked) 36 | turnScreenOff() 37 | else 38 | turnScreenOn() 39 | powerOffButton = false; 40 | } 41 | 42 | onPowerOffButtonChanged: { 43 | if (powerOffButton) { 44 | turnScreenOn(); 45 | process.start("lxde-pi-shutdown-helper", []); 46 | } 47 | } 48 | 49 | SystemTrayIcon { 50 | visible: true 51 | icon.source: if (batteryCharging) { "images/battery-full-charged-symbolic.svg" } 52 | else if (batteryPercentage >= 80) { "images/battery-full-symbolic.svg" } 53 | else if (batteryPercentage >= 50) { "images/battery-good-symbolic.svg" } 54 | else if (batteryPercentage >= 30) { "images/battery-low-symbolic.svg" } 55 | else if (batteryPercentage >= 20) { "images/battery-caution-symbolic.svg" } 56 | else { "images/battery-empty-symbolic.svg" } 57 | onActivated: showMessage("Battery: " + batteryPercentage + "%", "Measured voltage: " + meanVol + " v") 58 | } 59 | 60 | Process { id: process } 61 | 62 | McuInfo { 63 | id: mcuInfo 64 | portName: "/dev/ttyS0" 65 | portBaudRate: 115200 66 | 67 | property variant batteryAttributes: 68 | { '4.20': 100, '3.99': 95, '3.97': 90, '3.92': 85, '3.87': 80, '3.83': 75, '3.79': 70, 69 | '3.75': 65, '3.73': 60, '3.70': 55, '3.68': 50, '3.66': 45, '3.65': 40, '3.63': 35, 70 | '3.62': 30, '3.60': 25, '3.58': 20, '3.545': 15, '3.51': 10, '3.42': 5, '3.00': 0 } 71 | 72 | onButtonChanged: { 73 | if (button == 1) 74 | screenLocked = !screenLocked; 75 | if (button == 3) { 76 | powerOffButton = true; 77 | } 78 | } 79 | 80 | onBatteryChanged: { 81 | var currentVol = (battery/1000).toFixed(2); 82 | var sum = 0; 83 | queue.push(currentVol); 84 | if (queue.length > 10) 85 | queue.shift() 86 | for (var i = 0; i < queue.length; i++) { 87 | sum += parseFloat(queue[i]) 88 | } 89 | meanVol = (sum/queue.length).toFixed(2); 90 | for (var vol in batteryAttributes) { 91 | if (meanVol >= parseFloat(vol)) { 92 | var volPercent = batteryAttributes[vol]; 93 | batteryPercentage = volPercent 94 | break; 95 | } 96 | } 97 | } 98 | 99 | onChargeChanged: { 100 | if (charge == 4) batteryCharging = true 101 | if (charge == 5) batteryCharging = false 102 | } 103 | } 104 | 105 | Accelerometer { 106 | id: accel 107 | active: true 108 | dataRate: 30 109 | onReadingChanged: { 110 | var accX = accel.reading.x 111 | var accY = accel.reading.y - 2 //experimental calibration 112 | var accZ = -accel.reading.z 113 | 114 | var pitchAcc = Math.atan2(accY, accZ)*radians_to_degrees; 115 | var rollAcc = Math.atan2(accX, accZ)*radians_to_degrees; 116 | 117 | pitch = pitch * 0.98 + pitchAcc * 0.02; 118 | roll = roll * 0.98 + rollAcc * 0.02; 119 | 120 | var tmp = orientation; 121 | 122 | //update orientation 123 | if(pitch >= 30.0) 124 | tmp = 0 125 | else if(pitch <= -30.0) 126 | tmp = 180 127 | if(roll >= 30.0) 128 | tmp = 270 129 | else if(roll <= -30.0) 130 | tmp = 90 131 | 132 | orientation = tmp; 133 | } 134 | } 135 | 136 | Gyroscope { 137 | id: gyro 138 | active: true 139 | dataRate: 30 140 | onReadingChanged: { 141 | //integrate gyro rates to update angles (pitch and roll) 142 | var dt=0.01 //10ms 143 | pitch += gyro.reading.x*dt; 144 | roll -= gyro.reading.y*dt; 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /systray/qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | main.qml 4 | images/battery-caution-symbolic.svg 5 | images/battery-low-symbolic.svg 6 | images/battery-full-symbolic.svg 7 | images/battery-full-charged-symbolic.svg 8 | images/battery-empty-symbolic.svg 9 | images/battery-good-symbolic.svg 10 | 11 | 12 | -------------------------------------------------------------------------------- /systray/systray.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | TARGET = cutiepi-systray 3 | QT += qml widgets 4 | 5 | SOURCES += main.cpp 6 | RESOURCES += qml.qrc 7 | --------------------------------------------------------------------------------