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