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 // force setting modifiers state if a modifier key pressed
1194 // block out control keys
1195 if(keysym > 0xffe0 && keysym < 0xffff) break;
1196 // block out Alt_GR key
1197 if(keysym == 0xfe03) break;
1200 printf("BC_WindowBase::dispatch_event %x\n", (uint32_t)keysym);
1202 #ifdef X_HAVE_UTF8_STRING
1203 //It's Ascii or UTF8?
1204 // if (keysym != 0xffff && (keys_return[0] & 0xff) >= 0x7f )
1205 //printf("BC_WindowBase::dispatch_event %d %02x%02x\n", __LINE__, keys_return[0], keys_return[1]);
1207 if( ((keys_return[1] & 0xff) > 0x80) &&
1208 ((keys_return[0] & 0xff) > 0xC0) ) {
1209 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1210 key_pressed = keysym & 0xff;
1214 // shuttle speed codes
1215 if( keysym >= SKEY_MIN && keysym <= SKEY_MAX ) {
1216 key_pressed = keysym;
1218 else switch( keysym ) {
1219 // block out extra keys
1229 // Translate key codes
1230 case XK_Return: key_pressed = RETURN; break;
1231 case XK_Up: key_pressed = UP; break;
1232 case XK_Down: key_pressed = DOWN; break;
1233 case XK_Left: key_pressed = LEFT; break;
1234 case XK_Right: key_pressed = RIGHT; break;
1235 case XK_Next: key_pressed = PGDN; break;
1236 case XK_Prior: key_pressed = PGUP; break;
1237 case XK_BackSpace: key_pressed = BACKSPACE; break;
1238 case XK_Escape: key_pressed = ESC; break;
1241 key_pressed = LEFTTAB;
1245 case XK_ISO_Left_Tab: key_pressed = LEFTTAB; break;
1246 case XK_underscore: key_pressed = '_'; break;
1247 case XK_asciitilde: key_pressed = '~'; break;
1248 case XK_Delete: key_pressed = DELETE; break;
1249 case XK_Home: key_pressed = HOME; break;
1250 case XK_End: key_pressed = END; break;
1253 case XK_KP_Enter: key_pressed = KPENTER; break;
1254 case XK_KP_Add: key_pressed = KPPLUS; break;
1255 case XK_KP_Subtract: key_pressed = KPMINUS; break;
1256 case XK_KP_Multiply: key_pressed = KPSTAR; break;
1257 case XK_KP_Divide: key_pressed = KPSLASH; break;
1259 case XK_KP_End: key_pressed = KP1; break;
1261 case XK_KP_Down: key_pressed = KP2; break;
1263 case XK_KP_Page_Down: key_pressed = KP3; break;
1265 case XK_KP_Left: key_pressed = KP4; break;
1267 case XK_KP_Begin: key_pressed = KP5; break;
1269 case XK_KP_Right: key_pressed = KP6; break;
1271 case XK_KP_Home: key_pressed = KP7; break;
1273 case XK_KP_Up: key_pressed = KP8; break;
1275 case XK_KP_Page_Up: key_pressed = KP9; break;
1277 case XK_KP_Insert: key_pressed = KPINS; break;
1279 case XK_KP_Delete: key_pressed = KPDEL; break;
1281 case XK_F1: key_pressed = KEY_F1; break;
1282 case XK_F2: key_pressed = KEY_F2; break;
1283 case XK_F3: key_pressed = KEY_F3; break;
1284 case XK_F4: key_pressed = KEY_F4; break;
1285 case XK_F5: key_pressed = KEY_F5; break;
1286 case XK_F6: key_pressed = KEY_F6; break;
1287 case XK_F7: key_pressed = KEY_F7; break;
1288 case XK_F8: key_pressed = KEY_F8; break;
1289 case XK_F9: key_pressed = KEY_F9; break;
1290 case XK_F10: key_pressed = KEY_F10; break;
1291 case XK_F11: key_pressed = KEY_F11; break;
1292 case XK_F12: key_pressed = KEY_F12; break;
1294 case XK_Menu: key_pressed = KPMENU; break; /* menu */
1297 key_pressed = keysym & 0xff;
1298 #ifdef X_HAVE_UTF8_STRING
1299 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1304 #ifdef X_HAVE_UTF8_STRING
1306 key_pressed_utf8 = keys_return;
1311 if( top_level == this )
1312 result = BC_KeyboardHandler::run_listeners(this);
1314 //printf("BC_WindowBase::dispatch_event %d %d %x\n", shift_down(), alt_down(), key_pressed);
1316 result = dispatch_keypress_event();
1317 // Handle some default keypresses
1320 if(key_pressed == 'w' ||
1329 XLookupString((XKeyEvent*)event, keys_return, 1, &keysym, 0);
1330 get_key_masks(event->xkey.state);
1331 // force clearing modifiers state if a modifier key released
1348 dispatch_keyrelease_event();
1349 // printf("BC_WindowBase::dispatch_event KeyRelease keysym=%#lx keystate=%04x\n",
1350 // keysym, event->xkey.state);
1354 if( event->xcrossing.mode != NotifyNormal ) break;
1356 event_win = event->xany.window;
1357 dispatch_cursor_leave();
1361 if( event->xcrossing.mode != NotifyNormal ) break;
1363 if( !cursor_entered ) {
1364 for( int i=0; i<popups.size(); ++i ) { // popups always take focus
1365 if( popups[i]->win == event->xcrossing.window )
1368 if( !cursor_entered && get_resources()->grab_input_focus &&
1369 !event->xcrossing.focus && event->xcrossing.window == win ) {
1372 if( cursor_entered )
1375 event_win = event->xany.window;
1376 cursor_x = event->xcrossing.x;
1377 cursor_y = event->xcrossing.y;
1378 dispatch_cursor_enter();
1384 //printf("100 %s %p %d\n", title, event, event->type);
1385 //if(event->type != ClientMessage) dump();
1387 #ifndef SINGLE_THREAD
1390 if( resend_event_window ) {
1391 resend_event_window->put_event(event);
1392 resend_event_window = 0;
1398 // if(done) completion_lock->unlock();
1401 if(debug) printf("BC_WindowBase::dispatch_event this=%p %d\n", this, __LINE__);
1405 int BC_WindowBase::dispatch_expose_event()
1408 for(int i = 0; i < subwindows->total && !result; i++)
1410 result = subwindows->values[i]->dispatch_expose_event();
1413 // Propagate to user
1414 if(!result) expose_event();
1418 int BC_WindowBase::dispatch_resize_event(int w, int h)
1420 // Can't store new w and h until the event is handles
1421 // because bcfilebox depends on the old w and h to
1422 // reposition widgets.
1423 if( window_type == MAIN_WINDOW ) {
1428 pixmap = new BC_Pixmap(this, w, h);
1429 clear_box(0, 0, w, h);
1432 // Propagate to subwindows
1433 for(int i = 0; i < subwindows->total; i++) {
1434 subwindows->values[i]->dispatch_resize_event(w, h);
1437 // Propagate to user
1440 if( window_type == MAIN_WINDOW ) {
1449 int BC_WindowBase::dispatch_flash()
1452 for(int i = 0; i < subwindows->total; i++)
1453 subwindows->values[i]->dispatch_flash();
1457 int BC_WindowBase::dispatch_translation_event()
1459 translation_events = 0;
1460 if(window_type == MAIN_WINDOW)
1464 x = last_translate_x;
1465 y = last_translate_y;
1466 // Correct for window manager offsets
1471 for(int i = 0; i < subwindows->total; i++)
1473 subwindows->values[i]->dispatch_translation_event();
1476 translation_event();
1480 int BC_WindowBase::dispatch_motion_event()
1485 if(top_level == this)
1488 event_win = last_motion_win;
1489 get_key_masks(last_motion_state);
1492 if(get_button_down() && !active_menubar && !active_popup_menu)
1496 cursor_x = last_motion_x;
1497 cursor_y = last_motion_y;
1498 result = dispatch_drag_motion();
1502 (last_motion_x < drag_x1 || last_motion_x >= drag_x2 ||
1503 last_motion_y < drag_y1 || last_motion_y >= drag_y2))
1508 result = dispatch_drag_start();
1512 cursor_x = last_motion_x;
1513 cursor_y = last_motion_y;
1515 // printf("BC_WindowBase::dispatch_motion_event %d %p %p %p\n",
1518 // active_popup_menu,
1519 // active_subwindow);
1521 if(active_menubar && !result) result = active_menubar->dispatch_motion_event();
1522 if(active_popup_menu && !result) result = active_popup_menu->dispatch_motion_event();
1523 if(active_subwindow && !result) result = active_subwindow->dispatch_motion_event();
1526 // Dispatch in stacking order
1527 for(int i = subwindows->size() - 1; i >= 0 && !result; i--)
1529 result = subwindows->values[i]->dispatch_motion_event();
1532 if(!result) result = cursor_motion_event(); // give to user
1536 int BC_WindowBase::dispatch_keypress_event()
1539 if(top_level == this)
1541 if(active_subwindow) result = active_subwindow->dispatch_keypress_event();
1544 for(int i = 0; i < subwindows->total && !result; i++)
1546 result = subwindows->values[i]->dispatch_keypress_event();
1549 if(!result) result = keypress_event();
1554 int BC_WindowBase::dispatch_keyrelease_event()
1557 if(top_level == this)
1559 if(active_subwindow) result = active_subwindow->dispatch_keyrelease_event();
1562 for(int i = 0; i < subwindows->total && !result; i++)
1564 result = subwindows->values[i]->dispatch_keyrelease_event();
1567 if(!result) result = keyrelease_event();
1572 int BC_WindowBase::dispatch_focus_in()
1574 for(int i = 0; i < subwindows->total; i++)
1576 subwindows->values[i]->dispatch_focus_in();
1584 int BC_WindowBase::dispatch_focus_out()
1586 for(int i = 0; i < subwindows->total; i++)
1588 subwindows->values[i]->dispatch_focus_out();
1596 int BC_WindowBase::get_has_focus()
1598 return top_level->has_focus;
1601 int BC_WindowBase::get_deleting()
1603 if(is_deleting) return 1;
1604 if(parent_window && parent_window->get_deleting()) return 1;
1608 int BC_WindowBase::dispatch_button_press()
1613 if(top_level == this)
1615 if(active_menubar) result = active_menubar->dispatch_button_press();
1616 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_press();
1617 if(active_subwindow && !result) result = active_subwindow->dispatch_button_press();
1620 for(int i = 0; i < subwindows->total && !result; i++)
1622 result = subwindows->values[i]->dispatch_button_press();
1625 if(!result) result = button_press_event();
1631 int BC_WindowBase::dispatch_button_release()
1634 if(top_level == this)
1636 if(active_menubar) result = active_menubar->dispatch_button_release();
1637 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_release();
1638 if(active_subwindow && !result) result = active_subwindow->dispatch_button_release();
1639 if(!result && button_number != 4 && button_number != 5)
1640 result = dispatch_drag_stop();
1643 for(int i = 0; i < subwindows->total && !result; i++)
1645 result = subwindows->values[i]->dispatch_button_release();
1650 result = button_release_event();
1657 int BC_WindowBase::dispatch_repeat_event(int64_t duration)
1660 // all repeat event handlers get called and decide based on activity and duration
1661 // whether to respond
1662 for(int i = 0; i < subwindows->total; i++)
1664 subwindows->values[i]->dispatch_repeat_event(duration);
1668 repeat_event(duration);
1672 // Unlock next repeat signal
1673 if(window_type == MAIN_WINDOW)
1675 #ifdef SINGLE_THREAD
1676 BC_Display::display_global->unlock_repeaters(duration);
1678 for(int i = 0; i < repeaters.total; i++)
1680 if(repeaters.values[i]->delay == duration)
1682 repeaters.values[i]->repeat_lock->unlock();
1690 void BC_WindowBase::unhide_cursor()
1695 if(top_level->is_hourglass)
1696 set_cursor(HOURGLASS_CURSOR, 1, 0);
1698 set_cursor(current_cursor, 1, 0);
1700 cursor_timer->update();
1704 void BC_WindowBase::update_video_cursor()
1706 if(video_on && !is_transparent)
1708 if(cursor_timer->get_difference() > VIDEO_CURSOR_TIMEOUT && !is_transparent)
1711 set_cursor(TRANSPARENT_CURSOR, 1, 1);
1712 cursor_timer->update();
1717 cursor_timer->update();
1722 int BC_WindowBase::dispatch_cursor_leave()
1726 for(int i = 0; i < subwindows->total; i++)
1728 subwindows->values[i]->dispatch_cursor_leave();
1731 cursor_leave_event();
1735 int BC_WindowBase::dispatch_cursor_enter()
1741 if(active_menubar) result = active_menubar->dispatch_cursor_enter();
1742 if(!result && active_popup_menu) result = active_popup_menu->dispatch_cursor_enter();
1743 if(!result && active_subwindow) result = active_subwindow->dispatch_cursor_enter();
1745 for(int i = 0; !result && i < subwindows->total; i++)
1747 result = subwindows->values[i]->dispatch_cursor_enter();
1750 if(!result) result = cursor_enter_event();
1754 int BC_WindowBase::cursor_enter_event()
1759 int BC_WindowBase::cursor_leave_event()
1764 int BC_WindowBase::close_event()
1770 // *** CONTEXT_HELP ***
1771 // This basic implementation serves solely for context help.
1772 // We are handling Alt/H only. Any subclass requiring more sophisticated
1773 // processing of keystrokes has to provide its own overloaded handler.
1774 int BC_WindowBase::keypress_event()
1776 // printf("BC_WindowBase::keypress_event: %d\n", get_keypress());
1777 return context_help_check_and_show();
1780 // The stuff up to END_CONTEXT_HELP serves solely for context help
1781 void BC_WindowBase::context_help_set_keyword(const char *keyword)
1783 if (keyword) strcpy(context_help_keyword, keyword);
1786 const char *BC_WindowBase::context_help_get_keyword()
1788 // If we have context_help_keyword defined here, return it.
1789 // Otherwise recursively track widget hierarchy up to top_level
1790 // and return the nearest found nonempty keyword.
1791 // If nothing found, the special keyword "TOC" is returned.
1792 if (context_help_keyword[0] || this == top_level ||
1793 this == parent_window || ! parent_window) {
1794 if (! context_help_keyword[0] && this == top_level)
1795 context_help_set_keyword("TOC");
1796 return context_help_keyword;
1798 return parent_window->context_help_get_keyword();
1801 void BC_WindowBase::context_help_show(const char *keyword)
1803 char cmd[BCTEXTLEN];
1805 if (! keyword) return;
1807 sprintf(cmd, "\"%s/doc/ContextManual.pl\" \"%s\"", getenv("CIN_DAT"),
1809 // printf("BC_WindowBase::context_help_show(%s):\n%s\n", keyword, cmd);
1811 // ContextManual.pl starts browser in background, so system() should not block
1815 void BC_WindowBase::context_help_show()
1817 context_help_show(context_help_get_keyword());
1820 int BC_WindowBase::context_help_check_and_show(const char *keyword)
1822 if (! keyword) return 0;
1823 if (! keyword[0]) return 0;
1825 // We are handling Alt/H only
1826 if (get_keypress() != 'h' || ! alt_down()) return 0;
1828 // Restrict cursor location to that widget keystroke occured in
1829 if (! is_tooltip_event_win() || ! cursor_inside()) return 0;
1831 context_help_show(keyword);
1835 int BC_WindowBase::context_help_check_and_show()
1837 const char *keyword;
1839 // We are handling Alt/H only
1840 if (get_keypress() != 'h' || ! alt_down()) return 0;
1842 // Restrict cursor location, so any subwindow can define its own help keyword
1843 if (! is_tooltip_event_win() || ! cursor_inside()) return 0;
1845 // If a widget has not defined its own help keyword, the parent can provide it
1846 keyword = context_help_get_keyword();
1847 if (! keyword[0]) return 0;
1849 context_help_show(keyword);
1852 // *** END_CONTEXT_HELP ***
1854 int BC_WindowBase::dispatch_drag_start()
1857 if(active_menubar) result = active_menubar->dispatch_drag_start();
1858 if(!result && active_popup_menu) result = active_popup_menu->dispatch_drag_start();
1859 if(!result && active_subwindow) result = active_subwindow->dispatch_drag_start();
1861 for(int i = 0; i < subwindows->total && !result; i++)
1863 result = subwindows->values[i]->dispatch_drag_start();
1866 if(!result) result = is_dragging = drag_start_event();
1870 int BC_WindowBase::dispatch_drag_stop()
1874 for(int i = 0; i < subwindows->total && !result; i++)
1876 result = subwindows->values[i]->dispatch_drag_stop();
1879 if(is_dragging && !result)
1889 int BC_WindowBase::dispatch_drag_motion()
1892 for(int i = 0; i < subwindows->total && !result; i++)
1894 result = subwindows->values[i]->dispatch_drag_motion();
1897 if(is_dragging && !result)
1899 drag_motion_event();
1907 int BC_WindowBase::show_tooltip(const char *text, int x, int y, int w, int h)
1910 int forced = !text ? force_tooltip : 1;
1911 if( !text ) text = tooltip_text;
1912 if( !text || (!forced && !get_resources()->tooltips_enabled) ) {
1913 top_level->hide_tooltip();
1917 if(w < 0) w = get_text_width(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1918 if(h < 0) h = get_text_height(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1919 // default x,y (win relative)
1920 if( x < 0 ) x = get_w();
1921 if( y < 0 ) y = get_h();
1923 get_root_coordinates(x, y, &wx, &wy);
1924 // keep the tip inside the window/display
1925 int x0 = top_level->get_x(), x1 = x0 + top_level->get_w();
1926 int x2 = top_level->get_screen_x(0, -1) + top_level->get_screen_w(0, -1);
1927 if( x1 > x2 ) x1 = x2;
1928 if( wx < x0 ) wx = x0;
1929 if( wx >= (x1-=w) ) wx = x1;
1930 int y0 = top_level->get_y(), y1 = y0 + top_level->get_h();
1931 int y2 = top_level->get_root_h(0);
1932 if( y1 > y2 ) y1 = y2;
1933 if( wy < y0 ) wy = y0;
1934 if( wy >= (y1-=h) ) wy = y1;
1935 // avoid tip under cursor (flickers)
1937 get_abs_cursor(abs_x,abs_y, 0);
1938 if( wx < abs_x && abs_x < wx+w && wy < abs_y && abs_y < wy+h ) {
1939 if( wx-abs_x < wy-abs_y )
1946 tooltip_popup = new BC_Popup(top_level, wx, wy, w, h,
1947 get_resources()->tooltip_bg_color);
1950 tooltip_popup->reposition_window(wx, wy, w, h);
1953 tooltip_popup->flash();
1954 tooltip_popup->flush();
1958 int BC_WindowBase::hide_tooltip()
1961 for(int i = 0; i < subwindows->total; i++)
1963 subwindows->values[i]->hide_tooltip();
1969 delete tooltip_popup;
1975 const char *BC_WindowBase::get_tooltip()
1977 return tooltip_text;
1980 int BC_WindowBase::set_tooltip(const char *text)
1982 tooltip_text = text;
1984 // Update existing tooltip if it is visible
1988 tooltip_popup->flash();
1992 // signal the event handler to repeat
1993 int BC_WindowBase::set_repeat(int64_t duration)
1997 printf("BC_WindowBase::set_repeat duration=%jd\n", duration);
2000 if(window_type != MAIN_WINDOW) return top_level->set_repeat(duration);
2002 #ifdef SINGLE_THREAD
2003 BC_Display::display_global->set_repeat(this, duration);
2005 // test repeater database for duplicates
2006 for(int i = 0; i < repeaters.total; i++)
2009 if(repeaters.values[i]->delay == duration)
2011 repeaters.values[i]->start_repeating(this);
2016 BC_Repeater *repeater = new BC_Repeater(this, duration);
2017 repeater->initialize();
2018 repeaters.append(repeater);
2019 repeater->start_repeating();
2024 int BC_WindowBase::unset_repeat(int64_t duration)
2026 if(window_type != MAIN_WINDOW) return top_level->unset_repeat(duration);
2028 #ifdef SINGLE_THREAD
2029 BC_Display::display_global->unset_repeat(this, duration);
2031 for(int i = 0; i < repeaters.total; i++)
2033 if(repeaters.values[i]->delay == duration)
2035 repeaters.values[i]->stop_repeating();
2043 int BC_WindowBase::unset_all_repeaters()
2045 #ifdef SINGLE_THREAD
2046 BC_Display::display_global->unset_all_repeaters(this);
2048 for(int i = 0; i < repeaters.total; i++)
2050 repeaters.values[i]->stop_repeating();
2052 repeaters.remove_all_objects();
2057 // long BC_WindowBase::get_repeat_id()
2059 // return top_level->next_repeat_id++;
2062 XEvent *BC_WindowBase::new_xevent()
2064 XEvent *event = new XEvent;
2065 memset(event, 0, sizeof(*event));
2069 #ifndef SINGLE_THREAD
2070 int BC_WindowBase::arm_repeat(int64_t duration)
2072 XEvent *event = new_xevent();
2073 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
2074 ptr->type = ClientMessage;
2075 ptr->message_type = RepeaterXAtom;
2077 ptr->data.l[0] = duration;
2079 // Couldn't use XSendEvent since it locked up randomly.
2085 int BC_WindowBase::receive_custom_xatoms(xatom_event *event)
2090 int BC_WindowBase::send_custom_xatom(xatom_event *event)
2092 #ifndef SINGLE_THREAD
2093 XEvent *myevent = new_xevent();
2094 XClientMessageEvent *ptr = (XClientMessageEvent*)myevent;
2095 ptr->type = ClientMessage;
2096 ptr->message_type = event->message_type;
2097 ptr->format = event->format;
2098 ptr->data.l[0] = event->data.l[0];
2099 ptr->data.l[1] = event->data.l[1];
2100 ptr->data.l[2] = event->data.l[2];
2101 ptr->data.l[3] = event->data.l[3];
2102 ptr->data.l[4] = event->data.l[4];
2111 Atom BC_WindowBase::create_xatom(const char *atom_name)
2113 return XInternAtom(display, atom_name, False);
2116 int BC_WindowBase::get_atoms()
2118 SetDoneXAtom = XInternAtom(display, "BC_REPEAT_EVENT", False);
2119 RepeaterXAtom = XInternAtom(display, "BC_CLOSE_EVENT", False);
2120 DestroyAtom = XInternAtom(display, "BC_DESTROY_WINDOW", False);
2121 DelWinXAtom = XInternAtom(display, "WM_DELETE_WINDOW", False);
2122 if( (ProtoXAtom = XInternAtom(display, "WM_PROTOCOLS", False)) != 0 )
2123 XChangeProperty(display, win, ProtoXAtom, XA_ATOM, 32,
2124 PropModeReplace, (unsigned char *)&DelWinXAtom, True);
2130 void BC_WindowBase::init_cursors()
2132 arrow_cursor = XCreateFontCursor(display, XC_top_left_arrow);
2133 cross_cursor = XCreateFontCursor(display, XC_crosshair);
2134 ibeam_cursor = XCreateFontCursor(display, XC_xterm);
2135 vseparate_cursor = XCreateFontCursor(display, XC_sb_v_double_arrow);
2136 hseparate_cursor = XCreateFontCursor(display, XC_sb_h_double_arrow);
2137 move_cursor = XCreateFontCursor(display, XC_fleur);
2138 left_cursor = XCreateFontCursor(display, XC_sb_left_arrow);
2139 right_cursor = XCreateFontCursor(display, XC_sb_right_arrow);
2140 upright_arrow_cursor = XCreateFontCursor(display, XC_arrow);
2141 upleft_resize_cursor = XCreateFontCursor(display, XC_top_left_corner);
2142 upright_resize_cursor = XCreateFontCursor(display, XC_top_right_corner);
2143 downleft_resize_cursor = XCreateFontCursor(display, XC_bottom_left_corner);
2144 downright_resize_cursor = XCreateFontCursor(display, XC_bottom_right_corner);
2145 hourglass_cursor = XCreateFontCursor(display, XC_watch);
2146 grabbed_cursor = create_grab_cursor();
2148 static char cursor_data[] = { 0,0,0,0, 0,0,0,0 };
2149 Colormap colormap = DefaultColormap(display, screen);
2150 Pixmap pixmap_bottom = XCreateBitmapFromData(display,
2151 rootwin, cursor_data, 8, 8);
2152 XColor black, dummy;
2153 XAllocNamedColor(display, colormap, "black", &black, &dummy);
2154 transparent_cursor = XCreatePixmapCursor(display,
2155 pixmap_bottom, pixmap_bottom, &black, &black, 0, 0);
2156 // XDefineCursor(display, win, transparent_cursor);
2157 XFreePixmap(display, pixmap_bottom);
2160 int BC_WindowBase::evaluate_color_model(int client_byte_order, int server_byte_order, int depth)
2162 int color_model = BC_TRANSPARENCY;
2166 color_model = BC_RGB8;
2169 color_model = (server_byte_order == client_byte_order) ? BC_RGB565 : BC_BGR565;
2172 color_model = server_byte_order ? BC_BGR888 : BC_RGB888;
2175 color_model = server_byte_order ? BC_BGR8888 : BC_ARGB8888;
2181 int BC_WindowBase::init_colors()
2184 current_color_value = current_color_pixel = 0;
2186 // Get the real depth
2189 ximage = XCreateImage(top_level->display,
2190 top_level->vis, top_level->default_depth,
2191 ZPixmap, 0, data, 16, 16, 8, 0);
2192 bits_per_pixel = ximage->bits_per_pixel;
2193 XDestroyImage(ximage);
2195 color_model = evaluate_color_model(client_byte_order,
2198 // Get the color model
2203 cmap = XCreateColormap(display, rootwin, vis, AllocNone);
2204 create_private_colors();
2207 cmap = DefaultColormap(display, screen);
2208 create_shared_colors();
2211 allocate_color_table();
2215 //cmap = DefaultColormap(display, screen);
2216 cmap = XCreateColormap(display, rootwin, vis, AllocNone );
2222 int BC_WindowBase::create_private_colors()
2227 for(int i = 0; i < 255; i++)
2229 color = (i & 0xc0) << 16;
2230 color += (i & 0x38) << 10;
2231 color += (i & 0x7) << 5;
2232 color_table[i][0] = color;
2234 create_shared_colors(); // overwrite the necessary colors on the table
2239 int BC_WindowBase::create_color(int color)
2241 if(total_colors == 256)
2243 // replace the closest match with an exact match
2244 color_table[get_color_rgb8(color)][0] = color;
2248 // add the color to the table
2249 color_table[total_colors][0] = color;
2255 int BC_WindowBase::create_shared_colors()
2257 create_color(BLACK);
2258 create_color(WHITE);
2260 create_color(LTGREY);
2261 create_color(MEGREY);
2262 create_color(MDGREY);
2263 create_color(DKGREY);
2265 create_color(LTCYAN);
2266 create_color(MECYAN);
2267 create_color(MDCYAN);
2268 create_color(DKCYAN);
2270 create_color(LTGREEN);
2271 create_color(GREEN);
2272 create_color(DKGREEN);
2274 create_color(LTPINK);
2278 create_color(LTBLUE);
2280 create_color(DKBLUE);
2282 create_color(LTYELLOW);
2283 create_color(MEYELLOW);
2284 create_color(MDYELLOW);
2285 create_color(DKYELLOW);
2287 create_color(LTPURPLE);
2288 create_color(MEPURPLE);
2289 create_color(MDPURPLE);
2290 create_color(DKPURPLE);
2292 create_color(FGGREY);
2293 create_color(MNBLUE);
2294 create_color(ORANGE);
2295 create_color(FTGREY);
2300 Cursor BC_WindowBase::create_grab_cursor()
2302 int iw = 23, iw1 = iw-1, iw2 = iw/2;
2303 int ih = 23, ih1 = ih-1, ih2 = ih/2;
2304 VFrame grab(iw,ih,BC_RGB888);
2306 grab.set_pixel_color(RED); // fg
2307 grab.draw_smooth(iw2,0, iw1,0, iw1,ih2);
2308 grab.draw_smooth(iw1,ih2, iw1,ih1, iw2,ih1);
2309 grab.draw_smooth(iw2,ih1, 0,ih1, 0,ih2);
2310 grab.draw_smooth(0,ih2, 0,0, iw2,0);
2311 grab.set_pixel_color(WHITE); // bg
2312 grab.draw_line(0,ih2, iw2-2,ih2);
2313 grab.draw_line(iw2+2,ih2, iw1,ih2);
2314 grab.draw_line(iw2,0, iw2,ih2-2);
2315 grab.draw_line(iw2,ih2+2, iw2,ih1);
2317 int bpl = (iw+7)/8, isz = bpl * ih;
2318 char img[isz]; memset(img, 0, isz);
2319 char msk[isz]; memset(msk, 0, isz);
2320 unsigned char **rows = grab.get_rows();
2321 for( int iy=0; iy<ih; ++iy ) {
2322 char *op = img + iy*bpl;
2323 char *mp = msk + iy*bpl;
2324 unsigned char *ip = rows[iy];
2325 for( int ix=0; ix<iw; ++ix,ip+=3 ) {
2326 if( ip[0] ) mp[ix>>3] |= (1<<(ix&7));
2327 if( !ip[1] ) op[ix>>3] |= (1<<(ix&7));
2330 unsigned long white_pix = WhitePixel(display, screen);
2331 unsigned long black_pix = BlackPixel(display, screen);
2332 Pixmap img_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2333 img, iw,ih, white_pix,black_pix, 1);
2334 Pixmap msk_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2335 msk, iw,ih, white_pix,black_pix, 1);
2338 fc.flags = bc.flags = DoRed | DoGreen | DoBlue;
2339 fc.red = 0xffff; fc.green = fc.blue = 0; // fg
2340 bc.red = 0xffff; bc.green = 0xffff; bc.blue = 0x0000; // bg
2341 Cursor cursor = XCreatePixmapCursor(display, img_xpm,msk_xpm, &fc,&bc, iw2,ih2);
2342 XFreePixmap(display, img_xpm);
2343 XFreePixmap(display, msk_xpm);
2347 int BC_WindowBase::allocate_color_table()
2349 int red, green, blue, color;
2352 for(int i = 0; i < total_colors; i++)
2354 color = color_table[i][0];
2355 red = (color & 0xFF0000) >> 16;
2356 green = (color & 0x00FF00) >> 8;
2357 blue = color & 0xFF;
2359 col.flags = DoRed | DoGreen | DoBlue;
2360 col.red = red<<8 | red;
2361 col.green = green<<8 | green;
2362 col.blue = blue<<8 | blue;
2364 XAllocColor(display, cmap, &col);
2365 color_table[i][1] = col.pixel;
2368 XInstallColormap(display, cmap);
2372 int BC_WindowBase::init_window_shape()
2374 if(bg_pixmap && bg_pixmap->use_alpha())
2376 XShapeCombineMask(top_level->display,
2377 this->win, ShapeBounding, 0, 0,
2378 bg_pixmap->get_alpha(), ShapeSet);
2384 int BC_WindowBase::init_gc()
2386 unsigned long gcmask;
2387 gcmask = GCFont | GCGraphicsExposures;
2390 gcvalues.font = mediumfont->fid; // set the font
2391 gcvalues.graphics_exposures = 0; // prevent expose events for every redraw
2392 gc = XCreateGC(display, rootwin, gcmask, &gcvalues);
2394 // gcmask = GCCapStyle | GCJoinStyle;
2395 // XGetGCValues(display, gc, gcmask, &gcvalues);
2396 // printf("BC_WindowBase::init_gc %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2400 int BC_WindowBase::init_fonts()
2402 if( !(smallfont = XLoadQueryFont(display, _(resources->small_font))) )
2403 if( !(smallfont = XLoadQueryFont(display, _(resources->small_font2))) )
2404 smallfont = XLoadQueryFont(display, "fixed");
2405 if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font))) )
2406 if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font2))) )
2407 mediumfont = XLoadQueryFont(display, "fixed");
2408 if( !(largefont = XLoadQueryFont(display, _(resources->large_font))) )
2409 if( !(largefont = XLoadQueryFont(display, _(resources->large_font2))) )
2410 largefont = XLoadQueryFont(display, "fixed");
2411 if( !(bigfont = XLoadQueryFont(display, _(resources->big_font))) )
2412 if( !(bigfont = XLoadQueryFont(display, _(resources->big_font2))) )
2413 bigfont = XLoadQueryFont(display, "fixed");
2415 if((clockfont = XLoadQueryFont(display, _(resources->clock_font))) == NULL)
2416 if((clockfont = XLoadQueryFont(display, _(resources->clock_font2))) == NULL)
2417 clockfont = XLoadQueryFont(display, "fixed");
2420 if(get_resources()->use_fontset)
2425 // FIXME: should check the m,d,n values
2426 smallfontset = XCreateFontSet(display, resources->small_fontset, &m, &n, &d);
2428 smallfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2429 mediumfontset = XCreateFontSet(display, resources->medium_fontset, &m, &n, &d);
2430 if( !mediumfontset )
2431 mediumfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2432 largefontset = XCreateFontSet(display, resources->large_fontset, &m, &n, &d);
2434 largefontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2435 bigfontset = XCreateFontSet(display, resources->big_fontset, &m, &n, &d);
2437 bigfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2438 clockfontset = XCreateFontSet(display, resources->clock_fontset, &m, &n, &d);
2440 clockfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2441 if(clockfontset && bigfontset && largefontset && mediumfontset && smallfontset) {
2442 curr_fontset = mediumfontset;
2443 get_resources()->use_fontset = 1;
2447 get_resources()->use_fontset = 0;
2454 void BC_WindowBase::init_xft()
2457 if( !get_resources()->use_xft ) return;
2458 // apparently, xft is not reentrant, more than this is needed
2459 static Mutex xft_init_lock("BC_WindowBase::xft_init_lock", 0);
2460 xft_init_lock.lock("BC_WindowBase::init_xft");
2461 if(!(smallfont_xft =
2462 (resources->small_font_xft[0] == '-' ?
2463 xftFontOpenXlfd(display, screen, resources->small_font_xft) :
2464 xftFontOpenName(display, screen, resources->small_font_xft))) )
2465 if(!(smallfont_xft =
2466 xftFontOpenXlfd(display, screen, resources->small_font_xft2)))
2467 smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2468 if(!(mediumfont_xft =
2469 (resources->medium_font_xft[0] == '-' ?
2470 xftFontOpenXlfd(display, screen, resources->medium_font_xft) :
2471 xftFontOpenName(display, screen, resources->medium_font_xft))) )
2472 if(!(mediumfont_xft =
2473 xftFontOpenXlfd(display, screen, resources->medium_font_xft2)))
2474 mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2475 if(!(largefont_xft =
2476 (resources->large_font_xft[0] == '-' ?
2477 xftFontOpenXlfd(display, screen, resources->large_font_xft) :
2478 xftFontOpenName(display, screen, resources->large_font_xft))) )
2479 if(!(largefont_xft =
2480 xftFontOpenXlfd(display, screen, resources->large_font_xft2)))
2481 largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2483 (resources->big_font_xft[0] == '-' ?
2484 xftFontOpenXlfd(display, screen, resources->big_font_xft) :
2485 xftFontOpenName(display, screen, resources->big_font_xft))) )
2487 xftFontOpenXlfd(display, screen, resources->big_font_xft2)))
2488 bigfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2489 if(!(clockfont_xft =
2490 (resources->clock_font_xft[0] == '-' ?
2491 xftFontOpenXlfd(display, screen, resources->clock_font_xft) :
2492 xftFontOpenName(display, screen, resources->clock_font_xft))) )
2493 clockfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2496 if(!(bold_smallfont_xft =
2497 (resources->small_b_font_xft[0] == '-' ?
2498 xftFontOpenXlfd(display, screen, resources->small_b_font_xft) :
2499 xftFontOpenName(display, screen, resources->small_b_font_xft))) )
2500 bold_smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2501 if(!(bold_mediumfont_xft =
2502 (resources->medium_b_font_xft[0] == '-' ?
2503 xftFontOpenXlfd(display, screen, resources->medium_b_font_xft) :
2504 xftFontOpenName(display, screen, resources->medium_b_font_xft))) )
2505 bold_mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2506 if(!(bold_largefont_xft =
2507 (resources->large_b_font_xft[0] == '-' ?
2508 xftFontOpenXlfd(display, screen, resources->large_b_font_xft) :
2509 xftFontOpenName(display, screen, resources->large_b_font_xft))) )
2510 bold_largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2512 if( !smallfont_xft || !mediumfont_xft || !largefont_xft || !bigfont_xft ||
2513 !bold_largefont_xft || !bold_mediumfont_xft || !bold_largefont_xft ||
2515 printf("BC_WindowBase::init_fonts: no xft fonts found:"
2516 " %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n",
2517 resources->small_font_xft, smallfont_xft,
2518 resources->medium_font_xft, mediumfont_xft,
2519 resources->large_font_xft, largefont_xft,
2520 resources->big_font_xft, bigfont_xft,
2521 resources->clock_font_xft, clockfont_xft,
2522 resources->small_b_font_xft, bold_smallfont_xft,
2523 resources->medium_b_font_xft, bold_mediumfont_xft,
2524 resources->large_b_font_xft, bold_largefont_xft);
2525 get_resources()->use_xft = 0;
2528 // _XftDisplayInfo needs a lock.
2529 xftDefaultHasRender(display);
2530 xft_init_lock.unlock();
2534 void BC_WindowBase::init_glyphs()
2536 // draw all ascii char glyphs
2537 // There are problems with some/my graphics boards/drivers
2538 // which cause some glyphs to be munged if draws occur while
2539 // the font is being loaded. This code fills the font caches
2540 // by drawing all the ascii glyphs before the system starts.
2541 // Not a fix, but much better than nothing.
2542 static int inited = 0;
2543 if( inited ) return;
2544 XGrabServer(display);
2547 int cur_font = current_font;
2548 // locale encodings, needed glyphs to be preloaded
2549 const char *text = _( // ascii 0x20...0x7e
2550 " !\"#$%&'()*+,-./0123456789:;<=>?"
2551 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
2552 "`abcdefghijklmnopqrstuvwxyz{|}~");
2553 for( int font=SMALLFONT; font<=LARGEFONT; ++font ) {
2555 draw_text(5,5, text);
2558 XUngrabServer(display);
2561 void BC_WindowBase::init_im()
2563 XIMStyles *xim_styles;
2566 if(!(input_method = XOpenIM(display, NULL, NULL, NULL)))
2568 printf("BC_WindowBase::init_im: Could not open input method.\n");
2569 XSetLocaleModifiers("@im=local");
2570 if(!(input_method = XOpenIM(display, NULL, NULL, NULL))) {
2571 printf("BC_WindowBase::init_im: Could not open input method local.\n");
2575 if(XGetIMValues(input_method, XNQueryInputStyle, &xim_styles, NULL) ||
2578 printf("BC_WindowBase::init_im: Input method doesn't support any styles.\n");
2579 XCloseIM(input_method);
2584 for(int z = 0; z < xim_styles->count_styles; z++)
2586 if(xim_styles->supported_styles[z] == (XIMPreeditNothing | XIMStatusNothing))
2588 xim_style = xim_styles->supported_styles[z];
2596 printf("BC_WindowBase::init_im: Input method doesn't support the style we need.\n");
2597 XCloseIM(input_method);
2601 input_context = XCreateIC(input_method, XNInputStyle, xim_style,
2602 XNClientWindow, win, XNFocusWindow, win, NULL);
2605 printf("BC_WindowBase::init_im: Failed to create input context.\n");
2606 XCloseIM(input_method);
2611 void BC_WindowBase::finit_im()
2613 if( input_context ) {
2614 XDestroyIC(input_context);
2617 if( input_method ) {
2618 XCloseIM(input_method);
2624 int BC_WindowBase::get_color(int64_t color)
2626 // return pixel of color
2627 // use this only for drawing subwindows not for bitmaps
2628 int i, test, difference;
2634 return get_color_rgb8(color);
2635 // test last color looked up
2636 if(current_color_value == color)
2637 return current_color_pixel;
2640 current_color_value = color;
2641 for(i = 0; i < total_colors; i++)
2643 if(color_table[i][0] == color)
2645 current_color_pixel = color_table[i][1];
2646 return current_color_pixel;
2650 // find nearest match
2651 difference = 0xFFFFFF;
2653 for(i = 0; i < total_colors; i++)
2655 test = abs((int)(color_table[i][0] - color));
2657 if(test < difference)
2659 current_color_pixel = color_table[i][1];
2663 return current_color_pixel;
2666 return get_color_rgb16(color);
2669 return get_color_bgr16(color);
2673 return client_byte_order == server_byte_order ?
2674 color : get_color_bgr24(color);
2682 int BC_WindowBase::get_color_rgb8(int color)
2686 pixel = (color & 0xc00000) >> 16;
2687 pixel += (color & 0xe000) >> 10;
2688 pixel += (color & 0xe0) >> 5;
2692 int64_t BC_WindowBase::get_color_rgb16(int color)
2695 result = (color & 0xf80000) >> 8;
2696 result += (color & 0xfc00) >> 5;
2697 result += (color & 0xf8) >> 3;
2702 int64_t BC_WindowBase::get_color_bgr16(int color)
2705 result = (color & 0xf80000) >> 19;
2706 result += (color & 0xfc00) >> 5;
2707 result += (color & 0xf8) << 8;
2712 int64_t BC_WindowBase::get_color_bgr24(int color)
2715 result = (color & 0xff) << 16;
2716 result += (color & 0xff00);
2717 result += (color & 0xff0000) >> 16;
2721 void BC_WindowBase::start_video()
2723 cursor_timer->update();
2725 // set_color(BLACK);
2726 // draw_box(0, 0, get_w(), get_h());
2730 void BC_WindowBase::stop_video()
2738 int64_t BC_WindowBase::get_color()
2740 return top_level->current_color;
2743 void BC_WindowBase::set_color(int64_t color)
2745 top_level->current_color = color;
2746 XSetForeground(top_level->display,
2748 top_level->get_color(color));
2751 void BC_WindowBase::set_opaque()
2753 XSetFunction(top_level->display, top_level->gc, GXcopy);
2756 void BC_WindowBase::set_inverse()
2758 XSetFunction(top_level->display, top_level->gc, GXxor);
2761 void BC_WindowBase::set_line_width(int value)
2763 this->line_width = value;
2764 XSetLineAttributes(top_level->display, top_level->gc, value, /* line_width */
2765 line_dashes == 0 ? LineSolid : LineOnOffDash, /* line_style */
2766 line_dashes == 0 ? CapRound : CapNotLast, /* cap_style */
2767 JoinMiter); /* join_style */
2769 if(line_dashes > 0) {
2770 const char dashes = line_dashes;
2771 XSetDashes(top_level->display, top_level->gc, 0, &dashes, 1);
2774 // XGCValues gcvalues;
2775 // unsigned long gcmask;
2776 // gcmask = GCCapStyle | GCJoinStyle;
2777 // XGetGCValues(top_level->display, top_level->gc, gcmask, &gcvalues);
2778 // printf("BC_WindowBase::set_line_width %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2781 void BC_WindowBase::set_line_dashes(int value)
2783 line_dashes = value;
2784 // call XSetLineAttributes
2785 set_line_width(line_width);
2789 Cursor BC_WindowBase::get_cursor_struct(int cursor)
2793 case ARROW_CURSOR: return top_level->arrow_cursor;
2794 case CROSS_CURSOR: return top_level->cross_cursor;
2795 case IBEAM_CURSOR: return top_level->ibeam_cursor;
2796 case VSEPARATE_CURSOR: return top_level->vseparate_cursor;
2797 case HSEPARATE_CURSOR: return top_level->hseparate_cursor;
2798 case MOVE_CURSOR: return top_level->move_cursor;
2799 case LEFT_CURSOR: return top_level->left_cursor;
2800 case RIGHT_CURSOR: return top_level->right_cursor;
2801 case UPRIGHT_ARROW_CURSOR: return top_level->upright_arrow_cursor;
2802 case UPLEFT_RESIZE: return top_level->upleft_resize_cursor;
2803 case UPRIGHT_RESIZE: return top_level->upright_resize_cursor;
2804 case DOWNLEFT_RESIZE: return top_level->downleft_resize_cursor;
2805 case DOWNRIGHT_RESIZE: return top_level->downright_resize_cursor;
2806 case HOURGLASS_CURSOR: return top_level->hourglass_cursor;
2807 case TRANSPARENT_CURSOR: return top_level->transparent_cursor;
2808 case GRABBED_CURSOR: return top_level->grabbed_cursor;
2813 void BC_WindowBase::set_cursor(int cursor, int override, int flush)
2815 // inherit cursor from parent
2818 XUndefineCursor(top_level->display, win);
2819 current_cursor = cursor;
2822 // don't change cursor if overridden
2823 if((!top_level->is_hourglass && !is_transparent) ||
2826 XDefineCursor(top_level->display, win, get_cursor_struct(cursor));
2827 if(flush) this->flush();
2830 if(!override) current_cursor = cursor;
2833 void BC_WindowBase::set_x_cursor(int cursor)
2835 temp_cursor = XCreateFontCursor(top_level->display, cursor);
2836 XDefineCursor(top_level->display, win, temp_cursor);
2837 current_cursor = cursor;
2841 int BC_WindowBase::get_cursor()
2843 return current_cursor;
2846 void BC_WindowBase::start_hourglass()
2848 top_level->start_hourglass_recursive();
2852 void BC_WindowBase::stop_hourglass()
2854 top_level->stop_hourglass_recursive();
2858 void BC_WindowBase::start_hourglass_recursive()
2860 if(this == top_level)
2868 set_cursor(HOURGLASS_CURSOR, 1, 0);
2869 for(int i = 0; i < subwindows->total; i++)
2871 subwindows->values[i]->start_hourglass_recursive();
2876 void BC_WindowBase::stop_hourglass_recursive()
2878 if(this == top_level)
2880 if(hourglass_total == 0) return;
2881 top_level->hourglass_total--;
2884 if(!top_level->hourglass_total)
2886 top_level->is_hourglass = 0;
2888 // Cause set_cursor to perform change
2890 set_cursor(current_cursor, 1, 0);
2892 for(int i = 0; i < subwindows->total; i++)
2894 subwindows->values[i]->stop_hourglass_recursive();
2902 XFontStruct* BC_WindowBase::get_font_struct(int font)
2904 // Clear out unrelated flags
2905 if(font & BOLDFACE) font ^= BOLDFACE;
2908 case SMALLFONT: return top_level->smallfont; break;
2909 case MEDIUMFONT: return top_level->mediumfont; break;
2910 case LARGEFONT: return top_level->largefont; break;
2911 case BIGFONT: return top_level->bigfont; break;
2912 case CLOCKFONT: return top_level->clockfont; break;
2917 XFontSet BC_WindowBase::get_fontset(int font)
2921 if(get_resources()->use_fontset)
2923 switch(font & 0xff) {
2924 case SMALLFONT: fs = top_level->smallfontset; break;
2925 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2926 case LARGEFONT: fs = top_level->largefontset; break;
2927 case BIGFONT: fs = top_level->bigfontset; break;
2928 case CLOCKFONT: fs = top_level->clockfontset; break;
2936 XftFont* BC_WindowBase::get_xft_struct(int font)
2939 case SMALLFONT: return (XftFont*)top_level->smallfont_xft;
2940 case MEDIUMFONT: return (XftFont*)top_level->mediumfont_xft;
2941 case LARGEFONT: return (XftFont*)top_level->largefont_xft;
2942 case BIGFONT: return (XftFont*)top_level->bigfont_xft;
2943 case CLOCKFONT: return (XftFont*)top_level->clockfont_xft;
2944 case MEDIUMFONT_3D: return (XftFont*)top_level->bold_mediumfont_xft;
2945 case SMALLFONT_3D: return (XftFont*)top_level->bold_smallfont_xft;
2946 case LARGEFONT_3D: return (XftFont*)top_level->bold_largefont_xft;
2954 int BC_WindowBase::get_current_font()
2956 return top_level->current_font;
2959 void BC_WindowBase::set_font(int font)
2961 top_level->current_font = font;
2964 if(get_resources()->use_xft) {}
2967 if(get_resources()->use_fontset) {
2971 if(get_font_struct(font))
2973 XSetFont(top_level->display, top_level->gc, get_font_struct(font)->fid);
2979 void BC_WindowBase::set_fontset(int font)
2983 if(get_resources()->use_fontset) {
2985 case SMALLFONT: fs = top_level->smallfontset; break;
2986 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2987 case LARGEFONT: fs = top_level->largefontset; break;
2988 case BIGFONT: fs = top_level->bigfontset; break;
2989 case CLOCKFONT: fs = top_level->clockfontset; break;
2997 XFontSet BC_WindowBase::get_curr_fontset(void)
2999 if(get_resources()->use_fontset)
3000 return curr_fontset;
3004 int BC_WindowBase::get_single_text_width(int font, const char *text, int length)
3007 if(get_resources()->use_xft && get_xft_struct(font))
3010 #ifdef X_HAVE_UTF8_STRING
3011 if(get_resources()->locale_utf8)
3013 xftTextExtentsUtf8(top_level->display,
3014 get_xft_struct(font),
3015 (const XftChar8 *)text,
3022 xftTextExtents8(top_level->display,
3023 get_xft_struct(font),
3024 (const XftChar8 *)text,
3028 return extents.xOff;
3032 if(get_resources()->use_fontset && top_level->get_fontset(font))
3033 return XmbTextEscapement(top_level->get_fontset(font), text, length);
3035 if(get_font_struct(font))
3036 return XTextWidth(get_font_struct(font), text, length);
3042 case MEDIUM_7SEGMENT:
3043 return get_resources()->medium_7segment[0]->get_w() * length;
3053 int BC_WindowBase::get_text_width(int font, const char *text, int length)
3055 int i, j, w = 0, line_w = 0;
3056 if(length < 0) length = strlen(text);
3058 for(i = 0, j = 0; i <= length; i++)
3063 line_w = get_single_text_width(font, &text[j], i - j);
3069 line_w = get_single_text_width(font, &text[j], length - j);
3071 if(line_w > w) w = line_w;
3074 if(i > length && w == 0)
3076 w = get_single_text_width(font, text, length);
3082 int BC_WindowBase::get_text_width(int font, const wchr_t *text, int length)
3085 if( length < 0 ) length = wstrlen(text);
3087 for( i=j=0; i<length && text[i]; ++i ) {
3088 if( text[i] != '\n' ) continue;
3090 int lw = get_single_text_width(font, &text[j], i-j);
3091 if( w < lw ) w = lw;
3096 int lw = get_single_text_width(font, &text[j], length-j);
3097 if( w < lw ) w = lw;
3103 int BC_WindowBase::get_text_ascent(int font)
3107 if( (fstruct = get_xft_struct(font)) != 0 )
3108 return fstruct->ascent;
3110 if(get_resources()->use_fontset && top_level->get_fontset(font))
3112 XFontSetExtents *extents;
3114 extents = XExtentsOfFontSet(top_level->get_fontset(font));
3115 return -extents->max_logical_extent.y;
3118 if(get_font_struct(font))
3119 return top_level->get_font_struct(font)->ascent;
3122 case MEDIUM_7SEGMENT:
3123 return get_resources()->medium_7segment[0]->get_h();
3128 int BC_WindowBase::get_text_descent(int font)
3132 if( (fstruct = get_xft_struct(font)) != 0 )
3133 return fstruct->descent;
3135 if(get_resources()->use_fontset && top_level->get_fontset(font)) {
3136 XFontSetExtents *extents;
3137 extents = XExtentsOfFontSet(top_level->get_fontset(font));
3138 return (extents->max_logical_extent.height
3139 + extents->max_logical_extent.y);
3142 if(get_font_struct(font))
3143 return top_level->get_font_struct(font)->descent;
3148 int BC_WindowBase::get_text_height(int font, const char *text)
3153 if( (fstruct = get_xft_struct(font)) != 0 )
3154 rowh = fstruct->height;
3157 rowh = get_text_ascent(font) + get_text_descent(font);
3159 if(!text) return rowh;
3161 // Add height of lines
3162 int h = 0, i, length = strlen(text);
3163 for(i = 0; i <= length; i++)
3174 // truncate the text with ... & return a new string
3175 char *BC_WindowBase::get_truncated_text(int font, const char *text, int max_w)
3177 char *result = cstrdup(text);
3178 int text_w = get_text_width(font, text);
3179 int ci = -1, len = strlen(text);
3180 if( text_w > max_w ) {
3181 // get center of string
3182 int cx = text_w/2, best = INT_MAX;
3183 for( int i=1; i<=len; ++i ) {
3184 int cw = get_text_width(font, text, i);
3185 if( abs(cw-cx) < abs(best-cx) ) {
3190 if( ci > 0 && ci < len-1 ) {
3191 // insert ... in the center
3192 result[ci-1] = result[ci] = result[ci+1] = '.';
3194 while( ci-2>=0 && ci+2<(int)strlen(result) &&
3195 get_text_width(font, result) > max_w ) {
3196 // take away a character from the longer side
3197 int left_w = get_text_width(font, result, ci-2);
3198 int right_w = get_text_width(font, result + ci+3);
3199 int i = left_w > right_w ? --ci-1 : ci+2;
3200 while( (result[i]=result[i+1])!=0 ) ++i;
3207 BC_Bitmap* BC_WindowBase::new_bitmap(int w, int h, int color_model)
3209 if(color_model < 0) color_model = top_level->get_color_model();
3210 return new BC_Bitmap(top_level, w, h, color_model);
3213 void BC_WindowBase::init_wait()
3215 #ifndef SINGLE_THREAD
3216 if(window_type != MAIN_WINDOW)
3217 top_level->init_wait();
3218 init_lock->lock("BC_WindowBase::init_wait");
3219 init_lock->unlock();
3223 int BC_WindowBase::accel_available(int color_model, int lock_it)
3225 if( window_type != MAIN_WINDOW )
3226 return top_level->accel_available(color_model, lock_it);
3228 lock_window("BC_WindowBase::accel_available");
3230 switch(color_model) {
3232 grab_port_id(color_model);
3236 grab_port_id(color_model);
3245 //printf("BC_WindowBase::accel_available %d %d\n", color_model, xvideo_port_id);
3246 return xvideo_port_id >= 0 ? 1 : 0;
3250 int BC_WindowBase::grab_port_id(int color_model)
3253 if( !get_resources()->use_xvideo || // disabled
3254 !get_resources()->use_shm ) // Only local server is fast enough.
3256 if( xvideo_port_id >= 0 )
3257 return xvideo_port_id;
3259 unsigned int ver, rev, reqBase, eventBase, errorBase;
3260 if( Success != XvQueryExtension(display, // XV extension is available
3261 &ver, &rev, &reqBase, &eventBase, &errorBase) )
3264 // XV adaptors are available
3265 unsigned int numAdapt = 0;
3266 XvAdaptorInfo *info = 0;
3267 XvQueryAdaptors(display, DefaultRootWindow(display), &numAdapt, &info);
3271 // Translate from color_model to X color model
3272 int x_color_model = BC_CModels::bc_to_x(color_model);
3274 // Get adaptor with desired color model
3275 for( int i = 0; i < (int)numAdapt && xvideo_port_id == -1; i++) {
3276 if( !(info[i].type & XvImageMask) || !info[i].num_ports ) continue;
3277 // adaptor supports XvImages
3278 int numFormats = 0, numPorts = info[i].num_ports;
3279 XvImageFormatValues *formats =
3280 XvListImageFormats(display, info[i].base_id, &numFormats);
3281 if( !formats ) continue;
3283 for( int j=0; j<numFormats && xvideo_port_id<0; ++j ) {
3284 if( formats[j].id != x_color_model ) continue;
3285 // this adaptor supports the desired format, grab a port
3286 for( int k=0; k<numPorts; ++k ) {
3287 if( Success == XvGrabPort(top_level->display,
3288 info[i].base_id+k, CurrentTime) ) {
3289 //printf("BC_WindowBase::grab_port_id %llx\n", info[i].base_id);
3290 xvideo_port_id = info[i].base_id + k;
3298 XvFreeAdaptorInfo(info);
3299 return xvideo_port_id;
3306 int BC_WindowBase::show_window(int flush)
3308 for(int i = 0; i < subwindows->size(); i++)
3310 subwindows->get(i)->show_window(0);
3313 XMapWindow(top_level->display, win);
3314 if(flush) XFlush(top_level->display);
3315 // XSync(top_level->display, 0);
3320 int BC_WindowBase::hide_window(int flush)
3322 for(int i = 0; i < subwindows->size(); i++)
3324 subwindows->get(i)->hide_window(0);
3327 XUnmapWindow(top_level->display, win);
3328 if(flush) this->flush();
3333 BC_MenuBar* BC_WindowBase::add_menubar(BC_MenuBar *menu_bar)
3335 subwindows->append((BC_SubWindow*)menu_bar);
3337 menu_bar->parent_window = this;
3338 menu_bar->top_level = this->top_level;
3339 menu_bar->initialize();
3343 BC_WindowBase* BC_WindowBase::add_popup(BC_WindowBase *window)
3345 //printf("BC_WindowBase::add_popup window=%p win=%p\n", window, window->win);
3346 if(this != top_level) return top_level->add_popup(window);
3347 popups.append(window);
3351 void BC_WindowBase::remove_popup(BC_WindowBase *window)
3353 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3354 if(this != top_level)
3355 top_level->remove_popup(window);
3357 popups.remove(window);
3358 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3362 BC_WindowBase* BC_WindowBase::add_subwindow(BC_WindowBase *subwindow)
3364 subwindows->append(subwindow);
3366 if(subwindow->bg_color == -1) subwindow->bg_color = this->bg_color;
3368 // parent window must be set before the subwindow initialization
3369 subwindow->parent_window = this;
3370 subwindow->top_level = this->top_level;
3372 // Execute derived initialization
3373 subwindow->initialize();
3378 BC_WindowBase* BC_WindowBase::add_tool(BC_WindowBase *subwindow)
3380 return add_subwindow(subwindow);
3383 int BC_WindowBase::flash(int x, int y, int w, int h, int flush)
3385 if( !top_level->flash_enabled ) return 0;
3386 //printf("BC_WindowBase::flash %d %d %d %d %d\n", __LINE__, w, h, this->w, this->h);
3388 XSetWindowBackgroundPixmap(top_level->display, win, pixmap->opaque_pixmap);
3391 XClearArea(top_level->display, win, x, y, w, h, 0);
3395 XClearWindow(top_level->display, win);
3403 int BC_WindowBase::flash(int flush)
3405 flash(-1, -1, -1, -1, flush);
3409 void BC_WindowBase::flush()
3411 //if(!get_window_lock())
3412 // printf("BC_WindowBase::flush %s not locked\n", top_level->title);
3413 // X gets hosed if Flush/Sync are not user locked (at libX11-1.1.5 / libxcb-1.1.91)
3414 // _XReply deadlocks in condition_wait waiting for xlib lock when waiters!=-1
3415 int locked = get_window_lock();
3416 if( !locked ) lock_window("BC_WindowBase::flush");
3417 XFlush(top_level->display);
3418 if( !locked ) unlock_window();
3421 void BC_WindowBase::sync_display()
3423 int locked = get_window_lock();
3424 if( !locked ) lock_window("BC_WindowBase::sync_display");
3425 XSync(top_level->display, False);
3426 if( !locked ) unlock_window();
3429 int BC_WindowBase::get_window_lock()
3431 #ifdef SINGLE_THREAD
3432 return BC_Display::display_global->get_display_locked();
3434 return top_level->window_lock;
3438 int BC_WindowBase::lock_window(const char *location)
3440 if(top_level && top_level != this)
3442 top_level->lock_window(location);
3447 SET_LOCK(this, title, location);
3448 #ifdef SINGLE_THREAD
3449 BC_Display::lock_display(location);
3451 XLockDisplay(top_level->display);
3452 top_level->display_lock_owner = pthread_self();
3455 ++top_level->window_lock;
3459 printf("BC_WindowBase::lock_window top_level NULL\n");
3464 int BC_WindowBase::unlock_window()
3466 if(top_level && top_level != this)
3468 top_level->unlock_window();
3474 if( !top_level->window_lock ) {
3475 printf("BC_WindowBase::unlock_window %s not locked\n", title);
3478 if( top_level->window_lock > 0 )
3479 if( --top_level->window_lock == 0 )
3480 top_level->display_lock_owner = 0;
3481 #ifdef SINGLE_THREAD
3482 BC_Display::unlock_display();
3484 XUnlockDisplay(top_level->display);
3489 printf("BC_WindowBase::unlock_window top_level NULL\n");
3494 int BC_WindowBase::break_lock()
3496 if( !top_level ) return 0;
3497 if( top_level != this ) return top_level->break_lock();
3498 if( top_level->display_lock_owner != pthread_self() ) return 0;
3499 if( top_level->window_lock != 1 ) return 0;
3502 display_lock_owner = 0;
3503 #ifdef SINGLE_THREAD
3504 BC_Display::unlock_display();
3506 XUnlockDisplay(display);
3511 void BC_WindowBase::set_done(int return_value)
3513 if(done_set) return;
3515 if(window_type != MAIN_WINDOW)
3516 top_level->set_done(return_value);
3519 #ifdef SINGLE_THREAD
3520 this->return_value = return_value;
3521 BC_Display::display_global->arm_completion(this);
3522 completion_lock->unlock();
3523 #else // SINGLE_THREAD
3525 if( !event_thread ) return;
3526 XEvent *event = new_xevent();
3527 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
3528 event->type = ClientMessage;
3529 ptr->message_type = SetDoneXAtom;
3531 this->return_value = return_value;
3532 // May lock up here because XSendEvent doesn't work too well
3533 // asynchronous with XNextEvent.
3534 // This causes BC_WindowEvents to forward a copy of the event to run_window where
3536 // Deletion of event_thread is done at the end of BC_WindowBase::run_window() - by calling the destructor
3542 void BC_WindowBase::close(int return_value)
3544 hide_window(); flush();
3545 set_done(return_value);
3548 int BC_WindowBase::grab(BC_WindowBase *window)
3551 BC_WindowBase *grab_window = window->active_grab;
3553 int locked = get_window_lock();
3554 if( locked ) unlock_window();
3555 grab_window->lock_window("BC_WindowBase::grab(BC_WindowBase");
3556 grab_window->handle_ungrab();
3557 grab_window->unlock_window();
3558 if( locked ) lock_window("BC_WindowBase::grab(BC_WindowBase");
3560 window->grab_lock->lock("BC_WindowBase::grab");
3561 if( !window->active_grab ) {
3562 window->active_grab = this;
3563 this->grab_active = window;
3566 window->grab_lock->unlock();
3569 int BC_WindowBase::ungrab(BC_WindowBase *window)
3572 window->grab_lock->lock("BC_WindowBase::ungrab");
3573 if( this == window->active_grab ) {
3574 window->active_grab = 0;
3575 this->grab_active = 0;
3578 window->grab_lock->unlock();
3581 int BC_WindowBase::grab_event_count()
3584 #ifndef SINGLE_THREAD
3585 result = grab_active->get_event_count();
3589 int BC_WindowBase::grab_buttons()
3591 XSync(top_level->display, False);
3592 if( XGrabButton(top_level->display, AnyButton, AnyModifier,
3593 top_level->rootwin, True, ButtonPressMask | ButtonReleaseMask,
3594 GrabModeAsync, GrabModeSync, None, None) == GrabSuccess ) {
3595 set_active_subwindow(this);
3600 void BC_WindowBase::ungrab_buttons()
3602 XUngrabButton(top_level->display, AnyButton, AnyModifier, top_level->rootwin);
3603 set_active_subwindow(0);
3606 void BC_WindowBase::grab_cursor()
3608 Cursor cursor_grab = get_cursor_struct(GRABBED_CURSOR);
3609 XGrabPointer(top_level->display, top_level->rootwin, True,
3610 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
3611 GrabModeAsync, GrabModeAsync, None, cursor_grab, CurrentTime);
3613 void BC_WindowBase::ungrab_cursor()
3615 XUngrabPointer(top_level->display, CurrentTime);
3619 // WidthOfScreen/HeightOfScreen of XDefaultScreenOfDisplay
3620 // this is the bounding box of all the screens
3622 int BC_WindowBase::get_root_w(int lock_display)
3624 if(lock_display) lock_window("BC_WindowBase::get_root_w");
3625 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3626 int result = WidthOfScreen(def_screen);
3627 if(lock_display) unlock_window();
3631 int BC_WindowBase::get_root_h(int lock_display)
3633 if(lock_display) lock_window("BC_WindowBase::get_root_h");
3634 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3635 int result = HeightOfScreen(def_screen);
3636 if(lock_display) unlock_window();
3640 XineramaScreenInfo *
3641 BC_WindowBase::get_xinerama_info(int screen)
3643 if( !xinerama_info || !xinerama_screens ) return 0;
3645 for( int i=0; i<xinerama_screens; ++i )
3646 if( xinerama_info[i].screen_number == screen )
3647 return &xinerama_info[i];
3650 int top_x = get_x(), top_y = get_y();
3651 if( BC_DisplayInfo::left_border >= 0 ) top_x += BC_DisplayInfo::left_border;
3652 if( BC_DisplayInfo::top_border >= 0 ) top_y += BC_DisplayInfo::top_border;
3653 for( int i=0; i<xinerama_screens; ++i ) {
3654 int scr_y = top_y - xinerama_info[i].y_org;
3655 if( scr_y < 0 || scr_y >= xinerama_info[i].height ) continue;
3656 int scr_x = top_x - xinerama_info[i].x_org;
3657 if( scr_x >= 0 && scr_x < xinerama_info[i].width )
3658 return &xinerama_info[i];
3663 void BC_WindowBase::get_fullscreen_geometry(int &wx, int &wy, int &ww, int &wh)
3665 XineramaScreenInfo *info = top_level->get_xinerama_info(-1);
3667 wx = info->x_org; wy = info->y_org;
3668 ww = info->width; wh = info->height;
3671 wx = get_screen_x(0, -1);
3672 wy = get_screen_y(0, -1);
3673 int scr_w0 = get_screen_w(0, 0);
3674 int root_w = get_root_w(0);
3675 int root_h = get_root_h(0);
3676 if( root_w > scr_w0 ) { // multi-headed
3677 if( wx >= scr_w0 ) {
3678 // assumes right side is the big one
3679 ww = root_w - scr_w0;
3683 // use same aspect ratio to compute left height
3685 wh = (w*root_h) / (root_w-scr_w0);
3695 int BC_WindowBase::get_screen_x(int lock_display, int screen)
3698 if(lock_display) lock_window("BC_WindowBase::get_screen_x");
3699 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3702 int root_w = get_root_w(0);
3703 int root_h = get_root_h(0);
3704 // Shift X based on position of current window if dual head
3705 if( (float)root_w/root_h > 1.8 ) {
3706 root_w = get_screen_w(0, 0);
3707 if( top_level->get_x() >= root_w )
3712 result = info->x_org;
3713 if(lock_display) unlock_window();
3717 int BC_WindowBase::get_screen_y(int lock_display, int screen)
3719 if(lock_display) lock_window("BC_WindowBase::get_screen_y");
3720 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3721 int result = !info ? 0 : info->y_org;
3722 if(lock_display) unlock_window();
3726 int BC_WindowBase::get_screen_w(int lock_display, int screen)
3729 if(lock_display) lock_window("BC_WindowBase::get_screen_w");
3730 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3732 int width = get_root_w(0);
3733 int height = get_root_h(0);
3734 if( (float)width/height > 1.8 ) {
3735 // If dual head, the screen width is > 16x9
3736 // but we only want to fill one screen
3737 // this code assumes the "big" screen is on the right
3738 int scr_w0 = width / 2;
3740 case 600: scr_w0 = 800; break;
3741 case 720: scr_w0 = 1280; break;
3742 case 1024: scr_w0 = 1280; break;
3743 case 1200: scr_w0 = 1600; break;
3744 case 1080: scr_w0 = 1920; break;
3746 int scr_w1 = width - scr_w0;
3747 result = screen > 0 ? scr_w1 :
3748 screen == 0 ? scr_w0 :
3749 top_level->get_x() < scr_w0 ? scr_w0 : scr_w1;
3755 result = info->width;
3756 if(lock_display) unlock_window();
3760 int BC_WindowBase::get_screen_h(int lock_display, int screen)
3762 if(lock_display) lock_window("BC_WindowBase::get_screen_h");
3763 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3764 int result = info ? info->height : get_root_h(0);
3765 if(lock_display) unlock_window();
3769 // Bottom right corner
3770 int BC_WindowBase::get_x2()
3775 int BC_WindowBase::get_y2()
3780 int BC_WindowBase::get_video_on()
3785 int BC_WindowBase::get_hidden()
3787 return top_level->hidden;
3790 int BC_WindowBase::cursor_inside()
3792 return (top_level->cursor_x >= 0 &&
3793 top_level->cursor_y >= 0 &&
3794 top_level->cursor_x < w &&
3795 top_level->cursor_y < h);
3798 BC_WindowBase* BC_WindowBase::get_top_level()
3803 BC_WindowBase* BC_WindowBase::get_parent()
3805 return parent_window;
3808 int BC_WindowBase::get_color_model()
3810 return top_level->color_model;
3813 BC_Resources* BC_WindowBase::get_resources()
3815 return BC_WindowBase::resources;
3818 BC_Synchronous* BC_WindowBase::get_synchronous()
3820 return BC_WindowBase::resources->get_synchronous();
3823 int BC_WindowBase::get_bg_color()
3828 void BC_WindowBase::set_bg_color(int color)
3830 this->bg_color = color;
3833 BC_Pixmap* BC_WindowBase::get_bg_pixmap()
3838 void BC_WindowBase::set_active_subwindow(BC_WindowBase *subwindow)
3840 top_level->active_subwindow = subwindow;
3843 int BC_WindowBase::activate()
3848 int BC_WindowBase::deactivate()
3850 if(window_type == MAIN_WINDOW)
3852 if( top_level->active_menubar ) {
3853 top_level->active_menubar->deactivate();
3854 top_level->active_menubar = 0;
3856 if( top_level->active_popup_menu ) {
3857 top_level->active_popup_menu->deactivate();
3858 top_level->active_popup_menu = 0;
3860 if( top_level->active_subwindow ) {
3861 top_level->active_subwindow->deactivate();
3862 top_level->active_subwindow = 0;
3864 if( top_level->motion_events && top_level->last_motion_win == this->win )
3865 top_level->motion_events = 0;
3871 int BC_WindowBase::cycle_textboxes(int amount)
3874 BC_WindowBase *new_textbox = 0;
3878 BC_WindowBase *first_textbox = 0;
3879 find_next_textbox(&first_textbox, &new_textbox, result);
3880 if(!new_textbox) new_textbox = first_textbox;
3886 BC_WindowBase *last_textbox = 0;
3887 find_prev_textbox(&last_textbox, &new_textbox, result);
3888 if(!new_textbox) new_textbox = last_textbox;
3892 if(new_textbox != active_subwindow)
3895 new_textbox->activate();
3901 int BC_WindowBase::find_next_textbox(BC_WindowBase **first_textbox, BC_WindowBase **next_textbox, int &result)
3903 // Search subwindows for textbox
3904 for(int i = 0; i < subwindows->total && result < 2; i++)
3906 BC_WindowBase *test_subwindow = subwindows->values[i];
3907 test_subwindow->find_next_textbox(first_textbox, next_textbox, result);
3914 if(!*first_textbox) *first_textbox = this;
3918 if(top_level->active_subwindow == this)
3924 *next_textbox = this;
3931 int BC_WindowBase::find_prev_textbox(BC_WindowBase **last_textbox, BC_WindowBase **prev_textbox, int &result)
3937 if(!*last_textbox) *last_textbox = this;
3941 if(top_level->active_subwindow == this)
3947 *prev_textbox = this;
3952 // Search subwindows for textbox
3953 for(int i = subwindows->total - 1; i >= 0 && result < 2; i--)
3955 BC_WindowBase *test_subwindow = subwindows->values[i];
3956 test_subwindow->find_prev_textbox(last_textbox, prev_textbox, result);
3961 BC_Clipboard* BC_WindowBase::get_clipboard()
3963 #ifdef SINGLE_THREAD
3964 return BC_Display::display_global->clipboard;
3966 return top_level->clipboard;
3970 Atom BC_WindowBase::to_clipboard(const char *data, long len, int clipboard_num)
3972 return get_clipboard()->to_clipboard(this, data, len, clipboard_num);
3975 long BC_WindowBase::from_clipboard(char *data, long maxlen, int clipboard_num)
3977 return get_clipboard()->from_clipboard(data, maxlen, clipboard_num);
3980 long BC_WindowBase::clipboard_len(int clipboard_num)
3982 return get_clipboard()->clipboard_len(clipboard_num);
3985 int BC_WindowBase::do_selection_clear(Window win)
3987 top_level->event_win = win;
3988 return dispatch_selection_clear();
3991 int BC_WindowBase::dispatch_selection_clear()
3994 for( int i=0; i<subwindows->total && !result; ++i )
3995 result = subwindows->values[i]->dispatch_selection_clear();
3997 result = selection_clear_event();
4002 void BC_WindowBase::get_relative_cursor(int &x, int &y, int lock_window)
4004 int abs_x, abs_y, win_x, win_y;
4005 unsigned int temp_mask;
4008 if(lock_window) this->lock_window("BC_WindowBase::get_relative_cursor");
4009 XQueryPointer(top_level->display, top_level->win,
4010 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
4013 XTranslateCoordinates(top_level->display, top_level->rootwin,
4014 win, abs_x, abs_y, &x, &y, &temp_win);
4015 if(lock_window) this->unlock_window();
4017 int BC_WindowBase::get_relative_cursor_x(int lock_window)
4020 get_relative_cursor(x, y, lock_window);
4023 int BC_WindowBase::get_relative_cursor_y(int lock_window)
4026 get_relative_cursor(x, y, lock_window);
4030 void BC_WindowBase::get_abs_cursor(int &abs_x, int &abs_y, int lock_window)
4033 unsigned int temp_mask;
4036 if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor");
4037 XQueryPointer(top_level->display, top_level->win,
4038 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
4040 if(lock_window) this->unlock_window();
4042 int BC_WindowBase::get_abs_cursor_x(int lock_window)
4045 get_abs_cursor(abs_x, abs_y, lock_window);
4048 int BC_WindowBase::get_abs_cursor_y(int lock_window)
4051 get_abs_cursor(abs_x, abs_y, lock_window);
4055 void BC_WindowBase::get_pop_cursor(int &px, int &py, int lock_window)
4057 int xmargin = xS(100), ymargin = yS(100);
4058 get_abs_cursor(px, py, lock_window);
4059 if( px < xmargin ) px = xmargin;
4060 if( py < ymargin ) py = ymargin;
4061 int wd = get_screen_x(lock_window,-1) + get_screen_w(lock_window,-1) - xmargin;
4062 if( px > wd ) px = wd;
4063 int ht = get_screen_y(lock_window,-1) + get_screen_h(lock_window,-1) - ymargin;
4064 if( py > ht ) py = ht;
4066 int BC_WindowBase::get_pop_cursor_x(int lock_window)
4069 get_pop_cursor(px, py, lock_window);
4072 int BC_WindowBase::get_pop_cursor_y(int lock_window)
4075 get_pop_cursor(px, py, lock_window);
4079 int BC_WindowBase::match_window(Window win)
4081 if (this->win == win) return 1;
4083 for(int i = 0; i < subwindows->total; i++) {
4084 result = subwindows->values[i]->match_window(win);
4085 if (result) return result;
4091 int BC_WindowBase::get_cursor_over_window()
4093 int abs_x, abs_y, win_x, win_y;
4094 unsigned int mask_return;
4095 Window root_return, child_return;
4097 int ret = XQueryPointer(top_level->display, top_level->rootwin,
4098 &root_return, &child_return, &abs_x, &abs_y,
4099 &win_x, &win_y, &mask_return);
4100 if( ret && child_return == None ) ret = 0;
4101 if( ret && win != child_return )
4102 ret = top_level->match_window(child_return);
4103 // query pointer can return a window manager window with this top_level as a child
4104 // for kde this can be two levels deep
4105 unsigned int nchildren_return = 0;
4106 Window parent_return, *children_return = 0;
4107 Window top_win = top_level->win;
4108 while( !ret && top_win != top_level->rootwin && top_win != root_return &&
4109 XQueryTree(top_level->display, top_win, &root_return,
4110 &parent_return, &children_return, &nchildren_return) ) {
4111 if( children_return ) XFree(children_return);
4112 if( (top_win=parent_return) == child_return ) ret = 1;
4117 int BC_WindowBase::cursor_above()
4120 get_relative_cursor(rx, ry);
4121 return rx < 0 || rx >= get_w() ||
4122 ry < 0 || ry >= get_h() ? 0 : 1;
4125 int BC_WindowBase::get_drag_x()
4127 return top_level->drag_x;
4130 int BC_WindowBase::get_drag_y()
4132 return top_level->drag_y;
4135 int BC_WindowBase::get_cursor_x()
4137 return top_level->cursor_x;
4140 int BC_WindowBase::get_cursor_y()
4142 return top_level->cursor_y;
4145 int BC_WindowBase::dump_windows()
4147 printf("\tBC_WindowBase::dump_windows window=%p win=%p '%s', %dx%d+%d+%d %s\n",
4148 this, (void*)this->win, title, w,h,x,y, typeid(*this).name());
4149 for(int i = 0; i < subwindows->size(); i++)
4150 subwindows->get(i)->dump_windows();
4151 for(int i = 0; i < popups.size(); i++) {
4152 BC_WindowBase *p = popups[i];
4153 printf("\tBC_WindowBase::dump_windows popup=%p win=%p '%s', %dx%d+%d+%d %s\n",
4154 p, (void*)p->win, p->title, p->w,p->h,p->x,p->y, typeid(*p).name());
4159 int BC_WindowBase::is_event_win()
4161 return this->win == top_level->event_win;
4164 int BC_WindowBase::is_tooltip_event_win()
4166 return this->win == top_level->event_win ||
4167 tooltip_popup && tooltip_popup->win == top_level->event_win;
4170 void BC_WindowBase::set_dragging(int value)
4172 is_dragging = value;
4175 int BC_WindowBase::get_dragging()
4180 int BC_WindowBase::get_buttonpress()
4182 return top_level->button_number;
4185 int BC_WindowBase::get_button_down()
4187 return top_level->button_down;
4190 int BC_WindowBase::alt_down()
4192 return top_level->alt_mask;
4195 int BC_WindowBase::shift_down()
4197 return top_level->shift_mask;
4200 int BC_WindowBase::ctrl_down()
4202 return top_level->ctrl_mask;
4205 wchr_t* BC_WindowBase::get_wkeystring(int *length)
4208 *length = top_level->wkey_string_length;
4209 return top_level->wkey_string;
4212 #ifdef X_HAVE_UTF8_STRING
4213 char* BC_WindowBase::get_keypress_utf8()
4215 return top_level->key_pressed_utf8;
4220 int BC_WindowBase::get_keypress()
4222 return top_level->key_pressed;
4225 int BC_WindowBase::get_double_click()
4227 return top_level->double_click;
4230 int BC_WindowBase::get_triple_click()
4232 return top_level->triple_click;
4235 int BC_WindowBase::get_bgcolor()
4240 int BC_WindowBase::resize_window(int w, int h)
4242 if(this->w == w && this->h == h) return 0;
4244 if(window_type == MAIN_WINDOW && !allow_resize)
4246 XSizeHints size_hints;
4247 size_hints.flags = PSize | PMinSize | PMaxSize;
4248 size_hints.width = w;
4249 size_hints.height = h;
4250 size_hints.min_width = w;
4251 size_hints.max_width = w;
4252 size_hints.min_height = h;
4253 size_hints.max_height = h;
4254 if( this->x > -BC_INFINITY && this->x < BC_INFINITY ) {
4255 size_hints.flags |= PPosition;
4256 size_hints.x = this->x;
4257 size_hints.y = this->y;
4259 XSetNormalHints(top_level->display, win, &size_hints);
4261 XResizeWindow(top_level->display, win, w, h);
4266 pixmap = new BC_Pixmap(this, w, h);
4268 // Propagate to menubar
4269 for(int i = 0; i < subwindows->total; i++)
4271 subwindows->values[i]->dispatch_resize_event(w, h);
4274 draw_background(0, 0, w, h);
4275 if(top_level == this && get_resources()->recursive_resizing)
4276 resize_history.append(new BC_ResizeCall(w, h));
4280 // The only way for resize events to be propagated is by updating the internal w and h
4281 int BC_WindowBase::resize_event(int w, int h)
4283 if(window_type == MAIN_WINDOW)
4291 int BC_WindowBase::reposition_window(int x, int y)
4293 reposition_window(x, y, -1, -1);
4298 int BC_WindowBase::reposition_window(int x, int y, int w, int h)
4302 // Some tools set their own dimensions before calling this, causing the
4303 // resize check to skip.
4307 if(w > 0 && w != this->w)
4313 if(h > 0 && h != this->h)
4319 //printf("BC_WindowBase::reposition_window %d %d %d\n", translation_count, x_correction, y_correction);
4322 printf("BC_WindowBase::reposition_window this->w == %d\n", this->w);
4324 printf("BC_WindowBase::reposition_window this->h == %d\n", this->h);
4326 if(translation_count && window_type == MAIN_WINDOW)
4328 // KDE shifts window right and down.
4329 // FVWM leaves window alone and adds border around it.
4330 XMoveResizeWindow(top_level->display, win,
4331 x - BC_DisplayInfo::auto_reposition_x,
4332 y - BC_DisplayInfo::auto_reposition_y,
4337 XMoveResizeWindow(top_level->display, win, x, y,
4344 pixmap = new BC_Pixmap(this, this->w, this->h);
4345 clear_box(0,0, this->w, this->h);
4346 // Propagate to menubar
4347 for(int i = 0; i < subwindows->total; i++)
4349 subwindows->values[i]->dispatch_resize_event(this->w, this->h);
4352 // draw_background(0, 0, w, h);
4358 int BC_WindowBase::reposition_window_relative(int dx, int dy, int w, int h)
4360 return reposition_window(get_x()+dx, get_y()+dy, w, h);
4363 int BC_WindowBase::reposition_window_relative(int dx, int dy)
4365 return reposition_window_relative(dx, dy, -1, -1);
4368 void BC_WindowBase::set_tooltips(int v)
4370 get_resources()->tooltips_enabled = v;
4373 void BC_WindowBase::set_force_tooltip(int v)
4378 int BC_WindowBase::raise_window(int do_flush)
4380 if( hidden ) return 1;
4381 if( wait_viewable(500) ) return 1;
4382 XRaiseWindow(top_level->display, win);
4383 if(do_flush) XFlush(top_level->display);
4387 int BC_WindowBase::lower_window(int do_flush)
4389 XLowerWindow(top_level->display, win);
4390 if(do_flush) XFlush(top_level->display);
4394 void BC_WindowBase::set_background(VFrame *bitmap)
4396 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
4398 bg_pixmap = new BC_Pixmap(this, bitmap, PIXMAP_OPAQUE);
4399 shared_bg_pixmap = 0;
4400 draw_background(0, 0, w, h);
4403 void BC_WindowBase::put_title(const char *text)
4405 char *cp = this->title, *ep = cp+sizeof(this->title)-1;
4406 for( const unsigned char *bp = (const unsigned char *)text; *bp && cp<ep; ++bp )
4407 *cp++ = *bp >= ' ' ? *bp : ' ';
4411 void BC_WindowBase::set_title(const char *text, int utf8)
4413 // utf8>0: wm + net_wm, utf8=0: wm only, utf<0: net_wm only
4415 const unsigned char *wm_title = (const unsigned char *)title;
4416 int title_len = strlen((const char *)title);
4418 Atom xa_wm_name = XA_WM_NAME;
4419 Atom xa_icon_name = XA_WM_ICON_NAME;
4420 Atom xa_string = XA_STRING;
4421 XChangeProperty(display, win, xa_wm_name, xa_string, 8,
4422 PropModeReplace, wm_title, title_len);
4423 XChangeProperty(display, win, xa_icon_name, xa_string, 8,
4424 PropModeReplace, wm_title, title_len);
4427 Atom xa_net_wm_name = XInternAtom(display, "_NET_WM_NAME", True);
4428 Atom xa_net_icon_name = XInternAtom(display, "_NET_WM_ICON_NAME", True);
4429 Atom xa_utf8_string = XInternAtom(display, "UTF8_STRING", True);
4430 XChangeProperty(display, win, xa_net_wm_name, xa_utf8_string, 8,
4431 PropModeReplace, wm_title, title_len);
4432 XChangeProperty(display, win, xa_net_icon_name, xa_utf8_string, 8,
4433 PropModeReplace, wm_title, title_len);
4439 void BC_WindowBase::set_net_icon(VFrame *data)
4441 int width = data->get_w(), height = data->get_h();
4442 int size = 2 + width * height;
4443 unsigned long *icon_data = new unsigned long[size];
4444 unsigned long *lp = icon_data;
4445 *lp++ = width; *lp++ = height;
4446 uint8_t **rows = data->get_rows();
4447 for( int y=0; y<height; ++y ) {
4448 unsigned *up = (unsigned *)rows[y];
4449 for( int x=0; x<width; ++x )
4450 *lp++ = *(unsigned *)up++;
4452 Atom NetWMIcon = XInternAtom(display, "_NET_WM_ICON", True);
4453 XChangeProperty(top_level->display, top_level->win, NetWMIcon,
4454 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)icon_data, size);
4455 delete [] icon_data;
4458 const char *BC_WindowBase::get_title()
4463 int BC_WindowBase::get_toggle_value()
4465 return toggle_value;
4468 int BC_WindowBase::get_toggle_drag()
4473 int BC_WindowBase::set_icon(VFrame *data)
4475 if(icon_pixmap) delete icon_pixmap;
4476 icon_pixmap = new BC_Pixmap(top_level, data, PIXMAP_ALPHA, 1);
4478 if(icon_window) delete icon_window;
4479 icon_window = new BC_Popup(this, 0, 0,
4480 icon_pixmap->get_w(), icon_pixmap->get_h(),
4481 -1, 1, // All windows are hidden initially
4484 XWMHints wm_hints; memset(&wm_hints, 0, sizeof(wm_hints));
4485 wm_hints.flags = IconPixmapHint; // | IconMaskHint | IconWindowHint;
4486 wm_hints.icon_pixmap = icon_pixmap->get_pixmap();
4487 wm_hints.icon_mask = icon_pixmap->get_alpha();
4488 wm_hints.icon_window = icon_window->win;
4489 if( XGroupLeader ) {
4490 wm_hints.flags |= WindowGroupHint;
4491 wm_hints.window_group = XGroupLeader;
4494 // for(int i = 0; i < 1000; i++)
4495 // printf("02x ", icon_pixmap->get_alpha()->get_row_pointers()[0][i]);
4498 XSetWMHints(top_level->display, top_level->win, &wm_hints);
4501 XSync(top_level->display, 0);
4505 void BC_WindowBase::init_resources(float scale)
4507 if( resources ) return;
4509 const char *env = getenv("BC_SCALE");
4510 if( env ) scale = atof(env);
4511 float x_scale = 1, y_scale = 1;
4513 BC_DisplayInfo info;
4515 int cins = info.xinerama_big_screen();
4516 if( !info.xinerama_geometry(cins, wx, wy, ww, wh) ) {
4517 int sh = ww * 9 / 16;
4518 int sw = wh * 16 / 9;
4519 if( sw < ww ) ww = sw;
4520 if( sh < wh ) wh = sh;
4521 if( (x_scale = ww/1920.) < 1 ) x_scale = 1;
4522 if( (y_scale = wh/1080.) < 1 ) y_scale = 1;
4526 x_scale = y_scale = scale;
4527 // constructor sets BC_WindowBase::resources
4528 new BC_Resources(x_scale, y_scale);
4530 void BC_WindowBase::finit_resources()
4532 delete resources; resources = 0;
4535 int BC_WindowBase::set_w(int w)
4541 int BC_WindowBase::set_h(int h)
4547 int BC_WindowBase::load_defaults(BC_Hash *defaults)
4549 char string[BCTEXTLEN];
4550 int newest_id = - 1;
4551 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4553 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4554 resources->filebox_history[i].path[0] = 0;
4555 defaults->get(string, resources->filebox_history[i].path);
4556 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4557 resources->filebox_history[i].id = defaults->get(string, resources->get_id());
4558 if(resources->filebox_history[i].id > newest_id)
4559 newest_id = resources->filebox_history[i].id;
4562 resources->filebox_id = newest_id + 1;
4563 resources->filebox_mode = defaults->get("FILEBOX_MODE", get_resources()->filebox_mode);
4564 resources->filebox_w = defaults->get("FILEBOX_W", get_resources()->filebox_w);
4565 resources->filebox_h = defaults->get("FILEBOX_H", get_resources()->filebox_h);
4566 resources->filebox_columntype[0] = defaults->get("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4567 resources->filebox_columntype[1] = defaults->get("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4568 resources->filebox_columntype[2] = defaults->get("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4569 resources->filebox_columntype[3] = defaults->get("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4570 resources->filebox_columnwidth[0] = defaults->get("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4571 resources->filebox_columnwidth[1] = defaults->get("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4572 resources->filebox_columnwidth[2] = defaults->get("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4573 resources->filebox_columnwidth[3] = defaults->get("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4574 resources->filebox_size_format = defaults->get("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4575 defaults->get("FILEBOX_FILTER", resources->filebox_filter);
4579 int BC_WindowBase::save_defaults(BC_Hash *defaults)
4581 char string[BCTEXTLEN];
4582 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4584 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4585 defaults->update(string, resources->filebox_history[i].path);
4586 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4587 defaults->update(string, resources->filebox_history[i].id);
4589 defaults->update("FILEBOX_MODE", resources->filebox_mode);
4590 defaults->update("FILEBOX_W", resources->filebox_w);
4591 defaults->update("FILEBOX_H", resources->filebox_h);
4592 defaults->update("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4593 defaults->update("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4594 defaults->update("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4595 defaults->update("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4596 defaults->update("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4597 defaults->update("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4598 defaults->update("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4599 defaults->update("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4600 defaults->update("FILEBOX_FILTER", resources->filebox_filter);
4601 defaults->update("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4607 // For some reason XTranslateCoordinates can take a long time to return.
4608 // We work around this by only calling it when the event windows are different.
4609 void BC_WindowBase::translate_coordinates(Window src_w, Window dest_w,
4610 int src_x, int src_y, int *dest_x_return, int *dest_y_return)
4617 *dest_x_return = src_x;
4618 *dest_y_return = src_y;
4622 XTranslateCoordinates(top_level->display, src_w, dest_w,
4623 src_x, src_y, dest_x_return, dest_y_return, &tempwin);
4624 //printf("BC_WindowBase::translate_coordinates 1 %lld\n", timer.get_difference());
4628 void BC_WindowBase::get_root_coordinates(int x, int y, int *abs_x, int *abs_y)
4630 translate_coordinates(win, top_level->rootwin, x, y, abs_x, abs_y);
4633 void BC_WindowBase::get_win_coordinates(int abs_x, int abs_y, int *x, int *y)
4635 translate_coordinates(top_level->rootwin, win, abs_x, abs_y, x, y);
4639 #ifdef HAVE_LIBXXF86VM
4640 void BC_WindowBase::closest_vm(int *vm, int *width, int *height)
4644 if(XF86VidModeQueryExtension(top_level->display,&foo,&bar)) {
4646 XF86VidModeModeInfo **vm_modelines;
4647 XF86VidModeGetAllModeLines(top_level->display,
4648 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4649 for( i = 0; i < vm_count; i++ ) {
4650 if( vm_modelines[i]->hdisplay < vm_modelines[*vm]->hdisplay &&
4651 vm_modelines[i]->hdisplay >= *width )
4654 display = top_level->display;
4655 if( vm_modelines[*vm]->hdisplay == *width )
4658 *width = vm_modelines[*vm]->hdisplay;
4659 *height = vm_modelines[*vm]->vdisplay;
4664 void BC_WindowBase::scale_vm(int vm)
4666 int foo,bar,dotclock;
4667 if( XF86VidModeQueryExtension(top_level->display,&foo,&bar) ) {
4669 XF86VidModeModeInfo **vm_modelines;
4670 XF86VidModeModeLine vml;
4671 XF86VidModeGetAllModeLines(top_level->display,
4672 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4673 XF86VidModeGetModeLine(top_level->display,
4674 XDefaultScreen(top_level->display), &dotclock,&vml);
4675 orig_modeline.dotclock = dotclock;
4676 orig_modeline.hdisplay = vml.hdisplay;
4677 orig_modeline.hsyncstart = vml.hsyncstart;
4678 orig_modeline.hsyncend = vml.hsyncend;
4679 orig_modeline.htotal = vml.htotal;
4680 orig_modeline.vdisplay = vml.vdisplay;
4681 orig_modeline.vsyncstart = vml.vsyncstart;
4682 orig_modeline.vsyncend = vml.vsyncend;
4683 orig_modeline.vtotal = vml.vtotal;
4684 orig_modeline.flags = vml.flags;
4685 orig_modeline.privsize = vml.privsize;
4686 // orig_modeline.private = vml.private;
4687 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),vm_modelines[vm]);
4688 XF86VidModeSetViewPort(top_level->display,XDefaultScreen(top_level->display),0,0);
4689 XFlush(top_level->display);
4693 void BC_WindowBase::restore_vm()
4695 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),&orig_modeline);
4696 XFlush(top_level->display);
4701 #ifndef SINGLE_THREAD
4702 int BC_WindowBase::get_event_count()
4704 event_lock->lock("BC_WindowBase::get_event_count");
4705 int result = common_events.total;
4706 event_lock->unlock();
4710 XEvent* BC_WindowBase::get_event()
4713 while(!done && !result)
4715 event_condition->lock("BC_WindowBase::get_event");
4716 event_lock->lock("BC_WindowBase::get_event");
4718 if(common_events.total && !done)
4720 result = common_events.values[0];
4721 common_events.remove_number(0);
4724 event_lock->unlock();
4729 void BC_WindowBase::put_event(XEvent *event)
4731 event_lock->lock("BC_WindowBase::put_event");
4732 common_events.append(event);
4733 event_lock->unlock();
4734 event_condition->unlock();
4737 void BC_WindowBase::dequeue_events(Window win)
4739 event_lock->lock("BC_WindowBase::dequeue_events");
4741 int out = 0, total = common_events.size();
4742 for( int in=0; in<total; ++in ) {
4743 if( common_events[in]->xany.window == win ) continue;
4744 common_events[out++] = common_events[in];
4746 common_events.total = out;
4748 event_lock->unlock();
4751 int BC_WindowBase::resend_event(BC_WindowBase *window)
4753 if( resend_event_window ) return 1;
4754 resend_event_window = window;
4760 int BC_WindowBase::resend_event(BC_WindowBase *window)
4765 #endif // SINGLE_THREAD
4767 int BC_WindowBase::get_id()
4773 BC_Pixmap *BC_WindowBase::create_pixmap(VFrame *vframe)
4775 int w = vframe->get_w(), h = vframe->get_h();
4776 BC_Pixmap *icon = new BC_Pixmap(this, w, h);
4777 icon->draw_vframe(vframe, 0,0, w,h, 0,0);
4782 void BC_WindowBase::flicker(int n, int ms)
4784 int color = get_bg_color();
4785 for( int i=2*n; --i>=0; ) {
4786 set_inverse(); set_bg_color(WHITE);
4787 clear_box(0,0, w,h); flash(1);
4788 sync_display(); Timer::delay(ms);
4790 set_bg_color(color);
4794 void BC_WindowBase::focus()
4796 XWindowAttributes xwa;
4797 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4798 if( xwa.map_state == IsViewable )
4799 XSetInputFocus(top_level->display, top_level->win, RevertToParent, CurrentTime);
4802 int BC_WindowBase::wait_viewable(int ms)
4805 XWindowAttributes xwa;
4807 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4808 if( xwa.map_state == IsViewable ) return 0;
4810 } while( timer.get_difference() < ms );