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