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