Политика конфиденциальностиКонтактыО сайтеОтзывыGitHubDonate
© EVILEG 2015-2018
Рекомендует хостинг
TIMEWEB

Qt Linux - Урок 001. Автозапуск Qt приложения под Linux

Qt, Linux, Ubuntu, autorun, автозапуск

Поговорим, о том, как добавить в Qt приложение функционал по настройке автозапуска данного приложения. Например, у нас имеется окно настроек и мы хотим сделать возможность настройки автозапуска приложения из этого диалогового окна.

В отличие от автозапуска в Windows , где можно воспользоваться QSettings и внести изменения в реестр, в Linux потребуется создать специальный исполняемый файл, который будет отвечать за автозапуск приложения при входе пользователя в операционную систему.

Допустим название проекта и соответственно название исполняемого файла будет AutorunLinux, тогда потребуется создать исполняемый файл AutorunLinux.desktop по следующему пути:

~/.config/autostart/AutorunLinux.desktop

Содержимое исполняемого файла нужно сделать аналогичным другим файлам автозапуска других приложений, чтобы гарантировано получить требуемый результат. В случае с Ubuntu Linux 15.04/15.10 содержимое файла получилось следующее:

[Desktop Entry]
Type=Application
Exec=/home/dekadent/QT/Projects/build-AutorunLinux-Desktop_Qt_5_5_1_GCC_64bit-Debug/AutorunLinux
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
Name[en_GB]=AutorunLinux
Name=AutorunLinux
Comment[en_GB]=AutorunLinux
Comment=AutorunLinux

Где параметр Exec указывает путь к исполняемому файлу приложения.

Также не забудьте сделать файл исполняемым:

chmod +x ~/.config/autostart/AutorunLinux.desktop

Для того, чтобы гарантировано быть уверенным в правильности подготавливаемого содержимого файла автозапуска, рекомендую для начала добавить Ваше приложение в автозапуск с помощью стандартной утилиты Startup Applications .

Данная утилита создаст гарантированно рабочий вариант файла для Вашего приложения. После чего Вам останется только добавить содержимое через программный код с автоматической модификацией пути к исполняемому файлу приложения.

Структура проекта

Для демонстрации программного кода, предлагаю создать следующий проект, со следующим содержимым:

  • AutorunLinux.pro - профайл проекта;
  • widget.h - заголовочный файл главного окна приложения;
  • widget.cpp - файл исходных кодов главного окна приложения;
  • widget.ui - форма главного окна приложения;
  • main.cpp - основной файл исходных кодов приложения.

В данном приложении будет чекбокс, по состоянию которого мы будет удалять и добавлять приложения в автозапуск при нажатии кнопки PushButton. При запуске приложения будет выскакивать сообщение, что приложение запущено. Внешний вид приложения следующий:

widget.h

В заголовочном файле из всех изменений будет только объявление слота для нажатия кнопки:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;
};

#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QDir>
#include <QFile>
#include <QTextStream>
#include <QStandardPaths>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    QMessageBox::information(this,"AutoRun","Apllication is started!");
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_pushButton_clicked()
{
    // Путь к папке автозапуска
    QString autostartPath = QStandardPaths::standardLocations(QStandardPaths::ConfigLocation).at(0) + QLatin1String("/autostart");
    /* Проверяем, существует ли директория, в которой будет храниться файл автозапуска.
     * А то мало ли... пользователь удалил...
     * */
    QDir autorunDir(autostartPath);
    if(!autorunDir.exists()){
        // Если не существует, то создаём
        autorunDir.mkpath(autostartPath);
    }
    QFile autorunFile(autostartPath + QLatin1String("/AutorunLinux.desktop"));
    /* Проверяем состояние чекбокса, если отмечен, то добавляем приложения в автозапуск.
     * В противном случае удаляем
     * */
    if(ui->checkBox->isChecked()) {
        // Далее проверяем наличие самого файла автозапуска
        if(!autorunFile.exists()){

            /* Далее открываем файл и записываем в него необходимые данные
             * с указанием пути к исполняемому файлу, с помощью QCoreApplication::applicationFilePath()
             * */
            if(autorunFile.open(QFile::WriteOnly)){

                QString autorunContent("[Desktop Entry]\n"
                                       "Type=Application\n"
                                       "Exec=" + QCoreApplication::applicationFilePath() + "\n"
                                       "Hidden=false\n"
                                       "NoDisplay=false\n"
                                       "X-GNOME-Autostart-enabled=true\n"
                                       "Name[en_GB]=AutorunLinux\n"
                                       "Name=AutorunLinux\n"
                                       "Comment[en_GB]=AutorunLinux\n"
                                       "Comment=AutorunLinux\n");
                QTextStream outStream(&autorunFile);
                outStream << autorunContent;
                // Устанавливаем права доступа, в том числе и на исполнение файла, иначе автозапуск не сработает
                autorunFile.setPermissions(QFileDevice::ExeUser|QFileDevice::ExeOwner|QFileDevice::ExeOther|QFileDevice::ExeGroup|
                                       QFileDevice::WriteUser|QFileDevice::ReadUser);
                autorunFile.close();
            }
        }
    } else {
        // Удаляем файл автозапуска
        if(autorunFile.exists()) autorunFile.remove();
    }
}

Итог

В результате работы данного кода приложение будет вносить себя в автозапуск и запускаться при входе пользователя в систему. Для проверки работоспособности, создайте с помощью приложения файл автозапуска, выйдите из системы и войдите снова (Log Out/ Log In).

Исходный код проекта: AutorunLinux

a
  • #
  • 21 сентября 2018 г. 9:08

Спасибо за статью!

Пример рабочий! Со своим проектом тоже получилось!


Наткнулся на эту статью когда решал задачу запуска Qt app с помощью .

Когда пробовал с помощью получилось запустить простой проект Qt с QCoreApplication. Т.е. без gui.

Для этого оказалось достаточно создать файл (в моем случае) в /etc/systemd/system/

[Unit]
Description=qt_console_app service desription

[Service]
ExecStart=/home/user/cpp_examples/build/build_qt_console_app/qt_console_app
Restart=always

[Install]
WantedBy=graphical.target

И запустить:


Но если хочу запускать проект Qt с gui - не получается!

С помощью видно ошибку:

QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-root'
сен 21 11:29:44 debian systemd-demo[11389]: qt.qpa.screen: QXcbConnection: Could not connect to display
сен 21 11:29:44 debian systemd-demo[11389]: Could not connect to any X display.

Пытался играться с переменными DISPLAY и с Xauthority. Но воз и ныне там.

Только что на линуксовой форуме прочитал, что не для приложений с gui. Там советуют пользоваться средствами автозапуска. Это, скорее-всего, и есть тема данной статьи, которая сработало.

Не подскажете, может ли есть какой-то путь, хитрости, чтобы, всё-таки, запустить проект Qt с GUI с помощью ?


И второй вопрос. Через пробовал в том числе потому что нужен рестарт приложения, если упадет. Там всего-лишь дописывается одна строчка в вышеприведенный файл.

И с помощью Вашего подхода можно ли как-то дописать авторестарт при падение программы?

Если я вас правильно понял, то авторестарт сюда дописывается  QString autorunContent.
Не могли бы вы не выделять пока слова жирным текстом, в комментариях сломан парсинг тегов, завтра буду чинить. Поэтому съедаются жирные слова.

a
  • #
  • 24 сентября 2018 г. 14:40

Не могли бы подробнее рассказать об этой возможности? Я докопался до запросов Desktop Entry Files + restart, но до сих пор не найду autorunContent, о котором Вы писали...

Ну я имел ввиду, что дописать в коде вот сюда то, о чём вы говорили про рестарт

QString autorunContent("[Desktop Entry]\n"
                                       "Type=Application\n"
                                       "Exec=" + QCoreApplication::applicationFilePath() + "\n"
                                       "Hidden=false\n"
                                       "NoDisplay=false\n"
                                       "X-GNOME-Autostart-enabled=true\n"
                                       "Name[en_GB]=AutorunLinux\n"
                                       "Name=AutorunLinux\n"
                                       "Comment[en_GB]=AutorunLinux\n"
                                       "Comment=AutorunLinux\n");
a
  • #
  • 24 сентября 2018 г. 14:47

Просто сейчас правлю сам файл example.desktop. Пытаюсь понять какую пару key=value мне нужно дописать.

Если честно, то я не уверен, что это вообще можно реализовать через *.desktop файл. Я сделал предположение на основе того, что вы сказали про *.desktop и рестарт.

Все варианты, которые встречаются на форумах, предполагают наличие демона, который следит за тем, чтобы программа была онлайн.

Например я использую supervisor для автостарта сервисов сайта. Поэтому перезагрузка скриптов сайта у меня делается через killall. Грубовато, но supervisor ещё ни разу не подводил.



a
  • #
  • 24 сентября 2018 г. 15:00

Не могли бы дать ссылку на пример? Какое-то рабочее использование. Т.е. у меня есть Qt Gui App, которое я бы хотел запускать при старте системы и в случае, если оно грохнется. Если о чем Вы говорите это поможет сделать, не могли бы просвятить в виде ссылки или примерного направление копания))

А вот здесь у меня есть пример использования supervisor.

https://evileg.com/ru/post/3/

Вся статья вам там не интересна, интересен только шаг с настройкой supervisor. Он получается будет у вас как зависимость к вашему приложению, но вопрос зависимостей - это уже отдельная тема для разговора. В данном случае к самому программированию supervisor отношения не имеет. Это настройка демона.


a
  • #
  • 27 сентября 2018 г. 15:07

Спасибо! На данный момент выбор пал в сторону скрипта с бесконечным циклом, перегружающим программу при падение.

Здесь подробнее описал.

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
КА
19 февраля 2019 г. 18:32
Кристина Афанасьева

C++ - Тест 006. Перечисления

  • Результат:70баллов,
  • Очки рейтинга1
КА
19 февраля 2019 г. 18:26
Кристина Афанасьева

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:60баллов,
  • Очки рейтинга-1
КА
19 февраля 2019 г. 18:00
Кристина Афанасьева

C++ - Тест 002. Константы

  • Результат:50баллов,
  • Очки рейтинга-4
Последние комментарии
21 февраля 2019 г. 12:51
Евгений Легоцкой

Иногда CMake приходится перезапускать начисто, не обновляет кэш
R
21 февраля 2019 г. 12:29
RandyGallup

Я указал данные строки, т.к. без них у меня вылетала следующая ошибка: By not providing "FindQt5Core.cmake" in CMAKE_MODULE_PATH this project has asked CMake to find a package configurat...
21 февраля 2019 г. 12:08
BlinCT

Вот атк выглядит мой проектник, посмотрите его. cmake_minimum_required(VERSION 3.6)project(projecttimer)set(CMAKE_CXX_STANDARD 11)set(CMAKE_AUTOMOC ON)set(CMAKE_AUTORCC ON)find_packa...
21 февраля 2019 г. 12:04
BlinCT

Смотрите, если вы используете глобально для проекта -DCMAKE_PREFIX_PATH= то вам не надо уже указывать вот эти строкиset(Qt5Core_DIR "C:/Qt/5.12.1/mingw73_64/lib/cmake/Qt5Core")set(Qt5Gui_DIR...
R
21 февраля 2019 г. 11:54
RandyGallup

Даже не запускается. main.cpp у меня точно такой же, как в статье. CMakeLists.txt пришлось немного подправить (прикрепил ниже), т.к. не находились некоторые файлы. cmake_minimum_requi...
Сейчас обсуждают на форуме
21 февраля 2019 г. 8:58
Евгений Легоцкой

Ну у меня координаты передавались в зависимости от положения курсора мыши, а в вам по сути нужно будет аналогичным способом посылать даннные из полей ввода. Так что здесь скорее интерфес...
20 февраля 2019 г. 21:55
Евгений Легоцкой

Не до конца понимаю сути вопроса, наверное, нужно увидеть программный код и попытку его применения, но к методам базового класса можно обращаться в наследованном классе через вызов по имени ба...
MU
20 февраля 2019 г. 15:06
Maciej Urmański

Yes, ok I have solution! Thank you for directing me about annotate.:) Solution is: users_in = User.objects.filter(joined_users__goal=goal, joined_users__joined=True)
20 февраля 2019 г. 14:40
Евгений Легоцкой

Думаю, что ещё можно переопределить mouseReleaseEvent(QMouseEvent* event) у QTableView, который содержит модель и немного поиграться с индексом. Если это индекс, который соответству...
20 февраля 2019 г. 10:34
Евгений Легоцкой

Да, так тоже можно. Единственный момент в том, что lupdate не всегда понимает, к какому контексту это дело относится, и может запихать в левый контекст. В небольшом проекте это не критич...
Присоединяйтесь к нам в социальных сетях

Для зарегистрированных пользователей на сайте присутствует минимальное количество рекламы