r373: Merged the official release 1.2.1.
[cinelerra_cv.git] / guicast / bcwindowbase.C
blob6e9ac1b3e194a45e1b5f50ccc3684434711c123b
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); 
1540         create_color(FGGREY); 
1541         create_color(MNBLUE);
1542         create_color(ORANGE);
1543         create_color(FTGREY);
1545         return 0;
1548 int BC_WindowBase::allocate_color_table()
1550         int red, green, blue, color;
1551         int result;
1552         XColor col;
1554         for(int i = 0; i < total_colors; i++)
1555         {
1556                 color = color_table[i][0];
1557                 red = (color & 0xFF0000) >> 16;
1558                 green = (color & 0x00FF00) >> 8;
1559                 blue = color & 0xFF;
1561                 col.flags = DoRed | DoGreen | DoBlue;
1562                 col.red   = red<<8   | red;
1563                 col.green = green<<8 | green;
1564                 col.blue  = blue<<8  | blue;
1566                 XAllocColor(display, cmap, &col);
1567                 color_table[i][1] = col.pixel;
1568         }
1570         XInstallColormap(display, cmap);
1571         return 0;
1574 int BC_WindowBase::init_window_shape()
1576         if(bg_pixmap && bg_pixmap->use_alpha()) 
1577         {
1578                 XShapeCombineMask(top_level->display,
1579                 this->win,
1580                 ShapeBounding,
1581                 0,
1582                 0,
1583                 bg_pixmap->get_alpha(),
1584                 ShapeSet);
1585         }
1586         return 0;
1590 int BC_WindowBase::init_gc()
1592         unsigned long gcmask;
1593         gcmask = GCFont | GCGraphicsExposures;
1595         XGCValues gcvalues;
1596         gcvalues.font = mediumfont->fid;        // set the font
1597         gcvalues.graphics_exposures = 0;        // prevent expose events for every redraw
1598         gc = XCreateGC(display, rootwin, gcmask, &gcvalues);
1599         return 0;
1602 int BC_WindowBase::init_fonts()
1604         if((largefont = XLoadQueryFont(display, _(resources.large_font))) == NULL &&
1605                 (largefont = XLoadQueryFont(display, _(resources.large_font2))) == NULL) 
1606                 largefont = XLoadQueryFont(display, "fixed"); 
1608         if((mediumfont = XLoadQueryFont(display, _(resources.medium_font))) == NULL &&
1609                 (mediumfont = XLoadQueryFont(display, _(resources.medium_font2))) == NULL)
1610                 mediumfont = XLoadQueryFont(display, "fixed"); 
1612         if((smallfont = XLoadQueryFont(display, _(resources.small_font))) == NULL &&
1613                 (smallfont = XLoadQueryFont(display, _(resources.small_font2))) == NULL)
1614                 smallfont = XLoadQueryFont(display, "fixed");
1616 #ifdef HAVE_XFT
1617         if(get_resources()->use_xft)
1618         {
1621 //printf("BC_WindowBase::init_fonts 1 %p %p %s\n", display, screen, resources.large_font_xft);
1623                 if(!(largefont_xft = XftFontOpenXlfd(display,
1624                     screen,
1625                     resources.large_font_xft)))
1626                 {
1627                         largefont_xft = XftFontOpenXlfd(display,
1628                         screen,
1629                         "fixed");
1630                 }
1631 //printf("BC_WindowBase::init_fonts 1 %p\n", largefont_xft);
1632                 if(!(largefont_xft = XftFontOpenXlfd(display,
1633                     screen,
1634                     resources.large_font_xft)))
1635                 {
1636                         largefont_xft = XftFontOpenXlfd(display,
1637                         screen,
1638                         "fixed");
1639                 }
1640 //printf("BC_WindowBase::init_fonts 2 %p\n", largefont_xft);
1643                 if(!(mediumfont_xft = XftFontOpenXlfd(display,
1644                       screen,
1645                       resources.medium_font_xft)))
1646                 {
1647                         mediumfont_xft = XftFontOpenXlfd(display,
1648                         screen,
1649                         "fixed");
1650                 }
1653                 if(!(smallfont_xft = XftFontOpenXlfd(display,
1654                       screen,
1655                       resources.small_font_xft)))
1656                 {
1657                           smallfont_xft = XftFontOpenXlfd(display,
1658                           screen,
1659                           "fixed");
1660                 }
1662 //printf("BC_WindowBase::init_fonts 100 %s %p\n", 
1663 //resources.medium_font, 
1664 //mediumfont_xft);
1666 printf("BC_WindowBase::init_fonts: %s=%p %s=%p %s=%p\n",
1667         resources.large_font_xft,
1668         largefontset,
1669         resources.medium_font_xft,
1670         mediumfontset,
1671         resources.small_font_xft,
1672         smallfontset);
1674 // Extension failed to locate fonts
1675                 if(!largefontset || !mediumfontset || !smallfontset)
1676                 {
1677                         printf("BC_WindowBase::init_fonts: no xft fonts found %s=%p %s=%p %s=%p\n",
1678                                 resources.large_font_xft,
1679                                 largefontset,
1680                                 resources.medium_font_xft,
1681                                 mediumfontset,
1682                                 resources.small_font_xft,
1683                                 smallfontset);
1684                         get_resources()->use_xft = 0;
1685                 }
1686         }
1687         else
1688 #endif
1689         if(get_resources()->use_fontset)
1690         {
1691                 char **m, *d;
1692                 int n;
1694 // FIXME: should check the m,d,n values
1695                 if((largefontset = XCreateFontSet(display, 
1696                         resources.large_fontset,
1697             &m, 
1698                         &n, 
1699                         &d)) == 0)
1700             largefontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
1701                 if((mediumfontset = XCreateFontSet(display, 
1702                         resources.medium_fontset,
1703             &m, 
1704                         &n, 
1705                         &d)) == 0)
1706             mediumfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
1707                 if((smallfontset = XCreateFontSet(display, 
1708                         resources.small_fontset,
1709             &m, 
1710                         &n, 
1711                         &d)) == 0)
1712             smallfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
1714                 if(largefontset && mediumfontset && smallfontset)
1715                 {
1716                         curr_fontset = mediumfontset;
1717                         get_resources()->use_fontset = 1;
1718                 }
1719                 else
1720                 {
1721                         curr_fontset = 0;
1722                         get_resources()->use_fontset = 0;
1723                 }
1724         }
1726         return 0;
1729 int BC_WindowBase::get_color(int64_t color) 
1731 // return pixel of color
1732 // use this only for drawing subwindows not for bitmaps
1733          int i, test, difference, result;
1735         switch(color_model)
1736         {
1737                 case BC_RGB8:
1738                         if(private_color)
1739                         {
1740                                 return get_color_rgb8(color);
1741                         }
1742                         else
1743                         {
1744 // test last color looked up
1745                                 if(current_color_value == color) return current_color_pixel;
1747 // look up in table
1748                                 current_color_value = color;
1749                                 for(i = 0; i < total_colors; i++)
1750                                 {
1751                                         if(color_table[i][0] == color)
1752                                         {
1753                                                 current_color_pixel = color_table[i][1];
1754                                                 return current_color_pixel;
1755                                         }
1756                                 }
1758 // find nearest match
1759                                 difference = 0xFFFFFF;
1761                                 for(i = 0, result = 0; i < total_colors; i++)
1762                                 {
1763                                         test = abs((int)(color_table[i][0] - color));
1765                                         if(test < difference) 
1766                                         {
1767                                                 current_color_pixel = color_table[i][1]; 
1768                                                 difference = test;
1769                                         }
1770                                 }
1772                                 return current_color_pixel;
1773                         }
1774                         break;  
1776                 case BC_RGB565:
1777                         return get_color_rgb16(color);
1778                         break;
1780                 case BC_BGR565:
1781                         return get_color_bgr16(color);
1782                         break;
1784                 case BC_RGB888:
1785                 case BC_BGR888:
1786                         if(client_byte_order == server_byte_order)
1787                                 return color;
1788                         else
1789                                 get_color_bgr24(color);
1790                         break;
1792                 default:
1793                         return color;
1794                         break;  
1795         }
1796         return 0;
1799 int BC_WindowBase::get_color_rgb8(int color)
1801         int pixel;
1803         pixel = (color & 0xc00000) >> 16;
1804         pixel += (color & 0xe000) >> 10;
1805         pixel += (color & 0xe0) >> 5;
1806         return pixel;
1809 int64_t BC_WindowBase::get_color_rgb16(int color)
1811         int64_t result;
1812         result = (color & 0xf80000) >> 8;
1813         result += (color & 0xfc00) >> 5;
1814         result += (color & 0xf8) >> 3;
1815         
1816         return result;
1819 int64_t BC_WindowBase::get_color_bgr16(int color)
1821         int64_t result;
1822         result = (color & 0xf80000) >> 19;
1823         result += (color & 0xfc00) >> 5;
1824         result += (color & 0xf8) << 8;
1826         return result;
1829 int64_t BC_WindowBase::get_color_bgr24(int color)
1831         int64_t result;
1832         result = (color & 0xff) << 16;
1833         result += (color & 0xff00);
1834         result += (color & 0xff0000) >> 16;
1835         return result;
1838 int BC_WindowBase::video_is_on()
1840         return video_on;
1843 void BC_WindowBase::start_video()
1845         video_on = 1;
1846         set_color(BLACK);
1847         draw_box(0, 0, get_w(), get_h());
1848         flash();
1851 void BC_WindowBase::stop_video()
1853         video_on = 0;
1858 int64_t BC_WindowBase::get_color()
1860         return top_level->current_color;
1863 void BC_WindowBase::set_color(int64_t color)
1865         top_level->current_color = color;
1866         XSetForeground(top_level->display, 
1867                 top_level->gc, 
1868                 top_level->get_color(color));
1871 void BC_WindowBase::set_opaque()
1873         XSetFunction(top_level->display, top_level->gc, GXcopy);
1876 void BC_WindowBase::set_inverse() 
1878         XSetFunction(top_level->display, top_level->gc, GXxor);
1881 Cursor BC_WindowBase::get_cursor_struct(int cursor)
1883         switch(cursor)
1884         {
1885                 case ARROW_CURSOR:         return top_level->arrow_cursor;                 break;
1886                 case CROSS_CURSOR:         return top_level->cross_cursor;
1887                 case IBEAM_CURSOR:         return top_level->ibeam_cursor;                 break;
1888                 case VSEPARATE_CURSOR:     return top_level->vseparate_cursor;             break;
1889                 case HSEPARATE_CURSOR:     return top_level->hseparate_cursor;             break;
1890                 case MOVE_CURSOR:              return top_level->move_cursor;                  break;
1891                 case LEFT_CURSOR:          return top_level->left_cursor;                  break;
1892                 case RIGHT_CURSOR:         return top_level->right_cursor;                 break;
1893                 case UPRIGHT_ARROW_CURSOR: return top_level->upright_arrow_cursor;         break;
1894                 case UPLEFT_RESIZE:        return top_level->upleft_resize_cursor;         break;
1895                 case UPRIGHT_RESIZE:       return top_level->upright_resize_cursor;        break;
1896                 case DOWNLEFT_RESIZE:      return top_level->downleft_resize_cursor;       break;
1897                 case DOWNRIGHT_RESIZE:     return top_level->downright_resize_cursor;      break;
1898         }
1899         return 0;
1902 void BC_WindowBase::set_cursor(int cursor)
1904         XDefineCursor(top_level->display, win, get_cursor_struct(cursor));
1905         current_cursor = cursor;
1906         flush();
1909 void BC_WindowBase::set_x_cursor(int cursor)
1911         temp_cursor = XCreateFontCursor(top_level->display, cursor);
1912         XDefineCursor(top_level->display, win, temp_cursor);
1913         current_cursor = cursor;
1914         flush();
1917 int BC_WindowBase::get_cursor()
1919         return current_cursor;
1928 XFontStruct* BC_WindowBase::get_font_struct(int font)
1930 // Clear out unrelated flags
1931         if(font & BOLDFACE) font ^= BOLDFACE;
1932         
1933         switch(font)
1934         {
1935                 case MEDIUMFONT: return top_level->mediumfont; break;
1936                 case SMALLFONT:  return top_level->smallfont;  break;
1937                 case LARGEFONT:  return top_level->largefont;  break;
1938         }
1939         return 0;
1942 XFontSet BC_WindowBase::get_fontset(int font)
1944         XFontSet fs = 0;
1946         if(get_resources()->use_fontset)
1947         {
1948                 switch(font)
1949                 {
1950                         case SMALLFONT:  fs = top_level->smallfontset; break;
1951                         case LARGEFONT:  fs = top_level->largefontset; break;
1952                         case MEDIUMFONT: fs = top_level->mediumfontset; break;
1953                 }
1954         }
1956         return fs;
1959 #ifdef HAVE_XFT
1960 XftFont* BC_WindowBase::get_xft_struct(int font)
1962 // Clear out unrelated flags
1963         if(font & BOLDFACE) font ^= BOLDFACE;
1965         switch(font)
1966         {
1967                 case MEDIUMFONT:   return (XftFont*)top_level->mediumfont_xft; break;
1968                 case SMALLFONT:    return (XftFont*)top_level->smallfont_xft;  break;
1969                 case LARGEFONT:    return (XftFont*)top_level->largefont_xft;  break;
1970         }
1972         return 0;
1974 #endif
1986 void BC_WindowBase::set_font(int font)
1988         top_level->current_font = font;
1991 #ifdef HAVE_XFT
1992         if(get_resources()->use_xft)
1993         {
1994                 ;
1995         }
1996         else
1997 #endif
1998         if(get_resources()->use_fontset)
1999         {
2000                 set_fontset(font);
2001         }
2003         if(get_font_struct(font))
2004         {
2005                 XSetFont(top_level->display, top_level->gc, get_font_struct(font)->fid);
2006         }
2008         return;
2011 void BC_WindowBase::set_fontset(int font)
2013         XFontSet fs = 0;
2015         if(get_resources()->use_fontset)
2016         {
2017                 switch(font)
2018                 {
2019                         case SMALLFONT:  fs = top_level->smallfontset; break;
2020                         case LARGEFONT:  fs = top_level->largefontset; break;
2021                         case MEDIUMFONT: fs = top_level->mediumfontset; break;
2022                 }
2023         }
2025         curr_fontset = fs;
2029 XFontSet BC_WindowBase::get_curr_fontset(void)
2031         if(get_resources()->use_fontset)
2032                 return curr_fontset;
2033         return 0;
2036 int BC_WindowBase::get_single_text_width(int font, char *text, int length)
2038 #ifdef HAVE_XFT
2039         if(get_resources()->use_xft && get_xft_struct(font))
2040         {
2041                 XGlyphInfo extents;
2042                 XftTextExtents8(top_level->display,
2043                         get_xft_struct(font),
2044                         (FcChar8*)text, 
2045                         length,
2046                         &extents);
2047                 return extents.xOff;
2048         }
2049         else
2050 #endif
2051         if(get_resources()->use_fontset && top_level->get_fontset(font))
2052                 return XmbTextEscapement(top_level->get_fontset(font), text, length);
2053         else
2054         if(get_font_struct(font)) 
2055                 return XTextWidth(get_font_struct(font), text, length);
2056         else
2057         {
2058                 int w = 0;
2059                 switch(font)
2060                 {
2061                         case MEDIUM_7SEGMENT:
2062                                 return get_resources()->medium_7segment[0]->get_w() * length;
2063                                 break;
2065                         default:
2066                                 return 0;
2067                 }
2068                 return w;
2069         }
2072 int BC_WindowBase::get_text_width(int font, char *text, int length)
2074         int i, j, w = 0, line_w = 0;
2075         if(length < 0) length = strlen(text);
2077         for(i = 0, j = 0; i <= length; i++)
2078         {
2079                 line_w = 0;
2080                 if(text[i] == '\n')
2081                 {
2082                         line_w = get_single_text_width(font, &text[j], i - j);
2083                         j = i + 1;
2084                 }
2085                 else
2086                 if(text[i] == 0)
2087                 {
2088                         line_w = get_single_text_width(font, &text[j], length - j);
2089                 }
2090                 if(line_w > w) w = line_w;
2091         }
2093         if(i > length && w == 0)
2094         {
2095                 w = get_single_text_width(font, text, length);
2096         }
2098         return w;
2101 int BC_WindowBase::get_text_ascent(int font)
2103 #ifdef HAVE_XFT
2104         if(get_resources()->use_xft && get_xft_struct(font))
2105         {
2106                 XGlyphInfo extents;
2107                 XftTextExtents8(top_level->display,
2108                         get_xft_struct(font),
2109                         (FcChar8*)"O", 
2110                         1,
2111                         &extents);
2112                 return extents.y;
2113         }
2114         else
2115 #endif
2116         if(get_resources()->use_fontset && top_level->get_fontset(font))
2117         {
2118         XFontSetExtents *extents;
2120         extents = XExtentsOfFontSet(top_level->get_fontset(font));
2121         return -extents->max_logical_extent.y;
2122         }
2123         else
2124         if(get_font_struct(font))
2125                 return top_level->get_font_struct(font)->ascent;
2126         else
2127         switch(font)
2128         {
2129                 case MEDIUM_7SEGMENT:
2130                         return get_resources()->medium_7segment[0]->get_h();
2131                         break;
2133                 default:
2134                         return 0;
2135         }
2138 int BC_WindowBase::get_text_descent(int font)
2140 #ifdef HAVE_XFT
2141         if(get_resources()->use_xft && get_xft_struct(font))
2142         {
2143                 XGlyphInfo extents;
2144                 XftTextExtents8(top_level->display,
2145                         get_xft_struct(font),
2146                         (FcChar8*)"j", 
2147                         1,
2148                         &extents);
2149                 return extents.height - extents.y;
2150         }
2151         else
2152 #endif
2153     if(get_resources()->use_fontset && top_level->get_fontset(font))
2154     {
2155         XFontSetExtents *extents;
2157         extents = XExtentsOfFontSet(top_level->get_fontset(font));
2158         return (extents->max_logical_extent.height
2159                         + extents->max_logical_extent.y);
2160     }
2161     else
2162         if(get_font_struct(font))
2163                 return top_level->get_font_struct(font)->descent;
2164         else
2165         switch(font)
2166         {
2167                 default:
2168                         return 0;
2169         }
2172 int BC_WindowBase::get_text_height(int font, char *text)
2174         if(!text) return get_text_ascent(font) + get_text_descent(font);
2176 // Add height of lines
2177         int h = 0, i, length = strlen(text);
2178         for(i = 0; i <= length; i++)
2179         {
2180                 if(text[i] == '\n')
2181                         h++;
2182                 else
2183                 if(text[i] == 0)
2184                         h++;
2185         }
2186         return h * (get_text_ascent(font) + get_text_descent(font));
2189 BC_Bitmap* BC_WindowBase::new_bitmap(int w, int h, int color_model)
2191         if(color_model < 0) color_model = top_level->get_color_model();
2192         return new BC_Bitmap(top_level, w, h, color_model);
2195 int BC_WindowBase::accel_available(int color_model)
2197         if(window_type != MAIN_WINDOW) 
2198                 return top_level->accel_available(color_model);
2200         int result = 0;
2202         switch(color_model)
2203         {
2204                 case BC_YUV420P:
2205                         result = grab_port_id(this, color_model);
2206                         if(result >= 0)
2207                         {
2208                                 xvideo_port_id = result;
2209                                 result = 1;
2210                         }
2211                         else
2212                                 result = 0;
2213                         break;
2215                 case BC_YUV422P:
2216                         result = 0;
2217                         break;
2219                 case BC_YUV422:
2220 //printf("BC_WindowBase::accel_available 1\n");
2221                         result = grab_port_id(this, color_model);
2222 //printf("BC_WindowBase::accel_available 2 %d\n", result);
2223                         if(result >= 0)
2224                         {
2225                                 xvideo_port_id = result;
2226                                 result = 1;
2227                         }
2228                         else
2229                                 result = 0;
2230 //printf("BC_WindowBase::accel_available 3 %d\n", xvideo_port_id);
2231                         break;
2233                 default:
2234                         result = 0;
2235                         break;
2236         }
2237 //printf("BC_WindowBase::accel_available %d %d\n", color_model, result);
2238         return result;
2242 int BC_WindowBase::grab_port_id(BC_WindowBase *window, int color_model)
2244         int numFormats, i, j, k;
2245         unsigned int ver, rev, numAdapt, reqBase, eventBase, errorBase;
2246         int port_id = -1;
2247     XvAdaptorInfo *info;
2248     XvImageFormatValues *formats;
2249         int x_color_model;
2251         if(!get_resources()->use_xvideo) return -1;
2253 // Translate from color_model to X color model
2254         x_color_model = cmodel_bc_to_x(color_model);
2256 // Only local server is fast enough.
2257         if(!resources.use_shm) return -1;
2259 // XV extension is available
2260     if(Success != XvQueryExtension(window->display, 
2261                                   &ver, 
2262                                   &rev, 
2263                                   &reqBase, 
2264                                   &eventBase, 
2265                                   &errorBase))
2266     {
2267                 return -1;
2268     }
2270 // XV adaptors are available
2271         XvQueryAdaptors(window->display, 
2272                 DefaultRootWindow(window->display), 
2273                 &numAdapt, 
2274                 &info);
2276         if(!numAdapt)
2277         {
2278                 return -1;
2279         }
2281 // Get adaptor with desired color model
2282     for(i = 0; i < numAdapt && xvideo_port_id == -1; i++)
2283     {
2284 /* adaptor supports XvImages */
2285                 if(info[i].type & XvImageMask) 
2286                 {  
2287                 formats = XvListImageFormats(window->display, 
2288                                                         info[i].base_id, 
2289                                                         &numFormats);
2290 // for(j = 0; j < numFormats; j++)
2291 //      printf("%08x\n", formats[j].id);
2293                 for(j = 0; j < numFormats && xvideo_port_id < 0; j++) 
2294                 {
2295 /* this adaptor supports the desired format */
2296                                 if(formats[j].id == x_color_model)
2297                                 {
2298 /* Try to grab a port */
2299                                         for(k = 0; k < info[i].num_ports; k++)
2300                                         {
2301 /* Got a port */
2302                                                 if(Success == XvGrabPort(top_level->display, 
2303                                                         info[i].base_id + k, 
2304                                                         CurrentTime))
2305                                                 {
2306 //printf("BC_WindowBase::grab_port_id %llx\n", info[i].base_id);
2307                                                         xvideo_port_id = info[i].base_id + k;
2308                                                         break;
2309                                                 }
2310                                         }
2311                                 }
2312                         }
2313                 if(formats) XFree(formats);
2314                 }
2315         }
2317     XvFreeAdaptorInfo(info);
2319         return xvideo_port_id;
2323 int BC_WindowBase::show_window(int flush) 
2325         XMapWindow(top_level->display, win); 
2326         if(flush) XFlush(top_level->display);
2327 //      XSync(top_level->display, 0);
2328         hidden = 0; 
2329         return 0;
2332 int BC_WindowBase::hide_window(int flush) 
2334         XUnmapWindow(top_level->display, win); 
2335         if(flush) XFlush(top_level->display);
2336         hidden = 1; 
2337         return 0;
2340 BC_MenuBar* BC_WindowBase::add_menubar(BC_MenuBar *menu_bar)
2342         subwindows->append((BC_SubWindow*)menu_bar);
2344         menu_bar->parent_window = this;
2345         menu_bar->top_level = this->top_level;
2346         menu_bar->initialize();
2347         return menu_bar;
2350 BC_WindowBase* BC_WindowBase::add_subwindow(BC_WindowBase *subwindow)
2352         subwindows->append(subwindow);
2354         if(subwindow->bg_color == -1) subwindow->bg_color = this->bg_color;
2356 // parent window must be set before the subwindow initialization
2357         subwindow->parent_window = this;
2358         subwindow->top_level = this->top_level;
2360 // Execute derived initialization
2361         subwindow->initialize();
2362         return subwindow;
2366 BC_WindowBase* BC_WindowBase::add_tool(BC_WindowBase *subwindow)
2368         return add_subwindow(subwindow);
2371 int BC_WindowBase::flash(int x, int y, int w, int h, int flush)
2373         set_opaque();
2374         XSetWindowBackgroundPixmap(top_level->display, win, pixmap);
2375         if(x >= 0)
2376         {
2377                 XClearArea(top_level->display, win, x, y, w, h, 0);
2378         }
2379         else
2380         {
2381                 XClearWindow(top_level->display, win);
2382         }
2384         if(flush)
2385                 this->flush();
2386         return 0;
2389 int BC_WindowBase::flash(int flush)
2391         flash(-1, -1, -1, -1, flush);
2394 void BC_WindowBase::flush()
2396         XFlush(top_level->display);
2399 void BC_WindowBase::sync_display()
2401         XSync(top_level->display, False);
2404 int BC_WindowBase::get_window_lock()
2406         return top_level->window_lock;
2409 int BC_WindowBase::lock_window(char *location) 
2411         if(top_level && top_level != this)
2412         {
2413                 top_level->lock_window(location);
2414         }
2415         else
2416         if(top_level)
2417         {
2418                 SET_LOCK(this, title, location);
2419                 XLockDisplay(top_level->display);
2420                 SET_LOCK2
2421                 top_level->window_lock = 1;
2422         }
2423         else
2424         {
2425                 printf("BC_WindowBase::lock_window top_level NULL\n");
2426         }
2427         return 0;
2430 int BC_WindowBase::unlock_window() 
2432         if(top_level && top_level != this)
2433         {
2434                 top_level->unlock_window();
2435         }
2436         else
2437         if(top_level)
2438         {
2439                 UNSET_LOCK(this);
2440                 top_level->window_lock = 0;
2441                 XUnlockDisplay(top_level->display);
2442         }
2443         else
2444         {
2445                 printf("BC_WindowBase::unlock_window top_level NULL\n");
2446         }
2447         return 0;
2450 void BC_WindowBase::set_done(int return_value)
2452         if(window_type != MAIN_WINDOW)
2453                 top_level->set_done(return_value);
2454         else
2455         if(event_thread)
2456         {
2457                 XEvent *event = new XEvent;
2458                 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
2460                 event->type = ClientMessage;
2461                 ptr->message_type = SetDoneXAtom;
2462                 ptr->format = 32;
2463                 this->return_value = return_value;
2465 // May lock up here because XSendEvent doesn't work too well 
2466 // asynchronous with XNextEvent.
2467 // This causes BC_WindowEvents to forward a copy of the event to run_window where 
2468 // it is deleted.
2469                 event_thread->done = 1;
2470                 XSendEvent(display, 
2471                         win, 
2472                         0, 
2473                         0, 
2474                         event);
2475                 flush();
2476                 put_event(event);
2477         }
2480 int BC_WindowBase::get_w()
2482         return w;
2485 int BC_WindowBase::get_h()
2487         return h;
2490 int BC_WindowBase::get_x()
2492         return x;
2495 int BC_WindowBase::get_y()
2497         return y;
2500 int BC_WindowBase::get_root_w(int ignore_dualhead, int lock_display)
2502         if(lock_display) lock_window("BC_WindowBase::get_root_w");
2503         Screen *screen_ptr = XDefaultScreenOfDisplay(display);
2504         int result = WidthOfScreen(screen_ptr);
2505 // Wider than 16:9, narrower than dual head
2506         if(!ignore_dualhead) if((float)result / HeightOfScreen(screen_ptr) > 1.8) result /= 2;
2508         if(lock_display) unlock_window();
2509         return result;
2512 int BC_WindowBase::get_root_h(int lock_display)
2514         if(lock_display) lock_window("BC_WindowBase::get_root_h");
2515         Screen *screen_ptr = XDefaultScreenOfDisplay(display);
2516         int result = HeightOfScreen(screen_ptr);
2517         if(lock_display) unlock_window();
2518         return result;
2521 // Bottom right corner
2522 int BC_WindowBase::get_x2()
2524         return w + x;
2527 int BC_WindowBase::get_y2()
2529         return y + h;
2532 int BC_WindowBase::get_hidden()
2534         return top_level->hidden;
2537 int BC_WindowBase::cursor_inside()
2539         return (top_level->cursor_x >= 0 && 
2540                         top_level->cursor_y >= 0 && 
2541                         top_level->cursor_x < w && 
2542                         top_level->cursor_y < h);
2545 BC_WindowBase* BC_WindowBase::get_top_level()
2547         return top_level;
2550 BC_WindowBase* BC_WindowBase::get_parent()
2552         return parent_window;
2555 int BC_WindowBase::get_color_model()
2557         return top_level->color_model;
2560 BC_Resources* BC_WindowBase::get_resources()
2562         return &BC_WindowBase::resources;
2565 int BC_WindowBase::get_bg_color()
2567         return bg_color;
2570 BC_Pixmap* BC_WindowBase::get_bg_pixmap()
2572         return bg_pixmap;
2575 void BC_WindowBase::set_active_subwindow(BC_WindowBase *subwindow)
2577         top_level->active_subwindow = subwindow;
2580 int BC_WindowBase::activate()
2582         return 0;
2585 int BC_WindowBase::deactivate()
2587         if(window_type == MAIN_WINDOW)
2588         {
2589                 if(top_level->active_menubar) top_level->active_menubar->deactivate();
2590                 if(top_level->active_popup_menu) top_level->active_popup_menu->deactivate();
2591                 if(top_level->active_subwindow) top_level->active_subwindow->deactivate();
2593                 top_level->active_menubar = 0;
2594                 top_level->active_popup_menu = 0;
2595                 top_level->active_subwindow = 0;
2596         }
2597         return 0;
2600 int BC_WindowBase::cycle_textboxes(int amount)
2602         int result = 0;
2603         BC_WindowBase *new_textbox = 0;
2605         if(amount > 0)
2606         {
2607                 BC_WindowBase *first_textbox = 0;
2608                 find_next_textbox(&first_textbox, &new_textbox, result);
2609                 if(!new_textbox) new_textbox = first_textbox;
2610                 
2611         }
2612         else
2613         if(amount < 0)
2614         {
2615                 BC_WindowBase *last_textbox = 0;
2616                 find_prev_textbox(&last_textbox, &new_textbox, result);
2617                 if(!new_textbox) new_textbox = last_textbox;
2618                 
2619         }
2621         if(new_textbox != active_subwindow)
2622         {
2623                 deactivate();
2624                 new_textbox->activate();
2625         }
2626         
2627         return 0;
2630 int BC_WindowBase::find_next_textbox(BC_WindowBase **first_textbox, BC_WindowBase **next_textbox, int &result)
2632 // Search subwindows for textbox
2633         for(int i = 0; i < subwindows->total && result < 2; i++)
2634         {
2635                 BC_WindowBase *test_subwindow = subwindows->values[i];
2636                 test_subwindow->find_next_textbox(first_textbox, next_textbox, result);
2637         }
2639         if(result < 2)
2640         {
2641                 if(uses_text())
2642                 {
2643                         if(!*first_textbox) *first_textbox = this;
2645                         if(result < 1)
2646                         {
2647                                 if(top_level->active_subwindow == this)
2648                                         result++;
2649                         }
2650                         else
2651                         {
2652                                 result++;
2653                                 *next_textbox = this;
2654                         }
2655                 }
2656         }
2657         return 0;
2660 int BC_WindowBase::find_prev_textbox(BC_WindowBase **last_textbox, BC_WindowBase **prev_textbox, int &result)
2662         if(result < 2)
2663         {
2664                 if(uses_text())
2665                 {
2666                         if(!*last_textbox) *last_textbox = this;
2668                         if(result < 1)
2669                         {
2670                                 if(top_level->active_subwindow == this)
2671                                         result++;
2672                         }
2673                         else
2674                         {
2675                                 result++;
2676                                 *prev_textbox = this;
2677                         }
2678                 }
2679         }
2681 // Search subwindows for textbox
2682         for(int i = subwindows->total - 1; i >= 0 && result < 2; i--)
2683         {
2684                 BC_WindowBase *test_subwindow = subwindows->values[i];
2685                 test_subwindow->find_prev_textbox(last_textbox, prev_textbox, result);
2686         }
2687         return 0;
2690 BC_Clipboard* BC_WindowBase::get_clipboard()
2692         return top_level->clipboard;
2695 int BC_WindowBase::get_relative_cursor_x()
2697         int abs_x, abs_y, x, y, win_x, win_y;
2698         unsigned int temp_mask;
2699         Window temp_win;
2701         XQueryPointer(top_level->display, 
2702            top_level->win, 
2703            &temp_win, 
2704            &temp_win,
2705        &abs_x, 
2706            &abs_y, 
2707            &win_x, 
2708            &win_y, 
2709            &temp_mask);
2711         XTranslateCoordinates(top_level->display, 
2712                         top_level->rootwin, 
2713                         win, 
2714                         abs_x, 
2715                         abs_y, 
2716                         &x, 
2717                         &y, 
2718                         &temp_win);
2720         return x;
2723 int BC_WindowBase::get_relative_cursor_y()
2725         int abs_x, abs_y, x, y, win_x, win_y;
2726         unsigned int temp_mask;
2727         Window temp_win;
2729         XQueryPointer(top_level->display, 
2730            top_level->win, 
2731            &temp_win, 
2732            &temp_win,
2733        &abs_x, 
2734            &abs_y, 
2735            &win_x, 
2736            &win_y, 
2737            &temp_mask);
2739         XTranslateCoordinates(top_level->display, 
2740                         top_level->rootwin, 
2741                         win, 
2742                         abs_x, 
2743                         abs_y, 
2744                         &x, 
2745                         &y, 
2746                         &temp_win);
2748         return y;
2751 int BC_WindowBase::get_abs_cursor_x(int lock_window)
2753         int abs_x, abs_y, win_x, win_y;
2754         unsigned int temp_mask;
2755         Window temp_win;
2757         if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor_x");
2758         XQueryPointer(top_level->display, 
2759                 top_level->win, 
2760                 &temp_win, 
2761                 &temp_win,
2762                 &abs_x, 
2763                 &abs_y, 
2764                 &win_x, 
2765                 &win_y, 
2766                 &temp_mask);
2767         if(lock_window) this->unlock_window();
2768         return abs_x;
2771 int BC_WindowBase::get_abs_cursor_y(int lock_window)
2773         int abs_x, abs_y, win_x, win_y;
2774         unsigned int temp_mask;
2775         Window temp_win;
2777         if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor_y");
2778         XQueryPointer(top_level->display, 
2779                 top_level->win, 
2780                 &temp_win, 
2781                 &temp_win,
2782         &abs_x, 
2783                 &abs_y, 
2784                 &win_x, 
2785                 &win_y, 
2786                 &temp_mask);
2787         if(lock_window) this->unlock_window();
2788         return abs_y;
2791 int BC_WindowBase::match_window(Window win) 
2793         if (this->win == win) return 1;
2794         int result = 0;
2795         for(int i = 0; i < subwindows->total; i++)
2796         {
2797                 result = subwindows->values[i]->match_window(win);
2798                 if (result) return result;
2799         }
2800         return 0;
2804 int BC_WindowBase::get_cursor_over_window()
2806         if(top_level != this) return top_level->get_cursor_over_window();
2808         int abs_x, abs_y, win_x, win_y;
2809         unsigned int temp_mask;
2810         Window temp_win1, temp_win2;
2812         if (!XQueryPointer(display, 
2813                 win, 
2814                 &temp_win1, 
2815                 &temp_win2,
2816                 &abs_x, 
2817                 &abs_y, 
2818                 &win_x, 
2819                 &win_y, 
2820                 &temp_mask))
2821                 return 0;
2823         int result = match_window(temp_win2)    ;
2824         return result;
2827 int BC_WindowBase::relative_cursor_x(BC_WindowBase *pov)
2829         int x, y;
2830         Window tempwin;
2832         translate_coordinates(top_level->event_win, 
2833                 pov->win,
2834                 top_level->cursor_x,
2835                 top_level->cursor_y,
2836                 &x,
2837                 &y);
2838         return x;
2841 int BC_WindowBase::relative_cursor_y(BC_WindowBase *pov)
2843         int x, y;
2844         Window tempwin;
2846         translate_coordinates(top_level->event_win, 
2847                 pov->win,
2848                 top_level->cursor_x,
2849                 top_level->cursor_y,
2850                 &x,
2851                 &y);
2852         return y;
2855 int BC_WindowBase::get_drag_x()
2857         return top_level->drag_x;
2860 int BC_WindowBase::get_drag_y()
2862         return top_level->drag_y;
2865 int BC_WindowBase::get_cursor_x()
2867         return top_level->cursor_x;
2870 int BC_WindowBase::get_cursor_y()
2872         return top_level->cursor_y;
2875 int BC_WindowBase::is_event_win()
2877         return this->win == top_level->event_win;
2880 void BC_WindowBase::set_dragging(int value)
2882         is_dragging = value;
2885 int BC_WindowBase::get_dragging()
2887         return is_dragging;
2890 int BC_WindowBase::get_buttonpress()
2892         return top_level->button_number;
2895 int BC_WindowBase::get_button_down()
2897         return top_level->button_down;
2900 int BC_WindowBase::alt_down()
2902         return top_level->alt_mask;
2905 int BC_WindowBase::shift_down()
2907         return top_level->shift_mask;
2910 int BC_WindowBase::ctrl_down()
2912         return top_level->ctrl_mask;
2916 int BC_WindowBase::get_keypress()
2918         return top_level->key_pressed;
2921 int BC_WindowBase::get_double_click()
2923         return top_level->double_click;
2926 int BC_WindowBase::get_bgcolor()
2928         return bg_color;
2931 int BC_WindowBase::resize_window(int w, int h)
2933         if(window_type == MAIN_WINDOW && !allow_resize)
2934         {
2935                 XSizeHints size_hints;
2936                 size_hints.flags = PSize | PMinSize | PMaxSize;
2937                 size_hints.width = w;
2938                 size_hints.height = h;
2939                 size_hints.min_width = w;
2940                 size_hints.max_width = w; 
2941                 size_hints.min_height = h;
2942                 size_hints.max_height = h; 
2943                 XSetNormalHints(top_level->display, win, &size_hints);
2944         }
2945         XResizeWindow(top_level->display, win, w, h);
2947         this->w = w;
2948         this->h = h;
2949         XFreePixmap(top_level->display, pixmap);
2950         pixmap = XCreatePixmap(top_level->display, win, w, h, top_level->default_depth);
2952 // Propagate to menubar
2953         for(int i = 0; i < subwindows->total; i++)
2954         {
2955                 subwindows->values[i]->dispatch_resize_event(w, h);
2956         }
2958         draw_background(0, 0, w, h);
2959         if(top_level == this && get_resources()->recursive_resizing)
2960                 resize_history.append(new BC_ResizeCall(w, h));
2961         return 0;
2964 // The only way for resize events to be propagated is by updating the internal w and h
2965 int BC_WindowBase::resize_event(int w, int h)
2967         if(window_type == MAIN_WINDOW)
2968         {
2969                 this->w = w;
2970                 this->h = h;
2971         }
2972         return 0;
2975 int BC_WindowBase::reposition_window(int x, int y, int w, int h)
2977         int resize = 0;
2979 // Some tools set their own dimensions before calling this, causing the 
2980 // resize check to skip.
2981         this->x = x;
2982         this->y = y;
2984         if(w > 0 && w != this->w)
2985         {
2986                 resize = 1;
2987                 this->w = w;
2988         }
2990         if(h > 0 && h != this->h)
2991         {
2992                 resize = 1;
2993                 this->h = h;
2994         }
2996 //printf("BC_WindowBase::reposition_window %d %d %d\n", translation_count, x_correction, y_correction);
2998         if(this->w <= 0)
2999                 printf("BC_WindowBase::reposition_window this->w == %d\n", this->w);
3000         if(this->h <= 0)
3001                 printf("BC_WindowBase::reposition_window this->h == %d\n", this->h);
3003         if(translation_count && window_type == MAIN_WINDOW)
3004         {
3005 // KDE shifts window right and down.
3006 // FVWM leaves window alone and adds border around it.
3007                 XMoveResizeWindow(top_level->display, 
3008                         win, 
3009                         x + BC_DisplayInfo::left_border - BC_DisplayInfo::auto_reposition_x, 
3010                         y + BC_DisplayInfo::top_border - BC_DisplayInfo::auto_reposition_y, 
3011                         this->w,
3012                         this->h);
3013         }
3014         else
3015         {
3016                 XMoveResizeWindow(top_level->display, 
3017                         win, 
3018                         x, 
3019                         y, 
3020                         this->w, 
3021                         this->h);
3022         }
3024         if(resize)
3025         {
3026                 XFreePixmap(top_level->display, pixmap);
3027                 pixmap = XCreatePixmap(top_level->display, 
3028                         win, 
3029                         this->w, 
3030                         this->h, 
3031                         top_level->default_depth);
3033 // Propagate to menubar
3034                 for(int i = 0; i < subwindows->total; i++)
3035                 {
3036                         subwindows->values[i]->dispatch_resize_event(this->w, this->h);
3037                 }
3039 //              draw_background(0, 0, w, h);
3040         }
3042         return 0;
3045 int BC_WindowBase::set_tooltips(int tooltips_enabled)
3047         get_resources()->tooltips_enabled = tooltips_enabled;
3048         return 0;
3051 int BC_WindowBase::raise_window(int do_flush)
3053         XRaiseWindow(top_level->display, win);
3054         if(do_flush) XFlush(top_level->display);
3055         return 0;
3058 void BC_WindowBase::set_background(VFrame *bitmap)
3060         if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
3062         bg_pixmap = new BC_Pixmap(this, 
3063                         bitmap, 
3064                         PIXMAP_OPAQUE);
3065         shared_bg_pixmap = 0;
3066         draw_background(0, 0, w, h);
3069 void BC_WindowBase::set_title(char *text)
3071         XSetStandardProperties(top_level->display, top_level->win, text, text, None, 0, 0, 0); 
3072         strcpy(this->title, _(text));
3073         flush();
3076 char* BC_WindowBase::get_title()
3078         return title;
3081 int BC_WindowBase::get_toggle_value()
3083         return toggle_value;
3086 int BC_WindowBase::get_toggle_drag()
3088         return toggle_drag;
3091 int BC_WindowBase::set_icon(VFrame *data)
3093         if(icon_pixmap) delete icon_pixmap;
3094         icon_pixmap = new BC_Pixmap(top_level, 
3095                 data, 
3096                 PIXMAP_ALPHA,
3097                 1);
3099         icon_window = new BC_Popup(this, 
3100                 (int)BC_INFINITY, 
3101                 (int)BC_INFINITY, 
3102                 icon_pixmap->get_w(), 
3103                 icon_pixmap->get_h(), 
3104                 -1, 
3105                 1, // All windows are hidden initially
3106                 icon_pixmap);
3108         XWMHints wm_hints;
3109         wm_hints.flags = IconPixmapHint | IconMaskHint | IconWindowHint;
3110         wm_hints.icon_pixmap = icon_pixmap->get_pixmap();
3111         wm_hints.icon_mask = icon_pixmap->get_alpha();
3112         wm_hints.icon_window = icon_window->win;
3113 // for(int i = 0; i < 1000; i++)
3114 // printf("02x ", icon_pixmap->get_alpha()->get_row_pointers()[0][i]);
3115 // printf("\n");
3117         XSetWMHints(top_level->display, top_level->win, &wm_hints);
3118         XSync(top_level->display, 0);
3119         return 0;
3122 int BC_WindowBase::set_w(int w)
3124         this->w = w;
3125         return 0;
3128 int BC_WindowBase::set_h(int h)
3130         this->h = h;
3131         return 0;
3134 int BC_WindowBase::load_defaults(Defaults *defaults)
3136         get_resources()->filebox_mode = defaults->get("FILEBOX_MODE", get_resources()->filebox_mode);
3137         get_resources()->filebox_w = defaults->get("FILEBOX_W", get_resources()->filebox_w);
3138         get_resources()->filebox_h = defaults->get("FILEBOX_H", get_resources()->filebox_h);
3139         defaults->get("FILEBOX_FILTER", get_resources()->filebox_filter);
3140         return 0;
3143 int BC_WindowBase::save_defaults(Defaults *defaults)
3145         defaults->update("FILEBOX_MODE", get_resources()->filebox_mode);
3146         defaults->update("FILEBOX_W", get_resources()->filebox_w);
3147 //printf("BC_ListBox::cursor_motion_event 1 %lld\n", timer.get_difference());
3148         defaults->update("FILEBOX_H", get_resources()->filebox_h);
3149         defaults->update("FILEBOX_FILTER", get_resources()->filebox_filter);
3150         return 0;
3155 // For some reason XTranslateCoordinates can take a long time to return.
3156 // We work around this by only calling it when the event windows are different.
3157 void BC_WindowBase::translate_coordinates(Window src_w, 
3158                 Window dest_w,
3159                 int src_x,
3160                 int src_y,
3161                 int *dest_x_return,
3162                 int *dest_y_return)
3164         Window tempwin = 0;
3165 //Timer timer;
3166 //timer.update();
3167         if(src_w == dest_w)
3168         {
3169                 *dest_x_return = src_x;
3170                 *dest_y_return = src_y;
3171         }
3172         else
3173         {
3174                 XTranslateCoordinates(top_level->display, 
3175                         src_w, 
3176                         dest_w, 
3177                         src_x, 
3178                         src_y, 
3179                         dest_x_return, 
3180                         dest_y_return,
3181                         &tempwin);
3182 //printf("BC_WindowBase::translate_coordinates 1 %lld\n", timer.get_difference());
3183         }
3192 #ifdef HAVE_LIBXXF86VM
3193 void BC_WindowBase::closest_vm(int *vm, int *width, int *height)
3195    int foo,bar;
3196    *vm = 0;
3197    if(XF86VidModeQueryExtension(top_level->display,&foo,&bar)) {
3198            int vm_count,i;
3199            XF86VidModeModeInfo **vm_modelines;
3200            XF86VidModeGetAllModeLines(top_level->display,XDefaultScreen(top_level->display),&vm_count,&vm_modelines);
3201            for (i = 0; i < vm_count; i++) {
3202                    if (vm_modelines[i]->hdisplay < vm_modelines[*vm]->hdisplay && vm_modelines[i]->hdisplay >= *width)
3203                            *vm = i;
3204            }
3205            display = top_level->display;
3206            if (vm_modelines[*vm]->hdisplay == *width)
3207                    *vm = -1;
3208            else
3209            {
3210                    *width = vm_modelines[*vm]->hdisplay;
3211                    *height = vm_modelines[*vm]->vdisplay;
3212            }
3213    }
3216 void BC_WindowBase::scale_vm(int vm)
3218    int foo,bar,dotclock;
3219    if(XF86VidModeQueryExtension(top_level->display,&foo,&bar))
3220    {
3221            int vm_count;
3222            XF86VidModeModeInfo **vm_modelines;
3223            XF86VidModeModeLine vml;
3224            XF86VidModeGetAllModeLines(top_level->display,XDefaultScreen(top_level->display),&vm_count,&vm_modelines);
3225            XF86VidModeGetModeLine(top_level->display,XDefaultScreen(top_level->display),&dotclock,&vml);
3226            orig_modeline.dotclock = dotclock;
3227            orig_modeline.hdisplay = vml.hdisplay;
3228            orig_modeline.hsyncstart = vml.hsyncstart;
3229            orig_modeline.hsyncend = vml.hsyncend;
3230            orig_modeline.htotal = vml.htotal;
3231            orig_modeline.vdisplay = vml.vdisplay;
3232            orig_modeline.vsyncstart = vml.vsyncstart;
3233            orig_modeline.vsyncend = vml.vsyncend;
3234            orig_modeline.vtotal = vml.vtotal;
3235            orig_modeline.flags = vml.flags;
3236            orig_modeline.privsize = vml.privsize;
3237            // orig_modeline.private = vml.private;
3238            XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),vm_modelines[vm]);
3239            XF86VidModeSetViewPort(top_level->display,XDefaultScreen(top_level->display),0,0);
3240            XFlush(top_level->display);
3241    }
3244 void BC_WindowBase::restore_vm()
3246    XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),&orig_modeline);
3247    XFlush(top_level->display);
3251 #endif
3254 #ifdef HAVE_GL
3256 extern "C"
3258         GLXContext glXCreateContext(Display *dpy,
3259                                XVisualInfo *vis,
3260                                GLXContext shareList,
3261                                int direct);
3262         
3263         int glXMakeCurrent(Display *dpy,
3264                        Drawable drawable,
3265                        GLXContext ctx);
3267         void glXSwapBuffers(Display *dpy,
3268                        Drawable drawable);
3273 void BC_WindowBase::enable_opengl()
3275         lock_window("BC_WindowBase::enable_opengl");
3276         opengl_lock.lock();
3278         XVisualInfo viproto;
3279         XVisualInfo *visinfo;
3280         int nvi;
3282 //printf("BC_WindowBase::enable_opengl 1\n");
3283         viproto.screen = top_level->screen;
3284         visinfo = XGetVisualInfo(top_level->display,
3285         VisualScreenMask,
3286         &viproto,
3287         &nvi);
3288 //printf("BC_WindowBase::enable_opengl 1 %p\n", visinfo);
3290         gl_context = glXCreateContext(top_level->display,
3291                 visinfo,
3292                 0,
3293                 1);
3294 //printf("BC_WindowBase::enable_opengl 1\n");
3296         glXMakeCurrent(top_level->display,
3297                 win,
3298                 gl_context);
3300         unsigned long valuemask = CWEventMask;
3301         XSetWindowAttributes attributes;
3302         attributes.event_mask = DEFAULT_EVENT_MASKS |
3303                         ExposureMask;
3304         XChangeWindowAttributes(top_level->display, win, valuemask, &attributes);
3306         opengl_lock.unlock();
3307         unlock_window();
3308 //printf("BC_WindowBase::enable_opengl 2\n");
3311 void BC_WindowBase::disable_opengl()
3313         unsigned long valuemask = CWEventMask;
3314         XSetWindowAttributes attributes;
3315         attributes.event_mask = DEFAULT_EVENT_MASKS;
3316         XChangeWindowAttributes(top_level->display, win, valuemask, &attributes);
3319 void BC_WindowBase::lock_opengl()
3321         lock_window("BC_WindowBase::lock_opengl");
3322         opengl_lock.lock();
3323         glXMakeCurrent(top_level->display,
3324                 win,
3325                 gl_context);
3328 void BC_WindowBase::unlock_opengl()
3330         opengl_lock.unlock();
3331         unlock_window();
3334 void BC_WindowBase::flip_opengl()
3336         glXSwapBuffers(top_level->display, win);
3338 #endif
3340 int BC_WindowBase::get_event_count()
3342         event_lock->lock("BC_WindowBase::get_event_count");
3343         int result = common_events.total;
3344         event_lock->unlock();
3345         return result;
3348 XEvent* BC_WindowBase::get_event()
3350         XEvent *result = 0;
3351         while(!done && !result)
3352         {
3353                 event_condition->lock("BC_WindowBase::get_event");
3354                 event_lock->lock("BC_WindowBase::get_event");
3355                 if(common_events.total && !done)
3356                 {
3357                         result = common_events.values[0];
3358                         common_events.remove_number(0);
3359                 }
3360                 event_lock->unlock();
3361         }
3362         return result;
3365 void BC_WindowBase::put_event(XEvent *event)
3367         event_lock->lock("BC_WindowBase::put_event");
3368         common_events.append(event);
3369         event_lock->unlock();
3370         event_condition->unlock();