4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "bcclipboard.h"
24 #include "bcdisplay.h"
25 #include "bcdisplayinfo.h"
26 #include "bcmenubar.h"
29 #include "bcpopupmenu.h"
30 #include "bcrepeater.h"
31 #include "bcresources.h"
32 #include "bcsignals.h"
33 #include "bcsubwindow.h"
34 #include "bcsynchronous.h"
36 #include "bcwindowbase.h"
37 #include "bcwindowevents.h"
38 #include "bccmodels.h"
40 #include "condition.h"
49 #include "workarounds.h"
59 #include <X11/extensions/Xinerama.h>
61 #include <X11/extensions/Xvlib.h>
63 #include <X11/extensions/shape.h>
64 #include <X11/XF86keysym.h>
65 #include <X11/Sunkeysym.h>
67 BC_ResizeCall::BC_ResizeCall(int w, int h)
74 int BC_WindowBase::shm_completion_event = -1;
75 BC_Resources *BC_WindowBase::resources = 0;
76 Window XGroupLeader = 0;
78 Mutex BC_KeyboardHandlerLock::keyboard_listener_mutex("keyboard_listener",0);
79 ArrayList<BC_KeyboardHandler*> BC_KeyboardHandler::listeners;
81 BC_WindowBase::BC_WindowBase()
83 //printf("BC_WindowBase::BC_WindowBase 1\n");
84 BC_WindowBase::initialize();
87 BC_WindowBase::~BC_WindowBase()
90 BC_Display::lock_display("BC_WindowBase::~BC_WindowBase");
92 if(window_type == MAIN_WINDOW)
93 lock_window("BC_WindowBase::~BC_WindowBase");
96 #ifdef HAVE_LIBXXF86VM
97 if(window_type == VIDMODE_SCALED_WINDOW && vm_switched) {
104 if(window_type != MAIN_WINDOW)
107 XSelectInput(top_level->display, this->win, 0);
108 XSync(top_level->display,0);
109 #ifndef SINGLE_THREAD
110 top_level->dequeue_events(win);
112 // drop active window refs to this
113 if(top_level->active_menubar == this) top_level->active_menubar = 0;
114 if(top_level->active_popup_menu == this) top_level->active_popup_menu = 0;
115 if(top_level->active_subwindow == this) top_level->active_subwindow = 0;
116 // drop motion window refs to this
117 if(top_level->motion_events && top_level->last_motion_win == this->win)
118 top_level->motion_events = 0;
120 // Remove pointer from parent window to this
121 parent_window->subwindows->remove(this);
124 if(grab_active) grab_active->active_grab = 0;
125 if(icon_window) delete icon_window;
126 if(window_type == POPUP_WINDOW)
127 parent_window->remove_popup(this);
129 // Delete the subwindows
132 while(subwindows->total)
134 // Subwindow removes its own pointer
135 delete subwindows->values[0];
142 //printf("delete glx=%08x, win=%08x %s\n", (unsigned)glx_win, (unsigned)win, title);
144 if( get_resources()->get_synchronous() && glx_win != 0 ) {
145 if( window_type == MAIN_WINDOW )
147 get_resources()->get_synchronous()->delete_window(this);
148 if( window_type == MAIN_WINDOW )
149 lock_window("BC_WindowBase::delete_window");
152 XDestroyWindow(top_level->display, win);
154 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
155 if(icon_pixmap) delete icon_pixmap;
156 if(temp_bitmap) delete temp_bitmap;
157 top_level->active_bitmaps.remove_buffers(this);
158 if(_7segment_pixmaps)
160 for(int i = 0; i < TOTAL_7SEGMENT; i++)
161 delete _7segment_pixmaps[i];
163 delete [] _7segment_pixmaps;
168 if(window_type == MAIN_WINDOW)
170 XFreeGC(display, gc);
171 static XFontStruct *BC_WindowBase::*xfont[] = {
172 &BC_WindowBase::smallfont,
173 &BC_WindowBase::mediumfont,
174 &BC_WindowBase::largefont,
175 &BC_WindowBase::bigfont,
176 &BC_WindowBase::clockfont,
178 for( int i=sizeof(xfont)/sizeof(xfont[0]); --i>=0; )
179 XFreeFont(display, this->*xfont[i]);
182 // prevents a bug when Xft closes with unrefd fonts
183 FcPattern *defaults = FcPatternCreate();
184 FcPatternAddInteger(defaults, "maxunreffonts", 0);
185 XftDefaultSet(display, defaults);
187 static void *BC_WindowBase::*xft_font[] = {
188 &BC_WindowBase::smallfont_xft,
189 &BC_WindowBase::mediumfont_xft,
190 &BC_WindowBase::largefont_xft,
191 &BC_WindowBase::bigfont_xft,
192 &BC_WindowBase::bold_smallfont_xft,
193 &BC_WindowBase::bold_mediumfont_xft,
194 &BC_WindowBase::bold_largefont_xft,
195 &BC_WindowBase::clockfont_xft,
197 for( int i=sizeof(xft_font)/sizeof(xft_font[0]); --i>=0; ) {
198 XftFont *xft = (XftFont *)(this->*xft_font[i]);
199 if( xft ) xftFontClose (display, xft);
207 XFree(xinerama_info);
208 xinerama_screens = 0;
211 if( xvideo_port_id >= 0 )
212 XvUngrabPort(display, xvideo_port_id, CurrentTime);
215 // Must be last reference to display.
216 // _XftDisplayInfo needs a lock.
217 get_resources()->create_window_lock->lock("BC_WindowBase::~BC_WindowBase");
218 XCloseDisplay(display);
219 get_resources()->create_window_lock->unlock();
221 // clipboard uses a different display connection
222 clipboard->stop_clipboard();
226 resize_history.remove_all_objects();
229 #ifndef SINGLE_THREAD
230 common_events.remove_all_objects();
232 delete event_condition;
235 top_level->window_lock = 0;
236 BC_Display::unlock_display();
241 if( glx_fbcfgs_window ) XFree(glx_fbcfgs_window);
242 if( glx_fbcfgs_pbuffer) XFree(glx_fbcfgs_pbuffer);
243 if( glx_fbcfgs_pixmap ) XFree(glx_fbcfgs_pixmap);
246 UNSET_ALL_LOCKS(this)
249 int BC_WindowBase::initialize()
254 display_lock_owner = 0;
257 context_help_keyword[0] = 0;
260 resend_event_window = 0;
272 xinerama_screens = 0;
277 translation_events = 0;
278 ctrl_mask = shift_mask = alt_mask = 0;
279 cursor_x = cursor_y = button_number = 0;
293 active_popup_menu = 0;
294 active_subwindow = 0;
298 _7segment_pixmaps = 0;
301 // next_repeat_id = 0;
303 current_font = MEDIUMFONT;
304 current_color = BLACK;
305 current_cursor = ARROW_CURSOR;
308 shared_bg_pixmap = 0;
311 window_type = MAIN_WINDOW;
312 translation_count = 0;
313 x_correction = y_correction = 0;
322 #ifdef HAVE_LIBXXF86VM
340 bold_smallfont_xft = 0;
341 bold_mediumfont_xft = 0;
342 bold_largefont_xft = 0;
344 completion_lock = new Condition(0, "BC_WindowBase::completion_lock");
346 // Need these right away since put_event is called before run_window sometimes.
347 event_lock = new Mutex("BC_WindowBase::event_lock");
348 event_condition = new Condition(0, "BC_WindowBase::event_condition");
349 init_lock = new Condition(0, "BC_WindowBase::init_lock");
351 grab_lock = new Mutex("BC_WindowBase::grab_lock");
353 cursor_timer = new Timer;
356 glx_fbcfgs_window = 0; n_fbcfgs_window = 0;
357 glx_fbcfgs_pbuffer = 0; n_fbcfgs_pbuffer = 0;
358 glx_fbcfgs_pixmap = 0; n_fbcfgs_pixmap = 0;
372 #define DEFAULT_EVENT_MASKS EnterWindowMask | \
375 ButtonReleaseMask | \
376 PointerMotionMask | \
380 int BC_WindowBase::create_window(BC_WindowBase *parent_window, const char *title,
381 int x, int y, int w, int h, int minw, int minh, int allow_resize,
382 int private_color, int hide, int bg_color, const char *display_name,
383 int window_type, BC_Pixmap *bg_pixmap, int group_it)
385 XSetWindowAttributes attr;
387 XSizeHints size_hints;
390 #ifdef HAVE_LIBXXF86VM
394 id = get_resources()->get_id();
395 if(parent_window) top_level = parent_window->top_level;
396 if( top_level ) lock_window("BC_WindowBase::create_window");
397 get_resources()->create_window_lock->lock("BC_WindowBase::create_window");
399 #ifdef HAVE_LIBXXF86VM
400 if(window_type == VIDMODE_SCALED_WINDOW)
401 closest_vm(&vm,&w,&h);
408 this->bg_color = bg_color;
409 this->window_type = window_type;
411 this->private_color = private_color;
412 this->parent_window = parent_window;
413 this->bg_pixmap = bg_pixmap;
414 this->allow_resize = allow_resize;
416 strcpy(this->display_name, display_name);
418 this->display_name[0] = 0;
421 if(bg_pixmap) shared_bg_pixmap = 1;
423 subwindows = new BC_SubWindowList;
425 if(window_type == MAIN_WINDOW)
428 parent_window = this;
432 display = BC_Display::get_display(display_name);
433 BC_Display::lock_display("BC_WindowBase::create_window");
434 // BC_Display::display_global->new_window(this);
437 // get the display connection
439 // This function must be the first Xlib
440 // function a multi-threaded program calls
442 display = init_display(display_name);
443 if( shm_completion_event < 0 ) shm_completion_event =
444 ShmCompletion + XShmGetEventBase(display);
446 lock_window("BC_WindowBase::create_window 1");
448 screen = DefaultScreen(display);
449 rootwin = RootWindow(display, screen);
450 // window placement boundaries
451 if( !xinerama_screens && XineramaIsActive(display) )
452 xinerama_info = XineramaQueryScreens(display, &xinerama_screens);
453 root_w = get_root_w(0);
454 root_h = get_root_h(0);
457 vis = get_glx_visual(display);
461 int mask = VisualDepthMask | VisualClassMask;
462 static XVisualInfo vinfo;
463 memset(&vinfo, 0, sizeof(vinfo));
465 vinfo.c_class = TrueColor;
467 XVisualInfo *vis_info = XGetVisualInfo(display, mask, &vinfo, &nitems);
468 vis = vis_info && nitems>0 ? vis_info[0].visual : 0;
469 if( vis_info ) XFree(vis_info);
472 vis = DefaultVisual(display, screen);
473 default_depth = DefaultDepth(display, screen);
475 client_byte_order = (*(const u_int32_t*)"a ") & 0x00000001;
476 server_byte_order = (XImageByteOrder(display) == MSBFirst) ? 0 : 1;
479 // This must be done before fonts to know if antialiasing is available.
482 if(resources->use_shm < 0) resources->initialize_display(this);
483 x_correction = BC_DisplayInfo::get_left_border();
484 y_correction = BC_DisplayInfo::get_top_border();
486 // clamp window placement
487 if(this->x + this->w + x_correction > root_w)
488 this->x = root_w - this->w - x_correction;
489 if(this->y + this->h + y_correction > root_h)
490 this->y = root_h - this->h - y_correction;
491 if(this->x < 0) this->x = 0;
492 if(this->y < 0) this->y = 0;
494 if(this->bg_color == -1)
495 this->bg_color = resources->get_bg_color();
497 // printf("bcwindowbase 1 %s\n", title);
498 // if(window_type == MAIN_WINDOW) sleep(1);
499 // printf("bcwindowbase 10\n");
505 mask = CWEventMask | CWBackPixel | CWColormap | CWCursor;
507 attr.event_mask = DEFAULT_EVENT_MASKS |
508 StructureNotifyMask |
512 attr.background_pixel = get_color(this->bg_color);
513 attr.colormap = cmap;
514 attr.cursor = get_cursor_struct(ARROW_CURSOR);
516 win = XCreateWindow(display, rootwin,
517 this->x, this->y, this->w, this->h, 0,
518 top_level->default_depth, InputOutput,
520 XGetNormalHints(display, win, &size_hints);
522 size_hints.flags = PSize | PMinSize | PMaxSize;
523 size_hints.width = this->w;
524 size_hints.height = this->h;
525 size_hints.min_width = allow_resize ? minw : this->w;
526 size_hints.max_width = allow_resize ? 32767 : this->w;
527 size_hints.min_height = allow_resize ? minh : this->h;
528 size_hints.max_height = allow_resize ? 32767 : this->h;
529 if(x > -BC_INFINITY && x < BC_INFINITY)
531 size_hints.flags |= PPosition;
532 size_hints.x = this->x;
533 size_hints.y = this->y;
535 XSetWMProperties(display, win, 0, 0, 0, 0, &size_hints, 0, 0);
538 #ifndef SINGLE_THREAD
539 clipboard = new BC_Clipboard(this);
540 clipboard->start_clipboard();
546 Atom ClientLeaderXAtom;
547 if (XGroupLeader == 0)
549 const char *instance_name = "cinelerra";
550 const char *class_name = "Cinelerra";
551 XClassHint *class_hints = XAllocClassHint();
552 class_hints->res_name = (char*)instance_name;
553 class_hints->res_class = (char*)class_name;
554 XSetClassHint(top_level->display, win, class_hints);
556 ClientLeaderXAtom = XInternAtom(display, "WM_CLIENT_LEADER", True);
557 XChangeProperty(display, win, ClientLeaderXAtom, XA_WINDOW, 32,
558 PropModeReplace, (unsigned char *)&XGroupLeader, true);
561 set_icon(get_resources()->default_icon);
564 #ifdef HAVE_LIBXXF86VM
565 if(window_type == VIDMODE_SCALED_WINDOW && vm != -1)
572 #ifdef HAVE_LIBXXF86VM
573 if(window_type == POPUP_WINDOW || window_type == VIDMODE_SCALED_WINDOW)
575 if(window_type == POPUP_WINDOW)
578 mask = CWEventMask | CWBackPixel | CWColormap |
579 CWOverrideRedirect | CWSaveUnder | CWCursor;
581 attr.event_mask = DEFAULT_EVENT_MASKS | ExposureMask |
582 KeyPressMask | KeyReleaseMask;
584 if(this->bg_color == -1)
585 this->bg_color = resources->get_bg_color();
586 attr.background_pixel = top_level->get_color(bg_color);
587 attr.colormap = top_level->cmap;
588 if(top_level->is_hourglass)
589 attr.cursor = top_level->get_cursor_struct(HOURGLASS_CURSOR);
591 attr.cursor = top_level->get_cursor_struct(ARROW_CURSOR);
592 attr.override_redirect = True;
593 attr.save_under = True;
595 win = XCreateWindow(top_level->display,
596 top_level->rootwin, this->x, this->y, this->w, this->h, 0,
597 top_level->default_depth, InputOutput, top_level->vis, mask,
599 top_level->add_popup(this);
602 if(window_type == SUB_WINDOW)
604 mask = CWEventMask | CWBackPixel | CWCursor;
605 attr.event_mask = DEFAULT_EVENT_MASKS;
606 attr.background_pixel = top_level->get_color(this->bg_color);
607 if(top_level->is_hourglass)
608 attr.cursor = top_level->get_cursor_struct(HOURGLASS_CURSOR);
610 attr.cursor = top_level->get_cursor_struct(ARROW_CURSOR);
611 win = XCreateWindow(top_level->display,
612 parent_window->win, this->x, this->y, this->w, this->h, 0,
613 top_level->default_depth, InputOutput, top_level->vis, mask,
616 if(!hidden) XMapWindow(top_level->display, win);
619 // Create pixmap for all windows
620 pixmap = new BC_Pixmap(this, this->w, this->h);
622 // Set up options for main window
623 if(window_type == MAIN_WINDOW)
625 if(get_resources()->bg_image && !bg_pixmap && bg_color < 0)
627 this->bg_pixmap = new BC_Pixmap(this,
628 get_resources()->bg_image,
632 if(!hidden) show_window();
636 draw_background(0, 0, this->w, this->h);
638 flash(-1, -1, -1, -1, 0);
640 // Set up options for popup window
641 #ifdef HAVE_LIBXXF86VM
642 if(window_type == POPUP_WINDOW || window_type == VIDMODE_SCALED_WINDOW)
644 if(window_type == POPUP_WINDOW)
648 if(!hidden) show_window();
650 get_resources()->create_window_lock->unlock();
656 Display* BC_WindowBase::init_display(const char *display_name)
660 if(display_name && display_name[0] == 0) display_name = NULL;
661 if((display = XOpenDisplay(display_name)) == NULL) {
662 printf("BC_WindowBase::init_display: cannot connect to X server %s\n",
664 if(getenv("DISPLAY") == NULL) {
665 printf(_("'DISPLAY' environment variable not set.\n"));
668 // Try again with default display.
669 if((display = XOpenDisplay(0)) == NULL) {
670 printf("BC_WindowBase::init_display: cannot connect to default X server.\n");
675 static int xsynch = -1;
677 const char *cp = getenv("CIN_XSYNCH");
678 xsynch = !cp ? 0 : atoi(cp);
681 XSynchronize(display, True);
686 Display* BC_WindowBase::get_display()
688 return top_level->display;
691 int BC_WindowBase::get_screen()
693 return top_level->screen;
696 int BC_WindowBase::run_window()
702 // Events may have been sent before run_window so can't initialize them here.
705 set_repeat(get_resources()->tooltip_delay);
706 BC_Display::display_global->new_window(this);
708 // If the first window created, run the display loop in this thread.
709 if(BC_Display::display_global->is_first(this))
711 BC_Display::unlock_display();
712 BC_Display::display_global->loop();
716 BC_Display::unlock_display();
717 completion_lock->lock("BC_WindowBase::run_window");
720 BC_Display::lock_display("BC_WindowBase::run_window");
721 BC_Display::display_global->delete_window(this);
723 unset_all_repeaters();
725 BC_Display::unlock_display();
727 #else // SINGLE_THREAD
732 set_repeat(get_resources()->tooltip_delay);
734 // Start X server events
735 event_thread = new BC_WindowEvents(this);
736 event_thread->start();
742 // Handle common events
747 unset_all_repeaters();
751 event_condition->reset();
752 common_events.remove_all_objects();
756 #endif // SINGLE_THREAD
761 int BC_WindowBase::get_key_masks(unsigned int key_state)
763 // printf("BC_WindowBase::get_key_masks %llx\n",
764 // event->xkey.state);
765 ctrl_mask = (key_state & ControlMask) ? 1 : 0; // ctrl key down
766 shift_mask = (key_state & ShiftMask) ? 1 : 0; // shift key down
767 alt_mask = (key_state & Mod1Mask) ? 1 : 0; // alt key down
772 void BC_WindowBase::add_keyboard_listener(int(BC_WindowBase::*handler)(BC_WindowBase *))
774 BC_KeyboardHandlerLock set;
775 BC_KeyboardHandler::listeners.append(new BC_KeyboardHandler(handler, this));
778 void BC_WindowBase::del_keyboard_listener(int(BC_WindowBase::*handler)(BC_WindowBase *))
780 BC_KeyboardHandlerLock set;
781 int i = BC_KeyboardHandler::listeners.size();
782 while( --i >= 0 && BC_KeyboardHandler::listeners[i]->handler!=handler );
783 if( i >= 0 ) BC_KeyboardHandler::listeners.remove_object_number(i);
786 int BC_KeyboardHandler::run_event(BC_WindowBase *wp)
788 int result = (win->*handler)(wp);
792 int BC_KeyboardHandler::run_listeners(BC_WindowBase *wp)
795 BC_KeyboardHandlerLock set;
796 for( int i=0; !result && i<listeners.size(); ++i ) {
797 BC_KeyboardHandler *listener = listeners[i];
798 result = listener->run_event(wp);
803 void BC_KeyboardHandler::kill_grabs()
805 BC_KeyboardHandlerLock set;
806 for( int i=0; i<listeners.size(); ++i ) {
807 BC_WindowBase *win = listeners[i]->win;
808 if( win->get_window_type() != POPUP_WINDOW ) continue;
809 ((BC_Popup *)win)->ungrab_keyboard();
813 void BC_ActiveBitmaps::reque(XEvent *event)
815 XShmCompletionEvent *shm_ev = (XShmCompletionEvent *)event;
816 ShmSeg shmseg = shm_ev->shmseg;
817 Drawable drawable = shm_ev->drawable;
818 //printf("BC_BitmapImage::reque %08lx\n",shmseg);
819 active_lock.lock("BC_BitmapImage::reque");
820 BC_BitmapImage *bfr = first;
821 while( bfr && bfr->get_shmseg() != shmseg ) bfr = bfr->next;
822 if( bfr && bfr->drawable == drawable )
824 active_lock.unlock();
826 // sadly, X reports two drawable completions and creates false reporting, so no boobytrap
827 // printf("BC_BitmapImage::reque missed shmseg %08x, drawable %08x\n",
828 // (int)shmseg, (int)drawable);
831 if( bfr->drawable != drawable ) return;
832 if( bfr->is_zombie() ) { --BC_Bitmap::zombies; delete bfr; return; }
833 bfr->bitmap->reque(bfr);
836 void BC_ActiveBitmaps::insert(BC_BitmapImage *bfr, Drawable pixmap)
838 active_lock.lock("BC_BitmapImage::insert");
839 bfr->drawable = pixmap;
841 active_lock.unlock();
844 void BC_ActiveBitmaps::remove_buffers(BC_WindowBase *wdw)
846 active_lock.lock("BC_ActiveBitmaps::remove");
847 for( BC_BitmapImage *nxt=0, *bfr=first; bfr; bfr=nxt ) {
849 if( bfr->is_zombie() ) { --BC_Bitmap::zombies; delete bfr; continue; }
850 if( bfr->bitmap->parent_window == wdw ) remove_pointer(bfr);
852 active_lock.unlock();
855 BC_ActiveBitmaps::BC_ActiveBitmaps()
859 BC_ActiveBitmaps::~BC_ActiveBitmaps()
865 int BC_WindowBase::keysym_lookup(XEvent *event)
867 for( int i = 0; i < KEYPRESSLEN; ++i ) keys_return[i] = 0;
868 for( int i = 0; i < 4; ++i ) wkey_string[i] = 0;
870 if( event->xany.send_event && !event->xany.serial ) {
871 keysym = (KeySym) event->xkey.keycode;
872 keys_return[0] = keysym;
875 wkey_string_length = 0;
877 if( input_context ) {
879 wkey_string_length = XwcLookupString(input_context,
880 (XKeyEvent*)event, wkey, 4, &keysym, 0);
881 for( int i=0; i<wkey_string_length; ++i )
882 wkey_string[i] = wkey[i];
883 //printf("keysym_lookup 1 %d %d %lx %x %x %x %x\n", wkey_string_length, keysym,
884 // wkey_string[0], wkey_string[1], wkey_string[2], wkey_string[3]);
887 int ret = Xutf8LookupString(input_context, (XKeyEvent*)event,
888 keys_return, KEYPRESSLEN, &keysym, &stat);
889 //printf("keysym_lookup 2 %d %d %lx %x %x\n", ret, stat, keysym, keys_return[0], keys_return[1]);
890 if( stat == XLookupBoth ) return ret;
891 if( stat == XLookupKeySym ) return 0;
893 int ret = XLookupString((XKeyEvent*)event, keys_return, KEYPRESSLEN, &keysym, 0);
894 wkey_string_length = ret;
895 for( int i=0; i<ret; ++i ) wkey_string[i] = keys_return[i];
899 pthread_t locking_task = (pthread_t)-1L;
900 int locking_event = -1;
901 int locking_message = -1;
903 int BC_WindowBase::dispatch_event()
907 XClientMessageEvent *ptr;
908 int cancel_resize, cancel_translation;
909 volatile static int debug = 0;
914 #ifndef SINGLE_THREAD
915 // If an event is waiting get it, otherwise
916 // wait for next event only if there are no compressed events.
917 if(get_event_count() ||
918 (!motion_events && !resize_events && !translation_events))
921 // Lock out window deletions
922 lock_window("BC_WindowBase::dispatch_event 1");
923 locking_event = event->type;
924 locking_task = pthread_self();
925 locking_message = event->xclient.message_type;
928 // Handle compressed events
930 lock_window("BC_WindowBase::dispatch_event 2");
932 dispatch_resize_event(last_resize_w, last_resize_h);
934 dispatch_motion_event();
935 if(translation_events)
936 dispatch_translation_event();
947 if( debug && event->type != ClientMessage ) {
948 static const char *event_names[] = {
949 "Reply", "Error", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease", "MotionNotify",
950 "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut", "KeymapNotify", "Expose", "GraphicsExpose",
951 "NoExpose", "VisibilityNotify", "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify",
952 "MapRequest", "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
953 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear",
954 "SelectionRequest", "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify",
955 "GenericEvent", "LASTEvent",
957 const int nevents = sizeof(event_names)/sizeof(event_names[0]);
959 printf("BC_WindowBase::dispatch_event %d %s %p %d (%s)\n", __LINE__,
960 title, event, event->type, event->type>=0 && event->type<nevents ?
961 event_names[event->type] : "Unknown");
965 grab_lock->lock("BC_WindowBase::dispatch_event 3");
969 active_grab->lock_window("BC_WindowBase::dispatch_event 3");
970 result = active_grab->grab_event(event);
971 active_grab->unlock_window();
974 if( result ) return result;
975 lock_window("BC_WindowBase::dispatch_event 4");
978 switch(event->type) {
980 // Clear the resize buffer
982 dispatch_resize_event(last_resize_w, last_resize_h);
983 // Clear the motion buffer since this can clear the window
985 dispatch_motion_event();
987 ptr = (XClientMessageEvent*)event;
988 if( ptr->message_type == ProtoXAtom &&
989 (Atom)ptr->data.l[0] == DelWinXAtom ) {
992 else if( ptr->message_type == RepeaterXAtom ) {
993 dispatch_repeat_event(ptr->data.l[0]);
995 else if( ptr->message_type == SetDoneXAtom ) {
999 receive_custom_xatoms((xatom_event *)ptr);
1005 dispatch_focus_in();
1010 dispatch_focus_out();
1024 dispatch_motion_event();
1026 get_key_masks(event->xbutton.state);
1027 cursor_x = event->xbutton.x;
1028 cursor_y = event->xbutton.y;
1029 button_number = event->xbutton.button;
1031 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1032 event_win = event->xany.window;
1033 if( button_number < 6 ) {
1034 if( button_number < 4 )
1036 button_pressed = event->xbutton.button;
1037 button_time1 = button_time2;
1038 button_time2 = button_time3;
1039 button_time3 = event->xbutton.time;
1042 drag_win = event_win;
1043 drag_x1 = cursor_x - get_resources()->drag_radius;
1044 drag_x2 = cursor_x + get_resources()->drag_radius;
1045 drag_y1 = cursor_y - get_resources()->drag_radius;
1046 drag_y2 = cursor_y + get_resources()->drag_radius;
1047 if( button_number < 4 ) {
1048 if((long)(button_time3 - button_time1) < resources->double_click * 2) {
1050 button_time3 = button_time2 = button_time1 = 0;
1052 if((long)(button_time3 - button_time2) < resources->double_click) {
1054 // button_time3 = button_time2 = button_time1 = 0;
1061 dispatch_button_press();
1068 dispatch_motion_event();
1070 get_key_masks(event->xbutton.state);
1071 button_number = event->xbutton.button;
1072 event_win = event->xany.window;
1073 if (button_number < 6)
1075 if(button_number < 4)
1077 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1079 dispatch_button_release();
1084 event_win = event->xany.window;
1086 for( int i=0; !result && i<popups.size(); ++i ) { // popups take focus
1087 if( popups[i]->win == event_win )
1088 result = popups[i]->dispatch_expose_event();
1091 result = dispatch_expose_event();
1095 get_key_masks(event->xmotion.state);
1096 // Dispatch previous motion event if this is a subsequent motion from a different window
1097 if(motion_events && last_motion_win != event->xany.window)
1099 dispatch_motion_event();
1102 // Buffer the current motion
1104 last_motion_state = event->xmotion.state;
1105 last_motion_x = event->xmotion.x;
1106 last_motion_y = event->xmotion.y;
1107 last_motion_win = event->xany.window;
1110 case ConfigureNotify:
1111 // printf("BC_WindowBase::dispatch_event %d win=%p this->win=%p\n",
1113 // event->xany.window,
1116 XTranslateCoordinates(top_level->display,
1124 last_resize_w = event->xconfigure.width;
1125 last_resize_h = event->xconfigure.height;
1128 cancel_translation = 0;
1130 // Resize history prevents responses to recursive resize requests
1131 for(int i = 0; i < resize_history.total && !cancel_resize; i++)
1133 if(resize_history.values[i]->w == last_resize_w &&
1134 resize_history.values[i]->h == last_resize_h)
1136 delete resize_history.values[i];
1137 resize_history.remove_number(i);
1142 if(last_resize_w == w && last_resize_h == h)
1150 if((last_translate_x == x && last_translate_y == y))
1151 cancel_translation = 1;
1153 if(!cancel_translation)
1155 translation_events = 1;
1158 translation_count++;
1162 get_key_masks(event->xkey.state);
1163 keys_return[0] = 0; keysym = -1;
1164 if(XFilterEvent(event, win)) {
1167 if( keysym_lookup(event) < 0 ) {
1168 printf("keysym %x\n", (uint32_t)keysym);
1172 //printf("BC_WindowBase::dispatch_event %d keysym=0x%x\n",
1176 // block out control keys
1177 if(keysym > 0xffe0 && keysym < 0xffff) break;
1178 // block out Alt_GR key
1179 if(keysym == 0xfe03) break;
1182 printf("BC_WindowBase::dispatch_event %x\n", (uint32_t)keysym);
1184 #ifdef X_HAVE_UTF8_STRING
1185 //It's Ascii or UTF8?
1186 // if (keysym != 0xffff && (keys_return[0] & 0xff) >= 0x7f )
1187 //printf("BC_WindowBase::dispatch_event %d %02x%02x\n", __LINE__, keys_return[0], keys_return[1]);
1189 if( ((keys_return[1] & 0xff) > 0x80) &&
1190 ((keys_return[0] & 0xff) > 0xC0) ) {
1191 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1192 key_pressed = keysym & 0xff;
1196 // shuttle speed codes
1197 if( keysym >= SKEY_MIN && keysym <= SKEY_MAX ) {
1198 key_pressed = keysym;
1200 else switch( keysym ) {
1201 // block out extra keys
1211 // Translate key codes
1212 case XK_Return: key_pressed = RETURN; break;
1213 case XK_Up: key_pressed = UP; break;
1214 case XK_Down: key_pressed = DOWN; break;
1215 case XK_Left: key_pressed = LEFT; break;
1216 case XK_Right: key_pressed = RIGHT; break;
1217 case XK_Next: key_pressed = PGDN; break;
1218 case XK_Prior: key_pressed = PGUP; break;
1219 case XK_BackSpace: key_pressed = BACKSPACE; break;
1220 case XK_Escape: key_pressed = ESC; break;
1223 key_pressed = LEFTTAB;
1227 case XK_ISO_Left_Tab: key_pressed = LEFTTAB; break;
1228 case XK_underscore: key_pressed = '_'; break;
1229 case XK_asciitilde: key_pressed = '~'; break;
1230 case XK_Delete: key_pressed = DELETE; break;
1231 case XK_Home: key_pressed = HOME; break;
1232 case XK_End: key_pressed = END; break;
1235 case XK_KP_Enter: key_pressed = KPENTER; break;
1236 case XK_KP_Add: key_pressed = KPPLUS; break;
1237 case XK_KP_Subtract: key_pressed = KPMINUS; break;
1238 case XK_KP_Multiply: key_pressed = KPSTAR; break;
1239 case XK_KP_Divide: key_pressed = KPSLASH; break;
1241 case XK_KP_End: key_pressed = KP1; break;
1243 case XK_KP_Down: key_pressed = KP2; break;
1245 case XK_KP_Page_Down: key_pressed = KP3; break;
1247 case XK_KP_Left: key_pressed = KP4; break;
1249 case XK_KP_Begin: key_pressed = KP5; break;
1251 case XK_KP_Right: key_pressed = KP6; break;
1253 case XK_KP_Home: key_pressed = KP7; break;
1255 case XK_KP_Up: key_pressed = KP8; break;
1257 case XK_KP_Page_Up: key_pressed = KP9; break;
1259 case XK_KP_Insert: key_pressed = KPINS; break;
1261 case XK_KP_Delete: key_pressed = KPDEL; break;
1263 case XK_F1: key_pressed = KEY_F1; break;
1264 case XK_F2: key_pressed = KEY_F2; break;
1265 case XK_F3: key_pressed = KEY_F3; break;
1266 case XK_F4: key_pressed = KEY_F4; break;
1267 case XK_F5: key_pressed = KEY_F5; break;
1268 case XK_F6: key_pressed = KEY_F6; break;
1269 case XK_F7: key_pressed = KEY_F7; break;
1270 case XK_F8: key_pressed = KEY_F8; break;
1271 case XK_F9: key_pressed = KEY_F9; break;
1272 case XK_F10: key_pressed = KEY_F10; break;
1273 case XK_F11: key_pressed = KEY_F11; break;
1274 case XK_F12: key_pressed = KEY_F12; break;
1276 case XK_Menu: key_pressed = KPMENU; break; /* menu */
1279 key_pressed = keysym & 0xff;
1280 #ifdef X_HAVE_UTF8_STRING
1281 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1286 #ifdef X_HAVE_UTF8_STRING
1288 key_pressed_utf8 = keys_return;
1293 if( top_level == this )
1294 result = BC_KeyboardHandler::run_listeners(this);
1296 //printf("BC_WindowBase::dispatch_event %d %d %x\n", shift_down(), alt_down(), key_pressed);
1298 result = dispatch_keypress_event();
1299 // Handle some default keypresses
1302 if(key_pressed == 'w' ||
1311 XLookupString((XKeyEvent*)event, keys_return, 1, &keysym, 0);
1312 dispatch_keyrelease_event();
1313 // printf("BC_WindowBase::dispatch_event KeyRelease keysym=0x%x keystate=0x%lld\n",
1314 // keysym, event->xkey.state);
1318 if( event->xcrossing.mode != NotifyNormal ) break;
1320 event_win = event->xany.window;
1321 dispatch_cursor_leave();
1325 if( event->xcrossing.mode != NotifyNormal ) break;
1327 if( !cursor_entered ) {
1328 for( int i=0; i<popups.size(); ++i ) { // popups always take focus
1329 if( popups[i]->win == event->xcrossing.window )
1332 if( !cursor_entered && get_resources()->grab_input_focus &&
1333 !event->xcrossing.focus && event->xcrossing.window == win ) {
1336 if( cursor_entered )
1339 event_win = event->xany.window;
1340 cursor_x = event->xcrossing.x;
1341 cursor_y = event->xcrossing.y;
1342 dispatch_cursor_enter();
1348 //printf("100 %s %p %d\n", title, event, event->type);
1349 //if(event->type != ClientMessage) dump();
1351 #ifndef SINGLE_THREAD
1354 if( resend_event_window ) {
1355 resend_event_window->put_event(event);
1356 resend_event_window = 0;
1362 // if(done) completion_lock->unlock();
1365 if(debug) printf("BC_WindowBase::dispatch_event this=%p %d\n", this, __LINE__);
1369 int BC_WindowBase::dispatch_expose_event()
1372 for(int i = 0; i < subwindows->total && !result; i++)
1374 result = subwindows->values[i]->dispatch_expose_event();
1377 // Propagate to user
1378 if(!result) expose_event();
1382 int BC_WindowBase::dispatch_resize_event(int w, int h)
1384 // Can't store new w and h until the event is handles
1385 // because bcfilebox depends on the old w and h to
1386 // reposition widgets.
1387 if( window_type == MAIN_WINDOW ) {
1392 pixmap = new BC_Pixmap(this, w, h);
1393 clear_box(0, 0, w, h);
1396 // Propagate to subwindows
1397 for(int i = 0; i < subwindows->total; i++) {
1398 subwindows->values[i]->dispatch_resize_event(w, h);
1401 // Propagate to user
1404 if( window_type == MAIN_WINDOW ) {
1413 int BC_WindowBase::dispatch_flash()
1416 for(int i = 0; i < subwindows->total; i++)
1417 subwindows->values[i]->dispatch_flash();
1421 int BC_WindowBase::dispatch_translation_event()
1423 translation_events = 0;
1424 if(window_type == MAIN_WINDOW)
1428 x = last_translate_x;
1429 y = last_translate_y;
1430 // Correct for window manager offsets
1435 for(int i = 0; i < subwindows->total; i++)
1437 subwindows->values[i]->dispatch_translation_event();
1440 translation_event();
1444 int BC_WindowBase::dispatch_motion_event()
1449 if(top_level == this)
1452 event_win = last_motion_win;
1453 get_key_masks(last_motion_state);
1456 if(get_button_down() && !active_menubar && !active_popup_menu)
1460 cursor_x = last_motion_x;
1461 cursor_y = last_motion_y;
1462 result = dispatch_drag_motion();
1466 (last_motion_x < drag_x1 || last_motion_x >= drag_x2 ||
1467 last_motion_y < drag_y1 || last_motion_y >= drag_y2))
1472 result = dispatch_drag_start();
1476 cursor_x = last_motion_x;
1477 cursor_y = last_motion_y;
1479 // printf("BC_WindowBase::dispatch_motion_event %d %p %p %p\n",
1482 // active_popup_menu,
1483 // active_subwindow);
1485 if(active_menubar && !result) result = active_menubar->dispatch_motion_event();
1486 if(active_popup_menu && !result) result = active_popup_menu->dispatch_motion_event();
1487 if(active_subwindow && !result) result = active_subwindow->dispatch_motion_event();
1490 // Dispatch in stacking order
1491 for(int i = subwindows->size() - 1; i >= 0 && !result; i--)
1493 result = subwindows->values[i]->dispatch_motion_event();
1496 if(!result) result = cursor_motion_event(); // give to user
1500 int BC_WindowBase::dispatch_keypress_event()
1503 if(top_level == this)
1505 if(active_subwindow) result = active_subwindow->dispatch_keypress_event();
1508 for(int i = 0; i < subwindows->total && !result; i++)
1510 result = subwindows->values[i]->dispatch_keypress_event();
1513 if(!result) result = keypress_event();
1518 int BC_WindowBase::dispatch_keyrelease_event()
1521 if(top_level == this)
1523 if(active_subwindow) result = active_subwindow->dispatch_keyrelease_event();
1526 for(int i = 0; i < subwindows->total && !result; i++)
1528 result = subwindows->values[i]->dispatch_keyrelease_event();
1531 if(!result) result = keyrelease_event();
1536 int BC_WindowBase::dispatch_focus_in()
1538 for(int i = 0; i < subwindows->total; i++)
1540 subwindows->values[i]->dispatch_focus_in();
1548 int BC_WindowBase::dispatch_focus_out()
1550 for(int i = 0; i < subwindows->total; i++)
1552 subwindows->values[i]->dispatch_focus_out();
1560 int BC_WindowBase::get_has_focus()
1562 return top_level->has_focus;
1565 int BC_WindowBase::get_deleting()
1567 if(is_deleting) return 1;
1568 if(parent_window && parent_window->get_deleting()) return 1;
1572 int BC_WindowBase::dispatch_button_press()
1577 if(top_level == this)
1579 if(active_menubar) result = active_menubar->dispatch_button_press();
1580 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_press();
1581 if(active_subwindow && !result) result = active_subwindow->dispatch_button_press();
1584 for(int i = 0; i < subwindows->total && !result; i++)
1586 result = subwindows->values[i]->dispatch_button_press();
1589 if(!result) result = button_press_event();
1595 int BC_WindowBase::dispatch_button_release()
1598 if(top_level == this)
1600 if(active_menubar) result = active_menubar->dispatch_button_release();
1601 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_release();
1602 if(active_subwindow && !result) result = active_subwindow->dispatch_button_release();
1603 if(!result && button_number != 4 && button_number != 5)
1604 result = dispatch_drag_stop();
1607 for(int i = 0; i < subwindows->total && !result; i++)
1609 result = subwindows->values[i]->dispatch_button_release();
1614 result = button_release_event();
1621 int BC_WindowBase::dispatch_repeat_event(int64_t duration)
1624 // all repeat event handlers get called and decide based on activity and duration
1625 // whether to respond
1626 for(int i = 0; i < subwindows->total; i++)
1628 subwindows->values[i]->dispatch_repeat_event(duration);
1632 repeat_event(duration);
1636 // Unlock next repeat signal
1637 if(window_type == MAIN_WINDOW)
1639 #ifdef SINGLE_THREAD
1640 BC_Display::display_global->unlock_repeaters(duration);
1642 for(int i = 0; i < repeaters.total; i++)
1644 if(repeaters.values[i]->delay == duration)
1646 repeaters.values[i]->repeat_lock->unlock();
1654 void BC_WindowBase::unhide_cursor()
1659 if(top_level->is_hourglass)
1660 set_cursor(HOURGLASS_CURSOR, 1, 0);
1662 set_cursor(current_cursor, 1, 0);
1664 cursor_timer->update();
1668 void BC_WindowBase::update_video_cursor()
1670 if(video_on && !is_transparent)
1672 if(cursor_timer->get_difference() > VIDEO_CURSOR_TIMEOUT && !is_transparent)
1675 set_cursor(TRANSPARENT_CURSOR, 1, 1);
1676 cursor_timer->update();
1681 cursor_timer->update();
1686 int BC_WindowBase::dispatch_cursor_leave()
1690 for(int i = 0; i < subwindows->total; i++)
1692 subwindows->values[i]->dispatch_cursor_leave();
1695 cursor_leave_event();
1699 int BC_WindowBase::dispatch_cursor_enter()
1705 if(active_menubar) result = active_menubar->dispatch_cursor_enter();
1706 if(!result && active_popup_menu) result = active_popup_menu->dispatch_cursor_enter();
1707 if(!result && active_subwindow) result = active_subwindow->dispatch_cursor_enter();
1709 for(int i = 0; !result && i < subwindows->total; i++)
1711 result = subwindows->values[i]->dispatch_cursor_enter();
1714 if(!result) result = cursor_enter_event();
1718 int BC_WindowBase::cursor_enter_event()
1723 int BC_WindowBase::cursor_leave_event()
1728 int BC_WindowBase::close_event()
1734 // *** CONTEXT_HELP ***
1735 // This basic implementation serves solely for context help.
1736 // We are handling Alt/H only. Any subclass requiring more sophisticated
1737 // processing of keystrokes has to provide its own overloaded handler.
1738 int BC_WindowBase::keypress_event()
1740 // printf("BC_WindowBase::keypress_event: %d\n", get_keypress());
1741 return context_help_check_and_show();
1744 // The stuff up to END_CONTEXT_HELP serves solely for context help
1745 void BC_WindowBase::context_help_set_keyword(const char *keyword)
1747 if (keyword) strcpy(context_help_keyword, keyword);
1750 const char *BC_WindowBase::context_help_get_keyword()
1752 // If we have context_help_keyword defined here, return it.
1753 // Otherwise recursively track widget hierarchy up to top_level
1754 // and return the nearest found nonempty keyword.
1755 // If nothing found, the special keyword "TOC" is returned.
1756 if (context_help_keyword[0] || this == top_level ||
1757 this == parent_window || ! parent_window) {
1758 if (! context_help_keyword[0] && this == top_level)
1759 context_help_set_keyword("TOC");
1760 return context_help_keyword;
1762 return parent_window->context_help_get_keyword();
1765 void BC_WindowBase::context_help_show(const char *keyword)
1767 char cmd[BCTEXTLEN];
1769 if (! keyword) return;
1771 sprintf(cmd, "\"%s/doc/ContextManual.pl\" \"%s\"", getenv("CIN_DAT"),
1773 // printf("BC_WindowBase::context_help_show(%s):\n%s\n", keyword, cmd);
1775 // ContextManual.pl starts browser in background, so system() should not block
1779 void BC_WindowBase::context_help_show()
1781 context_help_show(context_help_get_keyword());
1784 int BC_WindowBase::context_help_check_and_show(const char *keyword)
1786 if (! keyword) return 0;
1787 if (! keyword[0]) return 0;
1789 // We are handling Alt/H only
1790 if (get_keypress() != 'h' || ! alt_down()) return 0;
1792 // Restrict cursor location to that widget keystroke occured in
1793 if (! is_tooltip_event_win() || ! cursor_inside()) return 0;
1795 context_help_show(keyword);
1799 int BC_WindowBase::context_help_check_and_show()
1801 const char *keyword;
1803 // We are handling Alt/H only
1804 if (get_keypress() != 'h' || ! alt_down()) return 0;
1806 // Restrict cursor location, so any subwindow can define its own help keyword
1807 if (! is_tooltip_event_win() || ! cursor_inside()) return 0;
1809 // If a widget has not defined its own help keyword, the parent can provide it
1810 keyword = context_help_get_keyword();
1811 if (! keyword[0]) return 0;
1813 context_help_show(keyword);
1816 // *** END_CONTEXT_HELP ***
1818 int BC_WindowBase::dispatch_drag_start()
1821 if(active_menubar) result = active_menubar->dispatch_drag_start();
1822 if(!result && active_popup_menu) result = active_popup_menu->dispatch_drag_start();
1823 if(!result && active_subwindow) result = active_subwindow->dispatch_drag_start();
1825 for(int i = 0; i < subwindows->total && !result; i++)
1827 result = subwindows->values[i]->dispatch_drag_start();
1830 if(!result) result = is_dragging = drag_start_event();
1834 int BC_WindowBase::dispatch_drag_stop()
1838 for(int i = 0; i < subwindows->total && !result; i++)
1840 result = subwindows->values[i]->dispatch_drag_stop();
1843 if(is_dragging && !result)
1853 int BC_WindowBase::dispatch_drag_motion()
1856 for(int i = 0; i < subwindows->total && !result; i++)
1858 result = subwindows->values[i]->dispatch_drag_motion();
1861 if(is_dragging && !result)
1863 drag_motion_event();
1871 int BC_WindowBase::show_tooltip(const char *text, int x, int y, int w, int h)
1874 int forced = !text ? force_tooltip : 1;
1875 if( !text ) text = tooltip_text;
1876 if( !text || (!forced && !get_resources()->tooltips_enabled) ) {
1877 top_level->hide_tooltip();
1881 if(w < 0) w = get_text_width(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1882 if(h < 0) h = get_text_height(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1883 // default x,y (win relative)
1884 if( x < 0 ) x = get_w();
1885 if( y < 0 ) y = get_h();
1887 get_root_coordinates(x, y, &wx, &wy);
1888 // keep the tip inside the window/display
1889 int x0 = top_level->get_x(), x1 = x0 + top_level->get_w();
1890 int x2 = top_level->get_screen_x(0, -1) + top_level->get_screen_w(0, -1);
1891 if( x1 > x2 ) x1 = x2;
1892 if( wx < x0 ) wx = x0;
1893 if( wx >= (x1-=w) ) wx = x1;
1894 int y0 = top_level->get_y(), y1 = y0 + top_level->get_h();
1895 int y2 = top_level->get_root_h(0);
1896 if( y1 > y2 ) y1 = y2;
1897 if( wy < y0 ) wy = y0;
1898 if( wy >= (y1-=h) ) wy = y1;
1899 // avoid tip under cursor (flickers)
1901 get_abs_cursor(abs_x,abs_y, 0);
1902 if( wx < abs_x && abs_x < wx+w && wy < abs_y && abs_y < wy+h ) {
1903 if( wx-abs_x < wy-abs_y )
1910 tooltip_popup = new BC_Popup(top_level, wx, wy, w, h,
1911 get_resources()->tooltip_bg_color);
1914 tooltip_popup->reposition_window(wx, wy, w, h);
1917 tooltip_popup->flash();
1918 tooltip_popup->flush();
1922 int BC_WindowBase::hide_tooltip()
1925 for(int i = 0; i < subwindows->total; i++)
1927 subwindows->values[i]->hide_tooltip();
1933 delete tooltip_popup;
1939 const char *BC_WindowBase::get_tooltip()
1941 return tooltip_text;
1944 int BC_WindowBase::set_tooltip(const char *text)
1946 tooltip_text = text;
1948 // Update existing tooltip if it is visible
1952 tooltip_popup->flash();
1956 // signal the event handler to repeat
1957 int BC_WindowBase::set_repeat(int64_t duration)
1961 printf("BC_WindowBase::set_repeat duration=%jd\n", duration);
1964 if(window_type != MAIN_WINDOW) return top_level->set_repeat(duration);
1966 #ifdef SINGLE_THREAD
1967 BC_Display::display_global->set_repeat(this, duration);
1969 // test repeater database for duplicates
1970 for(int i = 0; i < repeaters.total; i++)
1973 if(repeaters.values[i]->delay == duration)
1975 repeaters.values[i]->start_repeating(this);
1980 BC_Repeater *repeater = new BC_Repeater(this, duration);
1981 repeater->initialize();
1982 repeaters.append(repeater);
1983 repeater->start_repeating();
1988 int BC_WindowBase::unset_repeat(int64_t duration)
1990 if(window_type != MAIN_WINDOW) return top_level->unset_repeat(duration);
1992 #ifdef SINGLE_THREAD
1993 BC_Display::display_global->unset_repeat(this, duration);
1995 for(int i = 0; i < repeaters.total; i++)
1997 if(repeaters.values[i]->delay == duration)
1999 repeaters.values[i]->stop_repeating();
2007 int BC_WindowBase::unset_all_repeaters()
2009 #ifdef SINGLE_THREAD
2010 BC_Display::display_global->unset_all_repeaters(this);
2012 for(int i = 0; i < repeaters.total; i++)
2014 repeaters.values[i]->stop_repeating();
2016 repeaters.remove_all_objects();
2021 // long BC_WindowBase::get_repeat_id()
2023 // return top_level->next_repeat_id++;
2026 XEvent *BC_WindowBase::new_xevent()
2028 XEvent *event = new XEvent;
2029 memset(event, 0, sizeof(*event));
2033 #ifndef SINGLE_THREAD
2034 int BC_WindowBase::arm_repeat(int64_t duration)
2036 XEvent *event = new_xevent();
2037 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
2038 ptr->type = ClientMessage;
2039 ptr->message_type = RepeaterXAtom;
2041 ptr->data.l[0] = duration;
2043 // Couldn't use XSendEvent since it locked up randomly.
2049 int BC_WindowBase::receive_custom_xatoms(xatom_event *event)
2054 int BC_WindowBase::send_custom_xatom(xatom_event *event)
2056 #ifndef SINGLE_THREAD
2057 XEvent *myevent = new_xevent();
2058 XClientMessageEvent *ptr = (XClientMessageEvent*)myevent;
2059 ptr->type = ClientMessage;
2060 ptr->message_type = event->message_type;
2061 ptr->format = event->format;
2062 ptr->data.l[0] = event->data.l[0];
2063 ptr->data.l[1] = event->data.l[1];
2064 ptr->data.l[2] = event->data.l[2];
2065 ptr->data.l[3] = event->data.l[3];
2066 ptr->data.l[4] = event->data.l[4];
2075 Atom BC_WindowBase::create_xatom(const char *atom_name)
2077 return XInternAtom(display, atom_name, False);
2080 int BC_WindowBase::get_atoms()
2082 SetDoneXAtom = XInternAtom(display, "BC_REPEAT_EVENT", False);
2083 RepeaterXAtom = XInternAtom(display, "BC_CLOSE_EVENT", False);
2084 DestroyAtom = XInternAtom(display, "BC_DESTROY_WINDOW", False);
2085 DelWinXAtom = XInternAtom(display, "WM_DELETE_WINDOW", False);
2086 if( (ProtoXAtom = XInternAtom(display, "WM_PROTOCOLS", False)) != 0 )
2087 XChangeProperty(display, win, ProtoXAtom, XA_ATOM, 32,
2088 PropModeReplace, (unsigned char *)&DelWinXAtom, True);
2094 void BC_WindowBase::init_cursors()
2096 arrow_cursor = XCreateFontCursor(display, XC_top_left_arrow);
2097 cross_cursor = XCreateFontCursor(display, XC_crosshair);
2098 ibeam_cursor = XCreateFontCursor(display, XC_xterm);
2099 vseparate_cursor = XCreateFontCursor(display, XC_sb_v_double_arrow);
2100 hseparate_cursor = XCreateFontCursor(display, XC_sb_h_double_arrow);
2101 move_cursor = XCreateFontCursor(display, XC_fleur);
2102 left_cursor = XCreateFontCursor(display, XC_sb_left_arrow);
2103 right_cursor = XCreateFontCursor(display, XC_sb_right_arrow);
2104 upright_arrow_cursor = XCreateFontCursor(display, XC_arrow);
2105 upleft_resize_cursor = XCreateFontCursor(display, XC_top_left_corner);
2106 upright_resize_cursor = XCreateFontCursor(display, XC_top_right_corner);
2107 downleft_resize_cursor = XCreateFontCursor(display, XC_bottom_left_corner);
2108 downright_resize_cursor = XCreateFontCursor(display, XC_bottom_right_corner);
2109 hourglass_cursor = XCreateFontCursor(display, XC_watch);
2110 grabbed_cursor = create_grab_cursor();
2112 static char cursor_data[] = { 0,0,0,0, 0,0,0,0 };
2113 Colormap colormap = DefaultColormap(display, screen);
2114 Pixmap pixmap_bottom = XCreateBitmapFromData(display,
2115 rootwin, cursor_data, 8, 8);
2116 XColor black, dummy;
2117 XAllocNamedColor(display, colormap, "black", &black, &dummy);
2118 transparent_cursor = XCreatePixmapCursor(display,
2119 pixmap_bottom, pixmap_bottom, &black, &black, 0, 0);
2120 // XDefineCursor(display, win, transparent_cursor);
2121 XFreePixmap(display, pixmap_bottom);
2124 int BC_WindowBase::evaluate_color_model(int client_byte_order, int server_byte_order, int depth)
2126 int color_model = BC_TRANSPARENCY;
2130 color_model = BC_RGB8;
2133 color_model = (server_byte_order == client_byte_order) ? BC_RGB565 : BC_BGR565;
2136 color_model = server_byte_order ? BC_BGR888 : BC_RGB888;
2139 color_model = server_byte_order ? BC_BGR8888 : BC_ARGB8888;
2145 int BC_WindowBase::init_colors()
2148 current_color_value = current_color_pixel = 0;
2150 // Get the real depth
2153 ximage = XCreateImage(top_level->display,
2154 top_level->vis, top_level->default_depth,
2155 ZPixmap, 0, data, 16, 16, 8, 0);
2156 bits_per_pixel = ximage->bits_per_pixel;
2157 XDestroyImage(ximage);
2159 color_model = evaluate_color_model(client_byte_order,
2162 // Get the color model
2167 cmap = XCreateColormap(display, rootwin, vis, AllocNone);
2168 create_private_colors();
2171 cmap = DefaultColormap(display, screen);
2172 create_shared_colors();
2175 allocate_color_table();
2179 //cmap = DefaultColormap(display, screen);
2180 cmap = XCreateColormap(display, rootwin, vis, AllocNone );
2186 int BC_WindowBase::create_private_colors()
2191 for(int i = 0; i < 255; i++)
2193 color = (i & 0xc0) << 16;
2194 color += (i & 0x38) << 10;
2195 color += (i & 0x7) << 5;
2196 color_table[i][0] = color;
2198 create_shared_colors(); // overwrite the necessary colors on the table
2203 int BC_WindowBase::create_color(int color)
2205 if(total_colors == 256)
2207 // replace the closest match with an exact match
2208 color_table[get_color_rgb8(color)][0] = color;
2212 // add the color to the table
2213 color_table[total_colors][0] = color;
2219 int BC_WindowBase::create_shared_colors()
2221 create_color(BLACK);
2222 create_color(WHITE);
2224 create_color(LTGREY);
2225 create_color(MEGREY);
2226 create_color(MDGREY);
2227 create_color(DKGREY);
2229 create_color(LTCYAN);
2230 create_color(MECYAN);
2231 create_color(MDCYAN);
2232 create_color(DKCYAN);
2234 create_color(LTGREEN);
2235 create_color(GREEN);
2236 create_color(DKGREEN);
2238 create_color(LTPINK);
2242 create_color(LTBLUE);
2244 create_color(DKBLUE);
2246 create_color(LTYELLOW);
2247 create_color(MEYELLOW);
2248 create_color(MDYELLOW);
2249 create_color(DKYELLOW);
2251 create_color(LTPURPLE);
2252 create_color(MEPURPLE);
2253 create_color(MDPURPLE);
2254 create_color(DKPURPLE);
2256 create_color(FGGREY);
2257 create_color(MNBLUE);
2258 create_color(ORANGE);
2259 create_color(FTGREY);
2264 Cursor BC_WindowBase::create_grab_cursor()
2266 int iw = 23, iw1 = iw-1, iw2 = iw/2;
2267 int ih = 23, ih1 = ih-1, ih2 = ih/2;
2268 VFrame grab(iw,ih,BC_RGB888);
2270 grab.set_pixel_color(RED); // fg
2271 grab.draw_smooth(iw2,0, iw1,0, iw1,ih2);
2272 grab.draw_smooth(iw1,ih2, iw1,ih1, iw2,ih1);
2273 grab.draw_smooth(iw2,ih1, 0,ih1, 0,ih2);
2274 grab.draw_smooth(0,ih2, 0,0, iw2,0);
2275 grab.set_pixel_color(WHITE); // bg
2276 grab.draw_line(0,ih2, iw2-2,ih2);
2277 grab.draw_line(iw2+2,ih2, iw1,ih2);
2278 grab.draw_line(iw2,0, iw2,ih2-2);
2279 grab.draw_line(iw2,ih2+2, iw2,ih1);
2281 int bpl = (iw+7)/8, isz = bpl * ih;
2282 char img[isz]; memset(img, 0, isz);
2283 char msk[isz]; memset(msk, 0, isz);
2284 unsigned char **rows = grab.get_rows();
2285 for( int iy=0; iy<ih; ++iy ) {
2286 char *op = img + iy*bpl;
2287 char *mp = msk + iy*bpl;
2288 unsigned char *ip = rows[iy];
2289 for( int ix=0; ix<iw; ++ix,ip+=3 ) {
2290 if( ip[0] ) mp[ix>>3] |= (1<<(ix&7));
2291 if( !ip[1] ) op[ix>>3] |= (1<<(ix&7));
2294 unsigned long white_pix = WhitePixel(display, screen);
2295 unsigned long black_pix = BlackPixel(display, screen);
2296 Pixmap img_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2297 img, iw,ih, white_pix,black_pix, 1);
2298 Pixmap msk_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2299 msk, iw,ih, white_pix,black_pix, 1);
2302 fc.flags = bc.flags = DoRed | DoGreen | DoBlue;
2303 fc.red = 0xffff; fc.green = fc.blue = 0; // fg
2304 bc.red = 0xffff; bc.green = 0xffff; bc.blue = 0x0000; // bg
2305 Cursor cursor = XCreatePixmapCursor(display, img_xpm,msk_xpm, &fc,&bc, iw2,ih2);
2306 XFreePixmap(display, img_xpm);
2307 XFreePixmap(display, msk_xpm);
2311 int BC_WindowBase::allocate_color_table()
2313 int red, green, blue, color;
2316 for(int i = 0; i < total_colors; i++)
2318 color = color_table[i][0];
2319 red = (color & 0xFF0000) >> 16;
2320 green = (color & 0x00FF00) >> 8;
2321 blue = color & 0xFF;
2323 col.flags = DoRed | DoGreen | DoBlue;
2324 col.red = red<<8 | red;
2325 col.green = green<<8 | green;
2326 col.blue = blue<<8 | blue;
2328 XAllocColor(display, cmap, &col);
2329 color_table[i][1] = col.pixel;
2332 XInstallColormap(display, cmap);
2336 int BC_WindowBase::init_window_shape()
2338 if(bg_pixmap && bg_pixmap->use_alpha())
2340 XShapeCombineMask(top_level->display,
2341 this->win, ShapeBounding, 0, 0,
2342 bg_pixmap->get_alpha(), ShapeSet);
2348 int BC_WindowBase::init_gc()
2350 unsigned long gcmask;
2351 gcmask = GCFont | GCGraphicsExposures;
2354 gcvalues.font = mediumfont->fid; // set the font
2355 gcvalues.graphics_exposures = 0; // prevent expose events for every redraw
2356 gc = XCreateGC(display, rootwin, gcmask, &gcvalues);
2358 // gcmask = GCCapStyle | GCJoinStyle;
2359 // XGetGCValues(display, gc, gcmask, &gcvalues);
2360 // printf("BC_WindowBase::init_gc %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2364 int BC_WindowBase::init_fonts()
2366 if( !(smallfont = XLoadQueryFont(display, _(resources->small_font))) )
2367 if( !(smallfont = XLoadQueryFont(display, _(resources->small_font2))) )
2368 smallfont = XLoadQueryFont(display, "fixed");
2369 if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font))) )
2370 if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font2))) )
2371 mediumfont = XLoadQueryFont(display, "fixed");
2372 if( !(largefont = XLoadQueryFont(display, _(resources->large_font))) )
2373 if( !(largefont = XLoadQueryFont(display, _(resources->large_font2))) )
2374 largefont = XLoadQueryFont(display, "fixed");
2375 if( !(bigfont = XLoadQueryFont(display, _(resources->big_font))) )
2376 if( !(bigfont = XLoadQueryFont(display, _(resources->big_font2))) )
2377 bigfont = XLoadQueryFont(display, "fixed");
2379 if((clockfont = XLoadQueryFont(display, _(resources->clock_font))) == NULL)
2380 if((clockfont = XLoadQueryFont(display, _(resources->clock_font2))) == NULL)
2381 clockfont = XLoadQueryFont(display, "fixed");
2384 if(get_resources()->use_fontset)
2389 // FIXME: should check the m,d,n values
2390 smallfontset = XCreateFontSet(display, resources->small_fontset, &m, &n, &d);
2392 smallfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2393 mediumfontset = XCreateFontSet(display, resources->medium_fontset, &m, &n, &d);
2394 if( !mediumfontset )
2395 mediumfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2396 largefontset = XCreateFontSet(display, resources->large_fontset, &m, &n, &d);
2398 largefontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2399 bigfontset = XCreateFontSet(display, resources->big_fontset, &m, &n, &d);
2401 bigfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2402 clockfontset = XCreateFontSet(display, resources->clock_fontset, &m, &n, &d);
2404 clockfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2405 if(clockfontset && bigfontset && largefontset && mediumfontset && smallfontset) {
2406 curr_fontset = mediumfontset;
2407 get_resources()->use_fontset = 1;
2411 get_resources()->use_fontset = 0;
2418 void BC_WindowBase::init_xft()
2421 if( !get_resources()->use_xft ) return;
2422 // apparently, xft is not reentrant, more than this is needed
2423 static Mutex xft_init_lock("BC_WindowBase::xft_init_lock", 0);
2424 xft_init_lock.lock("BC_WindowBase::init_xft");
2425 if(!(smallfont_xft =
2426 (resources->small_font_xft[0] == '-' ?
2427 xftFontOpenXlfd(display, screen, resources->small_font_xft) :
2428 xftFontOpenName(display, screen, resources->small_font_xft))) )
2429 if(!(smallfont_xft =
2430 xftFontOpenXlfd(display, screen, resources->small_font_xft2)))
2431 smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2432 if(!(mediumfont_xft =
2433 (resources->medium_font_xft[0] == '-' ?
2434 xftFontOpenXlfd(display, screen, resources->medium_font_xft) :
2435 xftFontOpenName(display, screen, resources->medium_font_xft))) )
2436 if(!(mediumfont_xft =
2437 xftFontOpenXlfd(display, screen, resources->medium_font_xft2)))
2438 mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2439 if(!(largefont_xft =
2440 (resources->large_font_xft[0] == '-' ?
2441 xftFontOpenXlfd(display, screen, resources->large_font_xft) :
2442 xftFontOpenName(display, screen, resources->large_font_xft))) )
2443 if(!(largefont_xft =
2444 xftFontOpenXlfd(display, screen, resources->large_font_xft2)))
2445 largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2447 (resources->big_font_xft[0] == '-' ?
2448 xftFontOpenXlfd(display, screen, resources->big_font_xft) :
2449 xftFontOpenName(display, screen, resources->big_font_xft))) )
2451 xftFontOpenXlfd(display, screen, resources->big_font_xft2)))
2452 bigfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2453 if(!(clockfont_xft =
2454 (resources->clock_font_xft[0] == '-' ?
2455 xftFontOpenXlfd(display, screen, resources->clock_font_xft) :
2456 xftFontOpenName(display, screen, resources->clock_font_xft))) )
2457 clockfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2460 if(!(bold_smallfont_xft =
2461 (resources->small_b_font_xft[0] == '-' ?
2462 xftFontOpenXlfd(display, screen, resources->small_b_font_xft) :
2463 xftFontOpenName(display, screen, resources->small_b_font_xft))) )
2464 bold_smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2465 if(!(bold_mediumfont_xft =
2466 (resources->medium_b_font_xft[0] == '-' ?
2467 xftFontOpenXlfd(display, screen, resources->medium_b_font_xft) :
2468 xftFontOpenName(display, screen, resources->medium_b_font_xft))) )
2469 bold_mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2470 if(!(bold_largefont_xft =
2471 (resources->large_b_font_xft[0] == '-' ?
2472 xftFontOpenXlfd(display, screen, resources->large_b_font_xft) :
2473 xftFontOpenName(display, screen, resources->large_b_font_xft))) )
2474 bold_largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2476 if( !smallfont_xft || !mediumfont_xft || !largefont_xft || !bigfont_xft ||
2477 !bold_largefont_xft || !bold_mediumfont_xft || !bold_largefont_xft ||
2479 printf("BC_WindowBase::init_fonts: no xft fonts found:"
2480 " %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n",
2481 resources->small_font_xft, smallfont_xft,
2482 resources->medium_font_xft, mediumfont_xft,
2483 resources->large_font_xft, largefont_xft,
2484 resources->big_font_xft, bigfont_xft,
2485 resources->clock_font_xft, clockfont_xft,
2486 resources->small_b_font_xft, bold_smallfont_xft,
2487 resources->medium_b_font_xft, bold_mediumfont_xft,
2488 resources->large_b_font_xft, bold_largefont_xft);
2489 get_resources()->use_xft = 0;
2492 // _XftDisplayInfo needs a lock.
2493 xftDefaultHasRender(display);
2494 xft_init_lock.unlock();
2498 void BC_WindowBase::init_glyphs()
2500 // draw all ascii char glyphs
2501 // There are problems with some/my graphics boards/drivers
2502 // which cause some glyphs to be munged if draws occur while
2503 // the font is being loaded. This code fills the font caches
2504 // by drawing all the ascii glyphs before the system starts.
2505 // Not a fix, but much better than nothing.
2506 static int inited = 0;
2507 if( inited ) return;
2508 XGrabServer(display);
2511 int cur_font = current_font;
2512 // locale encodings, needed glyphs to be preloaded
2513 const char *text = _( // ascii 0x20...0x7e
2514 " !\"#$%&'()*+,-./0123456789:;<=>?"
2515 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
2516 "`abcdefghijklmnopqrstuvwxyz{|}~");
2517 for( int font=SMALLFONT; font<=LARGEFONT; ++font ) {
2519 draw_text(5,5, text);
2522 XUngrabServer(display);
2525 void BC_WindowBase::init_im()
2527 XIMStyles *xim_styles;
2530 if(!(input_method = XOpenIM(display, NULL, NULL, NULL)))
2532 printf("BC_WindowBase::init_im: Could not open input method.\n");
2533 XSetLocaleModifiers("@im=local");
2534 if(!(input_method = XOpenIM(display, NULL, NULL, NULL))) {
2535 printf("BC_WindowBase::init_im: Could not open input method local.\n");
2539 if(XGetIMValues(input_method, XNQueryInputStyle, &xim_styles, NULL) ||
2542 printf("BC_WindowBase::init_im: Input method doesn't support any styles.\n");
2543 XCloseIM(input_method);
2548 for(int z = 0; z < xim_styles->count_styles; z++)
2550 if(xim_styles->supported_styles[z] == (XIMPreeditNothing | XIMStatusNothing))
2552 xim_style = xim_styles->supported_styles[z];
2560 printf("BC_WindowBase::init_im: Input method doesn't support the style we need.\n");
2561 XCloseIM(input_method);
2565 input_context = XCreateIC(input_method, XNInputStyle, xim_style,
2566 XNClientWindow, win, XNFocusWindow, win, NULL);
2569 printf("BC_WindowBase::init_im: Failed to create input context.\n");
2570 XCloseIM(input_method);
2575 void BC_WindowBase::finit_im()
2577 if( input_context ) {
2578 XDestroyIC(input_context);
2581 if( input_method ) {
2582 XCloseIM(input_method);
2588 int BC_WindowBase::get_color(int64_t color)
2590 // return pixel of color
2591 // use this only for drawing subwindows not for bitmaps
2592 int i, test, difference;
2598 return get_color_rgb8(color);
2599 // test last color looked up
2600 if(current_color_value == color)
2601 return current_color_pixel;
2604 current_color_value = color;
2605 for(i = 0; i < total_colors; i++)
2607 if(color_table[i][0] == color)
2609 current_color_pixel = color_table[i][1];
2610 return current_color_pixel;
2614 // find nearest match
2615 difference = 0xFFFFFF;
2617 for(i = 0; i < total_colors; i++)
2619 test = abs((int)(color_table[i][0] - color));
2621 if(test < difference)
2623 current_color_pixel = color_table[i][1];
2627 return current_color_pixel;
2630 return get_color_rgb16(color);
2633 return get_color_bgr16(color);
2637 return client_byte_order == server_byte_order ?
2638 color : get_color_bgr24(color);
2646 int BC_WindowBase::get_color_rgb8(int color)
2650 pixel = (color & 0xc00000) >> 16;
2651 pixel += (color & 0xe000) >> 10;
2652 pixel += (color & 0xe0) >> 5;
2656 int64_t BC_WindowBase::get_color_rgb16(int color)
2659 result = (color & 0xf80000) >> 8;
2660 result += (color & 0xfc00) >> 5;
2661 result += (color & 0xf8) >> 3;
2666 int64_t BC_WindowBase::get_color_bgr16(int color)
2669 result = (color & 0xf80000) >> 19;
2670 result += (color & 0xfc00) >> 5;
2671 result += (color & 0xf8) << 8;
2676 int64_t BC_WindowBase::get_color_bgr24(int color)
2679 result = (color & 0xff) << 16;
2680 result += (color & 0xff00);
2681 result += (color & 0xff0000) >> 16;
2685 void BC_WindowBase::start_video()
2687 cursor_timer->update();
2689 // set_color(BLACK);
2690 // draw_box(0, 0, get_w(), get_h());
2694 void BC_WindowBase::stop_video()
2702 int64_t BC_WindowBase::get_color()
2704 return top_level->current_color;
2707 void BC_WindowBase::set_color(int64_t color)
2709 top_level->current_color = color;
2710 XSetForeground(top_level->display,
2712 top_level->get_color(color));
2715 void BC_WindowBase::set_opaque()
2717 XSetFunction(top_level->display, top_level->gc, GXcopy);
2720 void BC_WindowBase::set_inverse()
2722 XSetFunction(top_level->display, top_level->gc, GXxor);
2725 void BC_WindowBase::set_line_width(int value)
2727 this->line_width = value;
2728 XSetLineAttributes(top_level->display, top_level->gc, value, /* line_width */
2729 line_dashes == 0 ? LineSolid : LineOnOffDash, /* line_style */
2730 line_dashes == 0 ? CapRound : CapNotLast, /* cap_style */
2731 JoinMiter); /* join_style */
2733 if(line_dashes > 0) {
2734 const char dashes = line_dashes;
2735 XSetDashes(top_level->display, top_level->gc, 0, &dashes, 1);
2738 // XGCValues gcvalues;
2739 // unsigned long gcmask;
2740 // gcmask = GCCapStyle | GCJoinStyle;
2741 // XGetGCValues(top_level->display, top_level->gc, gcmask, &gcvalues);
2742 // printf("BC_WindowBase::set_line_width %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2745 void BC_WindowBase::set_line_dashes(int value)
2747 line_dashes = value;
2748 // call XSetLineAttributes
2749 set_line_width(line_width);
2753 Cursor BC_WindowBase::get_cursor_struct(int cursor)
2757 case ARROW_CURSOR: return top_level->arrow_cursor;
2758 case CROSS_CURSOR: return top_level->cross_cursor;
2759 case IBEAM_CURSOR: return top_level->ibeam_cursor;
2760 case VSEPARATE_CURSOR: return top_level->vseparate_cursor;
2761 case HSEPARATE_CURSOR: return top_level->hseparate_cursor;
2762 case MOVE_CURSOR: return top_level->move_cursor;
2763 case LEFT_CURSOR: return top_level->left_cursor;
2764 case RIGHT_CURSOR: return top_level->right_cursor;
2765 case UPRIGHT_ARROW_CURSOR: return top_level->upright_arrow_cursor;
2766 case UPLEFT_RESIZE: return top_level->upleft_resize_cursor;
2767 case UPRIGHT_RESIZE: return top_level->upright_resize_cursor;
2768 case DOWNLEFT_RESIZE: return top_level->downleft_resize_cursor;
2769 case DOWNRIGHT_RESIZE: return top_level->downright_resize_cursor;
2770 case HOURGLASS_CURSOR: return top_level->hourglass_cursor;
2771 case TRANSPARENT_CURSOR: return top_level->transparent_cursor;
2772 case GRABBED_CURSOR: return top_level->grabbed_cursor;
2777 void BC_WindowBase::set_cursor(int cursor, int override, int flush)
2779 // inherit cursor from parent
2782 XUndefineCursor(top_level->display, win);
2783 current_cursor = cursor;
2786 // don't change cursor if overridden
2787 if((!top_level->is_hourglass && !is_transparent) ||
2790 XDefineCursor(top_level->display, win, get_cursor_struct(cursor));
2791 if(flush) this->flush();
2794 if(!override) current_cursor = cursor;
2797 void BC_WindowBase::set_x_cursor(int cursor)
2799 temp_cursor = XCreateFontCursor(top_level->display, cursor);
2800 XDefineCursor(top_level->display, win, temp_cursor);
2801 current_cursor = cursor;
2805 int BC_WindowBase::get_cursor()
2807 return current_cursor;
2810 void BC_WindowBase::start_hourglass()
2812 top_level->start_hourglass_recursive();
2816 void BC_WindowBase::stop_hourglass()
2818 top_level->stop_hourglass_recursive();
2822 void BC_WindowBase::start_hourglass_recursive()
2824 if(this == top_level)
2832 set_cursor(HOURGLASS_CURSOR, 1, 0);
2833 for(int i = 0; i < subwindows->total; i++)
2835 subwindows->values[i]->start_hourglass_recursive();
2840 void BC_WindowBase::stop_hourglass_recursive()
2842 if(this == top_level)
2844 if(hourglass_total == 0) return;
2845 top_level->hourglass_total--;
2848 if(!top_level->hourglass_total)
2850 top_level->is_hourglass = 0;
2852 // Cause set_cursor to perform change
2854 set_cursor(current_cursor, 1, 0);
2856 for(int i = 0; i < subwindows->total; i++)
2858 subwindows->values[i]->stop_hourglass_recursive();
2866 XFontStruct* BC_WindowBase::get_font_struct(int font)
2868 // Clear out unrelated flags
2869 if(font & BOLDFACE) font ^= BOLDFACE;
2872 case SMALLFONT: return top_level->smallfont; break;
2873 case MEDIUMFONT: return top_level->mediumfont; break;
2874 case LARGEFONT: return top_level->largefont; break;
2875 case BIGFONT: return top_level->bigfont; break;
2876 case CLOCKFONT: return top_level->clockfont; break;
2881 XFontSet BC_WindowBase::get_fontset(int font)
2885 if(get_resources()->use_fontset)
2887 switch(font & 0xff) {
2888 case SMALLFONT: fs = top_level->smallfontset; break;
2889 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2890 case LARGEFONT: fs = top_level->largefontset; break;
2891 case BIGFONT: fs = top_level->bigfontset; break;
2892 case CLOCKFONT: fs = top_level->clockfontset; break;
2900 XftFont* BC_WindowBase::get_xft_struct(int font)
2903 case SMALLFONT: return (XftFont*)top_level->smallfont_xft;
2904 case MEDIUMFONT: return (XftFont*)top_level->mediumfont_xft;
2905 case LARGEFONT: return (XftFont*)top_level->largefont_xft;
2906 case BIGFONT: return (XftFont*)top_level->bigfont_xft;
2907 case CLOCKFONT: return (XftFont*)top_level->clockfont_xft;
2908 case MEDIUMFONT_3D: return (XftFont*)top_level->bold_mediumfont_xft;
2909 case SMALLFONT_3D: return (XftFont*)top_level->bold_smallfont_xft;
2910 case LARGEFONT_3D: return (XftFont*)top_level->bold_largefont_xft;
2918 int BC_WindowBase::get_current_font()
2920 return top_level->current_font;
2923 void BC_WindowBase::set_font(int font)
2925 top_level->current_font = font;
2928 if(get_resources()->use_xft) {}
2931 if(get_resources()->use_fontset) {
2935 if(get_font_struct(font))
2937 XSetFont(top_level->display, top_level->gc, get_font_struct(font)->fid);
2943 void BC_WindowBase::set_fontset(int font)
2947 if(get_resources()->use_fontset) {
2949 case SMALLFONT: fs = top_level->smallfontset; break;
2950 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2951 case LARGEFONT: fs = top_level->largefontset; break;
2952 case BIGFONT: fs = top_level->bigfontset; break;
2953 case CLOCKFONT: fs = top_level->clockfontset; break;
2961 XFontSet BC_WindowBase::get_curr_fontset(void)
2963 if(get_resources()->use_fontset)
2964 return curr_fontset;
2968 int BC_WindowBase::get_single_text_width(int font, const char *text, int length)
2971 if(get_resources()->use_xft && get_xft_struct(font))
2974 #ifdef X_HAVE_UTF8_STRING
2975 if(get_resources()->locale_utf8)
2977 xftTextExtentsUtf8(top_level->display,
2978 get_xft_struct(font),
2979 (const XftChar8 *)text,
2986 xftTextExtents8(top_level->display,
2987 get_xft_struct(font),
2988 (const XftChar8 *)text,
2992 return extents.xOff;
2996 if(get_resources()->use_fontset && top_level->get_fontset(font))
2997 return XmbTextEscapement(top_level->get_fontset(font), text, length);
2999 if(get_font_struct(font))
3000 return XTextWidth(get_font_struct(font), text, length);
3006 case MEDIUM_7SEGMENT:
3007 return get_resources()->medium_7segment[0]->get_w() * length;
3017 int BC_WindowBase::get_text_width(int font, const char *text, int length)
3019 int i, j, w = 0, line_w = 0;
3020 if(length < 0) length = strlen(text);
3022 for(i = 0, j = 0; i <= length; i++)
3027 line_w = get_single_text_width(font, &text[j], i - j);
3033 line_w = get_single_text_width(font, &text[j], length - j);
3035 if(line_w > w) w = line_w;
3038 if(i > length && w == 0)
3040 w = get_single_text_width(font, text, length);
3046 int BC_WindowBase::get_text_width(int font, const wchr_t *text, int length)
3049 if( length < 0 ) length = wstrlen(text);
3051 for( i=j=0; i<length && text[i]; ++i ) {
3052 if( text[i] != '\n' ) continue;
3054 int lw = get_single_text_width(font, &text[j], i-j);
3055 if( w < lw ) w = lw;
3060 int lw = get_single_text_width(font, &text[j], length-j);
3061 if( w < lw ) w = lw;
3067 int BC_WindowBase::get_text_ascent(int font)
3071 if( (fstruct = get_xft_struct(font)) != 0 )
3072 return fstruct->ascent;
3074 if(get_resources()->use_fontset && top_level->get_fontset(font))
3076 XFontSetExtents *extents;
3078 extents = XExtentsOfFontSet(top_level->get_fontset(font));
3079 return -extents->max_logical_extent.y;
3082 if(get_font_struct(font))
3083 return top_level->get_font_struct(font)->ascent;
3086 case MEDIUM_7SEGMENT:
3087 return get_resources()->medium_7segment[0]->get_h();
3092 int BC_WindowBase::get_text_descent(int font)
3096 if( (fstruct = get_xft_struct(font)) != 0 )
3097 return fstruct->descent;
3099 if(get_resources()->use_fontset && top_level->get_fontset(font)) {
3100 XFontSetExtents *extents;
3101 extents = XExtentsOfFontSet(top_level->get_fontset(font));
3102 return (extents->max_logical_extent.height
3103 + extents->max_logical_extent.y);
3106 if(get_font_struct(font))
3107 return top_level->get_font_struct(font)->descent;
3112 int BC_WindowBase::get_text_height(int font, const char *text)
3117 if( (fstruct = get_xft_struct(font)) != 0 )
3118 rowh = fstruct->height;
3121 rowh = get_text_ascent(font) + get_text_descent(font);
3123 if(!text) return rowh;
3125 // Add height of lines
3126 int h = 0, i, length = strlen(text);
3127 for(i = 0; i <= length; i++)
3138 // truncate the text with ... & return a new string
3139 char *BC_WindowBase::get_truncated_text(int font, const char *text, int max_w)
3141 char *result = cstrdup(text);
3142 int text_w = get_text_width(font, text);
3143 int ci = -1, len = strlen(text);
3144 if( text_w > max_w ) {
3145 // get center of string
3146 int cx = text_w/2, best = INT_MAX;
3147 for( int i=1; i<=len; ++i ) {
3148 int cw = get_text_width(font, text, i);
3149 if( abs(cw-cx) < abs(best-cx) ) {
3154 if( ci > 0 && ci < len-1 ) {
3155 // insert ... in the center
3156 result[ci-1] = result[ci] = result[ci+1] = '.';
3158 while( ci-2>=0 && ci+2<(int)strlen(result) &&
3159 get_text_width(font, result) > max_w ) {
3160 // take away a character from the longer side
3161 int left_w = get_text_width(font, result, ci-2);
3162 int right_w = get_text_width(font, result + ci+3);
3163 int i = left_w > right_w ? --ci-1 : ci+2;
3164 while( (result[i]=result[i+1])!=0 ) ++i;
3171 BC_Bitmap* BC_WindowBase::new_bitmap(int w, int h, int color_model)
3173 if(color_model < 0) color_model = top_level->get_color_model();
3174 return new BC_Bitmap(top_level, w, h, color_model);
3177 void BC_WindowBase::init_wait()
3179 #ifndef SINGLE_THREAD
3180 if(window_type != MAIN_WINDOW)
3181 top_level->init_wait();
3182 init_lock->lock("BC_WindowBase::init_wait");
3183 init_lock->unlock();
3187 int BC_WindowBase::accel_available(int color_model, int lock_it)
3189 if( window_type != MAIN_WINDOW )
3190 return top_level->accel_available(color_model, lock_it);
3192 lock_window("BC_WindowBase::accel_available");
3194 switch(color_model) {
3196 grab_port_id(color_model);
3200 grab_port_id(color_model);
3209 //printf("BC_WindowBase::accel_available %d %d\n", color_model, xvideo_port_id);
3210 return xvideo_port_id >= 0 ? 1 : 0;
3214 int BC_WindowBase::grab_port_id(int color_model)
3217 if( !get_resources()->use_xvideo || // disabled
3218 !get_resources()->use_shm ) // Only local server is fast enough.
3220 if( xvideo_port_id >= 0 )
3221 return xvideo_port_id;
3223 unsigned int ver, rev, reqBase, eventBase, errorBase;
3224 if( Success != XvQueryExtension(display, // XV extension is available
3225 &ver, &rev, &reqBase, &eventBase, &errorBase) )
3228 // XV adaptors are available
3229 unsigned int numAdapt = 0;
3230 XvAdaptorInfo *info = 0;
3231 XvQueryAdaptors(display, DefaultRootWindow(display), &numAdapt, &info);
3235 // Translate from color_model to X color model
3236 int x_color_model = BC_CModels::bc_to_x(color_model);
3238 // Get adaptor with desired color model
3239 for( int i = 0; i < (int)numAdapt && xvideo_port_id == -1; i++) {
3240 if( !(info[i].type & XvImageMask) || !info[i].num_ports ) continue;
3241 // adaptor supports XvImages
3242 int numFormats = 0, numPorts = info[i].num_ports;
3243 XvImageFormatValues *formats =
3244 XvListImageFormats(display, info[i].base_id, &numFormats);
3245 if( !formats ) continue;
3247 for( int j=0; j<numFormats && xvideo_port_id<0; ++j ) {
3248 if( formats[j].id != x_color_model ) continue;
3249 // this adaptor supports the desired format, grab a port
3250 for( int k=0; k<numPorts; ++k ) {
3251 if( Success == XvGrabPort(top_level->display,
3252 info[i].base_id+k, CurrentTime) ) {
3253 //printf("BC_WindowBase::grab_port_id %llx\n", info[i].base_id);
3254 xvideo_port_id = info[i].base_id + k;
3262 XvFreeAdaptorInfo(info);
3263 return xvideo_port_id;
3270 int BC_WindowBase::show_window(int flush)
3272 for(int i = 0; i < subwindows->size(); i++)
3274 subwindows->get(i)->show_window(0);
3277 XMapWindow(top_level->display, win);
3278 if(flush) XFlush(top_level->display);
3279 // XSync(top_level->display, 0);
3284 int BC_WindowBase::hide_window(int flush)
3286 for(int i = 0; i < subwindows->size(); i++)
3288 subwindows->get(i)->hide_window(0);
3291 XUnmapWindow(top_level->display, win);
3292 if(flush) this->flush();
3297 BC_MenuBar* BC_WindowBase::add_menubar(BC_MenuBar *menu_bar)
3299 subwindows->append((BC_SubWindow*)menu_bar);
3301 menu_bar->parent_window = this;
3302 menu_bar->top_level = this->top_level;
3303 menu_bar->initialize();
3307 BC_WindowBase* BC_WindowBase::add_popup(BC_WindowBase *window)
3309 //printf("BC_WindowBase::add_popup window=%p win=%p\n", window, window->win);
3310 if(this != top_level) return top_level->add_popup(window);
3311 popups.append(window);
3315 void BC_WindowBase::remove_popup(BC_WindowBase *window)
3317 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3318 if(this != top_level)
3319 top_level->remove_popup(window);
3321 popups.remove(window);
3322 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3326 BC_WindowBase* BC_WindowBase::add_subwindow(BC_WindowBase *subwindow)
3328 subwindows->append(subwindow);
3330 if(subwindow->bg_color == -1) subwindow->bg_color = this->bg_color;
3332 // parent window must be set before the subwindow initialization
3333 subwindow->parent_window = this;
3334 subwindow->top_level = this->top_level;
3336 // Execute derived initialization
3337 subwindow->initialize();
3342 BC_WindowBase* BC_WindowBase::add_tool(BC_WindowBase *subwindow)
3344 return add_subwindow(subwindow);
3347 int BC_WindowBase::flash(int x, int y, int w, int h, int flush)
3349 if( !top_level->flash_enabled ) return 0;
3350 //printf("BC_WindowBase::flash %d %d %d %d %d\n", __LINE__, w, h, this->w, this->h);
3352 XSetWindowBackgroundPixmap(top_level->display, win, pixmap->opaque_pixmap);
3355 XClearArea(top_level->display, win, x, y, w, h, 0);
3359 XClearWindow(top_level->display, win);
3367 int BC_WindowBase::flash(int flush)
3369 flash(-1, -1, -1, -1, flush);
3373 void BC_WindowBase::flush()
3375 //if(!get_window_lock())
3376 // printf("BC_WindowBase::flush %s not locked\n", top_level->title);
3377 // X gets hosed if Flush/Sync are not user locked (at libX11-1.1.5 / libxcb-1.1.91)
3378 // _XReply deadlocks in condition_wait waiting for xlib lock when waiters!=-1
3379 int locked = get_window_lock();
3380 if( !locked ) lock_window("BC_WindowBase::flush");
3381 XFlush(top_level->display);
3382 if( !locked ) unlock_window();
3385 void BC_WindowBase::sync_display()
3387 int locked = get_window_lock();
3388 if( !locked ) lock_window("BC_WindowBase::sync_display");
3389 XSync(top_level->display, False);
3390 if( !locked ) unlock_window();
3393 int BC_WindowBase::get_window_lock()
3395 #ifdef SINGLE_THREAD
3396 return BC_Display::display_global->get_display_locked();
3398 return top_level->window_lock;
3402 int BC_WindowBase::lock_window(const char *location)
3404 if(top_level && top_level != this)
3406 top_level->lock_window(location);
3411 SET_LOCK(this, title, location);
3412 #ifdef SINGLE_THREAD
3413 BC_Display::lock_display(location);
3415 XLockDisplay(top_level->display);
3416 top_level->display_lock_owner = pthread_self();
3419 ++top_level->window_lock;
3423 printf("BC_WindowBase::lock_window top_level NULL\n");
3428 int BC_WindowBase::unlock_window()
3430 if(top_level && top_level != this)
3432 top_level->unlock_window();
3438 if( !top_level->window_lock ) {
3439 printf("BC_WindowBase::unlock_window %s not locked\n", title);
3442 if( top_level->window_lock > 0 )
3443 if( --top_level->window_lock == 0 )
3444 top_level->display_lock_owner = 0;
3445 #ifdef SINGLE_THREAD
3446 BC_Display::unlock_display();
3448 XUnlockDisplay(top_level->display);
3453 printf("BC_WindowBase::unlock_window top_level NULL\n");
3458 int BC_WindowBase::break_lock()
3460 if( !top_level ) return 0;
3461 if( top_level != this ) return top_level->break_lock();
3462 if( top_level->display_lock_owner != pthread_self() ) return 0;
3463 if( top_level->window_lock != 1 ) return 0;
3466 display_lock_owner = 0;
3467 #ifdef SINGLE_THREAD
3468 BC_Display::unlock_display();
3470 XUnlockDisplay(display);
3475 void BC_WindowBase::set_done(int return_value)
3477 if(done_set) return;
3479 if(window_type != MAIN_WINDOW)
3480 top_level->set_done(return_value);
3483 #ifdef SINGLE_THREAD
3484 this->return_value = return_value;
3485 BC_Display::display_global->arm_completion(this);
3486 completion_lock->unlock();
3487 #else // SINGLE_THREAD
3489 if( !event_thread ) return;
3490 XEvent *event = new_xevent();
3491 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
3492 event->type = ClientMessage;
3493 ptr->message_type = SetDoneXAtom;
3495 this->return_value = return_value;
3496 // May lock up here because XSendEvent doesn't work too well
3497 // asynchronous with XNextEvent.
3498 // This causes BC_WindowEvents to forward a copy of the event to run_window where
3500 // Deletion of event_thread is done at the end of BC_WindowBase::run_window() - by calling the destructor
3506 void BC_WindowBase::close(int return_value)
3508 hide_window(); flush();
3509 set_done(return_value);
3512 int BC_WindowBase::grab(BC_WindowBase *window)
3515 BC_WindowBase *grab_window = window->active_grab;
3517 int locked = get_window_lock();
3518 if( locked ) unlock_window();
3519 grab_window->lock_window("BC_WindowBase::grab(BC_WindowBase");
3520 grab_window->handle_ungrab();
3521 grab_window->unlock_window();
3522 if( locked ) lock_window("BC_WindowBase::grab(BC_WindowBase");
3524 window->grab_lock->lock("BC_WindowBase::grab");
3525 if( !window->active_grab ) {
3526 window->active_grab = this;
3527 this->grab_active = window;
3530 window->grab_lock->unlock();
3533 int BC_WindowBase::ungrab(BC_WindowBase *window)
3536 window->grab_lock->lock("BC_WindowBase::ungrab");
3537 if( this == window->active_grab ) {
3538 window->active_grab = 0;
3539 this->grab_active = 0;
3542 window->grab_lock->unlock();
3545 int BC_WindowBase::grab_event_count()
3548 #ifndef SINGLE_THREAD
3549 result = grab_active->get_event_count();
3553 int BC_WindowBase::grab_buttons()
3555 XSync(top_level->display, False);
3556 if( XGrabButton(top_level->display, AnyButton, AnyModifier,
3557 top_level->rootwin, True, ButtonPressMask | ButtonReleaseMask,
3558 GrabModeAsync, GrabModeSync, None, None) == GrabSuccess ) {
3559 set_active_subwindow(this);
3564 void BC_WindowBase::ungrab_buttons()
3566 XUngrabButton(top_level->display, AnyButton, AnyModifier, top_level->rootwin);
3567 set_active_subwindow(0);
3570 void BC_WindowBase::grab_cursor()
3572 Cursor cursor_grab = get_cursor_struct(GRABBED_CURSOR);
3573 XGrabPointer(top_level->display, top_level->rootwin, True,
3574 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
3575 GrabModeAsync, GrabModeAsync, None, cursor_grab, CurrentTime);
3577 void BC_WindowBase::ungrab_cursor()
3579 XUngrabPointer(top_level->display, CurrentTime);
3583 // WidthOfScreen/HeightOfScreen of XDefaultScreenOfDisplay
3584 // this is the bounding box of all the screens
3586 int BC_WindowBase::get_root_w(int lock_display)
3588 if(lock_display) lock_window("BC_WindowBase::get_root_w");
3589 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3590 int result = WidthOfScreen(def_screen);
3591 if(lock_display) unlock_window();
3595 int BC_WindowBase::get_root_h(int lock_display)
3597 if(lock_display) lock_window("BC_WindowBase::get_root_h");
3598 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3599 int result = HeightOfScreen(def_screen);
3600 if(lock_display) unlock_window();
3604 XineramaScreenInfo *
3605 BC_WindowBase::get_xinerama_info(int screen)
3607 if( !xinerama_info || !xinerama_screens ) return 0;
3609 for( int i=0; i<xinerama_screens; ++i )
3610 if( xinerama_info[i].screen_number == screen )
3611 return &xinerama_info[i];
3614 int top_x = get_x(), top_y = get_y();
3615 if( BC_DisplayInfo::left_border >= 0 ) top_x += BC_DisplayInfo::left_border;
3616 if( BC_DisplayInfo::top_border >= 0 ) top_y += BC_DisplayInfo::top_border;
3617 for( int i=0; i<xinerama_screens; ++i ) {
3618 int scr_y = top_y - xinerama_info[i].y_org;
3619 if( scr_y < 0 || scr_y >= xinerama_info[i].height ) continue;
3620 int scr_x = top_x - xinerama_info[i].x_org;
3621 if( scr_x >= 0 && scr_x < xinerama_info[i].width )
3622 return &xinerama_info[i];
3627 void BC_WindowBase::get_fullscreen_geometry(int &wx, int &wy, int &ww, int &wh)
3629 XineramaScreenInfo *info = top_level->get_xinerama_info(-1);
3631 wx = info->x_org; wy = info->y_org;
3632 ww = info->width; wh = info->height;
3635 wx = get_screen_x(0, -1);
3636 wy = get_screen_y(0, -1);
3637 int scr_w0 = get_screen_w(0, 0);
3638 int root_w = get_root_w(0);
3639 int root_h = get_root_h(0);
3640 if( root_w > scr_w0 ) { // multi-headed
3641 if( wx >= scr_w0 ) {
3642 // assumes right side is the big one
3643 ww = root_w - scr_w0;
3647 // use same aspect ratio to compute left height
3649 wh = (w*root_h) / (root_w-scr_w0);
3659 int BC_WindowBase::get_screen_x(int lock_display, int screen)
3662 if(lock_display) lock_window("BC_WindowBase::get_screen_x");
3663 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3666 int root_w = get_root_w(0);
3667 int root_h = get_root_h(0);
3668 // Shift X based on position of current window if dual head
3669 if( (float)root_w/root_h > 1.8 ) {
3670 root_w = get_screen_w(0, 0);
3671 if( top_level->get_x() >= root_w )
3676 result = info->x_org;
3677 if(lock_display) unlock_window();
3681 int BC_WindowBase::get_screen_y(int lock_display, int screen)
3683 if(lock_display) lock_window("BC_WindowBase::get_screen_y");
3684 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3685 int result = !info ? 0 : info->y_org;
3686 if(lock_display) unlock_window();
3690 int BC_WindowBase::get_screen_w(int lock_display, int screen)
3693 if(lock_display) lock_window("BC_WindowBase::get_screen_w");
3694 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3696 int width = get_root_w(0);
3697 int height = get_root_h(0);
3698 if( (float)width/height > 1.8 ) {
3699 // If dual head, the screen width is > 16x9
3700 // but we only want to fill one screen
3701 // this code assumes the "big" screen is on the right
3702 int scr_w0 = width / 2;
3704 case 600: scr_w0 = 800; break;
3705 case 720: scr_w0 = 1280; break;
3706 case 1024: scr_w0 = 1280; break;
3707 case 1200: scr_w0 = 1600; break;
3708 case 1080: scr_w0 = 1920; break;
3710 int scr_w1 = width - scr_w0;
3711 result = screen > 0 ? scr_w1 :
3712 screen == 0 ? scr_w0 :
3713 top_level->get_x() < scr_w0 ? scr_w0 : scr_w1;
3719 result = info->width;
3720 if(lock_display) unlock_window();
3724 int BC_WindowBase::get_screen_h(int lock_display, int screen)
3726 if(lock_display) lock_window("BC_WindowBase::get_screen_h");
3727 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3728 int result = info ? info->height : get_root_h(0);
3729 if(lock_display) unlock_window();
3733 // Bottom right corner
3734 int BC_WindowBase::get_x2()
3739 int BC_WindowBase::get_y2()
3744 int BC_WindowBase::get_video_on()
3749 int BC_WindowBase::get_hidden()
3751 return top_level->hidden;
3754 int BC_WindowBase::cursor_inside()
3756 return (top_level->cursor_x >= 0 &&
3757 top_level->cursor_y >= 0 &&
3758 top_level->cursor_x < w &&
3759 top_level->cursor_y < h);
3762 BC_WindowBase* BC_WindowBase::get_top_level()
3767 BC_WindowBase* BC_WindowBase::get_parent()
3769 return parent_window;
3772 int BC_WindowBase::get_color_model()
3774 return top_level->color_model;
3777 BC_Resources* BC_WindowBase::get_resources()
3779 return BC_WindowBase::resources;
3782 BC_Synchronous* BC_WindowBase::get_synchronous()
3784 return BC_WindowBase::resources->get_synchronous();
3787 int BC_WindowBase::get_bg_color()
3792 void BC_WindowBase::set_bg_color(int color)
3794 this->bg_color = color;
3797 BC_Pixmap* BC_WindowBase::get_bg_pixmap()
3802 void BC_WindowBase::set_active_subwindow(BC_WindowBase *subwindow)
3804 top_level->active_subwindow = subwindow;
3807 int BC_WindowBase::activate()
3812 int BC_WindowBase::deactivate()
3814 if(window_type == MAIN_WINDOW)
3816 if( top_level->active_menubar ) {
3817 top_level->active_menubar->deactivate();
3818 top_level->active_menubar = 0;
3820 if( top_level->active_popup_menu ) {
3821 top_level->active_popup_menu->deactivate();
3822 top_level->active_popup_menu = 0;
3824 if( top_level->active_subwindow ) {
3825 top_level->active_subwindow->deactivate();
3826 top_level->active_subwindow = 0;
3828 if( top_level->motion_events && top_level->last_motion_win == this->win )
3829 top_level->motion_events = 0;
3835 int BC_WindowBase::cycle_textboxes(int amount)
3838 BC_WindowBase *new_textbox = 0;
3842 BC_WindowBase *first_textbox = 0;
3843 find_next_textbox(&first_textbox, &new_textbox, result);
3844 if(!new_textbox) new_textbox = first_textbox;
3850 BC_WindowBase *last_textbox = 0;
3851 find_prev_textbox(&last_textbox, &new_textbox, result);
3852 if(!new_textbox) new_textbox = last_textbox;
3856 if(new_textbox != active_subwindow)
3859 new_textbox->activate();
3865 int BC_WindowBase::find_next_textbox(BC_WindowBase **first_textbox, BC_WindowBase **next_textbox, int &result)
3867 // Search subwindows for textbox
3868 for(int i = 0; i < subwindows->total && result < 2; i++)
3870 BC_WindowBase *test_subwindow = subwindows->values[i];
3871 test_subwindow->find_next_textbox(first_textbox, next_textbox, result);
3878 if(!*first_textbox) *first_textbox = this;
3882 if(top_level->active_subwindow == this)
3888 *next_textbox = this;
3895 int BC_WindowBase::find_prev_textbox(BC_WindowBase **last_textbox, BC_WindowBase **prev_textbox, int &result)
3901 if(!*last_textbox) *last_textbox = this;
3905 if(top_level->active_subwindow == this)
3911 *prev_textbox = this;
3916 // Search subwindows for textbox
3917 for(int i = subwindows->total - 1; i >= 0 && result < 2; i--)
3919 BC_WindowBase *test_subwindow = subwindows->values[i];
3920 test_subwindow->find_prev_textbox(last_textbox, prev_textbox, result);
3925 BC_Clipboard* BC_WindowBase::get_clipboard()
3927 #ifdef SINGLE_THREAD
3928 return BC_Display::display_global->clipboard;
3930 return top_level->clipboard;
3934 Atom BC_WindowBase::to_clipboard(const char *data, long len, int clipboard_num)
3936 return get_clipboard()->to_clipboard(this, data, len, clipboard_num);
3939 long BC_WindowBase::from_clipboard(char *data, long maxlen, int clipboard_num)
3941 return get_clipboard()->from_clipboard(data, maxlen, clipboard_num);
3944 long BC_WindowBase::clipboard_len(int clipboard_num)
3946 return get_clipboard()->clipboard_len(clipboard_num);
3949 int BC_WindowBase::do_selection_clear(Window win)
3951 top_level->event_win = win;
3952 return dispatch_selection_clear();
3955 int BC_WindowBase::dispatch_selection_clear()
3958 for( int i=0; i<subwindows->total && !result; ++i )
3959 result = subwindows->values[i]->dispatch_selection_clear();
3961 result = selection_clear_event();
3966 void BC_WindowBase::get_relative_cursor(int &x, int &y, int lock_window)
3968 int abs_x, abs_y, win_x, win_y;
3969 unsigned int temp_mask;
3972 if(lock_window) this->lock_window("BC_WindowBase::get_relative_cursor");
3973 XQueryPointer(top_level->display, top_level->win,
3974 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3977 XTranslateCoordinates(top_level->display, top_level->rootwin,
3978 win, abs_x, abs_y, &x, &y, &temp_win);
3979 if(lock_window) this->unlock_window();
3981 int BC_WindowBase::get_relative_cursor_x(int lock_window)
3984 get_relative_cursor(x, y, lock_window);
3987 int BC_WindowBase::get_relative_cursor_y(int lock_window)
3990 get_relative_cursor(x, y, lock_window);
3994 void BC_WindowBase::get_abs_cursor(int &abs_x, int &abs_y, int lock_window)
3997 unsigned int temp_mask;
4000 if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor");
4001 XQueryPointer(top_level->display, top_level->win,
4002 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
4004 if(lock_window) this->unlock_window();
4006 int BC_WindowBase::get_abs_cursor_x(int lock_window)
4009 get_abs_cursor(abs_x, abs_y, lock_window);
4012 int BC_WindowBase::get_abs_cursor_y(int lock_window)
4015 get_abs_cursor(abs_x, abs_y, lock_window);
4019 void BC_WindowBase::get_pop_cursor(int &px, int &py, int lock_window)
4021 int xmargin = xS(100), ymargin = yS(100);
4022 get_abs_cursor(px, py, lock_window);
4023 if( px < xmargin ) px = xmargin;
4024 if( py < ymargin ) py = ymargin;
4025 int wd = get_screen_x(lock_window,-1) + get_screen_w(lock_window,-1) - xmargin;
4026 if( px > wd ) px = wd;
4027 int ht = get_screen_y(lock_window,-1) + get_screen_h(lock_window,-1) - ymargin;
4028 if( py > ht ) py = ht;
4030 int BC_WindowBase::get_pop_cursor_x(int lock_window)
4033 get_pop_cursor(px, py, lock_window);
4036 int BC_WindowBase::get_pop_cursor_y(int lock_window)
4039 get_pop_cursor(px, py, lock_window);
4043 int BC_WindowBase::match_window(Window win)
4045 if (this->win == win) return 1;
4047 for(int i = 0; i < subwindows->total; i++) {
4048 result = subwindows->values[i]->match_window(win);
4049 if (result) return result;
4055 int BC_WindowBase::get_cursor_over_window()
4057 int abs_x, abs_y, win_x, win_y;
4058 unsigned int mask_return;
4059 Window root_return, child_return;
4061 int ret = XQueryPointer(top_level->display, top_level->rootwin,
4062 &root_return, &child_return, &abs_x, &abs_y,
4063 &win_x, &win_y, &mask_return);
4064 if( ret && child_return == None ) ret = 0;
4065 if( ret && win != child_return )
4066 ret = top_level->match_window(child_return);
4067 // query pointer can return a window manager window with this top_level as a child
4068 // for kde this can be two levels deep
4069 unsigned int nchildren_return = 0;
4070 Window parent_return, *children_return = 0;
4071 Window top_win = top_level->win;
4072 while( !ret && top_win != top_level->rootwin && top_win != root_return &&
4073 XQueryTree(top_level->display, top_win, &root_return,
4074 &parent_return, &children_return, &nchildren_return) ) {
4075 if( children_return ) XFree(children_return);
4076 if( (top_win=parent_return) == child_return ) ret = 1;
4081 int BC_WindowBase::cursor_above()
4084 get_relative_cursor(rx, ry);
4085 return rx < 0 || rx >= get_w() ||
4086 ry < 0 || ry >= get_h() ? 0 : 1;
4089 int BC_WindowBase::get_drag_x()
4091 return top_level->drag_x;
4094 int BC_WindowBase::get_drag_y()
4096 return top_level->drag_y;
4099 int BC_WindowBase::get_cursor_x()
4101 return top_level->cursor_x;
4104 int BC_WindowBase::get_cursor_y()
4106 return top_level->cursor_y;
4109 int BC_WindowBase::dump_windows()
4111 printf("\tBC_WindowBase::dump_windows window=%p win=%p '%s', %dx%d+%d+%d %s\n",
4112 this, (void*)this->win, title, w,h,x,y, typeid(*this).name());
4113 for(int i = 0; i < subwindows->size(); i++)
4114 subwindows->get(i)->dump_windows();
4115 for(int i = 0; i < popups.size(); i++) {
4116 BC_WindowBase *p = popups[i];
4117 printf("\tBC_WindowBase::dump_windows popup=%p win=%p '%s', %dx%d+%d+%d %s\n",
4118 p, (void*)p->win, p->title, p->w,p->h,p->x,p->y, typeid(*p).name());
4123 int BC_WindowBase::is_event_win()
4125 return this->win == top_level->event_win;
4128 int BC_WindowBase::is_tooltip_event_win()
4130 return this->win == top_level->event_win ||
4131 tooltip_popup && tooltip_popup->win == top_level->event_win;
4134 void BC_WindowBase::set_dragging(int value)
4136 is_dragging = value;
4139 int BC_WindowBase::get_dragging()
4144 int BC_WindowBase::get_buttonpress()
4146 return top_level->button_number;
4149 int BC_WindowBase::get_button_down()
4151 return top_level->button_down;
4154 int BC_WindowBase::alt_down()
4156 return top_level->alt_mask;
4159 int BC_WindowBase::shift_down()
4161 return top_level->shift_mask;
4164 int BC_WindowBase::ctrl_down()
4166 return top_level->ctrl_mask;
4169 wchr_t* BC_WindowBase::get_wkeystring(int *length)
4172 *length = top_level->wkey_string_length;
4173 return top_level->wkey_string;
4176 #ifdef X_HAVE_UTF8_STRING
4177 char* BC_WindowBase::get_keypress_utf8()
4179 return top_level->key_pressed_utf8;
4184 int BC_WindowBase::get_keypress()
4186 return top_level->key_pressed;
4189 int BC_WindowBase::get_double_click()
4191 return top_level->double_click;
4194 int BC_WindowBase::get_triple_click()
4196 return top_level->triple_click;
4199 int BC_WindowBase::get_bgcolor()
4204 int BC_WindowBase::resize_window(int w, int h)
4206 if(this->w == w && this->h == h) return 0;
4208 if(window_type == MAIN_WINDOW && !allow_resize)
4210 XSizeHints size_hints;
4211 size_hints.flags = PSize | PMinSize | PMaxSize;
4212 size_hints.width = w;
4213 size_hints.height = h;
4214 size_hints.min_width = w;
4215 size_hints.max_width = w;
4216 size_hints.min_height = h;
4217 size_hints.max_height = h;
4218 if( this->x > -BC_INFINITY && this->x < BC_INFINITY ) {
4219 size_hints.flags |= PPosition;
4220 size_hints.x = this->x;
4221 size_hints.y = this->y;
4223 XSetNormalHints(top_level->display, win, &size_hints);
4225 XResizeWindow(top_level->display, win, w, h);
4230 pixmap = new BC_Pixmap(this, w, h);
4232 // Propagate to menubar
4233 for(int i = 0; i < subwindows->total; i++)
4235 subwindows->values[i]->dispatch_resize_event(w, h);
4238 draw_background(0, 0, w, h);
4239 if(top_level == this && get_resources()->recursive_resizing)
4240 resize_history.append(new BC_ResizeCall(w, h));
4244 // The only way for resize events to be propagated is by updating the internal w and h
4245 int BC_WindowBase::resize_event(int w, int h)
4247 if(window_type == MAIN_WINDOW)
4255 int BC_WindowBase::reposition_window(int x, int y)
4257 reposition_window(x, y, -1, -1);
4262 int BC_WindowBase::reposition_window(int x, int y, int w, int h)
4266 // Some tools set their own dimensions before calling this, causing the
4267 // resize check to skip.
4271 if(w > 0 && w != this->w)
4277 if(h > 0 && h != this->h)
4283 //printf("BC_WindowBase::reposition_window %d %d %d\n", translation_count, x_correction, y_correction);
4286 printf("BC_WindowBase::reposition_window this->w == %d\n", this->w);
4288 printf("BC_WindowBase::reposition_window this->h == %d\n", this->h);
4290 if(translation_count && window_type == MAIN_WINDOW)
4292 // KDE shifts window right and down.
4293 // FVWM leaves window alone and adds border around it.
4294 XMoveResizeWindow(top_level->display, win,
4295 x - BC_DisplayInfo::auto_reposition_x,
4296 y - BC_DisplayInfo::auto_reposition_y,
4301 XMoveResizeWindow(top_level->display, win, x, y,
4308 pixmap = new BC_Pixmap(this, this->w, this->h);
4309 clear_box(0,0, this->w, this->h);
4310 // Propagate to menubar
4311 for(int i = 0; i < subwindows->total; i++)
4313 subwindows->values[i]->dispatch_resize_event(this->w, this->h);
4316 // draw_background(0, 0, w, h);
4322 int BC_WindowBase::reposition_window_relative(int dx, int dy, int w, int h)
4324 return reposition_window(get_x()+dx, get_y()+dy, w, h);
4327 int BC_WindowBase::reposition_window_relative(int dx, int dy)
4329 return reposition_window_relative(dx, dy, -1, -1);
4332 void BC_WindowBase::set_tooltips(int v)
4334 get_resources()->tooltips_enabled = v;
4337 void BC_WindowBase::set_force_tooltip(int v)
4342 int BC_WindowBase::raise_window(int do_flush)
4344 if( hidden ) return 1;
4345 if( wait_viewable(500) ) return 1;
4346 XRaiseWindow(top_level->display, win);
4347 if(do_flush) XFlush(top_level->display);
4351 int BC_WindowBase::lower_window(int do_flush)
4353 XLowerWindow(top_level->display, win);
4354 if(do_flush) XFlush(top_level->display);
4358 void BC_WindowBase::set_background(VFrame *bitmap)
4360 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
4362 bg_pixmap = new BC_Pixmap(this, bitmap, PIXMAP_OPAQUE);
4363 shared_bg_pixmap = 0;
4364 draw_background(0, 0, w, h);
4367 void BC_WindowBase::put_title(const char *text)
4369 char *cp = this->title, *ep = cp+sizeof(this->title)-1;
4370 for( const unsigned char *bp = (const unsigned char *)text; *bp && cp<ep; ++bp )
4371 *cp++ = *bp >= ' ' ? *bp : ' ';
4375 void BC_WindowBase::set_title(const char *text, int utf8)
4377 // utf8>0: wm + net_wm, utf8=0: wm only, utf<0: net_wm only
4379 const unsigned char *wm_title = (const unsigned char *)title;
4380 int title_len = strlen((const char *)title);
4382 Atom xa_wm_name = XA_WM_NAME;
4383 Atom xa_icon_name = XA_WM_ICON_NAME;
4384 Atom xa_string = XA_STRING;
4385 XChangeProperty(display, win, xa_wm_name, xa_string, 8,
4386 PropModeReplace, wm_title, title_len);
4387 XChangeProperty(display, win, xa_icon_name, xa_string, 8,
4388 PropModeReplace, wm_title, title_len);
4391 Atom xa_net_wm_name = XInternAtom(display, "_NET_WM_NAME", True);
4392 Atom xa_net_icon_name = XInternAtom(display, "_NET_WM_ICON_NAME", True);
4393 Atom xa_utf8_string = XInternAtom(display, "UTF8_STRING", True);
4394 XChangeProperty(display, win, xa_net_wm_name, xa_utf8_string, 8,
4395 PropModeReplace, wm_title, title_len);
4396 XChangeProperty(display, win, xa_net_icon_name, xa_utf8_string, 8,
4397 PropModeReplace, wm_title, title_len);
4403 void BC_WindowBase::set_net_icon(VFrame *data)
4405 int width = data->get_w(), height = data->get_h();
4406 int size = 2 + width * height;
4407 unsigned long *icon_data = new unsigned long[size];
4408 unsigned long *lp = icon_data;
4409 *lp++ = width; *lp++ = height;
4410 uint8_t **rows = data->get_rows();
4411 for( int y=0; y<height; ++y ) {
4412 unsigned *up = (unsigned *)rows[y];
4413 for( int x=0; x<width; ++x )
4414 *lp++ = *(unsigned *)up++;
4416 Atom NetWMIcon = XInternAtom(display, "_NET_WM_ICON", True);
4417 XChangeProperty(top_level->display, top_level->win, NetWMIcon,
4418 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)icon_data, size);
4419 delete [] icon_data;
4422 const char *BC_WindowBase::get_title()
4427 int BC_WindowBase::get_toggle_value()
4429 return toggle_value;
4432 int BC_WindowBase::get_toggle_drag()
4437 int BC_WindowBase::set_icon(VFrame *data)
4439 if(icon_pixmap) delete icon_pixmap;
4440 icon_pixmap = new BC_Pixmap(top_level, data, PIXMAP_ALPHA, 1);
4442 if(icon_window) delete icon_window;
4443 icon_window = new BC_Popup(this, 0, 0,
4444 icon_pixmap->get_w(), icon_pixmap->get_h(),
4445 -1, 1, // All windows are hidden initially
4448 XWMHints wm_hints; memset(&wm_hints, 0, sizeof(wm_hints));
4449 wm_hints.flags = IconPixmapHint; // | IconMaskHint | IconWindowHint;
4450 wm_hints.icon_pixmap = icon_pixmap->get_pixmap();
4451 wm_hints.icon_mask = icon_pixmap->get_alpha();
4452 wm_hints.icon_window = icon_window->win;
4453 if( XGroupLeader ) {
4454 wm_hints.flags |= WindowGroupHint;
4455 wm_hints.window_group = XGroupLeader;
4458 // for(int i = 0; i < 1000; i++)
4459 // printf("02x ", icon_pixmap->get_alpha()->get_row_pointers()[0][i]);
4462 XSetWMHints(top_level->display, top_level->win, &wm_hints);
4465 XSync(top_level->display, 0);
4469 void BC_WindowBase::init_resources(float scale)
4471 if( resources ) return;
4473 const char *env = getenv("BC_SCALE");
4474 if( env ) scale = atof(env);
4475 float x_scale = 1, y_scale = 1;
4477 BC_DisplayInfo info;
4479 int cins = info.xinerama_big_screen();
4480 if( !info.xinerama_geometry(cins, wx, wy, ww, wh) ) {
4481 int sh = ww * 9 / 16;
4482 int sw = wh * 16 / 9;
4483 if( sw < ww ) ww = sw;
4484 if( sh < wh ) wh = sh;
4485 if( (x_scale = ww/1920.) < 1 ) x_scale = 1;
4486 if( (y_scale = wh/1080.) < 1 ) y_scale = 1;
4490 x_scale = y_scale = scale;
4491 // constructor sets BC_WindowBase::resources
4492 new BC_Resources(x_scale, y_scale);
4494 void BC_WindowBase::finit_resources()
4496 delete resources; resources = 0;
4499 int BC_WindowBase::set_w(int w)
4505 int BC_WindowBase::set_h(int h)
4511 int BC_WindowBase::load_defaults(BC_Hash *defaults)
4513 char string[BCTEXTLEN];
4514 int newest_id = - 1;
4515 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4517 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4518 resources->filebox_history[i].path[0] = 0;
4519 defaults->get(string, resources->filebox_history[i].path);
4520 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4521 resources->filebox_history[i].id = defaults->get(string, resources->get_id());
4522 if(resources->filebox_history[i].id > newest_id)
4523 newest_id = resources->filebox_history[i].id;
4526 resources->filebox_id = newest_id + 1;
4527 resources->filebox_mode = defaults->get("FILEBOX_MODE", get_resources()->filebox_mode);
4528 resources->filebox_w = defaults->get("FILEBOX_W", get_resources()->filebox_w);
4529 resources->filebox_h = defaults->get("FILEBOX_H", get_resources()->filebox_h);
4530 resources->filebox_columntype[0] = defaults->get("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4531 resources->filebox_columntype[1] = defaults->get("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4532 resources->filebox_columntype[2] = defaults->get("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4533 resources->filebox_columntype[3] = defaults->get("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4534 resources->filebox_columnwidth[0] = defaults->get("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4535 resources->filebox_columnwidth[1] = defaults->get("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4536 resources->filebox_columnwidth[2] = defaults->get("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4537 resources->filebox_columnwidth[3] = defaults->get("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4538 resources->filebox_size_format = defaults->get("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4539 defaults->get("FILEBOX_FILTER", resources->filebox_filter);
4543 int BC_WindowBase::save_defaults(BC_Hash *defaults)
4545 char string[BCTEXTLEN];
4546 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4548 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4549 defaults->update(string, resources->filebox_history[i].path);
4550 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4551 defaults->update(string, resources->filebox_history[i].id);
4553 defaults->update("FILEBOX_MODE", resources->filebox_mode);
4554 defaults->update("FILEBOX_W", resources->filebox_w);
4555 defaults->update("FILEBOX_H", resources->filebox_h);
4556 defaults->update("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4557 defaults->update("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4558 defaults->update("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4559 defaults->update("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4560 defaults->update("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4561 defaults->update("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4562 defaults->update("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4563 defaults->update("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4564 defaults->update("FILEBOX_FILTER", resources->filebox_filter);
4565 defaults->update("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4571 // For some reason XTranslateCoordinates can take a long time to return.
4572 // We work around this by only calling it when the event windows are different.
4573 void BC_WindowBase::translate_coordinates(Window src_w, Window dest_w,
4574 int src_x, int src_y, int *dest_x_return, int *dest_y_return)
4581 *dest_x_return = src_x;
4582 *dest_y_return = src_y;
4586 XTranslateCoordinates(top_level->display, src_w, dest_w,
4587 src_x, src_y, dest_x_return, dest_y_return, &tempwin);
4588 //printf("BC_WindowBase::translate_coordinates 1 %lld\n", timer.get_difference());
4592 void BC_WindowBase::get_root_coordinates(int x, int y, int *abs_x, int *abs_y)
4594 translate_coordinates(win, top_level->rootwin, x, y, abs_x, abs_y);
4597 void BC_WindowBase::get_win_coordinates(int abs_x, int abs_y, int *x, int *y)
4599 translate_coordinates(top_level->rootwin, win, abs_x, abs_y, x, y);
4603 #ifdef HAVE_LIBXXF86VM
4604 void BC_WindowBase::closest_vm(int *vm, int *width, int *height)
4608 if(XF86VidModeQueryExtension(top_level->display,&foo,&bar)) {
4610 XF86VidModeModeInfo **vm_modelines;
4611 XF86VidModeGetAllModeLines(top_level->display,
4612 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4613 for( i = 0; i < vm_count; i++ ) {
4614 if( vm_modelines[i]->hdisplay < vm_modelines[*vm]->hdisplay &&
4615 vm_modelines[i]->hdisplay >= *width )
4618 display = top_level->display;
4619 if( vm_modelines[*vm]->hdisplay == *width )
4622 *width = vm_modelines[*vm]->hdisplay;
4623 *height = vm_modelines[*vm]->vdisplay;
4628 void BC_WindowBase::scale_vm(int vm)
4630 int foo,bar,dotclock;
4631 if( XF86VidModeQueryExtension(top_level->display,&foo,&bar) ) {
4633 XF86VidModeModeInfo **vm_modelines;
4634 XF86VidModeModeLine vml;
4635 XF86VidModeGetAllModeLines(top_level->display,
4636 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4637 XF86VidModeGetModeLine(top_level->display,
4638 XDefaultScreen(top_level->display), &dotclock,&vml);
4639 orig_modeline.dotclock = dotclock;
4640 orig_modeline.hdisplay = vml.hdisplay;
4641 orig_modeline.hsyncstart = vml.hsyncstart;
4642 orig_modeline.hsyncend = vml.hsyncend;
4643 orig_modeline.htotal = vml.htotal;
4644 orig_modeline.vdisplay = vml.vdisplay;
4645 orig_modeline.vsyncstart = vml.vsyncstart;
4646 orig_modeline.vsyncend = vml.vsyncend;
4647 orig_modeline.vtotal = vml.vtotal;
4648 orig_modeline.flags = vml.flags;
4649 orig_modeline.privsize = vml.privsize;
4650 // orig_modeline.private = vml.private;
4651 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),vm_modelines[vm]);
4652 XF86VidModeSetViewPort(top_level->display,XDefaultScreen(top_level->display),0,0);
4653 XFlush(top_level->display);
4657 void BC_WindowBase::restore_vm()
4659 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),&orig_modeline);
4660 XFlush(top_level->display);
4665 #ifndef SINGLE_THREAD
4666 int BC_WindowBase::get_event_count()
4668 event_lock->lock("BC_WindowBase::get_event_count");
4669 int result = common_events.total;
4670 event_lock->unlock();
4674 XEvent* BC_WindowBase::get_event()
4677 while(!done && !result)
4679 event_condition->lock("BC_WindowBase::get_event");
4680 event_lock->lock("BC_WindowBase::get_event");
4682 if(common_events.total && !done)
4684 result = common_events.values[0];
4685 common_events.remove_number(0);
4688 event_lock->unlock();
4693 void BC_WindowBase::put_event(XEvent *event)
4695 event_lock->lock("BC_WindowBase::put_event");
4696 common_events.append(event);
4697 event_lock->unlock();
4698 event_condition->unlock();
4701 void BC_WindowBase::dequeue_events(Window win)
4703 event_lock->lock("BC_WindowBase::dequeue_events");
4705 int out = 0, total = common_events.size();
4706 for( int in=0; in<total; ++in ) {
4707 if( common_events[in]->xany.window == win ) continue;
4708 common_events[out++] = common_events[in];
4710 common_events.total = out;
4712 event_lock->unlock();
4715 int BC_WindowBase::resend_event(BC_WindowBase *window)
4717 if( resend_event_window ) return 1;
4718 resend_event_window = window;
4724 int BC_WindowBase::resend_event(BC_WindowBase *window)
4729 #endif // SINGLE_THREAD
4731 int BC_WindowBase::get_id()
4737 BC_Pixmap *BC_WindowBase::create_pixmap(VFrame *vframe)
4739 int w = vframe->get_w(), h = vframe->get_h();
4740 BC_Pixmap *icon = new BC_Pixmap(this, w, h);
4741 icon->draw_vframe(vframe, 0,0, w,h, 0,0);
4746 void BC_WindowBase::flicker(int n, int ms)
4748 int color = get_bg_color();
4749 for( int i=2*n; --i>=0; ) {
4750 set_inverse(); set_bg_color(WHITE);
4751 clear_box(0,0, w,h); flash(1);
4752 sync_display(); Timer::delay(ms);
4754 set_bg_color(color);
4758 void BC_WindowBase::focus()
4760 XWindowAttributes xwa;
4761 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4762 if( xwa.map_state == IsViewable )
4763 XSetInputFocus(top_level->display, top_level->win, RevertToParent, CurrentTime);
4766 int BC_WindowBase::wait_viewable(int ms)
4769 XWindowAttributes xwa;
4771 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4772 if( xwa.map_state == IsViewable ) return 0;
4774 } while( timer.get_difference() < ms );