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