4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "bcclipboard.h"
24 #include "bcdisplay.h"
25 #include "bcdisplayinfo.h"
26 #include "bcmenubar.h"
29 #include "bcpopupmenu.h"
30 #include "bcrepeater.h"
31 #include "bcresources.h"
32 #include "bcsignals.h"
33 #include "bcsubwindow.h"
34 #include "bcsynchronous.h"
36 #include "bcwindowbase.h"
37 #include "bcwindowevents.h"
38 #include "bccmodels.h"
40 #include "condition.h"
49 #include "workarounds.h"
59 #include <X11/extensions/Xinerama.h>
61 #include <X11/extensions/Xvlib.h>
63 #include <X11/extensions/shape.h>
64 #include <X11/XF86keysym.h>
65 #include <X11/Sunkeysym.h>
67 BC_ResizeCall::BC_ResizeCall(int w, int h)
74 int BC_WindowBase::shm_completion_event = -1;
75 BC_Resources *BC_WindowBase::resources = 0;
76 Window XGroupLeader = 0;
78 Mutex BC_KeyboardHandlerLock::keyboard_listener_mutex("keyboard_listener",0);
79 ArrayList<BC_KeyboardHandler*> BC_KeyboardHandler::listeners;
81 BC_WindowBase::BC_WindowBase()
83 //printf("BC_WindowBase::BC_WindowBase 1\n");
84 BC_WindowBase::initialize();
87 BC_WindowBase::~BC_WindowBase()
90 BC_Display::lock_display("BC_WindowBase::~BC_WindowBase");
92 if(window_type == MAIN_WINDOW)
93 lock_window("BC_WindowBase::~BC_WindowBase");
96 #ifdef HAVE_LIBXXF86VM
97 if(window_type == VIDMODE_SCALED_WINDOW && vm_switched) {
104 if(window_type != MAIN_WINDOW)
107 XSelectInput(top_level->display, this->win, 0);
108 XSync(top_level->display,0);
109 #ifndef SINGLE_THREAD
110 top_level->dequeue_events(win);
112 // drop active window refs to this
113 if(top_level->active_menubar == this) top_level->active_menubar = 0;
114 if(top_level->active_popup_menu == this) top_level->active_popup_menu = 0;
115 if(top_level->active_subwindow == this) top_level->active_subwindow = 0;
116 // drop motion window refs to this
117 if(top_level->motion_events && top_level->last_motion_win == this->win)
118 top_level->motion_events = 0;
120 // Remove pointer from parent window to this
121 parent_window->subwindows->remove(this);
124 if(grab_active) grab_active->active_grab = 0;
125 if(icon_window) delete icon_window;
126 if(window_type == POPUP_WINDOW)
127 parent_window->remove_popup(this);
129 // Delete the subwindows
132 while(subwindows->total)
134 // Subwindow removes its own pointer
135 delete subwindows->values[0];
142 //printf("delete glx=%08x, win=%08x %s\n", (unsigned)glx_win, (unsigned)win, title);
144 if( get_resources()->get_synchronous() && glx_win != 0 ) {
145 if( window_type == MAIN_WINDOW )
147 get_resources()->get_synchronous()->delete_window(this);
148 if( window_type == MAIN_WINDOW )
149 lock_window("BC_WindowBase::delete_window");
152 XDestroyWindow(top_level->display, win);
154 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
155 if(icon_pixmap) delete icon_pixmap;
156 if(temp_bitmap) delete temp_bitmap;
157 top_level->active_bitmaps.remove_buffers(this);
158 if(_7segment_pixmaps)
160 for(int i = 0; i < TOTAL_7SEGMENT; i++)
161 delete _7segment_pixmaps[i];
163 delete [] _7segment_pixmaps;
168 if(window_type == MAIN_WINDOW)
170 XFreeGC(display, gc);
171 static XFontStruct *BC_WindowBase::*xfont[] = {
172 &BC_WindowBase::smallfont,
173 &BC_WindowBase::mediumfont,
174 &BC_WindowBase::largefont,
175 &BC_WindowBase::bigfont,
176 &BC_WindowBase::clockfont,
178 for( int i=sizeof(xfont)/sizeof(xfont[0]); --i>=0; )
179 XFreeFont(display, this->*xfont[i]);
182 // prevents a bug when Xft closes with unrefd fonts
183 FcPattern *defaults = FcPatternCreate();
184 FcPatternAddInteger(defaults, "maxunreffonts", 0);
185 XftDefaultSet(display, defaults);
187 static void *BC_WindowBase::*xft_font[] = {
188 &BC_WindowBase::smallfont_xft,
189 &BC_WindowBase::mediumfont_xft,
190 &BC_WindowBase::largefont_xft,
191 &BC_WindowBase::bigfont_xft,
192 &BC_WindowBase::bold_smallfont_xft,
193 &BC_WindowBase::bold_mediumfont_xft,
194 &BC_WindowBase::bold_largefont_xft,
195 &BC_WindowBase::clockfont_xft,
197 for( int i=sizeof(xft_font)/sizeof(xft_font[0]); --i>=0; ) {
198 XftFont *xft = (XftFont *)(this->*xft_font[i]);
199 if( xft ) xftFontClose (display, xft);
207 XFree(xinerama_info);
208 xinerama_screens = 0;
211 if( xvideo_port_id >= 0 )
212 XvUngrabPort(display, xvideo_port_id, CurrentTime);
215 // Must be last reference to display.
216 // _XftDisplayInfo needs a lock.
217 get_resources()->create_window_lock->lock("BC_WindowBase::~BC_WindowBase");
218 XCloseDisplay(display);
219 get_resources()->create_window_lock->unlock();
221 // clipboard uses a different display connection
222 clipboard->stop_clipboard();
226 resize_history.remove_all_objects();
229 #ifndef SINGLE_THREAD
230 common_events.remove_all_objects();
232 delete event_condition;
235 top_level->window_lock = 0;
236 BC_Display::unlock_display();
241 if( glx_fbcfgs_window ) XFree(glx_fbcfgs_window);
242 if( glx_fbcfgs_pbuffer) XFree(glx_fbcfgs_pbuffer);
243 if( glx_fbcfgs_pixmap ) XFree(glx_fbcfgs_pixmap);
246 UNSET_ALL_LOCKS(this)
249 int BC_WindowBase::initialize()
254 display_lock_owner = 0;
257 context_help_keyword[0] = 0;
260 resend_event_window = 0;
272 xinerama_screens = 0;
277 translation_events = 0;
278 ctrl_mask = shift_mask = alt_mask = 0;
279 cursor_x = cursor_y = button_number = 0;
293 active_popup_menu = 0;
294 active_subwindow = 0;
298 _7segment_pixmaps = 0;
301 // next_repeat_id = 0;
303 current_font = MEDIUMFONT;
304 current_color = BLACK;
305 current_cursor = ARROW_CURSOR;
308 shared_bg_pixmap = 0;
311 window_type = MAIN_WINDOW;
312 translation_count = 0;
313 x_correction = y_correction = 0;
322 #ifdef HAVE_LIBXXF86VM
340 bold_smallfont_xft = 0;
341 bold_mediumfont_xft = 0;
342 bold_largefont_xft = 0;
344 completion_lock = new Condition(0, "BC_WindowBase::completion_lock");
346 // Need these right away since put_event is called before run_window sometimes.
347 event_lock = new Mutex("BC_WindowBase::event_lock");
348 event_condition = new Condition(0, "BC_WindowBase::event_condition");
349 init_lock = new Condition(0, "BC_WindowBase::init_lock");
351 grab_lock = new Mutex("BC_WindowBase::grab_lock");
353 cursor_timer = new Timer;
356 glx_fbcfgs_window = 0; n_fbcfgs_window = 0;
357 glx_fbcfgs_pbuffer = 0; n_fbcfgs_pbuffer = 0;
358 glx_fbcfgs_pixmap = 0; n_fbcfgs_pixmap = 0;
372 #define DEFAULT_EVENT_MASKS EnterWindowMask | \
375 ButtonReleaseMask | \
376 PointerMotionMask | \
380 int BC_WindowBase::create_window(BC_WindowBase *parent_window, const char *title,
381 int x, int y, int w, int h, int minw, int minh, int allow_resize,
382 int private_color, int hide, int bg_color, const char *display_name,
383 int window_type, BC_Pixmap *bg_pixmap, int group_it)
385 XSetWindowAttributes attr;
387 XSizeHints size_hints;
390 #ifdef HAVE_LIBXXF86VM
394 id = get_resources()->get_id();
395 if(parent_window) top_level = parent_window->top_level;
396 if( top_level ) lock_window("BC_WindowBase::create_window");
397 get_resources()->create_window_lock->lock("BC_WindowBase::create_window");
399 #ifdef HAVE_LIBXXF86VM
400 if(window_type == VIDMODE_SCALED_WINDOW)
401 closest_vm(&vm,&w,&h);
408 this->bg_color = bg_color;
409 this->window_type = window_type;
411 this->private_color = private_color;
412 this->parent_window = parent_window;
413 this->bg_pixmap = bg_pixmap;
414 this->allow_resize = allow_resize;
416 strcpy(this->display_name, display_name);
418 this->display_name[0] = 0;
421 if(bg_pixmap) shared_bg_pixmap = 1;
423 subwindows = new BC_SubWindowList;
425 if(window_type == MAIN_WINDOW)
428 parent_window = this;
432 display = BC_Display::get_display(display_name);
433 BC_Display::lock_display("BC_WindowBase::create_window");
434 // BC_Display::display_global->new_window(this);
437 // get the display connection
439 // This function must be the first Xlib
440 // function a multi-threaded program calls
442 display = init_display(display_name);
443 if( shm_completion_event < 0 ) shm_completion_event =
444 ShmCompletion + XShmGetEventBase(display);
446 lock_window("BC_WindowBase::create_window 1");
448 screen = DefaultScreen(display);
449 rootwin = RootWindow(display, screen);
450 // window placement boundaries
451 if( !xinerama_screens && XineramaIsActive(display) )
452 xinerama_info = XineramaQueryScreens(display, &xinerama_screens);
453 root_w = get_root_w(0);
454 root_h = get_root_h(0);
457 vis = get_glx_visual(display);
461 int mask = VisualDepthMask | VisualClassMask;
462 static XVisualInfo vinfo;
463 memset(&vinfo, 0, sizeof(vinfo));
465 vinfo.c_class = TrueColor;
467 XVisualInfo *vis_info = XGetVisualInfo(display, mask, &vinfo, &nitems);
468 vis = vis_info && nitems>0 ? vis_info[0].visual : 0;
469 if( vis_info ) XFree(vis_info);
472 vis = DefaultVisual(display, screen);
473 default_depth = DefaultDepth(display, screen);
475 client_byte_order = (*(const u_int32_t*)"a ") & 0x00000001;
476 server_byte_order = (XImageByteOrder(display) == MSBFirst) ? 0 : 1;
479 // This must be done before fonts to know if antialiasing is available.
482 if(resources->use_shm < 0) resources->initialize_display(this);
483 x_correction = BC_DisplayInfo::get_left_border();
484 y_correction = BC_DisplayInfo::get_top_border();
486 // clamp window placement
487 if(this->x + this->w + x_correction > root_w)
488 this->x = root_w - this->w - x_correction;
489 if(this->y + this->h + y_correction > root_h)
490 this->y = root_h - this->h - y_correction;
491 if(this->x < 0) this->x = 0;
492 if(this->y < 0) this->y = 0;
494 if(this->bg_color == -1)
495 this->bg_color = resources->get_bg_color();
497 // printf("bcwindowbase 1 %s\n", title);
498 // if(window_type == MAIN_WINDOW) sleep(1);
499 // printf("bcwindowbase 10\n");
505 mask = CWEventMask | CWBackPixel | CWColormap | CWCursor;
507 attr.event_mask = DEFAULT_EVENT_MASKS |
508 StructureNotifyMask |
512 attr.background_pixel = get_color(this->bg_color);
513 attr.colormap = cmap;
514 attr.cursor = get_cursor_struct(ARROW_CURSOR);
516 win = XCreateWindow(display, rootwin,
517 this->x, this->y, this->w, this->h, 0,
518 top_level->default_depth, InputOutput,
520 XGetNormalHints(display, win, &size_hints);
522 size_hints.flags = PSize | PMinSize | PMaxSize;
523 size_hints.width = this->w;
524 size_hints.height = this->h;
525 size_hints.min_width = allow_resize ? minw : this->w;
526 size_hints.max_width = allow_resize ? 32767 : this->w;
527 size_hints.min_height = allow_resize ? minh : this->h;
528 size_hints.max_height = allow_resize ? 32767 : this->h;
529 if(x > -BC_INFINITY && x < BC_INFINITY)
531 size_hints.flags |= PPosition;
532 size_hints.x = this->x;
533 size_hints.y = this->y;
535 XSetWMProperties(display, win, 0, 0, 0, 0, &size_hints, 0, 0);
538 #ifndef SINGLE_THREAD
539 clipboard = new BC_Clipboard(this);
540 clipboard->start_clipboard();
546 Atom ClientLeaderXAtom;
547 if (XGroupLeader == 0)
549 const char *instance_name = "cinelerra";
550 const char *class_name = "Cinelerra";
551 XClassHint *class_hints = XAllocClassHint();
552 class_hints->res_name = (char*)instance_name;
553 class_hints->res_class = (char*)class_name;
554 XSetClassHint(top_level->display, win, class_hints);
556 ClientLeaderXAtom = XInternAtom(display, "WM_CLIENT_LEADER", True);
557 XChangeProperty(display, win, ClientLeaderXAtom, XA_WINDOW, 32,
558 PropModeReplace, (unsigned char *)&XGroupLeader, true);
561 set_icon(get_resources()->default_icon);
564 #ifdef HAVE_LIBXXF86VM
565 if(window_type == VIDMODE_SCALED_WINDOW && vm != -1)
572 #ifdef HAVE_LIBXXF86VM
573 if(window_type == POPUP_WINDOW || window_type == VIDMODE_SCALED_WINDOW)
575 if(window_type == POPUP_WINDOW)
578 mask = CWEventMask | CWBackPixel | CWColormap |
579 CWOverrideRedirect | CWSaveUnder | CWCursor;
581 attr.event_mask = DEFAULT_EVENT_MASKS | ExposureMask |
582 KeyPressMask | KeyReleaseMask;
584 if(this->bg_color == -1)
585 this->bg_color = resources->get_bg_color();
586 attr.background_pixel = top_level->get_color(bg_color);
587 attr.colormap = top_level->cmap;
588 if(top_level->is_hourglass)
589 attr.cursor = top_level->get_cursor_struct(HOURGLASS_CURSOR);
591 attr.cursor = top_level->get_cursor_struct(ARROW_CURSOR);
592 attr.override_redirect = True;
593 attr.save_under = True;
595 win = XCreateWindow(top_level->display,
596 top_level->rootwin, this->x, this->y, this->w, this->h, 0,
597 top_level->default_depth, InputOutput, top_level->vis, mask,
599 top_level->add_popup(this);
602 if(window_type == SUB_WINDOW)
604 mask = CWEventMask | CWBackPixel | CWCursor;
605 attr.event_mask = DEFAULT_EVENT_MASKS;
606 attr.background_pixel = top_level->get_color(this->bg_color);
607 if(top_level->is_hourglass)
608 attr.cursor = top_level->get_cursor_struct(HOURGLASS_CURSOR);
610 attr.cursor = top_level->get_cursor_struct(ARROW_CURSOR);
611 win = XCreateWindow(top_level->display,
612 parent_window->win, this->x, this->y, this->w, this->h, 0,
613 top_level->default_depth, InputOutput, top_level->vis, mask,
616 if(!hidden) XMapWindow(top_level->display, win);
619 // Create pixmap for all windows
620 pixmap = new BC_Pixmap(this, this->w, this->h);
622 // Set up options for main window
623 if(window_type == MAIN_WINDOW)
625 if(get_resources()->bg_image && !bg_pixmap && bg_color < 0)
627 this->bg_pixmap = new BC_Pixmap(this,
628 get_resources()->bg_image,
632 if(!hidden) show_window();
636 draw_background(0, 0, this->w, this->h);
638 flash(-1, -1, -1, -1, 0);
640 // Set up options for popup window
641 #ifdef HAVE_LIBXXF86VM
642 if(window_type == POPUP_WINDOW || window_type == VIDMODE_SCALED_WINDOW)
644 if(window_type == POPUP_WINDOW)
648 if(!hidden) show_window();
650 get_resources()->create_window_lock->unlock();
656 Display* BC_WindowBase::init_display(const char *display_name)
660 if(display_name && display_name[0] == 0) display_name = NULL;
661 if((display = XOpenDisplay(display_name)) == NULL) {
662 printf("BC_WindowBase::init_display: cannot connect to X server %s\n",
664 if(getenv("DISPLAY") == NULL) {
665 printf(_("'DISPLAY' environment variable not set.\n"));
668 // Try again with default display.
669 if((display = XOpenDisplay(0)) == NULL) {
670 printf("BC_WindowBase::init_display: cannot connect to default X server.\n");
675 static int xsynch = -1;
677 const char *cp = getenv("CIN_XSYNCH");
678 xsynch = !cp ? 0 : atoi(cp);
681 XSynchronize(display, True);
686 Display* BC_WindowBase::get_display()
688 return top_level->display;
691 int BC_WindowBase::get_screen()
693 return top_level->screen;
696 int BC_WindowBase::run_window()
702 // Events may have been sent before run_window so can't initialize them here.
705 set_repeat(get_resources()->tooltip_delay);
706 BC_Display::display_global->new_window(this);
708 // If the first window created, run the display loop in this thread.
709 if(BC_Display::display_global->is_first(this))
711 BC_Display::unlock_display();
712 BC_Display::display_global->loop();
716 BC_Display::unlock_display();
717 completion_lock->lock("BC_WindowBase::run_window");
720 BC_Display::lock_display("BC_WindowBase::run_window");
721 BC_Display::display_global->delete_window(this);
723 unset_all_repeaters();
725 BC_Display::unlock_display();
727 #else // SINGLE_THREAD
732 set_repeat(get_resources()->tooltip_delay);
734 // Start X server events
735 event_thread = new BC_WindowEvents(this);
736 event_thread->start();
742 // Handle common events
747 unset_all_repeaters();
751 event_condition->reset();
752 common_events.remove_all_objects();
756 #endif // SINGLE_THREAD
761 int BC_WindowBase::get_key_masks(unsigned int key_state)
763 // printf("BC_WindowBase::get_key_masks %llx\n",
764 // event->xkey.state);
765 ctrl_mask = (key_state & ControlMask) ? 1 : 0; // ctrl key down
766 shift_mask = (key_state & ShiftMask) ? 1 : 0; // shift key down
767 alt_mask = (key_state & Mod1Mask) ? 1 : 0; // alt key down
772 void BC_WindowBase::add_keyboard_listener(int(BC_WindowBase::*handler)(BC_WindowBase *))
774 BC_KeyboardHandlerLock set;
775 BC_KeyboardHandler::listeners.append(new BC_KeyboardHandler(handler, this));
778 void BC_WindowBase::del_keyboard_listener(int(BC_WindowBase::*handler)(BC_WindowBase *))
780 BC_KeyboardHandlerLock set;
781 int i = BC_KeyboardHandler::listeners.size();
782 while( --i >= 0 && BC_KeyboardHandler::listeners[i]->handler!=handler );
783 if( i >= 0 ) BC_KeyboardHandler::listeners.remove_object_number(i);
786 int BC_KeyboardHandler::run_event(BC_WindowBase *wp)
788 int result = (win->*handler)(wp);
792 int BC_KeyboardHandler::run_listeners(BC_WindowBase *wp)
795 BC_KeyboardHandlerLock set;
796 for( int i=0; !result && i<listeners.size(); ++i ) {
797 BC_KeyboardHandler *listener = listeners[i];
798 result = listener->run_event(wp);
803 void BC_KeyboardHandler::kill_grabs()
805 BC_KeyboardHandlerLock set;
806 for( int i=0; i<listeners.size(); ++i ) {
807 BC_WindowBase *win = listeners[i]->win;
808 if( win->get_window_type() != POPUP_WINDOW ) continue;
809 ((BC_Popup *)win)->ungrab_keyboard();
813 void BC_ActiveBitmaps::reque(XEvent *event)
815 XShmCompletionEvent *shm_ev = (XShmCompletionEvent *)event;
816 ShmSeg shmseg = shm_ev->shmseg;
817 Drawable drawable = shm_ev->drawable;
818 //printf("BC_BitmapImage::reque %08lx\n",shmseg);
819 active_lock.lock("BC_BitmapImage::reque");
820 BC_BitmapImage *bfr = first;
821 while( bfr && bfr->get_shmseg() != shmseg ) bfr = bfr->next;
822 if( bfr && bfr->drawable == drawable )
824 active_lock.unlock();
826 // sadly, X reports two drawable completions and creates false reporting, so no boobytrap
827 // printf("BC_BitmapImage::reque missed shmseg %08x, drawable %08x\n",
828 // (int)shmseg, (int)drawable);
831 if( bfr->drawable != drawable ) return;
832 if( bfr->is_zombie() ) { --BC_Bitmap::zombies; delete bfr; return; }
833 bfr->bitmap->reque(bfr);
836 void BC_ActiveBitmaps::insert(BC_BitmapImage *bfr, Drawable pixmap)
838 active_lock.lock("BC_BitmapImage::insert");
839 bfr->drawable = pixmap;
841 active_lock.unlock();
844 void BC_ActiveBitmaps::remove_buffers(BC_WindowBase *wdw)
846 active_lock.lock("BC_ActiveBitmaps::remove");
847 for( BC_BitmapImage *nxt=0, *bfr=first; bfr; bfr=nxt ) {
849 if( bfr->is_zombie() ) { --BC_Bitmap::zombies; delete bfr; continue; }
850 if( bfr->bitmap->parent_window == wdw ) remove_pointer(bfr);
852 active_lock.unlock();
855 BC_ActiveBitmaps::BC_ActiveBitmaps()
859 BC_ActiveBitmaps::~BC_ActiveBitmaps()
865 int BC_WindowBase::keysym_lookup(XEvent *event)
867 for( int i = 0; i < KEYPRESSLEN; ++i ) keys_return[i] = 0;
868 for( int i = 0; i < 4; ++i ) wkey_string[i] = 0;
870 if( event->xany.send_event && !event->xany.serial ) {
871 keysym = (KeySym) event->xkey.keycode;
872 keys_return[0] = keysym;
875 wkey_string_length = 0;
877 if( input_context ) {
879 wkey_string_length = XwcLookupString(input_context,
880 (XKeyEvent*)event, wkey, 4, &keysym, 0);
881 for( int i=0; i<wkey_string_length; ++i )
882 wkey_string[i] = wkey[i];
883 //printf("keysym_lookup 1 %d %d %lx %x %x %x %x\n", wkey_string_length, keysym,
884 // wkey_string[0], wkey_string[1], wkey_string[2], wkey_string[3]);
887 int ret = Xutf8LookupString(input_context, (XKeyEvent*)event,
888 keys_return, KEYPRESSLEN, &keysym, &stat);
889 //printf("keysym_lookup 2 %d %d %lx %x %x\n", ret, stat, keysym, keys_return[0], keys_return[1]);
890 if( stat == XLookupBoth ) return ret;
891 if( stat == XLookupKeySym ) return 0;
893 int ret = XLookupString((XKeyEvent*)event, keys_return, KEYPRESSLEN, &keysym, 0);
894 wkey_string_length = ret;
895 for( int i=0; i<ret; ++i ) wkey_string[i] = keys_return[i];
899 pthread_t locking_task = (pthread_t)-1L;
900 int locking_event = -1;
901 int locking_message = -1;
903 int BC_WindowBase::dispatch_event()
907 XClientMessageEvent *ptr;
908 int cancel_resize, cancel_translation;
909 volatile static int debug = 0;
914 #ifndef SINGLE_THREAD
915 // If an event is waiting get it, otherwise
916 // wait for next event only if there are no compressed events.
917 if(get_event_count() ||
918 (!motion_events && !resize_events && !translation_events))
921 // Lock out window deletions
922 lock_window("BC_WindowBase::dispatch_event 1");
923 locking_event = event->type;
924 locking_task = pthread_self();
925 locking_message = event->xclient.message_type;
928 // Handle compressed events
930 lock_window("BC_WindowBase::dispatch_event 2");
932 dispatch_resize_event(last_resize_w, last_resize_h);
934 dispatch_motion_event();
935 if(translation_events)
936 dispatch_translation_event();
947 if( debug && event->type != ClientMessage ) {
948 static const char *event_names[] = {
949 "Reply", "Error", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease", "MotionNotify",
950 "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut", "KeymapNotify", "Expose", "GraphicsExpose",
951 "NoExpose", "VisibilityNotify", "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify",
952 "MapRequest", "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
953 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear",
954 "SelectionRequest", "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify",
955 "GenericEvent", "LASTEvent",
957 const int nevents = sizeof(event_names)/sizeof(event_names[0]);
959 printf("BC_WindowBase::dispatch_event %d %s %p %d (%s)\n", __LINE__,
960 title, event, event->type, event->type>=0 && event->type<nevents ?
961 event_names[event->type] : "Unknown");
965 grab_lock->lock("BC_WindowBase::dispatch_event 3");
969 active_grab->lock_window("BC_WindowBase::dispatch_event 3");
970 result = active_grab->grab_event(event);
971 active_grab->unlock_window();
974 if( result ) return result;
975 lock_window("BC_WindowBase::dispatch_event 4");
978 switch(event->type) {
980 // Clear the resize buffer
982 dispatch_resize_event(last_resize_w, last_resize_h);
983 // Clear the motion buffer since this can clear the window
985 dispatch_motion_event();
987 ptr = (XClientMessageEvent*)event;
988 if( ptr->message_type == ProtoXAtom &&
989 (Atom)ptr->data.l[0] == DelWinXAtom ) {
992 else if( ptr->message_type == RepeaterXAtom ) {
993 dispatch_repeat_event(ptr->data.l[0]);
995 else if( ptr->message_type == SetDoneXAtom ) {
999 receive_custom_xatoms((xatom_event *)ptr);
1005 dispatch_focus_in();
1010 dispatch_focus_out();
1024 dispatch_motion_event();
1026 get_key_masks(event->xbutton.state);
1027 cursor_x = event->xbutton.x;
1028 cursor_y = event->xbutton.y;
1029 button_number = event->xbutton.button;
1031 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1032 event_win = event->xany.window;
1033 if( button_number < 6 ) {
1034 if( button_number < 4 )
1036 button_pressed = event->xbutton.button;
1037 button_time1 = button_time2;
1038 button_time2 = button_time3;
1039 button_time3 = event->xbutton.time;
1042 drag_win = event_win;
1043 drag_x1 = cursor_x - get_resources()->drag_radius;
1044 drag_x2 = cursor_x + get_resources()->drag_radius;
1045 drag_y1 = cursor_y - get_resources()->drag_radius;
1046 drag_y2 = cursor_y + get_resources()->drag_radius;
1047 if( button_number < 4 ) {
1048 if((long)(button_time3 - button_time1) < resources->double_click * 2) {
1050 button_time3 = button_time2 = button_time1 = 0;
1052 if((long)(button_time3 - button_time2) < resources->double_click) {
1054 // button_time3 = button_time2 = button_time1 = 0;
1061 dispatch_button_press();
1068 dispatch_motion_event();
1070 get_key_masks(event->xbutton.state);
1071 button_number = event->xbutton.button;
1072 event_win = event->xany.window;
1073 if (button_number < 6)
1075 if(button_number < 4)
1077 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1079 dispatch_button_release();
1084 event_win = event->xany.window;
1086 for( int i=0; !result && i<popups.size(); ++i ) { // popups take focus
1087 if( popups[i]->win == event_win )
1088 result = popups[i]->dispatch_expose_event();
1091 result = dispatch_expose_event();
1095 get_key_masks(event->xmotion.state);
1096 // Dispatch previous motion event if this is a subsequent motion from a different window
1097 if(motion_events && last_motion_win != event->xany.window)
1099 dispatch_motion_event();
1102 // Buffer the current motion
1104 last_motion_state = event->xmotion.state;
1105 last_motion_x = event->xmotion.x;
1106 last_motion_y = event->xmotion.y;
1107 last_motion_win = event->xany.window;
1110 case ConfigureNotify:
1111 // printf("BC_WindowBase::dispatch_event %d win=%p this->win=%p\n",
1113 // event->xany.window,
1116 XTranslateCoordinates(top_level->display,
1124 last_resize_w = event->xconfigure.width;
1125 last_resize_h = event->xconfigure.height;
1128 cancel_translation = 0;
1130 // Resize history prevents responses to recursive resize requests
1131 for(int i = 0; i < resize_history.total && !cancel_resize; i++)
1133 if(resize_history.values[i]->w == last_resize_w &&
1134 resize_history.values[i]->h == last_resize_h)
1136 delete resize_history.values[i];
1137 resize_history.remove_number(i);
1142 if(last_resize_w == w && last_resize_h == h)
1150 if((last_translate_x == x && last_translate_y == y))
1151 cancel_translation = 1;
1153 if(!cancel_translation)
1155 translation_events = 1;
1158 translation_count++;
1162 get_key_masks(event->xkey.state);
1163 keys_return[0] = 0; keysym = -1;
1164 if(XFilterEvent(event, win)) {
1167 if( keysym_lookup(event) < 0 ) {
1168 printf("keysym %x\n", (uint32_t)keysym);
1172 //printf("BC_WindowBase::dispatch_event %d keysym=0x%x\n",
1176 // block out control keys
1177 if(keysym > 0xffe0 && keysym < 0xffff) break;
1178 // block out Alt_GR key
1179 if(keysym == 0xfe03) break;
1182 printf("BC_WindowBase::dispatch_event %x\n", (uint32_t)keysym);
1184 #ifdef X_HAVE_UTF8_STRING
1185 //It's Ascii or UTF8?
1186 // if (keysym != 0xffff && (keys_return[0] & 0xff) >= 0x7f )
1187 //printf("BC_WindowBase::dispatch_event %d %02x%02x\n", __LINE__, keys_return[0], keys_return[1]);
1189 if( ((keys_return[1] & 0xff) > 0x80) &&
1190 ((keys_return[0] & 0xff) > 0xC0) ) {
1191 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1192 key_pressed = keysym & 0xff;
1196 // shuttle speed codes
1197 if( keysym >= SKEY_MIN && keysym <= SKEY_MAX ) {
1198 key_pressed = keysym;
1200 else switch( keysym ) {
1201 // block out extra keys
1211 // Translate key codes
1212 case XK_Return: key_pressed = RETURN; break;
1213 case XK_Up: key_pressed = UP; break;
1214 case XK_Down: key_pressed = DOWN; break;
1215 case XK_Left: key_pressed = LEFT; break;
1216 case XK_Right: key_pressed = RIGHT; break;
1217 case XK_Next: key_pressed = PGDN; break;
1218 case XK_Prior: key_pressed = PGUP; break;
1219 case XK_BackSpace: key_pressed = BACKSPACE; break;
1220 case XK_Escape: key_pressed = ESC; break;
1223 key_pressed = LEFTTAB;
1227 case XK_ISO_Left_Tab: key_pressed = LEFTTAB; break;
1228 case XK_underscore: key_pressed = '_'; break;
1229 case XK_asciitilde: key_pressed = '~'; break;
1230 case XK_Delete: key_pressed = DELETE; break;
1231 case XK_Home: key_pressed = HOME; break;
1232 case XK_End: key_pressed = END; break;
1235 case XK_KP_Enter: key_pressed = KPENTER; break;
1236 case XK_KP_Add: key_pressed = KPPLUS; break;
1237 case XK_KP_Subtract: key_pressed = KPMINUS; break;
1238 case XK_KP_Multiply: key_pressed = KPSTAR; break;
1239 case XK_KP_Divide: key_pressed = KPSLASH; break;
1241 case XK_KP_End: key_pressed = KP1; break;
1243 case XK_KP_Down: key_pressed = KP2; break;
1245 case XK_KP_Page_Down: key_pressed = KP3; break;
1247 case XK_KP_Left: key_pressed = KP4; break;
1249 case XK_KP_Begin: key_pressed = KP5; break;
1251 case XK_KP_Right: key_pressed = KP6; break;
1253 case XK_KP_Home: key_pressed = KP7; break;
1255 case XK_KP_Up: key_pressed = KP8; break;
1257 case XK_KP_Page_Up: key_pressed = KP9; break;
1259 case XK_KP_Insert: key_pressed = KPINS; break;
1261 case XK_KP_Delete: key_pressed = KPDEL; break;
1263 case XK_F1: key_pressed = KEY_F1; break;
1264 case XK_F2: key_pressed = KEY_F2; break;
1265 case XK_F3: key_pressed = KEY_F3; break;
1266 case XK_F4: key_pressed = KEY_F4; break;
1267 case XK_F5: key_pressed = KEY_F5; break;
1268 case XK_F6: key_pressed = KEY_F6; break;
1269 case XK_F7: key_pressed = KEY_F7; break;
1270 case XK_F8: key_pressed = KEY_F8; break;
1271 case XK_F9: key_pressed = KEY_F9; break;
1272 case XK_F10: key_pressed = KEY_F10; break;
1273 case XK_F11: key_pressed = KEY_F11; break;
1274 case XK_F12: key_pressed = KEY_F12; break;
1276 case XK_Menu: key_pressed = KPMENU; break; /* menu */
1279 key_pressed = keysym & 0xff;
1280 #ifdef X_HAVE_UTF8_STRING
1281 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1286 #ifdef X_HAVE_UTF8_STRING
1288 key_pressed_utf8 = keys_return;
1293 if( top_level == this )
1294 result = BC_KeyboardHandler::run_listeners(this);
1296 //printf("BC_WindowBase::dispatch_event %d %d %x\n", shift_down(), alt_down(), key_pressed);
1298 result = dispatch_keypress_event();
1299 // Handle some default keypresses
1302 if(key_pressed == 'w' ||
1311 XLookupString((XKeyEvent*)event, keys_return, 1, &keysym, 0);
1312 dispatch_keyrelease_event();
1313 // printf("BC_WindowBase::dispatch_event KeyRelease keysym=0x%x keystate=0x%lld\n",
1314 // keysym, event->xkey.state);
1318 if( event->xcrossing.mode != NotifyNormal ) break;
1320 event_win = event->xany.window;
1321 dispatch_cursor_leave();
1325 if( event->xcrossing.mode != NotifyNormal ) break;
1327 if( !cursor_entered ) {
1328 for( int i=0; i<popups.size(); ++i ) { // popups always take focus
1329 if( popups[i]->win == event->xcrossing.window )
1332 if( !cursor_entered && get_resources()->grab_input_focus &&
1333 !event->xcrossing.focus && event->xcrossing.window == win ) {
1336 if( cursor_entered )
1339 event_win = event->xany.window;
1340 cursor_x = event->xcrossing.x;
1341 cursor_y = event->xcrossing.y;
1342 dispatch_cursor_enter();
1348 //printf("100 %s %p %d\n", title, event, event->type);
1349 //if(event->type != ClientMessage) dump();
1351 #ifndef SINGLE_THREAD
1354 if( resend_event_window ) {
1355 resend_event_window->put_event(event);
1356 resend_event_window = 0;
1362 // if(done) completion_lock->unlock();
1365 if(debug) printf("BC_WindowBase::dispatch_event this=%p %d\n", this, __LINE__);
1369 int BC_WindowBase::dispatch_expose_event()
1372 for(int i = 0; i < subwindows->total && !result; i++)
1374 result = subwindows->values[i]->dispatch_expose_event();
1377 // Propagate to user
1378 if(!result) expose_event();
1382 int BC_WindowBase::dispatch_resize_event(int w, int h)
1384 // Can't store new w and h until the event is handles
1385 // because bcfilebox depends on the old w and h to
1386 // reposition widgets.
1387 if( window_type == MAIN_WINDOW ) {
1392 pixmap = new BC_Pixmap(this, w, h);
1393 clear_box(0, 0, w, h);
1396 // Propagate to subwindows
1397 for(int i = 0; i < subwindows->total; i++) {
1398 subwindows->values[i]->dispatch_resize_event(w, h);
1401 // Propagate to user
1404 if( window_type == MAIN_WINDOW ) {
1413 int BC_WindowBase::dispatch_flash()
1416 for(int i = 0; i < subwindows->total; i++)
1417 subwindows->values[i]->dispatch_flash();
1421 int BC_WindowBase::dispatch_translation_event()
1423 translation_events = 0;
1424 if(window_type == MAIN_WINDOW)
1428 x = last_translate_x;
1429 y = last_translate_y;
1430 // Correct for window manager offsets
1435 for(int i = 0; i < subwindows->total; i++)
1437 subwindows->values[i]->dispatch_translation_event();
1440 translation_event();
1444 int BC_WindowBase::dispatch_motion_event()
1449 if(top_level == this)
1452 event_win = last_motion_win;
1453 get_key_masks(last_motion_state);
1456 if(get_button_down() && !active_menubar && !active_popup_menu)
1460 cursor_x = last_motion_x;
1461 cursor_y = last_motion_y;
1462 result = dispatch_drag_motion();
1466 (last_motion_x < drag_x1 || last_motion_x >= drag_x2 ||
1467 last_motion_y < drag_y1 || last_motion_y >= drag_y2))
1472 result = dispatch_drag_start();
1476 cursor_x = last_motion_x;
1477 cursor_y = last_motion_y;
1479 // printf("BC_WindowBase::dispatch_motion_event %d %p %p %p\n",
1482 // active_popup_menu,
1483 // active_subwindow);
1485 if(active_menubar && !result) result = active_menubar->dispatch_motion_event();
1486 if(active_popup_menu && !result) result = active_popup_menu->dispatch_motion_event();
1487 if(active_subwindow && !result) result = active_subwindow->dispatch_motion_event();
1490 // Dispatch in stacking order
1491 for(int i = subwindows->size() - 1; i >= 0 && !result; i--)
1493 result = subwindows->values[i]->dispatch_motion_event();
1496 if(!result) result = cursor_motion_event(); // give to user
1500 int BC_WindowBase::dispatch_keypress_event()
1503 if(top_level == this)
1505 if(active_subwindow) result = active_subwindow->dispatch_keypress_event();
1508 for(int i = 0; i < subwindows->total && !result; i++)
1510 result = subwindows->values[i]->dispatch_keypress_event();
1513 if(!result) result = keypress_event();
1518 int BC_WindowBase::dispatch_keyrelease_event()
1521 if(top_level == this)
1523 if(active_subwindow) result = active_subwindow->dispatch_keyrelease_event();
1526 for(int i = 0; i < subwindows->total && !result; i++)
1528 result = subwindows->values[i]->dispatch_keyrelease_event();
1531 if(!result) result = keyrelease_event();
1536 int BC_WindowBase::dispatch_focus_in()
1538 for(int i = 0; i < subwindows->total; i++)
1540 subwindows->values[i]->dispatch_focus_in();
1548 int BC_WindowBase::dispatch_focus_out()
1550 for(int i = 0; i < subwindows->total; i++)
1552 subwindows->values[i]->dispatch_focus_out();
1560 int BC_WindowBase::get_has_focus()
1562 return top_level->has_focus;
1565 int BC_WindowBase::get_deleting()
1567 if(is_deleting) return 1;
1568 if(parent_window && parent_window->get_deleting()) return 1;
1572 int BC_WindowBase::dispatch_button_press()
1577 if(top_level == this)
1579 if(active_menubar) result = active_menubar->dispatch_button_press();
1580 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_press();
1581 if(active_subwindow && !result) result = active_subwindow->dispatch_button_press();
1584 for(int i = 0; i < subwindows->total && !result; i++)
1586 result = subwindows->values[i]->dispatch_button_press();
1589 if(!result) result = button_press_event();
1595 int BC_WindowBase::dispatch_button_release()
1598 if(top_level == this)
1600 if(active_menubar) result = active_menubar->dispatch_button_release();
1601 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_release();
1602 if(active_subwindow && !result) result = active_subwindow->dispatch_button_release();
1603 if(!result && button_number != 4 && button_number != 5)
1604 result = dispatch_drag_stop();
1607 for(int i = 0; i < subwindows->total && !result; i++)
1609 result = subwindows->values[i]->dispatch_button_release();
1614 result = button_release_event();
1621 int BC_WindowBase::dispatch_repeat_event(int64_t duration)
1624 // all repeat event handlers get called and decide based on activity and duration
1625 // whether to respond
1626 for(int i = 0; i < subwindows->total; i++)
1628 subwindows->values[i]->dispatch_repeat_event(duration);
1632 repeat_event(duration);
1636 // Unlock next repeat signal
1637 if(window_type == MAIN_WINDOW)
1639 #ifdef SINGLE_THREAD
1640 BC_Display::display_global->unlock_repeaters(duration);
1642 for(int i = 0; i < repeaters.total; i++)
1644 if(repeaters.values[i]->delay == duration)
1646 repeaters.values[i]->repeat_lock->unlock();
1654 void BC_WindowBase::unhide_cursor()
1659 if(top_level->is_hourglass)
1660 set_cursor(HOURGLASS_CURSOR, 1, 0);
1662 set_cursor(current_cursor, 1, 0);
1664 cursor_timer->update();
1668 void BC_WindowBase::update_video_cursor()
1670 if(video_on && !is_transparent)
1672 if(cursor_timer->get_difference() > VIDEO_CURSOR_TIMEOUT && !is_transparent)
1675 set_cursor(TRANSPARENT_CURSOR, 1, 1);
1676 cursor_timer->update();
1681 cursor_timer->update();
1686 int BC_WindowBase::dispatch_cursor_leave()
1690 for(int i = 0; i < subwindows->total; i++)
1692 subwindows->values[i]->dispatch_cursor_leave();
1695 cursor_leave_event();
1699 int BC_WindowBase::dispatch_cursor_enter()
1705 if(active_menubar) result = active_menubar->dispatch_cursor_enter();
1706 if(!result && active_popup_menu) result = active_popup_menu->dispatch_cursor_enter();
1707 if(!result && active_subwindow) result = active_subwindow->dispatch_cursor_enter();
1709 for(int i = 0; !result && i < subwindows->total; i++)
1711 result = subwindows->values[i]->dispatch_cursor_enter();
1714 if(!result) result = cursor_enter_event();
1718 int BC_WindowBase::cursor_enter_event()
1723 int BC_WindowBase::cursor_leave_event()
1728 int BC_WindowBase::close_event()
1734 // *** CONTEXT_HELP ***
1735 // This basic implementation serves solely for context help.
1736 // We are handling Alt/H only. Any subclass requiring more sophisticated
1737 // processing of keystrokes has to provide its own overloaded handler.
1738 int BC_WindowBase::keypress_event()
1740 // printf("BC_WindowBase::keypress_event: %d\n", get_keypress());
1741 return context_help_check_and_show();
1744 // The stuff up to END_CONTEXT_HELP serves solely for context help
1745 void BC_WindowBase::context_help_set_keyword(const char *keyword)
1747 if (keyword) strcpy(context_help_keyword, keyword);
1750 const char *BC_WindowBase::context_help_get_keyword()
1752 // If we have context_help_keyword defined here, return it.
1753 // Otherwise recursively track widget hierarchy up to top_level
1754 // and return the nearest found nonempty keyword.
1755 // If nothing found, the special keyword "TOC" is returned.
1756 if (context_help_keyword[0] || this == top_level ||
1757 this == parent_window || ! parent_window) {
1758 if (! context_help_keyword[0] && this == top_level)
1759 context_help_set_keyword("TOC");
1760 return context_help_keyword;
1762 return parent_window->context_help_get_keyword();
1765 void BC_WindowBase::context_help_show(const char *keyword)
1767 char cmd[BCTEXTLEN];
1769 if (! keyword) return;
1771 sprintf(cmd, "\"%s/doc/ContextManual.pl\" \"%s\"", getenv("CIN_DAT"),
1773 // printf("BC_WindowBase::context_help_show(%s):\n%s\n", keyword, cmd);
1775 // ContextManual.pl starts browser in background, so system() should not block
1779 void BC_WindowBase::context_help_show()
1781 context_help_show(context_help_get_keyword());
1784 int BC_WindowBase::context_help_check_and_show(const char *keyword)
1786 if (! keyword) return 0;
1787 if (! keyword[0]) return 0;
1789 // We are handling Alt/H only
1790 if (get_keypress() != 'h' || ! alt_down()) return 0;
1792 // Restrict cursor location to that widget keystroke occured in
1793 if (! is_tooltip_event_win() || ! cursor_inside()) return 0;
1795 context_help_show(keyword);
1799 int BC_WindowBase::context_help_check_and_show()
1801 const char *keyword;
1803 // We are handling Alt/H only
1804 if (get_keypress() != 'h' || ! alt_down()) return 0;
1806 // Restrict cursor location, so any subwindow can define its own help keyword
1807 if (! is_tooltip_event_win() || ! cursor_inside()) return 0;
1809 // If a widget has not defined its own help keyword, the parent can provide it
1810 keyword = context_help_get_keyword();
1811 if (! keyword[0]) return 0;
1813 context_help_show(keyword);
1816 // *** END_CONTEXT_HELP ***
1818 int BC_WindowBase::dispatch_drag_start()
1821 if(active_menubar) result = active_menubar->dispatch_drag_start();
1822 if(!result && active_popup_menu) result = active_popup_menu->dispatch_drag_start();
1823 if(!result && active_subwindow) result = active_subwindow->dispatch_drag_start();
1825 for(int i = 0; i < subwindows->total && !result; i++)
1827 result = subwindows->values[i]->dispatch_drag_start();
1830 if(!result) result = is_dragging = drag_start_event();
1834 int BC_WindowBase::dispatch_drag_stop()
1838 for(int i = 0; i < subwindows->total && !result; i++)
1840 result = subwindows->values[i]->dispatch_drag_stop();
1843 if(is_dragging && !result)
1853 int BC_WindowBase::dispatch_drag_motion()
1856 for(int i = 0; i < subwindows->total && !result; i++)
1858 result = subwindows->values[i]->dispatch_drag_motion();
1861 if(is_dragging && !result)
1863 drag_motion_event();
1871 int BC_WindowBase::show_tooltip(const char *text, int x, int y, int w, int h)
1874 int forced = !text ? force_tooltip : 1;
1875 if( !text ) text = tooltip_text;
1876 if( !text || (!forced && !get_resources()->tooltips_enabled) ) {
1877 top_level->hide_tooltip();
1881 if(w < 0) w = get_text_width(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1882 if(h < 0) h = get_text_height(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1883 // default x,y (win relative)
1884 if( x < 0 ) x = get_w();
1885 if( y < 0 ) y = get_h();
1887 get_root_coordinates(x, y, &wx, &wy);
1888 // keep the tip inside the window/display
1889 int x0 = top_level->get_x(), x1 = x0 + top_level->get_w();
1890 int x2 = top_level->get_screen_x(0, -1) + top_level->get_screen_w(0, -1);
1891 if( x1 > x2 ) x1 = x2;
1892 if( wx < x0 ) wx = x0;
1893 if( wx >= (x1-=w) ) wx = x1;
1894 int y0 = top_level->get_y(), y1 = y0 + top_level->get_h();
1895 int y2 = top_level->get_root_h(0);
1896 if( y1 > y2 ) y1 = y2;
1897 if( wy < y0 ) wy = y0;
1898 if( wy >= (y1-=h) ) wy = y1;
1899 // avoid tip under cursor (flickers)
1901 get_abs_cursor(abs_x,abs_y, 0);
1902 if( wx < abs_x && abs_x < wx+w && wy < abs_y && abs_y < wy+h ) {
1903 if( wx-abs_x < wy-abs_y )
1910 tooltip_popup = new BC_Popup(top_level, wx, wy, w, h,
1911 get_resources()->tooltip_bg_color);
1914 tooltip_popup->reposition_window(wx, wy, w, h);
1917 tooltip_popup->flash();
1918 tooltip_popup->flush();
1922 int BC_WindowBase::hide_tooltip()
1925 for(int i = 0; i < subwindows->total; i++)
1927 subwindows->values[i]->hide_tooltip();
1933 delete tooltip_popup;
1939 const char *BC_WindowBase::get_tooltip()
1941 return tooltip_text;
1944 int BC_WindowBase::set_tooltip(const char *text)
1946 tooltip_text = text;
1948 // Update existing tooltip if it is visible
1952 tooltip_popup->flash();
1956 // signal the event handler to repeat
1957 int BC_WindowBase::set_repeat(int64_t duration)
1961 printf("BC_WindowBase::set_repeat duration=%jd\n", duration);
1964 if(window_type != MAIN_WINDOW) return top_level->set_repeat(duration);
1966 #ifdef SINGLE_THREAD
1967 BC_Display::display_global->set_repeat(this, duration);
1969 // test repeater database for duplicates
1970 for(int i = 0; i < repeaters.total; i++)
1973 if(repeaters.values[i]->delay == duration)
1975 repeaters.values[i]->start_repeating(this);
1980 BC_Repeater *repeater = new BC_Repeater(this, duration);
1981 repeater->initialize();
1982 repeaters.append(repeater);
1983 repeater->start_repeating();
1988 int BC_WindowBase::unset_repeat(int64_t duration)
1990 if(window_type != MAIN_WINDOW) return top_level->unset_repeat(duration);
1992 #ifdef SINGLE_THREAD
1993 BC_Display::display_global->unset_repeat(this, duration);
1995 for(int i = 0; i < repeaters.total; i++)
1997 if(repeaters.values[i]->delay == duration)
1999 repeaters.values[i]->stop_repeating();
2007 int BC_WindowBase::unset_all_repeaters()
2009 #ifdef SINGLE_THREAD
2010 BC_Display::display_global->unset_all_repeaters(this);
2012 for(int i = 0; i < repeaters.total; i++)
2014 repeaters.values[i]->stop_repeating();
2016 repeaters.remove_all_objects();
2021 // long BC_WindowBase::get_repeat_id()
2023 // return top_level->next_repeat_id++;
2026 XEvent *BC_WindowBase::new_xevent()
2028 XEvent *event = new XEvent;
2029 memset(event, 0, sizeof(*event));
2033 #ifndef SINGLE_THREAD
2034 int BC_WindowBase::arm_repeat(int64_t duration)
2036 XEvent *event = new_xevent();
2037 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
2038 ptr->type = ClientMessage;
2039 ptr->message_type = RepeaterXAtom;
2041 ptr->data.l[0] = duration;
2043 // Couldn't use XSendEvent since it locked up randomly.
2049 int BC_WindowBase::receive_custom_xatoms(xatom_event *event)
2054 int BC_WindowBase::send_custom_xatom(xatom_event *event)
2056 #ifndef SINGLE_THREAD
2057 XEvent *myevent = new_xevent();
2058 XClientMessageEvent *ptr = (XClientMessageEvent*)myevent;
2059 ptr->type = ClientMessage;
2060 ptr->message_type = event->message_type;
2061 ptr->format = event->format;
2062 ptr->data.l[0] = event->data.l[0];
2063 ptr->data.l[1] = event->data.l[1];
2064 ptr->data.l[2] = event->data.l[2];
2065 ptr->data.l[3] = event->data.l[3];
2066 ptr->data.l[4] = event->data.l[4];
2075 Atom BC_WindowBase::create_xatom(const char *atom_name)
2077 return XInternAtom(display, atom_name, False);
2080 int BC_WindowBase::get_atoms()
2082 SetDoneXAtom = XInternAtom(display, "BC_REPEAT_EVENT", False);
2083 RepeaterXAtom = XInternAtom(display, "BC_CLOSE_EVENT", False);
2084 DestroyAtom = XInternAtom(display, "BC_DESTROY_WINDOW", False);
2085 DelWinXAtom = XInternAtom(display, "WM_DELETE_WINDOW", False);
2086 if( (ProtoXAtom = XInternAtom(display, "WM_PROTOCOLS", False)) != 0 )
2087 XChangeProperty(display, win, ProtoXAtom, XA_ATOM, 32,
2088 PropModeReplace, (unsigned char *)&DelWinXAtom, True);
2094 void BC_WindowBase::init_cursors()
2096 arrow_cursor = XCreateFontCursor(display, XC_top_left_arrow);
2097 cross_cursor = XCreateFontCursor(display, XC_crosshair);
2098 ibeam_cursor = XCreateFontCursor(display, XC_xterm);
2099 vseparate_cursor = XCreateFontCursor(display, XC_sb_v_double_arrow);
2100 hseparate_cursor = XCreateFontCursor(display, XC_sb_h_double_arrow);
2101 move_cursor = XCreateFontCursor(display, XC_fleur);
2102 left_cursor = XCreateFontCursor(display, XC_sb_left_arrow);
2103 right_cursor = XCreateFontCursor(display, XC_sb_right_arrow);
2104 upright_arrow_cursor = XCreateFontCursor(display, XC_arrow);
2105 upleft_resize_cursor = XCreateFontCursor(display, XC_top_left_corner);
2106 upright_resize_cursor = XCreateFontCursor(display, XC_top_right_corner);
2107 downleft_resize_cursor = XCreateFontCursor(display, XC_bottom_left_corner);
2108 downright_resize_cursor = XCreateFontCursor(display, XC_bottom_right_corner);
2109 hourglass_cursor = XCreateFontCursor(display, XC_watch);
2110 grabbed_cursor = create_grab_cursor();
2112 static char cursor_data[] = { 0,0,0,0, 0,0,0,0 };
2113 Colormap colormap = DefaultColormap(display, screen);
2114 Pixmap pixmap_bottom = XCreateBitmapFromData(display,
2115 rootwin, cursor_data, 8, 8);
2116 XColor black, dummy;
2117 XAllocNamedColor(display, colormap, "black", &black, &dummy);
2118 transparent_cursor = XCreatePixmapCursor(display,
2119 pixmap_bottom, pixmap_bottom, &black, &black, 0, 0);
2120 // XDefineCursor(display, win, transparent_cursor);
2121 XFreePixmap(display, pixmap_bottom);
2124 int BC_WindowBase::evaluate_color_model(int client_byte_order, int server_byte_order, int depth)
2126 int color_model = BC_TRANSPARENCY;
2130 color_model = BC_RGB8;
2133 color_model = (server_byte_order == client_byte_order) ? BC_RGB565 : BC_BGR565;
2136 color_model = server_byte_order ? BC_BGR888 : BC_RGB888;
2139 color_model = server_byte_order ? BC_BGR8888 : BC_ARGB8888;
2145 int BC_WindowBase::init_colors()
2148 current_color_value = current_color_pixel = 0;
2150 // Get the real depth
2153 ximage = XCreateImage(top_level->display,
2154 top_level->vis, top_level->default_depth,
2155 ZPixmap, 0, data, 16, 16, 8, 0);
2156 bits_per_pixel = ximage->bits_per_pixel;
2157 XDestroyImage(ximage);
2159 color_model = evaluate_color_model(client_byte_order,
2162 // Get the color model
2167 cmap = XCreateColormap(display, rootwin, vis, AllocNone);
2168 create_private_colors();
2171 cmap = DefaultColormap(display, screen);
2172 create_shared_colors();
2175 allocate_color_table();
2179 //cmap = DefaultColormap(display, screen);
2180 cmap = XCreateColormap(display, rootwin, vis, AllocNone );
2186 int BC_WindowBase::create_private_colors()
2191 for(int i = 0; i < 255; i++)
2193 color = (i & 0xc0) << 16;
2194 color += (i & 0x38) << 10;
2195 color += (i & 0x7) << 5;
2196 color_table[i][0] = color;
2198 create_shared_colors(); // overwrite the necessary colors on the table
2203 int BC_WindowBase::create_color(int color)
2205 if(total_colors == 256)
2207 // replace the closest match with an exact match
2208 color_table[get_color_rgb8(color)][0] = color;
2212 // add the color to the table
2213 color_table[total_colors][0] = color;
2219 int BC_WindowBase::create_shared_colors()
2221 create_color(BLACK);
2222 create_color(WHITE);
2224 create_color(LTGREY);
2225 create_color(MEGREY);
2226 create_color(MDGREY);
2227 create_color(DKGREY);
2229 create_color(LTCYAN);
2230 create_color(MECYAN);
2231 create_color(MDCYAN);
2232 create_color(DKCYAN);
2234 create_color(LTGREEN);
2235 create_color(GREEN);
2236 create_color(DKGREEN);
2238 create_color(LTPINK);
2242 create_color(LTBLUE);
2244 create_color(DKBLUE);
2246 create_color(LTYELLOW);
2247 create_color(MEYELLOW);
2248 create_color(MDYELLOW);
2249 create_color(DKYELLOW);
2251 create_color(LTPURPLE);
2252 create_color(MEPURPLE);
2253 create_color(MDPURPLE);
2254 create_color(DKPURPLE);
2256 create_color(FGGREY);
2257 create_color(MNBLUE);
2258 create_color(ORANGE);
2259 create_color(FTGREY);
2264 Cursor BC_WindowBase::create_grab_cursor()
2266 int iw = 23, iw1 = iw-1, iw2 = iw/2;
2267 int ih = 23, ih1 = ih-1, ih2 = ih/2;
2268 VFrame grab(iw,ih,BC_RGB888);
2270 grab.set_pixel_color(RED); // fg
2271 grab.draw_smooth(iw2,0, iw1,0, iw1,ih2);
2272 grab.draw_smooth(iw1,ih2, iw1,ih1, iw2,ih1);
2273 grab.draw_smooth(iw2,ih1, 0,ih1, 0,ih2);
2274 grab.draw_smooth(0,ih2, 0,0, iw2,0);
2275 grab.set_pixel_color(WHITE); // bg
2276 grab.draw_line(0,ih2, iw2-2,ih2);
2277 grab.draw_line(iw2+2,ih2, iw1,ih2);
2278 grab.draw_line(iw2,0, iw2,ih2-2);
2279 grab.draw_line(iw2,ih2+2, iw2,ih1);
2281 int bpl = (iw+7)/8, isz = bpl * ih;
2282 char img[isz]; memset(img, 0, isz);
2283 char msk[isz]; memset(msk, 0, isz);
2284 unsigned char **rows = grab.get_rows();
2285 for( int iy=0; iy<ih; ++iy ) {
2286 char *op = img + iy*bpl;
2287 char *mp = msk + iy*bpl;
2288 unsigned char *ip = rows[iy];
2289 for( int ix=0; ix<iw; ++ix,ip+=3 ) {
2290 if( ip[0] ) mp[ix>>3] |= (1<<(ix&7));
2291 if( !ip[1] ) op[ix>>3] |= (1<<(ix&7));
2294 unsigned long white_pix = WhitePixel(display, screen);
2295 unsigned long black_pix = BlackPixel(display, screen);
2296 Pixmap img_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2297 img, iw,ih, white_pix,black_pix, 1);
2298 Pixmap msk_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2299 msk, iw,ih, white_pix,black_pix, 1);
2302 fc.flags = bc.flags = DoRed | DoGreen | DoBlue;
2303 fc.red = 0xffff; fc.green = fc.blue = 0; // fg
2304 bc.red = 0xffff; bc.green = 0xffff; bc.blue = 0x0000; // bg
2305 Cursor cursor = XCreatePixmapCursor(display, img_xpm,msk_xpm, &fc,&bc, iw2,ih2);
2306 XFreePixmap(display, img_xpm);
2307 XFreePixmap(display, msk_xpm);
2311 int BC_WindowBase::allocate_color_table()
2313 int red, green, blue, color;
2316 for(int i = 0; i < total_colors; i++)
2318 color = color_table[i][0];
2319 red = (color & 0xFF0000) >> 16;
2320 green = (color & 0x00FF00) >> 8;
2321 blue = color & 0xFF;
2323 col.flags = DoRed | DoGreen | DoBlue;
2324 col.red = red<<8 | red;
2325 col.green = green<<8 | green;
2326 col.blue = blue<<8 | blue;
2328 XAllocColor(display, cmap, &col);
2329 color_table[i][1] = col.pixel;
2332 XInstallColormap(display, cmap);
2336 int BC_WindowBase::init_window_shape()
2338 if(bg_pixmap && bg_pixmap->use_alpha())
2340 XShapeCombineMask(top_level->display,
2341 this->win, ShapeBounding, 0, 0,
2342 bg_pixmap->get_alpha(), ShapeSet);
2348 int BC_WindowBase::init_gc()
2350 unsigned long gcmask;
2351 gcmask = GCFont | GCGraphicsExposures;
2354 gcvalues.font = mediumfont->fid; // set the font
2355 gcvalues.graphics_exposures = 0; // prevent expose events for every redraw
2356 gc = XCreateGC(display, rootwin, gcmask, &gcvalues);
2358 // gcmask = GCCapStyle | GCJoinStyle;
2359 // XGetGCValues(display, gc, gcmask, &gcvalues);
2360 // printf("BC_WindowBase::init_gc %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2364 int BC_WindowBase::init_fonts()
2366 if( !(smallfont = XLoadQueryFont(display, _(resources->small_font))) )
2367 if( !(smallfont = XLoadQueryFont(display, _(resources->small_font2))) )
2368 smallfont = XLoadQueryFont(display, "fixed");
2369 if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font))) )
2370 if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font2))) )
2371 mediumfont = XLoadQueryFont(display, "fixed");
2372 if( !(largefont = XLoadQueryFont(display, _(resources->large_font))) )
2373 if( !(largefont = XLoadQueryFont(display, _(resources->large_font2))) )
2374 largefont = XLoadQueryFont(display, "fixed");
2375 if( !(bigfont = XLoadQueryFont(display, _(resources->big_font))) )
2376 if( !(bigfont = XLoadQueryFont(display, _(resources->big_font2))) )
2377 bigfont = XLoadQueryFont(display, "fixed");
2379 if((clockfont = XLoadQueryFont(display, _(resources->clock_font))) == NULL)
2380 if((clockfont = XLoadQueryFont(display, _(resources->clock_font2))) == NULL)
2381 clockfont = XLoadQueryFont(display, "fixed");
2384 if(get_resources()->use_fontset)
2389 // FIXME: should check the m,d,n values
2390 smallfontset = XCreateFontSet(display, resources->small_fontset, &m, &n, &d);
2392 smallfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2393 mediumfontset = XCreateFontSet(display, resources->medium_fontset, &m, &n, &d);
2394 if( !mediumfontset )
2395 mediumfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2396 largefontset = XCreateFontSet(display, resources->large_fontset, &m, &n, &d);
2398 largefontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2399 bigfontset = XCreateFontSet(display, resources->big_fontset, &m, &n, &d);
2401 bigfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2402 clockfontset = XCreateFontSet(display, resources->clock_fontset, &m, &n, &d);
2404 clockfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2405 if(clockfontset && bigfontset && largefontset && mediumfontset && smallfontset) {
2406 curr_fontset = mediumfontset;
2407 get_resources()->use_fontset = 1;
2411 get_resources()->use_fontset = 0;
2418 void BC_WindowBase::init_xft()
2421 if( !get_resources()->use_xft ) return;
2422 // apparently, xft is not reentrant, more than this is needed
2423 static Mutex xft_init_lock("BC_WindowBase::xft_init_lock", 0);
2424 xft_init_lock.lock("BC_WindowBase::init_xft");
2425 if(!(smallfont_xft =
2426 (resources->small_font_xft[0] == '-' ?
2427 xftFontOpenXlfd(display, screen, resources->small_font_xft) :
2428 xftFontOpenName(display, screen, resources->small_font_xft))) )
2429 if(!(smallfont_xft =
2430 xftFontOpenXlfd(display, screen, resources->small_font_xft2)))
2431 smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2432 if(!(mediumfont_xft =
2433 (resources->medium_font_xft[0] == '-' ?
2434 xftFontOpenXlfd(display, screen, resources->medium_font_xft) :
2435 xftFontOpenName(display, screen, resources->medium_font_xft))) )
2436 if(!(mediumfont_xft =
2437 xftFontOpenXlfd(display, screen, resources->medium_font_xft2)))
2438 mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2439 if(!(largefont_xft =
2440 (resources->large_font_xft[0] == '-' ?
2441 xftFontOpenXlfd(display, screen, resources->large_font_xft) :
2442 xftFontOpenName(display, screen, resources->large_font_xft))) )
2443 if(!(largefont_xft =
2444 xftFontOpenXlfd(display, screen, resources->large_font_xft2)))
2445 largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2447 (resources->big_font_xft[0] == '-' ?
2448 xftFontOpenXlfd(display, screen, resources->big_font_xft) :
2449 xftFontOpenName(display, screen, resources->big_font_xft))) )
2451 xftFontOpenXlfd(display, screen, resources->big_font_xft2)))
2452 bigfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2453 if(!(clockfont_xft =
2454 (resources->clock_font_xft[0] == '-' ?
2455 xftFontOpenXlfd(display, screen, resources->clock_font_xft) :
2456 xftFontOpenName(display, screen, resources->clock_font_xft))) )
2457 clockfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2460 if(!(bold_smallfont_xft =
2461 (resources->small_b_font_xft[0] == '-' ?
2462 xftFontOpenXlfd(display, screen, resources->small_b_font_xft) :
2463 xftFontOpenName(display, screen, resources->small_b_font_xft))) )
2464 bold_smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2465 if(!(bold_mediumfont_xft =
2466 (resources->medium_b_font_xft[0] == '-' ?
2467 xftFontOpenXlfd(display, screen, resources->medium_b_font_xft) :
2468 xftFontOpenName(display, screen, resources->medium_b_font_xft))) )
2469 bold_mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2470 if(!(bold_largefont_xft =
2471 (resources->large_b_font_xft[0] == '-' ?
2472 xftFontOpenXlfd(display, screen, resources->large_b_font_xft) :
2473 xftFontOpenName(display, screen, resources->large_b_font_xft))) )
2474 bold_largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2476 if( !smallfont_xft || !mediumfont_xft || !largefont_xft || !bigfont_xft ||
2477 !bold_largefont_xft || !bold_mediumfont_xft || !bold_largefont_xft ||
2479 printf("BC_WindowBase::init_fonts: no xft fonts found:"
2480 " %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n",
2481 resources->small_font_xft, smallfont_xft,
2482 resources->medium_font_xft, mediumfont_xft,
2483 resources->large_font_xft, largefont_xft,
2484 resources->big_font_xft, bigfont_xft,
2485 resources->clock_font_xft, clockfont_xft,
2486 resources->small_b_font_xft, bold_smallfont_xft,
2487 resources->medium_b_font_xft, bold_mediumfont_xft,
2488 resources->large_b_font_xft, bold_largefont_xft);
2489 get_resources()->use_xft = 0;
2492 // _XftDisplayInfo needs a lock.
2493 xftDefaultHasRender(display);
2494 xft_init_lock.unlock();
2498 void BC_WindowBase::init_glyphs()
2500 // draw all ascii char glyphs
2501 // There are problems with some/my graphics boards/drivers
2502 // which cause some glyphs to be munged if draws occur while
2503 // the font is being loaded. This code fills the font caches
2504 // by drawing all the ascii glyphs before the system starts.
2505 // Not a fix, but much better than nothing.
2506 static int inited = 0;
2507 if( inited ) return;
2508 XGrabServer(display);
2511 int cur_font = current_font;
2512 // locale encodings, needed glyphs to be preloaded
2513 const char *text = _( // ascii 0x20...0x7e
2514 " !\"#$%&'()*+,-./0123456789:;<=>?"
2515 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
2516 "`abcdefghijklmnopqrstuvwxyz{|}~");
2517 for( int font=SMALLFONT; font<=LARGEFONT; ++font ) {
2519 draw_text(5,5, text);
2522 XUngrabServer(display);
2525 void BC_WindowBase::init_im()
2527 XIMStyles *xim_styles;
2530 if(!(input_method = XOpenIM(display, NULL, NULL, NULL)))
2532 printf("BC_WindowBase::init_im: Could not open input method.\n");
2535 if(XGetIMValues(input_method, XNQueryInputStyle, &xim_styles, NULL) ||
2538 printf("BC_WindowBase::init_im: Input method doesn't support any styles.\n");
2539 XCloseIM(input_method);
2544 for(int z = 0; z < xim_styles->count_styles; z++)
2546 if(xim_styles->supported_styles[z] == (XIMPreeditNothing | XIMStatusNothing))
2548 xim_style = xim_styles->supported_styles[z];
2556 printf("BC_WindowBase::init_im: Input method doesn't support the style we need.\n");
2557 XCloseIM(input_method);
2561 input_context = XCreateIC(input_method, XNInputStyle, xim_style,
2562 XNClientWindow, win, XNFocusWindow, win, NULL);
2565 printf("BC_WindowBase::init_im: Failed to create input context.\n");
2566 XCloseIM(input_method);
2571 void BC_WindowBase::finit_im()
2573 if( input_context ) {
2574 XDestroyIC(input_context);
2577 if( input_method ) {
2578 XCloseIM(input_method);
2584 int BC_WindowBase::get_color(int64_t color)
2586 // return pixel of color
2587 // use this only for drawing subwindows not for bitmaps
2588 int i, test, difference;
2594 return get_color_rgb8(color);
2595 // test last color looked up
2596 if(current_color_value == color)
2597 return current_color_pixel;
2600 current_color_value = color;
2601 for(i = 0; i < total_colors; i++)
2603 if(color_table[i][0] == color)
2605 current_color_pixel = color_table[i][1];
2606 return current_color_pixel;
2610 // find nearest match
2611 difference = 0xFFFFFF;
2613 for(i = 0; i < total_colors; i++)
2615 test = abs((int)(color_table[i][0] - color));
2617 if(test < difference)
2619 current_color_pixel = color_table[i][1];
2623 return current_color_pixel;
2626 return get_color_rgb16(color);
2629 return get_color_bgr16(color);
2633 return client_byte_order == server_byte_order ?
2634 color : get_color_bgr24(color);
2642 int BC_WindowBase::get_color_rgb8(int color)
2646 pixel = (color & 0xc00000) >> 16;
2647 pixel += (color & 0xe000) >> 10;
2648 pixel += (color & 0xe0) >> 5;
2652 int64_t BC_WindowBase::get_color_rgb16(int color)
2655 result = (color & 0xf80000) >> 8;
2656 result += (color & 0xfc00) >> 5;
2657 result += (color & 0xf8) >> 3;
2662 int64_t BC_WindowBase::get_color_bgr16(int color)
2665 result = (color & 0xf80000) >> 19;
2666 result += (color & 0xfc00) >> 5;
2667 result += (color & 0xf8) << 8;
2672 int64_t BC_WindowBase::get_color_bgr24(int color)
2675 result = (color & 0xff) << 16;
2676 result += (color & 0xff00);
2677 result += (color & 0xff0000) >> 16;
2681 void BC_WindowBase::start_video()
2683 cursor_timer->update();
2685 // set_color(BLACK);
2686 // draw_box(0, 0, get_w(), get_h());
2690 void BC_WindowBase::stop_video()
2698 int64_t BC_WindowBase::get_color()
2700 return top_level->current_color;
2703 void BC_WindowBase::set_color(int64_t color)
2705 top_level->current_color = color;
2706 XSetForeground(top_level->display,
2708 top_level->get_color(color));
2711 void BC_WindowBase::set_opaque()
2713 XSetFunction(top_level->display, top_level->gc, GXcopy);
2716 void BC_WindowBase::set_inverse()
2718 XSetFunction(top_level->display, top_level->gc, GXxor);
2721 void BC_WindowBase::set_line_width(int value)
2723 this->line_width = value;
2724 XSetLineAttributes(top_level->display, top_level->gc, value, /* line_width */
2725 line_dashes == 0 ? LineSolid : LineOnOffDash, /* line_style */
2726 line_dashes == 0 ? CapRound : CapNotLast, /* cap_style */
2727 JoinMiter); /* join_style */
2729 if(line_dashes > 0) {
2730 const char dashes = line_dashes;
2731 XSetDashes(top_level->display, top_level->gc, 0, &dashes, 1);
2734 // XGCValues gcvalues;
2735 // unsigned long gcmask;
2736 // gcmask = GCCapStyle | GCJoinStyle;
2737 // XGetGCValues(top_level->display, top_level->gc, gcmask, &gcvalues);
2738 // printf("BC_WindowBase::set_line_width %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2741 void BC_WindowBase::set_line_dashes(int value)
2743 line_dashes = value;
2744 // call XSetLineAttributes
2745 set_line_width(line_width);
2749 Cursor BC_WindowBase::get_cursor_struct(int cursor)
2753 case ARROW_CURSOR: return top_level->arrow_cursor;
2754 case CROSS_CURSOR: return top_level->cross_cursor;
2755 case IBEAM_CURSOR: return top_level->ibeam_cursor;
2756 case VSEPARATE_CURSOR: return top_level->vseparate_cursor;
2757 case HSEPARATE_CURSOR: return top_level->hseparate_cursor;
2758 case MOVE_CURSOR: return top_level->move_cursor;
2759 case LEFT_CURSOR: return top_level->left_cursor;
2760 case RIGHT_CURSOR: return top_level->right_cursor;
2761 case UPRIGHT_ARROW_CURSOR: return top_level->upright_arrow_cursor;
2762 case UPLEFT_RESIZE: return top_level->upleft_resize_cursor;
2763 case UPRIGHT_RESIZE: return top_level->upright_resize_cursor;
2764 case DOWNLEFT_RESIZE: return top_level->downleft_resize_cursor;
2765 case DOWNRIGHT_RESIZE: return top_level->downright_resize_cursor;
2766 case HOURGLASS_CURSOR: return top_level->hourglass_cursor;
2767 case TRANSPARENT_CURSOR: return top_level->transparent_cursor;
2768 case GRABBED_CURSOR: return top_level->grabbed_cursor;
2773 void BC_WindowBase::set_cursor(int cursor, int override, int flush)
2775 // inherit cursor from parent
2778 XUndefineCursor(top_level->display, win);
2779 current_cursor = cursor;
2782 // don't change cursor if overridden
2783 if((!top_level->is_hourglass && !is_transparent) ||
2786 XDefineCursor(top_level->display, win, get_cursor_struct(cursor));
2787 if(flush) this->flush();
2790 if(!override) current_cursor = cursor;
2793 void BC_WindowBase::set_x_cursor(int cursor)
2795 temp_cursor = XCreateFontCursor(top_level->display, cursor);
2796 XDefineCursor(top_level->display, win, temp_cursor);
2797 current_cursor = cursor;
2801 int BC_WindowBase::get_cursor()
2803 return current_cursor;
2806 void BC_WindowBase::start_hourglass()
2808 top_level->start_hourglass_recursive();
2812 void BC_WindowBase::stop_hourglass()
2814 top_level->stop_hourglass_recursive();
2818 void BC_WindowBase::start_hourglass_recursive()
2820 if(this == top_level)
2828 set_cursor(HOURGLASS_CURSOR, 1, 0);
2829 for(int i = 0; i < subwindows->total; i++)
2831 subwindows->values[i]->start_hourglass_recursive();
2836 void BC_WindowBase::stop_hourglass_recursive()
2838 if(this == top_level)
2840 if(hourglass_total == 0) return;
2841 top_level->hourglass_total--;
2844 if(!top_level->hourglass_total)
2846 top_level->is_hourglass = 0;
2848 // Cause set_cursor to perform change
2850 set_cursor(current_cursor, 1, 0);
2852 for(int i = 0; i < subwindows->total; i++)
2854 subwindows->values[i]->stop_hourglass_recursive();
2862 XFontStruct* BC_WindowBase::get_font_struct(int font)
2864 // Clear out unrelated flags
2865 if(font & BOLDFACE) font ^= BOLDFACE;
2868 case SMALLFONT: return top_level->smallfont; break;
2869 case MEDIUMFONT: return top_level->mediumfont; break;
2870 case LARGEFONT: return top_level->largefont; break;
2871 case BIGFONT: return top_level->bigfont; break;
2872 case CLOCKFONT: return top_level->clockfont; break;
2877 XFontSet BC_WindowBase::get_fontset(int font)
2881 if(get_resources()->use_fontset)
2883 switch(font & 0xff) {
2884 case SMALLFONT: fs = top_level->smallfontset; break;
2885 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2886 case LARGEFONT: fs = top_level->largefontset; break;
2887 case BIGFONT: fs = top_level->bigfontset; break;
2888 case CLOCKFONT: fs = top_level->clockfontset; break;
2896 XftFont* BC_WindowBase::get_xft_struct(int font)
2899 case SMALLFONT: return (XftFont*)top_level->smallfont_xft;
2900 case MEDIUMFONT: return (XftFont*)top_level->mediumfont_xft;
2901 case LARGEFONT: return (XftFont*)top_level->largefont_xft;
2902 case BIGFONT: return (XftFont*)top_level->bigfont_xft;
2903 case CLOCKFONT: return (XftFont*)top_level->clockfont_xft;
2904 case MEDIUMFONT_3D: return (XftFont*)top_level->bold_mediumfont_xft;
2905 case SMALLFONT_3D: return (XftFont*)top_level->bold_smallfont_xft;
2906 case LARGEFONT_3D: return (XftFont*)top_level->bold_largefont_xft;
2914 int BC_WindowBase::get_current_font()
2916 return top_level->current_font;
2919 void BC_WindowBase::set_font(int font)
2921 top_level->current_font = font;
2924 if(get_resources()->use_xft) {}
2927 if(get_resources()->use_fontset) {
2931 if(get_font_struct(font))
2933 XSetFont(top_level->display, top_level->gc, get_font_struct(font)->fid);
2939 void BC_WindowBase::set_fontset(int font)
2943 if(get_resources()->use_fontset) {
2945 case SMALLFONT: fs = top_level->smallfontset; break;
2946 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2947 case LARGEFONT: fs = top_level->largefontset; break;
2948 case BIGFONT: fs = top_level->bigfontset; break;
2949 case CLOCKFONT: fs = top_level->clockfontset; break;
2957 XFontSet BC_WindowBase::get_curr_fontset(void)
2959 if(get_resources()->use_fontset)
2960 return curr_fontset;
2964 int BC_WindowBase::get_single_text_width(int font, const char *text, int length)
2967 if(get_resources()->use_xft && get_xft_struct(font))
2970 #ifdef X_HAVE_UTF8_STRING
2971 if(get_resources()->locale_utf8)
2973 xftTextExtentsUtf8(top_level->display,
2974 get_xft_struct(font),
2975 (const XftChar8 *)text,
2982 xftTextExtents8(top_level->display,
2983 get_xft_struct(font),
2984 (const XftChar8 *)text,
2988 return extents.xOff;
2992 if(get_resources()->use_fontset && top_level->get_fontset(font))
2993 return XmbTextEscapement(top_level->get_fontset(font), text, length);
2995 if(get_font_struct(font))
2996 return XTextWidth(get_font_struct(font), text, length);
3002 case MEDIUM_7SEGMENT:
3003 return get_resources()->medium_7segment[0]->get_w() * length;
3013 int BC_WindowBase::get_text_width(int font, const char *text, int length)
3015 int i, j, w = 0, line_w = 0;
3016 if(length < 0) length = strlen(text);
3018 for(i = 0, j = 0; i <= length; i++)
3023 line_w = get_single_text_width(font, &text[j], i - j);
3029 line_w = get_single_text_width(font, &text[j], length - j);
3031 if(line_w > w) w = line_w;
3034 if(i > length && w == 0)
3036 w = get_single_text_width(font, text, length);
3042 int BC_WindowBase::get_text_width(int font, const wchr_t *text, int length)
3045 if( length < 0 ) length = wstrlen(text);
3047 for( i=j=0; i<length && text[i]; ++i ) {
3048 if( text[i] != '\n' ) continue;
3050 int lw = get_single_text_width(font, &text[j], i-j);
3051 if( w < lw ) w = lw;
3056 int lw = get_single_text_width(font, &text[j], length-j);
3057 if( w < lw ) w = lw;
3063 int BC_WindowBase::get_text_ascent(int font)
3067 if( (fstruct = get_xft_struct(font)) != 0 )
3068 return fstruct->ascent;
3070 if(get_resources()->use_fontset && top_level->get_fontset(font))
3072 XFontSetExtents *extents;
3074 extents = XExtentsOfFontSet(top_level->get_fontset(font));
3075 return -extents->max_logical_extent.y;
3078 if(get_font_struct(font))
3079 return top_level->get_font_struct(font)->ascent;
3082 case MEDIUM_7SEGMENT:
3083 return get_resources()->medium_7segment[0]->get_h();
3088 int BC_WindowBase::get_text_descent(int font)
3092 if( (fstruct = get_xft_struct(font)) != 0 )
3093 return fstruct->descent;
3095 if(get_resources()->use_fontset && top_level->get_fontset(font)) {
3096 XFontSetExtents *extents;
3097 extents = XExtentsOfFontSet(top_level->get_fontset(font));
3098 return (extents->max_logical_extent.height
3099 + extents->max_logical_extent.y);
3102 if(get_font_struct(font))
3103 return top_level->get_font_struct(font)->descent;
3108 int BC_WindowBase::get_text_height(int font, const char *text)
3113 if( (fstruct = get_xft_struct(font)) != 0 )
3114 rowh = fstruct->height;
3117 rowh = get_text_ascent(font) + get_text_descent(font);
3119 if(!text) return rowh;
3121 // Add height of lines
3122 int h = 0, i, length = strlen(text);
3123 for(i = 0; i <= length; i++)
3134 // truncate the text with ... & return a new string
3135 char *BC_WindowBase::get_truncated_text(int font, const char *text, int max_w)
3137 char *result = cstrdup(text);
3138 int text_w = get_text_width(font, text);
3139 int ci = -1, len = strlen(text);
3140 if( text_w > max_w ) {
3141 // get center of string
3142 int cx = text_w/2, best = INT_MAX;
3143 for( int i=1; i<=len; ++i ) {
3144 int cw = get_text_width(font, text, i);
3145 if( abs(cw-cx) < abs(best-cx) ) {
3150 if( ci > 0 && ci < len-1 ) {
3151 // insert ... in the center
3152 result[ci-1] = result[ci] = result[ci+1] = '.';
3154 while( ci-2>=0 && ci+2<(int)strlen(result) &&
3155 get_text_width(font, result) > max_w ) {
3156 // take away a character from the longer side
3157 int left_w = get_text_width(font, result, ci-2);
3158 int right_w = get_text_width(font, result + ci+3);
3159 int i = left_w > right_w ? --ci-1 : ci+2;
3160 while( (result[i]=result[i+1])!=0 ) ++i;
3167 BC_Bitmap* BC_WindowBase::new_bitmap(int w, int h, int color_model)
3169 if(color_model < 0) color_model = top_level->get_color_model();
3170 return new BC_Bitmap(top_level, w, h, color_model);
3173 void BC_WindowBase::init_wait()
3175 #ifndef SINGLE_THREAD
3176 if(window_type != MAIN_WINDOW)
3177 top_level->init_wait();
3178 init_lock->lock("BC_WindowBase::init_wait");
3179 init_lock->unlock();
3183 int BC_WindowBase::accel_available(int color_model, int lock_it)
3185 if( window_type != MAIN_WINDOW )
3186 return top_level->accel_available(color_model, lock_it);
3188 lock_window("BC_WindowBase::accel_available");
3190 switch(color_model) {
3192 grab_port_id(color_model);
3196 grab_port_id(color_model);
3205 //printf("BC_WindowBase::accel_available %d %d\n", color_model, xvideo_port_id);
3206 return xvideo_port_id >= 0 ? 1 : 0;
3210 int BC_WindowBase::grab_port_id(int color_model)
3213 if( !get_resources()->use_xvideo || // disabled
3214 !get_resources()->use_shm ) // Only local server is fast enough.
3216 if( xvideo_port_id >= 0 )
3217 return xvideo_port_id;
3219 unsigned int ver, rev, reqBase, eventBase, errorBase;
3220 if( Success != XvQueryExtension(display, // XV extension is available
3221 &ver, &rev, &reqBase, &eventBase, &errorBase) )
3224 // XV adaptors are available
3225 unsigned int numAdapt = 0;
3226 XvAdaptorInfo *info = 0;
3227 XvQueryAdaptors(display, DefaultRootWindow(display), &numAdapt, &info);
3231 // Translate from color_model to X color model
3232 int x_color_model = BC_CModels::bc_to_x(color_model);
3234 // Get adaptor with desired color model
3235 for( int i = 0; i < (int)numAdapt && xvideo_port_id == -1; i++) {
3236 if( !(info[i].type & XvImageMask) || !info[i].num_ports ) continue;
3237 // adaptor supports XvImages
3238 int numFormats = 0, numPorts = info[i].num_ports;
3239 XvImageFormatValues *formats =
3240 XvListImageFormats(display, info[i].base_id, &numFormats);
3241 if( !formats ) continue;
3243 for( int j=0; j<numFormats && xvideo_port_id<0; ++j ) {
3244 if( formats[j].id != x_color_model ) continue;
3245 // this adaptor supports the desired format, grab a port
3246 for( int k=0; k<numPorts; ++k ) {
3247 if( Success == XvGrabPort(top_level->display,
3248 info[i].base_id+k, CurrentTime) ) {
3249 //printf("BC_WindowBase::grab_port_id %llx\n", info[i].base_id);
3250 xvideo_port_id = info[i].base_id + k;
3258 XvFreeAdaptorInfo(info);
3259 return xvideo_port_id;
3266 int BC_WindowBase::show_window(int flush)
3268 for(int i = 0; i < subwindows->size(); i++)
3270 subwindows->get(i)->show_window(0);
3273 XMapWindow(top_level->display, win);
3274 if(flush) XFlush(top_level->display);
3275 // XSync(top_level->display, 0);
3280 int BC_WindowBase::hide_window(int flush)
3282 for(int i = 0; i < subwindows->size(); i++)
3284 subwindows->get(i)->hide_window(0);
3287 XUnmapWindow(top_level->display, win);
3288 if(flush) this->flush();
3293 BC_MenuBar* BC_WindowBase::add_menubar(BC_MenuBar *menu_bar)
3295 subwindows->append((BC_SubWindow*)menu_bar);
3297 menu_bar->parent_window = this;
3298 menu_bar->top_level = this->top_level;
3299 menu_bar->initialize();
3303 BC_WindowBase* BC_WindowBase::add_popup(BC_WindowBase *window)
3305 //printf("BC_WindowBase::add_popup window=%p win=%p\n", window, window->win);
3306 if(this != top_level) return top_level->add_popup(window);
3307 popups.append(window);
3311 void BC_WindowBase::remove_popup(BC_WindowBase *window)
3313 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3314 if(this != top_level)
3315 top_level->remove_popup(window);
3317 popups.remove(window);
3318 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3322 BC_WindowBase* BC_WindowBase::add_subwindow(BC_WindowBase *subwindow)
3324 subwindows->append(subwindow);
3326 if(subwindow->bg_color == -1) subwindow->bg_color = this->bg_color;
3328 // parent window must be set before the subwindow initialization
3329 subwindow->parent_window = this;
3330 subwindow->top_level = this->top_level;
3332 // Execute derived initialization
3333 subwindow->initialize();
3338 BC_WindowBase* BC_WindowBase::add_tool(BC_WindowBase *subwindow)
3340 return add_subwindow(subwindow);
3343 int BC_WindowBase::flash(int x, int y, int w, int h, int flush)
3345 if( !top_level->flash_enabled ) return 0;
3346 //printf("BC_WindowBase::flash %d %d %d %d %d\n", __LINE__, w, h, this->w, this->h);
3348 XSetWindowBackgroundPixmap(top_level->display, win, pixmap->opaque_pixmap);
3351 XClearArea(top_level->display, win, x, y, w, h, 0);
3355 XClearWindow(top_level->display, win);
3363 int BC_WindowBase::flash(int flush)
3365 flash(-1, -1, -1, -1, flush);
3369 void BC_WindowBase::flush()
3371 //if(!get_window_lock())
3372 // printf("BC_WindowBase::flush %s not locked\n", top_level->title);
3373 // X gets hosed if Flush/Sync are not user locked (at libX11-1.1.5 / libxcb-1.1.91)
3374 // _XReply deadlocks in condition_wait waiting for xlib lock when waiters!=-1
3375 int locked = get_window_lock();
3376 if( !locked ) lock_window("BC_WindowBase::flush");
3377 XFlush(top_level->display);
3378 if( !locked ) unlock_window();
3381 void BC_WindowBase::sync_display()
3383 int locked = get_window_lock();
3384 if( !locked ) lock_window("BC_WindowBase::sync_display");
3385 XSync(top_level->display, False);
3386 if( !locked ) unlock_window();
3389 int BC_WindowBase::get_window_lock()
3391 #ifdef SINGLE_THREAD
3392 return BC_Display::display_global->get_display_locked();
3394 return top_level->window_lock;
3398 int BC_WindowBase::lock_window(const char *location)
3400 if(top_level && top_level != this)
3402 top_level->lock_window(location);
3407 SET_LOCK(this, title, location);
3408 #ifdef SINGLE_THREAD
3409 BC_Display::lock_display(location);
3411 XLockDisplay(top_level->display);
3412 top_level->display_lock_owner = pthread_self();
3415 ++top_level->window_lock;
3419 printf("BC_WindowBase::lock_window top_level NULL\n");
3424 int BC_WindowBase::unlock_window()
3426 if(top_level && top_level != this)
3428 top_level->unlock_window();
3434 if( !top_level->window_lock ) {
3435 printf("BC_WindowBase::unlock_window %s not locked\n", title);
3438 if( top_level->window_lock > 0 )
3439 if( --top_level->window_lock == 0 )
3440 top_level->display_lock_owner = 0;
3441 #ifdef SINGLE_THREAD
3442 BC_Display::unlock_display();
3444 XUnlockDisplay(top_level->display);
3449 printf("BC_WindowBase::unlock_window top_level NULL\n");
3454 int BC_WindowBase::break_lock()
3456 if( !top_level ) return 0;
3457 if( top_level != this ) return top_level->break_lock();
3458 if( top_level->display_lock_owner != pthread_self() ) return 0;
3459 if( top_level->window_lock != 1 ) return 0;
3462 display_lock_owner = 0;
3463 #ifdef SINGLE_THREAD
3464 BC_Display::unlock_display();
3466 XUnlockDisplay(display);
3471 void BC_WindowBase::set_done(int return_value)
3473 if(done_set) return;
3475 if(window_type != MAIN_WINDOW)
3476 top_level->set_done(return_value);
3479 #ifdef SINGLE_THREAD
3480 this->return_value = return_value;
3481 BC_Display::display_global->arm_completion(this);
3482 completion_lock->unlock();
3483 #else // SINGLE_THREAD
3485 if( !event_thread ) return;
3486 XEvent *event = new_xevent();
3487 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
3488 event->type = ClientMessage;
3489 ptr->message_type = SetDoneXAtom;
3491 this->return_value = return_value;
3492 // May lock up here because XSendEvent doesn't work too well
3493 // asynchronous with XNextEvent.
3494 // This causes BC_WindowEvents to forward a copy of the event to run_window where
3496 // Deletion of event_thread is done at the end of BC_WindowBase::run_window() - by calling the destructor
3502 void BC_WindowBase::close(int return_value)
3504 hide_window(); flush();
3505 set_done(return_value);
3508 int BC_WindowBase::grab(BC_WindowBase *window)
3511 BC_WindowBase *grab_window = window->active_grab;
3513 int locked = get_window_lock();
3514 if( locked ) unlock_window();
3515 grab_window->lock_window("BC_WindowBase::grab(BC_WindowBase");
3516 grab_window->handle_ungrab();
3517 grab_window->unlock_window();
3518 if( locked ) lock_window("BC_WindowBase::grab(BC_WindowBase");
3520 window->grab_lock->lock("BC_WindowBase::grab");
3521 if( !window->active_grab ) {
3522 window->active_grab = this;
3523 this->grab_active = window;
3526 window->grab_lock->unlock();
3529 int BC_WindowBase::ungrab(BC_WindowBase *window)
3532 window->grab_lock->lock("BC_WindowBase::ungrab");
3533 if( this == window->active_grab ) {
3534 window->active_grab = 0;
3535 this->grab_active = 0;
3538 window->grab_lock->unlock();
3541 int BC_WindowBase::grab_event_count()
3544 #ifndef SINGLE_THREAD
3545 result = grab_active->get_event_count();
3549 int BC_WindowBase::grab_buttons()
3551 XSync(top_level->display, False);
3552 if( XGrabButton(top_level->display, AnyButton, AnyModifier,
3553 top_level->rootwin, True, ButtonPressMask | ButtonReleaseMask,
3554 GrabModeAsync, GrabModeSync, None, None) == GrabSuccess ) {
3555 set_active_subwindow(this);
3560 void BC_WindowBase::ungrab_buttons()
3562 XUngrabButton(top_level->display, AnyButton, AnyModifier, top_level->rootwin);
3563 set_active_subwindow(0);
3566 void BC_WindowBase::grab_cursor()
3568 Cursor cursor_grab = get_cursor_struct(GRABBED_CURSOR);
3569 XGrabPointer(top_level->display, top_level->rootwin, True,
3570 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
3571 GrabModeAsync, GrabModeAsync, None, cursor_grab, CurrentTime);
3573 void BC_WindowBase::ungrab_cursor()
3575 XUngrabPointer(top_level->display, CurrentTime);
3579 // WidthOfScreen/HeightOfScreen of XDefaultScreenOfDisplay
3580 // this is the bounding box of all the screens
3582 int BC_WindowBase::get_root_w(int lock_display)
3584 if(lock_display) lock_window("BC_WindowBase::get_root_w");
3585 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3586 int result = WidthOfScreen(def_screen);
3587 if(lock_display) unlock_window();
3591 int BC_WindowBase::get_root_h(int lock_display)
3593 if(lock_display) lock_window("BC_WindowBase::get_root_h");
3594 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3595 int result = HeightOfScreen(def_screen);
3596 if(lock_display) unlock_window();
3600 XineramaScreenInfo *
3601 BC_WindowBase::get_xinerama_info(int screen)
3603 if( !xinerama_info || !xinerama_screens ) return 0;
3605 for( int i=0; i<xinerama_screens; ++i )
3606 if( xinerama_info[i].screen_number == screen )
3607 return &xinerama_info[i];
3610 int top_x = get_x(), top_y = get_y();
3611 if( BC_DisplayInfo::left_border >= 0 ) top_x += BC_DisplayInfo::left_border;
3612 if( BC_DisplayInfo::top_border >= 0 ) top_y += BC_DisplayInfo::top_border;
3613 for( int i=0; i<xinerama_screens; ++i ) {
3614 int scr_y = top_y - xinerama_info[i].y_org;
3615 if( scr_y < 0 || scr_y >= xinerama_info[i].height ) continue;
3616 int scr_x = top_x - xinerama_info[i].x_org;
3617 if( scr_x >= 0 && scr_x < xinerama_info[i].width )
3618 return &xinerama_info[i];
3623 void BC_WindowBase::get_fullscreen_geometry(int &wx, int &wy, int &ww, int &wh)
3625 XineramaScreenInfo *info = top_level->get_xinerama_info(-1);
3627 wx = info->x_org; wy = info->y_org;
3628 ww = info->width; wh = info->height;
3631 wx = get_screen_x(0, -1);
3632 wy = get_screen_y(0, -1);
3633 int scr_w0 = get_screen_w(0, 0);
3634 int root_w = get_root_w(0);
3635 int root_h = get_root_h(0);
3636 if( root_w > scr_w0 ) { // multi-headed
3637 if( wx >= scr_w0 ) {
3638 // assumes right side is the big one
3639 ww = root_w - scr_w0;
3643 // use same aspect ratio to compute left height
3645 wh = (w*root_h) / (root_w-scr_w0);
3655 int BC_WindowBase::get_screen_x(int lock_display, int screen)
3658 if(lock_display) lock_window("BC_WindowBase::get_screen_x");
3659 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3662 int root_w = get_root_w(0);
3663 int root_h = get_root_h(0);
3664 // Shift X based on position of current window if dual head
3665 if( (float)root_w/root_h > 1.8 ) {
3666 root_w = get_screen_w(0, 0);
3667 if( top_level->get_x() >= root_w )
3672 result = info->x_org;
3673 if(lock_display) unlock_window();
3677 int BC_WindowBase::get_screen_y(int lock_display, int screen)
3679 if(lock_display) lock_window("BC_WindowBase::get_screen_y");
3680 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3681 int result = !info ? 0 : info->y_org;
3682 if(lock_display) unlock_window();
3686 int BC_WindowBase::get_screen_w(int lock_display, int screen)
3689 if(lock_display) lock_window("BC_WindowBase::get_screen_w");
3690 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3692 int width = get_root_w(0);
3693 int height = get_root_h(0);
3694 if( (float)width/height > 1.8 ) {
3695 // If dual head, the screen width is > 16x9
3696 // but we only want to fill one screen
3697 // this code assumes the "big" screen is on the right
3698 int scr_w0 = width / 2;
3700 case 600: scr_w0 = 800; break;
3701 case 720: scr_w0 = 1280; break;
3702 case 1024: scr_w0 = 1280; break;
3703 case 1200: scr_w0 = 1600; break;
3704 case 1080: scr_w0 = 1920; break;
3706 int scr_w1 = width - scr_w0;
3707 result = screen > 0 ? scr_w1 :
3708 screen == 0 ? scr_w0 :
3709 top_level->get_x() < scr_w0 ? scr_w0 : scr_w1;
3715 result = info->width;
3716 if(lock_display) unlock_window();
3720 int BC_WindowBase::get_screen_h(int lock_display, int screen)
3722 if(lock_display) lock_window("BC_WindowBase::get_screen_h");
3723 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3724 int result = info ? info->height : get_root_h(0);
3725 if(lock_display) unlock_window();
3729 // Bottom right corner
3730 int BC_WindowBase::get_x2()
3735 int BC_WindowBase::get_y2()
3740 int BC_WindowBase::get_video_on()
3745 int BC_WindowBase::get_hidden()
3747 return top_level->hidden;
3750 int BC_WindowBase::cursor_inside()
3752 return (top_level->cursor_x >= 0 &&
3753 top_level->cursor_y >= 0 &&
3754 top_level->cursor_x < w &&
3755 top_level->cursor_y < h);
3758 BC_WindowBase* BC_WindowBase::get_top_level()
3763 BC_WindowBase* BC_WindowBase::get_parent()
3765 return parent_window;
3768 int BC_WindowBase::get_color_model()
3770 return top_level->color_model;
3773 BC_Resources* BC_WindowBase::get_resources()
3775 return BC_WindowBase::resources;
3778 BC_Synchronous* BC_WindowBase::get_synchronous()
3780 return BC_WindowBase::resources->get_synchronous();
3783 int BC_WindowBase::get_bg_color()
3788 void BC_WindowBase::set_bg_color(int color)
3790 this->bg_color = color;
3793 BC_Pixmap* BC_WindowBase::get_bg_pixmap()
3798 void BC_WindowBase::set_active_subwindow(BC_WindowBase *subwindow)
3800 top_level->active_subwindow = subwindow;
3803 int BC_WindowBase::activate()
3808 int BC_WindowBase::deactivate()
3810 if(window_type == MAIN_WINDOW)
3812 if( top_level->active_menubar ) {
3813 top_level->active_menubar->deactivate();
3814 top_level->active_menubar = 0;
3816 if( top_level->active_popup_menu ) {
3817 top_level->active_popup_menu->deactivate();
3818 top_level->active_popup_menu = 0;
3820 if( top_level->active_subwindow ) {
3821 top_level->active_subwindow->deactivate();
3822 top_level->active_subwindow = 0;
3824 if( top_level->motion_events && top_level->last_motion_win == this->win )
3825 top_level->motion_events = 0;
3831 int BC_WindowBase::cycle_textboxes(int amount)
3834 BC_WindowBase *new_textbox = 0;
3838 BC_WindowBase *first_textbox = 0;
3839 find_next_textbox(&first_textbox, &new_textbox, result);
3840 if(!new_textbox) new_textbox = first_textbox;
3846 BC_WindowBase *last_textbox = 0;
3847 find_prev_textbox(&last_textbox, &new_textbox, result);
3848 if(!new_textbox) new_textbox = last_textbox;
3852 if(new_textbox != active_subwindow)
3855 new_textbox->activate();
3861 int BC_WindowBase::find_next_textbox(BC_WindowBase **first_textbox, BC_WindowBase **next_textbox, int &result)
3863 // Search subwindows for textbox
3864 for(int i = 0; i < subwindows->total && result < 2; i++)
3866 BC_WindowBase *test_subwindow = subwindows->values[i];
3867 test_subwindow->find_next_textbox(first_textbox, next_textbox, result);
3874 if(!*first_textbox) *first_textbox = this;
3878 if(top_level->active_subwindow == this)
3884 *next_textbox = this;
3891 int BC_WindowBase::find_prev_textbox(BC_WindowBase **last_textbox, BC_WindowBase **prev_textbox, int &result)
3897 if(!*last_textbox) *last_textbox = this;
3901 if(top_level->active_subwindow == this)
3907 *prev_textbox = this;
3912 // Search subwindows for textbox
3913 for(int i = subwindows->total - 1; i >= 0 && result < 2; i--)
3915 BC_WindowBase *test_subwindow = subwindows->values[i];
3916 test_subwindow->find_prev_textbox(last_textbox, prev_textbox, result);
3921 BC_Clipboard* BC_WindowBase::get_clipboard()
3923 #ifdef SINGLE_THREAD
3924 return BC_Display::display_global->clipboard;
3926 return top_level->clipboard;
3930 Atom BC_WindowBase::to_clipboard(const char *data, long len, int clipboard_num)
3932 return get_clipboard()->to_clipboard(this, data, len, clipboard_num);
3935 long BC_WindowBase::from_clipboard(char *data, long maxlen, int clipboard_num)
3937 return get_clipboard()->from_clipboard(data, maxlen, clipboard_num);
3940 long BC_WindowBase::clipboard_len(int clipboard_num)
3942 return get_clipboard()->clipboard_len(clipboard_num);
3945 int BC_WindowBase::do_selection_clear(Window win)
3947 top_level->event_win = win;
3948 return dispatch_selection_clear();
3951 int BC_WindowBase::dispatch_selection_clear()
3954 for( int i=0; i<subwindows->total && !result; ++i )
3955 result = subwindows->values[i]->dispatch_selection_clear();
3957 result = selection_clear_event();
3962 void BC_WindowBase::get_relative_cursor(int &x, int &y, int lock_window)
3964 int abs_x, abs_y, win_x, win_y;
3965 unsigned int temp_mask;
3968 if(lock_window) this->lock_window("BC_WindowBase::get_relative_cursor");
3969 XQueryPointer(top_level->display, top_level->win,
3970 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3973 XTranslateCoordinates(top_level->display, top_level->rootwin,
3974 win, abs_x, abs_y, &x, &y, &temp_win);
3975 if(lock_window) this->unlock_window();
3977 int BC_WindowBase::get_relative_cursor_x(int lock_window)
3980 get_relative_cursor(x, y, lock_window);
3983 int BC_WindowBase::get_relative_cursor_y(int lock_window)
3986 get_relative_cursor(x, y, lock_window);
3990 void BC_WindowBase::get_abs_cursor(int &abs_x, int &abs_y, int lock_window)
3993 unsigned int temp_mask;
3996 if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor");
3997 XQueryPointer(top_level->display, top_level->win,
3998 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
4000 if(lock_window) this->unlock_window();
4002 int BC_WindowBase::get_abs_cursor_x(int lock_window)
4005 get_abs_cursor(abs_x, abs_y, lock_window);
4008 int BC_WindowBase::get_abs_cursor_y(int lock_window)
4011 get_abs_cursor(abs_x, abs_y, lock_window);
4015 void BC_WindowBase::get_pop_cursor(int &px, int &py, int lock_window)
4017 int xmargin = xS(100), ymargin = yS(100);
4018 get_abs_cursor(px, py, lock_window);
4019 if( px < xmargin ) px = xmargin;
4020 if( py < ymargin ) py = ymargin;
4021 int wd = get_screen_x(lock_window,-1) + get_screen_w(lock_window,-1) - xmargin;
4022 if( px > wd ) px = wd;
4023 int ht = get_screen_y(lock_window,-1) + get_screen_h(lock_window,-1) - ymargin;
4024 if( py > ht ) py = ht;
4026 int BC_WindowBase::get_pop_cursor_x(int lock_window)
4029 get_pop_cursor(px, py, lock_window);
4032 int BC_WindowBase::get_pop_cursor_y(int lock_window)
4035 get_pop_cursor(px, py, lock_window);
4039 int BC_WindowBase::match_window(Window win)
4041 if (this->win == win) return 1;
4043 for(int i = 0; i < subwindows->total; i++) {
4044 result = subwindows->values[i]->match_window(win);
4045 if (result) return result;
4051 int BC_WindowBase::get_cursor_over_window()
4053 int abs_x, abs_y, win_x, win_y;
4054 unsigned int mask_return;
4055 Window root_return, child_return;
4057 int ret = XQueryPointer(top_level->display, top_level->rootwin,
4058 &root_return, &child_return, &abs_x, &abs_y,
4059 &win_x, &win_y, &mask_return);
4060 if( ret && child_return == None ) ret = 0;
4061 if( ret && win != child_return )
4062 ret = top_level->match_window(child_return);
4063 // query pointer can return a window manager window with this top_level as a child
4064 // for kde this can be two levels deep
4065 unsigned int nchildren_return = 0;
4066 Window parent_return, *children_return = 0;
4067 Window top_win = top_level->win;
4068 while( !ret && top_win != top_level->rootwin && top_win != root_return &&
4069 XQueryTree(top_level->display, top_win, &root_return,
4070 &parent_return, &children_return, &nchildren_return) ) {
4071 if( children_return ) XFree(children_return);
4072 if( (top_win=parent_return) == child_return ) ret = 1;
4077 int BC_WindowBase::cursor_above()
4080 get_relative_cursor(rx, ry);
4081 return rx < 0 || rx >= get_w() ||
4082 ry < 0 || ry >= get_h() ? 0 : 1;
4085 int BC_WindowBase::get_drag_x()
4087 return top_level->drag_x;
4090 int BC_WindowBase::get_drag_y()
4092 return top_level->drag_y;
4095 int BC_WindowBase::get_cursor_x()
4097 return top_level->cursor_x;
4100 int BC_WindowBase::get_cursor_y()
4102 return top_level->cursor_y;
4105 int BC_WindowBase::dump_windows()
4107 printf("\tBC_WindowBase::dump_windows window=%p win=%p '%s', %dx%d+%d+%d %s\n",
4108 this, (void*)this->win, title, w,h,x,y, typeid(*this).name());
4109 for(int i = 0; i < subwindows->size(); i++)
4110 subwindows->get(i)->dump_windows();
4111 for(int i = 0; i < popups.size(); i++) {
4112 BC_WindowBase *p = popups[i];
4113 printf("\tBC_WindowBase::dump_windows popup=%p win=%p '%s', %dx%d+%d+%d %s\n",
4114 p, (void*)p->win, p->title, p->w,p->h,p->x,p->y, typeid(*p).name());
4119 int BC_WindowBase::is_event_win()
4121 return this->win == top_level->event_win;
4124 int BC_WindowBase::is_tooltip_event_win()
4126 return this->win == top_level->event_win ||
4127 tooltip_popup && tooltip_popup->win == top_level->event_win;
4130 void BC_WindowBase::set_dragging(int value)
4132 is_dragging = value;
4135 int BC_WindowBase::get_dragging()
4140 int BC_WindowBase::get_buttonpress()
4142 return top_level->button_number;
4145 int BC_WindowBase::get_button_down()
4147 return top_level->button_down;
4150 int BC_WindowBase::alt_down()
4152 return top_level->alt_mask;
4155 int BC_WindowBase::shift_down()
4157 return top_level->shift_mask;
4160 int BC_WindowBase::ctrl_down()
4162 return top_level->ctrl_mask;
4165 wchr_t* BC_WindowBase::get_wkeystring(int *length)
4168 *length = top_level->wkey_string_length;
4169 return top_level->wkey_string;
4172 #ifdef X_HAVE_UTF8_STRING
4173 char* BC_WindowBase::get_keypress_utf8()
4175 return top_level->key_pressed_utf8;
4180 int BC_WindowBase::get_keypress()
4182 return top_level->key_pressed;
4185 int BC_WindowBase::get_double_click()
4187 return top_level->double_click;
4190 int BC_WindowBase::get_triple_click()
4192 return top_level->triple_click;
4195 int BC_WindowBase::get_bgcolor()
4200 int BC_WindowBase::resize_window(int w, int h)
4202 if(this->w == w && this->h == h) return 0;
4204 if(window_type == MAIN_WINDOW && !allow_resize)
4206 XSizeHints size_hints;
4207 size_hints.flags = PSize | PMinSize | PMaxSize;
4208 size_hints.width = w;
4209 size_hints.height = h;
4210 size_hints.min_width = w;
4211 size_hints.max_width = w;
4212 size_hints.min_height = h;
4213 size_hints.max_height = h;
4214 if( this->x > -BC_INFINITY && this->x < BC_INFINITY ) {
4215 size_hints.flags |= PPosition;
4216 size_hints.x = this->x;
4217 size_hints.y = this->y;
4219 XSetNormalHints(top_level->display, win, &size_hints);
4221 XResizeWindow(top_level->display, win, w, h);
4226 pixmap = new BC_Pixmap(this, w, h);
4228 // Propagate to menubar
4229 for(int i = 0; i < subwindows->total; i++)
4231 subwindows->values[i]->dispatch_resize_event(w, h);
4234 draw_background(0, 0, w, h);
4235 if(top_level == this && get_resources()->recursive_resizing)
4236 resize_history.append(new BC_ResizeCall(w, h));
4240 // The only way for resize events to be propagated is by updating the internal w and h
4241 int BC_WindowBase::resize_event(int w, int h)
4243 if(window_type == MAIN_WINDOW)
4251 int BC_WindowBase::reposition_window(int x, int y)
4253 reposition_window(x, y, -1, -1);
4258 int BC_WindowBase::reposition_window(int x, int y, int w, int h)
4262 // Some tools set their own dimensions before calling this, causing the
4263 // resize check to skip.
4267 if(w > 0 && w != this->w)
4273 if(h > 0 && h != this->h)
4279 //printf("BC_WindowBase::reposition_window %d %d %d\n", translation_count, x_correction, y_correction);
4282 printf("BC_WindowBase::reposition_window this->w == %d\n", this->w);
4284 printf("BC_WindowBase::reposition_window this->h == %d\n", this->h);
4286 if(translation_count && window_type == MAIN_WINDOW)
4288 // KDE shifts window right and down.
4289 // FVWM leaves window alone and adds border around it.
4290 XMoveResizeWindow(top_level->display, win,
4291 x - BC_DisplayInfo::auto_reposition_x,
4292 y - BC_DisplayInfo::auto_reposition_y,
4297 XMoveResizeWindow(top_level->display, win, x, y,
4304 pixmap = new BC_Pixmap(this, this->w, this->h);
4305 clear_box(0,0, this->w, this->h);
4306 // Propagate to menubar
4307 for(int i = 0; i < subwindows->total; i++)
4309 subwindows->values[i]->dispatch_resize_event(this->w, this->h);
4312 // draw_background(0, 0, w, h);
4318 int BC_WindowBase::reposition_window_relative(int dx, int dy, int w, int h)
4320 return reposition_window(get_x()+dx, get_y()+dy, w, h);
4323 int BC_WindowBase::reposition_window_relative(int dx, int dy)
4325 return reposition_window_relative(dx, dy, -1, -1);
4328 void BC_WindowBase::set_tooltips(int v)
4330 get_resources()->tooltips_enabled = v;
4333 void BC_WindowBase::set_force_tooltip(int v)
4338 int BC_WindowBase::raise_window(int do_flush)
4340 if( hidden ) return 1;
4341 if( wait_viewable(500) ) return 1;
4342 XRaiseWindow(top_level->display, win);
4343 if(do_flush) XFlush(top_level->display);
4347 int BC_WindowBase::lower_window(int do_flush)
4349 XLowerWindow(top_level->display, win);
4350 if(do_flush) XFlush(top_level->display);
4354 void BC_WindowBase::set_background(VFrame *bitmap)
4356 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
4358 bg_pixmap = new BC_Pixmap(this, bitmap, PIXMAP_OPAQUE);
4359 shared_bg_pixmap = 0;
4360 draw_background(0, 0, w, h);
4363 void BC_WindowBase::put_title(const char *text)
4365 char *cp = this->title, *ep = cp+sizeof(this->title)-1;
4366 for( const unsigned char *bp = (const unsigned char *)text; *bp && cp<ep; ++bp )
4367 *cp++ = *bp >= ' ' ? *bp : ' ';
4371 void BC_WindowBase::set_title(const char *text, int utf8)
4373 // utf8>0: wm + net_wm, utf8=0: wm only, utf<0: net_wm only
4375 const unsigned char *wm_title = (const unsigned char *)title;
4376 int title_len = strlen((const char *)title);
4378 Atom xa_wm_name = XA_WM_NAME;
4379 Atom xa_icon_name = XA_WM_ICON_NAME;
4380 Atom xa_string = XA_STRING;
4381 XChangeProperty(display, win, xa_wm_name, xa_string, 8,
4382 PropModeReplace, wm_title, title_len);
4383 XChangeProperty(display, win, xa_icon_name, xa_string, 8,
4384 PropModeReplace, wm_title, title_len);
4387 Atom xa_net_wm_name = XInternAtom(display, "_NET_WM_NAME", True);
4388 Atom xa_net_icon_name = XInternAtom(display, "_NET_WM_ICON_NAME", True);
4389 Atom xa_utf8_string = XInternAtom(display, "UTF8_STRING", True);
4390 XChangeProperty(display, win, xa_net_wm_name, xa_utf8_string, 8,
4391 PropModeReplace, wm_title, title_len);
4392 XChangeProperty(display, win, xa_net_icon_name, xa_utf8_string, 8,
4393 PropModeReplace, wm_title, title_len);
4399 void BC_WindowBase::set_net_icon(VFrame *data)
4401 int width = data->get_w(), height = data->get_h();
4402 int size = 2 + width * height;
4403 unsigned long *icon_data = new unsigned long[size];
4404 unsigned long *lp = icon_data;
4405 *lp++ = width; *lp++ = height;
4406 uint8_t **rows = data->get_rows();
4407 for( int y=0; y<height; ++y ) {
4408 unsigned *up = (unsigned *)rows[y];
4409 for( int x=0; x<width; ++x )
4410 *lp++ = *(unsigned *)up++;
4412 Atom NetWMIcon = XInternAtom(display, "_NET_WM_ICON", True);
4413 XChangeProperty(top_level->display, top_level->win, NetWMIcon,
4414 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)icon_data, size);
4415 delete [] icon_data;
4418 const char *BC_WindowBase::get_title()
4423 int BC_WindowBase::get_toggle_value()
4425 return toggle_value;
4428 int BC_WindowBase::get_toggle_drag()
4433 int BC_WindowBase::set_icon(VFrame *data)
4435 if(icon_pixmap) delete icon_pixmap;
4436 icon_pixmap = new BC_Pixmap(top_level, data, PIXMAP_ALPHA, 1);
4438 if(icon_window) delete icon_window;
4439 icon_window = new BC_Popup(this, 0, 0,
4440 icon_pixmap->get_w(), icon_pixmap->get_h(),
4441 -1, 1, // All windows are hidden initially
4444 XWMHints wm_hints; memset(&wm_hints, 0, sizeof(wm_hints));
4445 wm_hints.flags = IconPixmapHint; // | IconMaskHint | IconWindowHint;
4446 wm_hints.icon_pixmap = icon_pixmap->get_pixmap();
4447 wm_hints.icon_mask = icon_pixmap->get_alpha();
4448 wm_hints.icon_window = icon_window->win;
4449 if( XGroupLeader ) {
4450 wm_hints.flags |= WindowGroupHint;
4451 wm_hints.window_group = XGroupLeader;
4454 // for(int i = 0; i < 1000; i++)
4455 // printf("02x ", icon_pixmap->get_alpha()->get_row_pointers()[0][i]);
4458 XSetWMHints(top_level->display, top_level->win, &wm_hints);
4461 XSync(top_level->display, 0);
4465 void BC_WindowBase::init_resources(float scale)
4467 if( resources ) return;
4469 const char *env = getenv("BC_SCALE");
4470 if( env ) scale = atof(env);
4471 float x_scale = 1, y_scale = 1;
4473 BC_DisplayInfo info;
4475 int cins = info.xinerama_big_screen();
4476 if( !info.xinerama_geometry(cins, wx, wy, ww, wh) ) {
4477 int sh = ww * 9 / 16;
4478 int sw = wh * 16 / 9;
4479 if( sw < ww ) ww = sw;
4480 if( sh < wh ) wh = sh;
4481 if( (x_scale = ww/1920.) < 1 ) x_scale = 1;
4482 if( (y_scale = wh/1080.) < 1 ) y_scale = 1;
4486 x_scale = y_scale = scale;
4487 // constructor sets BC_WindowBase::resources
4488 new BC_Resources(x_scale, y_scale);
4490 void BC_WindowBase::finit_resources()
4492 delete resources; resources = 0;
4495 int BC_WindowBase::set_w(int w)
4501 int BC_WindowBase::set_h(int h)
4507 int BC_WindowBase::load_defaults(BC_Hash *defaults)
4509 char string[BCTEXTLEN];
4510 int newest_id = - 1;
4511 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4513 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4514 resources->filebox_history[i].path[0] = 0;
4515 defaults->get(string, resources->filebox_history[i].path);
4516 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4517 resources->filebox_history[i].id = defaults->get(string, resources->get_id());
4518 if(resources->filebox_history[i].id > newest_id)
4519 newest_id = resources->filebox_history[i].id;
4522 resources->filebox_id = newest_id + 1;
4523 resources->filebox_mode = defaults->get("FILEBOX_MODE", get_resources()->filebox_mode);
4524 resources->filebox_w = defaults->get("FILEBOX_W", get_resources()->filebox_w);
4525 resources->filebox_h = defaults->get("FILEBOX_H", get_resources()->filebox_h);
4526 resources->filebox_columntype[0] = defaults->get("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4527 resources->filebox_columntype[1] = defaults->get("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4528 resources->filebox_columntype[2] = defaults->get("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4529 resources->filebox_columntype[3] = defaults->get("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4530 resources->filebox_columnwidth[0] = defaults->get("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4531 resources->filebox_columnwidth[1] = defaults->get("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4532 resources->filebox_columnwidth[2] = defaults->get("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4533 resources->filebox_columnwidth[3] = defaults->get("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4534 resources->filebox_size_format = defaults->get("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4535 defaults->get("FILEBOX_FILTER", resources->filebox_filter);
4539 int BC_WindowBase::save_defaults(BC_Hash *defaults)
4541 char string[BCTEXTLEN];
4542 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4544 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4545 defaults->update(string, resources->filebox_history[i].path);
4546 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4547 defaults->update(string, resources->filebox_history[i].id);
4549 defaults->update("FILEBOX_MODE", resources->filebox_mode);
4550 defaults->update("FILEBOX_W", resources->filebox_w);
4551 defaults->update("FILEBOX_H", resources->filebox_h);
4552 defaults->update("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4553 defaults->update("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4554 defaults->update("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4555 defaults->update("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4556 defaults->update("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4557 defaults->update("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4558 defaults->update("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4559 defaults->update("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4560 defaults->update("FILEBOX_FILTER", resources->filebox_filter);
4561 defaults->update("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4567 // For some reason XTranslateCoordinates can take a long time to return.
4568 // We work around this by only calling it when the event windows are different.
4569 void BC_WindowBase::translate_coordinates(Window src_w, Window dest_w,
4570 int src_x, int src_y, int *dest_x_return, int *dest_y_return)
4577 *dest_x_return = src_x;
4578 *dest_y_return = src_y;
4582 XTranslateCoordinates(top_level->display, src_w, dest_w,
4583 src_x, src_y, dest_x_return, dest_y_return, &tempwin);
4584 //printf("BC_WindowBase::translate_coordinates 1 %lld\n", timer.get_difference());
4588 void BC_WindowBase::get_root_coordinates(int x, int y, int *abs_x, int *abs_y)
4590 translate_coordinates(win, top_level->rootwin, x, y, abs_x, abs_y);
4593 void BC_WindowBase::get_win_coordinates(int abs_x, int abs_y, int *x, int *y)
4595 translate_coordinates(top_level->rootwin, win, abs_x, abs_y, x, y);
4599 #ifdef HAVE_LIBXXF86VM
4600 void BC_WindowBase::closest_vm(int *vm, int *width, int *height)
4604 if(XF86VidModeQueryExtension(top_level->display,&foo,&bar)) {
4606 XF86VidModeModeInfo **vm_modelines;
4607 XF86VidModeGetAllModeLines(top_level->display,
4608 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4609 for( i = 0; i < vm_count; i++ ) {
4610 if( vm_modelines[i]->hdisplay < vm_modelines[*vm]->hdisplay &&
4611 vm_modelines[i]->hdisplay >= *width )
4614 display = top_level->display;
4615 if( vm_modelines[*vm]->hdisplay == *width )
4618 *width = vm_modelines[*vm]->hdisplay;
4619 *height = vm_modelines[*vm]->vdisplay;
4624 void BC_WindowBase::scale_vm(int vm)
4626 int foo,bar,dotclock;
4627 if( XF86VidModeQueryExtension(top_level->display,&foo,&bar) ) {
4629 XF86VidModeModeInfo **vm_modelines;
4630 XF86VidModeModeLine vml;
4631 XF86VidModeGetAllModeLines(top_level->display,
4632 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4633 XF86VidModeGetModeLine(top_level->display,
4634 XDefaultScreen(top_level->display), &dotclock,&vml);
4635 orig_modeline.dotclock = dotclock;
4636 orig_modeline.hdisplay = vml.hdisplay;
4637 orig_modeline.hsyncstart = vml.hsyncstart;
4638 orig_modeline.hsyncend = vml.hsyncend;
4639 orig_modeline.htotal = vml.htotal;
4640 orig_modeline.vdisplay = vml.vdisplay;
4641 orig_modeline.vsyncstart = vml.vsyncstart;
4642 orig_modeline.vsyncend = vml.vsyncend;
4643 orig_modeline.vtotal = vml.vtotal;
4644 orig_modeline.flags = vml.flags;
4645 orig_modeline.privsize = vml.privsize;
4646 // orig_modeline.private = vml.private;
4647 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),vm_modelines[vm]);
4648 XF86VidModeSetViewPort(top_level->display,XDefaultScreen(top_level->display),0,0);
4649 XFlush(top_level->display);
4653 void BC_WindowBase::restore_vm()
4655 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),&orig_modeline);
4656 XFlush(top_level->display);
4661 #ifndef SINGLE_THREAD
4662 int BC_WindowBase::get_event_count()
4664 event_lock->lock("BC_WindowBase::get_event_count");
4665 int result = common_events.total;
4666 event_lock->unlock();
4670 XEvent* BC_WindowBase::get_event()
4673 while(!done && !result)
4675 event_condition->lock("BC_WindowBase::get_event");
4676 event_lock->lock("BC_WindowBase::get_event");
4678 if(common_events.total && !done)
4680 result = common_events.values[0];
4681 common_events.remove_number(0);
4684 event_lock->unlock();
4689 void BC_WindowBase::put_event(XEvent *event)
4691 event_lock->lock("BC_WindowBase::put_event");
4692 common_events.append(event);
4693 event_lock->unlock();
4694 event_condition->unlock();
4697 void BC_WindowBase::dequeue_events(Window win)
4699 event_lock->lock("BC_WindowBase::dequeue_events");
4701 int out = 0, total = common_events.size();
4702 for( int in=0; in<total; ++in ) {
4703 if( common_events[in]->xany.window == win ) continue;
4704 common_events[out++] = common_events[in];
4706 common_events.total = out;
4708 event_lock->unlock();
4711 int BC_WindowBase::resend_event(BC_WindowBase *window)
4713 if( resend_event_window ) return 1;
4714 resend_event_window = window;
4720 int BC_WindowBase::resend_event(BC_WindowBase *window)
4725 #endif // SINGLE_THREAD
4727 int BC_WindowBase::get_id()
4733 BC_Pixmap *BC_WindowBase::create_pixmap(VFrame *vframe)
4735 int w = vframe->get_w(), h = vframe->get_h();
4736 BC_Pixmap *icon = new BC_Pixmap(this, w, h);
4737 icon->draw_vframe(vframe, 0,0, w,h, 0,0);
4742 void BC_WindowBase::flicker(int n, int ms)
4744 int color = get_bg_color();
4745 for( int i=2*n; --i>=0; ) {
4746 set_inverse(); set_bg_color(WHITE);
4747 clear_box(0,0, w,h); flash(1);
4748 sync_display(); Timer::delay(ms);
4750 set_bg_color(color);
4754 void BC_WindowBase::focus()
4756 XWindowAttributes xwa;
4757 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4758 if( xwa.map_state == IsViewable )
4759 XSetInputFocus(top_level->display, top_level->win, RevertToParent, CurrentTime);
4762 int BC_WindowBase::wait_viewable(int ms)
4765 XWindowAttributes xwa;
4767 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4768 if( xwa.map_state == IsViewable ) return 0;
4770 } while( timer.get_difference() < ms );