aboutsummaryrefslogtreecommitdiff
path: root/src/QuickMedia.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/QuickMedia.cpp')
-rw-r--r--src/QuickMedia.cpp245
1 files changed, 143 insertions, 102 deletions
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index c7d63d7..afd8461 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -395,74 +395,16 @@ namespace QuickMedia {
Program::Program() :
disp(nullptr),
- window(sf::VideoMode(1280, 720, 24), "QuickMedia", sf::Style::Default),
window_size(1280, 720),
current_page(PageType::EXIT),
image_index(0),
tab_background(sf::Vector2f(1.0f, 1.0f), 10.0f, 10)
{
- disp = XOpenDisplay(NULL);
- if (!disp)
- throw std::runtime_error("Failed to open display to X11 server");
-
- resources_root = "/usr/share/quickmedia/";
- if(get_file_type("../../../images/manganelo_logo.png") == FileType::REGULAR) {
- resources_root = "../../../";
- }
-
- set_resource_loader_root_path(resources_root.c_str());
-
- if(!circle_mask_shader.loadFromFile(resources_root + "shaders/circle_mask.glsl", sf::Shader::Type::Fragment)) {
- fprintf(stderr, "Failed to load %s/shaders/circle_mask.glsl", resources_root.c_str());
- abort();
- }
-
- if(!loading_icon.loadFromFile(resources_root + "images/loading_icon.png")) {
- fprintf(stderr, "Failed to load %s/images/loading_icon.png", resources_root.c_str());
- abort();
- }
- loading_icon.setSmooth(true);
- load_sprite.setTexture(loading_icon, true);
- sf::Vector2u loading_icon_size = loading_icon.getSize();
- load_sprite.setOrigin(loading_icon_size.x * 0.5f, loading_icon_size.y * 0.5f);
-
- struct sigaction action;
- action.sa_handler = sigpipe_handler;
- sigemptyset(&action.sa_mask);
- action.sa_flags = 0;
- sigaction(SIGPIPE, &action, NULL);
-
- XSetErrorHandler(x_error_handler);
- XSetIOErrorHandler(x_io_error_handler);
-
- window.setVerticalSyncEnabled(true);
- monitor_hz = get_monitor_max_hz(disp);
- window.setFramerateLimit(FPS_IDLE);
- idle = true;
- vsync_set = false;
- /*
- if(enable_vsync(disp, window.getSystemHandle())) {
- vsync_set = true;
- } else {
- fprintf(stderr, "Failed to enable vsync, fallback to frame limiting\n");
- window.setFramerateLimit(monitor_hz);
- }
- */
- fprintf(stderr, "Monitor hz: %d\n", monitor_hz);
-
- if(create_directory_recursive(get_cache_dir().join("thumbnails")) != 0) {
- fprintf(stderr, "Failed to create thumbnails directory\n");
- }
-
- const char *qm_phone_factor = getenv("QM_PHONE_FACTOR");
- if(qm_phone_factor && atoi(qm_phone_factor) == 1)
- show_room_side_panel = false;
- else
- show_room_side_panel = true;
- main_thread_id = std::this_thread::get_id();
+
}
Program::~Program() {
+ window.close();
images_to_upscale_queue.close();
if(image_upscale_thead.joinable())
image_upscale_thead.join();
@@ -473,18 +415,20 @@ namespace QuickMedia {
}
static void usage() {
- fprintf(stderr, "usage: quickmedia <plugin> [--no-video] [--use-system-mpv-config] [--dir <directory>]\n");
+ fprintf(stderr, "usage: quickmedia <plugin> [--no-video] [--use-system-mpv-config] [--dir <directory>] [-e <window>]\n");
fprintf(stderr, "OPTIONS:\n");
fprintf(stderr, " plugin The plugin to use. Should be either launcher, 4chan, manganelo, mangatown, mangadex, pornhub, youtube, spotify, soundcloud, nyaa.si, matrix, file-manager or stdin\n");
fprintf(stderr, " --no-video Only play audio when playing a video. Disabled by default\n");
fprintf(stderr, " --use-system-mpv-config Use system mpv config instead of no config. Disabled by default\n");
fprintf(stderr, " --upscale-images Upscale low-resolution manga pages using waifu2x-ncnn-vulkan. Disabled by default\n");
fprintf(stderr, " --upscale-images-always Upscale manga pages using waifu2x-ncnn-vulkan, no matter what the original image resolution is. Disabled by default\n");
- fprintf(stderr, " --dir Set the start directory when using file-manager\n");
+ fprintf(stderr, " --dir <directory> Set the start directory when using file-manager\n");
+ fprintf(stderr, " -e <window> Embed QuickMedia into another window\n");
fprintf(stderr, "EXAMPLES:\n");
- fprintf(stderr, " quickmedia manganelo\n");
+ fprintf(stderr, " quickmedia launcher\n");
fprintf(stderr, " quickmedia --upscale-images-always manganelo\n");
fprintf(stderr, " echo -e \"hello\\nworld\" | quickmedia stdin\n");
+ fprintf(stderr, " tabbed quickmedia launcher -e\n");
}
static bool is_manga_plugin(const char *plugin_name) {
@@ -508,6 +452,7 @@ namespace QuickMedia {
}
const char *start_dir = nullptr;
+ Window parent_window = None;
std::vector<Tab> tabs;
for(int i = 1; i < argc; ++i) {
@@ -539,6 +484,20 @@ namespace QuickMedia {
}
} else if(strcmp(argv[i], "--low-cpu-mode") == 0) {
low_cpu_mode = true;
+ } else if(strcmp(argv[i], "-e") == 0) {
+ if(i < argc - 1) {
+ parent_window = strtol(argv[i + 1], nullptr, 0);
+ if(parent_window == None && errno == EINVAL) {
+ fprintf(stderr, "Invalid -e argument. Argument has to be a number\n");
+ usage();
+ return -1;
+ }
+ ++i;
+ } else {
+ fprintf(stderr, "Missing window to embed into after -e argument\n");
+ usage();
+ return -1;
+ }
} else if(argv[i][0] == '-') {
fprintf(stderr, "Invalid option %s\n", argv[i]);
usage();
@@ -546,17 +505,17 @@ namespace QuickMedia {
}
}
- if(low_cpu_mode)
- FPS_IDLE = 2;
- else
- FPS_IDLE = 20;
-
if(!plugin_name) {
fprintf(stderr, "Missing plugin argument\n");
usage();
return -1;
}
+ if(low_cpu_mode)
+ FPS_IDLE = 2;
+ else
+ FPS_IDLE = 20;
+
if(upscale_image_action != UpscaleImageAction::NO) {
if(!is_manga_plugin(plugin_name)) {
fprintf(stderr, "Option --upscale-images/-upscale-images-force is only valid for manganelo, mangatown and mangadex\n");
@@ -605,6 +564,7 @@ namespace QuickMedia {
return -1;
}
+ init(parent_window);
load_plugin_by_name(tabs, start_dir);
while(!tabs.empty() || matrix) {
@@ -632,16 +592,99 @@ namespace QuickMedia {
return exit_code;
}
+ void Program::init(Window parent_window) {
+ disp = XOpenDisplay(NULL);
+ if (!disp)
+ throw std::runtime_error("Failed to open display to X11 server");
+
+ wm_delete_window_atom = XInternAtom(disp, "WM_DELETE_WINDOW", False);
+
+ int screen = DefaultScreen(disp);
+ int screen_center_x = (DisplayWidth(disp, screen) - window_size.x) / 2;
+ int screen_center_y = (DisplayHeight(disp, screen) - window_size.y) / 2;
+
+ x11_window = XCreateWindow(disp, parent_window ? parent_window : DefaultRootWindow(disp),
+ screen_center_x, screen_center_y, window_size.x, window_size.y, 0,
+ DefaultDepth(disp, screen),
+ InputOutput,
+ DefaultVisual(disp, screen),
+ 0, nullptr);
+ if(!x11_window)
+ throw std::runtime_error("Failed to create window");
+
+ XStoreName(disp, x11_window, "QuickMedia");
+ XMapWindow(disp, x11_window);
+ XFlush(disp);
+
+ window.create(x11_window);
+
+ resources_root = "/usr/share/quickmedia/";
+ if(get_file_type("../../../images/manganelo_logo.png") == FileType::REGULAR) {
+ resources_root = "../../../";
+ }
+
+ set_resource_loader_root_path(resources_root.c_str());
+
+ if(!circle_mask_shader.loadFromFile(resources_root + "shaders/circle_mask.glsl", sf::Shader::Type::Fragment)) {
+ fprintf(stderr, "Failed to load %s/shaders/circle_mask.glsl", resources_root.c_str());
+ abort();
+ }
+
+ if(!loading_icon.loadFromFile(resources_root + "images/loading_icon.png")) {
+ fprintf(stderr, "Failed to load %s/images/loading_icon.png", resources_root.c_str());
+ abort();
+ }
+ loading_icon.setSmooth(true);
+ load_sprite.setTexture(loading_icon, true);
+ sf::Vector2u loading_icon_size = loading_icon.getSize();
+ load_sprite.setOrigin(loading_icon_size.x * 0.5f, loading_icon_size.y * 0.5f);
+
+ struct sigaction action;
+ action.sa_handler = sigpipe_handler;
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = 0;
+ sigaction(SIGPIPE, &action, NULL);
+
+ XSetErrorHandler(x_error_handler);
+ XSetIOErrorHandler(x_io_error_handler);
+
+ window.setVerticalSyncEnabled(true);
+ monitor_hz = get_monitor_max_hz(disp);
+ window.setFramerateLimit(FPS_IDLE);
+ idle = true;
+ vsync_set = false;
+ /*
+ if(enable_vsync(disp, window.getSystemHandle())) {
+ vsync_set = true;
+ } else {
+ fprintf(stderr, "Failed to enable vsync, fallback to frame limiting\n");
+ window.setFramerateLimit(monitor_hz);
+ }
+ */
+ fprintf(stderr, "Monitor hz: %d\n", monitor_hz);
+
+ if(create_directory_recursive(get_cache_dir().join("thumbnails")) != 0)
+ throw std::runtime_error("Failed to create thumbnails directory");
+
+ const char *qm_phone_factor = getenv("QM_PHONE_FACTOR");
+ if(qm_phone_factor && atoi(qm_phone_factor) == 1)
+ show_room_side_panel = false;
+ else
+ show_room_side_panel = true;
+ main_thread_id = std::this_thread::get_id();
+ }
+
void Program::load_plugin_by_name(std::vector<Tab> &tabs, const char *start_dir) {
if(!plugin_name || plugin_name[0] == '\0')
return;
window.setTitle("QuickMedia - " + std::string(plugin_name));
- const char *plugin_logo_name = get_plugin_logo_name(plugin_name);
+ no_video = force_no_video;
+
std::string plugin_logo_path;
+ const char *plugin_logo_name = get_plugin_logo_name(plugin_name);
if(plugin_logo_name)
plugin_logo_path = resources_root + "images/" + plugin_logo_name;
- no_video = force_no_video;
plugin_logo = sf::Texture();
if(!plugin_logo_path.empty()) {
@@ -744,11 +787,15 @@ namespace QuickMedia {
}
}
- void Program::base_event_handler(sf::Event &event, PageType previous_page, Body *body, SearchBar *search_bar, bool handle_keypress, bool handle_searchbar) {
- if (event.type == sf::Event::Closed) {
+ void Program::handle_window_close() {
+ if(wm_delete_window_atom && XCheckTypedWindowEvent(disp, x11_window, ClientMessage, &xev) && (Atom)xev.xclient.data.l[0] == wm_delete_window_atom) {
current_page = PageType::EXIT;
window.close();
- } else if(event.type == sf::Event::Resized) {
+ }
+ }
+
+ void Program::base_event_handler(sf::Event &event, PageType previous_page, Body *body, SearchBar *search_bar, bool handle_keypress, bool handle_searchbar) {
+ if(event.type == sf::Event::Resized) {
window_size.x = event.size.width;
window_size.y = event.size.height;
sf::FloatRect visible_area(0, 0, window_size.x, window_size.y);
@@ -1087,14 +1134,13 @@ namespace QuickMedia {
}
void Program::page_loop(std::vector<Tab> &tabs, int start_tab_index, PageLoopSubmitHandler after_submit_handler) {
- malloc_trim(0);
-
if(tabs.empty()) {
show_notification("QuickMedia", "No tabs provided!", Urgency::CRITICAL);
return;
}
window.setFramerateLimit(FPS_IDLE);
+ malloc_trim(0);
idle = true;
for(Tab &tab : tabs) {
@@ -1318,9 +1364,7 @@ namespace QuickMedia {
else
event_idle_handler(event);
- if (event.type == sf::Event::Closed) {
- window.close();
- } else if(event.type == sf::Event::Resized) {
+ if(event.type == sf::Event::Resized) {
window_size.x = event.size.width;
window_size.y = event.size.height;
sf::FloatRect visible_area(0, 0, window_size.x, window_size.y);
@@ -1416,6 +1460,7 @@ namespace QuickMedia {
}
}
update_idle_state();
+ handle_window_close();
if(redraw) {
redraw = false;
@@ -1711,12 +1756,7 @@ namespace QuickMedia {
sf::Event event;
while(window.isOpen()) {
while(window.pollEvent(event)) {
- if(event.type == sf::Event::Closed) {
- task.cancel();
- current_page = PageType::EXIT;
- window.close();
- return TaskResult::CANCEL;
- } else if(event.type == sf::Event::Resized) {
+ if(event.type == sf::Event::Resized) {
window_size.x = event.size.width;
window_size.y = event.size.height;
sf::FloatRect visible_area(0, 0, window_size.x, window_size.y);
@@ -1727,6 +1767,13 @@ namespace QuickMedia {
}
}
+ if(wm_delete_window_atom && XCheckTypedWindowEvent(disp, x11_window, ClientMessage, &xev) && (Atom)xev.xclient.data.l[0] == wm_delete_window_atom) {
+ task.cancel();
+ current_page = PageType::EXIT;
+ window.close();
+ return TaskResult::CANCEL;
+ }
+
if(task.ready()) {
if(task.get())
return TaskResult::TRUE;
@@ -1953,10 +2000,7 @@ namespace QuickMedia {
while (current_page == PageType::VIDEO_CONTENT && window.isOpen()) {
while (window.pollEvent(event)) {
- if (event.type == sf::Event::Closed) {
- current_page = PageType::EXIT;
- window.close();
- } else if(event.type == sf::Event::Resized) {
+ if(event.type == sf::Event::Resized) {
window_size.x = event.size.width;
window_size.y = event.size.height;
sf::FloatRect visible_area(0, 0, window_size.x, window_size.y);
@@ -1968,6 +2012,7 @@ namespace QuickMedia {
save_video_url_to_clipboard();
}
}
+ handle_window_close();
if(video_player_window && XCheckTypedWindowEvent(disp, video_player_window, KeyPress, &xev)/* && xev.xkey.subwindow == video_player_window*/) {
#pragma GCC diagnostic push
@@ -2448,10 +2493,7 @@ namespace QuickMedia {
// TODO: Show to user if a certain page is missing (by checking page name (number) and checking if some are skipped)
while (current_page == PageType::IMAGES && window.isOpen()) {
while(window.pollEvent(event)) {
- if (event.type == sf::Event::Closed) {
- current_page = PageType::EXIT;
- window.close();
- } else if(event.type == sf::Event::Resized) {
+ if(event.type == sf::Event::Resized) {
window_size.x = event.size.width;
window_size.y = event.size.height;
sf::FloatRect visible_area(0, 0, window_size.x, window_size.y);
@@ -2487,6 +2529,7 @@ namespace QuickMedia {
}
}
}
+ handle_window_close();
if(download_in_progress && check_downloaded_timer.getElapsedTime().asMilliseconds() >= check_downloaded_timeout_ms) {
sf::String error_msg;
@@ -2604,7 +2647,7 @@ namespace QuickMedia {
json_chapter = Json::Value(Json::objectValue);
}
- ImageViewer image_viewer(images_page, images_page->manga_name, images_page->get_chapter_name(), image_index, content_cache_dir);
+ ImageViewer image_viewer(&window, images_page, images_page->manga_name, images_page->get_chapter_name(), image_index, content_cache_dir);
json_chapter["current"] = std::min(latest_read, image_viewer.get_num_pages());
json_chapter["total"] = image_viewer.get_num_pages();
@@ -2616,8 +2659,9 @@ namespace QuickMedia {
window.setFramerateLimit(monitor_hz);
while(current_page == PageType::IMAGES_CONTINUOUS && window.isOpen()) {
+ handle_window_close();
window.clear(back_color);
- ImageViewerAction action = image_viewer.draw(window);
+ ImageViewerAction action = image_viewer.draw();
switch(action) {
case ImageViewerAction::NONE:
break;
@@ -2850,10 +2894,7 @@ namespace QuickMedia {
}
}
- if(event.type == sf::Event::Closed) {
- current_page = PageType::EXIT;
- window.close();
- } else if(event.type == sf::Event::Resized) {
+ if(event.type == sf::Event::Resized) {
window_size.x = event.size.width;
window_size.y = event.size.height;
sf::FloatRect visible_area(0, 0, window_size.x, window_size.y);
@@ -3016,6 +3057,7 @@ namespace QuickMedia {
}
frame_skip_text_entry = false;
update_idle_state();
+ handle_window_close();
chat_input_height_full = comment_input.get_height() + chat_input_padding_y * 2.0f;
@@ -3195,10 +3237,7 @@ namespace QuickMedia {
else
event_idle_handler(event);
- if (event.type == sf::Event::Closed) {
- current_page = PageType::EXIT;
- window.close();
- } else if(event.type == sf::Event::Resized) {
+ if(event.type == sf::Event::Resized) {
window_size.x = event.size.width;
window_size.y = event.size.height;
sf::FloatRect visible_area(0, 0, window_size.x, window_size.y);
@@ -3217,6 +3256,7 @@ namespace QuickMedia {
inputs[focused_input]->on_event(event);
}
update_idle_state();
+ handle_window_close();
if(redraw) {
redraw = false;
@@ -4690,6 +4730,7 @@ namespace QuickMedia {
}
frame_skip_text_entry = false;
update_idle_state();
+ handle_window_close();
matrix_chat_page->update();