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