Israel is a terrorist state
http://www.youtube.com/watch?v=noln8nx43Sk
From: gtkmm-list [mailto:gtkmm-list-bounces gnome org] On Behalf Of Andrew Potter
Sent: Tuesday, August 20, 2013 9:46 PM
To: gtkmm-list gnome org
Subject: Fwd: Re: What is the minimum number of lines to update a gui window without user clicking a button
I missed the list in my last reply, so I'm copying it here for the record. In addition to using a cancelable I changed CallbackDispatcher to use a recursive mutex so gui_print can be called from the main thread as well.
While providing such an in depth example to L. James maybe goes against the learn-the-fundamentals-and-help-yourself culture, I'd just like to have a final answer and close the thread after a month and 100+ messages.
---------- Forwarded message ----------
From: "Andrew Potter" <agpotter gmail com>
Date: Aug 20, 2013 11:22 AM
Subject: Re: What is the minimum number of lines to update a gui window without user clicking a button
To: "L. D. James" <ljames apollo3 com>
Cc:
> On Tue, Aug 20, 2013 at 6:01 AM, L. D. James <ljames apollo3 com> wrote:
> > When clicking on the close button to cancel the operation the gui window
> > dims ad become non-responsive... locked up. That is a problem, in that some
> > of the programs might only take seconds or minutes to complete.
>
> I designed it that way because I didn't know if it was safe to have
> your blocking operation terminated suddenly; instead it ensures that
> your blocking operation runs until it fully completes. If it is safe
> to stop at any point then you can remove thread_cleanup() from
> Example::~Example(). Otherwise it is best to periodically check in the
> blocking operation whether the window has been closed.
> Gio::Cancellable can be used for this.
>
> // Example 6
> #include <gtkmm.h>
> #include <unistd.h>
> #include <queue>
>
> class CallbackDispatcher {
> public:
> CallbackDispatcher() {
> dispatcher.connect(sigc::mem_fun(this,
> &CallbackDispatcher::on_dispatch));
> }
>
> typedef sigc::slot<void> Message;
> void send(Message msg) {
> Glib::Threads::RecMutex::Lock lock(mutex);
> queue.push(msg);
> dispatcher();
> }
>
> private:
> /* CallbackDispatcher may not be copied, so we must hide these
> * constructors. */
> CallbackDispatcher(const CallbackDispatcher&);
> CallbackDispatcher& operator=(const CallbackDispatcher&);
>
> Glib::Threads::RecMutex mutex;
> std::queue<Message> queue;
> Glib::Dispatcher dispatcher;
>
> void on_dispatch() {
> Glib::Threads::RecMutex::Lock lock(mutex);
> while (!queue.empty()) {
> queue.front()();
> queue.pop();
> }
> }
> };
>
> class Example {
> private:
> Glib::RefPtr<Gtk::Application> app;
> Gtk::Window win;
> Gtk::TextView tv;
> Glib::RefPtr<Gtk::TextBuffer> tb;
> CallbackDispatcher callback_dispatcher;
> Glib::Threads::Thread *thread;
> Glib::RefPtr<Gio::Cancellable> cancellable;
>
> /* Appends str to the textbuffer. Like all methods that use the
> * Gtk namespace, it is not safe to call from another thread. */
> void gui_print_cb(const Glib::ustring& str) {
> tb->insert(tb->end(), str);
> }
>
> /* Provides threadsafe access to gui_print_cb() */
> void gui_print(const Glib::ustring& str) {
> sigc::slot<void> slot = sigc::bind(sigc::mem_fun(this,
> &Example::gui_print_cb), str);
> callback_dispatcher.send(slot);
> }
>
> /* This function is called on a separate thread so as to avoid
> * blocking GTK+'s main loop.
> */
> void blocking_operation() {
> /* This simulates a blocking process */
> sleep(5);
> gui_print("5% complete.\n");
> if (cancellable->is_cancelled()) return;
>
> sleep(5);
> gui_print("15% complete.\n");
> if (cancellable->is_cancelled()) return;
>
> sleep(5);
> gui_print("35% complete.\n");
> if (cancellable->is_cancelled()) return;
>
> sleep(5);
> gui_print("55% complete.\n");
> if (cancellable->is_cancelled()) return;
>
> sleep(5);
> gui_print("75% complete.\n");
> if (cancellable->is_cancelled()) return;
>
> sleep(5);
> gui_print("95% complete.\n");
> if (cancellable->is_cancelled()) return;
>
> sleep(5);
> gui_print("100% complete.\n");
>
> /* When the process is finished, we notify the GTK+ Main Loop by
> * using the dispatcher */
> callback_dispatcher.send(sigc::mem_fun(this,
> &Example::blocking_operation_finished));
> };
>
> /* This function is called on GTK+'s main loop via a
> * Glib::Dispatcher */
> void blocking_operation_finished() {
> cleanup_thread();
> gui_print("Operation finished.\n");
> };
>
> void cleanup_thread() {
> /* We must call Glib::Threads::Thread::join() in order to
> * correctly clean up the resource. */
> if (thread) {
> thread->join();
> thread = NULL;
> }
> }
>
> public:
> ~Example() {
> /* This will prevent the Window from being closed while
> * the blocking operation is ongoing. */
> cancellable->cancel();
> cleanup_thread();
> }
>
> Example(int argc, char *argv[]) :
> app(Gtk::Application::create(argc, argv, "com.example")),
> tb(tv.get_buffer()),
> thread(NULL),
> cancellable(Gio::Cancellable::create())
> {
> win.add(tv);
> win.show_all();
> }
>
> void run() {
> /* Create a slot to the blocking_operation() member function
> * to pass to Glib::Threads::Thread::create(). */
> sigc::slot<void> op_functor = sigc::mem_fun(this,
> &Example::blocking_operation);
>
> /* Create a worker thread to perform the blocking_operation
> * function. */
> thread = Glib::Threads::Thread::create(op_functor);
>
> /* Now set the text in the buffer. */
> gui_print("Operation started.\n");
>
> app->run(win);
> }
> };
>
> int main(int argc, char *argv[]) {
> Example example(argc, argv);
>
> example.run();
> return 0;
> }
> // Example 6