r370: Heroine Virutal's official release 1.2.1
[cinelerra_cv/mob.git] / hvirtual / guicast / bcwindowbase.C
blobcc9ab825d5b92bf502e2e929b98eeec723f3e5c8
1 #include "bcbitmap.h"
2 #include "bcclipboard.h"
3 #include "bcdisplayinfo.h"
4 #include "bcmenubar.h"
5 #include "bcpixmap.h"
6 #include "bcpopup.h"
7 #include "bcpopupmenu.h"
8 #include "bcrepeater.h"
9 #include "bcresources.h"
10 #include "bcsignals.h"
11 #include "bcsubwindow.h"
12 #include "bcwindowbase.h"
13 #include "bcwindowevents.h"
14 #include "colormodels.h"
15 #include "colors.h"
16 #include "condition.h"
17 #include "cursors.h"
18 #include "defaults.h"
19 #include "fonts.h"
20 #include "keys.h"
21 #include "language.h"
22 #include "sizes.h"
23 #include "vframe.h"
25 #ifdef HAVE_GL
26 #include <GL/gl.h>
27 #endif
28 #include <string.h>
29 #include <unistd.h>
31 #include <X11/extensions/Xvlib.h>
32 #include <X11/extensions/shape.h>
35 BC_ResizeCall::BC_ResizeCall(int w, int h)
37         this->w = w;
38         this->h = h;
50 Mutex BC_WindowBase::opengl_lock;
52 BC_Resources BC_WindowBase::resources;
54 BC_WindowBase::BC_WindowBase()
56 //printf("BC_WindowBase::BC_WindowBase 1\n");
57         BC_WindowBase::initialize();
60 BC_WindowBase::~BC_WindowBase()
63 #ifdef HAVE_LIBXXF86VM
64    if(window_type == VIDMODE_SCALED_WINDOW && vm_switched)
65    {
66            restore_vm();   
67    }
68 #endif
70         hide_tooltip();
71         if(window_type != MAIN_WINDOW)
72         {
73                 if(top_level->active_menubar == this) top_level->active_menubar = 0;
74                 if(top_level->active_popup_menu == this) top_level->active_popup_menu = 0;
75                 if(top_level->active_subwindow == this) top_level->active_subwindow = 0;
76                 parent_window->subwindows->remove(this);
77         }
79         if(subwindows)
80         {
81                 for(int i = 0; i < subwindows->total; i++)
82                 {
83                         delete subwindows->values[i];
84                 }
85                 delete subwindows;
86         }
88         XFreePixmap(top_level->display, pixmap);
89         XDestroyWindow(top_level->display, win);
91         if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
92         if(icon_pixmap) delete icon_pixmap;
93         if(temp_bitmap) delete temp_bitmap;
96         if(window_type == MAIN_WINDOW) 
97         {
98                 
99                 XFreeGC(display, gc);
100 #ifdef HAVE_XFT
101                 if(largefont_xft) 
102                         XftFontClose (display, (XftFont*)largefont_xft);
103                 if(mediumfont_xft) 
104                         XftFontClose (display, (XftFont*)mediumfont_xft);
105                 if(smallfont_xft) 
106                         XftFontClose (display, (XftFont*)smallfont_xft);
107 #endif
108                 flush();
109 // Can't close display if another thread is waiting for events
110                 XCloseDisplay(display);
111 //              XCloseDisplay(event_display);
112                 clipboard->stop_clipboard();
113                 delete clipboard;
114         }
115         else
116         {
117                 flush();
118         }
120         resize_history.remove_all_objects();
121         common_events.remove_all_objects();
122         delete event_lock;
123         delete event_condition;
124         UNSET_ALL_LOCKS(this)
127 int BC_WindowBase::initialize()
129         window_lock = 0;
130         x = 0; 
131         y = 0; 
132         w = 0; 
133         h = 0;
134         bg_color = -1;
135         top_level = 0;
136         parent_window = 0;
137         subwindows = 0;
138         xvideo_port_id = -1;
139         video_on = 0;
140         motion_events = 0;
141         resize_events = 0;
142         translation_events = 0;
143         ctrl_mask = shift_mask = alt_mask = 0;
144         cursor_x = cursor_y = button_number = 0;
145         button_down = 0;
146         button_pressed = 0;
147         button_time1 = button_time2 = 0;
148         double_click = 0;
149         last_motion_win = 0;
150         key_pressed = 0;
151         active_menubar = 0;
152         active_popup_menu = 0;
153         active_subwindow = 0;
154         bg_pixmap = 0;
155         tooltip_text[0] = 0;
156         persistant_tooltip = 0;
157 //      next_repeat_id = 0;
158         tooltip_popup = 0;
159         tooltip_done = 0;
160         current_font = MEDIUMFONT;
161         current_cursor = ARROW_CURSOR;
162         current_color = BLACK;
163         is_dragging = 0;
164         shared_bg_pixmap = 0;
165         icon_pixmap = 0;
166         window_type = MAIN_WINDOW;
167         translation_count = 0;
168         x_correction = y_correction = 0;
169         temp_bitmap = 0;
170         tooltip_on = 0;
171         temp_cursor = 0;
172         toggle_value = 0;
173         toggle_drag = 0;
174         has_focus = 0;
175 #ifdef HAVE_LIBXXF86VM
176     vm_switched = 0;
177 #endif
178         xft_drawable = 0;
179         largefont_xft = 0;
180         mediumfont_xft = 0;
181         smallfont_xft = 0;
182 // Need these right away since put_event is called before run_window sometimes.
183         event_lock = new Mutex("BC_WindowBase::event_lock");
184         event_condition = new Condition(0, "BC_WindowBase::event_condition");
185         event_thread = 0;
187         return 0;
190 #define DEFAULT_EVENT_MASKS EnterWindowMask | \
191                         LeaveWindowMask | \
192                         ButtonPressMask | \
193                         ButtonReleaseMask | \
194                         PointerMotionMask | \
195                         FocusChangeMask
196                         
198 int BC_WindowBase::create_window(BC_WindowBase *parent_window,
199                                 char *title, 
200                                 int x,
201                                 int y,
202                                 int w, 
203                                 int h, 
204                                 int minw, 
205                                 int minh, 
206                                 int allow_resize,
207                                 int private_color, 
208                                 int hide,
209                                 int bg_color,
210                                 char *display_name,
211                                 int window_type,
212                                 BC_Pixmap *bg_pixmap)
214         XSetWindowAttributes attr;
215         unsigned long mask;
216         XSizeHints size_hints;
217         int root_w;
218         int root_h;
219 #ifdef HAVE_LIBXXF86VM
220     int vm;
221 #endif
223     if(parent_window) top_level = parent_window->top_level;
225 #ifdef HAVE_LIBXXF86VM
226     if(window_type == VIDMODE_SCALED_WINDOW)
227             closest_vm(&vm,&w,&h);
228 #endif
230         this->x = x;
231         this->y = y;
232         this->w = w;
233         this->h = h;
234         this->bg_color = bg_color;
235         this->window_type = window_type;
236         this->hidden = hide;
237         this->private_color = private_color;
238         this->parent_window = parent_window;
239         this->bg_pixmap = bg_pixmap;
240         this->allow_resize = allow_resize;
241         strcpy(this->title, _(title));
242         if(bg_pixmap) shared_bg_pixmap = 1;
244         if(parent_window) top_level = parent_window->top_level;
246         subwindows = new BC_SubWindowList;
248 // Mandatory setup
249         if(window_type == MAIN_WINDOW)
250         {
251                 top_level = this;
252                 parent_window = this;
254 // This function must be the first Xlib
255 // function a multi-threaded program calls
256                 XInitThreads();
259 // get the display connection
260                 display = init_display(display_name);
261 //              event_display = init_display(display_name);
263 // Fudge window placement
264                 root_w = get_root_w(1, 0);
265                 root_h = get_root_h(0);
266                 if(this->x + this->w > root_w) this->x = root_w - this->w;
267                 if(this->y + this->h > root_h) this->y = root_h - this->h;
268                 if(this->x < 0) this->x = 0;
269                 if(this->y < 0) this->y = 0;
270                 screen = DefaultScreen(display);
272                 rootwin = RootWindow(display, screen);
273                 vis = DefaultVisual(display, screen);
274                 default_depth = DefaultDepth(display, screen);
275                 client_byte_order = (*(u_int32_t*)"a   ") & 0x00000001;
276                 server_byte_order = (XImageByteOrder(display) == MSBFirst) ? 0 : 1;
280 // This must be done before fonts to know if antialiasing is available.
281                 init_colors();
282 // get the resources
283                 if(resources.use_shm < 0) resources.initialize_display(this);
284                 x_correction = get_resources()->get_left_border();
285                 y_correction = get_resources()->get_top_border();
287                 if(this->bg_color == -1)
288                         this->bg_color = resources.get_bg_color();
289                 init_fonts();
290                 init_gc();
291                 init_cursors();
293 // Create the window
294                 mask = CWEventMask | 
295                                 CWBackPixel | 
296                                 CWColormap | 
297                                 CWCursor;
299                 attr.event_mask = DEFAULT_EVENT_MASKS |
300                         StructureNotifyMask | 
301                         KeyPressMask;
303                 attr.background_pixel = get_color(this->bg_color);
304                 attr.colormap = cmap;
305                 attr.cursor = get_cursor_struct(ARROW_CURSOR);
307                 win = XCreateWindow(display, 
308                         rootwin, 
309                         this->x, 
310                         this->y, 
311                         this->w, 
312                         this->h, 
313                         0, 
314                         top_level->default_depth, 
315                         InputOutput, 
316                         vis, 
317                         mask, 
318                         &attr);
320                 XGetNormalHints(display, win, &size_hints);
322                 size_hints.flags = PSize | PMinSize | PMaxSize;
323                 size_hints.width = this->w;
324                 size_hints.height = this->h;
325                 size_hints.min_width = allow_resize ? minw : this->w;
326                 size_hints.max_width = allow_resize ? 32767 : this->w; 
327                 size_hints.min_height = allow_resize ? minh : this->h;
328                 size_hints.max_height = allow_resize ? 32767 : this->h; 
329                 if(x > -BC_INFINITY && x < BC_INFINITY)
330                 {
331                         size_hints.flags |= PPosition;
332                         size_hints.x = this->x;
333                         size_hints.y = this->y;
334                 }
336                 XSetStandardProperties(display, 
337                         win, 
338                         title, 
339                         title, 
340                         None, 
341                         0, 
342                         0, 
343                         &size_hints);
344                 get_atoms();
345                 
346                 clipboard = new BC_Clipboard(display_name);
347                 clipboard->start_clipboard();
348         }
350 #ifdef HAVE_LIBXXF86VM
351     if(window_type == VIDMODE_SCALED_WINDOW && vm != -1)
352     {
353             scale_vm (vm);
354             vm_switched = 1;
355     }
356 #endif
358 #ifdef HAVE_LIBXXF86VM
359     if(window_type == POPUP_WINDOW || window_type == VIDMODE_SCALED_WINDOW)
360 #else
361     if(window_type == POPUP_WINDOW)
362 #endif
363         {
364                 mask = CWEventMask | 
365                         CWBackPixel | 
366                         CWColormap | 
367                         CWOverrideRedirect | 
368                         CWSaveUnder | 
369                         CWCursor;
371                 attr.event_mask = DEFAULT_EVENT_MASKS;
373                 if(this->bg_color == -1)
374                         this->bg_color = resources.get_bg_color();
375                 attr.background_pixel = top_level->get_color(bg_color);
376                 attr.colormap = top_level->cmap;
377                 attr.cursor = top_level->get_cursor_struct(ARROW_CURSOR);
378                 attr.override_redirect = True;
379                 attr.save_under = True;
381                 win = XCreateWindow(top_level->display, 
382                         top_level->rootwin, 
383                         this->x, 
384                         this->y, 
385                         this->w, 
386                         this->h, 
387                         0, 
388                         top_level->default_depth, 
389                         InputOutput, 
390                         top_level->vis, 
391                         mask, 
392                         &attr);
393         }
395         if(window_type == SUB_WINDOW)
396         {
397                 mask = CWBackPixel | CWEventMask;
398                 attr.event_mask = DEFAULT_EVENT_MASKS;
399                 attr.background_pixel = top_level->get_color(this->bg_color);
400                 win = XCreateWindow(top_level->display, 
401                         parent_window->win, 
402                         this->x, 
403                         this->y, 
404                         this->w, 
405                         this->h, 
406                         0, 
407                         top_level->default_depth, 
408                         InputOutput, 
409                         top_level->vis, 
410                         mask, 
411                         &attr);
412                 init_window_shape();
413                 XMapWindow(top_level->display, win);
414         }
416 // Create pixmap for all windows
417         pixmap = XCreatePixmap(top_level->display, 
418                 win, 
419                 this->w, 
420                 this->h, 
421                 top_level->default_depth);
423 // Create truetype rendering surface
424 #ifdef HAVE_XFT
425         if(get_resources()->use_xft)
426         {
427 // printf("BC_WindowBase::create_window 1 %p %p %p %p\n", 
428 // top_level->display,
429 // pixmap,
430 // top_level->vis,
431 // top_level->cmap);
432                 xft_drawable = XftDrawCreate(top_level->display,
433                        pixmap,
434                        top_level->vis,
435                        top_level->cmap);
436 // printf("BC_WindowBase::create_window 10 %p %p %p %p %p\n", 
437 // xft_drawable, 
438 // top_level->display,
439 // pixmap,
440 // top_level->vis,
441 // top_level->cmap);
442         }
443 #endif
445 // Set up options for main window
446         if(window_type == MAIN_WINDOW)
447         {
448                 if(get_resources()->bg_image && !bg_pixmap && bg_color < 0)
449                 {
450                         this->bg_pixmap = new BC_Pixmap(this, 
451                                 get_resources()->bg_image, 
452                                 PIXMAP_OPAQUE);
453                 }
455                 if(!hidden) show_window();
457         }
462         draw_background(0, 0, this->w, this->h);
463         flash();
465 // Set up options for popup window
466 #ifdef HAVE_LIBXXF86VM
467     if(window_type == POPUP_WINDOW || window_type == VIDMODE_SCALED_WINDOW)
468 #else
469     if(window_type == POPUP_WINDOW)
470 #endif
471         {
472                 init_window_shape();
473                 if(!hidden) show_window();
474         }
475         return 0;
478 Display* BC_WindowBase::init_display(char *display_name)
480         Display* display;
482         if(display_name && display_name[0] == 0) display_name = NULL;
483         if((display = XOpenDisplay(display_name)) == NULL)
484         {
485                 printf("BC_WindowBase::init_display: cannot connect to X server %s\n", 
486                         display_name);
487                 if(getenv("DISPLAY") == NULL)
488         {
489                         printf("'DISPLAY' environment variable not set.\n");
490                         exit(1);
491                 }
492                 else
493 // Try again with default display.
494                 {
495                         if((display = XOpenDisplay(0)) == NULL)
496                         {
497                                 printf("BC_WindowBase::init_display: cannot connect to default X server.\n");
498                                 exit(1);
499                         }
500                 }
501         }
502         return display;
505 int BC_WindowBase::run_window()
507         done = 0;
508         return_value = 0;
511 // Events may have been sent before run_window so can't initialize them here.
513 // Start tooltips
514         if(window_type == MAIN_WINDOW)
515         {
516 //              tooltip_id = get_repeat_id();
517                 set_repeat(get_resources()->tooltip_delay);
518         }
520 // Start X server events
521         event_thread = new BC_WindowEvents(this);
522         event_thread->start();
524 // Start common events
525         while(!done)
526         {
527                 dispatch_event();
528         }
530         unset_all_repeaters();
531         hide_tooltip();
532         delete event_thread;
533         event_thread = 0;
534         event_condition->reset();
535         common_events.remove_all_objects();
536         done = 0;
538         return return_value;
541 int BC_WindowBase::get_key_masks(XEvent *event)
543 // ctrl key down
544         ctrl_mask = (event->xkey.state & ControlMask) ? 1 : 0;
545 // shift key down
546         shift_mask = (event->xkey.state & ShiftMask) ? 1 : 0;
547         alt_mask = (event->xkey.state & Mod1Mask) ? 1 : 0;
548         return 0;
557 int BC_WindowBase::dispatch_event()
559         XEvent *event = 0;
560     Window tempwin;
561         KeySym keysym;
562         char keys_return[2];
563         int result;
564         XClientMessageEvent *ptr;
565         int temp;
566         int cancel_resize, cancel_translation;
568         key_pressed = 0;
570 // If an event is waiting get it, otherwise
571 // wait for next event only if there are no compressed events.
572         if(/* XPending(display) */ 
573                 get_event_count() || 
574                 (!motion_events && !resize_events && !translation_events))
575         {
576 //              XNextEvent(display, event);
577                 event = get_event();
578 // Lock out window deletions
579                 lock_window("BC_WindowBase::dispatch_event 1");
580                 get_key_masks(event);
581         }
582         else
583 // Handle compressed events
584         {
585                 lock_window("BC_WindowBase::dispatch_event 2");
586                 if(resize_events)
587                         dispatch_resize_event(last_resize_w, last_resize_h);
588                 else
589                 if(motion_events)
590                         dispatch_motion_event();
591                 else
592                 if(translation_events)
593                         dispatch_translation_event();
595                 unlock_window();
596                 return 0;
597         }
599 //printf("1 %s %p %d\n", title, event, event->type);
600         switch(event->type)
601         {
602                 case ClientMessage:
603 // Clear the resize buffer
604                         if(resize_events) dispatch_resize_event(last_resize_w, last_resize_h);
605 // Clear the motion buffer since this can clear the window
606                         if(motion_events) dispatch_motion_event();
608                         ptr = (XClientMessageEvent*)event;
611                 if(ptr->message_type == ProtoXAtom && 
612                                 ptr->data.l[0] == DelWinXAtom)
613                 {
614                                 close_event();
615                         }
616                         else
617                         if(ptr->message_type == RepeaterXAtom)
618                         {
619                                 dispatch_repeat_event(ptr->data.l[0]);
620 // Make sure the repeater still exists.
621 //                              for(int i = 0; i < repeaters.total; i++)
622 //                              {
623 //                                      if(repeaters.values[i]->repeat_id == ptr->data.l[0])
624 //                                      {
625 //                                              dispatch_repeat_event_master(ptr->data.l[0]);
626 //                                              break;
627 //                                      }
628 //                              }
629                         }
630                         else
631                         if(ptr->message_type == SetDoneXAtom)
632                         {
633                                 done = 1;
634                         }
635                         break;
637                 case FocusIn:
638                         has_focus = 1;
639                         dispatch_focus_in();
640                         break;
642                 case FocusOut:
643                         has_focus = 0;
644                         dispatch_focus_out();
645                         break;
647                 case ButtonPress:
648                         cursor_x = event->xbutton.x;
649                         cursor_y = event->xbutton.y;
650                         button_number = event->xbutton.button;
651                         event_win = event->xany.window;
652                         button_down = 1;
653                         button_pressed = event->xbutton.button;
654                         button_time1 = button_time2;
655                         button_time2 = event->xbutton.time;
656                         drag_x = cursor_x;
657                         drag_y = cursor_y;
658                         drag_win = event_win;
659                         drag_x1 = cursor_x - get_resources()->drag_radius;
660                         drag_x2 = cursor_x + get_resources()->drag_radius;
661                         drag_y1 = cursor_y - get_resources()->drag_radius;
662                         drag_y2 = cursor_y + get_resources()->drag_radius;
664                         if(button_time2 - button_time1 < resources.double_click)
665                         {
666 // Ignore triple clicks
667                                 double_click = 1; 
668                                 button_time2 = button_time1 = 0; 
669                         }
670                         else 
671                                 double_click = 0;
673                         dispatch_button_press();
674                         break;
676                 case ButtonRelease:
677                         button_number = event->xbutton.button;
678                         event_win = event->xany.window;
679                         button_down = 0;
681                         dispatch_button_release();
682                         break;
684                 case Expose:
685                         event_win = event->xany.window;
686                         dispatch_expose_event();
687                         break;
689                 case MotionNotify:
690 // Dispatch previous motion event if this is a subsequent motion from a different window
691                         if(motion_events && last_motion_win != event->xany.window)
692                         {
693                                 dispatch_motion_event();
694                         }
696 // Buffer the current motion
697                         motion_events = 1;
698                         last_motion_x = event->xmotion.x;
699                         last_motion_y = event->xmotion.y;
700                         last_motion_win = event->xany.window;
701                         break;
703                 case ConfigureNotify:
704                         XTranslateCoordinates(top_level->display, 
705                                 top_level->win, 
706                                 top_level->rootwin, 
707                                 0, 
708                                 0, 
709                                 &last_translate_x, 
710                                 &last_translate_y, 
711                                 &tempwin);
712                         last_resize_w = event->xconfigure.width;
713                         last_resize_h = event->xconfigure.height;
715                         cancel_resize = 0;
716                         cancel_translation = 0;
718 // Resize history prevents responses to recursive resize requests
719                         for(int i = 0; i < resize_history.total && !cancel_resize; i++)
720                         {
721                                 if(resize_history.values[i]->w == last_resize_w &&
722                                         resize_history.values[i]->h == last_resize_h)
723                                 {
724                                         delete resize_history.values[i];
725                                         resize_history.remove_number(i);
726                                         cancel_resize = 1;
727                                 }
728                         }
730                         if(last_resize_w == w && last_resize_h == h)
731                                 cancel_resize = 1;
733                         if(!cancel_resize)
734                         {
735                                 resize_events = 1;
736                         }
738                         if((last_translate_x == x && last_translate_y == y))
739                                 cancel_translation = 1;
741                         if(!cancel_translation)
742                         {
743                                 translation_events = 1;
744                         }
746                         translation_count++;
747                         break;
749                 case KeyPress:
750                         keys_return[0] = 0;
751                         XLookupString((XKeyEvent*)event, keys_return, 1, &keysym, 0);
752 //printf("BC_WindowBase::dispatch_event %08x\n", keys_return[0]);
753 // block out control keys
754                         if(keysym > 0xffe0 && keysym < 0xffff) break;
755                         switch(keysym)
756                         {
757 // block out extra keys
758                         case XK_Alt_L:      
759                         case XK_Alt_R:      
760                         case XK_Shift_L:    
761                         case XK_Shift_R:    
762                         case XK_Control_L:  
763                         case XK_Control_R:  
764                                         key_pressed = 0;         
765                                         break;
767 // Translate key codes
768                                 case XK_Return:     key_pressed = RETURN;    break;
769                         case XK_Up:         key_pressed = UP;        break;
770                                 case XK_Down:       key_pressed = DOWN;      break;
771                                 case XK_Left:       key_pressed = LEFT;      break;
772                         case XK_Right:      key_pressed = RIGHT;     break;
773                         case XK_Next:       key_pressed = PGDN;      break;
774                         case XK_Prior:      key_pressed = PGUP;      break;
775                         case XK_BackSpace:  key_pressed = BACKSPACE; break;
776                         case XK_Escape:     key_pressed = ESC;       break;
777                         case XK_Tab:
778                                         if(shift_down())
779                                                 key_pressed = LEFTTAB;
780                                         else
781                                                 key_pressed = TAB;       
782                                         break;
783                                 case XK_ISO_Left_Tab: key_pressed = LEFTTAB; break;
784                                 case XK_underscore: key_pressed = '_';       break;
785                         case XK_asciitilde: key_pressed = '~';       break;
786                                 case XK_Delete:     key_pressed = DELETE;    break;
787                                 case XK_Home:       key_pressed = HOME;      break;
788                                 case XK_End:        key_pressed = END;       break;
790 // number pad
791                                 case XK_KP_Enter:       key_pressed = KPENTER;   break;
792                                 case XK_KP_Add:         key_pressed = KPPLUS;    break;
793                                 case XK_KP_1:
794                                 case XK_KP_End:         key_pressed = KP1;       break;
795                                 case XK_KP_2:
796                                 case XK_KP_Down:        key_pressed = KP2;       break;
797                                 case XK_KP_3:
798                                 case XK_KP_Page_Down:   key_pressed = KP3;       break;
799                                 case XK_KP_4:
800                                 case XK_KP_Left:        key_pressed = KP4;       break;
801                                 case XK_KP_5:
802                                 case XK_KP_Begin:       key_pressed = KP5;       break;
803                                 case XK_KP_6:
804                                 case XK_KP_Right:       key_pressed = KP6;       break;
805                                 case XK_KP_0:
806                                 case XK_KP_Insert:      key_pressed = KPINS;     break;
807                                 case XK_KP_Decimal:
808                                 case XK_KP_Delete:      key_pressed = KPDEL;     break;
809                         default:           
810                                         //key_pressed = keys_return[0]; 
811                                         key_pressed = keysym & 0xff;
812                                         break;
813                         }
815 //printf("BC_WindowBase::dispatch_event %d %d %x\n", shift_down(), alt_down(), key_pressed);
816                         result = dispatch_keypress_event();
817 // Handle some default keypresses
818                         if(!result)
819                         {
820                                 if(key_pressed == 'w' ||
821                                         key_pressed == 'W')
822                                 {
823                                         close_event();
824                                 }
825                         }
826                         break;
828                 case LeaveNotify:
829                         event_win = event->xany.window;
830                         dispatch_cursor_leave();
831                         break;
833                 case EnterNotify:
834                         event_win = event->xany.window;
835                         cursor_x = event->xcrossing.x;
836                         cursor_y = event->xcrossing.y;
837                         dispatch_cursor_enter();
838                         break;
839         }
840 //printf("100 %s %p %d\n", title, event, event->type);
842         unlock_window();
843         if(event) delete event;
844         return 0;
847 int BC_WindowBase::dispatch_expose_event()
849         int result = 0;
850         for(int i = 0; i < subwindows->total && !result; i++)
851         {
852                 result = subwindows->values[i]->dispatch_expose_event();
853         }
855 // Propagate to user
856         if(!result) expose_event();
857         return result;
860 int BC_WindowBase::dispatch_resize_event(int w, int h)
862         if(window_type == MAIN_WINDOW)
863         {
864                 resize_events = 0;
865 // Can't store w and h here because bcfilebox depends on the old w and h to
866 // reposition widgets.
867                 XFreePixmap(top_level->display, pixmap);
868                 pixmap = XCreatePixmap(top_level->display, 
869                         win, 
870                         w, 
871                         h, 
872                         top_level->default_depth);
873                 clear_box(0, 0, w, h);
874         }
876 // Propagate to subwindows
877         for(int i = 0; i < subwindows->total; i++)
878         {
879                 subwindows->values[i]->dispatch_resize_event(w, h);
880         }
882 // Propagate to user
883         resize_event(w, h);
885         if(window_type == MAIN_WINDOW)
886         {
887                 this->w = w;
888                 this->h = h;
889         }
890         return 0;
893 int BC_WindowBase::dispatch_translation_event()
895         translation_events = 0;
896         if(window_type == MAIN_WINDOW)
897         {
898                 prev_x = x;
899                 prev_y = y;
900                 x = last_translate_x;
901                 y = last_translate_y;
902 // Correct for window manager offsets
903                 x -= x_correction;
904                 y -= y_correction;
905         }
907         for(int i = 0; i < subwindows->total; i++)
908         {
909                 subwindows->values[i]->dispatch_translation_event();
910         }
912         translation_event();
913         return 0;
916 int BC_WindowBase::dispatch_motion_event()
918         int result = 0;
920         if(top_level == this)
921         {
922                 event_win = last_motion_win;
923                 motion_events = 0;
925 // Test for grab
926                 if(get_button_down() && !active_menubar && !active_popup_menu)
927                 {
928                         if(!result) 
929                         {
930                                 cursor_x = last_motion_x;
931                                 cursor_y = last_motion_y;
932                                 result = dispatch_drag_motion();
933                         }
935                         if(!result && 
936                                 (last_motion_x < drag_x1 || last_motion_x >= drag_x2 || 
937                                 last_motion_y < drag_y1 || last_motion_y >= drag_y2))
938                         {
939                                 cursor_x = drag_x;
940                                 cursor_y = drag_y;
942                                 result = dispatch_drag_start();
943                         }
944                 }
945                 cursor_x = last_motion_x;
946                 cursor_y = last_motion_y;
948                 if(active_menubar && !result) result = active_menubar->dispatch_motion_event();
949                 if(active_popup_menu && !result) result = active_popup_menu->dispatch_motion_event();
950                 if(active_subwindow && !result) result = active_subwindow->dispatch_motion_event();
951         }
953         for(int i = 0; i < subwindows->total && !result; i++)
954         {
955                 result = subwindows->values[i]->dispatch_motion_event();
956         }
958         if(!result) result = cursor_motion_event();    // give to user
959         return result;
962 int BC_WindowBase::dispatch_keypress_event()
964         int result = 0;
965         if(top_level == this)
966         {
967                 if(active_subwindow) result = active_subwindow->dispatch_keypress_event();
968         }
970         for(int i = 0; i < subwindows->total && !result; i++)
971         {
972                 result = subwindows->values[i]->dispatch_keypress_event();
973         }
975         if(!result) result = keypress_event();
977         return result;
980 int BC_WindowBase::dispatch_focus_in()
982         for(int i = 0; i < subwindows->total; i++)
983         {
984                 subwindows->values[i]->dispatch_focus_in();
985         }
987         focus_in_event();
989         return 0;
992 int BC_WindowBase::dispatch_focus_out()
994         for(int i = 0; i < subwindows->total; i++)
995         {
996                 subwindows->values[i]->dispatch_focus_out();
997         }
999         focus_out_event();
1001         return 0;
1004 int BC_WindowBase::get_has_focus()
1006         return top_level->has_focus;
1009 int BC_WindowBase::dispatch_button_press()
1011         int result = 0;
1012         if(top_level == this)
1013         {
1014                 if(active_menubar) result = active_menubar->dispatch_button_press();
1015                 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_press();
1016                 if(active_subwindow && !result) result = active_subwindow->dispatch_button_press();
1017         }
1019         for(int i = 0; i < subwindows->total && !result; i++)
1020         {
1021                 result = subwindows->values[i]->dispatch_button_press();
1022         }
1024         if(!result) result = button_press_event();
1026         return result;
1029 int BC_WindowBase::dispatch_button_release()
1031         int result = 0;
1032         if(top_level == this)
1033         {
1034                 if(active_menubar) result = active_menubar->dispatch_button_release();
1035 //printf("BC_WindowBase::dispatch_button_release 1 %d\n", result);
1036                 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_release();
1037 //printf("BC_WindowBase::dispatch_button_release 2 %p %d\n", active_subwindow, result);
1038                 if(active_subwindow && !result) result = active_subwindow->dispatch_button_release();
1039 //printf("BC_WindowBase::dispatch_button_release 3 %d\n", result);
1040                 if(!result) result = dispatch_drag_stop();
1041         }
1042 //printf("BC_WindowBase::dispatch_button_release 4 %d\n", result);
1044         for(int i = 0; i < subwindows->total && !result; i++)
1045         {
1046                 result = subwindows->values[i]->dispatch_button_release();
1047         }
1048 //printf("BC_WindowBase::dispatch_button_release 5 %d\n", result);
1050         if(!result)
1051         {
1052                 result = button_release_event();
1053         }
1054 //printf("BC_WindowBase::dispatch_button_release 6 %d\n", result);
1056         return result;
1059 // int BC_WindowBase::dispatch_repeat_event_master(long duration)
1060 // {
1061 //      int result = 0;
1062 //      BC_Repeater *repeater;
1063 // 
1064 // // Unlock the repeater if it still exists.
1065 //      for(int i = 0; i < repeaters.total; i++)
1066 //      {
1067 //              if(repeaters.values[i]->repeat_id == repeat_id)
1068 //              {
1069 //                      repeater = repeaters.values[i];
1070 //                      if(repeater->interrupted)
1071 //                      {
1072 // // Disregard
1073 //                              if(interrupt_now)
1074 //                              {
1075 // // Delete now
1076 //                                      repeater->join();
1077 //                                      repeaters.remove(repeater);
1078 //                                      delete repeater;
1079 //                              }
1080 //                      }
1081 //                      else
1082 //                      {
1083 // // Propogate to subwindows
1084 //                              if(active_menubar) result = active_menubar->dispatch_repeat_event(repeat_id);
1085 //                              if(!result && active_subwindow) result = active_subwindow->dispatch_repeat_event(repeat_id);
1086 //                              if(!result) result = dispatch_repeat_event(repeat_id);
1087 //                              repeater->repeat_mutex.unlock();
1088 //                      }
1089 //                      i = repeaters.total;
1090 //              }
1091 //      }
1092 // 
1093 //      return result;
1094 // }
1096 int BC_WindowBase::dispatch_repeat_event(int64_t duration)
1098 // all repeat event handlers get called and decide based on activity and duration
1099 // whether to respond
1100         for(int i = 0; i < subwindows->total; i++)
1101         {
1102                 subwindows->values[i]->dispatch_repeat_event(duration);
1103         }
1104         repeat_event(duration);
1106 // Unlock next signal
1107         if(window_type == MAIN_WINDOW)
1108         {
1109                 for(int i = 0; i < repeaters.total; i++)
1110                 {
1111                         if(repeaters.values[i]->delay == duration)
1112                         {
1113                                 repeaters.values[i]->repeat_lock->unlock();
1114                         }
1115                 }
1116         }
1118         return 0;
1121 int BC_WindowBase::dispatch_cursor_leave()
1123         for(int i = 0; i < subwindows->total; i++)
1124         {
1125                 subwindows->values[i]->dispatch_cursor_leave();
1126         }
1128         cursor_leave_event();
1129         return 0;
1132 int BC_WindowBase::dispatch_cursor_enter()
1134         int result = 0;
1136         if(active_menubar) result = active_menubar->dispatch_cursor_enter();
1137         if(!result && active_popup_menu) result = active_popup_menu->dispatch_cursor_enter();
1138         if(!result && active_subwindow) result = active_subwindow->dispatch_cursor_enter();
1140         for(int i = 0; !result && i < subwindows->total; i++)
1141         {
1142                 result = subwindows->values[i]->dispatch_cursor_enter();
1143         }
1145         if(!result) result = cursor_enter_event();
1146         return result;
1149 int BC_WindowBase::cursor_enter_event()
1151         return 0;
1154 int BC_WindowBase::cursor_leave_event()
1156         return 0;
1159 int BC_WindowBase::close_event()
1161         set_done(1);
1162         return 1;
1165 int BC_WindowBase::dispatch_drag_start()
1167         int result = 0;
1168         if(active_menubar) result = active_menubar->dispatch_drag_start();
1169         if(!result && active_popup_menu) result = active_popup_menu->dispatch_drag_start();
1170         if(!result && active_subwindow) result = active_subwindow->dispatch_drag_start();
1171         
1172         for(int i = 0; i < subwindows->total && !result; i++)
1173         {
1174                 result = subwindows->values[i]->dispatch_drag_start();
1175         }
1177         if(!result) result = is_dragging = drag_start_event();
1178         return result;
1181 int BC_WindowBase::dispatch_drag_stop()
1183         int result = 0;
1185         for(int i = 0; i < subwindows->total && !result; i++)
1186         {
1187                 result = subwindows->values[i]->dispatch_drag_stop();
1188         }
1190         if(is_dragging && !result) 
1191         {
1192                 drag_stop_event();
1193                 is_dragging = 0;
1194                 result = 1;
1195         }
1197         return result;
1200 int BC_WindowBase::dispatch_drag_motion()
1202         int result = 0;
1203         for(int i = 0; i < subwindows->total && !result; i++)
1204         {
1205                 result = subwindows->values[i]->dispatch_drag_motion();
1206         }
1207         
1208         if(is_dragging && !result)
1209         {
1210                 drag_motion_event();
1211                 result = 1;
1212         }
1213         
1214         return result;
1221 int BC_WindowBase::show_tooltip(int w, int h)
1223         Window tempwin;
1225         if(!tooltip_on && get_resources()->tooltips_enabled)
1226         {
1227                 int i, j, x, y;
1228                 top_level->hide_tooltip();
1230                 tooltip_on = 1;
1231                 if(w < 0)
1232                         w = get_text_width(MEDIUMFONT, tooltip_text);
1234                 if(h < 0)
1235                         h = get_text_height(MEDIUMFONT, tooltip_text);
1237                 w += TOOLTIP_MARGIN * 2;
1238                 h += TOOLTIP_MARGIN * 2;
1240                 XTranslateCoordinates(top_level->display, 
1241                                 win, 
1242                                 top_level->rootwin, 
1243                                 get_w(), 
1244                                 get_h(), 
1245                                 &x, 
1246                                 &y, 
1247                                 &tempwin);
1248                 tooltip_popup = new BC_Popup(top_level, 
1249                                         x,
1250                                         y,
1251                                         w, 
1252                                         h, 
1253                                         get_resources()->tooltip_bg_color);
1255                 draw_tooltip();
1256                 tooltip_popup->set_font(MEDIUMFONT);
1257                 tooltip_popup->flash();
1258                 tooltip_popup->flush();
1259         }
1260         return 0;
1263 int BC_WindowBase::hide_tooltip()
1265         if(subwindows)
1266                 for(int i = 0; i < subwindows->total; i++)
1267                 {
1268                         subwindows->values[i]->hide_tooltip();
1269                 }
1271         if(tooltip_on)
1272         {
1273                 tooltip_on = 0;
1274                 delete tooltip_popup;
1275                 tooltip_popup = 0;
1276         }
1277         return 0;
1280 int BC_WindowBase::set_tooltip(char *text)
1282         strcpy(this->tooltip_text, text);
1283 // Update existing tooltip if it is visible
1284         if(tooltip_on)
1285         {
1286                 draw_tooltip();
1287                 tooltip_popup->flash();
1288         }
1289         return 0;
1292 // signal the event handler to repeat
1293 int BC_WindowBase::set_repeat(int64_t duration)
1295         if(duration <= 0)
1296         {
1297                 printf("BC_WindowBase::set_repeat duration=%d\n", duration);
1298                 return 0;
1299         }
1300         if(window_type != MAIN_WINDOW) return top_level->set_repeat(duration);
1302 // test repeater database for duplicates
1303         for(int i = 0; i < repeaters.total; i++)
1304         {
1305 // Already exists
1306                 if(repeaters.values[i]->delay == duration)
1307                 {
1308                         repeaters.values[i]->start_repeating();
1309                         return 0;
1310                 }
1311         }
1313         BC_Repeater *repeater = new BC_Repeater(this, duration);
1314         repeater->initialize();
1315         repeaters.append(repeater);
1316     repeater->start_repeating();
1317         return 0;
1320 int BC_WindowBase::unset_repeat(int64_t duration)
1322         if(window_type != MAIN_WINDOW) return top_level->unset_repeat(duration);
1324         BC_Repeater *repeater = 0;
1325         for(int i = 0; i < repeaters.total; i++)
1326         {
1327                 if(repeaters.values[i]->delay == duration)
1328                 {
1329                         repeaters.values[i]->stop_repeating();
1330                 }
1331         }
1332         return 0;
1336 int BC_WindowBase::unset_all_repeaters()
1338         for(int i = 0; i < repeaters.total; i++)
1339         {
1340                 repeaters.values[i]->stop_repeating();
1341         }
1342         repeaters.remove_all_objects();
1343         return 0;
1346 // long BC_WindowBase::get_repeat_id()
1347 // {
1348 //      return top_level->next_repeat_id++;
1349 // }
1351 int BC_WindowBase::arm_repeat(int64_t duration)
1353         XEvent *event = new XEvent;
1354         XClientMessageEvent *ptr = (XClientMessageEvent*)event;
1355         ptr->type = ClientMessage;
1356         ptr->message_type = RepeaterXAtom;
1357         ptr->format = 32;
1358         ptr->data.l[0] = duration;
1360 // Couldn't use XSendEvent since it locked up randomly.
1361         put_event(event);
1362 //      XSendEvent(top_level->event_display, 
1363 //              top_level->win, 
1364 //              0, 
1365 //              0, 
1366 //              event);
1367 //      flush();
1368         return 0;
1371 int BC_WindowBase::get_atoms()
1373         SetDoneXAtom =  XInternAtom(display, "BC_REPEAT_EVENT", False);
1374         RepeaterXAtom = XInternAtom(display, "BC_CLOSE_EVENT", False);
1375         DelWinXAtom =   XInternAtom(display, "WM_DELETE_WINDOW", False);
1376         if(ProtoXAtom = XInternAtom(display, "WM_PROTOCOLS", False))
1377                 XChangeProperty(display, win, ProtoXAtom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&DelWinXAtom, True);
1378         return 0;
1381 void BC_WindowBase::init_cursors()
1383         arrow_cursor = XCreateFontCursor(display, XC_top_left_arrow);
1384         cross_cursor = XCreateFontCursor(display, XC_crosshair);
1385         ibeam_cursor = XCreateFontCursor(display, XC_xterm);
1386         vseparate_cursor = XCreateFontCursor(display, XC_sb_v_double_arrow);
1387         hseparate_cursor = XCreateFontCursor(display, XC_sb_h_double_arrow);
1388         move_cursor = XCreateFontCursor(display, XC_fleur);
1389         left_cursor = XCreateFontCursor(display, XC_sb_left_arrow);
1390         right_cursor = XCreateFontCursor(display, XC_sb_right_arrow);
1391         upright_arrow_cursor = XCreateFontCursor(display, XC_arrow);
1392         upleft_resize_cursor = XCreateFontCursor(display, XC_top_left_corner);
1393         upright_resize_cursor = XCreateFontCursor(display, XC_top_right_corner);
1394         downleft_resize_cursor = XCreateFontCursor(display, XC_bottom_left_corner);
1395         downright_resize_cursor = XCreateFontCursor(display, XC_bottom_right_corner);
1398 int BC_WindowBase::evaluate_color_model(int client_byte_order, int server_byte_order, int depth)
1400         int color_model;
1401         switch(depth)
1402         {
1403                 case 8:
1404                         color_model = BC_RGB8;
1405                         break;
1406                 case 16:
1407                         color_model = (server_byte_order == client_byte_order) ? BC_RGB565 : BC_BGR565;
1408                         break;
1409                 case 24:
1410                         color_model = server_byte_order ? BC_BGR888 : BC_RGB888;
1411                         break;
1412                 case 32:
1413                         color_model = server_byte_order ? BC_BGR8888 : BC_RGBA8888;
1414                         break;
1415         }
1416         return color_model;
1419 int BC_WindowBase::init_colors()
1421         total_colors = 0;
1422         current_color_value = current_color_pixel = 0;
1424 // Get the real depth
1425         char *data = 0;
1426         XImage *ximage;
1427         ximage = XCreateImage(top_level->display, 
1428                                         top_level->vis, 
1429                                         top_level->default_depth, 
1430                                         ZPixmap, 
1431                                         0, 
1432                                         data, 
1433                                         16, 
1434                                         16, 
1435                                         8, 
1436                                         0);
1437         bits_per_pixel = ximage->bits_per_pixel;
1438         XDestroyImage(ximage);
1440         color_model = evaluate_color_model(client_byte_order, 
1441                 server_byte_order, 
1442                 bits_per_pixel);
1443 // Get the color model
1444         switch(color_model)
1445         {
1446                 case BC_RGB8:
1447                         if(private_color)
1448                         {
1449                                 cmap = XCreateColormap(display, rootwin, vis, AllocNone);
1450                                 create_private_colors();
1451                         }
1452                         else
1453                         {
1454                                 cmap = DefaultColormap(display, screen);
1455                                 create_shared_colors();
1456                         }
1458                         allocate_color_table();
1459 // No antialiasing
1460                         get_resources()->use_xft = 0;
1461                         break;
1463                 default:
1464                         cmap = DefaultColormap(display, screen);
1465                         break;
1466         }
1467         return 0;
1470 int BC_WindowBase::create_private_colors()
1472         int color;
1473         total_colors = 256;
1475         for(int i = 0; i < 255; i++)
1476         {
1477                 color = (i & 0xc0) << 16;
1478                 color += (i & 0x38) << 10;
1479                 color += (i & 0x7) << 5;
1480                 color_table[i][0] = color;
1481         }
1482         create_shared_colors();        // overwrite the necessary colors on the table
1483         return 0;
1487 int BC_WindowBase::create_color(int color)
1489         if(total_colors == 256)
1490         {
1491 // replace the closest match with an exact match
1492                 color_table[get_color_rgb8(color)][0] = color;
1493         }
1494         else
1495         {
1496 // add the color to the table
1497                 color_table[total_colors][0] = color;
1498                 total_colors++;
1499         }
1500         return 0;
1503 int BC_WindowBase::create_shared_colors()
1505         create_color(BLACK);
1506         create_color(WHITE);   
1508         create_color(LTGREY);  
1509         create_color(MEGREY);  
1510         create_color(MDGREY);  
1511         create_color(DKGREY);                           
1513         create_color(LTCYAN);  
1514         create_color(MECYAN);  
1515         create_color(MDCYAN);  
1516         create_color(DKCYAN);  
1518         create_color(LTGREEN); 
1519         create_color(GREEN);   
1520         create_color(DKGREEN); 
1522         create_color(LTPINK);  
1523         create_color(PINK);
1524         create_color(RED);     
1526         create_color(LTBLUE);  
1527         create_color(BLUE);    
1528         create_color(DKBLUE);  
1530         create_color(LTYELLOW); 
1531         create_color(MEYELLOW); 
1532         create_color(MDYELLOW); 
1533         create_color(DKYELLOW); 
1535         create_color(LTPURPLE); 
1536         create_color(MEPURPLE); 
1537         create_color(MDPURPLE); 
1538         create_color(DKPURPLE); 
1539         return 0;
1542 int BC_WindowBase::allocate_color_table()
1544         int red, green, blue, color;
1545         int result;
1546         XColor col;
1548         for(int i = 0; i < total_colors; i++)
1549         {
1550                 color = color_table[i][0];
1551                 red = (color & 0xFF0000) >> 16;
1552                 green = (color & 0x00FF00) >> 8;
1553                 blue = color & 0xFF;
1555                 col.flags = DoRed | DoGreen | DoBlue;
1556                 col.red   = red<<8   | red;
1557                 col.green = green<<8 | green;
1558                 col.blue  = blue<<8  | blue;
1560                 XAllocColor(display, cmap, &col);
1561                 color_table[i][1] = col.pixel;
1562         }
1564         XInstallColormap(display, cmap);
1565         return 0;
1568 int BC_WindowBase::init_window_shape()
1570         if(bg_pixmap && bg_pixmap->use_alpha()) 
1571         {
1572                 XShapeCombineMask(top_level->display,
1573                 this->win,
1574                 ShapeBounding,
1575                 0,
1576                 0,
1577                 bg_pixmap->get_alpha(),
1578                 ShapeSet);
1579         }
1580         return 0;
1584 int BC_WindowBase::init_gc()
1586         unsigned long gcmask;
1587         gcmask = GCFont | GCGraphicsExposures;
1589         XGCValues gcvalues;
1590         gcvalues.font = mediumfont->fid;        // set the font
1591         gcvalues.graphics_exposures = 0;        // prevent expose events for every redraw
1592         gc = XCreateGC(display, rootwin, gcmask, &gcvalues);
1593         return 0;
1596 int BC_WindowBase::init_fonts()
1598         if((largefont = XLoadQueryFont(display, _(resources.large_font))) == NULL &&
1599                 (largefont = XLoadQueryFont(display, _(resources.large_font2))) == NULL) 
1600                 largefont = XLoadQueryFont(display, "fixed"); 
1602         if((mediumfont = XLoadQueryFont(display, _(resources.medium_font))) == NULL &&
1603                 (mediumfont = XLoadQueryFont(display, _(resources.medium_font2))) == NULL)
1604                 mediumfont = XLoadQueryFont(display, "fixed"); 
1606         if((smallfont = XLoadQueryFont(display, _(resources.small_font))) == NULL &&
1607                 (smallfont = XLoadQueryFont(display, _(resources.small_font2))) == NULL)
1608                 smallfont = XLoadQueryFont(display, "fixed");
1610 #ifdef HAVE_XFT
1611         if(get_resources()->use_xft)
1612         {
1615 //printf("BC_WindowBase::init_fonts 1 %p %p %s\n", display, screen, resources.large_font_xft);
1617                 if(!(largefont_xft = XftFontOpenXlfd(display,
1618                     screen,
1619                     resources.large_font_xft)))
1620                 {
1621                         largefont_xft = XftFontOpenXlfd(display,
1622                         screen,
1623                         "fixed");
1624                 }
1625 //printf("BC_WindowBase::init_fonts 1 %p\n", largefont_xft);
1626                 if(!(largefont_xft = XftFontOpenXlfd(display,
1627                     screen,
1628                     resources.large_font_xft)))
1629                 {
1630                         largefont_xft = XftFontOpenXlfd(display,
1631                         screen,
1632                         "fixed");
1633                 }
1634 //printf("BC_WindowBase::init_fonts 2 %p\n", largefont_xft);
1637                 if(!(mediumfont_xft = XftFontOpenXlfd(display,
1638                       screen,
1639                       resources.medium_font_xft)))
1640                 {
1641                         mediumfont_xft = XftFontOpenXlfd(display,
1642                         screen,
1643                         "fixed");
1644                 }
1647                 if(!(smallfont_xft = XftFontOpenXlfd(display,
1648                       screen,
1649                       resources.small_font_xft)))
1650                 {
1651                           smallfont_xft = XftFontOpenXlfd(display,
1652                           screen,
1653                           "fixed");
1654                 }
1656 //printf("BC_WindowBase::init_fonts 100 %s %p\n", 
1657 //resources.medium_font, 
1658 //mediumfont_xft);
1660 printf("BC_WindowBase::init_fonts: %s=%p %s=%p %s=%p\n",
1661         resources.large_font_xft,
1662         largefontset,
1663         resources.medium_font_xft,
1664         mediumfontset,
1665         resources.small_font_xft,
1666         smallfontset);
1668 // Extension failed to locate fonts
1669                 if(!largefontset || !mediumfontset || !smallfontset)
1670                 {
1671                         printf("BC_WindowBase::init_fonts: no xft fonts found %s=%p %s=%p %s=%p\n",
1672                                 resources.large_font_xft,
1673                                 largefontset,
1674                                 resources.medium_font_xft,
1675                                 mediumfontset,
1676                                 resources.small_font_xft,
1677                                 smallfontset);
1678                         get_resources()->use_xft = 0;
1679                 }
1680         }
1681         else
1682 #endif
1683         if(get_resources()->use_fontset)
1684         {
1685                 char **m, *d;
1686                 int n;
1688 // FIXME: should check the m,d,n values
1689                 if((largefontset = XCreateFontSet(display, 
1690                         resources.large_fontset,
1691             &m, 
1692                         &n, 
1693                         &d)) == 0)
1694             largefontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
1695                 if((mediumfontset = XCreateFontSet(display, 
1696                         resources.medium_fontset,
1697             &m, 
1698                         &n, 
1699                         &d)) == 0)
1700             mediumfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
1701                 if((smallfontset = XCreateFontSet(display, 
1702                         resources.small_fontset,
1703             &m, 
1704                         &n, 
1705                         &d)) == 0)
1706             smallfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
1708                 if(largefontset && mediumfontset && smallfontset)
1709                 {
1710                         curr_fontset = mediumfontset;
1711                         get_resources()->use_fontset = 1;
1712                 }
1713                 else
1714                 {
1715                         curr_fontset = 0;
1716                         get_resources()->use_fontset = 0;
1717                 }
1718         }
1720         return 0;
1723 int BC_WindowBase::get_color(int64_t color) 
1725 // return pixel of color
1726 // use this only for drawing subwindows not for bitmaps
1727          int i, test, difference, result;
1729         switch(color_model)
1730         {
1731                 case BC_RGB8:
1732                         if(private_color)
1733                         {
1734                                 return get_color_rgb8(color);
1735                         }
1736                         else
1737                         {
1738 // test last color looked up
1739                                 if(current_color_value == color) return current_color_pixel;
1741 // look up in table
1742                                 current_color_value = color;
1743                                 for(i = 0; i < total_colors; i++)
1744                                 {
1745                                         if(color_table[i][0] == color)
1746                                         {
1747                                                 current_color_pixel = color_table[i][1];
1748                                                 return current_color_pixel;
1749                                         }
1750                                 }
1752 // find nearest match
1753                                 difference = 0xFFFFFF;
1755                                 for(i = 0, result = 0; i < total_colors; i++)
1756                                 {
1757                                         test = abs((int)(color_table[i][0] - color));
1759                                         if(test < difference) 
1760                                         {
1761                                                 current_color_pixel = color_table[i][1]; 
1762                                                 difference = test;
1763                                         }
1764                                 }
1766                                 return current_color_pixel;
1767                         }
1768                         break;  
1770                 case BC_RGB565:
1771                         return get_color_rgb16(color);
1772                         break;
1774                 case BC_BGR565:
1775                         return get_color_bgr16(color);
1776                         break;
1778                 case BC_RGB888:
1779                 case BC_BGR888:
1780                         if(client_byte_order == server_byte_order)
1781                                 return color;
1782                         else
1783                                 get_color_bgr24(color);
1784                         break;
1786                 default:
1787                         return color;
1788                         break;  
1789         }
1790         return 0;
1793 int BC_WindowBase::get_color_rgb8(int color)
1795         int pixel;
1797         pixel = (color & 0xc00000) >> 16;
1798         pixel += (color & 0xe000) >> 10;
1799         pixel += (color & 0xe0) >> 5;
1800         return pixel;
1803 int64_t BC_WindowBase::get_color_rgb16(int color)
1805         int64_t result;
1806         result = (color & 0xf80000) >> 8;
1807         result += (color & 0xfc00) >> 5;
1808         result += (color & 0xf8) >> 3;
1809         
1810         return result;
1813 int64_t BC_WindowBase::get_color_bgr16(int color)
1815         int64_t result;
1816         result = (color & 0xf80000) >> 19;
1817         result += (color & 0xfc00) >> 5;
1818         result += (color & 0xf8) << 8;
1820         return result;
1823 int64_t BC_WindowBase::get_color_bgr24(int color)
1825         int64_t result;
1826         result = (color & 0xff) << 16;
1827         result += (color & 0xff00);
1828         result += (color & 0xff0000) >> 16;
1829         return result;
1832 int BC_WindowBase::video_is_on()
1834         return video_on;
1837 void BC_WindowBase::start_video()
1839         video_on = 1;
1840         set_color(BLACK);
1841         draw_box(0, 0, get_w(), get_h());
1842         flash();
1845 void BC_WindowBase::stop_video()
1847         video_on = 0;
1852 int64_t BC_WindowBase::get_color()
1854         return top_level->current_color;
1857 void BC_WindowBase::set_color(int64_t color)
1859         top_level->current_color = color;
1860         XSetForeground(top_level->display, 
1861                 top_level->gc, 
1862                 top_level->get_color(color));
1865 void BC_WindowBase::set_opaque()
1867         XSetFunction(top_level->display, top_level->gc, GXcopy);
1870 void BC_WindowBase::set_inverse() 
1872         XSetFunction(top_level->display, top_level->gc, GXxor);
1875 Cursor BC_WindowBase::get_cursor_struct(int cursor)
1877         switch(cursor)
1878         {
1879                 case ARROW_CURSOR:         return top_level->arrow_cursor;                 break;
1880                 case CROSS_CURSOR:         return top_level->cross_cursor;
1881                 case IBEAM_CURSOR:         return top_level->ibeam_cursor;                 break;
1882                 case VSEPARATE_CURSOR:     return top_level->vseparate_cursor;             break;
1883                 case HSEPARATE_CURSOR:     return top_level->hseparate_cursor;             break;
1884                 case MOVE_CURSOR:              return top_level->move_cursor;                  break;
1885                 case LEFT_CURSOR:          return top_level->left_cursor;                  break;
1886                 case RIGHT_CURSOR:         return top_level->right_cursor;                 break;
1887                 case UPRIGHT_ARROW_CURSOR: return top_level->upright_arrow_cursor;         break;
1888                 case UPLEFT_RESIZE:        return top_level->upleft_resize_cursor;         break;
1889                 case UPRIGHT_RESIZE:       return top_level->upright_resize_cursor;        break;
1890                 case DOWNLEFT_RESIZE:      return top_level->downleft_resize_cursor;       break;
1891                 case DOWNRIGHT_RESIZE:     return top_level->downright_resize_cursor;      break;
1892         }
1893         return 0;
1896 void BC_WindowBase::set_cursor(int cursor)
1898         XDefineCursor(top_level->display, win, get_cursor_struct(cursor));
1899         current_cursor = cursor;
1900         flush();
1903 void BC_WindowBase::set_x_cursor(int cursor)
1905         temp_cursor = XCreateFontCursor(top_level->display, cursor);
1906         XDefineCursor(top_level->display, win, temp_cursor);
1907         current_cursor = cursor;
1908         flush();
1911 int BC_WindowBase::get_cursor()
1913         return current_cursor;
1922 XFontStruct* BC_WindowBase::get_font_struct(int font)
1924 // Clear out unrelated flags
1925         if(font & BOLDFACE) font ^= BOLDFACE;
1926         
1927         switch(font)
1928         {
1929                 case MEDIUMFONT: return top_level->mediumfont; break;
1930                 case SMALLFONT:  return top_level->smallfont;  break;
1931                 case LARGEFONT:  return top_level->largefont;  break;
1932         }
1933         return 0;
1936 XFontSet BC_WindowBase::get_fontset(int font)
1938         XFontSet fs = 0;
1940         if(get_resources()->use_fontset)
1941         {
1942                 switch(font)
1943                 {
1944                         case SMALLFONT:  fs = top_level->smallfontset; break;
1945                         case LARGEFONT:  fs = top_level->largefontset; break;
1946                         case MEDIUMFONT: fs = top_level->mediumfontset; break;
1947                 }
1948         }
1950         return fs;
1953 #ifdef HAVE_XFT
1954 XftFont* BC_WindowBase::get_xft_struct(int font)
1956 // Clear out unrelated flags
1957         if(font & BOLDFACE) font ^= BOLDFACE;
1959         switch(font)
1960         {
1961                 case MEDIUMFONT:   return (XftFont*)top_level->mediumfont_xft; break;
1962                 case SMALLFONT:    return (XftFont*)top_level->smallfont_xft;  break;
1963                 case LARGEFONT:    return (XftFont*)top_level->largefont_xft;  break;
1964         }
1966         return 0;
1968 #endif
1980 void BC_WindowBase::set_font(int font)
1982         top_level->current_font = font;
1985 #ifdef HAVE_XFT
1986         if(get_resources()->use_xft)
1987         {
1988                 ;
1989         }
1990         else
1991 #endif
1992         if(get_resources()->use_fontset)
1993         {
1994                 set_fontset(font);
1995         }
1997         if(get_font_struct(font))
1998         {
1999                 XSetFont(top_level->display, top_level->gc, get_font_struct(font)->fid);
2000         }
2002         return;
2005 void BC_WindowBase::set_fontset(int font)
2007         XFontSet fs = 0;
2009         if(get_resources()->use_fontset)
2010         {
2011                 switch(font)
2012                 {
2013                         case SMALLFONT:  fs = top_level->smallfontset; break;
2014                         case LARGEFONT:  fs = top_level->largefontset; break;
2015                         case MEDIUMFONT: fs = top_level->mediumfontset; break;
2016                 }
2017         }
2019         curr_fontset = fs;
2023 XFontSet BC_WindowBase::get_curr_fontset(void)
2025         if(get_resources()->use_fontset)
2026                 return curr_fontset;
2027         return 0;
2030 int BC_WindowBase::get_single_text_width(int font, char *text, int length)
2032 #ifdef HAVE_XFT
2033         if(get_resources()->use_xft && get_xft_struct(font))
2034         {
2035                 XGlyphInfo extents;
2036                 XftTextExtents8(top_level->display,
2037                         get_xft_struct(font),
2038                         (FcChar8*)text, 
2039                         length,
2040                         &extents);
2041                 return extents.xOff;
2042         }
2043         else
2044 #endif
2045         if(get_resources()->use_fontset && top_level->get_fontset(font))
2046                 return XmbTextEscapement(top_level->get_fontset(font), text, length);
2047         else
2048         if(get_font_struct(font)) 
2049                 return XTextWidth(get_font_struct(font), text, length);
2050         else
2051         {
2052                 int w = 0;
2053                 switch(font)
2054                 {
2055                         case MEDIUM_7SEGMENT:
2056                                 return get_resources()->medium_7segment[0]->get_w() * length;
2057                                 break;
2059                         default:
2060                                 return 0;
2061                 }
2062                 return w;
2063         }
2066 int BC_WindowBase::get_text_width(int font, char *text, int length)
2068         int i, j, w = 0, line_w = 0;
2069         if(length < 0) length = strlen(text);
2071         for(i = 0, j = 0; i <= length; i++)
2072         {
2073                 line_w = 0;
2074                 if(text[i] == '\n')
2075                 {
2076                         line_w = get_single_text_width(font, &text[j], i - j);
2077                         j = i + 1;
2078                 }
2079                 else
2080                 if(text[i] == 0)
2081                 {
2082                         line_w = get_single_text_width(font, &text[j], length - j);
2083                 }
2084                 if(line_w > w) w = line_w;
2085         }
2087         if(i > length && w == 0)
2088         {
2089                 w = get_single_text_width(font, text, length);
2090         }
2092         return w;
2095 int BC_WindowBase::get_text_ascent(int font)
2097 #ifdef HAVE_XFT
2098         if(get_resources()->use_xft && get_xft_struct(font))
2099         {
2100                 XGlyphInfo extents;
2101                 XftTextExtents8(top_level->display,
2102                         get_xft_struct(font),
2103                         (FcChar8*)"O", 
2104                         1,
2105                         &extents);
2106                 return extents.y;
2107         }
2108         else
2109 #endif
2110         if(get_resources()->use_fontset && top_level->get_fontset(font))
2111         {
2112         XFontSetExtents *extents;
2114         extents = XExtentsOfFontSet(top_level->get_fontset(font));
2115         return -extents->max_logical_extent.y;
2116         }
2117         else
2118         if(get_font_struct(font))
2119                 return top_level->get_font_struct(font)->ascent;
2120         else
2121         switch(font)
2122         {
2123                 case MEDIUM_7SEGMENT:
2124                         return get_resources()->medium_7segment[0]->get_h();
2125                         break;
2127                 default:
2128                         return 0;
2129         }
2132 int BC_WindowBase::get_text_descent(int font)
2134 #ifdef HAVE_XFT
2135         if(get_resources()->use_xft && get_xft_struct(font))
2136         {
2137                 XGlyphInfo extents;
2138                 XftTextExtents8(top_level->display,
2139                         get_xft_struct(font),
2140                         (FcChar8*)"j", 
2141                         1,
2142                         &extents);
2143                 return extents.height - extents.y;
2144         }
2145         else
2146 #endif
2147     if(get_resources()->use_fontset && top_level->get_fontset(font))
2148     {
2149         XFontSetExtents *extents;
2151         extents = XExtentsOfFontSet(top_level->get_fontset(font));
2152         return (extents->max_logical_extent.height
2153                         + extents->max_logical_extent.y);
2154     }
2155     else
2156         if(get_font_struct(font))
2157                 return top_level->get_font_struct(font)->descent;
2158         else
2159         switch(font)
2160         {
2161                 default:
2162                         return 0;
2163         }
2166 int BC_WindowBase::get_text_height(int font, char *text)
2168         if(!text) return get_text_ascent(font) + get_text_descent(font);
2170 // Add height of lines
2171         int h = 0, i, length = strlen(text);
2172         for(i = 0; i <= length; i++)
2173         {
2174                 if(text[i] == '\n')
2175                         h++;
2176                 else
2177                 if(text[i] == 0)
2178                         h++;
2179         }
2180         return h * (get_text_ascent(font) + get_text_descent(font));
2183 BC_Bitmap* BC_WindowBase::new_bitmap(int w, int h, int color_model)
2185         if(color_model < 0) color_model = top_level->get_color_model();
2186         return new BC_Bitmap(top_level, w, h, color_model);
2189 int BC_WindowBase::accel_available(int color_model)
2191         if(window_type != MAIN_WINDOW) 
2192                 return top_level->accel_available(color_model);
2194         int result = 0;
2196         switch(color_model)
2197         {
2198                 case BC_YUV420P:
2199                         result = grab_port_id(this, color_model);
2200                         if(result >= 0)
2201                         {
2202                                 xvideo_port_id = result;
2203                                 result = 1;
2204                         }
2205                         else
2206                                 result = 0;
2207                         break;
2209                 case BC_YUV422P:
2210                         result = 0;
2211                         break;
2213                 case BC_YUV422:
2214 //printf("BC_WindowBase::accel_available 1\n");
2215                         result = grab_port_id(this, color_model);
2216 //printf("BC_WindowBase::accel_available 2 %d\n", result);
2217                         if(result >= 0)
2218                         {
2219                                 xvideo_port_id = result;
2220                                 result = 1;
2221                         }
2222                         else
2223                                 result = 0;
2224 //printf("BC_WindowBase::accel_available 3 %d\n", xvideo_port_id);
2225                         break;
2227                 default:
2228                         result = 0;
2229                         break;
2230         }
2231 //printf("BC_WindowBase::accel_available %d %d\n", color_model, result);
2232         return result;
2236 int BC_WindowBase::grab_port_id(BC_WindowBase *window, int color_model)
2238         int numFormats, i, j, k;
2239         unsigned int ver, rev, numAdapt, reqBase, eventBase, errorBase;
2240         int port_id = -1;
2241     XvAdaptorInfo *info;
2242     XvImageFormatValues *formats;
2243         int x_color_model;
2245         if(!get_resources()->use_xvideo) return -1;
2247 // Translate from color_model to X color model
2248         x_color_model = cmodel_bc_to_x(color_model);
2250 // Only local server is fast enough.
2251         if(!resources.use_shm) return -1;
2253 // XV extension is available
2254     if(Success != XvQueryExtension(window->display, 
2255                                   &ver, 
2256                                   &rev, 
2257                                   &reqBase, 
2258                                   &eventBase, 
2259                                   &errorBase))
2260     {
2261                 return -1;
2262     }
2264 // XV adaptors are available
2265         XvQueryAdaptors(window->display, 
2266                 DefaultRootWindow(window->display), 
2267                 &numAdapt, 
2268                 &info);
2270         if(!numAdapt)
2271         {
2272                 return -1;
2273         }
2275 // Get adaptor with desired color model
2276     for(i = 0; i < numAdapt && xvideo_port_id == -1; i++)
2277     {
2278 /* adaptor supports XvImages */
2279                 if(info[i].type & XvImageMask) 
2280                 {  
2281                 formats = XvListImageFormats(window->display, 
2282                                                         info[i].base_id, 
2283                                                         &numFormats);
2284 // for(j = 0; j < numFormats; j++)
2285 //      printf("%08x\n", formats[j].id);
2287                 for(j = 0; j < numFormats && xvideo_port_id < 0; j++) 
2288                 {
2289 /* this adaptor supports the desired format */
2290                                 if(formats[j].id == x_color_model)
2291                                 {
2292 /* Try to grab a port */
2293                                         for(k = 0; k < info[i].num_ports; k++)
2294                                         {
2295 /* Got a port */
2296                                                 if(Success == XvGrabPort(top_level->display, 
2297                                                         info[i].base_id + k, 
2298                                                         CurrentTime))
2299                                                 {
2300 //printf("BC_WindowBase::grab_port_id %llx\n", info[i].base_id);
2301                                                         xvideo_port_id = info[i].base_id + k;
2302                                                         break;
2303                                                 }
2304                                         }
2305                                 }
2306                         }
2307                 if(formats) XFree(formats);
2308                 }
2309         }
2311     XvFreeAdaptorInfo(info);
2313         return xvideo_port_id;
2317 int BC_WindowBase::show_window(int flush) 
2319         XMapWindow(top_level->display, win); 
2320         if(flush) XFlush(top_level->display);
2321 //      XSync(top_level->display, 0);
2322         hidden = 0; 
2323         return 0;
2326 int BC_WindowBase::hide_window(int flush) 
2328         XUnmapWindow(top_level->display, win); 
2329         if(flush) XFlush(top_level->display);
2330         hidden = 1; 
2331         return 0;
2334 BC_MenuBar* BC_WindowBase::add_menubar(BC_MenuBar *menu_bar)
2336         subwindows->append((BC_SubWindow*)menu_bar);
2338         menu_bar->parent_window = this;
2339         menu_bar->top_level = this->top_level;
2340         menu_bar->initialize();
2341         return menu_bar;
2344 BC_WindowBase* BC_WindowBase::add_subwindow(BC_WindowBase *subwindow)
2346         subwindows->append(subwindow);
2348         if(subwindow->bg_color == -1) subwindow->bg_color = this->bg_color;
2350 // parent window must be set before the subwindow initialization
2351         subwindow->parent_window = this;
2352         subwindow->top_level = this->top_level;
2354 // Execute derived initialization
2355         subwindow->initialize();
2356         return subwindow;
2360 BC_WindowBase* BC_WindowBase::add_tool(BC_WindowBase *subwindow)
2362         return add_subwindow(subwindow);
2365 int BC_WindowBase::flash(int x, int y, int w, int h, int flush)
2367         set_opaque();
2368         XSetWindowBackgroundPixmap(top_level->display, win, pixmap);
2369         if(x >= 0)
2370         {
2371                 XClearArea(top_level->display, win, x, y, w, h, 0);
2372         }
2373         else
2374         {
2375                 XClearWindow(top_level->display, win);
2376         }
2378         if(flush)
2379                 this->flush();
2380         return 0;
2383 int BC_WindowBase::flash(int flush)
2385         flash(-1, -1, -1, -1, flush);
2388 void BC_WindowBase::flush()
2390         XFlush(top_level->display);
2393 void BC_WindowBase::sync_display()
2395         XSync(top_level->display, False);
2398 int BC_WindowBase::get_window_lock()
2400         return top_level->window_lock;
2403 int BC_WindowBase::lock_window(char *location) 
2405         if(top_level && top_level != this)
2406         {
2407                 top_level->lock_window(location);
2408         }
2409         else
2410         if(top_level)
2411         {
2412                 SET_LOCK(this, title, location);
2413                 XLockDisplay(top_level->display);
2414                 SET_LOCK2
2415                 top_level->window_lock = 1;
2416         }
2417         else
2418         {
2419                 printf("BC_WindowBase::lock_window top_level NULL\n");
2420         }
2421         return 0;
2424 int BC_WindowBase::unlock_window() 
2426         if(top_level && top_level != this)
2427         {
2428                 top_level->unlock_window();
2429         }
2430         else
2431         if(top_level)
2432         {
2433                 UNSET_LOCK(this);
2434                 top_level->window_lock = 0;
2435                 XUnlockDisplay(top_level->display);
2436         }
2437         else
2438         {
2439                 printf("BC_WindowBase::unlock_window top_level NULL\n");
2440         }
2441         return 0;
2444 void BC_WindowBase::set_done(int return_value)
2446         if(window_type != MAIN_WINDOW)
2447                 top_level->set_done(return_value);
2448         else
2449         if(event_thread)
2450         {
2451                 XEvent *event = new XEvent;
2452                 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
2454                 event->type = ClientMessage;
2455                 ptr->message_type = SetDoneXAtom;
2456                 ptr->format = 32;
2457                 this->return_value = return_value;
2459 // May lock up here because XSendEvent doesn't work too well 
2460 // asynchronous with XNextEvent.
2461 // This causes BC_WindowEvents to forward a copy of the event to run_window where 
2462 // it is deleted.
2463                 event_thread->done = 1;
2464                 XSendEvent(display, 
2465                         win, 
2466                         0, 
2467                         0, 
2468                         event);
2469                 flush();
2470                 put_event(event);
2471         }
2474 int BC_WindowBase::get_w()
2476         return w;
2479 int BC_WindowBase::get_h()
2481         return h;
2484 int BC_WindowBase::get_x()
2486         return x;
2489 int BC_WindowBase::get_y()
2491         return y;
2494 int BC_WindowBase::get_root_w(int ignore_dualhead, int lock_display)
2496         if(lock_display) lock_window("BC_WindowBase::get_root_w");
2497         Screen *screen_ptr = XDefaultScreenOfDisplay(display);
2498         int result = WidthOfScreen(screen_ptr);
2499 // Wider than 16:9, narrower than dual head
2500         if(!ignore_dualhead) if((float)result / HeightOfScreen(screen_ptr) > 1.8) result /= 2;
2502         if(lock_display) unlock_window();
2503         return result;
2506 int BC_WindowBase::get_root_h(int lock_display)
2508         if(lock_display) lock_window("BC_WindowBase::get_root_h");
2509         Screen *screen_ptr = XDefaultScreenOfDisplay(display);
2510         int result = HeightOfScreen(screen_ptr);
2511         if(lock_display) unlock_window();
2512         return result;
2515 // Bottom right corner
2516 int BC_WindowBase::get_x2()
2518         return w + x;
2521 int BC_WindowBase::get_y2()
2523         return y + h;
2526 int BC_WindowBase::get_hidden()
2528         return top_level->hidden;
2531 int BC_WindowBase::cursor_inside()
2533         return (top_level->cursor_x >= 0 && 
2534                         top_level->cursor_y >= 0 && 
2535                         top_level->cursor_x < w && 
2536                         top_level->cursor_y < h);
2539 BC_WindowBase* BC_WindowBase::get_top_level()
2541         return top_level;
2544 BC_WindowBase* BC_WindowBase::get_parent()
2546         return parent_window;
2549 int BC_WindowBase::get_color_model()
2551         return top_level->color_model;
2554 BC_Resources* BC_WindowBase::get_resources()
2556         return &BC_WindowBase::resources;
2559 int BC_WindowBase::get_bg_color()
2561         return bg_color;
2564 BC_Pixmap* BC_WindowBase::get_bg_pixmap()
2566         return bg_pixmap;
2569 void BC_WindowBase::set_active_subwindow(BC_WindowBase *subwindow)
2571         top_level->active_subwindow = subwindow;
2574 int BC_WindowBase::activate()
2576         return 0;
2579 int BC_WindowBase::deactivate()
2581         if(window_type == MAIN_WINDOW)
2582         {
2583                 if(top_level->active_menubar) top_level->active_menubar->deactivate();
2584                 if(top_level->active_popup_menu) top_level->active_popup_menu->deactivate();
2585                 if(top_level->active_subwindow) top_level->active_subwindow->deactivate();
2587                 top_level->active_menubar = 0;
2588                 top_level->active_popup_menu = 0;
2589                 top_level->active_subwindow = 0;
2590         }
2591         return 0;
2594 int BC_WindowBase::cycle_textboxes(int amount)
2596         int result = 0;
2597         BC_WindowBase *new_textbox = 0;
2599         if(amount > 0)
2600         {
2601                 BC_WindowBase *first_textbox = 0;
2602                 find_next_textbox(&first_textbox, &new_textbox, result);
2603                 if(!new_textbox) new_textbox = first_textbox;
2604                 
2605         }
2606         else
2607         if(amount < 0)
2608         {
2609                 BC_WindowBase *last_textbox = 0;
2610                 find_prev_textbox(&last_textbox, &new_textbox, result);
2611                 if(!new_textbox) new_textbox = last_textbox;
2612                 
2613         }
2615         if(new_textbox != active_subwindow)
2616         {
2617                 deactivate();
2618                 new_textbox->activate();
2619         }
2620         
2621         return 0;
2624 int BC_WindowBase::find_next_textbox(BC_WindowBase **first_textbox, BC_WindowBase **next_textbox, int &result)
2626 // Search subwindows for textbox
2627         for(int i = 0; i < subwindows->total && result < 2; i++)
2628         {
2629                 BC_WindowBase *test_subwindow = subwindows->values[i];
2630                 test_subwindow->find_next_textbox(first_textbox, next_textbox, result);
2631         }
2633         if(result < 2)
2634         {
2635                 if(uses_text())
2636                 {
2637                         if(!*first_textbox) *first_textbox = this;
2639                         if(result < 1)
2640                         {
2641                                 if(top_level->active_subwindow == this)
2642                                         result++;
2643                         }
2644                         else
2645                         {
2646                                 result++;
2647                                 *next_textbox = this;
2648                         }
2649                 }
2650         }
2651         return 0;
2654 int BC_WindowBase::find_prev_textbox(BC_WindowBase **last_textbox, BC_WindowBase **prev_textbox, int &result)
2656         if(result < 2)
2657         {
2658                 if(uses_text())
2659                 {
2660                         if(!*last_textbox) *last_textbox = this;
2662                         if(result < 1)
2663                         {
2664                                 if(top_level->active_subwindow == this)
2665                                         result++;
2666                         }
2667                         else
2668                         {
2669                                 result++;
2670                                 *prev_textbox = this;
2671                         }
2672                 }
2673         }
2675 // Search subwindows for textbox
2676         for(int i = subwindows->total - 1; i >= 0 && result < 2; i--)
2677         {
2678                 BC_WindowBase *test_subwindow = subwindows->values[i];
2679                 test_subwindow->find_prev_textbox(last_textbox, prev_textbox, result);
2680         }
2681         return 0;
2684 BC_Clipboard* BC_WindowBase::get_clipboard()
2686         return top_level->clipboard;
2689 int BC_WindowBase::get_relative_cursor_x()
2691         int abs_x, abs_y, x, y, win_x, win_y;
2692         unsigned int temp_mask;
2693         Window temp_win;
2695         XQueryPointer(top_level->display, 
2696            top_level->win, 
2697            &temp_win, 
2698            &temp_win,
2699        &abs_x, 
2700            &abs_y, 
2701            &win_x, 
2702            &win_y, 
2703            &temp_mask);
2705         XTranslateCoordinates(top_level->display, 
2706                         top_level->rootwin, 
2707                         win, 
2708                         abs_x, 
2709                         abs_y, 
2710                         &x, 
2711                         &y, 
2712                         &temp_win);
2714         return x;
2717 int BC_WindowBase::get_relative_cursor_y()
2719         int abs_x, abs_y, x, y, win_x, win_y;
2720         unsigned int temp_mask;
2721         Window temp_win;
2723         XQueryPointer(top_level->display, 
2724            top_level->win, 
2725            &temp_win, 
2726            &temp_win,
2727        &abs_x, 
2728            &abs_y, 
2729            &win_x, 
2730            &win_y, 
2731            &temp_mask);
2733         XTranslateCoordinates(top_level->display, 
2734                         top_level->rootwin, 
2735                         win, 
2736                         abs_x, 
2737                         abs_y, 
2738                         &x, 
2739                         &y, 
2740                         &temp_win);
2742         return y;
2745 int BC_WindowBase::get_abs_cursor_x(int lock_window)
2747         int abs_x, abs_y, win_x, win_y;
2748         unsigned int temp_mask;
2749         Window temp_win;
2751         if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor_x");
2752         XQueryPointer(top_level->display, 
2753                 top_level->win, 
2754                 &temp_win, 
2755                 &temp_win,
2756                 &abs_x, 
2757                 &abs_y, 
2758                 &win_x, 
2759                 &win_y, 
2760                 &temp_mask);
2761         if(lock_window) this->unlock_window();
2762         return abs_x;
2765 int BC_WindowBase::get_abs_cursor_y(int lock_window)
2767         int abs_x, abs_y, win_x, win_y;
2768         unsigned int temp_mask;
2769         Window temp_win;
2771         if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor_y");
2772         XQueryPointer(top_level->display, 
2773                 top_level->win, 
2774                 &temp_win, 
2775                 &temp_win,
2776         &abs_x, 
2777                 &abs_y, 
2778                 &win_x, 
2779                 &win_y, 
2780                 &temp_mask);
2781         if(lock_window) this->unlock_window();
2782         return abs_y;
2785 int BC_WindowBase::match_window(Window win) 
2787         if (this->win == win) return 1;
2788         int result = 0;
2789         for(int i = 0; i < subwindows->total; i++)
2790         {
2791                 result = subwindows->values[i]->match_window(win);
2792                 if (result) return result;
2793         }
2794         return 0;
2798 int BC_WindowBase::get_cursor_over_window()
2800         if(top_level != this) return top_level->get_cursor_over_window();
2802         int abs_x, abs_y, win_x, win_y;
2803         unsigned int temp_mask;
2804         Window temp_win1, temp_win2;
2806         if (!XQueryPointer(display, 
2807                 win, 
2808                 &temp_win1, 
2809                 &temp_win2,
2810                 &abs_x, 
2811                 &abs_y, 
2812                 &win_x, 
2813                 &win_y, 
2814                 &temp_mask))
2815                 return 0;
2817         int result = match_window(temp_win2)    ;
2818         return result;
2821 int BC_WindowBase::relative_cursor_x(BC_WindowBase *pov)
2823         int x, y;
2824         Window tempwin;
2826         translate_coordinates(top_level->event_win, 
2827                 pov->win,
2828                 top_level->cursor_x,
2829                 top_level->cursor_y,
2830                 &x,
2831                 &y);
2832         return x;
2835 int BC_WindowBase::relative_cursor_y(BC_WindowBase *pov)
2837         int x, y;
2838         Window tempwin;
2840         translate_coordinates(top_level->event_win, 
2841                 pov->win,
2842                 top_level->cursor_x,
2843                 top_level->cursor_y,
2844                 &x,
2845                 &y);
2846         return y;
2849 int BC_WindowBase::get_drag_x()
2851         return top_level->drag_x;
2854 int BC_WindowBase::get_drag_y()
2856         return top_level->drag_y;
2859 int BC_WindowBase::get_cursor_x()
2861         return top_level->cursor_x;
2864 int BC_WindowBase::get_cursor_y()
2866         return top_level->cursor_y;
2869 int BC_WindowBase::is_event_win()
2871         return this->win == top_level->event_win;
2874 void BC_WindowBase::set_dragging(int value)
2876         is_dragging = value;
2879 int BC_WindowBase::get_dragging()
2881         return is_dragging;
2884 int BC_WindowBase::get_buttonpress()
2886         return top_level->button_number;
2889 int BC_WindowBase::get_button_down()
2891         return top_level->button_down;
2894 int BC_WindowBase::alt_down()
2896         return top_level->alt_mask;
2899 int BC_WindowBase::shift_down()
2901         return top_level->shift_mask;
2904 int BC_WindowBase::ctrl_down()
2906         return top_level->ctrl_mask;
2910 int BC_WindowBase::get_keypress()
2912         return top_level->key_pressed;
2915 int BC_WindowBase::get_double_click()
2917         return top_level->double_click;
2920 int BC_WindowBase::get_bgcolor()
2922         return bg_color;
2925 int BC_WindowBase::resize_window(int w, int h)
2927         if(window_type == MAIN_WINDOW && !allow_resize)
2928         {
2929                 XSizeHints size_hints;
2930                 size_hints.flags = PSize | PMinSize | PMaxSize;
2931                 size_hints.width = w;
2932                 size_hints.height = h;
2933                 size_hints.min_width = w;
2934                 size_hints.max_width = w; 
2935                 size_hints.min_height = h;
2936                 size_hints.max_height = h; 
2937                 XSetNormalHints(top_level->display, win, &size_hints);
2938         }
2939         XResizeWindow(top_level->display, win, w, h);
2941         this->w = w;
2942         this->h = h;
2943         XFreePixmap(top_level->display, pixmap);
2944         pixmap = XCreatePixmap(top_level->display, win, w, h, top_level->default_depth);
2946 // Propagate to menubar
2947         for(int i = 0; i < subwindows->total; i++)
2948         {
2949                 subwindows->values[i]->dispatch_resize_event(w, h);
2950         }
2952         draw_background(0, 0, w, h);
2953         if(top_level == this && get_resources()->recursive_resizing)
2954                 resize_history.append(new BC_ResizeCall(w, h));
2955         return 0;
2958 // The only way for resize events to be propagated is by updating the internal w and h
2959 int BC_WindowBase::resize_event(int w, int h)
2961         if(window_type == MAIN_WINDOW)
2962         {
2963                 this->w = w;
2964                 this->h = h;
2965         }
2966         return 0;
2969 int BC_WindowBase::reposition_window(int x, int y, int w, int h)
2971         int resize = 0;
2973 // Some tools set their own dimensions before calling this, causing the 
2974 // resize check to skip.
2975         this->x = x;
2976         this->y = y;
2978         if(w > 0 && w != this->w)
2979         {
2980                 resize = 1;
2981                 this->w = w;
2982         }
2984         if(h > 0 && h != this->h)
2985         {
2986                 resize = 1;
2987                 this->h = h;
2988         }
2990 //printf("BC_WindowBase::reposition_window %d %d %d\n", translation_count, x_correction, y_correction);
2992         if(this->w <= 0)
2993                 printf("BC_WindowBase::reposition_window this->w == %d\n", this->w);
2994         if(this->h <= 0)
2995                 printf("BC_WindowBase::reposition_window this->h == %d\n", this->h);
2997         if(translation_count && window_type == MAIN_WINDOW)
2998         {
2999 // KDE shifts window right and down.
3000 // FVWM leaves window alone and adds border around it.
3001                 XMoveResizeWindow(top_level->display, 
3002                         win, 
3003                         x + BC_DisplayInfo::left_border - BC_DisplayInfo::auto_reposition_x, 
3004                         y + BC_DisplayInfo::top_border - BC_DisplayInfo::auto_reposition_y, 
3005                         this->w,
3006                         this->h);
3007         }
3008         else
3009         {
3010                 XMoveResizeWindow(top_level->display, 
3011                         win, 
3012                         x, 
3013                         y, 
3014                         this->w, 
3015                         this->h);
3016         }
3018         if(resize)
3019         {
3020                 XFreePixmap(top_level->display, pixmap);
3021                 pixmap = XCreatePixmap(top_level->display, 
3022                         win, 
3023                         this->w, 
3024                         this->h, 
3025                         top_level->default_depth);
3027 // Propagate to menubar
3028                 for(int i = 0; i < subwindows->total; i++)
3029                 {
3030                         subwindows->values[i]->dispatch_resize_event(this->w, this->h);
3031                 }
3033 //              draw_background(0, 0, w, h);
3034         }
3036         return 0;
3039 int BC_WindowBase::set_tooltips(int tooltips_enabled)
3041         get_resources()->tooltips_enabled = tooltips_enabled;
3042         return 0;
3045 int BC_WindowBase::raise_window(int do_flush)
3047         XRaiseWindow(top_level->display, win);
3048         if(do_flush) XFlush(top_level->display);
3049         return 0;
3052 void BC_WindowBase::set_background(VFrame *bitmap)
3054         if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
3056         bg_pixmap = new BC_Pixmap(this, 
3057                         bitmap, 
3058                         PIXMAP_OPAQUE);
3059         shared_bg_pixmap = 0;
3060         draw_background(0, 0, w, h);
3063 void BC_WindowBase::set_title(char *text)
3065         XSetStandardProperties(top_level->display, top_level->win, text, text, None, 0, 0, 0); 
3066         strcpy(this->title, _(text));
3067         flush();
3070 char* BC_WindowBase::get_title()
3072         return title;
3075 int BC_WindowBase::get_toggle_value()
3077         return toggle_value;
3080 int BC_WindowBase::get_toggle_drag()
3082         return toggle_drag;
3085 int BC_WindowBase::set_icon(VFrame *data)
3087         if(icon_pixmap) delete icon_pixmap;
3088         icon_pixmap = new BC_Pixmap(top_level, 
3089                 data, 
3090                 PIXMAP_ALPHA,
3091                 1);
3093         icon_window = new BC_Popup(this, 
3094                 (int)BC_INFINITY, 
3095                 (int)BC_INFINITY, 
3096                 icon_pixmap->get_w(), 
3097                 icon_pixmap->get_h(), 
3098                 -1, 
3099                 1, // All windows are hidden initially
3100                 icon_pixmap);
3102         XWMHints wm_hints;
3103         wm_hints.flags = IconPixmapHint | IconMaskHint | IconWindowHint;
3104         wm_hints.icon_pixmap = icon_pixmap->get_pixmap();
3105         wm_hints.icon_mask = icon_pixmap->get_alpha();
3106         wm_hints.icon_window = icon_window->win;
3107 // for(int i = 0; i < 1000; i++)
3108 // printf("02x ", icon_pixmap->get_alpha()->get_row_pointers()[0][i]);
3109 // printf("\n");
3111         XSetWMHints(top_level->display, top_level->win, &wm_hints);
3112         XSync(top_level->display, 0);
3113         return 0;
3116 int BC_WindowBase::set_w(int w)
3118         this->w = w;
3119         return 0;
3122 int BC_WindowBase::set_h(int h)
3124         this->h = h;
3125         return 0;
3128 int BC_WindowBase::load_defaults(Defaults *defaults)
3130         get_resources()->filebox_mode = defaults->get("FILEBOX_MODE", get_resources()->filebox_mode);
3131         get_resources()->filebox_w = defaults->get("FILEBOX_W", get_resources()->filebox_w);
3132         get_resources()->filebox_h = defaults->get("FILEBOX_H", get_resources()->filebox_h);
3133         defaults->get("FILEBOX_FILTER", get_resources()->filebox_filter);
3134         return 0;
3137 int BC_WindowBase::save_defaults(Defaults *defaults)
3139         defaults->update("FILEBOX_MODE", get_resources()->filebox_mode);
3140         defaults->update("FILEBOX_W", get_resources()->filebox_w);
3141 //printf("BC_ListBox::cursor_motion_event 1 %lld\n", timer.get_difference());
3142         defaults->update("FILEBOX_H", get_resources()->filebox_h);
3143         defaults->update("FILEBOX_FILTER", get_resources()->filebox_filter);
3144         return 0;
3149 // For some reason XTranslateCoordinates can take a long time to return.
3150 // We work around this by only calling it when the event windows are different.
3151 void BC_WindowBase::translate_coordinates(Window src_w, 
3152                 Window dest_w,
3153                 int src_x,
3154                 int src_y,
3155                 int *dest_x_return,
3156                 int *dest_y_return)
3158         Window tempwin = 0;
3159 //Timer timer;
3160 //timer.update();
3161         if(src_w == dest_w)
3162         {
3163                 *dest_x_return = src_x;
3164                 *dest_y_return = src_y;
3165         }
3166         else
3167         {
3168                 XTranslateCoordinates(top_level->display, 
3169                         src_w, 
3170                         dest_w, 
3171                         src_x, 
3172                         src_y, 
3173                         dest_x_return, 
3174                         dest_y_return,
3175                         &tempwin);
3176 //printf("BC_WindowBase::translate_coordinates 1 %lld\n", timer.get_difference());
3177         }
3186 #ifdef HAVE_LIBXXF86VM
3187 void BC_WindowBase::closest_vm(int *vm, int *width, int *height)
3189    int foo,bar;
3190    *vm = 0;
3191    if(XF86VidModeQueryExtension(top_level->display,&foo,&bar)) {
3192            int vm_count,i;
3193            XF86VidModeModeInfo **vm_modelines;
3194            XF86VidModeGetAllModeLines(top_level->display,XDefaultScreen(top_level->display),&vm_count,&vm_modelines);
3195            for (i = 0; i < vm_count; i++) {
3196                    if (vm_modelines[i]->hdisplay < vm_modelines[*vm]->hdisplay && vm_modelines[i]->hdisplay >= *width)
3197                            *vm = i;
3198            }
3199            display = top_level->display;
3200            if (vm_modelines[*vm]->hdisplay == *width)
3201                    *vm = -1;
3202            else
3203            {
3204                    *width = vm_modelines[*vm]->hdisplay;
3205                    *height = vm_modelines[*vm]->vdisplay;
3206            }
3207    }
3210 void BC_WindowBase::scale_vm(int vm)
3212    int foo,bar,dotclock;
3213    if(XF86VidModeQueryExtension(top_level->display,&foo,&bar))
3214    {
3215            int vm_count;
3216            XF86VidModeModeInfo **vm_modelines;
3217            XF86VidModeModeLine vml;
3218            XF86VidModeGetAllModeLines(top_level->display,XDefaultScreen(top_level->display),&vm_count,&vm_modelines);
3219            XF86VidModeGetModeLine(top_level->display,XDefaultScreen(top_level->display),&dotclock,&vml);
3220            orig_modeline.dotclock = dotclock;
3221            orig_modeline.hdisplay = vml.hdisplay;
3222            orig_modeline.hsyncstart = vml.hsyncstart;
3223            orig_modeline.hsyncend = vml.hsyncend;
3224            orig_modeline.htotal = vml.htotal;
3225            orig_modeline.vdisplay = vml.vdisplay;
3226            orig_modeline.vsyncstart = vml.vsyncstart;
3227            orig_modeline.vsyncend = vml.vsyncend;
3228            orig_modeline.vtotal = vml.vtotal;
3229            orig_modeline.flags = vml.flags;
3230            orig_modeline.privsize = vml.privsize;
3231            // orig_modeline.private = vml.private;
3232            XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),vm_modelines[vm]);
3233            XF86VidModeSetViewPort(top_level->display,XDefaultScreen(top_level->display),0,0);
3234            XFlush(top_level->display);
3235    }
3238 void BC_WindowBase::restore_vm()
3240    XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),&orig_modeline);
3241    XFlush(top_level->display);
3245 #endif
3248 #ifdef HAVE_GL
3250 extern "C"
3252         GLXContext glXCreateContext(Display *dpy,
3253                                XVisualInfo *vis,
3254                                GLXContext shareList,
3255                                int direct);
3256         
3257         int glXMakeCurrent(Display *dpy,
3258                        Drawable drawable,
3259                        GLXContext ctx);
3261         void glXSwapBuffers(Display *dpy,
3262                        Drawable drawable);
3267 void BC_WindowBase::enable_opengl()
3269         lock_window("BC_WindowBase::enable_opengl");
3270         opengl_lock.lock();
3272         XVisualInfo viproto;
3273         XVisualInfo *visinfo;
3274         int nvi;
3276 //printf("BC_WindowBase::enable_opengl 1\n");
3277         viproto.screen = top_level->screen;
3278         visinfo = XGetVisualInfo(top_level->display,
3279         VisualScreenMask,
3280         &viproto,
3281         &nvi);
3282 //printf("BC_WindowBase::enable_opengl 1 %p\n", visinfo);
3284         gl_context = glXCreateContext(top_level->display,
3285                 visinfo,
3286                 0,
3287                 1);
3288 //printf("BC_WindowBase::enable_opengl 1\n");
3290         glXMakeCurrent(top_level->display,
3291                 win,
3292                 gl_context);
3294         unsigned long valuemask = CWEventMask;
3295         XSetWindowAttributes attributes;
3296         attributes.event_mask = DEFAULT_EVENT_MASKS |
3297                         ExposureMask;
3298         XChangeWindowAttributes(top_level->display, win, valuemask, &attributes);
3300         opengl_lock.unlock();
3301         unlock_window();
3302 //printf("BC_WindowBase::enable_opengl 2\n");
3305 void BC_WindowBase::disable_opengl()
3307         unsigned long valuemask = CWEventMask;
3308         XSetWindowAttributes attributes;
3309         attributes.event_mask = DEFAULT_EVENT_MASKS;
3310         XChangeWindowAttributes(top_level->display, win, valuemask, &attributes);
3313 void BC_WindowBase::lock_opengl()
3315         lock_window("BC_WindowBase::lock_opengl");
3316         opengl_lock.lock();
3317         glXMakeCurrent(top_level->display,
3318                 win,
3319                 gl_context);
3322 void BC_WindowBase::unlock_opengl()
3324         opengl_lock.unlock();
3325         unlock_window();
3328 void BC_WindowBase::flip_opengl()
3330         glXSwapBuffers(top_level->display, win);
3332 #endif
3334 int BC_WindowBase::get_event_count()
3336         event_lock->lock("BC_WindowBase::get_event_count");
3337         int result = common_events.total;
3338         event_lock->unlock();
3339         return result;
3342 XEvent* BC_WindowBase::get_event()
3344         XEvent *result = 0;
3345         while(!done && !result)
3346         {
3347                 event_condition->lock("BC_WindowBase::get_event");
3348                 event_lock->lock("BC_WindowBase::get_event");
3349                 if(common_events.total && !done)
3350                 {
3351                         result = common_events.values[0];
3352                         common_events.remove_number(0);
3353                 }
3354                 event_lock->unlock();
3355         }
3356         return result;
3359 void BC_WindowBase::put_event(XEvent *event)
3361         event_lock->lock("BC_WindowBase::put_event");
3362         common_events.append(event);
3363         event_lock->unlock();
3364         event_condition->unlock();