Программа для создания desktop-файлов

от автора

В дистрибутивах GNU/Linux значки приложений в меню описываются специальными текстовыми файлами. Эти файлы имеют расширение .desktop и при установке приложения создаются автоматически. Но иногда бывают ситуации когда нужно самому создать такой файл. Это может быть когда у вас на руках имеется только исполняемый файл приложения, то есть когда приложение не упаковано должным образом. В некоторых дистрибутивах из коробки имеются программы для создания значков запуска, а в некоторых их нет и нужно искать такие приложения в репозиториях. Я создал свой вариант такой программы и в этом посте расскажу, что она из себя представляет.

Немного о desktop-файлах

Вот пример desktop-файла для консольной игры nsnake:

[Desktop Entry] Version=1.1 Type=Application Name=nsnake GenericName=Classic snake game on the terminal NoDisplay=false//отображать в меню Icon=nsnake Exec=nsnake Terminal=true//запускать в терминале Actions= Categories=ActionGame;Game; Keywords=snake;ncurses;textual;terminal;

Тут и так все понятно, но я все-таки прокомментировал пару позиций. Самое главное, что нужно прописать это название приложения (Name), путь до исполняемого файла (Exec) и путь до иконки (Icon). Если иконки нет и нет желания ее искать или создавать, то некоторые окружения рабочего стола установят иконку по умолчанию.

Краткое описание

Исходники приложения находятся здесь. Программа довольно простая. Выглядит она вот так:

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

В хидербаре находится кнопка, при нажатии на которую в файловом менеджере откроется папка, находящаяся по пути /.local/share/applications. Именно там программа сохраняет созданные файлы.

Как работает

Приложение написано на языке Vala с помощью среды разработки GNOME Builder. Устанавливал самую свежую версию среды (40.0) из репозитория Flathub. Оказалось, что визуальный дизайнер в этой версии еще багованнее, чем в предыдущей, поэтому интерфейс делал в Glade.

После того как созданы значки в полях ввода и к ним, также как и к другим кнопкам, привязаны необходимые действия, записываем в переменную directory_path путь до папки с desktop-файлами. Также на всякий случай надо проверить наличие этой папки перед запуском приложения и если папка по каким-то причинам отсутствует, то вывести специальное сообщение и деактивировать кнопку CREATE, так как в этом случае в ней нет необходимости.

        button_open.clicked.connect(on_open_directory);         button_create.clicked.connect(on_create_file);         directory_path = Environment.get_home_dir()+"/.local/share/applications";         GLib.File file = GLib.File.new_for_path(directory_path);          if(!file.query_exists()){//проверяем существует ли директория             alert("Error!\nPath "+directory_path+" is not exists!\nThe program will not be able to perform its functions.");             button_create.set_sensitive(false);//деактивация кнопки CREATE            }

При нажатии на кнопку CREATE вызывается метод on_create_file:

private void on_create_file (){        if(is_empty(entry_name.get_text())){//проверяем введено ли имя файла              alert("Enter the name");              entry_name.grab_focus();//устанавливаем фокус              return;          }          GLib.File file = GLib.File.new_for_path(directory_path+"/"+entry_name.get_text().strip()+".desktop");          if(file.query_exists()){//проверяем есть ли файл с таким именем             alert("A file with the same name already exists");             entry_name.grab_focus();             return;          }          var dialog_create_desktop_file = new Gtk.MessageDialog(this,Gtk.DialogFlags.MODAL,Gtk.MessageType.QUESTION, Gtk.ButtonsType.OK_CANCEL, "Create file "+file.get_basename()+" ?");           dialog_create_desktop_file.set_title("Question");           Gtk.ResponseType result = (Gtk.ResponseType)dialog_create_desktop_file.run ();           dialog_create_desktop_file.destroy();           if(result==Gtk.ResponseType.OK){               create_desktop_file();//создаем файл           }    }

Он предназначен для проверки ввода имени файла и проверки возможных совпадений с именами уже существующих в папке файлов, а также для вывода запроса подтверждения на создание файла. Если все проверки пройдены и пользователь подтвердил создание файла, то вызывается метод create_desktop_file:

private void create_desktop_file(){          string display;          if(checkbutton_no_display.get_active()){//проверяем первый чекбокс              display="true";          }else{              display="false";          }          string terminal;          if(checkbutton_terminal.get_active()){//проверяем второй чекбокс              terminal="true";          }else{              terminal="false";          }          string desktop_file="[Desktop Entry] Encoding=UTF-8 Type=Application NoDisplay="+display+" Terminal="+terminal+" Exec="+entry_exec.get_text().strip()+" Icon="+entry_icon.get_text().strip()+" Name="+entry_name.get_text().strip()+" Comment="+entry_comment.get_text().strip()+" Categories="+entry_categories.get_text().strip();//записываем содержимое будущего файла в переменную         string path=directory_path+"/"+entry_name.get_text()+".desktop";         try {             FileUtils.set_contents (path, desktop_file);//создаем файл         } catch (Error e) {             stderr.printf ("Error: %s\n", e.message);         }         GLib.File file = GLib.File.new_for_path(path);          if(file.query_exists()){//проверяем существование файла              alert("File "+file.get_basename()+" is created!\nPath: "+path);          }else{              alert("Error! Could not create file");          }        }

Чтобы просмотреть готовые файлы существует метод on_open_directory. Он срабатывает при нажатии на кнопку в хидербаре.

private void on_open_directory(){             try{                 Gtk.show_uri_on_window(this, "file://"+directory_path, Gdk.CURRENT_TIME);             }catch(Error e){                 alert("Error!\n"+e.message);             }        }

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

private void on_open_exec(){         var file_chooser = new Gtk.FileChooserDialog ("Choose a file", this, Gtk.FileChooserAction.OPEN, "_Cancel", Gtk.ResponseType.CANCEL, "_Open", Gtk.ResponseType.ACCEPT);         if (file_chooser.run () == Gtk.ResponseType.ACCEPT) {             entry_exec.set_text(file_chooser.get_filename());         }         file_chooser.destroy ();    }

А для выбора иконки код сложнее, так как данный диалог, помимо фильтра, содержит функционал предварительного просмотра изображения:

private void on_open_icon () {         var file_chooser = new Gtk.FileChooserDialog ("Select image file", this, Gtk.FileChooserAction.OPEN, "_Cancel", Gtk.ResponseType.CANCEL, "_Open", Gtk.ResponseType.ACCEPT); 	    Gtk.FileFilter filter = new Gtk.FileFilter (); 		file_chooser.set_filter (filter);//установка фильтра для изображений 		filter.add_mime_type ("image/jpeg");         filter.add_mime_type ("image/png");         Gtk.Image preview_area = new Gtk.Image (); 		file_chooser.set_preview_widget (preview_area);//установка области предпросмотра 		file_chooser.update_preview.connect (() => { 			string uri = file_chooser.get_preview_uri (); 			string path = file_chooser.get_preview_filename(); 			if (uri != null && uri.has_prefix ("file://") == true) { 				try { 					Gdk.Pixbuf pixbuf = new Gdk.Pixbuf.from_file_at_scale (path, 250, 250, true); 					preview_area.set_from_pixbuf (pixbuf);//установка изображения 					preview_area.show ();//показываем область предпросмотра 				} catch (Error e) { 					preview_area.hide ();//скрываем область предпросмотра 				} 			} else { 				preview_area.hide (); 			} 		});         if (file_chooser.run () == Gtk.ResponseType.ACCEPT) {             entry_icon.set_text(file_chooser.get_filename());         }         file_chooser.destroy ();        }

Метод для вывода сообщений пользователю:

private void alert (string str){           var dialog_alert = new Gtk.MessageDialog(this, Gtk.DialogFlags.MODAL, Gtk.MessageType.INFO, Gtk.ButtonsType.OK, str);           dialog_alert.set_title("Message");           dialog_alert.run();           dialog_alert.destroy();        }

Чтобы проверить введено ли какое-либо значение в текстовое поле используется такой метод:

private bool is_empty(string str){           return str.strip().length == 0;         }

На этом все! Надеюсь, что пост был для Вас полезен.

Дополнительная ссылка на SourceForge. До встречи в следующих постах!

ссылка на оригинал статьи https://habr.com/ru/company/itsoft/blog/549418/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *