smooth-gtk-thread.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2017, 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.haxx.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. /* printf("write_file\n"); */
  59. return fwrite(ptr, size, nmemb, stream);
  60. }
  61. /* https://weather.com/weather/today/l/46214?cc=*&dayf=5&unit=i */
  62. void *pull_one_url(void *NaN)
  63. {
  64. CURL *curl;
  65. CURLcode res;
  66. gchar *http;
  67. FILE *outfile;
  68. /* Stop threads from entering unless j is incremented */
  69. pthread_mutex_lock(&lock);
  70. while(j < num_urls) {
  71. printf("j = %d\n", j);
  72. http =
  73. g_strdup_printf("xoap.weather.com/weather/local/%s?cc=*&dayf=5&unit=i\n",
  74. urls[j]);
  75. printf("http %s", http);
  76. curl = curl_easy_init();
  77. if(curl) {
  78. outfile = fopen(urls[j], "wb");
  79. /* Set the URL and transfer type */
  80. curl_easy_setopt(curl, CURLOPT_URL, http);
  81. /* Write to the file */
  82. curl_easy_setopt(curl, CURLOPT_WRITEDATA, outfile);
  83. curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_file);
  84. j++; /* critical line */
  85. pthread_mutex_unlock(&lock);
  86. res = curl_easy_perform(curl);
  87. fclose(outfile);
  88. printf("fclose\n");
  89. curl_easy_cleanup(curl);
  90. }
  91. g_free(http);
  92. /* Adds more latency, testing the mutex.*/
  93. sleep(1);
  94. } /* end while */
  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 will be called again;
  103. * returning false removes this timeout function.
  104. */
  105. return TRUE;
  106. }
  107. void *create_thread(void *progress_bar)
  108. {
  109. pthread_t tid[NUMT];
  110. int i;
  111. int error;
  112. /* Make sure I don't create more threads than urls. */
  113. for(i = 0; i < NUMT && i < num_urls ; i++) {
  114. error = pthread_create(&tid[i],
  115. NULL, /* default attributes please */
  116. pull_one_url,
  117. NULL);
  118. if(0 != error)
  119. fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error);
  120. else
  121. fprintf(stderr, "Thread %d, gets %s\n", i, urls[i]);
  122. }
  123. /* Wait for all threads to terminate. */
  124. for(i = 0; i < NUMT && i < num_urls; i++) {
  125. error = pthread_join(tid[i], NULL);
  126. fprintf(stderr, "Thread %d terminated\n", i);
  127. }
  128. /* This stops the pulsing if you have it turned on in the progress bar
  129. section */
  130. g_source_remove(GPOINTER_TO_INT(g_object_get_data(G_OBJECT(progress_bar),
  131. "pulse_id")));
  132. /* This destroys the progress bar */
  133. gtk_widget_destroy(progress_bar);
  134. /* [Un]Comment this out to kill the program rather than pushing close. */
  135. /* gtk_main_quit(); */
  136. return NULL;
  137. }
  138. static gboolean cb_delete(GtkWidget *window, gpointer data)
  139. {
  140. gtk_main_quit();
  141. return FALSE;
  142. }
  143. int main(int argc, char **argv)
  144. {
  145. GtkWidget *top_window, *outside_frame, *inside_frame, *progress_bar;
  146. /* Must initialize libcurl before any threads are started */
  147. curl_global_init(CURL_GLOBAL_ALL);
  148. /* Init thread */
  149. g_thread_init(NULL);
  150. gdk_threads_init();
  151. gdk_threads_enter();
  152. gtk_init(&argc, &argv);
  153. /* Base window */
  154. top_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  155. /* Frame */
  156. outside_frame = gtk_frame_new(NULL);
  157. gtk_frame_set_shadow_type(GTK_FRAME(outside_frame), GTK_SHADOW_OUT);
  158. gtk_container_add(GTK_CONTAINER(top_window), outside_frame);
  159. /* Frame */
  160. inside_frame = gtk_frame_new(NULL);
  161. gtk_frame_set_shadow_type(GTK_FRAME(inside_frame), GTK_SHADOW_IN);
  162. gtk_container_set_border_width(GTK_CONTAINER(inside_frame), 5);
  163. gtk_container_add(GTK_CONTAINER(outside_frame), inside_frame);
  164. /* Progress bar */
  165. progress_bar = gtk_progress_bar_new();
  166. gtk_progress_bar_pulse(GTK_PROGRESS_BAR (progress_bar));
  167. /* Make uniform pulsing */
  168. gint pulse_ref = g_timeout_add(300, pulse_bar, progress_bar);
  169. g_object_set_data(G_OBJECT(progress_bar), "pulse_id",
  170. GINT_TO_POINTER(pulse_ref));
  171. gtk_container_add(GTK_CONTAINER(inside_frame), progress_bar);
  172. gtk_widget_show_all(top_window);
  173. printf("gtk_widget_show_all\n");
  174. g_signal_connect(G_OBJECT (top_window), "delete-event",
  175. G_CALLBACK(cb_delete), NULL);
  176. if(!g_thread_create(&create_thread, progress_bar, FALSE, NULL) != 0)
  177. g_warning("can't create the thread");
  178. gtk_main();
  179. gdk_threads_leave();
  180. printf("gdk_threads_leave\n");
  181. return 0;
  182. }