4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
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"
37 pthread_mutex_t BC_Display::display_lock = PTHREAD_MUTEX_INITIALIZER;
38 BC_Display* BC_Display::display_global = 0;
40 BC_Display::BC_Display(const char *display_name)
45 translation_events = 0;
49 // This function must be the first Xlib
50 // function a multi-threaded program calls
53 if(display_name && display_name[0] == 0) display_name = NULL;
54 if((display = XOpenDisplay(display_name)) == NULL)
56 printf("BC_Display::BC_Display: cannot connect to X server %s\n",
58 if(getenv("DISPLAY") == NULL)
60 printf(_("'DISPLAY' environment variable not set.\n"));
64 // Try again with default display.
66 if((display = XOpenDisplay(0)) == NULL)
68 printf("BC_Display::BC_Display: cannot connect to default X server.\n");
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);
81 // Start event handling
82 event_thread = new BC_WindowEvents(this);
83 event_thread->start();
86 event_lock = new Mutex("BC_Display::event_lock", 1);
87 event_condition = new Condition(0, "BC_Display::event_condition");
90 BC_Display::~BC_Display()
94 Display* BC_Display::get_display(const char *name)
96 pthread_mutex_lock(&display_lock);
99 display_global = new BC_Display(name);
101 pthread_mutex_unlock(&display_lock);
103 return display_global->display;
106 int BC_Display::is_first(BC_WindowBase *window)
110 if(windows.size() && windows.values[0] == window) result = 1;
115 void BC_Display::dump_windows()
117 for(int i = 0; i < windows.size(); i++) {
118 printf("BC_Display::dump_windows %d window=%p window->win=0x%08jx\n",
119 i, windows.get(i), windows.get(i)->win);
123 void BC_Display::new_window(BC_WindowBase *window)
125 //printf("BC_Display::new_window %d\n", __LINE__);
128 clipboard = new BC_Clipboard(window);
129 clipboard->start_clipboard();
132 //printf("BC_Display::new_window %d\n", __LINE__);
133 windows.append(window);
135 //printf("BC_Display::new_window %d\n", __LINE__);
138 void BC_Display::delete_window(BC_WindowBase *window)
140 //printf("BC_Display::delete_window %d\n", __LINE__);
141 windows.remove(window);
142 //printf("BC_Display::delete_window %d\n", __LINE__);
145 // If the event happened in any subwindow
146 int BC_Display::is_event_win(XEvent *event, BC_WindowBase *window)
148 Window event_win = event->xany.window;
149 //printf("BC_Display::is_event_win %d\n", __LINE__);
150 if(event_win == 0 || window->win == event_win) return 1;
151 //printf("BC_Display::is_event_win %d\n", __LINE__);
152 for(int i = 0; i < window->subwindows->size(); i++)
154 if(is_event_win(event, window->subwindows->get(i)))
156 //printf("BC_Display::is_event_win %d\n", __LINE__);
161 // Test popups in the main window only
162 if(window->window_type == MAIN_WINDOW)
164 // Not all events are handled by popups.
165 for(int i = 0; i < window->popups.size(); i++)
167 if(window->popups.get(i)->win == event_win &&
168 event->type != ConfigureNotify) return 1;
171 //printf("BC_Display::is_event_win %d\n", __LINE__);
175 void BC_Display::loop()
178 if(debug) printf("BC_Display::loop %d\n", __LINE__);
182 // If an event is waiting, process it now.
183 if(debug) printf("BC_Display::loop %d\n", __LINE__);
184 if(get_event_count())
186 if(debug) printf("BC_Display::loop %d\n", __LINE__);
188 if(debug) printf("BC_Display::loop %d\n", __LINE__);
191 // Otherwise, process all compressed events & get the next event.
193 if(debug) printf("BC_Display::loop %d\n", __LINE__);
194 lock_display("BC_Display::loop");
195 for(int i = 0; i < windows.size(); i++)
197 BC_WindowBase *window = windows.get(i);
198 if(debug) printf("BC_Display::loop %d %d %d %d\n",
200 window->resize_events,
201 window->motion_events,
202 window->translation_events);
203 if(window->resize_events)
204 window->dispatch_resize_event(window->last_resize_w,
205 window->last_resize_h);
206 if(window->motion_events)
207 window->dispatch_motion_event();
208 if(debug) printf("BC_Display::loop %d\n", __LINE__);
209 if(window->translation_events)
210 window->dispatch_translation_event();
212 if(debug) printf("BC_Display::loop %d\n", __LINE__);
214 if(debug) printf("BC_Display::loop %d\n", __LINE__);
217 if(debug) printf("BC_Display::loop %d\n", __LINE__);
220 if(debug) printf("BC_Display::loop %d\n", __LINE__);
223 void BC_Display::handle_event()
226 XEvent *event = get_event();
227 if(debug) printf("BC_Display::handle_event %d type=%d\n",
231 lock_display("BC_Display::handle_event");
232 if(debug) printf("BC_Display::handle_event %d\n", __LINE__);
233 for(int i = 0; i < windows.size(); i++)
235 // Test if event was inside window
236 if(debug) printf("BC_Display::handle_event %d\n", __LINE__);
237 BC_WindowBase *window = windows.get(i);
238 if(debug) printf("BC_Display::handle_event %d\n", __LINE__);
239 if(is_event_win(event, window))
241 window->dispatch_event(event);
242 if(debug) printf("BC_Display::handle_event %d\n", __LINE__);
244 if(debug) printf("BC_Display::handle_event %d\n", __LINE__);
246 if(debug) printf("BC_Display::handle_event %d\n", __LINE__);
249 if(debug) printf("BC_Display::handle_event %d\n", __LINE__);
252 // Get pending events for the given window
253 int BC_Display::get_event_count(BC_WindowBase *window)
256 event_lock->lock("BC_WindowBase::get_event_count 2");
257 for(int i = 0; i < common_events.size(); i++)
259 XEvent *event = common_events.get(i);
260 if(is_event_win(event, window)) result++;
262 event_lock->unlock();
266 int BC_Display::get_event_count()
268 event_lock->lock("BC_WindowBase::get_event_count 1");
269 int result = common_events.size();
270 event_lock->unlock();
274 XEvent* BC_Display::get_event()
277 while(!done && !result)
279 //printf("BC_Display::get_event %d\n", __LINE__);
280 event_condition->lock("BC_WindowBase::get_event");
281 //printf("BC_Display::get_event %d\n", __LINE__);
282 event_lock->lock("BC_WindowBase::get_event");
283 //printf("BC_Display::get_event %d\n", __LINE__);
285 if(common_events.total && !done)
287 result = common_events.values[0];
288 common_events.remove_number(0);
291 event_lock->unlock();
296 void BC_Display::put_event(XEvent *event)
298 event_lock->lock("BC_WindowBase::put_event");
299 common_events.append(event);
300 event_lock->unlock();
301 event_condition->unlock();
304 void BC_Display::set_repeat(BC_WindowBase *window, int64_t duration)
307 // test repeater database for duplicates
308 for(int i = 0; i < repeaters.total; i++)
310 // Matching delay already exists
311 if(repeaters.values[i]->delay == duration)
313 repeaters.values[i]->start_repeating(window);
318 BC_Repeater *repeater = new BC_Repeater(window, duration);
319 repeater->initialize();
320 repeaters.append(repeater);
321 repeater->start_repeating();
324 void BC_Display::unset_repeat(BC_WindowBase *window, int64_t duration)
326 for(int i = 0; i < repeaters.size(); i++)
328 if(repeaters.get(i)->delay == duration)
330 repeaters.get(i)->stop_repeating(window);
335 void BC_Display::unset_all_repeaters(BC_WindowBase *window)
337 for(int i = 0; i < repeaters.total; i++)
339 repeaters.values[i]->stop_all_repeating(window);
343 void BC_Display::arm_repeat(int64_t duration)
345 XEvent *event = BC_WindowBase::new_xevent();
346 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
347 event->xany.window = 0;
348 ptr->type = ClientMessage;
349 ptr->message_type = RepeaterXAtom;
351 ptr->data.l[0] = duration;
353 // Couldn't use XSendEvent since it locked up randomly.
357 void BC_Display::arm_completion(BC_WindowBase *window)
359 XEvent *event = BC_WindowBase::new_xevent();
360 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
361 event->xany.window = window->win;
362 event->type = ClientMessage;
363 ptr->message_type = SetDoneXAtom;
369 void BC_Display::unlock_repeaters(int64_t duration)
371 for(int i = 0; i < repeaters.size(); i++)
373 if(repeaters.get(i)->delay == duration)
375 repeaters.get(i)->repeat_lock->unlock();
381 void BC_Display::lock_display(const char *location)
383 pthread_mutex_lock(&BC_Display::display_lock);
384 ++BC_Display::display_global->window_locked;
385 pthread_mutex_unlock(&BC_Display::display_lock);
387 //printf("BC_Display::lock_display %d %s result=%d\n", __LINE__, location, result);
388 XLockDisplay(BC_Display::display_global->display);
391 void BC_Display::unlock_display()
393 pthread_mutex_lock(&BC_Display::display_lock);
394 --BC_Display::display_global->window_locked;
395 // if(BC_Display::display_global->window_locked < 0)
396 // BC_Display::display_global->window_locked = 0;
397 pthread_mutex_unlock(&BC_Display::display_lock);
399 //printf("BC_Display::unlock_display %d result=%d\n", __LINE__, result);
400 XUnlockDisplay(BC_Display::display_global->display);
404 int BC_Display::get_display_locked()
406 return BC_Display::display_global->window_locked;