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