#pragma once #include namespace pdfcube { class app { public: app(const app&); app& operator=(const app&); /** @brief */ app() : the_doc_m(), the_stage_m(), filename_m(), progress_m(), progress_label_m(), current_page_m(), next_page_m(), current_page_no_m(0) { } bool init(int* argc, char** argv[]) { gchar **file_array; GOptionEntry options[] = { // TODO: add stage color/image and cube top color/image options { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &file_array, "Presentation PDF file to load", "FILE" }, { 0, 0, 0, (GOptionArg)0, 0, 0, 0 } }; g_thread_init(NULL); clutter_threads_init(); clutter_init_with_args (argc, argv, "PDFCube 0.1.0", options, NULL, NULL); // FIXME if(file_array[0] == 0 || file_array[1] != 0) return false; filename_m = file_array[0]; g_print(_("File is: %s\n"), filename_m); ClutterColor stage_color; the_stage_m = clutter_stage_get_default(); clutter_actor_set_size(the_stage_m, 1024, 768); clutter_color_from_string(&stage_color, "Black"); clutter_stage_set_color(CLUTTER_STAGE(the_stage_m), &stage_color); return true; } /** @brief Loads the PDF document. */ bool load() { // poppler needs an URI (e.g. file:///....) g_print(_("Loading %s...\n"), filename_m); PopplerDocument* active_document = poppler_document_new_from_file(filename_m, NULL, NULL); if(active_document == NULL) { g_print(_("PDF file %s cannot be opened," " check that it exists, permissions" " and that is \nnot encrypted.\n"), filename_m); return false; } g_print(_("Done.\n")); if(the_doc_m) delete the_doc_m; the_doc_m = new pdfcube::document(active_document); return true; } /** @brief Main application loop. */ void main_loop() { //clutter_stage_hide_cursor (CLUTTER_STAGE (stage)); ClutterColor label_color = { 0xff, 0xff, 0xff, 0x99 }; progress_label_m = clutter_text_new_full("Mono 36", "0%", &label_color); gfloat screen_w, screen_h; clutter_actor_get_size(CLUTTER_ACTOR(the_stage_m), &screen_w, &screen_h); clutter_actor_set_position(progress_label_m, screen_w/2.0, screen_h/2.0); clutter_actor_set_anchor_point_from_gravity(progress_label_m, CLUTTER_GRAVITY_CENTER); clutter_container_add_actor(CLUTTER_CONTAINER(the_stage_m), progress_label_m); clutter_actor_show(the_stage_m); g_thread_create(render_thread, this, FALSE, NULL); clutter_actor_set_reactive(the_stage_m, TRUE); g_signal_connect(the_stage_m, "key-press-event", G_CALLBACK (pdfcube::app::keypress_event), NULL); clutter_threads_enter(); clutter_main(); clutter_threads_leave(); } /** @brief The document. */ document* the_doc_m; protected: ClutterActor* the_stage_m; gchar *filename_m; std::string progress_m; ClutterActor* progress_label_m; ClutterActor* current_page_m; ClutterActor* next_page_m; int current_page_no_m; static gboolean progress_indicator_update(gpointer data) { app* me = static_cast(data); gfloat screen_w, screen_h; clutter_actor_get_size(CLUTTER_ACTOR(me->the_stage_m), &screen_w, &screen_h); clutter_text_set_text(CLUTTER_TEXT(me->progress_label_m), me->progress_m.c_str()); clutter_actor_set_anchor_point_from_gravity(me->progress_label_m, CLUTTER_GRAVITY_CENTER); clutter_actor_set_position(me->progress_label_m, screen_w/2.0, screen_h/2.0); return FALSE; } static gboolean progress_indicator_end(gpointer data) { app* me = static_cast(data); clutter_container_remove_actor(CLUTTER_CONTAINER(me->the_stage_m), me->progress_label_m); g_object_unref(me->progress_label_m); GError* error = 0; GdkPixbuf* buffer = me->the_doc_m->page(0).pixbuf(pdfcube::page::HI_RES); me->current_page_m = clutter_texture_new(); clutter_texture_set_filter_quality (CLUTTER_TEXTURE(me->current_page_m), CLUTTER_TEXTURE_QUALITY_HIGH); clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE(me->current_page_m), gdk_pixbuf_get_pixels(buffer), gdk_pixbuf_get_has_alpha(buffer), gdk_pixbuf_get_width(buffer), gdk_pixbuf_get_height(buffer), gdk_pixbuf_get_rowstride(buffer), 4, (ClutterTextureFlags)0, &error); gfloat screen_w, screen_h; clutter_actor_get_size(CLUTTER_ACTOR(me->the_stage_m), &screen_w, &screen_h); // Check if our slot ratio is less or more than owr own double aspect = me->the_doc_m->page(0).aspect_ratio(); double w = 0.0, h = 0.0; if(screen_h > screen_w/aspect) { w = screen_w; h = w/aspect; } else { h = screen_h; w = h*aspect; } clutter_actor_set_size(me->current_page_m, w, h); clutter_container_add_actor(CLUTTER_CONTAINER(me->the_stage_m), me->current_page_m); ClutterBindingPool *binding_pool; std::cerr << G_OBJECT_TYPE_NAME(me->the_stage_m) << std::endl; binding_pool = clutter_binding_pool_new(G_OBJECT_TYPE_NAME(me->the_stage_m)); clutter_binding_pool_install_action(binding_pool, "move-up", CLUTTER_Up, (ClutterModifierType)0, G_CALLBACK(pdfcube::app::action_move_up), me, NULL); clutter_binding_pool_install_action(binding_pool, "move-up", CLUTTER_KP_Up, (ClutterModifierType)0, G_CALLBACK(pdfcube::app::action_move_up), me, NULL); return FALSE; } static gpointer render_thread(gpointer data) { app* me = static_cast(data); std::cerr << me->filename_m << std::endl; me->load(); // ---------------------------------------------- // render low res version of all pages // ---------------------------------------------- for(int ii(0); ii != me->the_doc_m->n_pages(); ++ii) { me->the_doc_m->page(ii).render(pdfcube::page::LOW_RES); int percent = (100*(ii))/(me->the_doc_m->n_pages()+2); std::ostringstream pt; pt << percent << "%"; me->progress_m = pt.str(); clutter_threads_add_timeout(0, progress_indicator_update, data); } me->the_doc_m->page(0).render(pdfcube::page::HI_RES); int percent = (100*(me->the_doc_m->n_pages())) / (me->the_doc_m->n_pages()+2); std::ostringstream pt; pt << percent << "%"; me->progress_m = pt.str(); clutter_threads_add_timeout(0, progress_indicator_update, data); me->the_doc_m->page(1).render(pdfcube::page::HI_RES); me->progress_m = "100%"; clutter_threads_add_timeout(0, progress_indicator_update, data); clutter_threads_add_timeout(250, progress_indicator_end, data); return 0; } ////////////////////////////////////////////////////////////////////// // // Callbacks // static gboolean keypress_event(ClutterActor* actor, ClutterEvent* evt, gpointer data) { pdfcube::app* self = (pdfcube::app*)data; ClutterKeyEvent* key_evt = (ClutterKeyEvent*)evt; ClutterBindingPool *pool = NULL; std::cerr << " * " << G_OBJECT_TYPE_NAME(actor) << std::endl; /* retrieve the binding pool for the type of the actor */ pool = clutter_binding_pool_find(G_OBJECT_TYPE_NAME(actor)); assert(pool); /* activate any callback matching the key symbol and modifiers * mask of the key event. the returned value can be directly * used to signal that the actor has handled the event. */ return clutter_binding_pool_activate (pool, (guint)key_evt->keyval, (ClutterModifierType)key_evt->modifier_state, G_OBJECT(actor)); } static gboolean action_move_up(GObject *instance, const gchar *action_name, guint key_val, ClutterModifierType modifiers, gpointer user_data) { std::cerr << "move-up" << std::endl; } }; }