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