remove whitespace at eol
[goodguy/history.git] / cinelerra-5.1 / guicast / bcdisplay.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 "bcclipboard.h"
23 #include "bcdisplay.h"
24 #include "bcrepeater.h"
25 #include "bcsignals.h"
26 #include "bcsubwindow.h"
27 #include "bcwindowbase.h"
28 #include "bcwindowevents.h"
29 #include "condition.h"
30 #include "language.h"
31 #include "mutex.h"
32
33 #include <pthread.h>
34
35 #ifdef SINGLE_THREAD
36
37 pthread_mutex_t BC_Display::display_lock = PTHREAD_MUTEX_INITIALIZER;
38 BC_Display* BC_Display::display_global = 0;
39
40 BC_Display::BC_Display(const char *display_name)
41 {
42         done = 0;
43         motion_events = 0;
44         resize_events = 0;
45         translation_events = 0;
46         window_locked = 0;
47         clipboard = 0;
48
49 // This function must be the first Xlib
50 // function a multi-threaded program calls
51         XInitThreads();
52
53         if(display_name && display_name[0] == 0) display_name = NULL;
54         if((display = XOpenDisplay(display_name)) == NULL)
55         {
56                 printf("BC_Display::BC_Display: cannot connect to X server %s\n",
57                         display_name);
58                 if(getenv("DISPLAY") == NULL)
59         {
60                         printf(_("'DISPLAY' environment variable not set.\n"));
61                         exit(1);
62                 }
63                 else
64 // Try again with default display.
65                 {
66                         if((display = XOpenDisplay(0)) == NULL)
67                         {
68                                 printf("BC_Display::BC_Display: cannot connect to default X server.\n");
69                                 exit(1);
70                         }
71                 }
72         }
73
74 // Create atoms for events
75         SetDoneXAtom = XInternAtom(display, "BC_REPEAT_EVENT", False);
76         RepeaterXAtom = XInternAtom(display, "BC_CLOSE_EVENT", False);
77         DelWinXAtom = XInternAtom(display, "WM_DELETE_WINDOW", False);
78         ProtoXAtom = XInternAtom(display, "WM_PROTOCOLS", False);
79
80
81 // Start event handling
82         event_thread = new BC_WindowEvents(this);
83         event_thread->start();
84
85
86         event_lock = new Mutex("BC_Display::event_lock", 1);
87         event_condition = new Condition(0, "BC_Display::event_condition");
88 }
89
90 BC_Display::~BC_Display()
91 {
92 }
93
94 Display* BC_Display::get_display(const char *name)
95 {
96         pthread_mutex_lock(&display_lock);
97         if(!display_global)
98         {
99                 display_global = new BC_Display(name);
100         }
101         pthread_mutex_unlock(&display_lock);
102
103         return display_global->display;
104 }
105
106 int BC_Display::is_first(BC_WindowBase *window)
107 {
108         int result = 0;
109
110         if(windows.size() && windows.values[0] == window) result = 1;
111
112         return result;
113 }
114
115 void BC_Display::dump_windows()
116 {
117         for(int i = 0; i < windows.size(); i++)
118         {
119                 printf("BC_Display::dump_windows %d window=%p window->win=%p\n",
120                         i,
121                         windows.get(i),
122                         windows.get(i)->win);
123         }
124 }
125
126 void BC_Display::new_window(BC_WindowBase *window)
127 {
128 //printf("BC_Display::new_window %d\n", __LINE__);
129         if(!clipboard)
130         {
131                 clipboard = new BC_Clipboard("");
132                 clipboard->start_clipboard();
133         }
134
135 //printf("BC_Display::new_window %d\n", __LINE__);
136         windows.append(window);
137 //      dump_windows();
138 //printf("BC_Display::new_window %d\n", __LINE__);
139 }
140
141 void BC_Display::delete_window(BC_WindowBase *window)
142 {
143 //printf("BC_Display::delete_window %d\n", __LINE__);
144         windows.remove(window);
145 //printf("BC_Display::delete_window %d\n", __LINE__);
146 }
147
148 // If the event happened in any subwindow
149 int BC_Display::is_event_win(XEvent *event, BC_WindowBase *window)
150 {
151         Window event_win = event->xany.window;
152 //printf("BC_Display::is_event_win %d\n", __LINE__);
153         if(event_win == 0 || window->win == event_win) return 1;
154 //printf("BC_Display::is_event_win %d\n", __LINE__);
155         for(int i = 0; i < window->subwindows->size(); i++)
156         {
157                 if(is_event_win(event, window->subwindows->get(i)))
158                 {
159 //printf("BC_Display::is_event_win %d\n", __LINE__);
160                         return 1;
161                 }
162         }
163
164 // Test popups in the main window only
165         if(window->window_type == MAIN_WINDOW)
166         {
167 // Not all events are handled by popups.
168                 for(int i = 0; i < window->popups.size(); i++)
169                 {
170                         if(window->popups.get(i)->win == event_win &&
171                                 event->type != ConfigureNotify) return 1;
172                 }
173         }
174 //printf("BC_Display::is_event_win %d\n", __LINE__);
175         return 0;
176 }
177
178 void BC_Display::loop()
179 {
180         const int debug = 0;
181 if(debug) printf("BC_Display::loop %d\n", __LINE__);
182
183         while(!done)
184         {
185 // If an event is waiting, process it now.
186 if(debug) printf("BC_Display::loop %d\n", __LINE__);
187                 if(get_event_count())
188                 {
189 if(debug) printf("BC_Display::loop %d\n", __LINE__);
190                         handle_event();
191 if(debug) printf("BC_Display::loop %d\n", __LINE__);
192                 }
193                 else
194 // Otherwise, process all compressed events & get the next event.
195                 {
196 if(debug) printf("BC_Display::loop %d\n", __LINE__);
197                         lock_display("BC_Display::loop");
198                         for(int i = 0; i < windows.size(); i++)
199                         {
200                                 BC_WindowBase *window = windows.get(i);
201 if(debug) printf("BC_Display::loop %d %d %d %d\n",
202 __LINE__,
203 window->resize_events,
204 window->motion_events,
205 window->translation_events);
206                                 if(window->resize_events)
207                                         window->dispatch_resize_event(window->last_resize_w,
208                                                 window->last_resize_h);
209                                 if(window->motion_events)
210                                         window->dispatch_motion_event();
211 if(debug) printf("BC_Display::loop %d\n", __LINE__);
212                                 if(window->translation_events)
213                                         window->dispatch_translation_event();
214                         }
215 if(debug) printf("BC_Display::loop %d\n", __LINE__);
216                         unlock_display();
217 if(debug) printf("BC_Display::loop %d\n", __LINE__);
218
219                         handle_event();
220 if(debug) printf("BC_Display::loop %d\n", __LINE__);
221                 }
222         }
223 if(debug) printf("BC_Display::loop %d\n", __LINE__);
224 }
225
226 void BC_Display::handle_event()
227 {
228 const int debug = 0;
229         XEvent *event = get_event();
230 if(debug)  printf("BC_Display::handle_event %d type=%d\n",
231 __LINE__,
232 event->type);
233
234         lock_display("BC_Display::handle_event");
235 if(debug) printf("BC_Display::handle_event %d\n", __LINE__);
236         for(int i = 0; i < windows.size(); i++)
237         {
238 // Test if event was inside window
239 if(debug) printf("BC_Display::handle_event %d\n", __LINE__);
240                 BC_WindowBase *window = windows.get(i);
241 if(debug) printf("BC_Display::handle_event %d\n", __LINE__);
242                 if(is_event_win(event, window))
243 // Dispatch event
244                         window->dispatch_event(event);
245 if(debug) printf("BC_Display::handle_event %d\n", __LINE__);
246         }
247 if(debug) printf("BC_Display::handle_event %d\n", __LINE__);
248         unlock_display();
249 if(debug) printf("BC_Display::handle_event %d\n", __LINE__);
250
251         delete event;
252 if(debug) printf("BC_Display::handle_event %d\n", __LINE__);
253 }
254
255 // Get pending events for the given window
256 int BC_Display::get_event_count(BC_WindowBase *window)
257 {
258         int result = 0;
259         event_lock->lock("BC_WindowBase::get_event_count 2");
260         for(int i = 0; i < common_events.size(); i++)
261         {
262                 XEvent *event = common_events.get(i);
263                 if(is_event_win(event, window)) result++;
264         }
265         event_lock->unlock();
266         return result;
267 }
268
269 int BC_Display::get_event_count()
270 {
271         event_lock->lock("BC_WindowBase::get_event_count 1");
272         int result = common_events.size();
273         event_lock->unlock();
274         return result;
275 }
276
277 XEvent* BC_Display::get_event()
278 {
279         XEvent *result = 0;
280         while(!done && !result)
281         {
282 //printf("BC_Display::get_event %d\n", __LINE__);
283                 event_condition->lock("BC_WindowBase::get_event");
284 //printf("BC_Display::get_event %d\n", __LINE__);
285                 event_lock->lock("BC_WindowBase::get_event");
286 //printf("BC_Display::get_event %d\n", __LINE__);
287
288                 if(common_events.total && !done)
289                 {
290                         result = common_events.values[0];
291                         common_events.remove_number(0);
292                 }
293
294                 event_lock->unlock();
295         }
296         return result;
297 }
298
299 void BC_Display::put_event(XEvent *event)
300 {
301         event_lock->lock("BC_WindowBase::put_event");
302         common_events.append(event);
303         event_lock->unlock();
304         event_condition->unlock();
305 }
306
307 void BC_Display::set_repeat(BC_WindowBase *window, int64_t duration)
308 {
309 return;
310 // test repeater database for duplicates
311         for(int i = 0; i < repeaters.total; i++)
312         {
313 // Matching delay already exists
314                 if(repeaters.values[i]->delay == duration)
315                 {
316                         repeaters.values[i]->start_repeating(window);
317                         return;
318                 }
319         }
320
321         BC_Repeater *repeater = new BC_Repeater(window, duration);
322         repeater->initialize();
323         repeaters.append(repeater);
324     repeater->start_repeating();
325 }
326
327 void BC_Display::unset_repeat(BC_WindowBase *window, int64_t duration)
328 {
329         for(int i = 0; i < repeaters.size(); i++)
330         {
331                 if(repeaters.get(i)->delay == duration)
332                 {
333                         repeaters.get(i)->stop_repeating(window);
334                 }
335         }
336 }
337
338 int BC_Display::unset_all_repeaters(BC_WindowBase *window)
339 {
340         for(int i = 0; i < repeaters.total; i++)
341         {
342                 repeaters.values[i]->stop_all_repeating(window);
343         }
344 }
345
346 void BC_Display::arm_repeat(int64_t duration)
347 {
348         XEvent *event = BC_WindowBase::new_xevent();
349         XClientMessageEvent *ptr = (XClientMessageEvent*)event;
350         event->xany.window = 0;
351         ptr->type = ClientMessage;
352         ptr->message_type = RepeaterXAtom;
353         ptr->format = 32;
354         ptr->data.l[0] = duration;
355
356 // Couldn't use XSendEvent since it locked up randomly.
357         put_event(event);
358 }
359
360 void BC_Display::arm_completion(BC_WindowBase *window)
361 {
362         XEvent *event = BC_WindowBase::new_xevent();
363         XClientMessageEvent *ptr = (XClientMessageEvent*)event;
364         event->xany.window = window->win;
365         event->type = ClientMessage;
366         ptr->message_type = SetDoneXAtom;
367         ptr->format = 32;
368
369         put_event(event);
370 }
371
372 void BC_Display::unlock_repeaters(int64_t duration)
373 {
374         for(int i = 0; i < repeaters.size(); i++)
375         {
376                 if(repeaters.get(i)->delay == duration)
377                 {
378                         repeaters.get(i)->repeat_lock->unlock();
379                 }
380         }
381 }
382
383
384 void BC_Display::lock_display(const char *location)
385 {
386         pthread_mutex_lock(&BC_Display::display_lock);
387         int result = ++BC_Display::display_global->window_locked;
388         pthread_mutex_unlock(&BC_Display::display_lock);
389
390 //printf("BC_Display::lock_display %d %s result=%d\n", __LINE__, location, result);
391         XLockDisplay(BC_Display::display_global->display);
392 }
393
394 void BC_Display::unlock_display()
395 {
396         pthread_mutex_lock(&BC_Display::display_lock);
397         int result = --BC_Display::display_global->window_locked;
398 //      if(BC_Display::display_global->window_locked < 0)
399 //              BC_Display::display_global->window_locked = 0;
400         pthread_mutex_unlock(&BC_Display::display_lock);
401
402 //printf("BC_Display::unlock_display %d result=%d\n", __LINE__, result);
403         /* if(result == 1) */ XUnlockDisplay(BC_Display::display_global->display);
404 }
405
406
407 int BC_Display::get_display_locked()
408 {
409         return BC_Display::display_global->window_locked;
410 }
411
412
413 #endif