├── gtk ├── init ├── mark-and-exec ├── desktop-exports ├── snapcraft.yaml ├── runtime-exports ├── Makefile └── launcher-specific ├── qt ├── init ├── runtime-exports ├── desktop-exports ├── mark-and-exec ├── snapcraft.yaml ├── Makefile └── launcher-specific ├── glib-only ├── init ├── mark-and-exec ├── desktop-exports ├── launcher-specific └── Makefile ├── .gitignore ├── demos ├── qt5 │ ├── src │ │ ├── images │ │ │ ├── copy.png │ │ │ ├── cut.png │ │ │ ├── new.png │ │ │ ├── open.png │ │ │ ├── paste.png │ │ │ └── save.png │ │ ├── application.pro │ │ ├── application.qrc │ │ ├── main.cpp │ │ ├── mainwindow.h │ │ └── mainwindow.cpp │ ├── snap │ │ └── gui │ │ │ ├── qt5-application.png │ │ │ └── qt5-application.desktop │ └── snapcraft.yaml ├── gtk2 │ └── snapcraft.yaml └── gtk3 │ └── snapcraft.yaml ├── common ├── mark-and-exec ├── init └── desktop-exports ├── Dockerfile ├── LICENSE ├── README.md ├── src └── bindtextdomain.c └── snapcraft.yaml /gtk/init: -------------------------------------------------------------------------------- 1 | ../common/init -------------------------------------------------------------------------------- /qt/init: -------------------------------------------------------------------------------- 1 | ../common/init -------------------------------------------------------------------------------- /qt/runtime-exports: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /glib-only/init: -------------------------------------------------------------------------------- 1 | ../common/init -------------------------------------------------------------------------------- /gtk/mark-and-exec: -------------------------------------------------------------------------------- 1 | ../common/mark-and-exec -------------------------------------------------------------------------------- /qt/desktop-exports: -------------------------------------------------------------------------------- 1 | ../common/desktop-exports -------------------------------------------------------------------------------- /qt/mark-and-exec: -------------------------------------------------------------------------------- 1 | ../common/mark-and-exec -------------------------------------------------------------------------------- /glib-only/mark-and-exec: -------------------------------------------------------------------------------- 1 | ../common/mark-and-exec -------------------------------------------------------------------------------- /gtk/desktop-exports: -------------------------------------------------------------------------------- 1 | ../common/desktop-exports -------------------------------------------------------------------------------- /glib-only/desktop-exports: -------------------------------------------------------------------------------- 1 | ../common/desktop-exports -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/parts 2 | **/stage 3 | **/snap 4 | **/prime 5 | **/*.snap 6 | **/*.tar* 7 | -------------------------------------------------------------------------------- /demos/qt5/src/images/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ubuntu/snapcraft-desktop-helpers/HEAD/demos/qt5/src/images/copy.png -------------------------------------------------------------------------------- /demos/qt5/src/images/cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ubuntu/snapcraft-desktop-helpers/HEAD/demos/qt5/src/images/cut.png -------------------------------------------------------------------------------- /demos/qt5/src/images/new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ubuntu/snapcraft-desktop-helpers/HEAD/demos/qt5/src/images/new.png -------------------------------------------------------------------------------- /demos/qt5/src/images/open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ubuntu/snapcraft-desktop-helpers/HEAD/demos/qt5/src/images/open.png -------------------------------------------------------------------------------- /demos/qt5/src/images/paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ubuntu/snapcraft-desktop-helpers/HEAD/demos/qt5/src/images/paste.png -------------------------------------------------------------------------------- /demos/qt5/src/images/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ubuntu/snapcraft-desktop-helpers/HEAD/demos/qt5/src/images/save.png -------------------------------------------------------------------------------- /glib-only/launcher-specific: -------------------------------------------------------------------------------- 1 | ############################## 2 | # Glib minimum specific part # 3 | ############################## 4 | 5 | -------------------------------------------------------------------------------- /demos/qt5/snap/gui/qt5-application.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ubuntu/snapcraft-desktop-helpers/HEAD/demos/qt5/snap/gui/qt5-application.png -------------------------------------------------------------------------------- /demos/qt5/src/application.pro: -------------------------------------------------------------------------------- 1 | QT += widgets 2 | 3 | HEADERS = mainwindow.h 4 | SOURCES = main.cpp \ 5 | mainwindow.cpp 6 | #! [0] 7 | RESOURCES = application.qrc 8 | #! [0] 9 | 10 | # install 11 | target.path = /bin 12 | INSTALLS += target 13 | -------------------------------------------------------------------------------- /demos/qt5/src/application.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/copy.png 4 | images/cut.png 5 | images/new.png 6 | images/open.png 7 | images/paste.png 8 | images/save.png 9 | 10 | 11 | -------------------------------------------------------------------------------- /gtk/snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: gtk 2 | version: 0.1 3 | summary: This is meant to be consumed by other projects 4 | description: | 5 | This sets up the GTK environment for GTK-based projects and its dependencies 6 | confinement: strict 7 | 8 | parts: 9 | gtk: 10 | source: . 11 | plugin: make 12 | make-parameters: ["SRC_DIR=../src", "FLAVOR=gtk2"] 13 | -------------------------------------------------------------------------------- /demos/qt5/snap/gui/qt5-application.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Encoding=UTF-8 3 | Name=Qt5App 4 | GenericName=A simple text editor 5 | Comment=A simple text editor 6 | Exec=qt5-application 7 | Icon=${SNAP}/meta/gui/qt5-application.png 8 | Terminal=false 9 | Type=Application 10 | StartupNotify=false 11 | Categories=Application;Game 12 | Keywords=mc-installer; 13 | -------------------------------------------------------------------------------- /common/mark-and-exec: -------------------------------------------------------------------------------- 1 | ############################### 2 | # Mark update and exec binary # 3 | ############################### 4 | 5 | [ $needs_update = true ] && echo "SNAP_DESKTOP_LAST_REVISION=$SNAP_REVISION" > $SNAP_USER_DATA/.last_revision 6 | 7 | wait_for_async_execs 8 | 9 | if [ -n "$SNAP_DESKTOP_DEBUG" ]; then 10 | echo "desktop-launch elapsed time: " $(date +%s.%N --date="$START seconds ago") 11 | echo "Now running: exec $@" 12 | fi 13 | 14 | exec "$@" 15 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM snapcore/snapcraft:stable 2 | 3 | RUN apt-get install -q -y --no-install-recommends software-properties-common && \ 4 | add-apt-repository -yu ppa:ubuntu-desktop/gnome-3-26 && \ 5 | apt-get update && \ 6 | apt-get dist-upgrade --yes && \ 7 | apt-get install --yes \ 8 | build-essential \ 9 | libgtk-3-dev \ 10 | snapcraft \ 11 | && \ 12 | apt-get autoclean --yes && \ 13 | apt-get clean --yes 14 | 15 | # Required by click. 16 | ENV LC_ALL C.UTF-8 17 | ENV SNAPCRAFT_SETUP_CORE 1 18 | -------------------------------------------------------------------------------- /demos/gtk2/snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: gtk2-demo 2 | version: "0" 3 | summary: Gtk2 launcher demo 4 | description: This is using the gtk2 demo 5 | grade: stable 6 | confinement: strict 7 | 8 | apps: 9 | gtk2-demo: 10 | command: desktop-launch gtk-demo 11 | plugs: [unity7, x11, gsettings, home] 12 | gsettings: 13 | command: desktop-launch gsettings 14 | plugs: [x11, gsettings, home] 15 | 16 | parts: 17 | gtk2-demo: 18 | plugin: nil 19 | stage-packages: [gtk2.0-examples, libglib2.0-bin] 20 | after: [desktop-gtk2] 21 | -------------------------------------------------------------------------------- /glib-only/Makefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | SRC_DIR ?= . 4 | 5 | DEST_LAUNCHER = desktop-launch 6 | 7 | build: $(DEST_LAUNCHER) 8 | 9 | clean: 10 | rm -f $(DEST_LAUNCHER) 11 | 12 | $(DEST_LAUNCHER): 13 | @echo "#!/bin/bash" > $(DEST_LAUNCHER) 14 | @cat $(SRC_DIR)/init >> $(DEST_LAUNCHER) 15 | @cat $(SRC_DIR)/desktop-exports >> $(DEST_LAUNCHER) 16 | @cat $(SRC_DIR)/launcher-specific >> $(DEST_LAUNCHER) 17 | @cat $(SRC_DIR)/mark-and-exec >> $(DEST_LAUNCHER) 18 | 19 | install: $(DEST_LAUNCHER) 20 | install -D -m755 $(DEST_LAUNCHER) "$(DESTDIR)"/bin/$(DEST_LAUNCHER) 21 | -------------------------------------------------------------------------------- /qt/snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: application 2 | version: 1 3 | summary: Qt Application Example 4 | description: A simple text editor 5 | confinement: devmode 6 | 7 | apps: 8 | application: 9 | command: desktop-launch application 10 | plugs: [unity7, home] 11 | 12 | parts: 13 | application: 14 | source: src/ 15 | plugin: qmake 16 | qt-version: qt5 17 | after: [qt5] 18 | qt5: 19 | source: . 20 | plugin: make 21 | make-parameters: ["SRC_DIR=../src"] 22 | build-packages: 23 | - qtbase5-dev 24 | - dpkg-dev 25 | stage-packages: 26 | - libxkbcommon0 27 | - ttf-ubuntu-font-family 28 | - dmz-cursor-theme 29 | - light-themes 30 | - shared-mime-info 31 | - libqt5gui5 32 | - libgdk-pixbuf2.0-0 33 | - libqt5svg5 # for loading icon themes which are svg 34 | - appmenu-qt5 35 | 36 | -------------------------------------------------------------------------------- /gtk/runtime-exports: -------------------------------------------------------------------------------- 1 | ########################### 2 | # GNOME runtime selection # 3 | ########################### 4 | 5 | if [ -d $SNAP/gnome-platform ]; then 6 | RUNTIME=$SNAP/gnome-platform 7 | if [ ! -d $RUNTIME/usr ]; then 8 | platform_snap_name="$( 9 | grep \ 10 | --extended-regexp \ 11 | 'default-provider: *gnome-[[:digit:]]+-[[:digit:]]+-[[:digit:]]+' \ 12 | $SNAP/meta/snap.yaml \ 13 | | cut --delimiter=: --fields=2 \ 14 | | sed 's/^ *//' \ 15 | || true 16 | )" 17 | 18 | if test -n "${platform_snap_name}"; then 19 | echo "You need to connect this snap to the gnome platform snap." 20 | echo "" 21 | echo "You can do this with those commands:" 22 | echo "snap install ${platform_snap_name}" 23 | echo "snap connect $SNAP_NAME:${platform_snap_name} ${platform_snap_name}" 24 | echo "" 25 | exit 1 26 | fi 27 | fi 28 | fi 29 | 30 | -------------------------------------------------------------------------------- /gtk/Makefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | FLAVOR ?= gtk3 4 | SRC_DIR ?= . 5 | 6 | DEST_LAUNCHER = desktop-launch 7 | FLAVOR_FILE = flavor-select 8 | BINDTEXTDOMAIN = bindtextdomain.so 9 | 10 | build: $(DEST_LAUNCHER) 11 | 12 | clean: 13 | rm -f $(DEST_LAUNCHER) 14 | rm -f $(FLAVOR_FILE) 15 | rm -f $(BINDTEXTDOMAIN) 16 | 17 | $(DEST_LAUNCHER): 18 | @echo "#!/bin/bash" > $(DEST_LAUNCHER) 19 | @cat $(SRC_DIR)/init >> $(DEST_LAUNCHER) 20 | @cat $(SRC_DIR)/runtime-exports >> $(DEST_LAUNCHER) 21 | @cat $(SRC_DIR)/desktop-exports >> $(DEST_LAUNCHER) 22 | @cat $(SRC_DIR)/launcher-specific >> $(DEST_LAUNCHER) 23 | @cat $(SRC_DIR)/mark-and-exec >> $(DEST_LAUNCHER) 24 | @echo "USE_$(FLAVOR)=true" >> $(FLAVOR_FILE) 25 | gcc -Wall -O2 -o $(BINDTEXTDOMAIN) -fPIC -shared $(SRC_DIR)/../src/bindtextdomain.c -ldl 26 | 27 | install: $(DEST_LAUNCHER) 28 | install -D -m755 $(DEST_LAUNCHER) "$(DESTDIR)"/bin/$(DEST_LAUNCHER) 29 | install -D -m644 $(FLAVOR_FILE) "$(DESTDIR)"/ 30 | install -D -m644 $(BINDTEXTDOMAIN) "$(DESTDIR)"/lib/$(BINDTEXTDOMAIN) 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Canonical 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /gtk/launcher-specific: -------------------------------------------------------------------------------- 1 | ############################## 2 | # GTK launcher specific part # 3 | ############################## 4 | 5 | # select gtk version 6 | . $SNAP/flavor-select 7 | 8 | if [ "$USE_gtk3" = true ]; then 9 | if [ "$wayland_available" = true ]; then 10 | export GDK_BACKEND="wayland" 11 | export CLUTTER_BACKEND="wayland" 12 | # Does not hurt to specify this as well, just in case 13 | export QT_QPA_PLATFORM=wayland-egl 14 | fi 15 | append_dir GTK_PATH $RUNTIME/usr/lib/$ARCH/gtk-3.0 16 | else 17 | [ "$wayland_available" = true ] && echo "Warning: GTK2 does not support Wayland!" 18 | append_dir GTK_PATH $RUNTIME/usr/lib/$ARCH/gtk-2.0 19 | fi 20 | 21 | # ibus and fcitx integration 22 | GTK_IM_MODULE_DIR=$XDG_CACHE_HOME/immodules 23 | export GTK_IM_MODULE_FILE=$GTK_IM_MODULE_DIR/immodules.cache 24 | if [ $needs_update = true ]; then 25 | rm -rf $GTK_IM_MODULE_DIR 26 | ensure_dir_exists $GTK_IM_MODULE_DIR 27 | if [ "$USE_gtk3" = true ]; then 28 | ln -s $RUNTIME/usr/lib/$ARCH/gtk-3.0/3.0.0/immodules/*.so $GTK_IM_MODULE_DIR 29 | async_exec $RUNTIME/usr/lib/$ARCH/libgtk-3-0/gtk-query-immodules-3.0 > $GTK_IM_MODULE_FILE 30 | else 31 | ln -s $RUNTIME/usr/lib/$ARCH/gtk-2.0/2.10.0/immodules/*.so $GTK_IM_MODULE_DIR 32 | async_exec $RUNTIME/usr/lib/$ARCH/libgtk2.0-0/gtk-query-immodules-2.0 > $GTK_IM_MODULE_FILE 33 | fi 34 | fi 35 | 36 | -------------------------------------------------------------------------------- /qt/Makefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | FLAVOR ?= qt5 4 | SRC_DIR ?= . 5 | 6 | DEST_LAUNCHER = desktop-launch 7 | FLAVOR_FILE = flavor-select 8 | 9 | arch_triplet := $(shell dpkg-architecture -q DEB_TARGET_MULTIARCH) 10 | 11 | define QT5_CONF 12 | ./usr/lib/$(arch_triplet)/qt5/bin 13 | ./usr/lib/$(arch_triplet) 14 | endef 15 | export QT5_CONF 16 | 17 | define QT4_CONF 18 | ./usr/lib/$(arch_triplet)/qt4/bin 19 | ./usr/lib/$(arch_triplet) 20 | endef 21 | export QT4_CONF 22 | 23 | 24 | build: $(DEST_LAUNCHER) 25 | 26 | clean: 27 | rm -f $(DEST_LAUNCHER) 28 | rm -rf snappy-qt*.conf 29 | rm -f $(FLAVOR_FILE) 30 | 31 | desktop-launch: 32 | @echo "#!/bin/bash" > $(DEST_LAUNCHER) 33 | @cat $(SRC_DIR)/init >> $(DEST_LAUNCHER) 34 | @cat $(SRC_DIR)/runtime-exports >> $(DEST_LAUNCHER) 35 | @cat $(SRC_DIR)/desktop-exports >> $(DEST_LAUNCHER) 36 | @cat $(SRC_DIR)/launcher-specific >> $(DEST_LAUNCHER) 37 | @cat $(SRC_DIR)/mark-and-exec >> $(DEST_LAUNCHER) 38 | @echo "$$QT5_CONF" > snappy-qt5.conf 39 | @echo "$$QT4_CONF" > snappy-qt4.conf 40 | @echo "USE_$(FLAVOR)=true" >> $(FLAVOR_FILE) 41 | 42 | install: desktop-launch 43 | install -D -m755 $(DEST_LAUNCHER) "$(DESTDIR)"/bin/$(DEST_LAUNCHER) 44 | install -D -m644 snappy-qt5.conf \ 45 | "$(DESTDIR)"/etc/xdg/qtchooser/snappy-qt5.conf 46 | install -D -m644 snappy-qt4.conf \ 47 | "$(DESTDIR)"/etc/xdg/qtchooser/snappy-qt4.conf 48 | install -D -m644 $(FLAVOR_FILE) "$(DESTDIR)"/ 49 | 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DEPRECATED -- Use gnome or kde-neon extension 2 | 3 | The snapcraft desktop helpers are no longer support please use one of the following snapcraft extensions 4 | * [GNOME (for GTK or apps that require typical desktop support)](https://documentation.ubuntu.com/snapcraft/stable/reference/extensions/gnome-extension/) 5 | * [KDE (for KDE or Qt)](https://documentation.ubuntu.com/snapcraft/stable/reference/extensions/kde-neon-extensions/) 6 | 7 | # Snapcraft Desktop Helpers 8 | 9 | The snapcraft desktop helpers project contains a number of tools to help you create snaps for desktop applications. For example, several environment variables and compatibility symlinks are setup in the [desktop-launch wrapper](https://github.com/ubuntu/snapcraft-desktop-helpers/blob/master/common/desktop-exports) to help ensure the snap can find needed files. 10 | 11 | ## How to use the desktop helpers 12 | 13 | Go to the documentation on [snapping graphical applications](https://forum.snapcraft.io/t/desktop-applications/13034) and follow the instructions for the GUI toolkit that your application uses. 14 | 15 | > ℹ️ We are currently in the process of moving most of the functionality of the desktop helpers to [Snapcraft Extensions](https://forum.snapcraft.io/t/snapcraft-extensions/13486). The extensions are much easier to use and contain many improvements, so it's advised to use an extension if one is available for the GUI toolkit that you use. 16 | 17 | ## Need help? 18 | 19 | Please feel free to ask questions in the [forum](https://forum.snapcraft.io) if you are having trouble. 20 | -------------------------------------------------------------------------------- /demos/gtk3/snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: gtk3-demo 2 | version: "3.18" 3 | summary: Gtk3 launcher demo 4 | description: | 5 | Use the gtk3 demo to show desktop launcher properties with all libraries included. 6 | grade: stable 7 | confinement: strict 8 | base: core18 9 | 10 | apps: 11 | gtk3-demo: 12 | command: bin/desktop-launch gtk3-demo 13 | plugs: 14 | - desktop 15 | - desktop-legacy 16 | - wayland 17 | - x11 18 | - unity7 19 | - gsettings # For desktop theme detection under Wayland session 20 | - home 21 | gsettings: 22 | command: bin/desktop-launch gsettings 23 | plugs: 24 | - gsettings 25 | 26 | parts: 27 | gtk3-demo: 28 | plugin: nil 29 | stage-packages: [gtk-3-examples, libglib2.0-bin] 30 | after: [desktop-gnome-platform] 31 | 32 | # This part installs the `desktop-launch` script which initialises desktop 33 | # features such as fonts, themes and the XDG environment. 34 | # 35 | # It is copied straight from the snapcraft desktop helpers project. Please 36 | # periodically check the source for updates and copy the changes. 37 | # https://github.com/ubuntu/snapcraft-desktop-helpers/blob/master/snapcraft.yaml 38 | # 39 | desktop-gnome-platform: 40 | source: https://github.com/ubuntu/snapcraft-desktop-helpers.git 41 | source-subdir: gtk 42 | plugin: make 43 | make-parameters: ["FLAVOR=gtk3"] 44 | build-packages: 45 | - gcc 46 | override-build: | 47 | snapcraftctl build 48 | mkdir -pv $SNAPCRAFT_PART_INSTALL/gnome-platform 49 | 50 | plugs: 51 | gnome-3-28-1804: 52 | interface: content 53 | target: $SNAP/gnome-platform 54 | default-provider: gnome-3-28-1804 55 | gtk-3-themes: 56 | interface: content 57 | target: $SNAP/data-dir/themes 58 | default-provider: gtk-common-themes 59 | icon-themes: 60 | interface: content 61 | target: $SNAP/data-dir/icons 62 | default-provider: gtk-common-themes 63 | sound-themes: 64 | interface: content 65 | target: $SNAP/data-dir/sounds 66 | default-provider: gtk-common-themes 67 | -------------------------------------------------------------------------------- /qt/launcher-specific: -------------------------------------------------------------------------------- 1 | ############################# 2 | # QT launcher specific part # 3 | ############################# 4 | 5 | # select qt version 6 | . $SNAP/flavor-select 7 | 8 | export QTCHOOSER_NO_GLOBAL_DIR=1 9 | if [ "$USE_qt5" = true ]; then 10 | # QT_SELECT not exported by ubuntu app platform runtime 11 | if [ -z "$QT_SELECT" ]; then 12 | export QT_SELECT=snappy-qt5 13 | fi 14 | else 15 | export QT_SELECT=snappy-qt4 16 | fi 17 | 18 | # Removes Qt warning: Could not find a location 19 | # of the system Compose files 20 | export QTCOMPOSE=$RUNTIME/usr/share/X11/locale 21 | 22 | # Qt Libs, Modules and helpers 23 | if [ "$USE_qt5" = true ]; then 24 | prepend_dir QT_PLUGIN_PATH $RUNTIME/usr/lib/$ARCH/qt5/plugins 25 | prepend_dir QML2_IMPORT_PATH $RUNTIME/usr/lib/$ARCH/qt5/qml 26 | prepend_dir QML2_IMPORT_PATH $RUNTIME/lib/$ARCH 27 | # Try to use qtubuntu-print plugin, if not found Qt will fallback to the first found (usually cups plugin) 28 | export QT_PRINTER_MODULE=qtubuntu-print 29 | if [ "$WITH_RUNTIME" = yes ]; then 30 | prepend_dir QML2_IMPORT_PATH $SNAP/usr/lib/$ARCH/qt5/qml 31 | prepend_dir QML2_IMPORT_PATH $SNAP/lib/$ARCH 32 | fi 33 | prepend_dir PATH $RUNTIME/usr/lib/$ARCH/qt5/bin 34 | 35 | if [ "$wayland_available" = true ]; then 36 | export QT_QPA_PLATFORM=wayland-egl 37 | # Does not hurt to specify these as well, just in case 38 | export GDK_BACKEND="wayland" 39 | export CLUTTER_BACKEND="wayland" 40 | else 41 | # Should check if a X11 $DISPLAY variable is set and accessible 42 | export QT_QPA_PLATFORM=xcb 43 | if ! [ -v QT_QPA_PLATFORMTHEME ] || [ -z "${QT_QPA_PLATFORMTHEME}" ]; then 44 | export QT_QPA_PLATFORMTHEME=appmenu-qt5 45 | fi 46 | fi 47 | 48 | else 49 | [ "$wayland_available" = true ] && echo "Warning: Qt4 does not support Wayland!" 50 | append_dir LD_LIBRARY_PATH $SNAP/usr/lib/$ARCH/qt4 51 | export QT_PLUGIN_PATH=$SNAP/usr/lib/$ARCH/qt4/plugins 52 | prepend_dir QML_IMPORT_PATH $SNAP/usr/lib/$ARCH/qt4/qml:$SNAP/lib/$ARCH 53 | prepend_dir PATH $SNAP/usr/lib/$ARCH/qt4/bin 54 | fi 55 | 56 | # Use GTK styling for running under the GNOME desktop 57 | append_dir GTK_PATH $RUNTIME/usr/lib/$ARCH/gtk-2.0 58 | 59 | # Fix locating the QtWebEngineProcess executable 60 | export QTWEBENGINEPROCESS_PATH=$RUNTIME/usr/lib/$ARCH/qt5/libexec/QtWebEngineProcess 61 | -------------------------------------------------------------------------------- /demos/qt5/snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: qt5-application 2 | version: "2" 3 | summary: Qt5 Application Example 4 | description: A simple text editor 5 | grade: stable 6 | confinement: strict 7 | base: core18 8 | icon: snap/gui/qt5-application.png 9 | 10 | apps: 11 | qt5-application: 12 | environment: 13 | # Use GTK3 cursor theme, icon theme and open/save file dialogs. 14 | QT_QPA_PLATFORMTHEME: gtk3 15 | command: desktop-launch application 16 | plugs: [unity7, home] 17 | 18 | parts: 19 | application: 20 | source: src/ 21 | plugin: qmake 22 | qt-version: qt5 23 | after: [desktop-qt5] 24 | 25 | # This part installs the qt5 dependencies and the `desktop-launch` script 26 | # which initialises desktop features such as fonts, themes and the XDG 27 | # environment. 28 | # 29 | # It is copied straight from the snapcraft desktop helpers project. Please 30 | # periodically check the source for updates and copy the changes. 31 | # https://github.com/ubuntu/snapcraft-desktop-helpers/blob/master/snapcraft.yaml 32 | # 33 | desktop-qt5: 34 | source: https://github.com/ubuntu/snapcraft-desktop-helpers.git 35 | source-subdir: qt 36 | plugin: make 37 | make-parameters: ["FLAVOR=qt5"] 38 | build-packages: 39 | - build-essential 40 | - qtbase5-dev 41 | - dpkg-dev 42 | stage-packages: 43 | - libxkbcommon0 44 | - ttf-ubuntu-font-family 45 | - dmz-cursor-theme 46 | - light-themes 47 | - adwaita-icon-theme 48 | - gnome-themes-standard 49 | - shared-mime-info 50 | - libqt5gui5 51 | - libgdk-pixbuf2.0-0 52 | - libqt5svg5 # for loading icon themes which are svg 53 | - try: [appmenu-qt5] # not available on core18 54 | - locales-all 55 | - xdg-user-dirs 56 | - fcitx-frontend-qt5 57 | 58 | qt5-gtk-platform: 59 | plugin: nil 60 | stage-packages: 61 | - qt5-gtk-platformtheme 62 | 63 | plugs: 64 | # Support for common GTK themes 65 | # https://forum.snapcraft.io/t/how-to-use-the-system-gtk-theme-via-the-gtk-common-themes-snap/6235 66 | gsettings: 67 | gtk-3-themes: 68 | interface: content 69 | target: $SNAP/data-dir/themes 70 | default-provider: gtk-common-themes 71 | icon-themes: 72 | interface: content 73 | target: $SNAP/data-dir/icons 74 | default-provider: gtk-common-themes 75 | sound-themes: 76 | interface: content 77 | target: $SNAP/data-dir/sounds 78 | default-provider: gtk-common-themes 79 | -------------------------------------------------------------------------------- /common/init: -------------------------------------------------------------------------------- 1 | ################# 2 | # Launcher init # 3 | ################# 4 | 5 | START=$(date +%s.%N) 6 | 7 | declare -A PIDS 8 | function async_exec() { 9 | $@ & 10 | PIDS[$!]=$@ 11 | } 12 | function wait_for_async_execs() { 13 | for i in ${!PIDS[@]} 14 | do 15 | wait $i && continue || echo "ERROR: ${PIDS[$i]} exited abnormally with status $?" 16 | done 17 | } 18 | 19 | # ensure_dir_exists calls `mkdir -p` if the given path is not a directory. 20 | # This speeds up execution time by avoiding unnecessary calls to mkdir. 21 | # 22 | # Usage: ensure_dir_exists []... 23 | # 24 | function ensure_dir_exists() { 25 | [ -d "$1" ] || mkdir -p "$@" 26 | } 27 | 28 | # On Fedora $SNAP is under /var and there is some magic to map it to /snap. 29 | # # We need to handle that case and reset $SNAP 30 | SNAP=`echo $SNAP | sed -e "s|/var/lib/snapd||g"` 31 | 32 | needs_update=true 33 | 34 | . $SNAP_USER_DATA/.last_revision 2>/dev/null || true 35 | if [ "$SNAP_DESKTOP_LAST_REVISION" = "$SNAP_REVISION" ]; then 36 | needs_update=false 37 | fi 38 | 39 | # Set $REALHOME to the users real home directory 40 | REALHOME=`getent passwd $UID | cut -d ':' -f 6` 41 | 42 | # Set config folder to local path 43 | export XDG_CONFIG_HOME=$SNAP_USER_DATA/.config 44 | ensure_dir_exists $XDG_CONFIG_HOME -m 700 45 | 46 | # If the user has modified their user-dirs settings, force an update 47 | if [[ -f "$XDG_CONFIG_HOME/user-dirs.dirs.md5sum" ]]; then 48 | if [[ "$(md5sum < "$REALHOME/.config/user-dirs.dirs")" != "$(cat "$XDG_CONFIG_HOME/user-dirs.dirs.md5sum")" || 49 | ( -f "$XDG_CONFIG_HOME/user-dirs.locale.md5sum" && 50 | "$(md5sum < "$REALHOME/.config/user-dirs.locale")" != "$(cat "$XDG_CONFIG_HOME/user-dirs.locale.md5sum")" ) ]]; then 51 | needs_update=true 52 | fi 53 | else 54 | needs_update=true 55 | fi 56 | 57 | if [ "$SNAP_ARCH" == "amd64" ]; then 58 | ARCH="x86_64-linux-gnu" 59 | elif [ "$SNAP_ARCH" == "armhf" ]; then 60 | ARCH="arm-linux-gnueabihf" 61 | elif [ "$SNAP_ARCH" == "arm64" ]; then 62 | ARCH="aarch64-linux-gnu" 63 | elif [ "$SNAP_ARCH" == "ppc64el" ]; then 64 | ARCH="powerpc64le-linux-gnu" 65 | else 66 | ARCH="$SNAP_ARCH-linux-gnu" 67 | fi 68 | 69 | export SNAP_LAUNCHER_ARCH_TRIPLET=$ARCH 70 | 71 | # Don't LD_PRELOAD bindtextdomain for classic snaps 72 | if ! grep -qs "^\s*confinement:\s*classic\s*" $SNAP/meta/snap.yaml; then 73 | if [ -f $SNAP/lib/bindtextdomain.so ]; then 74 | export LD_PRELOAD=$LD_PRELOAD:$SNAP/lib/bindtextdomain.so 75 | fi 76 | fi 77 | -------------------------------------------------------------------------------- /demos/qt5/src/main.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2015 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the examples of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:BSD$ 9 | ** You may use this file under the terms of the BSD license as follows: 10 | ** 11 | ** "Redistribution and use in source and binary forms, with or without 12 | ** modification, are permitted provided that the following conditions are 13 | ** met: 14 | ** * Redistributions of source code must retain the above copyright 15 | ** notice, this list of conditions and the following disclaimer. 16 | ** * Redistributions in binary form must reproduce the above copyright 17 | ** notice, this list of conditions and the following disclaimer in 18 | ** the documentation and/or other materials provided with the 19 | ** distribution. 20 | ** * Neither the name of The Qt Company Ltd nor the names of its 21 | ** contributors may be used to endorse or promote products derived 22 | ** from this software without specific prior written permission. 23 | ** 24 | ** 25 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 36 | ** 37 | ** $QT_END_LICENSE$ 38 | ** 39 | ****************************************************************************/ 40 | 41 | //! [0] 42 | #include 43 | 44 | #include "mainwindow.h" 45 | 46 | int main(int argc, char *argv[]) 47 | { 48 | Q_INIT_RESOURCE(application); 49 | 50 | QApplication app(argc, argv); 51 | app.setOrganizationName("QtProject"); 52 | app.setApplicationName("Application Example"); 53 | MainWindow mainWin; 54 | mainWin.show(); 55 | return app.exec(); 56 | } 57 | //! [0] 58 | -------------------------------------------------------------------------------- /demos/qt5/src/mainwindow.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2015 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the examples of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:BSD$ 9 | ** You may use this file under the terms of the BSD license as follows: 10 | ** 11 | ** "Redistribution and use in source and binary forms, with or without 12 | ** modification, are permitted provided that the following conditions are 13 | ** met: 14 | ** * Redistributions of source code must retain the above copyright 15 | ** notice, this list of conditions and the following disclaimer. 16 | ** * Redistributions in binary form must reproduce the above copyright 17 | ** notice, this list of conditions and the following disclaimer in 18 | ** the documentation and/or other materials provided with the 19 | ** distribution. 20 | ** * Neither the name of The Qt Company Ltd nor the names of its 21 | ** contributors may be used to endorse or promote products derived 22 | ** from this software without specific prior written permission. 23 | ** 24 | ** 25 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 36 | ** 37 | ** $QT_END_LICENSE$ 38 | ** 39 | ****************************************************************************/ 40 | 41 | #ifndef MAINWINDOW_H 42 | #define MAINWINDOW_H 43 | 44 | #include 45 | 46 | QT_BEGIN_NAMESPACE 47 | class QAction; 48 | class QMenu; 49 | class QPlainTextEdit; 50 | QT_END_NAMESPACE 51 | 52 | //! [0] 53 | class MainWindow : public QMainWindow 54 | { 55 | Q_OBJECT 56 | 57 | public: 58 | MainWindow(); 59 | 60 | protected: 61 | void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE; 62 | 63 | private slots: 64 | void newFile(); 65 | void open(); 66 | bool save(); 67 | bool saveAs(); 68 | void about(); 69 | void documentWasModified(); 70 | 71 | private: 72 | void createActions(); 73 | void createMenus(); 74 | void createToolBars(); 75 | void createStatusBar(); 76 | void readSettings(); 77 | void writeSettings(); 78 | bool maybeSave(); 79 | void loadFile(const QString &fileName); 80 | bool saveFile(const QString &fileName); 81 | void setCurrentFile(const QString &fileName); 82 | QString strippedName(const QString &fullFileName); 83 | 84 | QPlainTextEdit *textEdit; 85 | QString curFile; 86 | 87 | QMenu *fileMenu; 88 | QMenu *editMenu; 89 | QMenu *helpMenu; 90 | QToolBar *fileToolBar; 91 | QToolBar *editToolBar; 92 | QAction *newAct; 93 | QAction *openAct; 94 | QAction *saveAct; 95 | QAction *saveAsAct; 96 | QAction *exitAct; 97 | QAction *cutAct; 98 | QAction *copyAct; 99 | QAction *pasteAct; 100 | QAction *aboutAct; 101 | QAction *aboutQtAct; 102 | }; 103 | //! [0] 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /src/bindtextdomain.c: -------------------------------------------------------------------------------- 1 | /* gcc -Wall -O2 -o bindtextdomain.so -fPIC -shared bindtextdomain.c -ldl */ 2 | 3 | #define _GNU_SOURCE 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static void die (const char *msg) 14 | { 15 | fprintf (stderr, "can't preload: %s\n", msg); 16 | exit (EXIT_FAILURE); 17 | } 18 | 19 | typedef char * (*BindTextDomainFunc) (const char *a, 20 | const char *b); 21 | 22 | static BindTextDomainFunc r_bindtextdomain = NULL; 23 | 24 | char *bindtextdomain(const char *domainname, const char *dirname) 25 | { 26 | char *snap = NULL; 27 | char *snap_path = NULL; 28 | char *snap_locale_path = NULL; 29 | DIR *dir = NULL; 30 | struct dirent *ent = NULL; 31 | char *ret = NULL; 32 | 33 | if (r_bindtextdomain == 0 && !(r_bindtextdomain = 34 | (BindTextDomainFunc) dlsym (RTLD_NEXT, "bindtextdomain"))) 35 | die ("can't find symbol \"bindtextdomain\""); 36 | 37 | if (dirname == NULL || dirname[0] != '/') 38 | goto orig; 39 | 40 | snap = getenv ("SNAP"); 41 | 42 | if (snap == NULL || strcmp (snap, "") == 0) 43 | goto orig; 44 | 45 | char * paths[] = { 46 | "share/locale", 47 | "gnome-platform/usr/share/locale", 48 | "usr/share/locale", 49 | "usr/share/locale-langpack", 50 | NULL 51 | }; 52 | for(int i = 0; paths[i] != NULL; i++) 53 | { 54 | if (asprintf (&snap_path, "%s/%s", snap, paths[i]) < 0) 55 | continue; 56 | 57 | if (access (snap_path, F_OK) < 0) 58 | continue; 59 | 60 | /* 61 | * if the mo file exists for one language we assume it exists for them 62 | * all, or at least that we're not going to find it anywhere else. we 63 | * don't know at this point what locale the application is actually 64 | * going to use, so we can't look in any particular directory. 65 | */ 66 | dir = opendir (snap_path); 67 | if (dir == NULL) 68 | continue; 69 | 70 | while ((ent = readdir (dir)) != NULL) { 71 | if (ent->d_name[0] == '.') 72 | continue; 73 | 74 | if (asprintf (&snap_locale_path, 75 | "%s/%s/LC_MESSAGES/%s.mo", 76 | snap_path, 77 | ent->d_name, 78 | domainname) < 0) 79 | continue; 80 | 81 | /* snap_locale_path has been allocated if we made it 82 | * this far, be sure it's freed before any goto 83 | * or continue 84 | */ 85 | 86 | if (access (snap_locale_path, F_OK) == 0) { 87 | closedir (dir); 88 | free (snap_locale_path); 89 | snap_locale_path = NULL; 90 | goto ok; 91 | } else { 92 | free (snap_locale_path); 93 | snap_locale_path = NULL; 94 | continue; 95 | } 96 | } 97 | 98 | closedir (dir); 99 | free (snap_path); 100 | snap_path = NULL; 101 | free (snap_locale_path); 102 | snap_locale_path = NULL; 103 | } 104 | /* 105 | * we fell out of the loop, so we'll go to orig regardless - no need to 106 | * check for errors 107 | */ 108 | goto orig; 109 | 110 | ok: 111 | ret = r_bindtextdomain (domainname, snap_path); 112 | goto out; 113 | orig: 114 | ret = r_bindtextdomain (domainname, dirname); 115 | goto out; 116 | out: 117 | free (snap_path); 118 | snap_path = NULL; 119 | return ret; 120 | } 121 | -------------------------------------------------------------------------------- /snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: desktop-helpers 2 | version: 1 3 | summary: Various technology desktop helpers for snapcraft 4 | description: | 5 | Note: We are currently in the process of moving most of the functionality of the 6 | desktop helpers to Snapcraft Extensions. The extensions are much easier to use 7 | and contain many improvements. Please read the documentation on snapping 8 | desktop applications to see what the best way is to create a snap for 9 | your application: https://forum.snapcraft.io/t/desktop-applications/13034 10 | . 11 | Helpers for gtk2, gtk3, qt4 and qt5 or gnome-platform and glib minimal launchers. 12 | It brings the necessary code and exports for binding and using those 13 | desktop technologies in a relocatable fashion, enabling binding with 14 | global desktop theme, icon theme, image caching, fonts, mimetype handlers 15 | application global menu and gsettings integration. 16 | It also brings basic ubuntu dependency packages. 17 | . 18 | Usage: 19 | 1. copy the part of the toolkit you need to your snapcraft.yaml file: 20 | - gtk2, gtk3, qt4 and qt5 corresponds to their respective toolkit 21 | main dependencies and default choices. 22 | - gnome-platform is similar to gtk3 without the extra depends, it's 23 | meant to be used with the gnome platform which already includes those. 24 | - glib-only enables to compile mime types and gsettings infos. If you 25 | added your own graphical drivers, it will link them as well. 26 | 2. prepend your command with "desktop-launch", like: 27 | commands: "desktop-launch foo" if foo is in $PATH. You can as well 28 | specify: "desktop-launch $SNAP/foo". 29 | 3. add needed plugs to your application: 30 | - for graphical application: 31 | plugs: [x11] or: 32 | [unity7] for appmenu, input methods, a11y integration. And/or: 33 | [desktop] for GNOME Shell/Plasma 34 | [wayland] for Wayland compositors 35 | See https://forum.snapcraft.io/t/the-desktop-interfaces/2042 36 | for details 37 | - if your application needs hw acceleration: 38 | plugs: [opengl] 39 | - for sound playback: 40 | plugs: [audio-playback] 41 | - for sound playback and recording: 42 | plugs: [audio-playback, audio-record] 43 | - accessing to user's home directory: 44 | plugs: [home] 45 | - read/write to gsettings: 46 | plugs: [gsettings] 47 | - if using "desktop" and need a11y or other input methods: 48 | plugs: [desktop-legacy] 49 | - use of the shared platform snap content, first define the plug: 50 | plugs: 51 | gnome-3-26-1604: 52 | interface: content 53 | target: gnome-platform 54 | default-provider: gnome-3-26-1604:gnome-3-26-1604 55 | and then make your apps use it: 56 | plugs: [gnome-3-26-1604] 57 | Note that an empty "gnome-platform" directory will be created for you 58 | in your snap. 59 | 60 | confinement: strict 61 | 62 | parts: 63 | desktop: 64 | plugin: nil 65 | gtk2: 66 | source: . 67 | source-subdir: gtk 68 | plugin: make 69 | make-parameters: ["FLAVOR=gtk2"] 70 | build-packages: 71 | - libgtk2.0-dev 72 | stage-packages: 73 | - libxkbcommon0 # XKB_CONFIG_ROOT 74 | - ttf-ubuntu-font-family 75 | - dmz-cursor-theme 76 | - light-themes 77 | - adwaita-icon-theme 78 | - gnome-themes-standard 79 | - shared-mime-info 80 | - libgtk2.0-0 81 | - libgdk-pixbuf2.0-0 82 | - libglib2.0-bin 83 | - libgtk2.0-bin 84 | - unity-gtk2-module 85 | - libappindicator1 86 | - locales-all 87 | - ibus-gtk 88 | - libibus-1.0-5 89 | gtk3: 90 | source: . 91 | source-subdir: gtk 92 | plugin: make 93 | make-parameters: ["FLAVOR=gtk3"] 94 | build-packages: 95 | - libgtk-3-dev 96 | stage-packages: 97 | - libxkbcommon0 # XKB_CONFIG_ROOT 98 | - ttf-ubuntu-font-family 99 | - dmz-cursor-theme 100 | - light-themes 101 | - adwaita-icon-theme 102 | - gnome-themes-standard 103 | - shared-mime-info 104 | - libgtk-3-0 105 | - libgdk-pixbuf2.0-0 106 | - libglib2.0-bin 107 | - libgtk-3-bin 108 | - unity-gtk3-module 109 | - libappindicator3-1 110 | - locales-all 111 | - xdg-user-dirs 112 | - ibus-gtk3 113 | - libibus-1.0-5 114 | qt4: 115 | source: . 116 | source-subdir: qt 117 | plugin: make 118 | make-parameters: ["FLAVOR=qt4"] 119 | build-packages: 120 | - libqt4-dev 121 | - dpkg-dev 122 | stage-packages: 123 | - libxkbcommon0 124 | - ttf-ubuntu-font-family 125 | - dmz-cursor-theme 126 | - light-themes 127 | - adwaita-icon-theme 128 | - gnome-themes-standard 129 | - shared-mime-info 130 | - libqtgui4 131 | - libgdk-pixbuf2.0-0 132 | - libqt4-svg # for loading icon themes which are svg 133 | - appmenu-qt 134 | - locales-all 135 | - sni-qt 136 | qt5: 137 | source: . 138 | source-subdir: qt 139 | plugin: make 140 | make-parameters: ["FLAVOR=qt5"] 141 | build-packages: 142 | - qtbase5-dev 143 | - dpkg-dev 144 | stage-packages: 145 | - libxkbcommon0 146 | - ttf-ubuntu-font-family 147 | - dmz-cursor-theme 148 | - light-themes 149 | - adwaita-icon-theme 150 | - gnome-themes-standard 151 | - shared-mime-info 152 | - libqt5gui5 153 | - libgdk-pixbuf2.0-0 154 | - libqt5svg5 # for loading icon themes which are svg 155 | - try: [appmenu-qt5] # not available on core18 156 | - locales-all 157 | glib-only: 158 | source: . 159 | source-subdir: glib-only 160 | plugin: make 161 | build-packages: 162 | - libglib2.0-dev 163 | stage-packages: 164 | - libglib2.0-bin 165 | desktop-gtk2: 166 | source: . 167 | source-subdir: gtk 168 | plugin: make 169 | make-parameters: ["FLAVOR=gtk2"] 170 | build-packages: 171 | - build-essential 172 | - libgtk2.0-dev 173 | stage-packages: 174 | - libxkbcommon0 # XKB_CONFIG_ROOT 175 | - ttf-ubuntu-font-family 176 | - dmz-cursor-theme 177 | - light-themes 178 | - adwaita-icon-theme 179 | - gnome-themes-standard 180 | - shared-mime-info 181 | - libgtk2.0-0 182 | - libgdk-pixbuf2.0-0 183 | - libglib2.0-bin 184 | - libgtk2.0-bin 185 | - unity-gtk2-module 186 | - locales-all 187 | - libappindicator1 188 | - xdg-user-dirs 189 | - ibus-gtk 190 | - libibus-1.0-5 191 | desktop-gtk3: 192 | source: . 193 | source-subdir: gtk 194 | plugin: make 195 | make-parameters: ["FLAVOR=gtk3"] 196 | build-packages: 197 | - build-essential 198 | - libgtk-3-dev 199 | stage-packages: 200 | - libxkbcommon0 # XKB_CONFIG_ROOT 201 | - ttf-ubuntu-font-family 202 | - dmz-cursor-theme 203 | - light-themes 204 | - adwaita-icon-theme 205 | - gnome-themes-standard 206 | - shared-mime-info 207 | - libgtk-3-0 208 | - libgdk-pixbuf2.0-0 209 | - libglib2.0-bin 210 | - libgtk-3-bin 211 | - unity-gtk3-module 212 | - libappindicator3-1 213 | - locales-all 214 | - xdg-user-dirs 215 | - ibus-gtk3 216 | - libibus-1.0-5 217 | - fcitx-frontend-gtk3 218 | desktop-qt4: 219 | source: . 220 | source-subdir: qt 221 | plugin: make 222 | make-parameters: ["FLAVOR=qt4"] 223 | build-packages: 224 | - build-essential 225 | - libqt4-dev 226 | - dpkg-dev 227 | stage-packages: 228 | - libxkbcommon0 229 | - ttf-ubuntu-font-family 230 | - dmz-cursor-theme 231 | - light-themes 232 | - adwaita-icon-theme 233 | - gnome-themes-standard 234 | - shared-mime-info 235 | - libqtgui4 236 | - libgdk-pixbuf2.0-0 237 | - libqt4-svg # for loading icon themes which are svg 238 | - appmenu-qt 239 | - locales-all 240 | - sni-qt 241 | - xdg-user-dirs 242 | desktop-qt5: 243 | source: . 244 | source-subdir: qt 245 | plugin: make 246 | make-parameters: ["FLAVOR=qt5"] 247 | build-packages: 248 | - build-essential 249 | - qtbase5-dev 250 | - dpkg-dev 251 | stage-packages: 252 | - libxkbcommon0 253 | - ttf-ubuntu-font-family 254 | - dmz-cursor-theme 255 | - light-themes 256 | - adwaita-icon-theme 257 | - gnome-themes-standard 258 | - shared-mime-info 259 | - libqt5gui5 260 | - libgdk-pixbuf2.0-0 261 | - libqt5svg5 # for loading icon themes which are svg 262 | - try: [appmenu-qt5] # not available on core18 263 | - locales-all 264 | - xdg-user-dirs 265 | - fcitx-frontend-qt5 266 | desktop-glib-only: 267 | source: . 268 | source-subdir: glib-only 269 | plugin: make 270 | build-packages: 271 | - libglib2.0-dev 272 | stage-packages: 273 | - libglib2.0-bin 274 | desktop-gnome-platform: 275 | source: . 276 | source-subdir: gtk 277 | plugin: make 278 | make-parameters: ["FLAVOR=gtk3"] 279 | build-packages: 280 | - gcc 281 | override-build: | 282 | snapcraftctl build 283 | mkdir -pv $SNAPCRAFT_PART_INSTALL/gnome-platform 284 | -------------------------------------------------------------------------------- /demos/qt5/src/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2015 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the examples of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:BSD$ 9 | ** You may use this file under the terms of the BSD license as follows: 10 | ** 11 | ** "Redistribution and use in source and binary forms, with or without 12 | ** modification, are permitted provided that the following conditions are 13 | ** met: 14 | ** * Redistributions of source code must retain the above copyright 15 | ** notice, this list of conditions and the following disclaimer. 16 | ** * Redistributions in binary form must reproduce the above copyright 17 | ** notice, this list of conditions and the following disclaimer in 18 | ** the documentation and/or other materials provided with the 19 | ** distribution. 20 | ** * Neither the name of The Qt Company Ltd nor the names of its 21 | ** contributors may be used to endorse or promote products derived 22 | ** from this software without specific prior written permission. 23 | ** 24 | ** 25 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 36 | ** 37 | ** $QT_END_LICENSE$ 38 | ** 39 | ****************************************************************************/ 40 | 41 | //! [0] 42 | #include 43 | 44 | #include "mainwindow.h" 45 | //! [0] 46 | 47 | //! [1] 48 | MainWindow::MainWindow() 49 | //! [1] //! [2] 50 | { 51 | textEdit = new QPlainTextEdit; 52 | setCentralWidget(textEdit); 53 | 54 | createActions(); 55 | createMenus(); 56 | createToolBars(); 57 | createStatusBar(); 58 | 59 | readSettings(); 60 | 61 | connect(textEdit->document(), SIGNAL(contentsChanged()), 62 | this, SLOT(documentWasModified())); 63 | 64 | setCurrentFile(""); 65 | setUnifiedTitleAndToolBarOnMac(true); 66 | } 67 | //! [2] 68 | 69 | //! [3] 70 | void MainWindow::closeEvent(QCloseEvent *event) 71 | //! [3] //! [4] 72 | { 73 | if (maybeSave()) { 74 | writeSettings(); 75 | event->accept(); 76 | } else { 77 | event->ignore(); 78 | } 79 | } 80 | //! [4] 81 | 82 | //! [5] 83 | void MainWindow::newFile() 84 | //! [5] //! [6] 85 | { 86 | if (maybeSave()) { 87 | textEdit->clear(); 88 | setCurrentFile(""); 89 | } 90 | } 91 | //! [6] 92 | 93 | //! [7] 94 | void MainWindow::open() 95 | //! [7] //! [8] 96 | { 97 | if (maybeSave()) { 98 | QString fileName = QFileDialog::getOpenFileName(this); 99 | if (!fileName.isEmpty()) 100 | loadFile(fileName); 101 | } 102 | } 103 | //! [8] 104 | 105 | //! [9] 106 | bool MainWindow::save() 107 | //! [9] //! [10] 108 | { 109 | if (curFile.isEmpty()) { 110 | return saveAs(); 111 | } else { 112 | return saveFile(curFile); 113 | } 114 | } 115 | //! [10] 116 | 117 | //! [11] 118 | bool MainWindow::saveAs() 119 | //! [11] //! [12] 120 | { 121 | QFileDialog dialog(this); 122 | dialog.setWindowModality(Qt::WindowModal); 123 | dialog.setAcceptMode(QFileDialog::AcceptSave); 124 | QStringList files; 125 | if (dialog.exec()) 126 | files = dialog.selectedFiles(); 127 | else 128 | return false; 129 | 130 | return saveFile(files.at(0)); 131 | } 132 | //! [12] 133 | 134 | //! [13] 135 | void MainWindow::about() 136 | //! [13] //! [14] 137 | { 138 | QMessageBox::about(this, tr("About Application"), 139 | tr("The Application example demonstrates how to " 140 | "write modern GUI applications using Qt, with a menu bar, " 141 | "toolbars, and a status bar.")); 142 | } 143 | //! [14] 144 | 145 | //! [15] 146 | void MainWindow::documentWasModified() 147 | //! [15] //! [16] 148 | { 149 | setWindowModified(textEdit->document()->isModified()); 150 | } 151 | //! [16] 152 | 153 | //! [17] 154 | void MainWindow::createActions() 155 | //! [17] //! [18] 156 | { 157 | newAct = new QAction(QIcon(":/images/new.png"), tr("&New"), this); 158 | newAct->setShortcuts(QKeySequence::New); 159 | newAct->setStatusTip(tr("Create a new file")); 160 | connect(newAct, SIGNAL(triggered()), this, SLOT(newFile())); 161 | 162 | //! [19] 163 | openAct = new QAction(QIcon(":/images/open.png"), tr("&Open..."), this); 164 | openAct->setShortcuts(QKeySequence::Open); 165 | openAct->setStatusTip(tr("Open an existing file")); 166 | connect(openAct, SIGNAL(triggered()), this, SLOT(open())); 167 | //! [18] //! [19] 168 | 169 | saveAct = new QAction(QIcon(":/images/save.png"), tr("&Save"), this); 170 | saveAct->setShortcuts(QKeySequence::Save); 171 | saveAct->setStatusTip(tr("Save the document to disk")); 172 | connect(saveAct, SIGNAL(triggered()), this, SLOT(save())); 173 | 174 | saveAsAct = new QAction(tr("Save &As..."), this); 175 | saveAsAct->setShortcuts(QKeySequence::SaveAs); 176 | saveAsAct->setStatusTip(tr("Save the document under a new name")); 177 | connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs())); 178 | 179 | //! [20] 180 | exitAct = new QAction(tr("E&xit"), this); 181 | exitAct->setShortcuts(QKeySequence::Quit); 182 | //! [20] 183 | exitAct->setStatusTip(tr("Exit the application")); 184 | connect(exitAct, SIGNAL(triggered()), this, SLOT(close())); 185 | 186 | //! [21] 187 | cutAct = new QAction(QIcon(":/images/cut.png"), tr("Cu&t"), this); 188 | //! [21] 189 | cutAct->setShortcuts(QKeySequence::Cut); 190 | cutAct->setStatusTip(tr("Cut the current selection's contents to the " 191 | "clipboard")); 192 | connect(cutAct, SIGNAL(triggered()), textEdit, SLOT(cut())); 193 | 194 | copyAct = new QAction(QIcon(":/images/copy.png"), tr("&Copy"), this); 195 | copyAct->setShortcuts(QKeySequence::Copy); 196 | copyAct->setStatusTip(tr("Copy the current selection's contents to the " 197 | "clipboard")); 198 | connect(copyAct, SIGNAL(triggered()), textEdit, SLOT(copy())); 199 | 200 | pasteAct = new QAction(QIcon(":/images/paste.png"), tr("&Paste"), this); 201 | pasteAct->setShortcuts(QKeySequence::Paste); 202 | pasteAct->setStatusTip(tr("Paste the clipboard's contents into the current " 203 | "selection")); 204 | connect(pasteAct, SIGNAL(triggered()), textEdit, SLOT(paste())); 205 | 206 | aboutAct = new QAction(tr("&About"), this); 207 | aboutAct->setStatusTip(tr("Show the application's About box")); 208 | connect(aboutAct, SIGNAL(triggered()), this, SLOT(about())); 209 | 210 | //! [22] 211 | aboutQtAct = new QAction(tr("About &Qt"), this); 212 | aboutQtAct->setStatusTip(tr("Show the Qt library's About box")); 213 | connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt())); 214 | //! [22] 215 | 216 | //! [23] 217 | cutAct->setEnabled(false); 218 | //! [23] //! [24] 219 | copyAct->setEnabled(false); 220 | connect(textEdit, SIGNAL(copyAvailable(bool)), 221 | cutAct, SLOT(setEnabled(bool))); 222 | connect(textEdit, SIGNAL(copyAvailable(bool)), 223 | copyAct, SLOT(setEnabled(bool))); 224 | } 225 | //! [24] 226 | 227 | //! [25] //! [26] 228 | void MainWindow::createMenus() 229 | //! [25] //! [27] 230 | { 231 | fileMenu = menuBar()->addMenu(tr("&File")); 232 | fileMenu->addAction(newAct); 233 | //! [28] 234 | fileMenu->addAction(openAct); 235 | //! [28] 236 | fileMenu->addAction(saveAct); 237 | //! [26] 238 | fileMenu->addAction(saveAsAct); 239 | fileMenu->addSeparator(); 240 | fileMenu->addAction(exitAct); 241 | 242 | editMenu = menuBar()->addMenu(tr("&Edit")); 243 | editMenu->addAction(cutAct); 244 | editMenu->addAction(copyAct); 245 | editMenu->addAction(pasteAct); 246 | 247 | menuBar()->addSeparator(); 248 | 249 | helpMenu = menuBar()->addMenu(tr("&Help")); 250 | helpMenu->addAction(aboutAct); 251 | helpMenu->addAction(aboutQtAct); 252 | } 253 | //! [27] 254 | 255 | //! [29] //! [30] 256 | void MainWindow::createToolBars() 257 | { 258 | fileToolBar = addToolBar(tr("File")); 259 | fileToolBar->addAction(newAct); 260 | //! [29] //! [31] 261 | fileToolBar->addAction(openAct); 262 | //! [31] 263 | fileToolBar->addAction(saveAct); 264 | 265 | editToolBar = addToolBar(tr("Edit")); 266 | editToolBar->addAction(cutAct); 267 | editToolBar->addAction(copyAct); 268 | editToolBar->addAction(pasteAct); 269 | } 270 | //! [30] 271 | 272 | //! [32] 273 | void MainWindow::createStatusBar() 274 | //! [32] //! [33] 275 | { 276 | statusBar()->showMessage(tr("Ready")); 277 | } 278 | //! [33] 279 | 280 | //! [34] //! [35] 281 | void MainWindow::readSettings() 282 | //! [34] //! [36] 283 | { 284 | QSettings settings("QtProject", "Application Example"); 285 | QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint(); 286 | QSize size = settings.value("size", QSize(400, 400)).toSize(); 287 | resize(size); 288 | move(pos); 289 | } 290 | //! [35] //! [36] 291 | 292 | //! [37] //! [38] 293 | void MainWindow::writeSettings() 294 | //! [37] //! [39] 295 | { 296 | QSettings settings("QtProject", "Application Example"); 297 | settings.setValue("pos", pos()); 298 | settings.setValue("size", size()); 299 | } 300 | //! [38] //! [39] 301 | 302 | //! [40] 303 | bool MainWindow::maybeSave() 304 | //! [40] //! [41] 305 | { 306 | if (textEdit->document()->isModified()) { 307 | QMessageBox::StandardButton ret; 308 | ret = QMessageBox::warning(this, tr("Application"), 309 | tr("The document has been modified.\n" 310 | "Do you want to save your changes?"), 311 | QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); 312 | if (ret == QMessageBox::Save) 313 | return save(); 314 | else if (ret == QMessageBox::Cancel) 315 | return false; 316 | } 317 | return true; 318 | } 319 | //! [41] 320 | 321 | //! [42] 322 | void MainWindow::loadFile(const QString &fileName) 323 | //! [42] //! [43] 324 | { 325 | QFile file(fileName); 326 | if (!file.open(QFile::ReadOnly | QFile::Text)) { 327 | QMessageBox::warning(this, tr("Application"), 328 | tr("Cannot read file %1:\n%2.") 329 | .arg(fileName) 330 | .arg(file.errorString())); 331 | return; 332 | } 333 | 334 | QTextStream in(&file); 335 | #ifndef QT_NO_CURSOR 336 | QApplication::setOverrideCursor(Qt::WaitCursor); 337 | #endif 338 | textEdit->setPlainText(in.readAll()); 339 | #ifndef QT_NO_CURSOR 340 | QApplication::restoreOverrideCursor(); 341 | #endif 342 | 343 | setCurrentFile(fileName); 344 | statusBar()->showMessage(tr("File loaded"), 2000); 345 | } 346 | //! [43] 347 | 348 | //! [44] 349 | bool MainWindow::saveFile(const QString &fileName) 350 | //! [44] //! [45] 351 | { 352 | QFile file(fileName); 353 | if (!file.open(QFile::WriteOnly | QFile::Text)) { 354 | QMessageBox::warning(this, tr("Application"), 355 | tr("Cannot write file %1:\n%2.") 356 | .arg(fileName) 357 | .arg(file.errorString())); 358 | return false; 359 | } 360 | 361 | QTextStream out(&file); 362 | #ifndef QT_NO_CURSOR 363 | QApplication::setOverrideCursor(Qt::WaitCursor); 364 | #endif 365 | out << textEdit->toPlainText(); 366 | #ifndef QT_NO_CURSOR 367 | QApplication::restoreOverrideCursor(); 368 | #endif 369 | 370 | setCurrentFile(fileName); 371 | statusBar()->showMessage(tr("File saved"), 2000); 372 | return true; 373 | } 374 | //! [45] 375 | 376 | //! [46] 377 | void MainWindow::setCurrentFile(const QString &fileName) 378 | //! [46] //! [47] 379 | { 380 | curFile = fileName; 381 | textEdit->document()->setModified(false); 382 | setWindowModified(false); 383 | 384 | QString shownName = curFile; 385 | if (curFile.isEmpty()) 386 | shownName = "untitled.txt"; 387 | setWindowFilePath(shownName); 388 | } 389 | //! [47] 390 | 391 | //! [48] 392 | QString MainWindow::strippedName(const QString &fullFileName) 393 | //! [48] //! [49] 394 | { 395 | return QFileInfo(fullFileName).fileName(); 396 | } 397 | //! [49] 398 | -------------------------------------------------------------------------------- /common/desktop-exports: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # Launcher common exports for any desktop app # 3 | ############################################### 4 | 5 | function prepend_dir() { 6 | local var="$1" 7 | local dir="$2" 8 | if [ -d "$dir" ]; then 9 | eval "export $var=\"\$dir\${$var:+:\$$var}\"" 10 | fi 11 | } 12 | 13 | function append_dir() { 14 | local var="$1" 15 | local dir="$2" 16 | if [ -d "$dir" ]; then 17 | eval "export $var=\"\${$var:+\$$var:}\$dir\"" 18 | fi 19 | } 20 | 21 | function can_open_file() { 22 | return `head -c0 "$1" &> /dev/null`; 23 | } 24 | 25 | function update_xdg_dirs_values() { 26 | local save_initial_values=false 27 | local XDG_DIRS="DOCUMENTS DESKTOP DOWNLOAD MUSIC PICTURES VIDEOS PUBLICSHARE TEMPLATES" 28 | unset XDG_SPECIAL_DIRS_PATHS 29 | 30 | if [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/user-dirs.dirs" ]; then 31 | source "${XDG_CONFIG_HOME:-$HOME/.config}/user-dirs.dirs" 32 | fi 33 | 34 | if [ -z ${XDG_SPECIAL_DIRS+x} ]; then 35 | save_initial_values=true 36 | fi 37 | 38 | for d in $XDG_DIRS; do 39 | var="XDG_${d}_DIR" 40 | value="$(eval echo $(echo \$${var}))" 41 | 42 | if [ "$save_initial_values" = true ]; then 43 | XDG_SPECIAL_DIRS+=("$var") 44 | XDG_SPECIAL_DIRS_INITIAL_PATHS+=("$value") 45 | fi 46 | 47 | XDG_SPECIAL_DIRS_PATHS+=("$value") 48 | done 49 | } 50 | 51 | function is_subpath() { 52 | dir=$(realpath $1) 53 | parent=$(realpath $2) 54 | [ "${dir##$parent/}" != "$dir" ] && return 0 || return 1 55 | } 56 | 57 | WITH_RUNTIME=no 58 | if [ -z "$RUNTIME" ]; then 59 | RUNTIME=$SNAP 60 | else 61 | # add general paths not added by snapcraft due to runtime snap 62 | append_dir LD_LIBRARY_PATH $RUNTIME/lib/$ARCH 63 | append_dir LD_LIBRARY_PATH $RUNTIME/usr/lib 64 | append_dir LD_LIBRARY_PATH $RUNTIME/usr/lib/$ARCH 65 | append_dir PATH $RUNTIME/usr/bin 66 | WITH_RUNTIME=yes 67 | fi 68 | 69 | # XKB config 70 | export XKB_CONFIG_ROOT=$RUNTIME/usr/share/X11/xkb 71 | 72 | # Give XOpenIM a chance to locate locale data. 73 | # This is required for text input to work in SDL2 games. 74 | export XLOCALEDIR=$RUNTIME/usr/share/X11/locale 75 | 76 | # Set XCursors path 77 | export XCURSOR_PATH=$RUNTIME/usr/share/icons 78 | prepend_dir XCURSOR_PATH $SNAP/data-dir/icons 79 | 80 | # Mesa Libs for OpenGL support 81 | append_dir LD_LIBRARY_PATH $RUNTIME/usr/lib/$ARCH/mesa 82 | append_dir LD_LIBRARY_PATH $RUNTIME/usr/lib/$ARCH/mesa-egl 83 | 84 | # Tell libGL and libva where to find the drivers 85 | export LIBGL_DRIVERS_PATH=$RUNTIME/usr/lib/$ARCH/dri 86 | append_dir LD_LIBRARY_PATH $LIBGL_DRIVERS_PATH 87 | export LIBVA_DRIVERS_PATH=$RUNTIME/usr/lib/$ARCH/dri 88 | 89 | # Set where the VDPAU drivers are located 90 | export VDPAU_DRIVER_PATH="/usr/lib/$ARCH/vdpau/" 91 | if [ -e "/var/lib/snapd/lib/gl/vdpau/libvdpau_nvidia.so" ]; then 92 | export VDPAU_DRIVER_PATH="/var/lib/snapd/lib/gl/vdpau" 93 | # Prevent picking VA-API (Intel/AMD) over NVIDIA VDPAU; on PRIME systems for example 94 | unset LIBVA_DRIVERS_PATH 95 | fi 96 | 97 | # Unity7 export (workaround for https://launchpad.net/bugs/1638405) 98 | append_dir LD_LIBRARY_PATH $RUNTIME/usr/lib/$ARCH/libunity 99 | 100 | # Pulseaudio export 101 | append_dir LD_LIBRARY_PATH $RUNTIME/usr/lib/$ARCH/pulseaudio 102 | 103 | # EGL vendor files on glvnd enabled systems 104 | [ -d /var/lib/snapd/lib/glvnd/egl_vendor.d ] && \ 105 | prepend_dir __EGL_VENDOR_LIBRARY_DIRS /var/lib/snapd/lib/glvnd/egl_vendor.d 106 | 107 | # EGL vendor files 108 | append_dir __EGL_VENDOR_LIBRARY_DIRS $RUNTIME/etc/glvnd/egl_vendor.d 109 | append_dir __EGL_VENDOR_LIBRARY_DIRS $RUNTIME/usr/share/glvnd/egl_vendor.d 110 | 111 | # Tell GStreamer where to find its plugins 112 | export GST_PLUGIN_PATH=$SNAP/usr/lib/$ARCH/gstreamer-1.0 113 | export GST_PLUGIN_SYSTEM_PATH=$RUNTIME/usr/lib/$ARCH/gstreamer-1.0 114 | # gst plugin scanner doesn't install in the correct path: https://github.com/ubuntu/snapcraft-desktop-helpers/issues/43 115 | export GST_PLUGIN_SCANNER=$RUNTIME/usr/lib/$ARCH/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner 116 | 117 | # XDG Config 118 | [ "$WITH_RUNTIME" = yes ] && prepend_dir XDG_CONFIG_DIRS $RUNTIME/etc/xdg 119 | prepend_dir XDG_CONFIG_DIRS $SNAP/etc/xdg 120 | 121 | # Define snaps' own data dir 122 | [ "$WITH_RUNTIME" = yes ] && prepend_dir XDG_DATA_DIRS $RUNTIME/usr/share 123 | prepend_dir XDG_DATA_DIRS $SNAP/usr/share 124 | prepend_dir XDG_DATA_DIRS $SNAP/share 125 | prepend_dir XDG_DATA_DIRS $SNAP/data-dir 126 | prepend_dir XDG_DATA_DIRS $SNAP_USER_DATA 127 | 128 | # Set XDG_DATA_HOME to local path 129 | export XDG_DATA_HOME=$SNAP_USER_DATA/.local/share 130 | ensure_dir_exists $XDG_DATA_HOME -m 700 131 | 132 | # Workaround for GLib < 2.53.2 not searching for schemas in $XDG_DATA_HOME: 133 | # https://bugzilla.gnome.org/show_bug.cgi?id=741335 134 | prepend_dir XDG_DATA_DIRS $XDG_DATA_HOME 135 | 136 | # Set cache folder to local path 137 | export XDG_CACHE_HOME=$SNAP_USER_COMMON/.cache 138 | if [[ -d $SNAP_USER_DATA/.cache && ! -e $XDG_CACHE_HOME ]]; then 139 | # the .cache directory used to be stored under $SNAP_USER_DATA, migrate it 140 | mv $SNAP_USER_DATA/.cache $SNAP_USER_COMMON/ 141 | fi 142 | ensure_dir_exists $XDG_CACHE_HOME -m 700 143 | 144 | # Create $XDG_RUNTIME_DIR if not exists (to be removed when LP: #1656340 is fixed) 145 | ensure_dir_exists $XDG_RUNTIME_DIR -m 700 146 | 147 | # Ensure the app finds locale definitions (requires locales-all to be installed) 148 | append_dir LOCPATH $RUNTIME/usr/lib/locale 149 | 150 | # If any, keep track of where XDG dirs were so we can potentially migrate the content later 151 | update_xdg_dirs_values 152 | 153 | # Setup user-dirs.* or run xdg-user-dirs-update if needed 154 | needs_xdg_update=false 155 | needs_xdg_reload=false 156 | needs_xdg_links=false 157 | 158 | if [ "$HOME" != "$SNAP_USER_DATA" ] && ! is_subpath "$XDG_CONFIG_HOME" "$HOME"; then 159 | for f in user-dirs.dirs user-dirs.locale; do 160 | if [ -f "$HOME/.config/$f" ]; then 161 | mv "$HOME/.config/$f" "$XDG_CONFIG_HOME" 162 | needs_xdg_reload=true 163 | fi 164 | done 165 | fi 166 | 167 | if can_open_file "$REALHOME/.config/user-dirs.dirs"; then 168 | # shellcheck disable=SC2154 169 | if [ "$needs_update" = true ] || [ "$needs_xdg_reload" = true ]; then 170 | sed "/^#/!s#\$HOME#${REALHOME}#g" "$REALHOME/.config/user-dirs.dirs" > "$XDG_CONFIG_HOME/user-dirs.dirs" 171 | md5sum < "$REALHOME/.config/user-dirs.dirs" > "$XDG_CONFIG_HOME/user-dirs.dirs.md5sum" 172 | # It's possible user-dirs.dirs exists when user-dirs.locale doesn't. This 173 | # simply means the user opted to never ask to translate their user dirs 174 | if can_open_file "$REALHOME/.config/user-dirs.locale"; then 175 | cp -a "$REALHOME/.config/user-dirs.locale" "$XDG_CONFIG_HOME" 176 | md5sum < "$REALHOME/.config/user-dirs.locale" > "$XDG_CONFIG_HOME/user-dirs.locale.md5sum" 177 | elif [ -f "$XDG_CONFIG_HOME/user-dirs.locale.md5sum" ]; then 178 | rm "$XDG_CONFIG_HOME/user-dirs.locale.md5sum" 179 | fi 180 | needs_xdg_reload=true 181 | fi 182 | else 183 | needs_xdg_update=true 184 | needs_xdg_links=true 185 | fi 186 | 187 | if [ $needs_xdg_reload = true ]; then 188 | update_xdg_dirs_values 189 | needs_xdg_reload=false 190 | fi 191 | 192 | # Check if we can actually read the contents of each xdg dir 193 | for ((i = 0; i < ${#XDG_SPECIAL_DIRS_PATHS[@]}; i++)); do 194 | if ! can_open_file "${XDG_SPECIAL_DIRS_PATHS[$i]}"; then 195 | needs_xdg_update=true 196 | needs_xdg_links=true 197 | break 198 | fi 199 | done 200 | 201 | # If needs XDG update and xdg-user-dirs-update exists in $PATH, run it 202 | if [ $needs_xdg_update = true ] && command -v xdg-user-dirs-update >/dev/null; then 203 | xdg-user-dirs-update 204 | update_xdg_dirs_values 205 | fi 206 | 207 | # Create links for user-dirs.dirs 208 | if [ $needs_xdg_links = true ]; then 209 | for ((i = 0; i < ${#XDG_SPECIAL_DIRS_PATHS[@]}; i++)); do 210 | b=$(realpath "${XDG_SPECIAL_DIRS_PATHS[$i]}" --relative-to="$HOME") 211 | if [[ "$b" != "." && -e $REALHOME/$b ]]; then 212 | [ -d $HOME/$b ] && rmdir $HOME/$b 2> /dev/null 213 | [ ! -e $HOME/$b ] && ln -s $REALHOME/$b $HOME/$b 214 | fi 215 | done 216 | else 217 | # If we aren't creating new links, check if we have content saved in old locations and move it 218 | for ((i = 0; i < ${#XDG_SPECIAL_DIRS[@]}; i++)); do 219 | old="${XDG_SPECIAL_DIRS_INITIAL_PATHS[$i]}" 220 | new="${XDG_SPECIAL_DIRS_PATHS[$i]}" 221 | if [ -L "$old" ] && [ -d "$new" ] && [ `readlink "$old" 2>/dev/null` != "$new" ] && 222 | (is_subpath "$old" "$SNAP_USER_DATA" || is_subpath "$old" "$SNAP_USER_COMMON"); then 223 | mv -vn "$old"/* "$new"/ 2>/dev/null 224 | elif [ -d "$old" ] && [ -d "$new" ] && [ "$old" != "$new" ] && 225 | (is_subpath "$old" "$SNAP_USER_DATA" || is_subpath "$old" "$SNAP_USER_COMMON"); then 226 | mv -vn "$old"/* "$new"/ 2>/dev/null 227 | fi 228 | done 229 | fi 230 | 231 | # If detect wayland server socket, then set environment so applications prefer 232 | # wayland, and setup compat symlink (until we use user mounts. Remember, 233 | # XDG_RUNTIME_DIR is /run/user//snap.$SNAP so look in the parent directory 234 | # for the socket. For details: 235 | # https://forum.snapcraft.io/t/wayland-dconf-and-xdg-runtime-dir/186/10 236 | # Applications that don't support wayland natively may define DISABLE_WAYLAND 237 | # (to any non-empty value) to skip that logic entirely. 238 | wayland_available=false 239 | if [[ -n "$XDG_RUNTIME_DIR" && -z "$DISABLE_WAYLAND" ]]; then 240 | wdisplay="wayland-0" 241 | if [ -n "$WAYLAND_DISPLAY" ]; then 242 | wdisplay="$WAYLAND_DISPLAY" 243 | fi 244 | wayland_sockpath="$XDG_RUNTIME_DIR/../$wdisplay" 245 | wayland_snappath="$XDG_RUNTIME_DIR/$wdisplay" 246 | if [ -S "$wayland_sockpath" ]; then 247 | # if running under wayland, use it 248 | #export WAYLAND_DEBUG=1 249 | wayland_available=true 250 | # create the compat symlink for now 251 | if [ ! -e "$wayland_snappath" ]; then 252 | ln -s "$wayland_sockpath" "$wayland_snappath" 253 | fi 254 | fi 255 | fi 256 | 257 | # Make PulseAudio socket available inside the snap-specific $XDG_RUNTIME_DIR 258 | if [ -n "$XDG_RUNTIME_DIR" ]; then 259 | pulsenative="pulse/native" 260 | pulseaudio_sockpath="$XDG_RUNTIME_DIR/../$pulsenative" 261 | if [ -S "$pulseaudio_sockpath" ]; then 262 | export PULSE_SERVER="unix:${pulseaudio_sockpath}" 263 | fi 264 | fi 265 | 266 | # GI repository 267 | [ "$WITH_RUNTIME" = yes ] && prepend_dir GI_TYPELIB_PATH $RUNTIME/usr/lib/$ARCH/girepository-1.0 268 | [ "$WITH_RUNTIME" = yes ] && prepend_dir GI_TYPELIB_PATH $RUNTIME/usr/lib/girepository-1.0 269 | prepend_dir GI_TYPELIB_PATH $SNAP/usr/lib/$ARCH/girepository-1.0 270 | prepend_dir GI_TYPELIB_PATH $SNAP/usr/lib/girepository-1.0 271 | prepend_dir GI_TYPELIB_PATH $SNAP/usr/lib/gjs/girepository-1.0 272 | 273 | # Keep an array of data dirs, for looping through them 274 | IFS=':' read -r -a data_dirs_array <<< "$XDG_DATA_DIRS" 275 | 276 | # Font Config and themes 277 | export FONTCONFIG_PATH=$RUNTIME/etc/fonts 278 | export FONTCONFIG_FILE=$RUNTIME/etc/fonts/fonts.conf 279 | 280 | function make_user_fontconfig { 281 | echo "" 282 | if [ -d $REALHOME/.local/share/fonts ]; then 283 | echo " $REALHOME/.local/share/fonts" 284 | fi 285 | if [ -d $REALHOME/.fonts ]; then 286 | echo " $REALHOME/.fonts" 287 | fi 288 | for ((i = 0; i < ${#data_dirs_array[@]}; i++)); do 289 | if [ -d "${data_dirs_array[$i]}/fonts" ]; then 290 | echo " ${data_dirs_array[$i]}/fonts" 291 | fi 292 | done 293 | # fix font render for modified fonts, that discussed on Snapcraft Forum: 294 | # https://forum.snapcraft.io/t/snap-package-cannot-read-fonts-conf/16657 295 | echo ' /etc/fonts/conf.d' 296 | echo ' conf.d' 297 | 298 | # We need to include this default cachedir first so that caching 299 | # works: without it, fontconfig will try to write to the real user home 300 | # cachedir and be blocked by AppArmor. 301 | echo ' fontconfig' 302 | if [ -d $REALHOME/.cache/fontconfig ]; then 303 | echo " $REALHOME/.cache/fontconfig" 304 | fi 305 | echo "" 306 | } 307 | 308 | if [ $needs_update = true ]; then 309 | rm -rf $XDG_DATA_HOME/{fontconfig,fonts,fonts-*,themes,.themes} 310 | 311 | # This fontconfig fragment is installed in a location that is 312 | # included by the system fontconfig configuration: namely the 313 | # etc/fonts/conf.d/50-user.conf file. 314 | ensure_dir_exists $XDG_CONFIG_HOME/fontconfig 315 | async_exec make_user_fontconfig > $XDG_CONFIG_HOME/fontconfig/fonts.conf 316 | 317 | # the themes symlink are needed for GTK 3.18 when the prefix isn't changed 318 | # GTK 3.20 looks into XDG_DATA_DIR which has connected themes. 319 | if [ -d $SNAP/data-dir/themes ]; then 320 | ln -sf $SNAP/data-dir/themes $XDG_DATA_HOME 321 | ln -sfn $SNAP/data-dir/themes $SNAP_USER_DATA/.themes 322 | else 323 | ln -sf $RUNTIME/usr/share/themes $XDG_DATA_HOME 324 | ln -sfn $RUNTIME/usr/share/themes $SNAP_USER_DATA/.themes 325 | fi 326 | fi 327 | 328 | # Build mime.cache 329 | # needed for gtk and qt icon 330 | if [ $needs_update = true ]; then 331 | rm -rf $XDG_DATA_HOME/mime 332 | if [ ! -f $RUNTIME/usr/share/mime/mime.cache ]; then 333 | if command -v update-mime-database >/dev/null; then 334 | cp --preserve=timestamps -dR $RUNTIME/usr/share/mime $XDG_DATA_HOME 335 | async_exec update-mime-database $XDG_DATA_HOME/mime 336 | fi 337 | fi 338 | fi 339 | 340 | # Gio modules and cache (including gsettings module) 341 | export GIO_MODULE_DIR=$XDG_CACHE_HOME/gio-modules 342 | function compile_giomodules { 343 | if [ -f $1/glib-2.0/gio-querymodules ]; then 344 | rm -rf $GIO_MODULE_DIR 345 | ensure_dir_exists $GIO_MODULE_DIR 346 | ln -s $1/gio/modules/*.so $GIO_MODULE_DIR 347 | $1/glib-2.0/gio-querymodules $GIO_MODULE_DIR 348 | fi 349 | } 350 | if [ $needs_update = true ]; then 351 | async_exec compile_giomodules $RUNTIME/usr/lib/$ARCH 352 | fi 353 | 354 | # Setup compiled gsettings schema 355 | GS_SCHEMA_DIR=$XDG_DATA_HOME/glib-2.0/schemas 356 | function compile_schemas { 357 | if [ -f "$1" ]; then 358 | rm -rf $GS_SCHEMA_DIR 359 | ensure_dir_exists $GS_SCHEMA_DIR 360 | for ((i = 0; i < ${#data_dirs_array[@]}; i++)); do 361 | schema_dir="${data_dirs_array[$i]}/glib-2.0/schemas" 362 | if [ -f "$schema_dir/gschemas.compiled" ]; then 363 | # This directory already has compiled schemas 364 | continue 365 | fi 366 | if [ -n "$(ls -A $schema_dir/*.xml 2>/dev/null)" ]; then 367 | ln -s $schema_dir/*.xml $GS_SCHEMA_DIR 368 | fi 369 | if [ -n "$(ls -A $schema_dir/*.override 2>/dev/null)" ]; then 370 | ln -s $schema_dir/*.override $GS_SCHEMA_DIR 371 | fi 372 | done 373 | # Only compile schemas if we copied anyting 374 | if [ -n "$(ls -A $GS_SCHEMA_DIR/*.xml $GS_SCHEMA_DIR/*.override 2>/dev/null)" ]; then 375 | "$1" $GS_SCHEMA_DIR 376 | fi 377 | fi 378 | } 379 | if [ $needs_update = true ]; then 380 | async_exec compile_schemas $RUNTIME/usr/lib/$ARCH/glib-2.0/glib-compile-schemas 381 | fi 382 | 383 | # Enable gsettings user changes 384 | # symlink the dconf file if home plug is connected for read 385 | DCONF_DEST_USER_DIR=$SNAP_USER_DATA/.config/dconf 386 | if [ ! -f $DCONF_DEST_USER_DIR/user ]; then 387 | if [ -f $REALHOME/.config/dconf/user ]; then 388 | ensure_dir_exists $DCONF_DEST_USER_DIR 389 | ln -s $REALHOME/.config/dconf/user $DCONF_DEST_USER_DIR 390 | fi 391 | fi 392 | # symlink the runtime dconf file as well 393 | if [ -r $XDG_RUNTIME_DIR/../dconf/user ]; then 394 | ensure_dir_exists $XDG_RUNTIME_DIR/dconf 395 | ln -sf ../../dconf/user $XDG_RUNTIME_DIR/dconf/user 396 | fi 397 | 398 | # Testability support 399 | append_dir LD_LIBRARY_PATH $SNAP/testability 400 | append_dir LD_LIBRARY_PATH $SNAP/testability/$ARCH 401 | append_dir LD_LIBRARY_PATH $SNAP/testability/$ARCH/mesa 402 | 403 | # Gdk-pixbuf loaders 404 | export GDK_PIXBUF_MODULE_FILE=$XDG_CACHE_HOME/gdk-pixbuf-loaders.cache 405 | export GDK_PIXBUF_MODULEDIR=$RUNTIME/usr/lib/$ARCH/gdk-pixbuf-2.0/2.10.0/loaders 406 | if [ $needs_update = true ] || [ ! -f $GDK_PIXBUF_MODULE_FILE ]; then 407 | rm -f $GDK_PIXBUF_MODULE_FILE 408 | if [ -f $RUNTIME/usr/lib/$ARCH/gdk-pixbuf-2.0/gdk-pixbuf-query-loaders ]; then 409 | async_exec $RUNTIME/usr/lib/$ARCH/gdk-pixbuf-2.0/gdk-pixbuf-query-loaders > $GDK_PIXBUF_MODULE_FILE 410 | fi 411 | fi 412 | 413 | # Icon themes cache 414 | if [ $needs_update = true ]; then 415 | rm -rf $XDG_DATA_HOME/icons 416 | ensure_dir_exists $XDG_DATA_HOME/icons 417 | for ((i = 0; i < ${#data_dirs_array[@]}; i++)); do 418 | # The runtime and theme content snaps should already contain icon caches 419 | # so we skip them to optimise app start time. 420 | if [[ "${data_dirs_array[$i]}" == "$SNAP/data-dir" || "${data_dirs_array[$i]}" == "$RUNTIME/"* ]]; then 421 | continue 422 | fi 423 | for theme in "${data_dirs_array[$i]}/icons/"*; do 424 | if [ -f "$theme/index.theme" -a ! -f "$theme/icon-theme.cache" ]; then 425 | theme_dir=$XDG_DATA_HOME/icons/$(basename "$theme") 426 | if [ ! -d "$theme_dir" ]; then 427 | ensure_dir_exists "$theme_dir" 428 | ln -s $theme/* "$theme_dir" 429 | if [ -f $RUNTIME/usr/sbin/update-icon-caches ]; then 430 | async_exec $RUNTIME/usr/sbin/update-icon-caches "$theme_dir" 431 | elif [ -f $RUNTIME/usr/sbin/update-icon-cache.gtk2 ]; then 432 | async_exec $RUNTIME/usr/sbin/update-icon-cache.gtk2 "$theme_dir" 433 | fi 434 | fi 435 | fi 436 | done 437 | done 438 | fi 439 | 440 | # GTK theme and behavior modifier 441 | # Those can impact the theme engine used by Qt as well 442 | gtk_configs=(gtk-3.0/settings.ini gtk-3.0/bookmarks gtk-2.0/gtkfilechooser.ini) 443 | for f in ${gtk_configs[@]}; do 444 | dest="$XDG_CONFIG_HOME/$f" 445 | if [ ! -L "$dest" ]; then 446 | ensure_dir_exists `dirname $dest` 447 | ln -s $REALHOME/.config/$f $dest 448 | fi 449 | done 450 | 451 | # create symbolic link to ibus socket path for ibus to look up its socket files 452 | # (see comments #3 and #6 on https://launchpad.net/bugs/1580463) 453 | IBUS_CONFIG_PATH=$XDG_CONFIG_HOME/ibus 454 | ensure_dir_exists $IBUS_CONFIG_PATH 455 | [ -d $IBUS_CONFIG_PATH/bus ] && rm -rf $IBUS_CONFIG_PATH/bus 456 | ln -sfn $REALHOME/.config/ibus/bus $IBUS_CONFIG_PATH 457 | --------------------------------------------------------------------------------