merge hv v6, rework trace methods
[goodguy/history.git] / cinelerra-5.1 / guicast / bcwindowbase.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 "bcbitmap.h"
23 #include "bcclipboard.h"
24 #include "bcdisplay.h"
25 #include "bcdisplayinfo.h"
26 #include "bcmenubar.h"
27 #include "bcpixmap.h"
28 #include "bcpopup.h"
29 #include "bcpopupmenu.h"
30 #include "bcrepeater.h"
31 #include "bcresources.h"
32 #include "bcsignals.h"
33 #include "bcsubwindow.h"
34 #include "bcsynchronous.h"
35 #include "bctimer.h"
36 #include "bcwindowbase.h"
37 #include "bcwindowevents.h"
38 #include "bccmodels.h"
39 #include "colors.h"
40 #include "condition.h"
41 #include "cursors.h"
42 #include "bchash.h"
43 #include "fonts.h"
44 #include "keys.h"
45 #include "language.h"
46 #include "mutex.h"
47 #include "sizes.h"
48 #include "vframe.h"
49
50 #ifdef HAVE_GL
51 #include <GL/gl.h>
52 #endif
53 #include <string.h>
54 #include <unistd.h>
55 #include <wchar.h>
56 #include <typeinfo>
57
58 #include <X11/extensions/Xinerama.h>
59 #include <X11/extensions/Xvlib.h>
60 #include <X11/extensions/shape.h>
61 #include <X11/XF86keysym.h>
62 #include <X11/Sunkeysym.h>
63
64
65 BC_ResizeCall::BC_ResizeCall(int w, int h)
66 {
67         this->w = w;
68         this->h = h;
69 }
70
71
72
73
74
75
76
77 int BC_WindowBase::shm_completion_event = -1;
78
79
80
81 BC_Resources BC_WindowBase::resources;
82
83 Window XGroupLeader = 0;
84
85 Mutex BC_KeyboardHandlerLock::keyboard_listener_mutex("keyboard_listener",0);
86 ArrayList<BC_KeyboardHandler*> BC_KeyboardHandler::listeners;
87
88 BC_WindowBase::BC_WindowBase(int opts)
89 {
90         this->options = opts;
91 //printf("BC_WindowBase::BC_WindowBase 1\n");
92         BC_WindowBase::initialize();
93 }
94
95 BC_WindowBase::~BC_WindowBase()
96 {
97 #ifdef SINGLE_THREAD
98         BC_Display::lock_display("BC_WindowBase::~BC_WindowBase");
99 #else
100         if(window_type == MAIN_WINDOW)
101                 lock_window("BC_WindowBase::~BC_WindowBase");
102 #endif
103
104 #ifdef HAVE_LIBXXF86VM
105         if(window_type == VIDMODE_SCALED_WINDOW && vm_switched) {
106                 restore_vm();
107         }
108 #endif
109         is_deleting = 1;
110
111         hide_tooltip();
112         if(window_type != MAIN_WINDOW)
113         {
114 // stop event input
115                 XSelectInput(top_level->display, this->win, 0);
116                 motion_events = resize_events = translation_events = 0;
117 #ifndef SINGLE_THREAD
118                 top_level->dequeue_events(win);
119 #endif
120                 if(top_level->active_menubar == this) top_level->active_menubar = 0;
121                 if(top_level->active_popup_menu == this) top_level->active_popup_menu = 0;
122                 if(top_level->active_subwindow == this) top_level->active_subwindow = 0;
123 // Remove pointer from parent window to this
124                 parent_window->subwindows->remove(this);
125         }
126
127         if(icon_window) delete icon_window;
128         if(window_type == POPUP_WINDOW)
129                 parent_window->remove_popup(this);
130
131 // Delete the subwindows
132         if(subwindows)
133         {
134                 while(subwindows->total)
135                 {
136 // Subwindow removes its own pointer
137                         delete subwindows->values[0];
138                 }
139                 delete subwindows;
140         }
141
142         delete pixmap;
143
144 #ifdef HAVE_GL
145         if( get_resources()->get_synchronous() &&
146                 (top_level->options & GLX_WINDOW) && glx_win != 0 )
147                 get_resources()->get_synchronous()->delete_window(this);
148         else
149 #endif
150                 XDestroyWindow(top_level->display, win);
151
152         if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
153         if(icon_pixmap) delete icon_pixmap;
154         if(temp_bitmap) delete temp_bitmap;
155         top_level->active_bitmaps.remove_buffers(this);
156         if(_7segment_pixmaps)
157         {
158                 for(int i = 0; i < TOTAL_7SEGMENT; i++)
159                         delete _7segment_pixmaps[i];
160
161                 delete [] _7segment_pixmaps;
162         }
163
164
165
166         if(window_type == MAIN_WINDOW)
167         {
168                 XFreeGC(display, gc);
169                 static XFontStruct *BC_WindowBase::*xfont[] = {
170                          &BC_WindowBase::smallfont,
171                          &BC_WindowBase::mediumfont,
172                          &BC_WindowBase::largefont,
173                          &BC_WindowBase::bigfont,
174                 };
175                 for( int i=sizeof(xfont)/sizeof(xfont[0]); --i>=0; )
176                         XFreeFont(display, this->*xfont[i]);
177
178 // bug in X causes XRenderExtensionInfo to be damaged if this is done here
179 //  left to be done in XCloseDisplay by Xlib.
180 #if defined(HAVE_XFT) && 0
181                 static void *BC_WindowBase::*xft_font[] = {
182                          &BC_WindowBase::smallfont_xft,
183                          &BC_WindowBase::mediumfont_xft,
184                          &BC_WindowBase::largefont_xft,
185                          &BC_WindowBase::bigfont_xft,
186                          &BC_WindowBase::bold_smallfont_xft,
187                          &BC_WindowBase::bold_mediumfont_xft,
188                          &BC_WindowBase::bold_largefont_xft,
189                 };
190                 for( int i=sizeof(xft_font)/sizeof(xft_font[0]); --i>=0; ) {
191                         XftFont *xft = (XftFont *)(this->*xft_font[i]);
192                         if( xft ) XftFontClose (display, xft);
193                 }
194 #endif
195                 finit_im();
196                 flush();
197                 sync_display();
198
199                 if( xinerama_info )
200                         XFree(xinerama_info);
201                 xinerama_screens = 0;
202                 xinerama_info = 0;
203                 if( xvideo_port_id >= 0 )
204                         XvUngrabPort(display, xvideo_port_id, CurrentTime);
205
206                 unlock_window();
207 // Can't close display if another thread is waiting for events.
208 // Synchronous thread must delete display it owns a GLX_WINDOW
209 // Must be last reference to display.
210 #ifndef SINGLE_THREAD
211 #ifdef HAVE_GL
212                 if( (options & GLX_DISPLAY) != 0 && get_resources()->get_synchronous() ) {
213                         printf(_("BC_WindowBase::~BC_WindowBase window deleted but opengl deletion is not\n"
214                                 "implemented for BC_Pixmap.\n"));
215                         get_resources()->get_synchronous()->delete_display(this);
216                 }
217                 else
218 #endif
219                         XCloseDisplay(display);
220 // clipboard uses a different display connection
221                 clipboard->stop_clipboard();
222                 delete clipboard;
223 #endif // SINGLE_THREAD
224         }
225
226         resize_history.remove_all_objects();
227
228 #ifndef SINGLE_THREAD
229         common_events.remove_all_objects();
230         delete event_lock;
231         delete event_condition;
232         delete init_lock;
233 #else
234         top_level->window_lock = 0;
235         BC_Display::unlock_display();
236 #endif
237         delete cursor_timer;
238
239 #if HAVE_GL
240         if( glx_fbcfgs_window ) XFree(glx_fbcfgs_window);
241         if( glx_fbcfgs_pbuffer) XFree(glx_fbcfgs_pbuffer);
242         if( glx_fbcfgs_pixmap ) XFree(glx_fbcfgs_pixmap);
243 #endif
244
245         UNSET_ALL_LOCKS(this)
246 }
247
248 int BC_WindowBase::initialize()
249 {
250         done = 0;
251         done_set = 0;
252         window_running = 0;
253         display_lock_owner = 0;
254         test_keypress = 0;
255         keys_return[0] = 0;
256         is_deleting = 0;
257         window_lock = 0;
258         x = 0;
259         y = 0;
260         w = 0;
261         h = 0;
262         bg_color = -1;
263         line_width = 1;
264         line_dashes = 0;
265         top_level = 0;
266         parent_window = 0;
267         subwindows = 0;
268         xinerama_info = 0;
269         xinerama_screens = 0;
270         xvideo_port_id = -1;
271         video_on = 0;
272         motion_events = 0;
273         resize_events = 0;
274         translation_events = 0;
275         ctrl_mask = shift_mask = alt_mask = 0;
276         cursor_x = cursor_y = button_number = 0;
277         button_down = 0;
278         button_pressed = 0;
279         button_time1 = 0;
280         button_time2 = 0;
281         button_time3 = 0;
282         double_click = 0;
283         triple_click = 0;
284         event_win = 0;
285         last_motion_win = 0;
286         key_pressed = 0;
287         active_menubar = 0;
288         active_popup_menu = 0;
289         active_subwindow = 0;
290         pixmap = 0;
291         bg_pixmap = 0;
292         _7segment_pixmaps = 0;
293         tooltip_text = 0;
294         force_tooltip = 0;
295 //      next_repeat_id = 0;
296         tooltip_popup = 0;
297         tooltip_done = 0;
298         current_font = MEDIUMFONT;
299         current_color = BLACK;
300         current_cursor = ARROW_CURSOR;
301         hourglass_total = 0;
302         is_dragging = 0;
303         shared_bg_pixmap = 0;
304         icon_pixmap = 0;
305         icon_window = 0;
306         window_type = MAIN_WINDOW;
307         translation_count = 0;
308         x_correction = y_correction = 0;
309         temp_bitmap = 0;
310         tooltip_on = 0;
311         temp_cursor = 0;
312         toggle_value = 0;
313         toggle_drag = 0;
314         has_focus = 0;
315         is_hourglass = 0;
316         is_transparent = 0;
317 #ifdef HAVE_LIBXXF86VM
318         vm_switched = 0;
319 #endif
320         smallfont_xft = 0;
321         bold_largefont_xft = 0;
322         bold_mediumfont_xft = 0;
323         bold_smallfont_xft = 0;
324         input_method = 0;
325         input_context = 0;
326
327         mediumfont_xft = 0;
328         largefont_xft = 0;
329         bigfont_xft = 0;
330 #ifdef SINGLE_THREAD
331         completion_lock = new Condition(0, "BC_WindowBase::completion_lock");
332 #else
333 // Need these right away since put_event is called before run_window sometimes.
334         event_lock = new Mutex("BC_WindowBase::event_lock");
335         event_condition = new Condition(0, "BC_WindowBase::event_condition");
336         init_lock = new Condition(0, "BC_WindowBase::init_lock");
337 #endif
338
339         cursor_timer = new Timer;
340         event_thread = 0;
341 #ifdef HAVE_GL
342         glx_fbcfgs_window = 0;  n_fbcfgs_window = 0;
343         glx_fbcfgs_pbuffer = 0; n_fbcfgs_pbuffer = 0;
344         glx_fbcfgs_pixmap = 0;  n_fbcfgs_pixmap = 0;
345
346         glx_fb_config = 0;
347         glx_win_context = 0;
348         glx_win = 0;
349 #endif
350
351         flash_enabled = 1;
352         win = 0;
353         return 0;
354 }
355
356
357
358 #define DEFAULT_EVENT_MASKS EnterWindowMask | \
359                         LeaveWindowMask | \
360                         ButtonPressMask | \
361                         ButtonReleaseMask | \
362                         PointerMotionMask | \
363                         FocusChangeMask
364
365
366 int BC_WindowBase::create_window(BC_WindowBase *parent_window,
367                                 const char *title,
368                                 int x,
369                                 int y,
370                                 int w,
371                                 int h,
372                                 int minw,
373                                 int minh,
374                                 int allow_resize,
375                                 int private_color,
376                                 int hide,
377                                 int bg_color,
378                                 const char *display_name,
379                                 int window_type,
380                                 BC_Pixmap *bg_pixmap,
381                                 int group_it)
382 {
383         XSetWindowAttributes attr;
384         unsigned long mask;
385         XSizeHints size_hints;
386         int root_w;
387         int root_h;
388 #ifdef HAVE_LIBXXF86VM
389         int vm;
390 #endif
391
392         id = get_resources()->get_id();
393         int need_lock = 0;
394         if(parent_window) top_level = parent_window->top_level;
395         if( top_level ) { // need this to avoid deadlock with Xlib's locks
396                 need_lock = 1;
397                 lock_window("BC_WindowBase::create_window");
398         }
399         get_resources()->create_window_lock->lock("BC_WindowBase::create_window");
400
401 #ifdef HAVE_LIBXXF86VM
402         if(window_type == VIDMODE_SCALED_WINDOW)
403                 closest_vm(&vm,&w,&h);
404 #endif
405
406         this->x = x;
407         this->y = y;
408         this->w = w;
409         this->h = h;
410         this->bg_color = bg_color;
411         this->window_type = window_type;
412         this->hidden = hide;
413         this->private_color = private_color;
414         this->parent_window = parent_window;
415         this->bg_pixmap = bg_pixmap;
416         this->allow_resize = allow_resize;
417         if(display_name)
418                 strcpy(this->display_name, display_name);
419         else
420                 this->display_name[0] = 0;
421
422         put_title(_(title));
423         if(bg_pixmap) shared_bg_pixmap = 1;
424
425         subwindows = new BC_SubWindowList;
426
427         if(window_type == MAIN_WINDOW)
428         {
429                 top_level = this;
430                 parent_window = this;
431
432
433 #ifdef SINGLE_THREAD
434                 display = BC_Display::get_display(display_name);
435                 BC_Display::lock_display("BC_WindowBase::create_window");
436 //              BC_Display::display_global->new_window(this);
437 #else
438
439 // get the display connection
440
441 // This function must be the first Xlib
442 // function a multi-threaded program calls
443                 XInitThreads();
444                 display = init_display(display_name);
445                 if( shm_completion_event < 0 ) shm_completion_event =
446                         ShmCompletion + XShmGetEventBase(display);
447 #endif
448
449                 screen = DefaultScreen(display);
450                 rootwin = RootWindow(display, screen);
451 // window placement boundaries
452                 if( !xinerama_screens && XineramaIsActive(display) )
453                         xinerama_info = XineramaQueryScreens(display, &xinerama_screens);
454                 root_w = get_root_w(0);
455                 root_h = get_root_h(0);
456
457 #if HAVE_GL
458                 vis = get_glx_visual(display);
459                 if( !vis )
460 #endif
461                         vis = DefaultVisual(display, screen);
462
463                 default_depth = DefaultDepth(display, screen);
464
465                 client_byte_order = (*(const u_int32_t*)"a   ") & 0x00000001;
466                 server_byte_order = (XImageByteOrder(display) == MSBFirst) ? 0 : 1;
467
468
469 // This must be done before fonts to know if antialiasing is available.
470                 init_colors();
471 // get the resources
472                 if(resources.use_shm < 0) resources.initialize_display(this);
473                 x_correction = BC_DisplayInfo::get_left_border();
474                 y_correction = BC_DisplayInfo::get_top_border();
475
476 // clamp window placement
477                 if(this->x + this->w + x_correction > root_w)
478                         this->x = root_w - this->w - x_correction;
479                 if(this->y + this->h + y_correction > root_h)
480                         this->y = root_h - this->h - y_correction;
481                 if(this->x < 0) this->x = 0;
482                 if(this->y < 0) this->y = 0;
483
484                 if(this->bg_color == -1)
485                         this->bg_color = resources.get_bg_color();
486
487 // printf("bcwindowbase 1 %s\n", title);
488 // if(window_type == MAIN_WINDOW) sleep(1);
489 // printf("bcwindowbase 10\n");
490                 init_fonts();
491                 init_gc();
492                 init_cursors();
493
494 // Create the window
495                 mask = CWEventMask | CWBackPixel | CWColormap | CWCursor;
496
497                 attr.event_mask = DEFAULT_EVENT_MASKS |
498                         StructureNotifyMask |
499                         KeyPressMask |
500                         KeyReleaseMask;
501
502                 attr.background_pixel = get_color(this->bg_color);
503                 attr.colormap = cmap;
504                 attr.cursor = get_cursor_struct(ARROW_CURSOR);
505
506                 win = XCreateWindow(display, rootwin,
507                         this->x, this->y, this->w, this->h, 0,
508                         top_level->default_depth, InputOutput,
509                         vis, mask, &attr);
510                 XGetNormalHints(display, win, &size_hints);
511
512                 size_hints.flags = PSize | PMinSize | PMaxSize;
513                 size_hints.width = this->w;
514                 size_hints.height = this->h;
515                 size_hints.min_width = allow_resize ? minw : this->w;
516                 size_hints.max_width = allow_resize ? 32767 : this->w;
517                 size_hints.min_height = allow_resize ? minh : this->h;
518                 size_hints.max_height = allow_resize ? 32767 : this->h;
519                 if(x > -BC_INFINITY && x < BC_INFINITY)
520                 {
521                         size_hints.flags |= PPosition;
522                         size_hints.x = this->x;
523                         size_hints.y = this->y;
524                 }
525
526                 char *txlist[2];
527                 txlist[0] = this->title;
528                 txlist[1] = 0;
529                 XTextProperty titleprop;
530                 if(options & WINDOW_UTF8)
531                         Xutf8TextListToTextProperty(display, txlist,  1,
532                                 XUTF8StringStyle, &titleprop);
533                 else
534                         XmbTextListToTextProperty(display, txlist, 1,
535                                 XStdICCTextStyle, &titleprop);
536                 XSetWMProperties(display, win, &titleprop, &titleprop,
537                         0, 0, &size_hints, 0, 0);
538                 XFree(titleprop.value);
539                 get_atoms();
540
541 #ifndef SINGLE_THREAD
542                 clipboard = new BC_Clipboard(display_name);
543                 clipboard->start_clipboard();
544 #endif
545
546
547                 if (group_it)
548                 {
549                         Atom ClientLeaderXAtom;
550                         if (XGroupLeader == 0)
551                                 XGroupLeader = win;
552                         const char *instance_name = "cinelerra";
553                         const char *class_name = "Cinelerra";
554                         XClassHint *class_hints = XAllocClassHint();
555                         class_hints->res_name = (char*)instance_name;
556                         class_hints->res_class = (char*)class_name;
557                         XSetClassHint(top_level->display, win, class_hints);
558                         XFree(class_hints);
559                         ClientLeaderXAtom = XInternAtom(display, "WM_CLIENT_LEADER", True);
560                         XChangeProperty(display, win, ClientLeaderXAtom, XA_WINDOW, 32,
561                                 PropModeReplace, (unsigned char *)&XGroupLeader, true);
562                 }
563                 init_im();
564         }
565
566 #ifdef HAVE_LIBXXF86VM
567         if(window_type == VIDMODE_SCALED_WINDOW && vm != -1)
568         {
569                 scale_vm (vm);
570                 vm_switched = 1;
571         }
572 #endif
573
574 #ifdef HAVE_LIBXXF86VM
575         if(window_type == POPUP_WINDOW || window_type == VIDMODE_SCALED_WINDOW)
576 #else
577         if(window_type == POPUP_WINDOW)
578 #endif
579         {
580                 mask = CWEventMask | CWBackPixel | CWColormap |
581                         CWOverrideRedirect | CWSaveUnder | CWCursor;
582
583                 attr.event_mask = DEFAULT_EVENT_MASKS |
584                         KeyPressMask |
585                         KeyReleaseMask;
586
587                 if(this->bg_color == -1)
588                         this->bg_color = resources.get_bg_color();
589                 attr.background_pixel = top_level->get_color(bg_color);
590                 attr.colormap = top_level->cmap;
591                 if(top_level->is_hourglass)
592                         attr.cursor = top_level->get_cursor_struct(HOURGLASS_CURSOR);
593                 else
594                         attr.cursor = top_level->get_cursor_struct(ARROW_CURSOR);
595                 attr.override_redirect = True;
596                 attr.save_under = True;
597
598                 win = XCreateWindow(top_level->display,
599                         top_level->rootwin, this->x, this->y, this->w, this->h, 0,
600                         top_level->default_depth, InputOutput, top_level->vis, mask,
601                         &attr);
602                 top_level->add_popup(this);
603         }
604
605         if(window_type == SUB_WINDOW)
606         {
607                 mask = CWEventMask | CWBackPixel | CWCursor;
608                 attr.event_mask = DEFAULT_EVENT_MASKS;
609                 attr.background_pixel = top_level->get_color(this->bg_color);
610                 if(top_level->is_hourglass)
611                         attr.cursor = top_level->get_cursor_struct(HOURGLASS_CURSOR);
612                 else
613                         attr.cursor = top_level->get_cursor_struct(ARROW_CURSOR);
614                 win = XCreateWindow(top_level->display,
615                         parent_window->win, this->x, this->y, this->w, this->h, 0,
616                         top_level->default_depth, InputOutput, top_level->vis, mask,
617                         &attr);
618                 init_window_shape();
619                 if(!hidden) XMapWindow(top_level->display, win);
620         }
621
622 // Create pixmap for all windows
623         pixmap = new BC_Pixmap(this, this->w, this->h);
624
625 // Set up options for main window
626         if(window_type == MAIN_WINDOW)
627         {
628                 if(get_resources()->bg_image && !bg_pixmap && bg_color < 0)
629                 {
630                         this->bg_pixmap = new BC_Pixmap(this,
631                                 get_resources()->bg_image,
632                                 PIXMAP_OPAQUE);
633                 }
634
635                 if(!hidden) show_window();
636
637         }
638
639         draw_background(0, 0, this->w, this->h);
640
641         flash(-1, -1, -1, -1, 0);
642
643 // Set up options for popup window
644 #ifdef HAVE_LIBXXF86VM
645         if(window_type == POPUP_WINDOW || window_type == VIDMODE_SCALED_WINDOW)
646 #else
647         if(window_type == POPUP_WINDOW)
648 #endif
649         {
650                 init_window_shape();
651                 if(!hidden) show_window();
652         }
653         get_resources()->create_window_lock->unlock();
654         if(need_lock) unlock_window();
655
656         return 0;
657 }
658
659 Display* BC_WindowBase::init_display(const char *display_name)
660 {
661         Display* display;
662
663         if(display_name && display_name[0] == 0) display_name = NULL;
664         if((display = XOpenDisplay(display_name)) == NULL) {
665                 printf("BC_WindowBase::init_display: cannot connect to X server %s\n",
666                         display_name);
667                 if(getenv("DISPLAY") == NULL) {
668                         printf(_("'DISPLAY' environment variable not set.\n"));
669                         exit(1);
670                 }
671                 else {
672 // Try again with default display.
673                         if((display = XOpenDisplay(0)) == NULL) {
674                                 printf("BC_WindowBase::init_display: cannot connect to default X server.\n");
675                                 exit(1);
676                         }
677                 }
678         }
679         return display;
680 }
681
682 Display* BC_WindowBase::get_display()
683 {
684         return top_level->display;
685 }
686
687 int BC_WindowBase::get_screen()
688 {
689         return top_level->screen;
690 }
691
692 int BC_WindowBase::run_window()
693 {
694         done_set = done = 0;
695         return_value = 0;
696
697
698 // Events may have been sent before run_window so can't initialize them here.
699
700 #ifdef SINGLE_THREAD
701         set_repeat(get_resources()->tooltip_delay);
702         BC_Display::display_global->new_window(this);
703
704 // If the first window created, run the display loop in this thread.
705         if(BC_Display::display_global->is_first(this))
706         {
707                 BC_Display::unlock_display();
708                 BC_Display::display_global->loop();
709         }
710         else
711         {
712                 BC_Display::unlock_display();
713                 completion_lock->lock("BC_WindowBase::run_window");
714         }
715
716         BC_Display::lock_display("BC_WindowBase::run_window");
717         BC_Display::display_global->delete_window(this);
718
719         unset_all_repeaters();
720         hide_tooltip();
721         BC_Display::unlock_display();
722
723 #else // SINGLE_THREAD
724
725
726
727 // Start tooltips
728         set_repeat(get_resources()->tooltip_delay);
729
730 // Start X server events
731         event_thread = new BC_WindowEvents(this);
732         event_thread->start();
733
734 // Release wait lock
735         window_running = 1;
736         init_lock->unlock();
737
738 // Handle common events
739         while(!done)
740         {
741                 dispatch_event(0);
742         }
743
744         unset_all_repeaters();
745         hide_tooltip();
746         delete event_thread;
747         event_thread = 0;
748         event_condition->reset();
749         common_events.remove_all_objects();
750         window_running = 0;
751         done = 0;
752
753 #endif // SINGLE_THREAD
754
755         return return_value;
756 }
757
758 int BC_WindowBase::get_key_masks(unsigned int key_state)
759 {
760 // printf("BC_WindowBase::get_key_masks %llx\n",
761 // event->xkey.state);
762         ctrl_mask = (key_state & ControlMask) ? 1 : 0;  // ctrl key down
763         shift_mask = (key_state & ShiftMask) ? 1 : 0;   // shift key down
764         alt_mask = (key_state & Mod1Mask) ? 1 : 0;      // alt key down
765         return 0;
766 }
767
768
769 void BC_WindowBase::add_keyboard_listener(int(BC_WindowBase::*handler)(BC_WindowBase *))
770 {
771         BC_KeyboardHandlerLock set;
772         BC_KeyboardHandler::listeners.append(new BC_KeyboardHandler(handler, this));
773 }
774
775 void BC_WindowBase::del_keyboard_listener(int(BC_WindowBase::*handler)(BC_WindowBase *))
776 {
777         BC_KeyboardHandlerLock set;
778         int i = BC_KeyboardHandler::listeners.size();
779         while( --i >= 0 && BC_KeyboardHandler::listeners[i]->handler!=handler );
780         if( i >= 0 ) BC_KeyboardHandler::listeners.remove_object_number(i);
781 }
782
783 int BC_KeyboardHandler::run_event(BC_WindowBase *wp)
784 {
785         int result = (win->*handler)(wp);
786         return result;
787 }
788
789 int BC_KeyboardHandler::run_listeners(BC_WindowBase *wp)
790 {
791         int result = 0;
792         BC_KeyboardHandlerLock set;
793         for( int i=0; !result && i<listeners.size(); ++i ) {
794                 BC_KeyboardHandler *listener = listeners[i];
795                 result = listener->run_event(wp);
796         }
797         return result;
798 }
799
800 void BC_KeyboardHandler::kill_grabs()
801 {
802         BC_KeyboardHandlerLock set;
803         for( int i=0; i<listeners.size(); ++i ) {
804                 BC_WindowBase *win = listeners[i]->win;
805                 if( win->get_window_type() != POPUP_WINDOW ) continue;
806                 ((BC_Popup *)win)->ungrab_keyboard();
807         }
808 }
809
810 void BC_ActiveBitmaps::reque(XEvent *event)
811 {
812         XShmCompletionEvent *shm_ev = (XShmCompletionEvent *)event;
813         ShmSeg shmseg = shm_ev->shmseg;
814         Drawable drawable = shm_ev->drawable;
815 //printf("BC_BitmapImage::reque %08lx\n",shmseg);
816         active_lock.lock("BC_BitmapImage::reque");
817         BC_BitmapImage *bfr = first;
818         while( bfr && bfr->get_shmseg() != shmseg ) bfr = bfr->next;
819         if( bfr && bfr->drawable == drawable )
820                 remove_pointer(bfr);
821         active_lock.unlock();
822         if( !bfr ) {
823 // sadly, X reports two drawable completions and creates false reporting, so no boobytrap
824 //              printf("BC_BitmapImage::reque missed shmseg %08x, drawable %08x\n",
825 //                       (int)shmseg, (int)drawable);
826                 return;
827         }
828         if( bfr->drawable != drawable ) return;
829         if( bfr->is_zombie() ) { --BC_Bitmap::zombies; delete bfr; return; }
830         bfr->bitmap->reque(bfr);
831 }
832
833 void BC_ActiveBitmaps::insert(BC_BitmapImage *bfr, Drawable pixmap)
834 {
835         active_lock.lock("BC_BitmapImage::insert");
836         bfr->drawable = pixmap;
837         append(bfr);
838         active_lock.unlock();
839 }
840
841 void BC_ActiveBitmaps::remove_buffers(BC_WindowBase *wdw)
842 {
843         active_lock.lock("BC_ActiveBitmaps::remove");
844         for( BC_BitmapImage *nxt=0, *bfr=first; bfr; bfr=nxt ) {
845                 nxt = bfr->next;
846                 if( bfr->is_zombie() ) { --BC_Bitmap::zombies; delete bfr; continue; }
847                 if( bfr->bitmap->parent_window == wdw ) remove_pointer(bfr);
848         }
849         active_lock.unlock();
850 }
851
852 BC_ActiveBitmaps::BC_ActiveBitmaps()
853 {
854 }
855
856 BC_ActiveBitmaps::~BC_ActiveBitmaps()
857 {
858 }
859
860
861
862 int BC_WindowBase::keysym_lookup(XEvent *event)
863 {
864         for( int i = 0; i < KEYPRESSLEN; ++i ) keys_return[i] = 0;
865         for( int i = 0; i < 4; ++i ) wkey_string[i] = 0;
866
867         if( event->xany.send_event && !event->xany.serial ) {
868                 keysym = (KeySym) event->xkey.keycode;
869                 keys_return[0] = keysym;
870                 return 0;
871         }
872         wkey_string_length = 0;
873
874         if( input_context ) {
875                 wkey_string_length = XwcLookupString(input_context,
876                         (XKeyEvent*)event, wkey_string, 4, &keysym, 0);
877 //printf("keysym_lookup 1 %d %d %lx %x %x %x %x\n", wkey_string_length, keysym,
878 //  wkey_string[0], wkey_string[1], wkey_string[2], wkey_string[3]);
879
880                 Status stat;
881                 int ret = Xutf8LookupString(input_context, (XKeyEvent*)event,
882                                 keys_return, KEYPRESSLEN, &keysym, &stat);
883 //printf("keysym_lookup 2 %d %d %lx %x %x\n", ret, stat, keysym, keys_return[0], keys_return[1]);
884                 if( stat == XLookupBoth ) return ret;
885                 if( stat == XLookupKeySym ) return 0;
886         }
887         int ret = XLookupString((XKeyEvent*)event, keys_return, KEYPRESSLEN, &keysym, 0);
888         wkey_string_length = ret;
889         for( int i=0; i<ret; ++i ) wkey_string[i] = keys_return[i];
890         return ret;
891 }
892
893 pthread_t locking_task = (pthread_t)-1L;
894 int locking_event = -1;
895 int locking_message = -1;
896
897 int BC_WindowBase::dispatch_event(XEvent *event)
898 {
899         Window tempwin;
900         int result;
901         XClientMessageEvent *ptr;
902         int cancel_resize, cancel_translation;
903         const int debug = 0;
904
905         key_pressed = 0;
906
907 #ifndef SINGLE_THREAD
908 // If an event is waiting get it, otherwise
909 // wait for next event only if there are no compressed events.
910         if(get_event_count() ||
911                 (!motion_events && !resize_events && !translation_events))
912         {
913                 event = get_event();
914 // Lock out window deletions
915                 lock_window("BC_WindowBase::dispatch_event 1");
916 locking_event = event->type;
917 locking_task = pthread_self();
918 locking_message = event->xclient.message_type;
919         }
920         else
921 // Handle compressed events
922         {
923                 lock_window("BC_WindowBase::dispatch_event 2");
924                 if(resize_events)
925                         dispatch_resize_event(last_resize_w, last_resize_h);
926                 if(motion_events)
927                         dispatch_motion_event();
928                 if(translation_events)
929                         dispatch_translation_event();
930
931                 unlock_window();
932                 return 0;
933         }
934
935 #endif
936
937
938
939
940 //static const char *event_names[] = {
941 //  "Reply", "Error", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease", "MotionNotify",
942 //  "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut", "KeymapNotify", "Expose", "GraphicsExpose",
943 //  "NoExpose", "VisibilityNotify", "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify",
944 //  "MapRequest", "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
945 //  "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear",
946 //  "SelectionRequest", "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify",
947 //  "GenericEvent", "LASTEvent",
948 //};
949 //
950 //if(debug)
951 //if(event->type != ClientMessage) {
952 // printf("BC_WindowBase::dispatch_event %d %s %p %d (%s)\n",
953 //__LINE__, title, event, event->type,
954 //  event->type>=0 && event->type<sizeof(event_names)/sizeof(event_names[0]) ?
955 //   event_names[event->type] : "Unknown");
956 //}
957
958
959
960
961         switch(event->type) {
962         case ClientMessage:
963 // Clear the resize buffer
964                 if(resize_events) dispatch_resize_event(last_resize_w, last_resize_h);
965 // Clear the motion buffer since this can clear the window
966                 if(motion_events)
967                 {
968                         dispatch_motion_event();
969                 }
970
971                 ptr = (XClientMessageEvent*)event;
972
973
974                 if(ptr->message_type == ProtoXAtom &&
975                         (Atom)ptr->data.l[0] == DelWinXAtom)
976                 {
977                         close_event();
978                 }
979                 else
980                 if(ptr->message_type == RepeaterXAtom)
981                 {
982                         dispatch_repeat_event(ptr->data.l[0]);
983 // Make sure the repeater still exists.
984 //                              for(int i = 0; i < repeaters.total; i++)
985 //                              {
986 //                                      if(repeaters.values[i]->repeat_id == ptr->data.l[0])
987 //                                      {
988 //                                              dispatch_repeat_event_master(ptr->data.l[0]);
989 //                                              break;
990 //                                      }
991 //                              }
992                 }
993                 else
994                 if(ptr->message_type == SetDoneXAtom)
995                 {
996                         done = 1;
997                         } else
998                         { // We currently use X marshalling for xatom events, we can switch to something else later
999                                 recieve_custom_xatoms((xatom_event *)ptr);
1000                 }
1001                 break;
1002
1003         case FocusIn:
1004                 has_focus = 1;
1005                 dispatch_focus_in();
1006                 break;
1007
1008         case FocusOut:
1009                 has_focus = 0;
1010                 dispatch_focus_out();
1011                 break;
1012
1013 // Maximized
1014         case MapNotify:
1015                 break;
1016
1017 // Minimized
1018         case UnmapNotify:
1019                 break;
1020
1021         case ButtonPress:
1022                 get_key_masks(event->xbutton.state);
1023                 cursor_x = event->xbutton.x;
1024                 cursor_y = event->xbutton.y;
1025                 button_number = event->xbutton.button;
1026
1027 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1028                 event_win = event->xany.window;
1029                 if (button_number < 6)
1030                 {
1031                         if(button_number < 4)
1032                                 button_down = 1;
1033                         button_pressed = event->xbutton.button;
1034                         button_time1 = button_time2;
1035                         button_time2 = button_time3;
1036                         button_time3 = event->xbutton.time;
1037                         drag_x = cursor_x;
1038                         drag_y = cursor_y;
1039                         drag_win = event_win;
1040                         drag_x1 = cursor_x - get_resources()->drag_radius;
1041                         drag_x2 = cursor_x + get_resources()->drag_radius;
1042                         drag_y1 = cursor_y - get_resources()->drag_radius;
1043                         drag_y2 = cursor_y + get_resources()->drag_radius;
1044
1045                         if((long)(button_time3 - button_time1) < resources.double_click * 2)
1046                         {
1047                                 triple_click = 1;
1048                                 button_time3 = button_time2 = button_time1 = 0;
1049                         }
1050                         if((long)(button_time3 - button_time2) < resources.double_click)
1051                         {
1052                                 double_click = 1;
1053 //                              button_time3 = button_time2 = button_time1 = 0;
1054                         }
1055                         else
1056                         {
1057                                 triple_click = 0;
1058                                 double_click = 0;
1059                         }
1060
1061                         dispatch_button_press();
1062                 }
1063                 break;
1064
1065         case ButtonRelease:
1066                 get_key_masks(event->xbutton.state);
1067                 button_number = event->xbutton.button;
1068                 event_win = event->xany.window;
1069                 if (button_number < 6)
1070                 {
1071                         if(button_number < 4)
1072                                 button_down = 0;
1073 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1074
1075                         dispatch_button_release();
1076                 }
1077                 break;
1078
1079         case Expose:
1080                 event_win = event->xany.window;
1081                 dispatch_expose_event();
1082                 break;
1083
1084         case MotionNotify:
1085                 get_key_masks(event->xmotion.state);
1086 // Dispatch previous motion event if this is a subsequent motion from a different window
1087                 if(motion_events && last_motion_win != event->xany.window)
1088                 {
1089                         dispatch_motion_event();
1090                 }
1091
1092 // Buffer the current motion
1093                 motion_events = 1;
1094                 last_motion_state = event->xmotion.state;
1095                 last_motion_x = event->xmotion.x;
1096                 last_motion_y = event->xmotion.y;
1097                 last_motion_win = event->xany.window;
1098                 break;
1099
1100         case ConfigureNotify:
1101 // printf("BC_WindowBase::dispatch_event %d win=%p this->win=%p\n",
1102 // __LINE__,
1103 // event->xany.window,
1104 // win);
1105 // dump_windows();
1106                 XTranslateCoordinates(top_level->display,
1107                         top_level->win,
1108                         top_level->rootwin,
1109                         0,
1110                         0,
1111                         &last_translate_x,
1112                         &last_translate_y,
1113                         &tempwin);
1114                 last_resize_w = event->xconfigure.width;
1115                 last_resize_h = event->xconfigure.height;
1116
1117                 cancel_resize = 0;
1118                 cancel_translation = 0;
1119
1120 // Resize history prevents responses to recursive resize requests
1121                 for(int i = 0; i < resize_history.total && !cancel_resize; i++)
1122                 {
1123                         if(resize_history.values[i]->w == last_resize_w &&
1124                                 resize_history.values[i]->h == last_resize_h)
1125                         {
1126                                 delete resize_history.values[i];
1127                                 resize_history.remove_number(i);
1128                                 cancel_resize = 1;
1129                         }
1130                 }
1131
1132                 if(last_resize_w == w && last_resize_h == h)
1133                         cancel_resize = 1;
1134
1135                 if(!cancel_resize)
1136                 {
1137                         resize_events = 1;
1138                 }
1139
1140                 if((last_translate_x == x && last_translate_y == y))
1141                         cancel_translation = 1;
1142
1143                 if(!cancel_translation)
1144                 {
1145                         translation_events = 1;
1146                 }
1147
1148                 translation_count++;
1149                 break;
1150
1151         case KeyPress:
1152                 get_key_masks(event->xkey.state);
1153                 keys_return[0] = 0;  keysym = -1;
1154                 if(XFilterEvent(event, win)) {
1155                         break;
1156                 }
1157                 if( keysym_lookup(event) < 0 ) {
1158                         printf("keysym %x\n", (uint32_t)keysym);
1159                         break;
1160                 }
1161
1162 //printf("BC_WindowBase::dispatch_event %d keysym=0x%x\n",
1163 //__LINE__,
1164 //keysym);
1165
1166 // block out control keys
1167                 if(keysym > 0xffe0 && keysym < 0xffff) break;
1168 // block out Alt_GR key
1169                 if(keysym == 0xfe03) break;
1170
1171                 if(test_keypress)
1172                          printf("BC_WindowBase::dispatch_event %x\n", (uint32_t)keysym);
1173
1174 #ifdef X_HAVE_UTF8_STRING
1175 //It's Ascii or UTF8?
1176 //              if (keysym != 0xffff && (keys_return[0] & 0xff) >= 0x7f )
1177 //printf("BC_WindowBase::dispatch_event %d %02x%02x\n", __LINE__, keys_return[0], keys_return[1]);
1178
1179                 if( ((keys_return[1] & 0xff) > 0x80) &&
1180                     ((keys_return[0] & 0xff) > 0xC0) ) {
1181 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1182                         key_pressed = keysym & 0xff;
1183                 }
1184                 else {
1185 #endif
1186
1187                 switch(keysym) {
1188 // block out extra keys
1189                 case XK_Alt_L:
1190                 case XK_Alt_R:
1191                 case XK_Shift_L:
1192                 case XK_Shift_R:
1193                 case XK_Control_L:
1194                 case XK_Control_R:
1195                         key_pressed = 0;
1196                         break;
1197
1198 // Translate key codes
1199                 case XK_Return:         key_pressed = RETURN;   break;
1200                 case XK_Up:             key_pressed = UP;       break;
1201                 case XK_Down:           key_pressed = DOWN;     break;
1202                 case XK_Left:           key_pressed = LEFT;     break;
1203                 case XK_Right:          key_pressed = RIGHT;    break;
1204                 case XK_Next:           key_pressed = PGDN;     break;
1205                 case XK_Prior:          key_pressed = PGUP;     break;
1206                 case XK_BackSpace:      key_pressed = BACKSPACE; break;
1207                 case XK_Escape:         key_pressed = ESC;      break;
1208                 case XK_Tab:
1209                         if(shift_down())
1210                                 key_pressed = LEFTTAB;
1211                         else
1212                                 key_pressed = TAB;
1213                         break;
1214                 case XK_ISO_Left_Tab:   key_pressed = LEFTTAB;  break;
1215                 case XK_underscore:     key_pressed = '_';      break;
1216                 case XK_asciitilde:     key_pressed = '~';      break;
1217                 case XK_Delete:         key_pressed = DELETE;   break;
1218                 case XK_Home:           key_pressed = HOME;     break;
1219                 case XK_End:            key_pressed = END;      break;
1220
1221 // number pad
1222                 case XK_KP_Enter:       key_pressed = KPENTER;  break;
1223                 case XK_KP_Add:         key_pressed = KPPLUS;   break;
1224                 case XK_KP_Subtract:    key_pressed = KPMINUS;  break;
1225                 case XK_KP_Multiply:    key_pressed = KPSTAR;   break;
1226                 case XK_KP_Divide:      key_pressed = KPSLASH;  break;
1227                 case XK_KP_1:
1228                 case XK_KP_End:         key_pressed = KP1;      break;
1229                 case XK_KP_2:
1230                 case XK_KP_Down:        key_pressed = KP2;      break;
1231                 case XK_KP_3:
1232                 case XK_KP_Page_Down:   key_pressed = KP3;      break;
1233                 case XK_KP_4:
1234                 case XK_KP_Left:        key_pressed = KP4;      break;
1235                 case XK_KP_5:
1236                 case XK_KP_Begin:       key_pressed = KP5;      break;
1237                 case XK_KP_6:
1238                 case XK_KP_Right:       key_pressed = KP6;      break;
1239                 case XK_KP_7:
1240                 case XK_KP_Home:        key_pressed = KP7;      break;
1241                 case XK_KP_8:
1242                 case XK_KP_Up:          key_pressed = KP8;      break;
1243                 case XK_KP_9:
1244                 case XK_KP_Page_Up:     key_pressed = KP9;      break;
1245                 case XK_KP_0:
1246                 case XK_KP_Insert:      key_pressed = KPINS;    break;
1247                 case XK_KP_Decimal:
1248                 case XK_KP_Delete:      key_pressed = KPDEL;    break;
1249                 case XK_Menu:           key_pressed = KPMENU;   break;  /* menu */
1250 // remote control
1251 // above        case XK_KP_Enter:       key_pressed = KPENTER;  break;  /* check */
1252                 case XF86XK_MenuKB:     key_pressed = KPMENU;   break;  /* menu */
1253 // intercepted  case XF86XK_PowerDown: key_pressed = KPPOWER;   break;  /* Power */
1254                 case XF86XK_Launch1:    key_pressed = KPTV;     break;  /* TV */
1255                 case XF86XK_Launch2:    key_pressed = KPDVD;    break;  /* DVD */
1256 // intercepted  case XF86XK_WWW:        key_pressed = KPWWEB;   break;  /* WEB */
1257                 case XF86XK_Launch3:    key_pressed = KPBOOK;   break;  /* book */
1258                 case XF86XK_Launch4:    key_pressed = KPHAND;   break;  /* hand */
1259                 case XF86XK_Reply:      key_pressed = KPTMR;    break;  /* timer */
1260                 case SunXK_Front:       key_pressed = KPMAXW;   break;  /* max */
1261 // above        case XK_Left:           key_pressed = LEFT;     break;  /* left */
1262 // above        case XK_Right:          key_pressed = RIGHT;    break;  /* right */
1263 // above        case XK_Down:           key_pressed = DOWN;     break;  /* down */
1264 // above        case XK_Up:             key_pressed = UP;       break;  /* up */
1265 // above        case XK_SPACE:          key_pressed = KPSPACE;  break;  /* ok */
1266 // intercepted  case XF86XK_AudioRaiseVolume: key_pressed = KPVOLU;     break;  /* VOL + */
1267 // intercepted  case XF86XK_AudioMute: key_pressed = KPMUTE;    break;  /* MUTE */
1268 // intercepted  case XF86XK_AudioLowerVolume: key_pressed = KPVOLD;     break;  /* VOL - */
1269                 case XF86XK_ScrollUp:   key_pressed = KPCHUP;   break;  /* CH + */
1270                 case XF86XK_ScrollDown: key_pressed = KPCHDN;   break;  /* CH - */
1271                 case XF86XK_AudioRecord: key_pressed = KPRECD;  break;  /* ( o) red */
1272                 case XF86XK_Forward:    key_pressed = KPPLAY;   break;  /* ( >) */
1273                 case XK_Redo:           key_pressed = KPFWRD;   break;  /* (>>) */
1274                 case XF86XK_Back:       key_pressed = KPBACK;   break;  /* (<<) */
1275                 case XK_Cancel:         key_pressed = KPSTOP;   break;  /* ([]) */
1276                 case XK_Pause:          key_pressed = KPAUSE;   break;  /* ('') */
1277
1278                 default:
1279                         key_pressed = keysym & 0xff;
1280 #ifdef X_HAVE_UTF8_STRING
1281 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1282                         keys_return[1] = 0;
1283 #endif
1284                         break;
1285                 }
1286 #ifdef X_HAVE_UTF8_STRING
1287                 }
1288                 key_pressed_utf8 = keys_return;
1289 #endif
1290
1291
1292                 result = 0;
1293                 if( top_level == this )
1294                         result = BC_KeyboardHandler::run_listeners(this);
1295
1296 //printf("BC_WindowBase::dispatch_event %d %d %x\n", shift_down(), alt_down(), key_pressed);
1297                 if( !result )
1298                         result = dispatch_keypress_event();
1299 // Handle some default keypresses
1300                 if(!result)
1301                 {
1302                         if(key_pressed == 'w' ||
1303                                 key_pressed == 'W')
1304                         {
1305                                 close_event();
1306                         }
1307                 }
1308                 break;
1309
1310         case KeyRelease:
1311                 XLookupString((XKeyEvent*)event, keys_return, 1, &keysym, 0);
1312                 dispatch_keyrelease_event();
1313 // printf("BC_WindowBase::dispatch_event KeyRelease keysym=0x%x keystate=0x%lld\n",
1314 // keysym, event->xkey.state);
1315                 break;
1316
1317         case LeaveNotify:
1318                 event_win = event->xany.window;
1319                 dispatch_cursor_leave();
1320                 break;
1321
1322         case EnterNotify:
1323                 event_win = event->xany.window;
1324                 cursor_x = event->xcrossing.x;
1325                 cursor_y = event->xcrossing.y;
1326                 dispatch_cursor_enter();
1327                 break;
1328         default:
1329                 break;
1330         }
1331 //printf("100 %s %p %d\n", title, event, event->type);
1332 //if(event->type != ClientMessage) dump();
1333
1334 #ifndef SINGLE_THREAD
1335         unlock_window();
1336         if(event) delete event;
1337 #else
1338 //      if(done) completion_lock->unlock();
1339 #endif
1340
1341 if(debug) printf("BC_WindowBase::dispatch_event this=%p %d\n", this, __LINE__);
1342         return 0;
1343 }
1344
1345 int BC_WindowBase::dispatch_expose_event()
1346 {
1347         int result = 0;
1348         for(int i = 0; i < subwindows->total && !result; i++)
1349         {
1350                 result = subwindows->values[i]->dispatch_expose_event();
1351         }
1352
1353 // Propagate to user
1354         if(!result) expose_event();
1355         return result;
1356 }
1357
1358 int BC_WindowBase::dispatch_resize_event(int w, int h)
1359 {
1360 // Can't store new w and h until the event is handles
1361 // because bcfilebox depends on the old w and h to
1362 // reposition widgets.
1363         if( window_type == MAIN_WINDOW ) {
1364                 flash_enabled = 0;
1365                 resize_events = 0;
1366
1367                 delete pixmap;
1368                 pixmap = new BC_Pixmap(this, w, h);
1369                 clear_box(0, 0, w, h);
1370         }
1371
1372 // Propagate to subwindows
1373         for(int i = 0; i < subwindows->total; i++) {
1374                 subwindows->values[i]->dispatch_resize_event(w, h);
1375         }
1376
1377 // Propagate to user
1378         resize_event(w, h);
1379
1380         if( window_type == MAIN_WINDOW ) {
1381                 this->w = w;
1382                 this->h = h;
1383                 dispatch_flash();
1384                 flush();
1385         }
1386         return 0;
1387 }
1388
1389 int BC_WindowBase::dispatch_flash()
1390 {
1391         flash_enabled = 1;
1392         for(int i = 0; i < subwindows->total; i++)
1393                 subwindows->values[i]->dispatch_flash();
1394         return flash(0);
1395 }
1396
1397 int BC_WindowBase::dispatch_translation_event()
1398 {
1399         translation_events = 0;
1400         if(window_type == MAIN_WINDOW)
1401         {
1402                 prev_x = x;
1403                 prev_y = y;
1404                 x = last_translate_x;
1405                 y = last_translate_y;
1406 // Correct for window manager offsets
1407                 x -= x_correction;
1408                 y -= y_correction;
1409         }
1410
1411         for(int i = 0; i < subwindows->total; i++)
1412         {
1413                 subwindows->values[i]->dispatch_translation_event();
1414         }
1415
1416         translation_event();
1417         return 0;
1418 }
1419
1420 int BC_WindowBase::dispatch_motion_event()
1421 {
1422         int result = 0;
1423         unhide_cursor();
1424
1425         if(top_level == this)
1426         {
1427                 motion_events = 0;
1428                 event_win = last_motion_win;
1429                 get_key_masks(last_motion_state);
1430
1431 // Test for grab
1432                 if(get_button_down() && !active_menubar && !active_popup_menu)
1433                 {
1434                         if(!result)
1435                         {
1436                                 cursor_x = last_motion_x;
1437                                 cursor_y = last_motion_y;
1438                                 result = dispatch_drag_motion();
1439                         }
1440
1441                         if(!result &&
1442                                 (last_motion_x < drag_x1 || last_motion_x >= drag_x2 ||
1443                                 last_motion_y < drag_y1 || last_motion_y >= drag_y2))
1444                         {
1445                                 cursor_x = drag_x;
1446                                 cursor_y = drag_y;
1447
1448                                 result = dispatch_drag_start();
1449                         }
1450                 }
1451
1452                 cursor_x = last_motion_x;
1453                 cursor_y = last_motion_y;
1454
1455 // printf("BC_WindowBase::dispatch_motion_event %d %p %p %p\n",
1456 // __LINE__,
1457 // active_menubar,
1458 // active_popup_menu,
1459 // active_subwindow);
1460
1461                 if(active_menubar && !result) result = active_menubar->dispatch_motion_event();
1462                 if(active_popup_menu && !result) result = active_popup_menu->dispatch_motion_event();
1463                 if(active_subwindow && !result) result = active_subwindow->dispatch_motion_event();
1464         }
1465
1466 // Dispatch in stacking order
1467         for(int i = subwindows->size() - 1; i >= 0 && !result; i--)
1468         {
1469                 result = subwindows->values[i]->dispatch_motion_event();
1470         }
1471
1472         if(!result) result = cursor_motion_event();    // give to user
1473         return result;
1474 }
1475
1476 int BC_WindowBase::dispatch_keypress_event()
1477 {
1478         int result = 0;
1479         if(top_level == this)
1480         {
1481                 if(active_subwindow) result = active_subwindow->dispatch_keypress_event();
1482         }
1483
1484         for(int i = 0; i < subwindows->total && !result; i++)
1485         {
1486                 result = subwindows->values[i]->dispatch_keypress_event();
1487         }
1488
1489         if(!result) result = keypress_event();
1490
1491         return result;
1492 }
1493
1494 int BC_WindowBase::dispatch_keyrelease_event()
1495 {
1496         int result = 0;
1497         if(top_level == this)
1498         {
1499                 if(active_subwindow) result = active_subwindow->dispatch_keyrelease_event();
1500         }
1501
1502         for(int i = 0; i < subwindows->total && !result; i++)
1503         {
1504                 result = subwindows->values[i]->dispatch_keyrelease_event();
1505         }
1506
1507         if(!result) result = keyrelease_event();
1508
1509         return result;
1510 }
1511
1512 int BC_WindowBase::dispatch_focus_in()
1513 {
1514         for(int i = 0; i < subwindows->total; i++)
1515         {
1516                 subwindows->values[i]->dispatch_focus_in();
1517         }
1518
1519         focus_in_event();
1520
1521         return 0;
1522 }
1523
1524 int BC_WindowBase::dispatch_focus_out()
1525 {
1526         for(int i = 0; i < subwindows->total; i++)
1527         {
1528                 subwindows->values[i]->dispatch_focus_out();
1529         }
1530
1531         focus_out_event();
1532
1533         return 0;
1534 }
1535
1536 int BC_WindowBase::get_has_focus()
1537 {
1538         return top_level->has_focus;
1539 }
1540
1541 int BC_WindowBase::get_deleting()
1542 {
1543         if(is_deleting) return 1;
1544         if(parent_window && parent_window->get_deleting()) return 1;
1545         return 0;
1546 }
1547
1548 int BC_WindowBase::dispatch_button_press()
1549 {
1550         int result = 0;
1551
1552
1553         if(top_level == this)
1554         {
1555                 if(active_menubar) result = active_menubar->dispatch_button_press();
1556                 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_press();
1557                 if(active_subwindow && !result) result = active_subwindow->dispatch_button_press();
1558         }
1559
1560         for(int i = 0; i < subwindows->total && !result; i++)
1561         {
1562                 result = subwindows->values[i]->dispatch_button_press();
1563         }
1564
1565         if(!result) result = button_press_event();
1566
1567
1568         return result;
1569 }
1570
1571 int BC_WindowBase::dispatch_button_release()
1572 {
1573         int result = 0;
1574         if(top_level == this)
1575         {
1576                 if(active_menubar) result = active_menubar->dispatch_button_release();
1577                 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_release();
1578                 if(active_subwindow && !result) result = active_subwindow->dispatch_button_release();
1579                 if(!result && button_number != 4 && button_number != 5)
1580                         result = dispatch_drag_stop();
1581         }
1582
1583         for(int i = 0; i < subwindows->total && !result; i++)
1584         {
1585                 result = subwindows->values[i]->dispatch_button_release();
1586         }
1587
1588         if(!result)
1589         {
1590                 result = button_release_event();
1591         }
1592
1593         return result;
1594 }
1595
1596
1597 int BC_WindowBase::dispatch_repeat_event(int64_t duration)
1598 {
1599
1600 // all repeat event handlers get called and decide based on activity and duration
1601 // whether to respond
1602         for(int i = 0; i < subwindows->total; i++)
1603         {
1604                 subwindows->values[i]->dispatch_repeat_event(duration);
1605         }
1606
1607
1608         repeat_event(duration);
1609
1610
1611
1612 // Unlock next repeat signal
1613         if(window_type == MAIN_WINDOW)
1614         {
1615 #ifdef SINGLE_THREAD
1616                 BC_Display::display_global->unlock_repeaters(duration);
1617 #else
1618                 for(int i = 0; i < repeaters.total; i++)
1619                 {
1620                         if(repeaters.values[i]->delay == duration)
1621                         {
1622                                 repeaters.values[i]->repeat_lock->unlock();
1623                         }
1624                 }
1625 #endif
1626         }
1627         return 0;
1628 }
1629
1630 void BC_WindowBase::unhide_cursor()
1631 {
1632         if(is_transparent)
1633         {
1634                 is_transparent = 0;
1635                 if(top_level->is_hourglass)
1636                         set_cursor(HOURGLASS_CURSOR, 1, 0);
1637                 else
1638                         set_cursor(current_cursor, 1, 0);
1639         }
1640         cursor_timer->update();
1641 }
1642
1643
1644 void BC_WindowBase::update_video_cursor()
1645 {
1646         if(video_on && !is_transparent)
1647         {
1648                 if(cursor_timer->get_difference() > VIDEO_CURSOR_TIMEOUT && !is_transparent)
1649                 {
1650                         is_transparent = 1;
1651                         set_cursor(TRANSPARENT_CURSOR, 1, 1);
1652                         cursor_timer->update();
1653                 }
1654         }
1655         else
1656         {
1657                 cursor_timer->update();
1658         }
1659 }
1660
1661
1662 int BC_WindowBase::dispatch_cursor_leave()
1663 {
1664         unhide_cursor();
1665
1666         for(int i = 0; i < subwindows->total; i++)
1667         {
1668                 subwindows->values[i]->dispatch_cursor_leave();
1669         }
1670
1671         cursor_leave_event();
1672         return 0;
1673 }
1674
1675 int BC_WindowBase::dispatch_cursor_enter()
1676 {
1677         int result = 0;
1678
1679         unhide_cursor();
1680
1681         if(active_menubar) result = active_menubar->dispatch_cursor_enter();
1682         if(!result && active_popup_menu) result = active_popup_menu->dispatch_cursor_enter();
1683         if(!result && active_subwindow) result = active_subwindow->dispatch_cursor_enter();
1684
1685         for(int i = 0; !result && i < subwindows->total; i++)
1686         {
1687                 result = subwindows->values[i]->dispatch_cursor_enter();
1688         }
1689
1690         if(!result) result = cursor_enter_event();
1691         return result;
1692 }
1693
1694 int BC_WindowBase::cursor_enter_event()
1695 {
1696         return 0;
1697 }
1698
1699 int BC_WindowBase::cursor_leave_event()
1700 {
1701         return 0;
1702 }
1703
1704 int BC_WindowBase::close_event()
1705 {
1706         set_done(1);
1707         return 1;
1708 }
1709
1710 int BC_WindowBase::dispatch_drag_start()
1711 {
1712         int result = 0;
1713         if(active_menubar) result = active_menubar->dispatch_drag_start();
1714         if(!result && active_popup_menu) result = active_popup_menu->dispatch_drag_start();
1715         if(!result && active_subwindow) result = active_subwindow->dispatch_drag_start();
1716
1717         for(int i = 0; i < subwindows->total && !result; i++)
1718         {
1719                 result = subwindows->values[i]->dispatch_drag_start();
1720         }
1721
1722         if(!result) result = is_dragging = drag_start_event();
1723         return result;
1724 }
1725
1726 int BC_WindowBase::dispatch_drag_stop()
1727 {
1728         int result = 0;
1729
1730         for(int i = 0; i < subwindows->total && !result; i++)
1731         {
1732                 result = subwindows->values[i]->dispatch_drag_stop();
1733         }
1734
1735         if(is_dragging && !result)
1736         {
1737                 drag_stop_event();
1738                 is_dragging = 0;
1739                 result = 1;
1740         }
1741
1742         return result;
1743 }
1744
1745 int BC_WindowBase::dispatch_drag_motion()
1746 {
1747         int result = 0;
1748         for(int i = 0; i < subwindows->total && !result; i++)
1749         {
1750                 result = subwindows->values[i]->dispatch_drag_motion();
1751         }
1752
1753         if(is_dragging && !result)
1754         {
1755                 drag_motion_event();
1756                 result = 1;
1757         }
1758
1759         return result;
1760 }
1761
1762
1763
1764
1765
1766 int BC_WindowBase::show_tooltip(int w, int h)
1767 {
1768         Window tempwin;
1769
1770         if(tooltip_text && !tooltip_on &&
1771                 (force_tooltip || get_resources()->tooltips_enabled))
1772         {
1773                 int x, y;
1774                 top_level->hide_tooltip();
1775
1776                 tooltip_on = 1;
1777                 if(w < 0)
1778                         w = get_text_width(MEDIUMFONT, tooltip_text);
1779
1780                 if(h < 0)
1781                         h = get_text_height(MEDIUMFONT, tooltip_text);
1782
1783                 w += TOOLTIP_MARGIN * 2;
1784                 h += TOOLTIP_MARGIN * 2;
1785
1786                 XTranslateCoordinates(top_level->display, win,
1787                                 top_level->rootwin, get_w(), get_h(),
1788                                 &x, &y, &tempwin);
1789                 // keep the tip inside the window/display
1790                 int top_x = top_level->get_x();
1791                 if( x < top_x ) x = top_x;
1792                 int top_w = top_x + top_level->get_w();
1793                 int lmt_w = top_level->get_screen_x(0, -1) + top_level->get_screen_w(0, -1);
1794                 if( top_w < lmt_w ) lmt_w = top_w;
1795                 if( x+w > lmt_w ) x = lmt_w-w;
1796                 if( x < 0 ) x = 0;
1797                 int top_y = top_level->get_y();
1798                 if( y < top_y ) y = top_y;
1799                 int top_h = top_y + top_level->get_h();
1800                 int lmt_h = top_level->get_root_h(0);
1801                 if( top_h < lmt_h ) lmt_h = top_h;
1802                 if( y+h > lmt_h ) y = lmt_h-h;
1803                 if( y < 0 ) y = 0;
1804                 int abs_x, abs_y, win_x, win_y;
1805                 unsigned int temp_mask;
1806                 Window temp_win;
1807                 XQueryPointer(top_level->display, top_level->win,
1808                         &temp_win, &temp_win, &abs_x, &abs_y,
1809                         &win_x, &win_y, &temp_mask);
1810                 // check for cursor inside popup
1811                 if( x < abs_x && abs_x < x+w && y < abs_y && abs_y < y+h )
1812                 {
1813                         if( x-abs_x < y-abs_y )
1814                                 x = abs_x+1;
1815                         else
1816                                 y = abs_y+1;
1817                 }
1818                 tooltip_popup = new BC_Popup(top_level, x, y, w, h,
1819                                         get_resources()->tooltip_bg_color);
1820
1821                 draw_tooltip();
1822                 tooltip_popup->set_font(MEDIUMFONT);
1823                 tooltip_popup->flash();
1824                 tooltip_popup->flush();
1825         }
1826         return 0;
1827 }
1828
1829 int BC_WindowBase::hide_tooltip()
1830 {
1831         if(subwindows)
1832                 for(int i = 0; i < subwindows->total; i++)
1833                 {
1834                         subwindows->values[i]->hide_tooltip();
1835                 }
1836
1837         if(tooltip_on)
1838         {
1839                 tooltip_on = 0;
1840                 delete tooltip_popup;
1841                 tooltip_popup = 0;
1842         }
1843         return 0;
1844 }
1845
1846 const char *BC_WindowBase::get_tooltip()
1847 {
1848         return tooltip_text;
1849 }
1850
1851 int BC_WindowBase::set_tooltip(const char *text)
1852 {
1853         tooltip_text = text;
1854
1855 // Update existing tooltip if it is visible
1856         if(tooltip_on)
1857         {
1858                 draw_tooltip();
1859                 tooltip_popup->flash();
1860         }
1861         return 0;
1862 }
1863
1864 // signal the event handler to repeat
1865 int BC_WindowBase::set_repeat(int64_t duration)
1866 {
1867         if(duration <= 0)
1868         {
1869                 printf("BC_WindowBase::set_repeat duration=%jd\n", duration);
1870                 return 0;
1871         }
1872         if(window_type != MAIN_WINDOW) return top_level->set_repeat(duration);
1873
1874 #ifdef SINGLE_THREAD
1875         BC_Display::display_global->set_repeat(this, duration);
1876 #else
1877 // test repeater database for duplicates
1878         for(int i = 0; i < repeaters.total; i++)
1879         {
1880 // Already exists
1881                 if(repeaters.values[i]->delay == duration)
1882                 {
1883                         repeaters.values[i]->start_repeating(this);
1884                         return 0;
1885                 }
1886         }
1887
1888         BC_Repeater *repeater = new BC_Repeater(this, duration);
1889         repeater->initialize();
1890         repeaters.append(repeater);
1891         repeater->start_repeating();
1892 #endif
1893         return 0;
1894 }
1895
1896 int BC_WindowBase::unset_repeat(int64_t duration)
1897 {
1898         if(window_type != MAIN_WINDOW) return top_level->unset_repeat(duration);
1899
1900 #ifdef SINGLE_THREAD
1901         BC_Display::display_global->unset_repeat(this, duration);
1902 #else
1903         for(int i = 0; i < repeaters.total; i++)
1904         {
1905                 if(repeaters.values[i]->delay == duration)
1906                 {
1907                         repeaters.values[i]->stop_repeating();
1908                 }
1909         }
1910 #endif
1911         return 0;
1912 }
1913
1914
1915 int BC_WindowBase::unset_all_repeaters()
1916 {
1917 #ifdef SINGLE_THREAD
1918         BC_Display::display_global->unset_all_repeaters(this);
1919 #else
1920         for(int i = 0; i < repeaters.total; i++)
1921         {
1922                 repeaters.values[i]->stop_repeating();
1923         }
1924         repeaters.remove_all_objects();
1925 #endif
1926         return 0;
1927 }
1928
1929 // long BC_WindowBase::get_repeat_id()
1930 // {
1931 //      return top_level->next_repeat_id++;
1932 // }
1933
1934 XEvent *BC_WindowBase::new_xevent()
1935 {
1936         XEvent *event = new XEvent;
1937         memset(event, 0, sizeof(*event));
1938         return event;
1939 }
1940
1941 #ifndef SINGLE_THREAD
1942 int BC_WindowBase::arm_repeat(int64_t duration)
1943 {
1944         XEvent *event = new_xevent();
1945         XClientMessageEvent *ptr = (XClientMessageEvent*)event;
1946         ptr->type = ClientMessage;
1947         ptr->message_type = RepeaterXAtom;
1948         ptr->format = 32;
1949         ptr->data.l[0] = duration;
1950
1951 // Couldn't use XSendEvent since it locked up randomly.
1952         put_event(event);
1953         return 0;
1954 }
1955 #endif
1956
1957 int BC_WindowBase::recieve_custom_xatoms(xatom_event *event)
1958 {
1959         return 0;
1960 }
1961
1962 int BC_WindowBase::send_custom_xatom(xatom_event *event)
1963 {
1964 #ifndef SINGLE_THREAD
1965         XEvent *myevent = new_xevent();
1966         XClientMessageEvent *ptr = (XClientMessageEvent*)myevent;
1967         ptr->type = ClientMessage;
1968         ptr->message_type = event->message_type;
1969         ptr->format = event->format;
1970         ptr->data.l[0] = event->data.l[0];
1971         ptr->data.l[1] = event->data.l[1];
1972         ptr->data.l[2] = event->data.l[2];
1973         ptr->data.l[3] = event->data.l[3];
1974         ptr->data.l[4] = event->data.l[4];
1975
1976         put_event(myevent);
1977 #endif
1978         return 0;
1979 }
1980
1981
1982
1983 Atom BC_WindowBase::create_xatom(const char *atom_name)
1984 {
1985         return XInternAtom(display, atom_name, False);
1986 }
1987
1988 int BC_WindowBase::get_atoms()
1989 {
1990         SetDoneXAtom =  XInternAtom(display, "BC_REPEAT_EVENT", False);
1991         RepeaterXAtom = XInternAtom(display, "BC_CLOSE_EVENT", False);
1992         DestroyAtom =   XInternAtom(display, "BC_DESTROY_WINDOW", False);
1993         DelWinXAtom =   XInternAtom(display, "WM_DELETE_WINDOW", False);
1994         if( (ProtoXAtom = XInternAtom(display, "WM_PROTOCOLS", False)) != 0 )
1995                 XChangeProperty(display, win, ProtoXAtom, XA_ATOM, 32,
1996                         PropModeReplace, (unsigned char *)&DelWinXAtom, True);
1997         return 0;
1998
1999 }
2000
2001
2002 void BC_WindowBase::init_cursors()
2003 {
2004         arrow_cursor = XCreateFontCursor(display, XC_top_left_arrow);
2005         cross_cursor = XCreateFontCursor(display, XC_crosshair);
2006         ibeam_cursor = XCreateFontCursor(display, XC_xterm);
2007         vseparate_cursor = XCreateFontCursor(display, XC_sb_v_double_arrow);
2008         hseparate_cursor = XCreateFontCursor(display, XC_sb_h_double_arrow);
2009         move_cursor = XCreateFontCursor(display, XC_fleur);
2010         left_cursor = XCreateFontCursor(display, XC_sb_left_arrow);
2011         right_cursor = XCreateFontCursor(display, XC_sb_right_arrow);
2012         upright_arrow_cursor = XCreateFontCursor(display, XC_arrow);
2013         upleft_resize_cursor = XCreateFontCursor(display, XC_top_left_corner);
2014         upright_resize_cursor = XCreateFontCursor(display, XC_top_right_corner);
2015         downleft_resize_cursor = XCreateFontCursor(display, XC_bottom_left_corner);
2016         downright_resize_cursor = XCreateFontCursor(display, XC_bottom_right_corner);
2017         hourglass_cursor = XCreateFontCursor(display, XC_watch);
2018
2019
2020         char cursor_data[] = { 0,0,0,0, 0,0,0,0 };
2021         Colormap colormap = DefaultColormap(display, screen);
2022         Pixmap pixmap_bottom = XCreateBitmapFromData(display,
2023                 rootwin, cursor_data, 8, 8);
2024         XColor black, dummy;
2025         XAllocNamedColor(display, colormap, "black", &black, &dummy);
2026         transparent_cursor = XCreatePixmapCursor(display,
2027                 pixmap_bottom, pixmap_bottom, &black, &black, 0, 0);
2028 //      XDefineCursor(display, win, transparent_cursor);
2029         XFreePixmap(display, pixmap_bottom);
2030 }
2031
2032 int BC_WindowBase::evaluate_color_model(int client_byte_order, int server_byte_order, int depth)
2033 {
2034         int color_model = BC_TRANSPARENCY;
2035         switch(depth)
2036         {
2037                 case 8:
2038                         color_model = BC_RGB8;
2039                         break;
2040                 case 16:
2041                         color_model = (server_byte_order == client_byte_order) ? BC_RGB565 : BC_BGR565;
2042                         break;
2043                 case 24:
2044                         color_model = server_byte_order ? BC_BGR888 : BC_RGB888;
2045                         break;
2046                 case 32:
2047                         color_model = server_byte_order ? BC_BGR8888 : BC_ARGB8888;
2048                         break;
2049         }
2050         return color_model;
2051 }
2052
2053 int BC_WindowBase::init_colors()
2054 {
2055         total_colors = 0;
2056         current_color_value = current_color_pixel = 0;
2057
2058 // Get the real depth
2059         char *data = 0;
2060         XImage *ximage;
2061         ximage = XCreateImage(top_level->display,
2062                                         top_level->vis,
2063                                         top_level->default_depth,
2064                                         ZPixmap,
2065                                         0,
2066                                         data,
2067                                         16,
2068                                         16,
2069                                         8,
2070                                         0);
2071         bits_per_pixel = ximage->bits_per_pixel;
2072         XDestroyImage(ximage);
2073
2074         color_model = evaluate_color_model(client_byte_order,
2075                 server_byte_order,
2076                 bits_per_pixel);
2077 // Get the color model
2078         switch(color_model)
2079         {
2080                 case BC_RGB8:
2081                         if(private_color)
2082                         {
2083                                 cmap = XCreateColormap(display, rootwin, vis, AllocNone);
2084                                 create_private_colors();
2085                         }
2086                         else
2087                         {
2088                                 cmap = DefaultColormap(display, screen);
2089                                 create_shared_colors();
2090                         }
2091
2092                         allocate_color_table();
2093                         break;
2094
2095                 default:
2096                         //cmap = DefaultColormap(display, screen);
2097                         cmap = XCreateColormap(display, rootwin, vis, AllocNone );
2098                         break;
2099         }
2100         return 0;
2101 }
2102
2103 int BC_WindowBase::create_private_colors()
2104 {
2105         int color;
2106         total_colors = 256;
2107
2108         for(int i = 0; i < 255; i++)
2109         {
2110                 color = (i & 0xc0) << 16;
2111                 color += (i & 0x38) << 10;
2112                 color += (i & 0x7) << 5;
2113                 color_table[i][0] = color;
2114         }
2115         create_shared_colors();        // overwrite the necessary colors on the table
2116         return 0;
2117 }
2118
2119
2120 int BC_WindowBase::create_color(int color)
2121 {
2122         if(total_colors == 256)
2123         {
2124 // replace the closest match with an exact match
2125                 color_table[get_color_rgb8(color)][0] = color;
2126         }
2127         else
2128         {
2129 // add the color to the table
2130                 color_table[total_colors][0] = color;
2131                 total_colors++;
2132         }
2133         return 0;
2134 }
2135
2136 int BC_WindowBase::create_shared_colors()
2137 {
2138         create_color(BLACK);
2139         create_color(WHITE);
2140
2141         create_color(LTGREY);
2142         create_color(MEGREY);
2143         create_color(MDGREY);
2144         create_color(DKGREY);
2145
2146         create_color(LTCYAN);
2147         create_color(MECYAN);
2148         create_color(MDCYAN);
2149         create_color(DKCYAN);
2150
2151         create_color(LTGREEN);
2152         create_color(GREEN);
2153         create_color(DKGREEN);
2154
2155         create_color(LTPINK);
2156         create_color(PINK);
2157         create_color(RED);
2158
2159         create_color(LTBLUE);
2160         create_color(BLUE);
2161         create_color(DKBLUE);
2162
2163         create_color(LTYELLOW);
2164         create_color(MEYELLOW);
2165         create_color(MDYELLOW);
2166         create_color(DKYELLOW);
2167
2168         create_color(LTPURPLE);
2169         create_color(MEPURPLE);
2170         create_color(MDPURPLE);
2171         create_color(DKPURPLE);
2172
2173         create_color(FGGREY);
2174         create_color(MNBLUE);
2175         create_color(ORANGE);
2176         create_color(FTGREY);
2177
2178         return 0;
2179 }
2180
2181 int BC_WindowBase::allocate_color_table()
2182 {
2183         int red, green, blue, color;
2184         XColor col;
2185
2186         for(int i = 0; i < total_colors; i++)
2187         {
2188                 color = color_table[i][0];
2189                 red = (color & 0xFF0000) >> 16;
2190                 green = (color & 0x00FF00) >> 8;
2191                 blue = color & 0xFF;
2192
2193                 col.flags = DoRed | DoGreen | DoBlue;
2194                 col.red   = red<<8   | red;
2195                 col.green = green<<8 | green;
2196                 col.blue  = blue<<8  | blue;
2197
2198                 XAllocColor(display, cmap, &col);
2199                 color_table[i][1] = col.pixel;
2200         }
2201
2202         XInstallColormap(display, cmap);
2203         return 0;
2204 }
2205
2206 int BC_WindowBase::init_window_shape()
2207 {
2208         if(bg_pixmap && bg_pixmap->use_alpha())
2209         {
2210                 XShapeCombineMask(top_level->display,
2211                         this->win, ShapeBounding, 0, 0,
2212                         bg_pixmap->get_alpha(), ShapeSet);
2213         }
2214         return 0;
2215 }
2216
2217
2218 int BC_WindowBase::init_gc()
2219 {
2220         unsigned long gcmask;
2221         gcmask = GCFont | GCGraphicsExposures;
2222
2223         XGCValues gcvalues;
2224         gcvalues.font = mediumfont->fid;        // set the font
2225         gcvalues.graphics_exposures = 0;        // prevent expose events for every redraw
2226         gc = XCreateGC(display, rootwin, gcmask, &gcvalues);
2227
2228 // gcmask = GCCapStyle | GCJoinStyle;
2229 // XGetGCValues(display, gc, gcmask, &gcvalues);
2230 // printf("BC_WindowBase::init_gc %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2231         return 0;
2232 }
2233
2234 int BC_WindowBase::init_fonts()
2235 {
2236         if( !(smallfont = XLoadQueryFont(display, _(resources.small_font))) )
2237                 if( !(smallfont = XLoadQueryFont(display, _(resources.small_font2))) )
2238                         smallfont = XLoadQueryFont(display, "fixed");
2239         if( !(mediumfont = XLoadQueryFont(display, _(resources.medium_font))) )
2240                 if( !(mediumfont = XLoadQueryFont(display, _(resources.medium_font2))) )
2241                         mediumfont = XLoadQueryFont(display, "fixed");
2242         if( !(largefont = XLoadQueryFont(display, _(resources.large_font))) )
2243                 if( !(largefont = XLoadQueryFont(display, _(resources.large_font2))) )
2244                         largefont = XLoadQueryFont(display, "fixed");
2245         if( !(bigfont = XLoadQueryFont(display, _(resources.big_font))) )
2246                 if( !(bigfont = XLoadQueryFont(display, _(resources.big_font2))) )
2247                         bigfont = XLoadQueryFont(display, "fixed");
2248
2249         init_xft();
2250         if(get_resources()->use_fontset)
2251         {
2252                 char **m, *d;
2253                 int n;
2254
2255 // FIXME: should check the m,d,n values
2256                 smallfontset = XCreateFontSet(display, resources.small_fontset, &m, &n, &d);
2257                 if( !smallfontset )
2258                         smallfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2259                 mediumfontset = XCreateFontSet(display, resources.medium_fontset, &m, &n, &d);
2260                 if( !mediumfontset )
2261                         mediumfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2262                 largefontset = XCreateFontSet(display, resources.large_fontset, &m, &n, &d);
2263                 if( !largefontset )
2264                         largefontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2265                 bigfontset = XCreateFontSet(display, resources.big_fontset, &m, &n, &d);
2266                 if( !bigfontset )
2267                         largefontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2268                 if(bigfontset && largefontset && mediumfontset && smallfontset) {
2269                         curr_fontset = mediumfontset;
2270                         get_resources()->use_fontset = 1;
2271                 }
2272                 else {
2273                         curr_fontset = 0;
2274                         get_resources()->use_fontset = 0;
2275                 }
2276         }
2277
2278         return 0;
2279 }
2280
2281 void BC_WindowBase::init_xft()
2282 {
2283 #ifdef HAVE_XFT
2284         if( !get_resources()->use_xft ) return;
2285         if(!(smallfont_xft =
2286                 (resources.small_font_xft[0] == '-' ?
2287                         XftFontOpenXlfd(display, screen, resources.small_font_xft) :
2288                         XftFontOpenName(display, screen, resources.small_font_xft))) )
2289                 if(!(smallfont_xft =
2290                         XftFontOpenXlfd(display, screen, resources.small_font_xft2)))
2291                         smallfont_xft = XftFontOpenXlfd(display, screen, "fixed");
2292         if(!(mediumfont_xft =
2293                 (resources.medium_font_xft[0] == '-' ?
2294                         XftFontOpenXlfd(display, screen, resources.medium_font_xft) :
2295                         XftFontOpenName(display, screen, resources.medium_font_xft))) )
2296                 if(!(mediumfont_xft =
2297                         XftFontOpenXlfd(display, screen, resources.medium_font_xft2)))
2298                         mediumfont_xft = XftFontOpenXlfd(display, screen, "fixed");
2299         if(!(largefont_xft =
2300                 (resources.large_font_xft[0] == '-' ?
2301                         XftFontOpenXlfd(display, screen, resources.large_font_xft) :
2302                         XftFontOpenName(display, screen, resources.large_font_xft))) )
2303                 if(!(largefont_xft =
2304                         XftFontOpenXlfd(display, screen, resources.large_font_xft2)))
2305                         largefont_xft = XftFontOpenXlfd(display, screen, "fixed");
2306         if(!(bigfont_xft =
2307                 (resources.big_font_xft[0] == '-' ?
2308                         XftFontOpenXlfd(display, screen, resources.big_font_xft) :
2309                         XftFontOpenName(display, screen, resources.big_font_xft))) )
2310                 if(!(bigfont_xft =
2311                         XftFontOpenXlfd(display, screen, resources.big_font_xft2)))
2312                         bigfont_xft = XftFontOpenXlfd(display, screen, "fixed");
2313
2314         if(!(bold_smallfont_xft =
2315                 (resources.small_b_font_xft[0] == '-' ?
2316                         XftFontOpenXlfd(display, screen, resources.small_b_font_xft) :
2317                         XftFontOpenName(display, screen, resources.small_b_font_xft))) )
2318                 bold_smallfont_xft = XftFontOpenXlfd(display, screen, "fixed");
2319         if(!(bold_mediumfont_xft =
2320                 (resources.medium_b_font_xft[0] == '-' ?
2321                         XftFontOpenXlfd(display, screen, resources.medium_b_font_xft) :
2322                         XftFontOpenName(display, screen, resources.medium_b_font_xft))) )
2323                 bold_mediumfont_xft = XftFontOpenXlfd(display, screen, "fixed");
2324         if(!(bold_largefont_xft =
2325                 (resources.large_b_font_xft[0] == '-' ?
2326                         XftFontOpenXlfd(display, screen, resources.large_b_font_xft) :
2327                         XftFontOpenName(display, screen, resources.large_b_font_xft))) )
2328                 bold_largefont_xft = XftFontOpenXlfd(display, screen, "fixed");
2329
2330 // Extension failed to locate fonts
2331         if( !smallfont_xft || !mediumfont_xft || !largefont_xft || !bigfont_xft ||
2332             !bold_largefont_xft || !bold_mediumfont_xft || !bold_largefont_xft ) {
2333                 printf("BC_WindowBase::init_fonts: no xft fonts found:"
2334                         " %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n",
2335                         resources.small_font_xft, smallfont_xft,
2336                         resources.medium_font_xft, mediumfont_xft,
2337                         resources.large_font_xft, largefont_xft,
2338                         resources.big_font_xft, bigfont_xft,
2339                         resources.small_b_font_xft, bold_smallfont_xft,
2340                         resources.medium_b_font_xft, bold_mediumfont_xft,
2341                         resources.large_b_font_xft, bold_largefont_xft);
2342                 get_resources()->use_xft = 0;
2343                 exit(1);
2344         }
2345 #endif // HAVE_XFT
2346 }
2347
2348 void BC_WindowBase::init_im()
2349 {
2350         XIMStyles *xim_styles;
2351         XIMStyle xim_style;
2352
2353         if(!(input_method = XOpenIM(display, NULL, NULL, NULL)))
2354         {
2355                 printf("BC_WindowBase::init_im: Could not open input method.\n");
2356                 exit(1);
2357         }
2358         if(XGetIMValues(input_method, XNQueryInputStyle, &xim_styles, NULL) ||
2359                         xim_styles == NULL)
2360         {
2361                 printf("BC_WindowBase::init_im: Input method doesn't support any styles.\n");
2362                 XCloseIM(input_method);
2363                 exit(1);
2364         }
2365
2366         xim_style = 0;
2367         for(int z = 0;  z < xim_styles->count_styles;  z++)
2368         {
2369                 if(xim_styles->supported_styles[z] == (XIMPreeditNothing | XIMStatusNothing))
2370                 {
2371                         xim_style = xim_styles->supported_styles[z];
2372                         break;
2373                 }
2374         }
2375         XFree(xim_styles);
2376
2377         if(xim_style == 0)
2378         {
2379                 printf("BC_WindowBase::init_im: Input method doesn't support the style we need.\n");
2380                 XCloseIM(input_method);
2381                 exit(1);
2382         }
2383
2384         input_context = XCreateIC(input_method, XNInputStyle, xim_style,
2385                 XNClientWindow, win, XNFocusWindow, win, NULL);
2386         if(!input_context)
2387         {
2388                 printf("BC_WindowBase::init_im: Failed to create input context.\n");
2389                 XCloseIM(input_method);
2390                 exit(1);
2391         }
2392 }
2393
2394 void BC_WindowBase::finit_im()
2395 {
2396         if( input_context ) {
2397                 XDestroyIC(input_context);
2398                 input_context = 0;
2399         }
2400         if( input_method ) {
2401                 XCloseIM(input_method);
2402                 input_method = 0;
2403         }
2404 }
2405
2406
2407 int BC_WindowBase::get_color(int64_t color)
2408 {
2409 // return pixel of color
2410 // use this only for drawing subwindows not for bitmaps
2411          int i, test, difference;
2412
2413         switch(color_model)
2414         {
2415         case BC_RGB8:
2416                 if(private_color)
2417                         return get_color_rgb8(color);
2418 // test last color looked up
2419                 if(current_color_value == color)
2420                         return current_color_pixel;
2421
2422 // look up in table
2423                 current_color_value = color;
2424                 for(i = 0; i < total_colors; i++)
2425                 {
2426                         if(color_table[i][0] == color)
2427                         {
2428                                 current_color_pixel = color_table[i][1];
2429                                 return current_color_pixel;
2430                         }
2431                 }
2432
2433 // find nearest match
2434                 difference = 0xFFFFFF;
2435
2436                 for(i = 0; i < total_colors; i++)
2437                 {
2438                         test = abs((int)(color_table[i][0] - color));
2439
2440                         if(test < difference)
2441                         {
2442                                 current_color_pixel = color_table[i][1];
2443                                 difference = test;
2444                         }
2445                 }
2446                 return current_color_pixel;
2447
2448         case BC_RGB565:
2449                 return get_color_rgb16(color);
2450
2451         case BC_BGR565:
2452                 return get_color_bgr16(color);
2453
2454         case BC_RGB888:
2455         case BC_BGR888:
2456                 return client_byte_order == server_byte_order ?
2457                         color : get_color_bgr24(color);
2458
2459         default:
2460                 return color;
2461         }
2462         return 0;
2463 }
2464
2465 int BC_WindowBase::get_color_rgb8(int color)
2466 {
2467         int pixel;
2468
2469         pixel = (color & 0xc00000) >> 16;
2470         pixel += (color & 0xe000) >> 10;
2471         pixel += (color & 0xe0) >> 5;
2472         return pixel;
2473 }
2474
2475 int64_t BC_WindowBase::get_color_rgb16(int color)
2476 {
2477         int64_t result;
2478         result = (color & 0xf80000) >> 8;
2479         result += (color & 0xfc00) >> 5;
2480         result += (color & 0xf8) >> 3;
2481
2482         return result;
2483 }
2484
2485 int64_t BC_WindowBase::get_color_bgr16(int color)
2486 {
2487         int64_t result;
2488         result = (color & 0xf80000) >> 19;
2489         result += (color & 0xfc00) >> 5;
2490         result += (color & 0xf8) << 8;
2491
2492         return result;
2493 }
2494
2495 int64_t BC_WindowBase::get_color_bgr24(int color)
2496 {
2497         int64_t result;
2498         result = (color & 0xff) << 16;
2499         result += (color & 0xff00);
2500         result += (color & 0xff0000) >> 16;
2501         return result;
2502 }
2503
2504 void BC_WindowBase::start_video()
2505 {
2506         cursor_timer->update();
2507         video_on = 1;
2508 //      set_color(BLACK);
2509 //      draw_box(0, 0, get_w(), get_h());
2510 //      flash();
2511 }
2512
2513 void BC_WindowBase::stop_video()
2514 {
2515         video_on = 0;
2516         unhide_cursor();
2517 }
2518
2519
2520
2521 int64_t BC_WindowBase::get_color()
2522 {
2523         return top_level->current_color;
2524 }
2525
2526 void BC_WindowBase::set_color(int64_t color)
2527 {
2528         top_level->current_color = color;
2529         XSetForeground(top_level->display,
2530                 top_level->gc,
2531                 top_level->get_color(color));
2532 }
2533
2534 void BC_WindowBase::set_opaque()
2535 {
2536         XSetFunction(top_level->display, top_level->gc, GXcopy);
2537 }
2538
2539 void BC_WindowBase::set_inverse()
2540 {
2541         XSetFunction(top_level->display, top_level->gc, GXxor);
2542 }
2543
2544 void BC_WindowBase::set_line_width(int value)
2545 {
2546         this->line_width = value;
2547         XSetLineAttributes(top_level->display, top_level->gc, value,    /* line_width */
2548                 line_dashes == 0 ? LineSolid : LineOnOffDash,           /* line_style */
2549                 line_dashes == 0 ? CapRound : CapNotLast,               /* cap_style */
2550                 JoinMiter);                                             /* join_style */
2551
2552         if(line_dashes > 0) {
2553                 const char dashes = line_dashes;
2554                 XSetDashes(top_level->display, top_level->gc, 0, &dashes, 1);
2555         }
2556
2557 // XGCValues gcvalues;
2558 // unsigned long gcmask;
2559 // gcmask = GCCapStyle | GCJoinStyle;
2560 // XGetGCValues(top_level->display, top_level->gc, gcmask, &gcvalues);
2561 // printf("BC_WindowBase::set_line_width %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2562 }
2563
2564 void BC_WindowBase::set_line_dashes(int value)
2565 {
2566         line_dashes = value;
2567 // call XSetLineAttributes
2568         set_line_width(line_width);
2569 }
2570
2571
2572 Cursor BC_WindowBase::get_cursor_struct(int cursor)
2573 {
2574         switch(cursor)
2575         {
2576                 case ARROW_CURSOR:         return top_level->arrow_cursor;                 break;
2577                 case CROSS_CURSOR:         return top_level->cross_cursor;
2578                 case IBEAM_CURSOR:         return top_level->ibeam_cursor;                 break;
2579                 case VSEPARATE_CURSOR:     return top_level->vseparate_cursor;             break;
2580                 case HSEPARATE_CURSOR:     return top_level->hseparate_cursor;             break;
2581                 case MOVE_CURSOR:              return top_level->move_cursor;                  break;
2582                 case LEFT_CURSOR:          return top_level->left_cursor;                  break;
2583                 case RIGHT_CURSOR:         return top_level->right_cursor;                 break;
2584                 case UPRIGHT_ARROW_CURSOR: return top_level->upright_arrow_cursor;         break;
2585                 case UPLEFT_RESIZE:        return top_level->upleft_resize_cursor;         break;
2586                 case UPRIGHT_RESIZE:       return top_level->upright_resize_cursor;        break;
2587                 case DOWNLEFT_RESIZE:      return top_level->downleft_resize_cursor;       break;
2588                 case DOWNRIGHT_RESIZE:     return top_level->downright_resize_cursor;      break;
2589                 case HOURGLASS_CURSOR:     return top_level->hourglass_cursor;                 break;
2590                 case TRANSPARENT_CURSOR:   return top_level->transparent_cursor;               break;
2591         }
2592         return 0;
2593 }
2594
2595 void BC_WindowBase::set_cursor(int cursor, int override, int flush)
2596 {
2597 // inherit cursor from parent
2598         if(cursor < 0)
2599         {
2600                 XUndefineCursor(top_level->display, win);
2601                 current_cursor = cursor;
2602         }
2603         else
2604 // don't change cursor if overridden
2605         if((!top_level->is_hourglass && !is_transparent) ||
2606                 override)
2607         {
2608                 XDefineCursor(top_level->display, win, get_cursor_struct(cursor));
2609                 if(flush) this->flush();
2610         }
2611
2612         if(!override) current_cursor = cursor;
2613 }
2614
2615 void BC_WindowBase::set_x_cursor(int cursor)
2616 {
2617         temp_cursor = XCreateFontCursor(top_level->display, cursor);
2618         XDefineCursor(top_level->display, win, temp_cursor);
2619         current_cursor = cursor;
2620         flush();
2621 }
2622
2623 int BC_WindowBase::get_cursor()
2624 {
2625         return current_cursor;
2626 }
2627
2628 void BC_WindowBase::start_hourglass()
2629 {
2630         top_level->start_hourglass_recursive();
2631         top_level->flush();
2632 }
2633
2634 void BC_WindowBase::stop_hourglass()
2635 {
2636         top_level->stop_hourglass_recursive();
2637         top_level->flush();
2638 }
2639
2640 void BC_WindowBase::start_hourglass_recursive()
2641 {
2642         if(this == top_level)
2643         {
2644                 hourglass_total++;
2645                 is_hourglass = 1;
2646         }
2647
2648         if(!is_transparent)
2649         {
2650                 set_cursor(HOURGLASS_CURSOR, 1, 0);
2651                 for(int i = 0; i < subwindows->total; i++)
2652                 {
2653                         subwindows->values[i]->start_hourglass_recursive();
2654                 }
2655         }
2656 }
2657
2658 void BC_WindowBase::stop_hourglass_recursive()
2659 {
2660         if(this == top_level)
2661         {
2662                 if(hourglass_total == 0) return;
2663                 top_level->hourglass_total--;
2664         }
2665
2666         if(!top_level->hourglass_total)
2667         {
2668                 top_level->is_hourglass = 0;
2669
2670 // Cause set_cursor to perform change
2671                 if(!is_transparent)
2672                         set_cursor(current_cursor, 1, 0);
2673
2674                 for(int i = 0; i < subwindows->total; i++)
2675                 {
2676                         subwindows->values[i]->stop_hourglass_recursive();
2677                 }
2678         }
2679 }
2680
2681
2682
2683
2684 XFontStruct* BC_WindowBase::get_font_struct(int font)
2685 {
2686 // Clear out unrelated flags
2687         if(font & BOLDFACE) font ^= BOLDFACE;
2688
2689         switch(font) {
2690                 case SMALLFONT:  return top_level->smallfont;  break;
2691                 case MEDIUMFONT: return top_level->mediumfont; break;
2692                 case LARGEFONT:  return top_level->largefont;  break;
2693                 case BIGFONT:    return top_level->bigfont;    break;
2694         }
2695         return 0;
2696 }
2697
2698 XFontSet BC_WindowBase::get_fontset(int font)
2699 {
2700         XFontSet fs = 0;
2701
2702         if(get_resources()->use_fontset)
2703         {
2704                 switch(font & 0xff) {
2705                         case SMALLFONT:  fs = top_level->smallfontset; break;
2706                         case MEDIUMFONT: fs = top_level->mediumfontset; break;
2707                         case LARGEFONT:  fs = top_level->largefontset; break;
2708                         case BIGFONT:    fs = top_level->bigfontset;   break;
2709                 }
2710         }
2711
2712         return fs;
2713 }
2714
2715 #ifdef HAVE_XFT
2716 XftFont* BC_WindowBase::get_xft_struct(int font)
2717 {
2718         switch(font) {
2719                 case SMALLFONT:    return (XftFont*)top_level->smallfont_xft;
2720                 case MEDIUMFONT:   return (XftFont*)top_level->mediumfont_xft;
2721                 case LARGEFONT:    return (XftFont*)top_level->largefont_xft;
2722                 case BIGFONT:      return (XftFont*)top_level->bigfont_xft;
2723                 case MEDIUMFONT_3D: return (XftFont*)top_level->bold_mediumfont_xft;
2724                 case SMALLFONT_3D:  return (XftFont*)top_level->bold_smallfont_xft;
2725                 case LARGEFONT_3D:  return (XftFont*)top_level->bold_largefont_xft;
2726         }
2727
2728         return 0;
2729 }
2730 #endif
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740 int BC_WindowBase::get_current_font()
2741 {
2742         return top_level->current_font;
2743 }
2744
2745 void BC_WindowBase::set_font(int font)
2746 {
2747         top_level->current_font = font;
2748
2749 #ifdef HAVE_XFT
2750         if(get_resources()->use_xft) {}
2751         else
2752 #endif
2753         if(get_resources()->use_fontset) {
2754                 set_fontset(font);
2755         }
2756
2757         if(get_font_struct(font))
2758         {
2759                 XSetFont(top_level->display, top_level->gc, get_font_struct(font)->fid);
2760         }
2761
2762         return;
2763 }
2764
2765 void BC_WindowBase::set_fontset(int font)
2766 {
2767         XFontSet fs = 0;
2768
2769         if(get_resources()->use_fontset) {
2770                 switch(font) {
2771                         case SMALLFONT:  fs = top_level->smallfontset; break;
2772                         case MEDIUMFONT: fs = top_level->mediumfontset; break;
2773                         case LARGEFONT:  fs = top_level->largefontset; break;
2774                         case BIGFONT:    fs = top_level->bigfontset;   break;
2775                 }
2776         }
2777
2778         curr_fontset = fs;
2779 }
2780
2781
2782 XFontSet BC_WindowBase::get_curr_fontset(void)
2783 {
2784         if(get_resources()->use_fontset)
2785                 return curr_fontset;
2786         return 0;
2787 }
2788
2789 int BC_WindowBase::get_single_text_width(int font, const char *text, int length)
2790 {
2791 #ifdef HAVE_XFT
2792         if(get_resources()->use_xft && get_xft_struct(font))
2793         {
2794                 XGlyphInfo extents;
2795 #ifdef X_HAVE_UTF8_STRING
2796                 if(get_resources()->locale_utf8)
2797                 {
2798                         XftTextExtentsUtf8(top_level->display,
2799                                 get_xft_struct(font),
2800                                 (const XftChar8 *)text,
2801                                 length,
2802                                 &extents);
2803                 }
2804                 else
2805 #endif
2806                 {
2807                         XftTextExtents8(top_level->display,
2808                                 get_xft_struct(font),
2809                                 (const XftChar8 *)text,
2810                                 length,
2811                                 &extents);
2812                 }
2813                 return extents.xOff;
2814         }
2815         else
2816 #endif
2817         if(get_resources()->use_fontset && top_level->get_fontset(font))
2818                 return XmbTextEscapement(top_level->get_fontset(font), text, length);
2819         else
2820         if(get_font_struct(font)) 
2821                 return XTextWidth(get_font_struct(font), text, length);
2822         else
2823         {
2824                 int w = 0;
2825                 switch(font)
2826                 {
2827                         case MEDIUM_7SEGMENT:
2828                                 return get_resources()->medium_7segment[0]->get_w() * length;
2829                                 break;
2830
2831                         default:
2832                                 return 0;
2833                 }
2834                 return w;
2835         }
2836 }
2837
2838 int BC_WindowBase::get_single_text_width(int font, const wchar_t *text, int length)
2839 {
2840 #ifdef HAVE_XFT
2841         if(get_resources()->use_xft && get_xft_struct(font)) {
2842                 XGlyphInfo extents;
2843
2844                 XftTextExtents32(top_level->display, get_xft_struct(font),
2845                         (const FcChar32*)text, length, &extents);
2846                 return extents.xOff;
2847         }
2848 #endif
2849         if(!get_font_struct(font)) return 0;
2850         XChar2b xtext[length], *xp = xtext;
2851         for( int i=0; i<length; ++i,++xp ) {
2852                 xp->byte1 = (unsigned char) (text[i] >> 8);
2853                 xp->byte2 = (unsigned char) (text[i] & 0xff);
2854         }
2855         return XTextWidth16(get_font_struct(font), xtext, length);
2856 }
2857
2858 int BC_WindowBase::get_text_width(int font, const char *text, int length)
2859 {
2860         int i, j, w = 0, line_w = 0;
2861         if(length < 0) length = strlen(text);
2862
2863         for(i = 0, j = 0; i <= length; i++)
2864         {
2865                 line_w = 0;
2866                 if(text[i] == '\n')
2867                 {
2868                         line_w = get_single_text_width(font, &text[j], i - j);
2869                         j = i + 1;
2870                 }
2871                 else
2872                 if(text[i] == 0)
2873                 {
2874                         line_w = get_single_text_width(font, &text[j], length - j);
2875                 }
2876                 if(line_w > w) w = line_w;
2877         }
2878
2879         if(i > length && w == 0)
2880         {
2881                 w = get_single_text_width(font, text, length);
2882         }
2883
2884         return w;
2885 }
2886
2887 int BC_WindowBase::get_text_width(int font, const wchar_t *text, int length)
2888 {
2889         int i, j, w = 0, line_w = 0;
2890
2891         if(length < 0) length = wcslen(text);
2892
2893         for(i = 0, j = 0; i <= length; i++)
2894         {
2895                 line_w = 0;
2896                 if(text[i] == '\n')
2897                 {
2898                         line_w = get_single_text_width(font, &text[j], i - j);
2899                         j = i + 1;
2900                 }
2901                 else
2902                 if(text[i] == 0)
2903                         line_w = get_single_text_width(font, &text[j], length - j);
2904
2905                 if(line_w > w) w = line_w;
2906         }
2907
2908         if(i > length && w == 0)
2909                 w = get_single_text_width(font, text, length);
2910
2911         return w;
2912 }
2913
2914 int BC_WindowBase::get_text_ascent(int font)
2915 {
2916 #ifdef HAVE_XFT
2917         XftFont *fstruct;
2918         if( (fstruct = get_xft_struct(font)) != 0 )
2919                 return fstruct->ascent;
2920 #endif
2921         if(get_resources()->use_fontset && top_level->get_fontset(font))
2922         {
2923                 XFontSetExtents *extents;
2924
2925                 extents = XExtentsOfFontSet(top_level->get_fontset(font));
2926                 return -extents->max_logical_extent.y;
2927         }
2928
2929         if(get_font_struct(font))
2930                 return top_level->get_font_struct(font)->ascent;
2931
2932         switch(font) {
2933                 case MEDIUM_7SEGMENT:
2934                         return get_resources()->medium_7segment[0]->get_h();
2935         }
2936         return 0;
2937 }
2938
2939 int BC_WindowBase::get_text_descent(int font)
2940 {
2941 #ifdef HAVE_XFT
2942         XftFont *fstruct;
2943         if( (fstruct = get_xft_struct(font)) != 0 )
2944                 return fstruct->descent;
2945 #endif
2946         if(get_resources()->use_fontset && top_level->get_fontset(font)) {
2947                 XFontSetExtents *extents;
2948                 extents = XExtentsOfFontSet(top_level->get_fontset(font));
2949                 return (extents->max_logical_extent.height
2950                         + extents->max_logical_extent.y);
2951         }
2952
2953         if(get_font_struct(font))
2954                 return top_level->get_font_struct(font)->descent;
2955
2956         return 0;
2957 }
2958
2959 int BC_WindowBase::get_text_height(int font, const char *text)
2960 {
2961         int rowh;
2962 #ifdef HAVE_XFT
2963         XftFont *fstruct;
2964         if( (fstruct = get_xft_struct(font)) != 0 )
2965                 rowh = fstruct->height;
2966         else
2967 #endif
2968                 rowh = get_text_ascent(font) + get_text_descent(font);
2969
2970         if(!text) return rowh;
2971
2972 // Add height of lines
2973         int h = 0, i, length = strlen(text);
2974         for(i = 0; i <= length; i++)
2975         {
2976                 if(text[i] == '\n')
2977                         h++;
2978                 else
2979                 if(text[i] == 0)
2980                         h++;
2981         }
2982         return h * rowh;
2983 }
2984
2985 BC_Bitmap* BC_WindowBase::new_bitmap(int w, int h, int color_model)
2986 {
2987         if(color_model < 0) color_model = top_level->get_color_model();
2988         return new BC_Bitmap(top_level, w, h, color_model);
2989 }
2990
2991 void BC_WindowBase::init_wait()
2992 {
2993 #ifndef SINGLE_THREAD
2994         if(window_type != MAIN_WINDOW)
2995                 top_level->init_wait();
2996         init_lock->lock("BC_WindowBase::init_wait");
2997         init_lock->unlock();
2998 #endif
2999 }
3000
3001 int BC_WindowBase::accel_available(int color_model, int lock_it)
3002 {
3003         if( window_type != MAIN_WINDOW )
3004                 return top_level->accel_available(color_model, lock_it);
3005         if( lock_it )
3006                 lock_window("BC_WindowBase::accel_available");
3007
3008         switch(color_model) {
3009         case BC_YUV420P:
3010                 grab_port_id(color_model);
3011                 break;
3012
3013         case BC_YUV422:
3014                 grab_port_id(color_model);
3015                 break;
3016
3017         default:
3018                 break;
3019         }
3020
3021         if( lock_it )
3022                 unlock_window();
3023 //printf("BC_WindowBase::accel_available %d %d\n", color_model, xvideo_port_id);
3024         return xvideo_port_id >= 0 ? 1 : 0;
3025 }
3026
3027
3028 int BC_WindowBase::grab_port_id(int color_model)
3029 {
3030         if( !get_resources()->use_xvideo ||     // disabled
3031             !get_resources()->use_shm )         // Only local server is fast enough.
3032                 return -1;
3033         if( xvideo_port_id >= 0 )
3034                 return xvideo_port_id;
3035
3036         unsigned int ver, rev, reqBase, eventBase, errorBase;
3037         if( Success != XvQueryExtension(display, // XV extension is available
3038                     &ver, &rev, &reqBase, &eventBase, &errorBase) )
3039                 return -1;
3040
3041 // XV adaptors are available
3042         unsigned int numAdapt = 0;
3043         XvAdaptorInfo *info = 0;
3044         XvQueryAdaptors(display, DefaultRootWindow(display), &numAdapt, &info);
3045         if( !numAdapt )
3046                 return -1;
3047
3048 // Translate from color_model to X color model
3049         int x_color_model = BC_CModels::bc_to_x(color_model);
3050
3051 // Get adaptor with desired color model
3052         for( int i = 0; i < (int)numAdapt && xvideo_port_id == -1; i++) {
3053                 if( !(info[i].type & XvImageMask) || !info[i].num_ports ) continue;
3054 // adaptor supports XvImages
3055                 int numFormats = 0, numPorts = info[i].num_ports;
3056                 XvImageFormatValues *formats =
3057                         XvListImageFormats(display, info[i].base_id, &numFormats);
3058                 if( !formats ) continue;
3059
3060                 for( int j=0; j<numFormats && xvideo_port_id<0; ++j ) {
3061                         if( formats[j].id != x_color_model ) continue;
3062 // this adaptor supports the desired format, grab a port
3063                         for( int k=0; k<numPorts; ++k ) {
3064                                 if( Success == XvGrabPort(top_level->display,
3065                                         info[i].base_id+k, CurrentTime) ) {
3066 //printf("BC_WindowBase::grab_port_id %llx\n", info[i].base_id);
3067                                         xvideo_port_id = info[i].base_id + k;
3068                                         break;
3069                                 }
3070                         }
3071                 }
3072                 XFree(formats);
3073         }
3074
3075         XvFreeAdaptorInfo(info);
3076
3077         return xvideo_port_id;
3078 }
3079
3080
3081 int BC_WindowBase::show_window(int flush)
3082 {
3083         for(int i = 0; i < subwindows->size(); i++)
3084         {
3085                 subwindows->get(i)->show_window(0);
3086         }
3087
3088         XMapWindow(top_level->display, win);
3089         if(flush) XFlush(top_level->display);
3090 //      XSync(top_level->display, 0);
3091         hidden = 0;
3092         return 0;
3093 }
3094
3095 int BC_WindowBase::hide_window(int flush)
3096 {
3097         for(int i = 0; i < subwindows->size(); i++)
3098         {
3099                 subwindows->get(i)->hide_window(0);
3100         }
3101
3102         XUnmapWindow(top_level->display, win);
3103         if(flush) this->flush();
3104         hidden = 1;
3105         return 0;
3106 }
3107
3108 BC_MenuBar* BC_WindowBase::add_menubar(BC_MenuBar *menu_bar)
3109 {
3110         subwindows->append((BC_SubWindow*)menu_bar);
3111
3112         menu_bar->parent_window = this;
3113         menu_bar->top_level = this->top_level;
3114         menu_bar->initialize();
3115         return menu_bar;
3116 }
3117
3118 BC_WindowBase* BC_WindowBase::add_popup(BC_WindowBase *window)
3119 {
3120 //printf("BC_WindowBase::add_popup window=%p win=%p\n", window, window->win);
3121         if(this != top_level) return top_level->add_popup(window);
3122         popups.append(window);
3123         return window;
3124 }
3125
3126 void BC_WindowBase::remove_popup(BC_WindowBase *window)
3127 {
3128 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3129         if(this != top_level)
3130                 top_level->remove_popup(window);
3131         else
3132                 popups.remove(window);
3133 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3134 }
3135
3136
3137 BC_WindowBase* BC_WindowBase::add_subwindow(BC_WindowBase *subwindow)
3138 {
3139         subwindows->append(subwindow);
3140
3141         if(subwindow->bg_color == -1) subwindow->bg_color = this->bg_color;
3142
3143 // parent window must be set before the subwindow initialization
3144         subwindow->parent_window = this;
3145         subwindow->top_level = this->top_level;
3146
3147 // Execute derived initialization
3148         subwindow->initialize();
3149         return subwindow;
3150 }
3151
3152
3153 BC_WindowBase* BC_WindowBase::add_tool(BC_WindowBase *subwindow)
3154 {
3155         return add_subwindow(subwindow);
3156 }
3157
3158 int BC_WindowBase::flash(int x, int y, int w, int h, int flush)
3159 {
3160         if( !top_level->flash_enabled ) return 0;
3161 //printf("BC_WindowBase::flash %d %d %d %d %d\n", __LINE__, w, h, this->w, this->h);
3162         set_opaque();
3163         XSetWindowBackgroundPixmap(top_level->display, win, pixmap->opaque_pixmap);
3164         if(x >= 0)
3165         {
3166                 XClearArea(top_level->display, win, x, y, w, h, 0);
3167         }
3168         else
3169         {
3170                 XClearWindow(top_level->display, win);
3171         }
3172
3173         if(flush)
3174                 this->flush();
3175         return 0;
3176 }
3177
3178 int BC_WindowBase::flash(int flush)
3179 {
3180         flash(-1, -1, -1, -1, flush);
3181         return 0;
3182 }
3183
3184 void BC_WindowBase::flush()
3185 {
3186         //if(!get_window_lock())
3187         //      printf("BC_WindowBase::flush %s not locked\n", top_level->title);
3188         // X gets hosed if Flush/Sync are not user locked (at libX11-1.1.5 / libxcb-1.1.91)
3189         //   _XReply deadlocks in condition_wait waiting for xlib lock when waiters!=-1
3190         int locked  = get_window_lock();
3191         if( !locked ) lock_window("BC_WindowBase::flush");
3192         XFlush(top_level->display);
3193         if( !locked ) unlock_window();
3194 }
3195
3196 void BC_WindowBase::sync_display()
3197 {
3198         int locked  = get_window_lock();
3199         if( !locked ) lock_window("BC_WindowBase::sync_display");
3200         XSync(top_level->display, False);
3201         if( !locked ) unlock_window();
3202 }
3203
3204 int BC_WindowBase::get_window_lock()
3205 {
3206 #ifdef SINGLE_THREAD
3207         return BC_Display::display_global->get_display_locked();
3208 #else
3209         return top_level->window_lock;
3210 #endif
3211 }
3212
3213 int BC_WindowBase::lock_window(const char *location)
3214 {
3215         if(top_level && top_level != this)
3216         {
3217                 top_level->lock_window(location);
3218         }
3219         else
3220         if(top_level)
3221         {
3222                 SET_LOCK(this, title, location);
3223 #ifdef SINGLE_THREAD
3224                 BC_Display::lock_display(location);
3225 #else
3226                 XLockDisplay(top_level->display);
3227                 top_level->display_lock_owner = pthread_self();
3228 #endif
3229                 SET_LOCK2
3230                 ++top_level->window_lock;
3231         }
3232         else
3233         {
3234                 printf("BC_WindowBase::lock_window top_level NULL\n");
3235         }
3236         return 0;
3237 }
3238
3239 int BC_WindowBase::unlock_window()
3240 {
3241         if(top_level && top_level != this)
3242         {
3243                 top_level->unlock_window();
3244         }
3245         else
3246         if(top_level)
3247         {
3248                 UNSET_LOCK(this);
3249
3250 //              if(!top_level->window_lock)
3251 //              {
3252 //                      printf("BC_WindowBase::unlock_window %d %s already unlocked\n",
3253 //                              __LINE__,
3254 //                              title);
3255 //              }
3256                 if( top_level->window_lock > 0 )
3257                         if( --top_level->window_lock == 0 )
3258                                 top_level->display_lock_owner = 0;
3259 #ifdef SINGLE_THREAD
3260                 BC_Display::unlock_display();
3261 #else
3262                 XUnlockDisplay(top_level->display);
3263 #endif
3264         }
3265         else
3266         {
3267                 printf("BC_WindowBase::unlock_window top_level NULL\n");
3268         }
3269         return 0;
3270 }
3271
3272 void BC_WindowBase::set_done(int return_value)
3273 {
3274         if(done_set) return;
3275         done_set = 1;
3276         if(window_type != MAIN_WINDOW)
3277                 top_level->set_done(return_value);
3278         else
3279         {
3280 #ifdef SINGLE_THREAD
3281                 this->return_value = return_value;
3282                 BC_Display::display_global->arm_completion(this);
3283                 completion_lock->unlock();
3284 #else // SINGLE_THREAD
3285                 init_wait();
3286                 if( !event_thread ) return;
3287                 XEvent *event = new_xevent();
3288                 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
3289                 event->type = ClientMessage;
3290                 ptr->message_type = SetDoneXAtom;
3291                 ptr->format = 32;
3292                 this->return_value = return_value;
3293 // May lock up here because XSendEvent doesn't work too well 
3294 // asynchronous with XNextEvent.
3295 // This causes BC_WindowEvents to forward a copy of the event to run_window where 
3296 // it is deleted.
3297 // Deletion of event_thread is done at the end of BC_WindowBase::run_window() - by calling the destructor
3298                 put_event(event);
3299 #endif
3300         }
3301 }
3302
3303 void BC_WindowBase::close(int return_value)
3304 {
3305         hide_window();  flush();
3306         set_done(return_value);
3307 }
3308
3309 int BC_WindowBase::get_w()
3310 {
3311         return w;
3312 }
3313
3314 int BC_WindowBase::get_h()
3315 {
3316         return h;
3317 }
3318
3319 int BC_WindowBase::get_x()
3320 {
3321         return x;
3322 }
3323
3324 int BC_WindowBase::get_y()
3325 {
3326         return y;
3327 }
3328
3329 // for get_root_w/h
3330 //   WidthOfScreen/HeightOfScreen of XDefaultScreenOfDisplay
3331 //   this is the bounding box of all the screens
3332
3333 int BC_WindowBase::get_root_w(int lock_display)
3334 {
3335         if(lock_display) lock_window("BC_WindowBase::get_root_w");
3336         Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3337         int result = WidthOfScreen(def_screen);
3338         if(lock_display) unlock_window();
3339         return result;
3340 }
3341
3342 int BC_WindowBase::get_root_h(int lock_display)
3343 {
3344         if(lock_display) lock_window("BC_WindowBase::get_root_h");
3345         Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3346         int result = HeightOfScreen(def_screen);
3347         if(lock_display) unlock_window();
3348         return result;
3349 }
3350
3351 XineramaScreenInfo *
3352 BC_WindowBase::get_xinerama_info(int screen)
3353 {
3354         if( !xinerama_info || !xinerama_screens ) return 0;
3355         if( screen >= 0 ) {
3356                 for( int i=0; i<xinerama_screens; ++i )
3357                         if( xinerama_info[i].screen_number == screen )
3358                                 return &xinerama_info[i];
3359                 return 0;
3360         }
3361         int top_x = get_x(), top_y = get_y();
3362         for( int i=0; i<xinerama_screens; ++i ) {
3363                 int scr_y = top_y - xinerama_info[i].y_org;
3364                 if( scr_y < 0 || scr_y >= xinerama_info[i].height ) continue;
3365                 int scr_x = top_x - xinerama_info[i].x_org;
3366                 if( scr_x >= 0 && scr_x < xinerama_info[i].width )
3367                         return &xinerama_info[i];
3368         }
3369         return 0;
3370 }
3371
3372 int BC_WindowBase::get_screen_x(int lock_display, int screen)
3373 {
3374         int result = -1;
3375         if(lock_display) lock_window("BC_WindowBase::get_screen_x");
3376         XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3377         if( !info ) {
3378                 result = 0;
3379                 int root_w = get_root_w(0);
3380                 int root_h = get_root_h(0);
3381 // Shift X based on position of current window if dual head
3382                 if( (float)root_w/root_h > 1.8 ) {
3383                         root_w = get_screen_w(0, 0);
3384                         if( top_level->get_x() >= root_w )
3385                                 result = root_w;
3386                 }
3387         }
3388         else
3389                 result = info->x_org;
3390         if(lock_display) unlock_window();
3391         return result;
3392 }
3393
3394 int BC_WindowBase::get_screen_y(int lock_display, int screen)
3395 {
3396         if(lock_display) lock_window("BC_WindowBase::get_screen_y");
3397         XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3398         int result = !info ? 0 : info->y_org;
3399         if(lock_display) unlock_window();
3400         return result;
3401 }
3402
3403 int BC_WindowBase::get_screen_w(int lock_display, int screen)
3404 {
3405         int result = -1;
3406         if(lock_display) lock_window("BC_WindowBase::get_screen_w");
3407         XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3408         if( !info ) {
3409                 int width = get_root_w(0);
3410                 int height = get_root_h(0);
3411                 if( (float)width/height > 1.8 ) {
3412                         // If dual head, the screen width is > 16x9
3413                         // but we only want to fill one screen
3414                         // this code assumes the "big" screen is on the right
3415                         int scr_w0 = width / 2;
3416                         switch( height ) {
3417                         case 600:  scr_w0 = 800;   break;
3418                         case 720:  scr_w0 = 1280;  break;
3419                         case 1024: scr_w0 = 1280;  break;
3420                         case 1200: scr_w0 = 1600;  break;
3421                         case 1080: scr_w0 = 1920;  break;
3422                         }
3423                         int scr_w1 = width - scr_w0;
3424                         result = screen > 0 ? scr_w1 :
3425                                 screen == 0 ? scr_w0 :
3426                                 top_level->get_x() < scr_w0 ? scr_w0 : scr_w1;
3427                 }
3428                 else
3429                         result = width;
3430         }
3431         else
3432                 result = info->width;
3433         if(lock_display) unlock_window();
3434         return result;
3435 }
3436
3437 int BC_WindowBase::get_screen_h(int lock_display, int screen)
3438 {
3439         if(lock_display) lock_window("BC_WindowBase::get_screen_h");
3440         XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3441         int result = info ? info->height : get_root_h(0);
3442         if(lock_display) unlock_window();
3443         return result;
3444 }
3445
3446 // Bottom right corner
3447 int BC_WindowBase::get_x2()
3448 {
3449         return w + x;
3450 }
3451
3452 int BC_WindowBase::get_y2()
3453 {
3454         return y + h;
3455 }
3456
3457 int BC_WindowBase::get_video_on()
3458 {
3459         return video_on;
3460 }
3461
3462 int BC_WindowBase::get_hidden()
3463 {
3464         return top_level->hidden;
3465 }
3466
3467 int BC_WindowBase::cursor_inside()
3468 {
3469         return (top_level->cursor_x >= 0 &&
3470                         top_level->cursor_y >= 0 &&
3471                         top_level->cursor_x < w &&
3472                         top_level->cursor_y < h);
3473 }
3474
3475 BC_WindowBase* BC_WindowBase::get_top_level()
3476 {
3477         return top_level;
3478 }
3479
3480 BC_WindowBase* BC_WindowBase::get_parent()
3481 {
3482         return parent_window;
3483 }
3484
3485 int BC_WindowBase::get_color_model()
3486 {
3487         return top_level->color_model;
3488 }
3489
3490 BC_Resources* BC_WindowBase::get_resources()
3491 {
3492         return &BC_WindowBase::resources;
3493 }
3494
3495 BC_Synchronous* BC_WindowBase::get_synchronous()
3496 {
3497         return BC_WindowBase::resources.get_synchronous();
3498 }
3499
3500 int BC_WindowBase::get_bg_color()
3501 {
3502         return bg_color;
3503 }
3504
3505 void BC_WindowBase::set_bg_color(int color)
3506 {
3507         this->bg_color = color;
3508 }
3509
3510 BC_Pixmap* BC_WindowBase::get_bg_pixmap()
3511 {
3512         return bg_pixmap;
3513 }
3514
3515 void BC_WindowBase::set_active_subwindow(BC_WindowBase *subwindow)
3516 {
3517         top_level->active_subwindow = subwindow;
3518 }
3519
3520 int BC_WindowBase::activate()
3521 {
3522         return 0;
3523 }
3524
3525 int BC_WindowBase::deactivate()
3526 {
3527         if(window_type == MAIN_WINDOW)
3528         {
3529                 if(top_level->active_menubar) top_level->active_menubar->deactivate();
3530                 if(top_level->active_popup_menu) top_level->active_popup_menu->deactivate();
3531                 if(top_level->active_subwindow) top_level->active_subwindow->deactivate();
3532
3533                 top_level->active_menubar = 0;
3534                 top_level->active_popup_menu = 0;
3535                 top_level->active_subwindow = 0;
3536         }
3537         return 0;
3538 }
3539
3540 int BC_WindowBase::cycle_textboxes(int amount)
3541 {
3542         int result = 0;
3543         BC_WindowBase *new_textbox = 0;
3544
3545         if(amount > 0)
3546         {
3547                 BC_WindowBase *first_textbox = 0;
3548                 find_next_textbox(&first_textbox, &new_textbox, result);
3549                 if(!new_textbox) new_textbox = first_textbox;
3550
3551         }
3552         else
3553         if(amount < 0)
3554         {
3555                 BC_WindowBase *last_textbox = 0;
3556                 find_prev_textbox(&last_textbox, &new_textbox, result);
3557                 if(!new_textbox) new_textbox = last_textbox;
3558
3559         }
3560
3561         if(new_textbox != active_subwindow)
3562         {
3563                 deactivate();
3564                 new_textbox->activate();
3565         }
3566
3567         return 0;
3568 }
3569
3570 int BC_WindowBase::find_next_textbox(BC_WindowBase **first_textbox, BC_WindowBase **next_textbox, int &result)
3571 {
3572 // Search subwindows for textbox
3573         for(int i = 0; i < subwindows->total && result < 2; i++)
3574         {
3575                 BC_WindowBase *test_subwindow = subwindows->values[i];
3576                 test_subwindow->find_next_textbox(first_textbox, next_textbox, result);
3577         }
3578
3579         if(result < 2)
3580         {
3581                 if(uses_text())
3582                 {
3583                         if(!*first_textbox) *first_textbox = this;
3584
3585                         if(result < 1)
3586                         {
3587                                 if(top_level->active_subwindow == this)
3588                                         result++;
3589                         }
3590                         else
3591                         {
3592                                 result++;
3593                                 *next_textbox = this;
3594                         }
3595                 }
3596         }
3597         return 0;
3598 }
3599
3600 int BC_WindowBase::find_prev_textbox(BC_WindowBase **last_textbox, BC_WindowBase **prev_textbox, int &result)
3601 {
3602         if(result < 2)
3603         {
3604                 if(uses_text())
3605                 {
3606                         if(!*last_textbox) *last_textbox = this;
3607
3608                         if(result < 1)
3609                         {
3610                                 if(top_level->active_subwindow == this)
3611                                         result++;
3612                         }
3613                         else
3614                         {
3615                                 result++;
3616                                 *prev_textbox = this;
3617                         }
3618                 }
3619         }
3620
3621 // Search subwindows for textbox
3622         for(int i = subwindows->total - 1; i >= 0 && result < 2; i--)
3623         {
3624                 BC_WindowBase *test_subwindow = subwindows->values[i];
3625                 test_subwindow->find_prev_textbox(last_textbox, prev_textbox, result);
3626         }
3627         return 0;
3628 }
3629
3630 BC_Clipboard* BC_WindowBase::get_clipboard()
3631 {
3632 #ifdef SINGLE_THREAD
3633         return BC_Display::display_global->clipboard;
3634 #else
3635         return top_level->clipboard;
3636 #endif
3637 }
3638
3639 int BC_WindowBase::get_relative_cursor_x()
3640 {
3641         int abs_x, abs_y, x, y, win_x, win_y;
3642         unsigned int temp_mask;
3643         Window temp_win;
3644
3645         XQueryPointer(top_level->display, top_level->win,
3646            &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3647            &temp_mask);
3648
3649         XTranslateCoordinates(top_level->display, top_level->rootwin,
3650            win, abs_x, abs_y, &x, &y, &temp_win);
3651
3652         return x;
3653 }
3654
3655 int BC_WindowBase::get_relative_cursor_y()
3656 {
3657         int abs_x, abs_y, x, y, win_x, win_y;
3658         unsigned int temp_mask;
3659         Window temp_win;
3660
3661         XQueryPointer(top_level->display, top_level->win,
3662            &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3663            &temp_mask);
3664
3665         XTranslateCoordinates(top_level->display,
3666            top_level->rootwin, win, abs_x, abs_y, &x, &y, &temp_win);
3667
3668         return y;
3669 }
3670
3671 int BC_WindowBase::get_abs_cursor_x(int lock_window)
3672 {
3673         int abs_x, abs_y, win_x, win_y;
3674         unsigned int temp_mask;
3675         Window temp_win;
3676
3677         if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor_x");
3678         XQueryPointer(top_level->display, top_level->win,
3679                 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3680                 &temp_mask);
3681         if(lock_window) this->unlock_window();
3682         return abs_x;
3683 }
3684
3685 int BC_WindowBase::get_abs_cursor_y(int lock_window)
3686 {
3687         int abs_x, abs_y, win_x, win_y;
3688         unsigned int temp_mask;
3689         Window temp_win;
3690
3691         if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor_y");
3692         XQueryPointer(top_level->display, top_level->win,
3693                 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3694                 &temp_mask);
3695         if(lock_window) this->unlock_window();
3696         return abs_y;
3697 }
3698
3699 int BC_WindowBase::match_window(Window win)
3700 {
3701         if (this->win == win) return 1;
3702         int result = 0;
3703         for(int i = 0; i < subwindows->total; i++) {
3704                 result = subwindows->values[i]->match_window(win);
3705                 if (result) return result;
3706         }
3707         return 0;
3708
3709 }
3710
3711 int BC_WindowBase::get_cursor_over_window()
3712 {
3713         if(top_level != this) return top_level->get_cursor_over_window();
3714
3715         int abs_x, abs_y, win_x, win_y;
3716         unsigned int temp_mask;
3717         Window root_return, child_return;
3718
3719         int ret = XQueryPointer(display, win,
3720                 &root_return, &child_return, &abs_x, &abs_y,
3721                 &win_x, &win_y, &temp_mask);
3722 //printf("BC_WindowBase::get_cursor_over_window %d %s 0x%x %d 0x%x\n",
3723 //  __LINE__, title, win, ret, child_return);
3724
3725         int result = !ret || child_return == None ? 0 :
3726                 match_window(child_return);
3727         return result;
3728 }
3729
3730 int BC_WindowBase::cursor_above()
3731 {
3732         int rx = get_relative_cursor_x();
3733         if( rx < 0 || rx >= get_w() ) return 0;
3734         int ry = get_relative_cursor_y();
3735         if( ry < 0 || ry >= get_h() ) return 0;
3736         return 1;
3737 }
3738
3739 int BC_WindowBase::get_drag_x()
3740 {
3741         return top_level->drag_x;
3742 }
3743
3744 int BC_WindowBase::get_drag_y()
3745 {
3746         return top_level->drag_y;
3747 }
3748
3749 int BC_WindowBase::get_cursor_x()
3750 {
3751         return top_level->cursor_x;
3752 }
3753
3754 int BC_WindowBase::get_cursor_y()
3755 {
3756         return top_level->cursor_y;
3757 }
3758
3759 int BC_WindowBase::dump_windows()
3760 {
3761         printf("\tBC_WindowBase::dump_windows window=%p win=%p '%s', %dx%d+%d+%d %s\n",
3762                 this, (void*)this->win, title, w,h,x,y, typeid(*this).name());
3763         for(int i = 0; i < subwindows->size(); i++)
3764                 subwindows->get(i)->dump_windows();
3765         for(int i = 0; i < popups.size(); i++) {
3766                 BC_WindowBase *p = popups[i];
3767                 printf("\tBC_WindowBase::dump_windows popup=%p win=%p '%s', %dx%d+%d+%d %s\n",
3768                         p, (void*)p->win, p->title, p->w,p->h,p->x,p->y, typeid(*p).name());
3769         }
3770         return 0;
3771 }
3772
3773 int BC_WindowBase::is_event_win()
3774 {
3775         return this->win == top_level->event_win;
3776 }
3777
3778 void BC_WindowBase::set_dragging(int value)
3779 {
3780         is_dragging = value;
3781 }
3782
3783 int BC_WindowBase::get_dragging()
3784 {
3785         return is_dragging;
3786 }
3787
3788 int BC_WindowBase::get_buttonpress()
3789 {
3790         return top_level->button_number;
3791 }
3792
3793 int BC_WindowBase::get_button_down()
3794 {
3795         return top_level->button_down;
3796 }
3797
3798 int BC_WindowBase::alt_down()
3799 {
3800         return top_level->alt_mask;
3801 }
3802
3803 int BC_WindowBase::shift_down()
3804 {
3805         return top_level->shift_mask;
3806 }
3807
3808 int BC_WindowBase::ctrl_down()
3809 {
3810         return top_level->ctrl_mask;
3811 }
3812
3813 wchar_t* BC_WindowBase::get_wkeystring(int *length)
3814 {
3815         if(length)
3816                 *length = top_level->wkey_string_length;
3817         return top_level->wkey_string;
3818 }
3819
3820 #ifdef X_HAVE_UTF8_STRING
3821 char* BC_WindowBase::get_keypress_utf8()
3822 {
3823         return top_level->key_pressed_utf8;
3824 }
3825 #endif
3826
3827
3828 int BC_WindowBase::get_keypress()
3829 {
3830         return top_level->key_pressed;
3831 }
3832
3833 int BC_WindowBase::get_double_click()
3834 {
3835         return top_level->double_click;
3836 }
3837
3838 int BC_WindowBase::get_triple_click()
3839 {
3840         return top_level->triple_click;
3841 }
3842
3843 int BC_WindowBase::get_bgcolor()
3844 {
3845         return bg_color;
3846 }
3847
3848 int BC_WindowBase::resize_window(int w, int h)
3849 {
3850         if(this->w == w && this->h == h) return 0;
3851
3852         if(window_type == MAIN_WINDOW && !allow_resize)
3853         {
3854                 XSizeHints size_hints;
3855                 size_hints.flags = PSize | PMinSize | PMaxSize;
3856                 size_hints.width = w;
3857                 size_hints.height = h;
3858                 size_hints.min_width = w;
3859                 size_hints.max_width = w;
3860                 size_hints.min_height = h;
3861                 size_hints.max_height = h;
3862                 XSetNormalHints(top_level->display, win, &size_hints);
3863         }
3864         XResizeWindow(top_level->display, win, w, h);
3865
3866         this->w = w;
3867         this->h = h;
3868         delete pixmap;
3869         pixmap = new BC_Pixmap(this, w, h);
3870
3871 // Propagate to menubar
3872         for(int i = 0; i < subwindows->total; i++)
3873         {
3874                 subwindows->values[i]->dispatch_resize_event(w, h);
3875         }
3876
3877         draw_background(0, 0, w, h);
3878         if(top_level == this && get_resources()->recursive_resizing)
3879                 resize_history.append(new BC_ResizeCall(w, h));
3880         return 0;
3881 }
3882
3883 // The only way for resize events to be propagated is by updating the internal w and h
3884 int BC_WindowBase::resize_event(int w, int h)
3885 {
3886         if(window_type == MAIN_WINDOW)
3887         {
3888                 this->w = w;
3889                 this->h = h;
3890         }
3891         return 0;
3892 }
3893
3894 int BC_WindowBase::reposition_window(int x, int y)
3895 {
3896         reposition_window(x, y, -1, -1);
3897         return 0;
3898 }
3899
3900
3901 int BC_WindowBase::reposition_window(int x, int y, int w, int h)
3902 {
3903         int resize = 0;
3904
3905 // Some tools set their own dimensions before calling this, causing the
3906 // resize check to skip.
3907         this->x = x;
3908         this->y = y;
3909
3910         if(w > 0 && w != this->w)
3911         {
3912                 resize = 1;
3913                 this->w = w;
3914         }
3915
3916         if(h > 0 && h != this->h)
3917         {
3918                 resize = 1;
3919                 this->h = h;
3920         }
3921
3922 //printf("BC_WindowBase::reposition_window %d %d %d\n", translation_count, x_correction, y_correction);
3923
3924         if(this->w <= 0)
3925                 printf("BC_WindowBase::reposition_window this->w == %d\n", this->w);
3926         if(this->h <= 0)
3927                 printf("BC_WindowBase::reposition_window this->h == %d\n", this->h);
3928
3929         if(translation_count && window_type == MAIN_WINDOW)
3930         {
3931 // KDE shifts window right and down.
3932 // FVWM leaves window alone and adds border around it.
3933                 XMoveResizeWindow(top_level->display,
3934                         win,
3935                         x - BC_DisplayInfo::auto_reposition_x,
3936                         y - BC_DisplayInfo::auto_reposition_y,
3937                         this->w,
3938                         this->h);
3939         }
3940         else
3941         {
3942                 XMoveResizeWindow(top_level->display,
3943                         win,
3944                         x,
3945                         y,
3946                         this->w,
3947                         this->h);
3948         }
3949
3950         if(resize)
3951         {
3952                 delete pixmap;
3953                 pixmap = new BC_Pixmap(this, this->w, this->h);
3954                 clear_box(0,0, this->w, this->h);
3955 // Propagate to menubar
3956                 for(int i = 0; i < subwindows->total; i++)
3957                 {
3958                         subwindows->values[i]->dispatch_resize_event(this->w, this->h);
3959                 }
3960
3961 //              draw_background(0, 0, w, h);
3962         }
3963
3964         return 0;
3965 }
3966
3967 int BC_WindowBase::reposition_window_relative(int dx, int dy, int w, int h)
3968 {
3969         return reposition_window(get_x()+dx, get_y()+dy, w, h);
3970 }
3971
3972 int BC_WindowBase::reposition_window_relative(int dx, int dy)
3973 {
3974         return reposition_window_relative(dx, dy, -1, -1);
3975 }
3976
3977 void BC_WindowBase::set_tooltips(int v)
3978 {
3979         get_resources()->tooltips_enabled = v;
3980 }
3981
3982 void BC_WindowBase::set_force_tooltip(int v)
3983 {
3984         force_tooltip = v;
3985 }
3986
3987 int BC_WindowBase::raise_window(int do_flush)
3988 {
3989         XRaiseWindow(top_level->display, win);
3990         if(do_flush) XFlush(top_level->display);
3991         return 0;
3992 }
3993
3994 int BC_WindowBase::lower_window(int do_flush)
3995 {
3996         XLowerWindow(top_level->display, win);
3997         if(do_flush) XFlush(top_level->display);
3998         return 0;
3999 }
4000
4001 void BC_WindowBase::set_background(VFrame *bitmap)
4002 {
4003         if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
4004
4005         bg_pixmap = new BC_Pixmap(this, bitmap, PIXMAP_OPAQUE);
4006         shared_bg_pixmap = 0;
4007         draw_background(0, 0, w, h);
4008 }
4009
4010 void BC_WindowBase::put_title(const char *text)
4011 {
4012         char *cp = this->title, *ep = cp+sizeof(this->title)-1;
4013         for( const unsigned char *bp = (const unsigned char *)text; *bp && cp<ep; ++bp )
4014                 *cp++ = *bp >= ' ' ? *bp : ' ';
4015         *cp = 0;
4016 }
4017
4018 void BC_WindowBase::set_title(const char *text)
4019 {
4020         put_title(_(text));
4021
4022         char *txlist[2];
4023         txlist[0] = this->title;
4024         txlist[1] = 0;
4025
4026         XTextProperty titleprop;
4027         XmbTextListToTextProperty(top_level->display, txlist, 1,
4028                 XStdICCTextStyle, &titleprop);
4029         XSetWMName(top_level->display, top_level->win, &titleprop);
4030         XSetWMIconName(top_level->display, top_level->win, &titleprop);
4031         XFree(titleprop.value);
4032
4033         flush();
4034 }
4035
4036 void BC_WindowBase::set_utf8title(const char *text)
4037 {
4038         XTextProperty titleprop;
4039         char *txlist[2];
4040
4041         strcpy(this->title, text);
4042         txlist[0] = this->title;
4043         txlist[1] = 0;
4044
4045         Xutf8TextListToTextProperty(top_level->display, txlist,  1,
4046                 XUTF8StringStyle, &titleprop);
4047         XSetWMName(top_level->display, top_level->win, &titleprop);
4048         XSetWMIconName(top_level->display, top_level->win, &titleprop);
4049         XFree(titleprop.value);
4050
4051         flush();
4052 }
4053
4054 const char *BC_WindowBase::get_title()
4055 {
4056         return title;
4057 }
4058
4059 int BC_WindowBase::get_toggle_value()
4060 {
4061         return toggle_value;
4062 }
4063
4064 int BC_WindowBase::get_toggle_drag()
4065 {
4066         return toggle_drag;
4067 }
4068
4069 int BC_WindowBase::set_icon(VFrame *data)
4070 {
4071         if(icon_pixmap) delete icon_pixmap;
4072         icon_pixmap = new BC_Pixmap(top_level, data, PIXMAP_ALPHA, 1);
4073
4074         if(icon_window) delete icon_window;
4075         icon_window = new BC_Popup(this,
4076                 (int)BC_INFINITY,
4077                 (int)BC_INFINITY,
4078                 icon_pixmap->get_w(),
4079                 icon_pixmap->get_h(),
4080                 -1,
4081                 1, // All windows are hidden initially
4082                 icon_pixmap);
4083
4084         XWMHints wm_hints;
4085         wm_hints.flags = WindowGroupHint | IconPixmapHint | IconMaskHint | IconWindowHint;
4086         wm_hints.icon_pixmap = icon_pixmap->get_pixmap();
4087         wm_hints.icon_mask = icon_pixmap->get_alpha();
4088         wm_hints.icon_window = icon_window->win;
4089         wm_hints.window_group = XGroupLeader;
4090
4091 // for(int i = 0; i < 1000; i++)
4092 // printf("02x ", icon_pixmap->get_alpha()->get_row_pointers()[0][i]);
4093 // printf("\n");
4094
4095         XSetWMHints(top_level->display, top_level->win, &wm_hints);
4096         XSync(top_level->display, 0);
4097         return 0;
4098 }
4099
4100 int BC_WindowBase::set_w(int w)
4101 {
4102         this->w = w;
4103         return 0;
4104 }
4105
4106 int BC_WindowBase::set_h(int h)
4107 {
4108         this->h = h;
4109         return 0;
4110 }
4111
4112 int BC_WindowBase::load_defaults(BC_Hash *defaults)
4113 {
4114         BC_Resources *resources = get_resources();
4115         char string[BCTEXTLEN];
4116         int newest_id = - 1;
4117         for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4118         {
4119                 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4120                 resources->filebox_history[i].path[0] = 0;
4121                 defaults->get(string, resources->filebox_history[i].path);
4122                 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4123                 resources->filebox_history[i].id = defaults->get(string, resources->get_id());
4124                 if(resources->filebox_history[i].id > newest_id)
4125                         newest_id = resources->filebox_history[i].id;
4126         }
4127
4128         resources->filebox_id = newest_id + 1;
4129         resources->filebox_mode = defaults->get("FILEBOX_MODE", get_resources()->filebox_mode);
4130         resources->filebox_w = defaults->get("FILEBOX_W", get_resources()->filebox_w);
4131         resources->filebox_h = defaults->get("FILEBOX_H", get_resources()->filebox_h);
4132         resources->filebox_columntype[0] = defaults->get("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4133         resources->filebox_columntype[1] = defaults->get("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4134         resources->filebox_columntype[2] = defaults->get("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4135         resources->filebox_columntype[3] = defaults->get("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4136         resources->filebox_columnwidth[0] = defaults->get("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4137         resources->filebox_columnwidth[1] = defaults->get("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4138         resources->filebox_columnwidth[2] = defaults->get("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4139         resources->filebox_columnwidth[3] = defaults->get("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4140         defaults->get("FILEBOX_FILTER", resources->filebox_filter);
4141         return 0;
4142 }
4143
4144 int BC_WindowBase::save_defaults(BC_Hash *defaults)
4145 {
4146         BC_Resources *resources = get_resources();
4147         char string[BCTEXTLEN];
4148         for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4149         {
4150                 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4151                 defaults->update(string, resources->filebox_history[i].path);
4152                 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4153                 defaults->update(string, resources->filebox_history[i].id);
4154         }
4155         defaults->update("FILEBOX_MODE", resources->filebox_mode);
4156         defaults->update("FILEBOX_W", resources->filebox_w);
4157         defaults->update("FILEBOX_H", resources->filebox_h);
4158         defaults->update("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4159         defaults->update("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4160         defaults->update("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4161         defaults->update("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4162         defaults->update("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4163         defaults->update("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4164         defaults->update("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4165         defaults->update("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4166         defaults->update("FILEBOX_FILTER", resources->filebox_filter);
4167         return 0;
4168 }
4169
4170
4171
4172 // For some reason XTranslateCoordinates can take a long time to return.
4173 // We work around this by only calling it when the event windows are different.
4174 void BC_WindowBase::translate_coordinates(Window src_w,
4175                 Window dest_w,
4176                 int src_x,
4177                 int src_y,
4178                 int *dest_x_return,
4179                 int *dest_y_return)
4180 {
4181         Window tempwin = 0;
4182 //Timer timer;
4183 //timer.update();
4184         if(src_w == dest_w)
4185         {
4186                 *dest_x_return = src_x;
4187                 *dest_y_return = src_y;
4188         }
4189         else
4190         {
4191                 XTranslateCoordinates(top_level->display,
4192                         src_w,
4193                         dest_w,
4194                         src_x,
4195                         src_y,
4196                         dest_x_return,
4197                         dest_y_return,
4198                         &tempwin);
4199 //printf("BC_WindowBase::translate_coordinates 1 %lld\n", timer.get_difference());
4200         }
4201 }
4202
4203 void BC_WindowBase::get_root_coordinates(int x, int y, int *abs_x, int *abs_y)
4204 {
4205         translate_coordinates(win, top_level->rootwin, x, y, abs_x, abs_y);
4206 }
4207
4208 void BC_WindowBase::get_win_coordinates(int abs_x, int abs_y, int *x, int *y)
4209 {
4210         translate_coordinates(top_level->rootwin, win, abs_x, abs_y, x, y);
4211 }
4212
4213
4214
4215
4216
4217
4218 #ifdef HAVE_LIBXXF86VM
4219 void BC_WindowBase::closest_vm(int *vm, int *width, int *height)
4220 {
4221    int foo,bar;
4222    *vm = 0;
4223    if(XF86VidModeQueryExtension(top_level->display,&foo,&bar)) {
4224            int vm_count,i;
4225            XF86VidModeModeInfo **vm_modelines;
4226            XF86VidModeGetAllModeLines(top_level->display,XDefaultScreen(top_level->display),&vm_count,&vm_modelines);
4227            for (i = 0; i < vm_count; i++) {
4228                    if (vm_modelines[i]->hdisplay < vm_modelines[*vm]->hdisplay && vm_modelines[i]->hdisplay >= *width)
4229                            *vm = i;
4230            }
4231            display = top_level->display;
4232            if (vm_modelines[*vm]->hdisplay == *width)
4233                    *vm = -1;
4234            else
4235            {
4236                    *width = vm_modelines[*vm]->hdisplay;
4237                    *height = vm_modelines[*vm]->vdisplay;
4238            }
4239    }
4240 }
4241
4242 void BC_WindowBase::scale_vm(int vm)
4243 {
4244    int foo,bar,dotclock;
4245    if(XF86VidModeQueryExtension(top_level->display,&foo,&bar))
4246    {
4247            int vm_count;
4248            XF86VidModeModeInfo **vm_modelines;
4249            XF86VidModeModeLine vml;
4250            XF86VidModeGetAllModeLines(top_level->display,XDefaultScreen(top_level->display),&vm_count,&vm_modelines);
4251            XF86VidModeGetModeLine(top_level->display,XDefaultScreen(top_level->display),&dotclock,&vml);
4252            orig_modeline.dotclock = dotclock;
4253            orig_modeline.hdisplay = vml.hdisplay;
4254            orig_modeline.hsyncstart = vml.hsyncstart;
4255            orig_modeline.hsyncend = vml.hsyncend;
4256            orig_modeline.htotal = vml.htotal;
4257            orig_modeline.vdisplay = vml.vdisplay;
4258            orig_modeline.vsyncstart = vml.vsyncstart;
4259            orig_modeline.vsyncend = vml.vsyncend;
4260            orig_modeline.vtotal = vml.vtotal;
4261            orig_modeline.flags = vml.flags;
4262            orig_modeline.privsize = vml.privsize;
4263            // orig_modeline.private = vml.private;
4264            XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),vm_modelines[vm]);
4265            XF86VidModeSetViewPort(top_level->display,XDefaultScreen(top_level->display),0,0);
4266            XFlush(top_level->display);
4267    }
4268 }
4269
4270 void BC_WindowBase::restore_vm()
4271 {
4272    XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),&orig_modeline);
4273    XFlush(top_level->display);
4274 }
4275
4276
4277 #endif
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296 #ifndef SINGLE_THREAD
4297 int BC_WindowBase::get_event_count()
4298 {
4299         event_lock->lock("BC_WindowBase::get_event_count");
4300         int result = common_events.total;
4301         event_lock->unlock();
4302         return result;
4303 }
4304
4305 XEvent* BC_WindowBase::get_event()
4306 {
4307         XEvent *result = 0;
4308         while(!done && !result)
4309         {
4310                 event_condition->lock("BC_WindowBase::get_event");
4311                 event_lock->lock("BC_WindowBase::get_event");
4312
4313                 if(common_events.total && !done)
4314                 {
4315                         result = common_events.values[0];
4316                         common_events.remove_number(0);
4317                 }
4318
4319                 event_lock->unlock();
4320         }
4321         return result;
4322 }
4323
4324 void BC_WindowBase::put_event(XEvent *event)
4325 {
4326         event_lock->lock("BC_WindowBase::put_event");
4327         common_events.append(event);
4328         event_lock->unlock();
4329         event_condition->unlock();
4330 }
4331
4332 void BC_WindowBase::dequeue_events(Window win)
4333 {
4334         event_lock->lock("BC_WindowBase::dequeue_events");
4335
4336         int out = 0, total = common_events.size();
4337         for( int in=0; in<total; ++in ) {
4338                 if( common_events[in]->xany.window == win ) continue;
4339                 common_events[out++] = common_events[in];
4340         }
4341         common_events.total = out;
4342
4343         event_lock->unlock();
4344 }
4345
4346 #endif // SINGLE_THREAD
4347
4348 int BC_WindowBase::get_id()
4349 {
4350         return id;
4351 }
4352
4353
4354 BC_Pixmap *BC_WindowBase::create_pixmap(VFrame *vframe)
4355 {
4356         int w = vframe->get_w(), h = vframe->get_h();
4357         BC_Pixmap *icon = new BC_Pixmap(this, w, h);
4358         icon->draw_vframe(vframe, 0,0, w,h, 0,0);
4359         return icon;
4360 }
4361
4362
4363 void BC_WindowBase::flicker(int n, int ms)
4364 {
4365         int color = get_bg_color();
4366         for( int i=2*n; --i>=0; ) {
4367                 set_inverse();          set_bg_color(WHITE);
4368                 clear_box(0,0, w,h);    flash(1);
4369                 sync_display();         Timer::delay(ms);
4370         }
4371         set_bg_color(color);
4372         set_opaque();
4373 }
4374