initial commit
[goodguy/history.git] / cinelerra-5.0 / guicast / bcrepeater.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  * 
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * 
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  * 
20  */
21
22 #include "bcdisplay.h"
23 #include "bcrepeater.h"
24 #include "bcsignals.h"
25 #include "bcwindow.h"
26 #include "condition.h"
27
28 #include <unistd.h>
29
30 BC_Repeater::BC_Repeater(BC_WindowBase *window, long delay)
31  : Thread(1, 0, 0)
32 {
33         pause_lock = new Condition(0, "BC_Repeater::pause_lock");
34         startup_lock = new Condition(0, "BC_Repeater::startup_lock");
35         repeat_lock = new Condition(1, "BC_Repeater::repeat_lock");
36         repeating = 0;
37         interrupted = 0;
38         this->delay = delay;
39         windows.append(window);
40
41 }
42
43 BC_Repeater::~BC_Repeater()
44 {
45         interrupted = 1;
46         pause_lock->unlock();
47         repeat_lock->unlock();
48
49         Thread::cancel();
50         Thread::join();
51
52         delete pause_lock;
53         delete startup_lock;
54         delete repeat_lock;
55 }
56
57 void BC_Repeater::initialize()
58 {
59         start();
60 // This is important.  It doesn't unblock until the thread is running.
61         startup_lock->lock("BC_Repeater::initialize");
62 }
63
64 int BC_Repeater::start_repeating()
65 {
66 //printf("BC_Repeater::start_repeating 1 %d\n", delay);
67         repeating++;
68         if(repeating == 1)
69         {
70 // Resume the loop
71                 pause_lock->unlock();
72         }
73         return 0;
74 }
75
76 int BC_Repeater::stop_repeating()
77 {
78 // Recursive calling happens when mouse wheel is used.
79         if(repeating > 0)
80         {
81                 repeating--;
82 // Pause the loop
83                 if(repeating == 0) pause_lock->lock("BC_Repeater::stop_repeating");
84         }
85         return 0;
86 }
87
88 int BC_Repeater::start_repeating(BC_WindowBase *window)
89 {
90 // Test if the window already exists
91 //      for(int i = 0; i < windows.size(); i++)
92 //      {
93 //              if(windows.get(i) == window)
94 //              {
95 //                      return 0;
96 //              }
97 //      }
98 //printf("BC_Repeater::start_repeating 1 %d\n", delay);
99
100 // Add window to users
101         repeating++;
102         windows.append(window);
103         if(repeating == 1)
104         {
105 // Resume the loop
106                 pause_lock->unlock();
107         }
108         return 0;
109 }
110
111 int BC_Repeater::stop_repeating(BC_WindowBase *window)
112 {
113         for(int i = 0; i < windows.size(); i++)
114         {
115                 if(windows.get(i) == window)
116                 {
117 // Remove all entries of window
118                         windows.remove_number(i);
119                         i--;
120 // Recursive calling happens when mouse wheel is used.
121                         if(repeating > 0)
122                         {
123                                 repeating--;
124 // Pause the loop
125                                 if(repeating == 0)
126                                 {
127                                         pause_lock->lock("BC_Repeater::stop_repeating");
128                                         return 0;
129                                 }
130                         }
131                         break;
132                 }
133         }
134         return 0;
135 }
136
137 int BC_Repeater::stop_all_repeating(BC_WindowBase *window)
138 {
139         for(int i = 0; i < windows.size(); i++)
140         {
141                 if(windows.get(i) == window)
142                 {
143 // Remove all entries of window
144                         windows.remove_number(i);
145                         i--;
146 // Recursive calling happens when mouse wheel is used.
147                         if(repeating > 0)
148                         {
149                                 repeating--;
150 // Pause the loop
151                                 if(repeating == 0)
152                                 {
153                                         pause_lock->lock("BC_Repeater::stop_repeating");
154                                         return 0;
155                                 }
156                         }
157                 }
158         }
159         return 0;
160 }
161
162 void BC_Repeater::run()
163 {
164 //printf("BC_Repeater::run 1 %d\n", getpid());
165         next_delay = delay;
166         Thread::disable_cancel();
167         startup_lock->unlock();
168
169         while(!interrupted)
170         {
171                 Thread::enable_cancel();
172                 timer.delay(next_delay);
173                 Thread::disable_cancel();
174 //if(next_delay <= 0) printf("BC_Repeater::run delay=%d next_delay=%d\n", delay, next_delay);
175
176 // Test exit conditions
177                 if(interrupted) return;
178 // Busy wait here
179 //              if(repeating <= 0) continue;
180
181 // Test for pause
182                 pause_lock->lock("BC_Repeater::run");
183                 pause_lock->unlock();
184                 timer.update();
185
186 // Test exit conditions
187                 if(interrupted) return;
188                 if(repeating <= 0) continue;
189
190 // Wait for existing signal to be processed before sending a new one
191                 repeat_lock->lock("BC_Repeater::run");
192
193 // Test exit conditions
194                 if(interrupted)
195                 {
196                         repeat_lock->unlock();
197                         return;
198                 }
199                 if(repeating <= 0)
200                 {
201                         repeat_lock->unlock();
202                         continue;
203                 }
204
205 #ifdef SINGLE_THREAD
206                 BC_Display::display_global->lock_display("BC_Repeater::run");
207 // Test exit conditions again
208                 if(interrupted)
209                 {
210                         repeat_lock->unlock();
211                         BC_Display::display_global->unlock_display();
212                         return;
213                 }
214                 if(repeating <= 0)
215                 {
216                         repeat_lock->unlock();
217                         BC_Display::display_global->unlock_display();
218                         continue;
219                 }
220
221 // Stick event into queue
222                 BC_Display::display_global->arm_repeat(delay);
223                 BC_Display::display_global->unlock_display();
224 #else
225 // Wait for window to become available.
226                 windows.get(0)->lock_window("BC_Repeater::run");
227
228 // Test exit conditions again
229                 if(interrupted)
230                 {
231                         repeat_lock->unlock();
232                         windows.get(0)->unlock_window();
233                         return;
234                 }
235                 if(repeating <= 0)
236                 {
237                         repeat_lock->unlock();
238                         windows.get(0)->unlock_window();
239                         continue;
240                 }
241
242 // Stick event into queue
243                 windows.get(0)->arm_repeat(delay);
244                 windows.get(0)->unlock_window();
245 #endif
246
247
248
249                 next_delay = delay - timer.get_difference();
250                 if(next_delay <= 0) next_delay = 0;
251
252 // Test exit conditions
253                 if(interrupted) 
254                 {
255                         repeat_lock->unlock();
256                         return;
257                 }
258                 if(repeating <= 0)
259                 {
260                         repeat_lock->unlock();
261                         continue;
262                 }
263         }
264 }