Add URL drag and drop and desktop-aware theming

This commit is contained in:
Mario Fetka
2026-07-14 18:16:21 +02:00
parent 910cefc951
commit ba55befc63
9 changed files with 245 additions and 5 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.20)
project(prozgui VERSION 2.2.2 LANGUAGES C CXX)
project(prozgui VERSION 2.3.0 LANGUAGES C CXX)
include(GNUInstallDirs)
find_package(Threads REQUIRED)
+4 -1
View File
@@ -11,6 +11,10 @@ file downloading speeds.
Features:
Supports FTP
Supports HTTP including redirection.
Supports dragging URLs, newline-separated URL lists, and local URL-list files
onto the main window.
Selects a suitable FLTK appearance for GNOME/MATE and KDE automatically;
set FLTK_SCHEME to override the automatic choice.
Proxy servers supported.
Resume Supported.
Improved error checking and correction.
@@ -93,4 +97,3 @@ We sincerely hope that you will like the download accelerator..
Enjoy!
Kalum Somaratana (Grendel) <kalum@genesys.ro>
+6
View File
@@ -532,3 +532,9 @@ msgstr "Version de l'interface %s"
msgid "libprozilla version %s"
msgstr "Version de libprozilla %s"
msgid "Drop URLs or URL list files here"
msgstr "Déposez ici des URL ou des fichiers de listes dURL"
#, c-format
msgid "Started %d download(s); skipped %d invalid, duplicate, or unreadable item(s)."
msgstr "%d téléchargement(s) démarré(s) ; %d élément(s) invalide(s), en double ou illisible(s) ignoré(s)."
+6
View File
@@ -515,3 +515,9 @@ msgstr "Versione GUI %s"
msgid "libprozilla version %s"
msgstr "Versione libprozilla %s"
msgid "Drop URLs or URL list files here"
msgstr "Trascina qui URL o file con elenchi di URL"
#, c-format
msgid "Started %d download(s); skipped %d invalid, duplicate, or unreadable item(s)."
msgstr "Avviati %d download; ignorati %d elementi non validi, duplicati o illeggibili."
+6
View File
@@ -431,3 +431,9 @@ msgstr "GUI-versie %s"
msgid "libprozilla version %s"
msgstr "libprozilla-versie %s"
msgid "Drop URLs or URL list files here"
msgstr "Sleep URL's of bestanden met URL-lijsten hierheen"
#, c-format
msgid "Started %d download(s); skipped %d invalid, duplicate, or unreadable item(s)."
msgstr "%d download(s) gestart; %d ongeldig(e), dubbel(e) of onleesbaar(e) item(s) overgeslagen."
+9
View File
@@ -555,6 +555,15 @@ msgstr ""
msgid "Prozilla - Download Accelerator"
msgstr ""
#: src/main.cpp
msgid "Drop URLs or URL list files here"
msgstr ""
#: src/main.cpp
#, c-format
msgid "Started %d download(s); skipped %d invalid, duplicate, or unreadable item(s)."
msgstr ""
#: src/options.cpp:130
#, c-format
msgid "%s does not seem to be a valid directory"
+6
View File
@@ -534,3 +534,9 @@ msgstr "Versão da interface %s"
msgid "libprozilla version %s"
msgstr "Versão da libprozilla %s"
msgid "Drop URLs or URL list files here"
msgstr "Solte URLs ou arquivos de listas de URLs aqui"
#, c-format
msgid "Started %d download(s); skipped %d invalid, duplicate, or unreadable item(s)."
msgstr "%d download(s) iniciado(s); %d item(ns) inválido(s), duplicado(s) ou ilegível(is) ignorado(s)."
+6
View File
@@ -454,3 +454,9 @@ msgstr "Versiune interfață %s"
msgid "libprozilla version %s"
msgstr "Versiune libprozilla %s"
msgid "Drop URLs or URL list files here"
msgstr "Plasați aici URL-uri sau fișiere cu liste de URL-uri"
#, c-format
msgid "Started %d download(s); skipped %d invalid, duplicate, or unreadable item(s)."
msgstr "S-au pornit %d descărcări; s-au omis %d elemente nevalide, duplicate sau ilizibile."
+201 -3
View File
@@ -23,6 +23,12 @@
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <cctype>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <sstream>
#include <string>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>
@@ -70,6 +76,36 @@ void open_new_dl_win(urlinfo * url_data, boolean ftpsearch);
void menu_download_start();
void menu_download_stop();
void menu_download_remove();
void import_dropped_text(const char *text);
void apply_desktop_scheme()
{
const char *requested_scheme = getenv("FLTK_SCHEME");
if (requested_scheme && *requested_scheme)
{
Fl::scheme(requested_scheme);
return;
}
const char *desktop = getenv("XDG_CURRENT_DESKTOP");
if (!desktop)
desktop = getenv("XDG_SESSION_DESKTOP");
if (!desktop)
return;
std::string name(desktop);
for (std::string::size_type i = 0; i < name.size(); ++i)
name[i] = static_cast<char>(std::tolower(static_cast<unsigned char>(name[i])));
if (name.find("gnome") != std::string::npos ||
name.find("mate") != std::string::npos ||
name.find("cinnamon") != std::string::npos ||
name.find("xfce") != std::string::npos)
Fl::scheme("gtk+");
else if (name.find("kde") != std::string::npos ||
name.find("plasma") != std::string::npos)
Fl::scheme("gleam");
}
class Main_Window:public Fl_Window {
public:
@@ -85,11 +121,17 @@ Main_Window::Main_Window(int w, int h, const char *l):Fl_Window(w, h, l)
int Main_Window::handle(int e)
{
if (e == FL_PASTE)
switch (e)
{
// printf("%s\n", Fl::event_text());
case FL_DND_ENTER:
case FL_DND_DRAG:
case FL_DND_RELEASE:
return 1;
case FL_PASTE:
import_dropped_text(Fl::event_text());
return 1;
default:
break;
}
if (Fl_Window::handle(e))
@@ -209,6 +251,154 @@ void open_new_dl_win(urlinfo * url_data, boolean ftpsearch)
}
namespace {
std::string trim(const std::string &value)
{
const std::string::size_type first = value.find_first_not_of(" \t\r\n");
if (first == std::string::npos)
return std::string();
const std::string::size_type last = value.find_last_not_of(" \t\r\n");
return value.substr(first, last - first + 1);
}
int hex_value(char value)
{
if (value >= '0' && value <= '9')
return value - '0';
value = static_cast<char>(std::tolower(static_cast<unsigned char>(value)));
return value >= 'a' && value <= 'f' ? value - 'a' + 10 : -1;
}
bool file_uri_to_path(const std::string &uri, std::string *path)
{
if (uri.compare(0, 7, "file://") != 0)
return false;
std::string encoded = uri.substr(7);
if (encoded.compare(0, 10, "localhost/") == 0)
encoded.erase(0, 9);
else if (encoded.empty() || encoded[0] != '/')
return false;
path->clear();
for (std::string::size_type i = 0; i < encoded.size(); ++i)
{
if (encoded[i] == '%' && i + 2 < encoded.size())
{
const int high = hex_value(encoded[i + 1]);
const int low = hex_value(encoded[i + 2]);
if (high < 0 || low < 0)
return false;
path->push_back(static_cast<char>((high << 4) | low));
i += 2;
}
else
path->push_back(encoded[i]);
}
return path->find('\0') == std::string::npos;
}
bool read_url_list(const std::string &path, std::string *contents)
{
std::error_code error;
const std::filesystem::path file(path);
if (!std::filesystem::is_regular_file(file, error) || error)
return false;
const std::uintmax_t size = std::filesystem::file_size(file, error);
if (error || size > 1024 * 1024)
return false;
std::ifstream stream(file, std::ios::binary);
if (!stream)
return false;
std::ostringstream buffer;
buffer << stream.rdbuf();
*contents = buffer.str();
return static_cast<bool>(stream) || stream.eof();
}
bool start_dropped_url(const std::string &url)
{
urlinfo *url_data = static_cast<urlinfo *>(calloc(1, sizeof(urlinfo)));
if (!url_data)
return false;
if (proz_parse_url(url.c_str(), url_data, 0) != URLOK ||
strlen(url_data->file) == 0)
{
proz_free_url(url_data, 0);
free(url_data);
return false;
}
for (int i = 0; i < browser->size(); ++i)
{
if (strcmp(url_data->url, browser->text(i + 1)) == 0)
{
proz_free_url(url_data, 0);
free(url_data);
return false;
}
}
open_new_dl_win(url_data, rt.use_ftpsearch);
return true;
}
void import_url_lines(const std::string &text, int *started, int *skipped)
{
std::istringstream lines(text);
std::string line;
while (std::getline(lines, line))
{
line = trim(line);
if (line.empty() || line[0] == '#')
continue;
if (start_dropped_url(line))
++*started;
else
++*skipped;
}
}
} // namespace
void import_dropped_text(const char *text)
{
if (!text || !*text)
return;
int started = 0;
int skipped = 0;
std::istringstream dropped(text);
std::string item;
while (std::getline(dropped, item))
{
item = trim(item);
if (item.empty() || item[0] == '#')
continue;
std::string path;
std::string contents;
if (file_uri_to_path(item, &path))
{
if (read_url_list(path, &contents))
import_url_lines(contents, &started, &skipped);
else
++skipped;
}
else if (start_dropped_url(item))
++started;
else
++skipped;
}
if (skipped > 0)
fl_message(_("Started %d download(s); skipped %d invalid, duplicate, or unreadable item(s)."),
started, skipped);
}
void show_prefs()
@@ -431,6 +621,8 @@ int main(int argc, char **argv)
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
apply_desktop_scheme();
set_defaults(&argc, &argv);
load_prefs();
set_runtime_values();
@@ -473,6 +665,12 @@ int main(int argc, char **argv)
menubar->menu(menuitems);
}
Fl_Box *drop_hint = new Fl_Box(20, 55, 460, 165,
_("Drop URLs or URL list files here"));
drop_hint->box(FL_DOWN_BOX);
drop_hint->labelsize(16);
drop_hint->labelcolor(FL_DARK3);
/*The browser window */
browser = new Fl_Hold_Browser(2, 250, 495, 80);
browser->callback(browser_cb);