smooth-gtk-thread.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at https://curl.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * SPDX-License-Identifier: curl
  22. *
  23. ***************************************************************************/
  24. /* <DESC>
  25. * A multi threaded application that uses a progress bar to show
  26. * status. It uses Gtk+ to make a smooth pulse.
  27. * </DESC>
  28. */
  29. /*
  30. * Written by Jud Bishop after studying the other examples provided with
  31. * libcurl.
  32. *
  33. * To compile (on a single line):
  34. * gcc -ggdb `pkg-config --cflags --libs gtk+-2.0` -lcurl -lssl -lcrypto
  35. * -lgthread-2.0 -dl smooth-gtk-thread.c -o smooth-gtk-thread
  36. */
  37. #include <stdio.h>
  38. #include <gtk/gtk.h>
  39. #include <glib.h>
  40. #include <unistd.h>
  41. #include <pthread.h>
  42. #include <curl/curl.h>
  43. #define NUMT 4
  44. pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
  45. int j = 0;
  46. gint num_urls = 9; /* Just make sure this is less than urls[]*/
  47. const char * const urls[]= {
  48. "90022",
  49. "90023",
  50. "90024",
  51. "90025",
  52. "90026",
  53. "90027",
  54. "90028",
  55. "90029",
  56. "90030"
  57. };
  58. size_t write_file(void *ptr, size_t size, size_t nmemb, FILE *stream)
  59. {
  60. return fwrite(ptr, size, nmemb, stream);
  61. }
  62. static void run_one(gchar *http, int j)
  63. {
  64. FILE *outfile = fopen(urls[j], "wb");
  65. CURL *curl;
  66. curl = curl_easy_init();
  67. if(curl) {
  68. printf("j = %d\n", j);
  69. /* Set the URL and transfer type */
  70. curl_easy_setopt(curl, CURLOPT_URL, http);
  71. /* Write to the file */
  72. curl_easy_setopt(curl, CURLOPT_WRITEDATA, outfile);
  73. curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_file);
  74. curl_easy_perform(curl);
  75. fclose(outfile);
  76. curl_easy_cleanup(curl);
  77. }
  78. }
  79. void *pull_one_url(void *NaN)
  80. {
  81. /* protect the reading and increasing of 'j' with a mutex */
  82. pthread_mutex_lock(&lock);
  83. while(j < num_urls) {
  84. int i = j;
  85. j++;
  86. pthread_mutex_unlock(&lock);
  87. http = g_strdup_printf("https://example.com/%s", urls[i]);
  88. if(http) {
  89. run_one(http, i);
  90. g_free(http);
  91. }
  92. pthread_mutex_lock(&lock);
  93. }
  94. pthread_mutex_unlock(&lock);
  95. return NULL;
  96. }
  97. gboolean pulse_bar(gpointer data)
  98. {
  99. gdk_threads_enter();
  100. gtk_progress_bar_pulse(GTK_PROGRESS_BAR (data));
  101. gdk_threads_leave();
  102. /* Return true so the function is called again; returning false removes this
  103. * timeout function.
  104. */
  105. return TRUE;
  106. }
  107. void *create_thread(void *progress_bar)
  108. {
  109. pthread_t tid[NUMT];
  110. int i;
  111. /* Make sure I do not create more threads than urls. */
  112. for(i = 0; i < NUMT && i < num_urls ; i++) {
  113. int error = pthread_create(&tid[i],
  114. NULL, /* default attributes please */
  115. pull_one_url,
  116. NULL);
  117. if(0 != error)
  118. fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error);
  119. else
  120. fprintf(stderr, "Thread %d, gets %s\n", i, urls[i]);
  121. }
  122. /* Wait for all threads to terminate. */
  123. for(i = 0; i < NUMT && i < num_urls; i++) {
  124. pthread_join(tid[i], NULL);
  125. fprintf(stderr, "Thread %d terminated\n", i);
  126. }
  127. /* This stops the pulsing if you have it turned on in the progress bar
  128. section */
  129. g_source_remove(GPOINTER_TO_INT(g_object_get_data(G_OBJECT(progress_bar),
  130. "pulse_id")));
  131. /* This destroys the progress bar */
  132. gtk_widget_destroy(progress_bar);
  133. /* [Un]Comment this out to kill the program rather than pushing close. */
  134. /* gtk_main_quit(); */
  135. return NULL;
  136. }
  137. static gboolean cb_delete(GtkWidget *window, gpointer data)
  138. {
  139. gtk_main_quit();
  140. return FALSE;
  141. }
  142. int main(int argc, char **argv)
  143. {
  144. GtkWidget *top_window, *outside_frame, *inside_frame, *progress_bar;
  145. /* Must initialize libcurl before any threads are started */
  146. curl_global_init(CURL_GLOBAL_ALL);
  147. /* Init thread */
  148. g_thread_init(NULL);
  149. gdk_threads_init();
  150. gdk_threads_enter();
  151. gtk_init(&argc, &argv);
  152. /* Base window */
  153. top_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  154. /* Frame */
  155. outside_frame = gtk_frame_new(NULL);
  156. gtk_frame_set_shadow_type(GTK_FRAME(outside_frame), GTK_SHADOW_OUT);
  157. gtk_container_add(GTK_CONTAINER(top_window), outside_frame);
  158. /* Frame */
  159. inside_frame = gtk_frame_new(NULL);
  160. gtk_frame_set_shadow_type(GTK_FRAME(inside_frame), GTK_SHADOW_IN);
  161. gtk_container_set_border_width(GTK_CONTAINER(inside_frame), 5);
  162. gtk_container_add(GTK_CONTAINER(outside_frame), inside_frame);
  163. /* Progress bar */
  164. progress_bar = gtk_progress_bar_new();
  165. gtk_progress_bar_pulse(GTK_PROGRESS_BAR (progress_bar));
  166. /* Make uniform pulsing */
  167. gint pulse_ref = g_timeout_add(300, pulse_bar, progress_bar);
  168. g_object_set_data(G_OBJECT(progress_bar), "pulse_id",
  169. GINT_TO_POINTER(pulse_ref));
  170. gtk_container_add(GTK_CONTAINER(inside_frame), progress_bar);
  171. gtk_widget_show_all(top_window);
  172. printf("gtk_widget_show_all\n");
  173. g_signal_connect(G_OBJECT (top_window), "delete-event",
  174. G_CALLBACK(cb_delete), NULL);
  175. if(!g_thread_create(&create_thread, progress_bar, FALSE, NULL) != 0)
  176. g_warning("cannot create the thread");
  177. gtk_main();
  178. gdk_threads_leave();
  179. printf("gdk_threads_leave\n");
  180. return 0;
  181. }