smooth-gtk-thread.c 5.8 KB

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