Hello community, here is the log from the commit of package nwg-launchers for openSUSE:Factory checked in at 2020-11-05 21:54:59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/nwg-launchers (Old) and /work/SRC/openSUSE:Factory/.nwg-launchers.new.11331 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "nwg-launchers" Thu Nov 5 21:54:59 2020 rev:5 rq:846134 version:0.4.1 Changes: -------- --- /work/SRC/openSUSE:Factory/nwg-launchers/nwg-launchers.changes 2020-09-23 18:46:26.997655234 +0200 +++ /work/SRC/openSUSE:Factory/.nwg-launchers.new.11331/nwg-launchers.changes 2020-11-05 21:55:58.596041633 +0100 @@ -1,0 +2,13 @@ +Thu Nov 5 07:29:03 UTC 2020 - Michael Vetter <mvet...@suse.com> + +- Update to 0.4.1: + * bug breaking compilation with libstdc++ fixed #118 + * [nwgbar] added support for mnemonics #120 + * [nwggrid] added -d argument to force custom .desktop files + path(s) #122 + * [nwggrid] support for running apps in the terminal emulator + (Terminal=true) added; see README for details on detection + changing the terminal #127 + * [nwggrid] sorting names longer than 25 characters fixed #128 + +------------------------------------------------------------------- Old: ---- v0.4.0.tar.gz New: ---- v0.4.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ nwg-launchers.spec ++++++ --- /var/tmp/diff_new_pack.W6K5Wh/_old 2020-11-05 21:55:59.268040122 +0100 +++ /var/tmp/diff_new_pack.W6K5Wh/_new 2020-11-05 21:55:59.276040104 +0100 @@ -17,7 +17,7 @@ Name: nwg-launchers -Version: 0.4.0 +Version: 0.4.1 Release: 0 Summary: GTK launchers and menu for sway and i3 License: GPL-3.0-or-later ++++++ v0.4.0.tar.gz -> v0.4.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nwg-launchers-0.4.0/README.md new/nwg-launchers-0.4.1/README.md --- old/nwg-launchers-0.4.0/README.md 2020-09-22 02:41:14.000000000 +0200 +++ new/nwg-launchers-0.4.1/README.md 2020-11-05 00:51:26.000000000 +0100 @@ -82,12 +82,13 @@ ``` $ nwggrid -h -GTK application grid: nwggrid 0.3.1 (c) Piotr Miller 2020 & Contributors +GTK application grid: nwggrid 0.4.1 (c) 2020 Piotr Miller, Sergey Smirnykh & Contributors Options: -h show this help message and exit --f display favourites (most used entries) --p display pinned entries +-f display favourites (most used entries); does not work with -d +-p display pinned entries; does not work with -d +-d look for .desktop files in custom paths (-d '/my/path1:/my/another path:/third/path') -o <opacity> default (black) background opacity (0.0 - 1.0, default 0.9) -b <background> background colour in RRGGBB or RRGGBBAA format (RRGGBBAA alpha overrides <opacity>) -n <col> number of grid columns (default: 6) @@ -97,6 +98,15 @@ -wm <wmname> window manager name (if can not be detected) ``` +### Terminal applications + +`.desktop` files with the `Terminal=true` line should be started in a terminal emulator. There's no common method +to determine which terminal to use. The `nwggrid` command since v0.4.1 at the first run will look for installed +terminals in the following order: alacritty, kitty, urxvt, lxterminal, sakura, st, termite, terminator, xfce4-terminal, +gnome-terminal. The name of the first one found will be saved to the `~/.config/nwg-launchers/nwggrid/term` file. +If none of above is found, the fallback `xterm` value will be saved, regardless of whether xterm is installed or not. +You may edit the `term` file to use another terminal. + ### Custom background Use -b <RRGGBB> | <RRGGBBAA> argument (w/o #) to define custom background colour. If alpha value given, it overrides @@ -139,8 +149,8 @@ ### Customization -On first run the program creates the `nwg-launchers/nwgbar` folder in your .config directory. You'll find a sample template `bar.json` -and the `style.css` files inside. +On first run the program creates the `nwg-launchers/nwgbar` folder in your .config directory. You'll find a sample +template `bar.json` and the `style.css` files inside. Templates use json format. The default one defines an example Exit menu for sway window manager on Arch Linux: @@ -169,6 +179,25 @@ ] ``` +To set a keyboard shortcut (using Alt+KEY) for an entry, you can add an underscore before the letter you want to use. +Example to set `s` as the shortcut: + +``` +[ +... + { + "name": "Lock _screen", + "exec": "swaylock -f -c 000000", + "icon": "system-lock-screen" + } +... +] +``` + +**Note for underscore ("_")** + +If you want to use an underscore in the name, you have to double it ("__"). + **Wayfire note** For the Logout button, as in the bar above, you may use [wayland-logout](https://github.com/soreau/wayland-logout) by @soreau. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nwg-launchers-0.4.0/common/nwg_classes.cc new/nwg-launchers-0.4.1/common/nwg_classes.cc --- old/nwg-launchers-0.4.0/common/nwg_classes.cc 2020-09-22 02:41:14.000000000 +0200 +++ new/nwg-launchers-0.4.1/common/nwg_classes.cc 2020-11-05 00:51:26.000000000 +0100 @@ -79,7 +79,7 @@ this -> set_always_show_image(true); } -AppBox::AppBox(Glib::ustring name, Glib::ustring exec, Glib::ustring comment) { +AppBox::AppBox(Glib::ustring name, Glib::ustring exec, Glib::ustring comment) : Gtk::Button(name, true) { this -> name = name; if (name.length() > 25) { name = name.substr(0, 22) + "..."; @@ -87,7 +87,6 @@ this -> exec = std::move(exec); this -> comment = std::move(comment); this -> set_always_show_image(true); - this -> set_label(name); } AppBox::~AppBox() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nwg-launchers-0.4.0/common/nwg_classes.h new/nwg-launchers-0.4.1/common/nwg_classes.h --- old/nwg-launchers-0.4.0/common/nwg_classes.h 2020-09-22 02:41:14.000000000 +0200 +++ new/nwg-launchers-0.4.1/common/nwg_classes.h 2020-11-05 00:51:26.000000000 +0100 @@ -76,6 +76,7 @@ std::string icon; std::string comment; std::string mime_type; + bool terminal; }; struct RGBA { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nwg-launchers-0.4.0/common/nwg_tools.cc new/nwg-launchers-0.4.1/common/nwg_tools.cc --- old/nwg-launchers-0.4.0/common/nwg_tools.cc 2020-09-22 02:41:14.000000000 +0200 +++ new/nwg-launchers-0.4.1/common/nwg_tools.cc 2020-11-05 00:51:26.000000000 +0100 @@ -88,6 +88,56 @@ } /* + * Detect installed terminal emulator, save the command to txt file for further use. + * */ + std::string get_term(std::string config_dir) { + std::string t{"xterm"}; + std::string term_file = config_dir + "/term"; + if (std::ifstream(term_file)) { + // File exists: read command from the file, skip checks + t = read_file_to_string(term_file); + t.erase(remove(t.begin(), t.end(), '\n'), t.end()); + } else { + // We'll look for the first terminal available and save its name to '~/.config/nwg-launchers/nwggrid/term'. + // User may change the file content (terminal name) to their liking. + std::string terms [] = { + "alacritty", + "kitty", + "urxvt", + "lxterminal", + "sakura", + "st", + "termite", + "terminator", + "xfce4-terminal", + "gnome-terminal" + }; + for (auto&& term : terms) { + std::string check = "command -v " + term + " &>/dev/null"; + const char *command = check.c_str(); + int status = std::system(command); + if (status == 0) { + t = term; + std::string cmd = "echo " + t + " > " + term_file; + const char *c = cmd.c_str(); + std::system(c); + std::cout << "Saving \'" << t << "\' to \'" << term_file << "\' - edit to use another terminal.\n"; + break; + } + } + // In case we've found nothing, 'xterm' will be saved to the '~/.config/nwg-launchers/nwggrid/term' file, + // regardless of whether it is installed or not. User may still edit the file. + if (!std::ifstream(term_file)) { + std::cout << "No known terminal found. Saving \'xterm\' to \'" << term_file << "\'.\n"; + std::string cmd = "echo " + t + " > " + term_file; + const char *c = cmd.c_str(); + std::system(c); + } + } + return t; + } + +/* * Returns x, y, width, hight of focused display * */ Geometry display_geometry(const std::string& wm, Glib::RefPtr<Gdk::Display> display, Glib::RefPtr<Gdk::Window> window) { @@ -217,8 +267,8 @@ /* * Splits string into vector of strings by delimiter * */ -std::vector<std::string_view> split_string(std::string_view str, std::string_view delimiter) { - std::vector<std::string_view> result; +std::vector<std::string> split_string(std::string_view str, std::string_view delimiter) { + std::vector<std::string> result; std::size_t current, previous = 0; current = str.find_first_of(delimiter); while (current != std::string_view::npos) { @@ -310,7 +360,6 @@ return result; } - /* * Remove pid_file created by create_pid_file_or_kill_pid. * This function will be run before exiting. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nwg-launchers-0.4.0/common/nwg_tools.h new/nwg-launchers-0.4.1/common/nwg_tools.h --- old/nwg-launchers-0.4.0/common/nwg_tools.h 2020-09-22 02:41:14.000000000 +0200 +++ new/nwg-launchers-0.4.1/common/nwg_tools.h 2020-11-05 00:51:26.000000000 +0100 @@ -31,11 +31,13 @@ std::string detect_wm(void); +std::string get_term(std::string); + std::string get_locale(void); std::string read_file_to_string(const std::string&); void save_string_to_file(const std::string&, const std::string&); -std::vector<std::string_view> split_string(std::string_view, std::string_view); +std::vector<std::string> split_string(std::string_view, std::string_view); std::string_view take_last_by(std::string_view, std::string_view); ns::json string_to_json(const std::string&); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nwg-launchers-0.4.0/grid/grid.cc new/nwg-launchers-0.4.1/grid/grid.cc --- old/nwg-launchers-0.4.0/grid/grid.cc 2020-09-22 02:41:14.000000000 +0200 +++ new/nwg-launchers-0.4.1/grid/grid.cc 2020-11-05 00:51:26.000000000 +0100 @@ -9,6 +9,7 @@ #include <sys/time.h> #include <unistd.h> +#include <sys/stat.h> #include <charconv> @@ -20,6 +21,7 @@ bool pins = false; // whether to display pinned bool favs = false; // whether to display favorites std::string wm {""}; // detected or forced window manager name +std::string term {""}; std::size_t num_col = 6; // number of grid columns RGBA background = {0.0, 0.0, 0.0, 0.9}; @@ -33,8 +35,9 @@ \ Options:\n\ -h show this help message and exit\n\ --f display favourites (most used entries)\n\ --p display pinned entries \n\ +-f display favourites (most used entries); does not work with -d\n\ +-p display pinned entries; does not work with -d \n\ +-d look for .desktop files in custom paths (-d '/my/path1:/my/another path:/third/path') \n\ -o <opacity> default (black) background opacity (0.0 - 1.0, default 0.9)\n\ -b <background> background colour in RRGGBB or RRGGBBAA format (RRGGBBAA alpha overrides <opacity>)\n\ -n <col> number of grid columns (default: 6)\n\ @@ -59,8 +62,8 @@ std::cout << HELP_MESSAGE; std::exit(0); } - favs = input.cmdOptionExists("-f"); - pins = input.cmdOptionExists("-p"); + favs = input.cmdOptionExists("-f") && !input.cmdOptionExists("-d"); + pins = input.cmdOptionExists("-p") && !input.cmdOptionExists("-d"); auto forced_lang = input.getCmdOption("-l"); if (!forced_lang.empty()){ lang = forced_lang; @@ -104,6 +107,8 @@ } } + auto special_dirs = input.getCmdOption("-d"); + std::string_view bcg = input.getCmdOption("-b"); if (!bcg.empty()) { set_background(bcg); @@ -168,6 +173,8 @@ fs::create_directories(config_dir); } + term = get_term(config_dir); + // default and custom style sheet std::string default_css_file = config_dir + "/style.css"; // css file to be used @@ -188,8 +195,26 @@ favourites = get_favourites(std::move(cache), n); } - /* get all applications dirs */ - auto dirs = get_app_dirs(); + std::vector<std::string> dirs{""}; + if (special_dirs.empty()) { + // get all applications dirs + dirs = get_app_dirs(); + } else { + // use special dirs specified with -d argument (feature request #122) + dirs = split_string(special_dirs, ":"); + std::cout << "\nUsing custom .desktop files path(s):\n"; + struct stat statbuf; + for (auto& dir : dirs) { + if (stat(dir.c_str(), &statbuf) != -1) { + if (S_ISDIR(statbuf.st_mode)) { + std::cout << "'" << dir << "' [OK]\n"; + } + } else { + std::cout << "'" << dir << "' [INVALID]\n"; + } + } + std::cout << "\n"; + } gettimeofday(&tp, NULL); long int commons_ms = tp.tv_sec * 1000 + tp.tv_usec / 1000; @@ -308,7 +333,8 @@ long int boxes_ms = tp.tv_sec * 1000 + tp.tv_usec / 1000; for (auto& [desktop_id, pos_] : desktop_ids) { - if (auto pos = *pos_; pos_) { + if (pos_) { + auto pos = *pos_; auto& entry = desktop_entries[pos]; auto& ab = window.emplace_box(std::move(entry.name), std::move(entry.comment), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nwg-launchers-0.4.0/grid/grid.h new/nwg-launchers-0.4.1/grid/grid.h --- old/nwg-launchers-0.4.0/grid/grid.h 2020-09-22 02:41:14.000000000 +0200 +++ new/nwg-launchers-0.4.1/grid/grid.h 2020-11-05 00:51:26.000000000 +0100 @@ -32,6 +32,7 @@ extern std::vector<std::string> pinned; extern ns::json cache; extern std::string cache_file; +extern std::string term; /* Primitive version of C++20's std::span */ template <typename T> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nwg-launchers-0.4.0/grid/grid_classes.cc new/nwg-launchers-0.4.1/grid/grid_classes.cc --- old/nwg-launchers-0.4.0/grid/grid_classes.cc 2020-09-22 02:41:14.000000000 +0200 +++ new/nwg-launchers-0.4.1/grid/grid_classes.cc 2020-11-05 00:51:26.000000000 +0100 @@ -86,7 +86,7 @@ inner_vbox.set_halign(Gtk::ALIGN_CENTER); inner_vbox.pack_start(pinned_hbox, Gtk::PACK_SHRINK, 5); inner_vbox.pack_start(separator1, false, true, 0); - + favs_hbox.pack_start(favs_grid, true, false, 0); inner_vbox.pack_start(favs_hbox, false, false, 5); inner_vbox.pack_start(separator, false, true, 0); @@ -98,7 +98,7 @@ scrolled_window.show_all_children(); outer_vbox.pack_start(description, Gtk::PACK_SHRINK); - + this -> add(outer_vbox); this -> show_all_children(); } @@ -136,7 +136,7 @@ // so we make sure to drop the selection this -> searchbox.select_region(0, 0); this -> searchbox.set_position(-1); - + } } // Delegate handling to the base class @@ -269,7 +269,7 @@ auto& stats = this->stats_of(box); auto is_pinned = stats.pinned == Stats::Pinned; stats.pinned = Stats::PinTag{ !is_pinned }; - + // monotonic index increases each time an entry is pinned // ensuring it will appear last stats.position = this->monotonic_index * !is_pinned; @@ -294,7 +294,7 @@ to->push_back(&box); refresh_max_children_per_line(*from_grid, *from); refresh_max_children_per_line(*to_grid, *to); - + // get_parent is important // FlowBox { ... FlowBoxChild { box } ... } // box is not child to FlowBox @@ -348,14 +348,16 @@ } GridBox::GridBox(Glib::ustring name, Glib::ustring comment, const std::string& id, std::size_t index) -: name(std::move(name)), comment(std::move(comment)), desktop_id(&id), index(index) -{ - if (this->name.length() > 25) { - this->name.resize(22); - this->name += "..."; - } - this->set_always_show_image(true); - this->set_label(this->name); +: name(std::move(name)), comment(std::move(comment)), desktop_id(&id), index(index) { + // As we sort dynamically by actual names, we need to avoid shortening them, or long names will remain unsorted. + // See the issue: https://github.com/nwg-piotr/nwg-launchers/issues/128 + std::string display_name = this->name; + if (display_name.length() > 25) { + display_name.resize(22); + display_name += "..."; + } + this->set_always_show_image(true); + this->set_label(display_name); } bool GridBox::on_button_press_event(GdkEventButton* event) { @@ -387,6 +389,9 @@ toplevel.stats_of(*this).clicks++; std::string cmd = toplevel.exec_of(*this); cmd += " &"; + if (cmd.find(term) == 0) { + std::cout << "Running: \'" << cmd << "\'\n"; + } std::system(cmd.data()); toplevel.close(); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nwg-launchers-0.4.0/grid/grid_tools.cc new/nwg-launchers-0.4.1/grid/grid_tools.cc --- old/nwg-launchers-0.4.0/grid/grid_tools.cc 2020-09-22 02:41:14.000000000 +0200 +++ new/nwg-launchers-0.4.1/grid/grid_tools.cc 2020-11-05 00:51:26.000000000 +0100 @@ -50,7 +50,7 @@ }; std::string home = getenv("HOME"); - + auto xdg_data_home = getenv("XDG_DATA_HOME"); if (xdg_data_home) { auto dirs = split_string(xdg_data_home, ":"); @@ -64,7 +64,7 @@ append(s, ".local/share/applications"); } } - + const char* xdg_data_dirs = getenv("XDG_DATA_DIRS"); if (!xdg_data_dirs) { xdg_data_dirs = "/usr/local/share/:/usr/share/"; @@ -85,7 +85,7 @@ result.emplace_back(fp_dir); } } - + return result; } @@ -142,6 +142,7 @@ } // Repeat until the next section constexpr auto nodisplay = "NoDisplay=true"sv; + constexpr auto terminal = "Terminal=true"sv; while (std::getline(file, str)) { if (str[0] == '[') { // new section begins, break break; @@ -151,6 +152,9 @@ if (view == nodisplay) { return std::nullopt; } + if (view == terminal) { + entry.terminal = true; + } auto try_strip_prefix = [&view, view_len](auto& prefix) { auto len = std::min(view_len, std::size(prefix)); return Result { @@ -185,6 +189,9 @@ if (entry.name.empty() || entry.exec.empty()) { return std::nullopt; } + if (entry.terminal) { + entry.exec = term + " -e " + entry.exec; + } return entry; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nwg-launchers-0.4.0/meson.build new/nwg-launchers-0.4.1/meson.build --- old/nwg-launchers-0.4.0/meson.build 2020-09-22 02:41:14.000000000 +0200 +++ new/nwg-launchers-0.4.1/meson.build 2020-11-05 00:51:26.000000000 +0100 @@ -4,7 +4,7 @@ 'warning_level=3' ], license: 'GPL-3.0-or-later', - version: '0.4.0' + version: '0.4.1' ) compiler = meson.get_compiler('cpp')