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