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