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();
228 #ifndef SINGLE_THREAD
229 common_events.remove_all_objects();
231 delete event_condition;
234 top_level->window_lock = 0;
235 BC_Display::unlock_display();
240 if( glx_fbcfgs_window ) XFree(glx_fbcfgs_window);
241 if( glx_fbcfgs_pbuffer) XFree(glx_fbcfgs_pbuffer);
242 if( glx_fbcfgs_pixmap ) XFree(glx_fbcfgs_pixmap);
245 UNSET_ALL_LOCKS(this)
248 int BC_WindowBase::initialize()
253 display_lock_owner = 0;
258 resend_event_window = 0;
270 xinerama_screens = 0;
275 translation_events = 0;
276 ctrl_mask = shift_mask = alt_mask = 0;
277 cursor_x = cursor_y = button_number = 0;
291 active_popup_menu = 0;
292 active_subwindow = 0;
296 _7segment_pixmaps = 0;
299 // next_repeat_id = 0;
301 current_font = MEDIUMFONT;
302 current_color = BLACK;
303 current_cursor = ARROW_CURSOR;
306 shared_bg_pixmap = 0;
309 window_type = MAIN_WINDOW;
310 translation_count = 0;
311 x_correction = y_correction = 0;
320 #ifdef HAVE_LIBXXF86VM
338 bold_smallfont_xft = 0;
339 bold_mediumfont_xft = 0;
340 bold_largefont_xft = 0;
342 completion_lock = new Condition(0, "BC_WindowBase::completion_lock");
344 // Need these right away since put_event is called before run_window sometimes.
345 event_lock = new Mutex("BC_WindowBase::event_lock");
346 event_condition = new Condition(0, "BC_WindowBase::event_condition");
347 init_lock = new Condition(0, "BC_WindowBase::init_lock");
350 cursor_timer = new Timer;
353 glx_fbcfgs_window = 0; n_fbcfgs_window = 0;
354 glx_fbcfgs_pbuffer = 0; n_fbcfgs_pbuffer = 0;
355 glx_fbcfgs_pixmap = 0; n_fbcfgs_pixmap = 0;
369 #define DEFAULT_EVENT_MASKS EnterWindowMask | \
372 ButtonReleaseMask | \
373 PointerMotionMask | \
377 int BC_WindowBase::create_window(BC_WindowBase *parent_window, const char *title,
378 int x, int y, int w, int h, int minw, int minh, int allow_resize,
379 int private_color, int hide, int bg_color, const char *display_name,
380 int window_type, BC_Pixmap *bg_pixmap, int group_it)
382 XSetWindowAttributes attr;
384 XSizeHints size_hints;
387 #ifdef HAVE_LIBXXF86VM
391 id = get_resources()->get_id();
392 if(parent_window) top_level = parent_window->top_level;
393 if( top_level ) lock_window("BC_WindowBase::create_window");
394 get_resources()->create_window_lock->lock("BC_WindowBase::create_window");
396 #ifdef HAVE_LIBXXF86VM
397 if(window_type == VIDMODE_SCALED_WINDOW)
398 closest_vm(&vm,&w,&h);
405 this->bg_color = bg_color;
406 this->window_type = window_type;
408 this->private_color = private_color;
409 this->parent_window = parent_window;
410 this->bg_pixmap = bg_pixmap;
411 this->allow_resize = allow_resize;
413 strcpy(this->display_name, display_name);
415 this->display_name[0] = 0;
418 if(bg_pixmap) shared_bg_pixmap = 1;
420 subwindows = new BC_SubWindowList;
422 if(window_type == MAIN_WINDOW)
425 parent_window = this;
429 display = BC_Display::get_display(display_name);
430 BC_Display::lock_display("BC_WindowBase::create_window");
431 // BC_Display::display_global->new_window(this);
434 // get the display connection
436 // This function must be the first Xlib
437 // function a multi-threaded program calls
439 display = init_display(display_name);
440 if( shm_completion_event < 0 ) shm_completion_event =
441 ShmCompletion + XShmGetEventBase(display);
443 lock_window("BC_WindowBase::create_window 1");
445 screen = DefaultScreen(display);
446 rootwin = RootWindow(display, screen);
447 // window placement boundaries
448 if( !xinerama_screens && XineramaIsActive(display) )
449 xinerama_info = XineramaQueryScreens(display, &xinerama_screens);
450 root_w = get_root_w(0);
451 root_h = get_root_h(0);
454 vis = get_glx_visual(display);
458 int mask = VisualDepthMask | VisualClassMask;
459 static XVisualInfo vinfo;
460 memset(&vinfo, 0, sizeof(vinfo));
462 vinfo.c_class = TrueColor;
464 XVisualInfo *vis_info = XGetVisualInfo(display, mask, &vinfo, &nitems);
465 vis = vis_info && nitems>0 ? vis_info[0].visual : 0;
466 if( vis_info ) XFree(vis_info);
469 vis = DefaultVisual(display, screen);
470 default_depth = DefaultDepth(display, screen);
472 client_byte_order = (*(const u_int32_t*)"a ") & 0x00000001;
473 server_byte_order = (XImageByteOrder(display) == MSBFirst) ? 0 : 1;
476 // This must be done before fonts to know if antialiasing is available.
479 if(resources->use_shm < 0) resources->initialize_display(this);
480 x_correction = BC_DisplayInfo::get_left_border();
481 y_correction = BC_DisplayInfo::get_top_border();
483 // clamp window placement
484 if(this->x + this->w + x_correction > root_w)
485 this->x = root_w - this->w - x_correction;
486 if(this->y + this->h + y_correction > root_h)
487 this->y = root_h - this->h - y_correction;
488 if(this->x < 0) this->x = 0;
489 if(this->y < 0) this->y = 0;
491 if(this->bg_color == -1)
492 this->bg_color = resources->get_bg_color();
494 // printf("bcwindowbase 1 %s\n", title);
495 // if(window_type == MAIN_WINDOW) sleep(1);
496 // printf("bcwindowbase 10\n");
502 mask = CWEventMask | CWBackPixel | CWColormap | CWCursor;
504 attr.event_mask = DEFAULT_EVENT_MASKS |
505 StructureNotifyMask |
509 attr.background_pixel = get_color(this->bg_color);
510 attr.colormap = cmap;
511 attr.cursor = get_cursor_struct(ARROW_CURSOR);
513 win = XCreateWindow(display, rootwin,
514 this->x, this->y, this->w, this->h, 0,
515 top_level->default_depth, InputOutput,
517 XGetNormalHints(display, win, &size_hints);
519 size_hints.flags = PSize | PMinSize | PMaxSize;
520 size_hints.width = this->w;
521 size_hints.height = this->h;
522 size_hints.min_width = allow_resize ? minw : this->w;
523 size_hints.max_width = allow_resize ? 32767 : this->w;
524 size_hints.min_height = allow_resize ? minh : this->h;
525 size_hints.max_height = allow_resize ? 32767 : this->h;
526 if(x > -BC_INFINITY && x < BC_INFINITY)
528 size_hints.flags |= PPosition;
529 size_hints.x = this->x;
530 size_hints.y = this->y;
532 XSetWMProperties(display, win, 0, 0, 0, 0, &size_hints, 0, 0);
535 #ifndef SINGLE_THREAD
536 clipboard = new BC_Clipboard(this);
537 clipboard->start_clipboard();
543 Atom ClientLeaderXAtom;
544 if (XGroupLeader == 0)
546 const char *instance_name = "cinelerra";
547 const char *class_name = "Cinelerra";
548 XClassHint *class_hints = XAllocClassHint();
549 class_hints->res_name = (char*)instance_name;
550 class_hints->res_class = (char*)class_name;
551 XSetClassHint(top_level->display, win, class_hints);
553 ClientLeaderXAtom = XInternAtom(display, "WM_CLIENT_LEADER", True);
554 XChangeProperty(display, win, ClientLeaderXAtom, XA_WINDOW, 32,
555 PropModeReplace, (unsigned char *)&XGroupLeader, true);
558 set_icon(get_resources()->default_icon);
561 #ifdef HAVE_LIBXXF86VM
562 if(window_type == VIDMODE_SCALED_WINDOW && vm != -1)
569 #ifdef HAVE_LIBXXF86VM
570 if(window_type == POPUP_WINDOW || window_type == VIDMODE_SCALED_WINDOW)
572 if(window_type == POPUP_WINDOW)
575 mask = CWEventMask | CWBackPixel | CWColormap |
576 CWOverrideRedirect | CWSaveUnder | CWCursor;
578 attr.event_mask = DEFAULT_EVENT_MASKS | ExposureMask |
579 KeyPressMask | KeyReleaseMask;
581 if(this->bg_color == -1)
582 this->bg_color = resources->get_bg_color();
583 attr.background_pixel = top_level->get_color(bg_color);
584 attr.colormap = top_level->cmap;
585 if(top_level->is_hourglass)
586 attr.cursor = top_level->get_cursor_struct(HOURGLASS_CURSOR);
588 attr.cursor = top_level->get_cursor_struct(ARROW_CURSOR);
589 attr.override_redirect = True;
590 attr.save_under = True;
592 win = XCreateWindow(top_level->display,
593 top_level->rootwin, this->x, this->y, this->w, this->h, 0,
594 top_level->default_depth, InputOutput, top_level->vis, mask,
596 top_level->add_popup(this);
599 if(window_type == SUB_WINDOW)
601 mask = CWEventMask | CWBackPixel | CWCursor;
602 attr.event_mask = DEFAULT_EVENT_MASKS;
603 attr.background_pixel = top_level->get_color(this->bg_color);
604 if(top_level->is_hourglass)
605 attr.cursor = top_level->get_cursor_struct(HOURGLASS_CURSOR);
607 attr.cursor = top_level->get_cursor_struct(ARROW_CURSOR);
608 win = XCreateWindow(top_level->display,
609 parent_window->win, this->x, this->y, this->w, this->h, 0,
610 top_level->default_depth, InputOutput, top_level->vis, mask,
613 if(!hidden) XMapWindow(top_level->display, win);
616 // Create pixmap for all windows
617 pixmap = new BC_Pixmap(this, this->w, this->h);
619 // Set up options for main window
620 if(window_type == MAIN_WINDOW)
622 if(get_resources()->bg_image && !bg_pixmap && bg_color < 0)
624 this->bg_pixmap = new BC_Pixmap(this,
625 get_resources()->bg_image,
629 if(!hidden) show_window();
633 draw_background(0, 0, this->w, this->h);
635 flash(-1, -1, -1, -1, 0);
637 // Set up options for popup window
638 #ifdef HAVE_LIBXXF86VM
639 if(window_type == POPUP_WINDOW || window_type == VIDMODE_SCALED_WINDOW)
641 if(window_type == POPUP_WINDOW)
645 if(!hidden) show_window();
647 get_resources()->create_window_lock->unlock();
653 Display* BC_WindowBase::init_display(const char *display_name)
657 if(display_name && display_name[0] == 0) display_name = NULL;
658 if((display = XOpenDisplay(display_name)) == NULL) {
659 printf("BC_WindowBase::init_display: cannot connect to X server %s\n",
661 if(getenv("DISPLAY") == NULL) {
662 printf(_("'DISPLAY' environment variable not set.\n"));
665 // Try again with default display.
666 if((display = XOpenDisplay(0)) == NULL) {
667 printf("BC_WindowBase::init_display: cannot connect to default X server.\n");
672 static int xsynch = -1;
674 const char *cp = getenv("CIN_XSYNCH");
675 xsynch = !cp ? 0 : atoi(cp);
678 XSynchronize(display, True);
683 Display* BC_WindowBase::get_display()
685 return top_level->display;
688 int BC_WindowBase::get_screen()
690 return top_level->screen;
693 int BC_WindowBase::run_window()
699 // Events may have been sent before run_window so can't initialize them here.
702 set_repeat(get_resources()->tooltip_delay);
703 BC_Display::display_global->new_window(this);
705 // If the first window created, run the display loop in this thread.
706 if(BC_Display::display_global->is_first(this))
708 BC_Display::unlock_display();
709 BC_Display::display_global->loop();
713 BC_Display::unlock_display();
714 completion_lock->lock("BC_WindowBase::run_window");
717 BC_Display::lock_display("BC_WindowBase::run_window");
718 BC_Display::display_global->delete_window(this);
720 unset_all_repeaters();
722 BC_Display::unlock_display();
724 #else // SINGLE_THREAD
729 set_repeat(get_resources()->tooltip_delay);
731 // Start X server events
732 event_thread = new BC_WindowEvents(this);
733 event_thread->start();
739 // Handle common events
744 unset_all_repeaters();
748 event_condition->reset();
749 common_events.remove_all_objects();
753 #endif // SINGLE_THREAD
758 int BC_WindowBase::get_key_masks(unsigned int key_state)
760 // printf("BC_WindowBase::get_key_masks %llx\n",
761 // event->xkey.state);
762 ctrl_mask = (key_state & ControlMask) ? 1 : 0; // ctrl key down
763 shift_mask = (key_state & ShiftMask) ? 1 : 0; // shift key down
764 alt_mask = (key_state & Mod1Mask) ? 1 : 0; // alt key down
769 void BC_WindowBase::add_keyboard_listener(int(BC_WindowBase::*handler)(BC_WindowBase *))
771 BC_KeyboardHandlerLock set;
772 BC_KeyboardHandler::listeners.append(new BC_KeyboardHandler(handler, this));
775 void BC_WindowBase::del_keyboard_listener(int(BC_WindowBase::*handler)(BC_WindowBase *))
777 BC_KeyboardHandlerLock set;
778 int i = BC_KeyboardHandler::listeners.size();
779 while( --i >= 0 && BC_KeyboardHandler::listeners[i]->handler!=handler );
780 if( i >= 0 ) BC_KeyboardHandler::listeners.remove_object_number(i);
783 int BC_KeyboardHandler::run_event(BC_WindowBase *wp)
785 int result = (win->*handler)(wp);
789 int BC_KeyboardHandler::run_listeners(BC_WindowBase *wp)
792 BC_KeyboardHandlerLock set;
793 for( int i=0; !result && i<listeners.size(); ++i ) {
794 BC_KeyboardHandler *listener = listeners[i];
795 result = listener->run_event(wp);
800 void BC_KeyboardHandler::kill_grabs()
802 BC_KeyboardHandlerLock set;
803 for( int i=0; i<listeners.size(); ++i ) {
804 BC_WindowBase *win = listeners[i]->win;
805 if( win->get_window_type() != POPUP_WINDOW ) continue;
806 ((BC_Popup *)win)->ungrab_keyboard();
810 void BC_ActiveBitmaps::reque(XEvent *event)
812 XShmCompletionEvent *shm_ev = (XShmCompletionEvent *)event;
813 ShmSeg shmseg = shm_ev->shmseg;
814 Drawable drawable = shm_ev->drawable;
815 //printf("BC_BitmapImage::reque %08lx\n",shmseg);
816 active_lock.lock("BC_BitmapImage::reque");
817 BC_BitmapImage *bfr = first;
818 while( bfr && bfr->get_shmseg() != shmseg ) bfr = bfr->next;
819 if( bfr && bfr->drawable == drawable )
821 active_lock.unlock();
823 // sadly, X reports two drawable completions and creates false reporting, so no boobytrap
824 // printf("BC_BitmapImage::reque missed shmseg %08x, drawable %08x\n",
825 // (int)shmseg, (int)drawable);
828 if( bfr->drawable != drawable ) return;
829 if( bfr->is_zombie() ) { --BC_Bitmap::zombies; delete bfr; return; }
830 bfr->bitmap->reque(bfr);
833 void BC_ActiveBitmaps::insert(BC_BitmapImage *bfr, Drawable pixmap)
835 active_lock.lock("BC_BitmapImage::insert");
836 bfr->drawable = pixmap;
838 active_lock.unlock();
841 void BC_ActiveBitmaps::remove_buffers(BC_WindowBase *wdw)
843 active_lock.lock("BC_ActiveBitmaps::remove");
844 for( BC_BitmapImage *nxt=0, *bfr=first; bfr; bfr=nxt ) {
846 if( bfr->is_zombie() ) { --BC_Bitmap::zombies; delete bfr; continue; }
847 if( bfr->bitmap->parent_window == wdw ) remove_pointer(bfr);
849 active_lock.unlock();
852 BC_ActiveBitmaps::BC_ActiveBitmaps()
856 BC_ActiveBitmaps::~BC_ActiveBitmaps()
862 int BC_WindowBase::keysym_lookup(XEvent *event)
864 for( int i = 0; i < KEYPRESSLEN; ++i ) keys_return[i] = 0;
865 for( int i = 0; i < 4; ++i ) wkey_string[i] = 0;
867 if( event->xany.send_event && !event->xany.serial ) {
868 keysym = (KeySym) event->xkey.keycode;
869 keys_return[0] = keysym;
872 wkey_string_length = 0;
874 if( input_context ) {
876 wkey_string_length = XwcLookupString(input_context,
877 (XKeyEvent*)event, wkey, 4, &keysym, 0);
878 for( int i=0; i<wkey_string_length; ++i )
879 wkey_string[i] = wkey[i];
880 //printf("keysym_lookup 1 %d %d %lx %x %x %x %x\n", wkey_string_length, keysym,
881 // wkey_string[0], wkey_string[1], wkey_string[2], wkey_string[3]);
884 int ret = Xutf8LookupString(input_context, (XKeyEvent*)event,
885 keys_return, KEYPRESSLEN, &keysym, &stat);
886 //printf("keysym_lookup 2 %d %d %lx %x %x\n", ret, stat, keysym, keys_return[0], keys_return[1]);
887 if( stat == XLookupBoth ) return ret;
888 if( stat == XLookupKeySym ) return 0;
890 int ret = XLookupString((XKeyEvent*)event, keys_return, KEYPRESSLEN, &keysym, 0);
891 wkey_string_length = ret;
892 for( int i=0; i<ret; ++i ) wkey_string[i] = keys_return[i];
896 pthread_t locking_task = (pthread_t)-1L;
897 int locking_event = -1;
898 int locking_message = -1;
900 int BC_WindowBase::dispatch_event()
904 XClientMessageEvent *ptr;
905 int cancel_resize, cancel_translation;
906 volatile static int debug = 0;
911 #ifndef SINGLE_THREAD
912 // If an event is waiting get it, otherwise
913 // wait for next event only if there are no compressed events.
914 if(get_event_count() ||
915 (!motion_events && !resize_events && !translation_events))
918 // Lock out window deletions
919 lock_window("BC_WindowBase::dispatch_event 1");
920 locking_event = event->type;
921 locking_task = pthread_self();
922 locking_message = event->xclient.message_type;
925 // Handle compressed events
927 lock_window("BC_WindowBase::dispatch_event 2");
929 dispatch_resize_event(last_resize_w, last_resize_h);
931 dispatch_motion_event();
932 if(translation_events)
933 dispatch_translation_event();
944 if( debug && event->type != ClientMessage ) {
945 static const char *event_names[] = {
946 "Reply", "Error", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease", "MotionNotify",
947 "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut", "KeymapNotify", "Expose", "GraphicsExpose",
948 "NoExpose", "VisibilityNotify", "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify",
949 "MapRequest", "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
950 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear",
951 "SelectionRequest", "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify",
952 "GenericEvent", "LASTEvent",
954 const int nevents = sizeof(event_names)/sizeof(event_names[0]);
956 printf("BC_WindowBase::dispatch_event %d %s %p %d (%s)\n", __LINE__,
957 title, event, event->type, event->type>=0 && event->type<nevents ?
958 event_names[event->type] : "Unknown");
963 active_grab->lock_window("BC_WindowBase::dispatch_event 3");
964 result = active_grab->grab_event(event);
965 active_grab->unlock_window();
966 if( result ) return result;
967 lock_window("BC_WindowBase::dispatch_event 4");
970 switch(event->type) {
972 // Clear the resize buffer
974 dispatch_resize_event(last_resize_w, last_resize_h);
975 // Clear the motion buffer since this can clear the window
977 dispatch_motion_event();
979 ptr = (XClientMessageEvent*)event;
980 if( ptr->message_type == ProtoXAtom &&
981 (Atom)ptr->data.l[0] == DelWinXAtom ) {
984 else if( ptr->message_type == RepeaterXAtom ) {
985 dispatch_repeat_event(ptr->data.l[0]);
987 else if( ptr->message_type == SetDoneXAtom ) {
991 receive_custom_xatoms((xatom_event *)ptr);
1002 dispatch_focus_out();
1016 dispatch_motion_event();
1018 get_key_masks(event->xbutton.state);
1019 cursor_x = event->xbutton.x;
1020 cursor_y = event->xbutton.y;
1021 button_number = event->xbutton.button;
1023 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1024 event_win = event->xany.window;
1025 if( button_number < 6 ) {
1026 if( button_number < 4 )
1028 button_pressed = event->xbutton.button;
1029 button_time1 = button_time2;
1030 button_time2 = button_time3;
1031 button_time3 = event->xbutton.time;
1034 drag_win = event_win;
1035 drag_x1 = cursor_x - get_resources()->drag_radius;
1036 drag_x2 = cursor_x + get_resources()->drag_radius;
1037 drag_y1 = cursor_y - get_resources()->drag_radius;
1038 drag_y2 = cursor_y + get_resources()->drag_radius;
1039 if( button_number < 4 ) {
1040 if((long)(button_time3 - button_time1) < resources->double_click * 2) {
1042 button_time3 = button_time2 = button_time1 = 0;
1044 if((long)(button_time3 - button_time2) < resources->double_click) {
1046 // button_time3 = button_time2 = button_time1 = 0;
1053 dispatch_button_press();
1060 dispatch_motion_event();
1062 get_key_masks(event->xbutton.state);
1063 button_number = event->xbutton.button;
1064 event_win = event->xany.window;
1065 if (button_number < 6)
1067 if(button_number < 4)
1069 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1071 dispatch_button_release();
1076 event_win = event->xany.window;
1078 for( int i=0; !result && i<popups.size(); ++i ) { // popups take focus
1079 if( popups[i]->win == event_win )
1080 result = popups[i]->dispatch_expose_event();
1083 result = dispatch_expose_event();
1087 get_key_masks(event->xmotion.state);
1088 // Dispatch previous motion event if this is a subsequent motion from a different window
1089 if(motion_events && last_motion_win != event->xany.window)
1091 dispatch_motion_event();
1094 // Buffer the current motion
1096 last_motion_state = event->xmotion.state;
1097 last_motion_x = event->xmotion.x;
1098 last_motion_y = event->xmotion.y;
1099 last_motion_win = event->xany.window;
1102 case ConfigureNotify:
1103 // printf("BC_WindowBase::dispatch_event %d win=%p this->win=%p\n",
1105 // event->xany.window,
1108 XTranslateCoordinates(top_level->display,
1116 last_resize_w = event->xconfigure.width;
1117 last_resize_h = event->xconfigure.height;
1120 cancel_translation = 0;
1122 // Resize history prevents responses to recursive resize requests
1123 for(int i = 0; i < resize_history.total && !cancel_resize; i++)
1125 if(resize_history.values[i]->w == last_resize_w &&
1126 resize_history.values[i]->h == last_resize_h)
1128 delete resize_history.values[i];
1129 resize_history.remove_number(i);
1134 if(last_resize_w == w && last_resize_h == h)
1142 if((last_translate_x == x && last_translate_y == y))
1143 cancel_translation = 1;
1145 if(!cancel_translation)
1147 translation_events = 1;
1150 translation_count++;
1154 get_key_masks(event->xkey.state);
1155 keys_return[0] = 0; keysym = -1;
1156 if(XFilterEvent(event, win)) {
1159 if( keysym_lookup(event) < 0 ) {
1160 printf("keysym %x\n", (uint32_t)keysym);
1164 //printf("BC_WindowBase::dispatch_event %d keysym=0x%x\n",
1168 // block out control keys
1169 if(keysym > 0xffe0 && keysym < 0xffff) break;
1170 // block out Alt_GR key
1171 if(keysym == 0xfe03) break;
1174 printf("BC_WindowBase::dispatch_event %x\n", (uint32_t)keysym);
1176 #ifdef X_HAVE_UTF8_STRING
1177 //It's Ascii or UTF8?
1178 // if (keysym != 0xffff && (keys_return[0] & 0xff) >= 0x7f )
1179 //printf("BC_WindowBase::dispatch_event %d %02x%02x\n", __LINE__, keys_return[0], keys_return[1]);
1181 if( ((keys_return[1] & 0xff) > 0x80) &&
1182 ((keys_return[0] & 0xff) > 0xC0) ) {
1183 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1184 key_pressed = keysym & 0xff;
1188 // shuttle speed codes
1189 if( keysym >= SKEY_MIN && keysym <= SKEY_MAX ) {
1190 key_pressed = keysym;
1192 else switch( keysym ) {
1193 // block out extra keys
1203 // Translate key codes
1204 case XK_Return: key_pressed = RETURN; break;
1205 case XK_Up: key_pressed = UP; break;
1206 case XK_Down: key_pressed = DOWN; break;
1207 case XK_Left: key_pressed = LEFT; break;
1208 case XK_Right: key_pressed = RIGHT; break;
1209 case XK_Next: key_pressed = PGDN; break;
1210 case XK_Prior: key_pressed = PGUP; break;
1211 case XK_BackSpace: key_pressed = BACKSPACE; break;
1212 case XK_Escape: key_pressed = ESC; break;
1215 key_pressed = LEFTTAB;
1219 case XK_ISO_Left_Tab: key_pressed = LEFTTAB; break;
1220 case XK_underscore: key_pressed = '_'; break;
1221 case XK_asciitilde: key_pressed = '~'; break;
1222 case XK_Delete: key_pressed = DELETE; break;
1223 case XK_Home: key_pressed = HOME; break;
1224 case XK_End: key_pressed = END; break;
1227 case XK_KP_Enter: key_pressed = KPENTER; break;
1228 case XK_KP_Add: key_pressed = KPPLUS; break;
1229 case XK_KP_Subtract: key_pressed = KPMINUS; break;
1230 case XK_KP_Multiply: key_pressed = KPSTAR; break;
1231 case XK_KP_Divide: key_pressed = KPSLASH; break;
1233 case XK_KP_End: key_pressed = KP1; break;
1235 case XK_KP_Down: key_pressed = KP2; break;
1237 case XK_KP_Page_Down: key_pressed = KP3; break;
1239 case XK_KP_Left: key_pressed = KP4; break;
1241 case XK_KP_Begin: key_pressed = KP5; break;
1243 case XK_KP_Right: key_pressed = KP6; break;
1245 case XK_KP_Home: key_pressed = KP7; break;
1247 case XK_KP_Up: key_pressed = KP8; break;
1249 case XK_KP_Page_Up: key_pressed = KP9; break;
1251 case XK_KP_Insert: key_pressed = KPINS; break;
1253 case XK_KP_Delete: key_pressed = KPDEL; break;
1255 case XK_F1: key_pressed = KEY_F1; break;
1256 case XK_F2: key_pressed = KEY_F2; break;
1257 case XK_F3: key_pressed = KEY_F3; break;
1258 case XK_F4: key_pressed = KEY_F4; break;
1259 case XK_F5: key_pressed = KEY_F5; break;
1260 case XK_F6: key_pressed = KEY_F6; break;
1261 case XK_F7: key_pressed = KEY_F7; break;
1262 case XK_F8: key_pressed = KEY_F8; break;
1263 case XK_F9: key_pressed = KEY_F9; break;
1264 case XK_F10: key_pressed = KEY_F10; break;
1265 case XK_F11: key_pressed = KEY_F11; break;
1266 case XK_F12: key_pressed = KEY_F12; break;
1268 case XK_Menu: key_pressed = KPMENU; break; /* menu */
1271 key_pressed = keysym & 0xff;
1272 #ifdef X_HAVE_UTF8_STRING
1273 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1278 #ifdef X_HAVE_UTF8_STRING
1280 key_pressed_utf8 = keys_return;
1285 if( top_level == this )
1286 result = BC_KeyboardHandler::run_listeners(this);
1288 //printf("BC_WindowBase::dispatch_event %d %d %x\n", shift_down(), alt_down(), key_pressed);
1290 result = dispatch_keypress_event();
1291 // Handle some default keypresses
1294 if(key_pressed == 'w' ||
1303 XLookupString((XKeyEvent*)event, keys_return, 1, &keysym, 0);
1304 dispatch_keyrelease_event();
1305 // printf("BC_WindowBase::dispatch_event KeyRelease keysym=0x%x keystate=0x%lld\n",
1306 // keysym, event->xkey.state);
1310 if( event->xcrossing.mode != NotifyNormal ) break;
1312 event_win = event->xany.window;
1313 dispatch_cursor_leave();
1317 if( event->xcrossing.mode != NotifyNormal ) break;
1319 if( !cursor_entered ) {
1320 for( int i=0; i<popups.size(); ++i ) { // popups always take focus
1321 if( popups[i]->win == event->xcrossing.window )
1324 if( !cursor_entered && get_resources()->grab_input_focus &&
1325 !event->xcrossing.focus && event->xcrossing.window == win ) {
1328 if( cursor_entered )
1331 event_win = event->xany.window;
1332 cursor_x = event->xcrossing.x;
1333 cursor_y = event->xcrossing.y;
1334 dispatch_cursor_enter();
1340 //printf("100 %s %p %d\n", title, event, event->type);
1341 //if(event->type != ClientMessage) dump();
1343 #ifndef SINGLE_THREAD
1346 if( resend_event_window ) {
1347 resend_event_window->put_event(event);
1348 resend_event_window = 0;
1354 // if(done) completion_lock->unlock();
1357 if(debug) printf("BC_WindowBase::dispatch_event this=%p %d\n", this, __LINE__);
1361 int BC_WindowBase::dispatch_expose_event()
1364 for(int i = 0; i < subwindows->total && !result; i++)
1366 result = subwindows->values[i]->dispatch_expose_event();
1369 // Propagate to user
1370 if(!result) expose_event();
1374 int BC_WindowBase::dispatch_resize_event(int w, int h)
1376 // Can't store new w and h until the event is handles
1377 // because bcfilebox depends on the old w and h to
1378 // reposition widgets.
1379 if( window_type == MAIN_WINDOW ) {
1384 pixmap = new BC_Pixmap(this, w, h);
1385 clear_box(0, 0, w, h);
1388 // Propagate to subwindows
1389 for(int i = 0; i < subwindows->total; i++) {
1390 subwindows->values[i]->dispatch_resize_event(w, h);
1393 // Propagate to user
1396 if( window_type == MAIN_WINDOW ) {
1405 int BC_WindowBase::dispatch_flash()
1408 for(int i = 0; i < subwindows->total; i++)
1409 subwindows->values[i]->dispatch_flash();
1413 int BC_WindowBase::dispatch_translation_event()
1415 translation_events = 0;
1416 if(window_type == MAIN_WINDOW)
1420 x = last_translate_x;
1421 y = last_translate_y;
1422 // Correct for window manager offsets
1427 for(int i = 0; i < subwindows->total; i++)
1429 subwindows->values[i]->dispatch_translation_event();
1432 translation_event();
1436 int BC_WindowBase::dispatch_motion_event()
1441 if(top_level == this)
1444 event_win = last_motion_win;
1445 get_key_masks(last_motion_state);
1448 if(get_button_down() && !active_menubar && !active_popup_menu)
1452 cursor_x = last_motion_x;
1453 cursor_y = last_motion_y;
1454 result = dispatch_drag_motion();
1458 (last_motion_x < drag_x1 || last_motion_x >= drag_x2 ||
1459 last_motion_y < drag_y1 || last_motion_y >= drag_y2))
1464 result = dispatch_drag_start();
1468 cursor_x = last_motion_x;
1469 cursor_y = last_motion_y;
1471 // printf("BC_WindowBase::dispatch_motion_event %d %p %p %p\n",
1474 // active_popup_menu,
1475 // active_subwindow);
1477 if(active_menubar && !result) result = active_menubar->dispatch_motion_event();
1478 if(active_popup_menu && !result) result = active_popup_menu->dispatch_motion_event();
1479 if(active_subwindow && !result) result = active_subwindow->dispatch_motion_event();
1482 // Dispatch in stacking order
1483 for(int i = subwindows->size() - 1; i >= 0 && !result; i--)
1485 result = subwindows->values[i]->dispatch_motion_event();
1488 if(!result) result = cursor_motion_event(); // give to user
1492 int BC_WindowBase::dispatch_keypress_event()
1495 if(top_level == this)
1497 if(active_subwindow) result = active_subwindow->dispatch_keypress_event();
1500 for(int i = 0; i < subwindows->total && !result; i++)
1502 result = subwindows->values[i]->dispatch_keypress_event();
1505 if(!result) result = keypress_event();
1510 int BC_WindowBase::dispatch_keyrelease_event()
1513 if(top_level == this)
1515 if(active_subwindow) result = active_subwindow->dispatch_keyrelease_event();
1518 for(int i = 0; i < subwindows->total && !result; i++)
1520 result = subwindows->values[i]->dispatch_keyrelease_event();
1523 if(!result) result = keyrelease_event();
1528 int BC_WindowBase::dispatch_focus_in()
1530 for(int i = 0; i < subwindows->total; i++)
1532 subwindows->values[i]->dispatch_focus_in();
1540 int BC_WindowBase::dispatch_focus_out()
1542 for(int i = 0; i < subwindows->total; i++)
1544 subwindows->values[i]->dispatch_focus_out();
1552 int BC_WindowBase::get_has_focus()
1554 return top_level->has_focus;
1557 int BC_WindowBase::get_deleting()
1559 if(is_deleting) return 1;
1560 if(parent_window && parent_window->get_deleting()) return 1;
1564 int BC_WindowBase::dispatch_button_press()
1569 if(top_level == this)
1571 if(active_menubar) result = active_menubar->dispatch_button_press();
1572 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_press();
1573 if(active_subwindow && !result) result = active_subwindow->dispatch_button_press();
1576 for(int i = 0; i < subwindows->total && !result; i++)
1578 result = subwindows->values[i]->dispatch_button_press();
1581 if(!result) result = button_press_event();
1587 int BC_WindowBase::dispatch_button_release()
1590 if(top_level == this)
1592 if(active_menubar) result = active_menubar->dispatch_button_release();
1593 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_release();
1594 if(active_subwindow && !result) result = active_subwindow->dispatch_button_release();
1595 if(!result && button_number != 4 && button_number != 5)
1596 result = dispatch_drag_stop();
1599 for(int i = 0; i < subwindows->total && !result; i++)
1601 result = subwindows->values[i]->dispatch_button_release();
1606 result = button_release_event();
1613 int BC_WindowBase::dispatch_repeat_event(int64_t duration)
1616 // all repeat event handlers get called and decide based on activity and duration
1617 // whether to respond
1618 for(int i = 0; i < subwindows->total; i++)
1620 subwindows->values[i]->dispatch_repeat_event(duration);
1624 repeat_event(duration);
1628 // Unlock next repeat signal
1629 if(window_type == MAIN_WINDOW)
1631 #ifdef SINGLE_THREAD
1632 BC_Display::display_global->unlock_repeaters(duration);
1634 for(int i = 0; i < repeaters.total; i++)
1636 if(repeaters.values[i]->delay == duration)
1638 repeaters.values[i]->repeat_lock->unlock();
1646 void BC_WindowBase::unhide_cursor()
1651 if(top_level->is_hourglass)
1652 set_cursor(HOURGLASS_CURSOR, 1, 0);
1654 set_cursor(current_cursor, 1, 0);
1656 cursor_timer->update();
1660 void BC_WindowBase::update_video_cursor()
1662 if(video_on && !is_transparent)
1664 if(cursor_timer->get_difference() > VIDEO_CURSOR_TIMEOUT && !is_transparent)
1667 set_cursor(TRANSPARENT_CURSOR, 1, 1);
1668 cursor_timer->update();
1673 cursor_timer->update();
1678 int BC_WindowBase::dispatch_cursor_leave()
1682 for(int i = 0; i < subwindows->total; i++)
1684 subwindows->values[i]->dispatch_cursor_leave();
1687 cursor_leave_event();
1691 int BC_WindowBase::dispatch_cursor_enter()
1697 if(active_menubar) result = active_menubar->dispatch_cursor_enter();
1698 if(!result && active_popup_menu) result = active_popup_menu->dispatch_cursor_enter();
1699 if(!result && active_subwindow) result = active_subwindow->dispatch_cursor_enter();
1701 for(int i = 0; !result && i < subwindows->total; i++)
1703 result = subwindows->values[i]->dispatch_cursor_enter();
1706 if(!result) result = cursor_enter_event();
1710 int BC_WindowBase::cursor_enter_event()
1715 int BC_WindowBase::cursor_leave_event()
1720 int BC_WindowBase::close_event()
1726 int BC_WindowBase::dispatch_drag_start()
1729 if(active_menubar) result = active_menubar->dispatch_drag_start();
1730 if(!result && active_popup_menu) result = active_popup_menu->dispatch_drag_start();
1731 if(!result && active_subwindow) result = active_subwindow->dispatch_drag_start();
1733 for(int i = 0; i < subwindows->total && !result; i++)
1735 result = subwindows->values[i]->dispatch_drag_start();
1738 if(!result) result = is_dragging = drag_start_event();
1742 int BC_WindowBase::dispatch_drag_stop()
1746 for(int i = 0; i < subwindows->total && !result; i++)
1748 result = subwindows->values[i]->dispatch_drag_stop();
1751 if(is_dragging && !result)
1761 int BC_WindowBase::dispatch_drag_motion()
1764 for(int i = 0; i < subwindows->total && !result; i++)
1766 result = subwindows->values[i]->dispatch_drag_motion();
1769 if(is_dragging && !result)
1771 drag_motion_event();
1779 int BC_WindowBase::show_tooltip(const char *text, int x, int y, int w, int h)
1782 int forced = !text ? force_tooltip : 1;
1783 if( !text ) text = tooltip_text;
1784 if( !text || (!forced && !get_resources()->tooltips_enabled) ) {
1785 top_level->hide_tooltip();
1789 if(w < 0) w = get_text_width(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1790 if(h < 0) h = get_text_height(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1791 // default x,y (win relative)
1792 if( x < 0 ) x = get_w();
1793 if( y < 0 ) y = get_h();
1795 get_root_coordinates(x, y, &wx, &wy);
1796 // keep the tip inside the window/display
1797 int x0 = top_level->get_x(), x1 = x0 + top_level->get_w();
1798 int x2 = top_level->get_screen_x(0, -1) + top_level->get_screen_w(0, -1);
1799 if( x1 > x2 ) x1 = x2;
1800 if( wx < x0 ) wx = x0;
1801 if( wx >= (x1-=w) ) wx = x1;
1802 int y0 = top_level->get_y(), y1 = y0 + top_level->get_h();
1803 int y2 = top_level->get_root_h(0);
1804 if( y1 > y2 ) y1 = y2;
1805 if( wy < y0 ) wy = y0;
1806 if( wy >= (y1-=h) ) wy = y1;
1807 // avoid tip under cursor (flickers)
1809 get_abs_cursor(abs_x,abs_y, 0);
1810 if( wx < abs_x && abs_x < wx+w && wy < abs_y && abs_y < wy+h ) {
1811 if( wx-abs_x < wy-abs_y )
1818 tooltip_popup = new BC_Popup(top_level, wx, wy, w, h,
1819 get_resources()->tooltip_bg_color);
1822 tooltip_popup->reposition_window(wx, wy, w, h);
1825 tooltip_popup->flash();
1826 tooltip_popup->flush();
1830 int BC_WindowBase::hide_tooltip()
1833 for(int i = 0; i < subwindows->total; i++)
1835 subwindows->values[i]->hide_tooltip();
1841 delete tooltip_popup;
1847 const char *BC_WindowBase::get_tooltip()
1849 return tooltip_text;
1852 int BC_WindowBase::set_tooltip(const char *text)
1854 tooltip_text = text;
1856 // Update existing tooltip if it is visible
1860 tooltip_popup->flash();
1864 // signal the event handler to repeat
1865 int BC_WindowBase::set_repeat(int64_t duration)
1869 printf("BC_WindowBase::set_repeat duration=%jd\n", duration);
1872 if(window_type != MAIN_WINDOW) return top_level->set_repeat(duration);
1874 #ifdef SINGLE_THREAD
1875 BC_Display::display_global->set_repeat(this, duration);
1877 // test repeater database for duplicates
1878 for(int i = 0; i < repeaters.total; i++)
1881 if(repeaters.values[i]->delay == duration)
1883 repeaters.values[i]->start_repeating(this);
1888 BC_Repeater *repeater = new BC_Repeater(this, duration);
1889 repeater->initialize();
1890 repeaters.append(repeater);
1891 repeater->start_repeating();
1896 int BC_WindowBase::unset_repeat(int64_t duration)
1898 if(window_type != MAIN_WINDOW) return top_level->unset_repeat(duration);
1900 #ifdef SINGLE_THREAD
1901 BC_Display::display_global->unset_repeat(this, duration);
1903 for(int i = 0; i < repeaters.total; i++)
1905 if(repeaters.values[i]->delay == duration)
1907 repeaters.values[i]->stop_repeating();
1915 int BC_WindowBase::unset_all_repeaters()
1917 #ifdef SINGLE_THREAD
1918 BC_Display::display_global->unset_all_repeaters(this);
1920 for(int i = 0; i < repeaters.total; i++)
1922 repeaters.values[i]->stop_repeating();
1924 repeaters.remove_all_objects();
1929 // long BC_WindowBase::get_repeat_id()
1931 // return top_level->next_repeat_id++;
1934 XEvent *BC_WindowBase::new_xevent()
1936 XEvent *event = new XEvent;
1937 memset(event, 0, sizeof(*event));
1941 #ifndef SINGLE_THREAD
1942 int BC_WindowBase::arm_repeat(int64_t duration)
1944 XEvent *event = new_xevent();
1945 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
1946 ptr->type = ClientMessage;
1947 ptr->message_type = RepeaterXAtom;
1949 ptr->data.l[0] = duration;
1951 // Couldn't use XSendEvent since it locked up randomly.
1957 int BC_WindowBase::receive_custom_xatoms(xatom_event *event)
1962 int BC_WindowBase::send_custom_xatom(xatom_event *event)
1964 #ifndef SINGLE_THREAD
1965 XEvent *myevent = new_xevent();
1966 XClientMessageEvent *ptr = (XClientMessageEvent*)myevent;
1967 ptr->type = ClientMessage;
1968 ptr->message_type = event->message_type;
1969 ptr->format = event->format;
1970 ptr->data.l[0] = event->data.l[0];
1971 ptr->data.l[1] = event->data.l[1];
1972 ptr->data.l[2] = event->data.l[2];
1973 ptr->data.l[3] = event->data.l[3];
1974 ptr->data.l[4] = event->data.l[4];
1983 Atom BC_WindowBase::create_xatom(const char *atom_name)
1985 return XInternAtom(display, atom_name, False);
1988 int BC_WindowBase::get_atoms()
1990 SetDoneXAtom = XInternAtom(display, "BC_REPEAT_EVENT", False);
1991 RepeaterXAtom = XInternAtom(display, "BC_CLOSE_EVENT", False);
1992 DestroyAtom = XInternAtom(display, "BC_DESTROY_WINDOW", False);
1993 DelWinXAtom = XInternAtom(display, "WM_DELETE_WINDOW", False);
1994 if( (ProtoXAtom = XInternAtom(display, "WM_PROTOCOLS", False)) != 0 )
1995 XChangeProperty(display, win, ProtoXAtom, XA_ATOM, 32,
1996 PropModeReplace, (unsigned char *)&DelWinXAtom, True);
2002 void BC_WindowBase::init_cursors()
2004 arrow_cursor = XCreateFontCursor(display, XC_top_left_arrow);
2005 cross_cursor = XCreateFontCursor(display, XC_crosshair);
2006 ibeam_cursor = XCreateFontCursor(display, XC_xterm);
2007 vseparate_cursor = XCreateFontCursor(display, XC_sb_v_double_arrow);
2008 hseparate_cursor = XCreateFontCursor(display, XC_sb_h_double_arrow);
2009 move_cursor = XCreateFontCursor(display, XC_fleur);
2010 left_cursor = XCreateFontCursor(display, XC_sb_left_arrow);
2011 right_cursor = XCreateFontCursor(display, XC_sb_right_arrow);
2012 upright_arrow_cursor = XCreateFontCursor(display, XC_arrow);
2013 upleft_resize_cursor = XCreateFontCursor(display, XC_top_left_corner);
2014 upright_resize_cursor = XCreateFontCursor(display, XC_top_right_corner);
2015 downleft_resize_cursor = XCreateFontCursor(display, XC_bottom_left_corner);
2016 downright_resize_cursor = XCreateFontCursor(display, XC_bottom_right_corner);
2017 hourglass_cursor = XCreateFontCursor(display, XC_watch);
2018 grabbed_cursor = create_grab_cursor();
2020 static char cursor_data[] = { 0,0,0,0, 0,0,0,0 };
2021 Colormap colormap = DefaultColormap(display, screen);
2022 Pixmap pixmap_bottom = XCreateBitmapFromData(display,
2023 rootwin, cursor_data, 8, 8);
2024 XColor black, dummy;
2025 XAllocNamedColor(display, colormap, "black", &black, &dummy);
2026 transparent_cursor = XCreatePixmapCursor(display,
2027 pixmap_bottom, pixmap_bottom, &black, &black, 0, 0);
2028 // XDefineCursor(display, win, transparent_cursor);
2029 XFreePixmap(display, pixmap_bottom);
2032 int BC_WindowBase::evaluate_color_model(int client_byte_order, int server_byte_order, int depth)
2034 int color_model = BC_TRANSPARENCY;
2038 color_model = BC_RGB8;
2041 color_model = (server_byte_order == client_byte_order) ? BC_RGB565 : BC_BGR565;
2044 color_model = server_byte_order ? BC_BGR888 : BC_RGB888;
2047 color_model = server_byte_order ? BC_BGR8888 : BC_ARGB8888;
2053 int BC_WindowBase::init_colors()
2056 current_color_value = current_color_pixel = 0;
2058 // Get the real depth
2061 ximage = XCreateImage(top_level->display,
2062 top_level->vis, top_level->default_depth,
2063 ZPixmap, 0, data, 16, 16, 8, 0);
2064 bits_per_pixel = ximage->bits_per_pixel;
2065 XDestroyImage(ximage);
2067 color_model = evaluate_color_model(client_byte_order,
2070 // Get the color model
2075 cmap = XCreateColormap(display, rootwin, vis, AllocNone);
2076 create_private_colors();
2079 cmap = DefaultColormap(display, screen);
2080 create_shared_colors();
2083 allocate_color_table();
2087 //cmap = DefaultColormap(display, screen);
2088 cmap = XCreateColormap(display, rootwin, vis, AllocNone );
2094 int BC_WindowBase::create_private_colors()
2099 for(int i = 0; i < 255; i++)
2101 color = (i & 0xc0) << 16;
2102 color += (i & 0x38) << 10;
2103 color += (i & 0x7) << 5;
2104 color_table[i][0] = color;
2106 create_shared_colors(); // overwrite the necessary colors on the table
2111 int BC_WindowBase::create_color(int color)
2113 if(total_colors == 256)
2115 // replace the closest match with an exact match
2116 color_table[get_color_rgb8(color)][0] = color;
2120 // add the color to the table
2121 color_table[total_colors][0] = color;
2127 int BC_WindowBase::create_shared_colors()
2129 create_color(BLACK);
2130 create_color(WHITE);
2132 create_color(LTGREY);
2133 create_color(MEGREY);
2134 create_color(MDGREY);
2135 create_color(DKGREY);
2137 create_color(LTCYAN);
2138 create_color(MECYAN);
2139 create_color(MDCYAN);
2140 create_color(DKCYAN);
2142 create_color(LTGREEN);
2143 create_color(GREEN);
2144 create_color(DKGREEN);
2146 create_color(LTPINK);
2150 create_color(LTBLUE);
2152 create_color(DKBLUE);
2154 create_color(LTYELLOW);
2155 create_color(MEYELLOW);
2156 create_color(MDYELLOW);
2157 create_color(DKYELLOW);
2159 create_color(LTPURPLE);
2160 create_color(MEPURPLE);
2161 create_color(MDPURPLE);
2162 create_color(DKPURPLE);
2164 create_color(FGGREY);
2165 create_color(MNBLUE);
2166 create_color(ORANGE);
2167 create_color(FTGREY);
2172 Cursor BC_WindowBase::create_grab_cursor()
2174 int iw = 23, iw1 = iw-1, iw2 = iw/2;
2175 int ih = 23, ih1 = ih-1, ih2 = ih/2;
2176 VFrame grab(iw,ih,BC_RGB888);
2178 grab.set_pixel_color(RED); // fg
2179 grab.draw_smooth(iw2,0, iw1,0, iw1,ih2);
2180 grab.draw_smooth(iw1,ih2, iw1,ih1, iw2,ih1);
2181 grab.draw_smooth(iw2,ih1, 0,ih1, 0,ih2);
2182 grab.draw_smooth(0,ih2, 0,0, iw2,0);
2183 grab.set_pixel_color(WHITE); // bg
2184 grab.draw_line(0,ih2, iw2-2,ih2);
2185 grab.draw_line(iw2+2,ih2, iw1,ih2);
2186 grab.draw_line(iw2,0, iw2,ih2-2);
2187 grab.draw_line(iw2,ih2+2, iw2,ih1);
2189 int bpl = (iw+7)/8, isz = bpl * ih;
2190 char img[isz]; memset(img, 0, isz);
2191 char msk[isz]; memset(msk, 0, isz);
2192 unsigned char **rows = grab.get_rows();
2193 for( int iy=0; iy<ih; ++iy ) {
2194 char *op = img + iy*bpl;
2195 char *mp = msk + iy*bpl;
2196 unsigned char *ip = rows[iy];
2197 for( int ix=0; ix<iw; ++ix,ip+=3 ) {
2198 if( ip[0] ) mp[ix>>3] |= (1<<(ix&7));
2199 if( !ip[1] ) op[ix>>3] |= (1<<(ix&7));
2202 unsigned long white_pix = WhitePixel(display, screen);
2203 unsigned long black_pix = BlackPixel(display, screen);
2204 Pixmap img_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2205 img, iw,ih, white_pix,black_pix, 1);
2206 Pixmap msk_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2207 msk, iw,ih, white_pix,black_pix, 1);
2210 fc.flags = bc.flags = DoRed | DoGreen | DoBlue;
2211 fc.red = 0xffff; fc.green = fc.blue = 0; // fg
2212 bc.red = 0xffff; bc.green = 0xffff; bc.blue = 0x0000; // bg
2213 Cursor cursor = XCreatePixmapCursor(display, img_xpm,msk_xpm, &fc,&bc, iw2,ih2);
2214 XFreePixmap(display, img_xpm);
2215 XFreePixmap(display, msk_xpm);
2219 int BC_WindowBase::allocate_color_table()
2221 int red, green, blue, color;
2224 for(int i = 0; i < total_colors; i++)
2226 color = color_table[i][0];
2227 red = (color & 0xFF0000) >> 16;
2228 green = (color & 0x00FF00) >> 8;
2229 blue = color & 0xFF;
2231 col.flags = DoRed | DoGreen | DoBlue;
2232 col.red = red<<8 | red;
2233 col.green = green<<8 | green;
2234 col.blue = blue<<8 | blue;
2236 XAllocColor(display, cmap, &col);
2237 color_table[i][1] = col.pixel;
2240 XInstallColormap(display, cmap);
2244 int BC_WindowBase::init_window_shape()
2246 if(bg_pixmap && bg_pixmap->use_alpha())
2248 XShapeCombineMask(top_level->display,
2249 this->win, ShapeBounding, 0, 0,
2250 bg_pixmap->get_alpha(), ShapeSet);
2256 int BC_WindowBase::init_gc()
2258 unsigned long gcmask;
2259 gcmask = GCFont | GCGraphicsExposures;
2262 gcvalues.font = mediumfont->fid; // set the font
2263 gcvalues.graphics_exposures = 0; // prevent expose events for every redraw
2264 gc = XCreateGC(display, rootwin, gcmask, &gcvalues);
2266 // gcmask = GCCapStyle | GCJoinStyle;
2267 // XGetGCValues(display, gc, gcmask, &gcvalues);
2268 // printf("BC_WindowBase::init_gc %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2272 int BC_WindowBase::init_fonts()
2274 if( !(smallfont = XLoadQueryFont(display, _(resources->small_font))) )
2275 if( !(smallfont = XLoadQueryFont(display, _(resources->small_font2))) )
2276 smallfont = XLoadQueryFont(display, "fixed");
2277 if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font))) )
2278 if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font2))) )
2279 mediumfont = XLoadQueryFont(display, "fixed");
2280 if( !(largefont = XLoadQueryFont(display, _(resources->large_font))) )
2281 if( !(largefont = XLoadQueryFont(display, _(resources->large_font2))) )
2282 largefont = XLoadQueryFont(display, "fixed");
2283 if( !(bigfont = XLoadQueryFont(display, _(resources->big_font))) )
2284 if( !(bigfont = XLoadQueryFont(display, _(resources->big_font2))) )
2285 bigfont = XLoadQueryFont(display, "fixed");
2287 if((clockfont = XLoadQueryFont(display, _(resources->clock_font))) == NULL)
2288 if((clockfont = XLoadQueryFont(display, _(resources->clock_font2))) == NULL)
2289 clockfont = XLoadQueryFont(display, "fixed");
2292 if(get_resources()->use_fontset)
2297 // FIXME: should check the m,d,n values
2298 smallfontset = XCreateFontSet(display, resources->small_fontset, &m, &n, &d);
2300 smallfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2301 mediumfontset = XCreateFontSet(display, resources->medium_fontset, &m, &n, &d);
2302 if( !mediumfontset )
2303 mediumfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2304 largefontset = XCreateFontSet(display, resources->large_fontset, &m, &n, &d);
2306 largefontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2307 bigfontset = XCreateFontSet(display, resources->big_fontset, &m, &n, &d);
2309 bigfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2310 clockfontset = XCreateFontSet(display, resources->clock_fontset, &m, &n, &d);
2312 clockfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2313 if(clockfontset && bigfontset && largefontset && mediumfontset && smallfontset) {
2314 curr_fontset = mediumfontset;
2315 get_resources()->use_fontset = 1;
2319 get_resources()->use_fontset = 0;
2326 void BC_WindowBase::init_xft()
2329 if( !get_resources()->use_xft ) return;
2330 // apparently, xft is not reentrant, more than this is needed
2331 static Mutex xft_init_lock("BC_WindowBase::xft_init_lock", 0);
2332 xft_init_lock.lock("BC_WindowBase::init_xft");
2333 if(!(smallfont_xft =
2334 (resources->small_font_xft[0] == '-' ?
2335 xftFontOpenXlfd(display, screen, resources->small_font_xft) :
2336 xftFontOpenName(display, screen, resources->small_font_xft))) )
2337 if(!(smallfont_xft =
2338 xftFontOpenXlfd(display, screen, resources->small_font_xft2)))
2339 smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2340 if(!(mediumfont_xft =
2341 (resources->medium_font_xft[0] == '-' ?
2342 xftFontOpenXlfd(display, screen, resources->medium_font_xft) :
2343 xftFontOpenName(display, screen, resources->medium_font_xft))) )
2344 if(!(mediumfont_xft =
2345 xftFontOpenXlfd(display, screen, resources->medium_font_xft2)))
2346 mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2347 if(!(largefont_xft =
2348 (resources->large_font_xft[0] == '-' ?
2349 xftFontOpenXlfd(display, screen, resources->large_font_xft) :
2350 xftFontOpenName(display, screen, resources->large_font_xft))) )
2351 if(!(largefont_xft =
2352 xftFontOpenXlfd(display, screen, resources->large_font_xft2)))
2353 largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2355 (resources->big_font_xft[0] == '-' ?
2356 xftFontOpenXlfd(display, screen, resources->big_font_xft) :
2357 xftFontOpenName(display, screen, resources->big_font_xft))) )
2359 xftFontOpenXlfd(display, screen, resources->big_font_xft2)))
2360 bigfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2361 if(!(clockfont_xft =
2362 (resources->clock_font_xft[0] == '-' ?
2363 xftFontOpenXlfd(display, screen, resources->clock_font_xft) :
2364 xftFontOpenName(display, screen, resources->clock_font_xft))) )
2365 clockfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2368 if(!(bold_smallfont_xft =
2369 (resources->small_b_font_xft[0] == '-' ?
2370 xftFontOpenXlfd(display, screen, resources->small_b_font_xft) :
2371 xftFontOpenName(display, screen, resources->small_b_font_xft))) )
2372 bold_smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2373 if(!(bold_mediumfont_xft =
2374 (resources->medium_b_font_xft[0] == '-' ?
2375 xftFontOpenXlfd(display, screen, resources->medium_b_font_xft) :
2376 xftFontOpenName(display, screen, resources->medium_b_font_xft))) )
2377 bold_mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2378 if(!(bold_largefont_xft =
2379 (resources->large_b_font_xft[0] == '-' ?
2380 xftFontOpenXlfd(display, screen, resources->large_b_font_xft) :
2381 xftFontOpenName(display, screen, resources->large_b_font_xft))) )
2382 bold_largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2384 if( !smallfont_xft || !mediumfont_xft || !largefont_xft || !bigfont_xft ||
2385 !bold_largefont_xft || !bold_mediumfont_xft || !bold_largefont_xft ||
2387 printf("BC_WindowBase::init_fonts: no xft fonts found:"
2388 " %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n",
2389 resources->small_font_xft, smallfont_xft,
2390 resources->medium_font_xft, mediumfont_xft,
2391 resources->large_font_xft, largefont_xft,
2392 resources->big_font_xft, bigfont_xft,
2393 resources->clock_font_xft, clockfont_xft,
2394 resources->small_b_font_xft, bold_smallfont_xft,
2395 resources->medium_b_font_xft, bold_mediumfont_xft,
2396 resources->large_b_font_xft, bold_largefont_xft);
2397 get_resources()->use_xft = 0;
2400 // _XftDisplayInfo needs a lock.
2401 xftDefaultHasRender(display);
2402 xft_init_lock.unlock();
2406 void BC_WindowBase::init_glyphs()
2408 // draw all ascii char glyphs
2409 // There are problems with some/my graphics boards/drivers
2410 // which cause some glyphs to be munged if draws occur while
2411 // the font is being loaded. This code fills the font caches
2412 // by drawing all the ascii glyphs before the system starts.
2413 // Not a fix, but much better than nothing.
2414 static int inited = 0;
2415 if( inited ) return;
2416 XGrabServer(display);
2419 int cur_font = current_font;
2420 // locale encodings, needed glyphs to be preloaded
2421 const char *text = _( // ascii 0x20...0x7e
2422 " !\"#$%&'()*+,-./0123456789:;<=>?"
2423 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
2424 "`abcdefghijklmnopqrstuvwxyz{|}~");
2425 for( int font=SMALLFONT; font<=LARGEFONT; ++font ) {
2427 draw_text(5,5, text);
2430 XUngrabServer(display);
2433 void BC_WindowBase::init_im()
2435 XIMStyles *xim_styles;
2438 if(!(input_method = XOpenIM(display, NULL, NULL, NULL)))
2440 printf("BC_WindowBase::init_im: Could not open input method.\n");
2443 if(XGetIMValues(input_method, XNQueryInputStyle, &xim_styles, NULL) ||
2446 printf("BC_WindowBase::init_im: Input method doesn't support any styles.\n");
2447 XCloseIM(input_method);
2452 for(int z = 0; z < xim_styles->count_styles; z++)
2454 if(xim_styles->supported_styles[z] == (XIMPreeditNothing | XIMStatusNothing))
2456 xim_style = xim_styles->supported_styles[z];
2464 printf("BC_WindowBase::init_im: Input method doesn't support the style we need.\n");
2465 XCloseIM(input_method);
2469 input_context = XCreateIC(input_method, XNInputStyle, xim_style,
2470 XNClientWindow, win, XNFocusWindow, win, NULL);
2473 printf("BC_WindowBase::init_im: Failed to create input context.\n");
2474 XCloseIM(input_method);
2479 void BC_WindowBase::finit_im()
2481 if( input_context ) {
2482 XDestroyIC(input_context);
2485 if( input_method ) {
2486 XCloseIM(input_method);
2492 int BC_WindowBase::get_color(int64_t color)
2494 // return pixel of color
2495 // use this only for drawing subwindows not for bitmaps
2496 int i, test, difference;
2502 return get_color_rgb8(color);
2503 // test last color looked up
2504 if(current_color_value == color)
2505 return current_color_pixel;
2508 current_color_value = color;
2509 for(i = 0; i < total_colors; i++)
2511 if(color_table[i][0] == color)
2513 current_color_pixel = color_table[i][1];
2514 return current_color_pixel;
2518 // find nearest match
2519 difference = 0xFFFFFF;
2521 for(i = 0; i < total_colors; i++)
2523 test = abs((int)(color_table[i][0] - color));
2525 if(test < difference)
2527 current_color_pixel = color_table[i][1];
2531 return current_color_pixel;
2534 return get_color_rgb16(color);
2537 return get_color_bgr16(color);
2541 return client_byte_order == server_byte_order ?
2542 color : get_color_bgr24(color);
2550 int BC_WindowBase::get_color_rgb8(int color)
2554 pixel = (color & 0xc00000) >> 16;
2555 pixel += (color & 0xe000) >> 10;
2556 pixel += (color & 0xe0) >> 5;
2560 int64_t BC_WindowBase::get_color_rgb16(int color)
2563 result = (color & 0xf80000) >> 8;
2564 result += (color & 0xfc00) >> 5;
2565 result += (color & 0xf8) >> 3;
2570 int64_t BC_WindowBase::get_color_bgr16(int color)
2573 result = (color & 0xf80000) >> 19;
2574 result += (color & 0xfc00) >> 5;
2575 result += (color & 0xf8) << 8;
2580 int64_t BC_WindowBase::get_color_bgr24(int color)
2583 result = (color & 0xff) << 16;
2584 result += (color & 0xff00);
2585 result += (color & 0xff0000) >> 16;
2589 void BC_WindowBase::start_video()
2591 cursor_timer->update();
2593 // set_color(BLACK);
2594 // draw_box(0, 0, get_w(), get_h());
2598 void BC_WindowBase::stop_video()
2606 int64_t BC_WindowBase::get_color()
2608 return top_level->current_color;
2611 void BC_WindowBase::set_color(int64_t color)
2613 top_level->current_color = color;
2614 XSetForeground(top_level->display,
2616 top_level->get_color(color));
2619 void BC_WindowBase::set_opaque()
2621 XSetFunction(top_level->display, top_level->gc, GXcopy);
2624 void BC_WindowBase::set_inverse()
2626 XSetFunction(top_level->display, top_level->gc, GXxor);
2629 void BC_WindowBase::set_line_width(int value)
2631 this->line_width = value;
2632 XSetLineAttributes(top_level->display, top_level->gc, value, /* line_width */
2633 line_dashes == 0 ? LineSolid : LineOnOffDash, /* line_style */
2634 line_dashes == 0 ? CapRound : CapNotLast, /* cap_style */
2635 JoinMiter); /* join_style */
2637 if(line_dashes > 0) {
2638 const char dashes = line_dashes;
2639 XSetDashes(top_level->display, top_level->gc, 0, &dashes, 1);
2642 // XGCValues gcvalues;
2643 // unsigned long gcmask;
2644 // gcmask = GCCapStyle | GCJoinStyle;
2645 // XGetGCValues(top_level->display, top_level->gc, gcmask, &gcvalues);
2646 // printf("BC_WindowBase::set_line_width %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2649 void BC_WindowBase::set_line_dashes(int value)
2651 line_dashes = value;
2652 // call XSetLineAttributes
2653 set_line_width(line_width);
2657 Cursor BC_WindowBase::get_cursor_struct(int cursor)
2661 case ARROW_CURSOR: return top_level->arrow_cursor;
2662 case CROSS_CURSOR: return top_level->cross_cursor;
2663 case IBEAM_CURSOR: return top_level->ibeam_cursor;
2664 case VSEPARATE_CURSOR: return top_level->vseparate_cursor;
2665 case HSEPARATE_CURSOR: return top_level->hseparate_cursor;
2666 case MOVE_CURSOR: return top_level->move_cursor;
2667 case LEFT_CURSOR: return top_level->left_cursor;
2668 case RIGHT_CURSOR: return top_level->right_cursor;
2669 case UPRIGHT_ARROW_CURSOR: return top_level->upright_arrow_cursor;
2670 case UPLEFT_RESIZE: return top_level->upleft_resize_cursor;
2671 case UPRIGHT_RESIZE: return top_level->upright_resize_cursor;
2672 case DOWNLEFT_RESIZE: return top_level->downleft_resize_cursor;
2673 case DOWNRIGHT_RESIZE: return top_level->downright_resize_cursor;
2674 case HOURGLASS_CURSOR: return top_level->hourglass_cursor;
2675 case TRANSPARENT_CURSOR: return top_level->transparent_cursor;
2676 case GRABBED_CURSOR: return top_level->grabbed_cursor;
2681 void BC_WindowBase::set_cursor(int cursor, int override, int flush)
2683 // inherit cursor from parent
2686 XUndefineCursor(top_level->display, win);
2687 current_cursor = cursor;
2690 // don't change cursor if overridden
2691 if((!top_level->is_hourglass && !is_transparent) ||
2694 XDefineCursor(top_level->display, win, get_cursor_struct(cursor));
2695 if(flush) this->flush();
2698 if(!override) current_cursor = cursor;
2701 void BC_WindowBase::set_x_cursor(int cursor)
2703 temp_cursor = XCreateFontCursor(top_level->display, cursor);
2704 XDefineCursor(top_level->display, win, temp_cursor);
2705 current_cursor = cursor;
2709 int BC_WindowBase::get_cursor()
2711 return current_cursor;
2714 void BC_WindowBase::start_hourglass()
2716 top_level->start_hourglass_recursive();
2720 void BC_WindowBase::stop_hourglass()
2722 top_level->stop_hourglass_recursive();
2726 void BC_WindowBase::start_hourglass_recursive()
2728 if(this == top_level)
2736 set_cursor(HOURGLASS_CURSOR, 1, 0);
2737 for(int i = 0; i < subwindows->total; i++)
2739 subwindows->values[i]->start_hourglass_recursive();
2744 void BC_WindowBase::stop_hourglass_recursive()
2746 if(this == top_level)
2748 if(hourglass_total == 0) return;
2749 top_level->hourglass_total--;
2752 if(!top_level->hourglass_total)
2754 top_level->is_hourglass = 0;
2756 // Cause set_cursor to perform change
2758 set_cursor(current_cursor, 1, 0);
2760 for(int i = 0; i < subwindows->total; i++)
2762 subwindows->values[i]->stop_hourglass_recursive();
2770 XFontStruct* BC_WindowBase::get_font_struct(int font)
2772 // Clear out unrelated flags
2773 if(font & BOLDFACE) font ^= BOLDFACE;
2776 case SMALLFONT: return top_level->smallfont; break;
2777 case MEDIUMFONT: return top_level->mediumfont; break;
2778 case LARGEFONT: return top_level->largefont; break;
2779 case BIGFONT: return top_level->bigfont; break;
2780 case CLOCKFONT: return top_level->clockfont; break;
2785 XFontSet BC_WindowBase::get_fontset(int font)
2789 if(get_resources()->use_fontset)
2791 switch(font & 0xff) {
2792 case SMALLFONT: fs = top_level->smallfontset; break;
2793 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2794 case LARGEFONT: fs = top_level->largefontset; break;
2795 case BIGFONT: fs = top_level->bigfontset; break;
2796 case CLOCKFONT: fs = top_level->clockfontset; break;
2804 XftFont* BC_WindowBase::get_xft_struct(int font)
2807 case SMALLFONT: return (XftFont*)top_level->smallfont_xft;
2808 case MEDIUMFONT: return (XftFont*)top_level->mediumfont_xft;
2809 case LARGEFONT: return (XftFont*)top_level->largefont_xft;
2810 case BIGFONT: return (XftFont*)top_level->bigfont_xft;
2811 case CLOCKFONT: return (XftFont*)top_level->clockfont_xft;
2812 case MEDIUMFONT_3D: return (XftFont*)top_level->bold_mediumfont_xft;
2813 case SMALLFONT_3D: return (XftFont*)top_level->bold_smallfont_xft;
2814 case LARGEFONT_3D: return (XftFont*)top_level->bold_largefont_xft;
2822 int BC_WindowBase::get_current_font()
2824 return top_level->current_font;
2827 void BC_WindowBase::set_font(int font)
2829 top_level->current_font = font;
2832 if(get_resources()->use_xft) {}
2835 if(get_resources()->use_fontset) {
2839 if(get_font_struct(font))
2841 XSetFont(top_level->display, top_level->gc, get_font_struct(font)->fid);
2847 void BC_WindowBase::set_fontset(int font)
2851 if(get_resources()->use_fontset) {
2853 case SMALLFONT: fs = top_level->smallfontset; break;
2854 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2855 case LARGEFONT: fs = top_level->largefontset; break;
2856 case BIGFONT: fs = top_level->bigfontset; break;
2857 case CLOCKFONT: fs = top_level->clockfontset; break;
2865 XFontSet BC_WindowBase::get_curr_fontset(void)
2867 if(get_resources()->use_fontset)
2868 return curr_fontset;
2872 int BC_WindowBase::get_single_text_width(int font, const char *text, int length)
2875 if(get_resources()->use_xft && get_xft_struct(font))
2878 #ifdef X_HAVE_UTF8_STRING
2879 if(get_resources()->locale_utf8)
2881 xftTextExtentsUtf8(top_level->display,
2882 get_xft_struct(font),
2883 (const XftChar8 *)text,
2890 xftTextExtents8(top_level->display,
2891 get_xft_struct(font),
2892 (const XftChar8 *)text,
2896 return extents.xOff;
2900 if(get_resources()->use_fontset && top_level->get_fontset(font))
2901 return XmbTextEscapement(top_level->get_fontset(font), text, length);
2903 if(get_font_struct(font))
2904 return XTextWidth(get_font_struct(font), text, length);
2910 case MEDIUM_7SEGMENT:
2911 return get_resources()->medium_7segment[0]->get_w() * length;
2921 int BC_WindowBase::get_text_width(int font, const char *text, int length)
2923 int i, j, w = 0, line_w = 0;
2924 if(length < 0) length = strlen(text);
2926 for(i = 0, j = 0; i <= length; i++)
2931 line_w = get_single_text_width(font, &text[j], i - j);
2937 line_w = get_single_text_width(font, &text[j], length - j);
2939 if(line_w > w) w = line_w;
2942 if(i > length && w == 0)
2944 w = get_single_text_width(font, text, length);
2950 int BC_WindowBase::get_text_width(int font, const wchr_t *text, int length)
2953 if( length < 0 ) length = wstrlen(text);
2955 for( i=j=0; i<length && text[i]; ++i ) {
2956 if( text[i] != '\n' ) continue;
2958 int lw = get_single_text_width(font, &text[j], i-j);
2959 if( w < lw ) w = lw;
2964 int lw = get_single_text_width(font, &text[j], length-j);
2965 if( w < lw ) w = lw;
2971 int BC_WindowBase::get_text_ascent(int font)
2975 if( (fstruct = get_xft_struct(font)) != 0 )
2976 return fstruct->ascent;
2978 if(get_resources()->use_fontset && top_level->get_fontset(font))
2980 XFontSetExtents *extents;
2982 extents = XExtentsOfFontSet(top_level->get_fontset(font));
2983 return -extents->max_logical_extent.y;
2986 if(get_font_struct(font))
2987 return top_level->get_font_struct(font)->ascent;
2990 case MEDIUM_7SEGMENT:
2991 return get_resources()->medium_7segment[0]->get_h();
2996 int BC_WindowBase::get_text_descent(int font)
3000 if( (fstruct = get_xft_struct(font)) != 0 )
3001 return fstruct->descent;
3003 if(get_resources()->use_fontset && top_level->get_fontset(font)) {
3004 XFontSetExtents *extents;
3005 extents = XExtentsOfFontSet(top_level->get_fontset(font));
3006 return (extents->max_logical_extent.height
3007 + extents->max_logical_extent.y);
3010 if(get_font_struct(font))
3011 return top_level->get_font_struct(font)->descent;
3016 int BC_WindowBase::get_text_height(int font, const char *text)
3021 if( (fstruct = get_xft_struct(font)) != 0 )
3022 rowh = fstruct->height;
3025 rowh = get_text_ascent(font) + get_text_descent(font);
3027 if(!text) return rowh;
3029 // Add height of lines
3030 int h = 0, i, length = strlen(text);
3031 for(i = 0; i <= length; i++)
3042 // truncate the text with ... & return a new string
3043 char *BC_WindowBase::get_truncated_text(int font, const char *text, int max_w)
3045 char *result = cstrdup(text);
3046 int text_w = get_text_width(font, text);
3047 int ci = -1, len = strlen(text);
3048 if( text_w > max_w ) {
3049 // get center of string
3050 int cx = text_w/2, best = INT_MAX;
3051 for( int i=1; i<=len; ++i ) {
3052 int cw = get_text_width(font, text, i);
3053 if( abs(cw-cx) < abs(best-cx) ) {
3058 if( ci > 0 && ci < len-1 ) {
3059 // insert ... in the center
3060 result[ci-1] = result[ci] = result[ci+1] = '.';
3062 while( ci-2>=0 && ci+2<(int)strlen(result) &&
3063 get_text_width(font, result) > max_w ) {
3064 // take away a character from the longer side
3065 int left_w = get_text_width(font, result, ci-2);
3066 int right_w = get_text_width(font, result + ci+3);
3067 int i = left_w > right_w ? --ci-1 : ci+2;
3068 while( (result[i]=result[i+1])!=0 ) ++i;
3075 BC_Bitmap* BC_WindowBase::new_bitmap(int w, int h, int color_model)
3077 if(color_model < 0) color_model = top_level->get_color_model();
3078 return new BC_Bitmap(top_level, w, h, color_model);
3081 void BC_WindowBase::init_wait()
3083 #ifndef SINGLE_THREAD
3084 if(window_type != MAIN_WINDOW)
3085 top_level->init_wait();
3086 init_lock->lock("BC_WindowBase::init_wait");
3087 init_lock->unlock();
3091 int BC_WindowBase::accel_available(int color_model, int lock_it)
3093 if( window_type != MAIN_WINDOW )
3094 return top_level->accel_available(color_model, lock_it);
3096 lock_window("BC_WindowBase::accel_available");
3098 switch(color_model) {
3100 grab_port_id(color_model);
3104 grab_port_id(color_model);
3113 //printf("BC_WindowBase::accel_available %d %d\n", color_model, xvideo_port_id);
3114 return xvideo_port_id >= 0 ? 1 : 0;
3118 int BC_WindowBase::grab_port_id(int color_model)
3121 if( !get_resources()->use_xvideo || // disabled
3122 !get_resources()->use_shm ) // Only local server is fast enough.
3124 if( xvideo_port_id >= 0 )
3125 return xvideo_port_id;
3127 unsigned int ver, rev, reqBase, eventBase, errorBase;
3128 if( Success != XvQueryExtension(display, // XV extension is available
3129 &ver, &rev, &reqBase, &eventBase, &errorBase) )
3132 // XV adaptors are available
3133 unsigned int numAdapt = 0;
3134 XvAdaptorInfo *info = 0;
3135 XvQueryAdaptors(display, DefaultRootWindow(display), &numAdapt, &info);
3139 // Translate from color_model to X color model
3140 int x_color_model = BC_CModels::bc_to_x(color_model);
3142 // Get adaptor with desired color model
3143 for( int i = 0; i < (int)numAdapt && xvideo_port_id == -1; i++) {
3144 if( !(info[i].type & XvImageMask) || !info[i].num_ports ) continue;
3145 // adaptor supports XvImages
3146 int numFormats = 0, numPorts = info[i].num_ports;
3147 XvImageFormatValues *formats =
3148 XvListImageFormats(display, info[i].base_id, &numFormats);
3149 if( !formats ) continue;
3151 for( int j=0; j<numFormats && xvideo_port_id<0; ++j ) {
3152 if( formats[j].id != x_color_model ) continue;
3153 // this adaptor supports the desired format, grab a port
3154 for( int k=0; k<numPorts; ++k ) {
3155 if( Success == XvGrabPort(top_level->display,
3156 info[i].base_id+k, CurrentTime) ) {
3157 //printf("BC_WindowBase::grab_port_id %llx\n", info[i].base_id);
3158 xvideo_port_id = info[i].base_id + k;
3166 XvFreeAdaptorInfo(info);
3167 return xvideo_port_id;
3174 int BC_WindowBase::show_window(int flush)
3176 for(int i = 0; i < subwindows->size(); i++)
3178 subwindows->get(i)->show_window(0);
3181 XMapWindow(top_level->display, win);
3182 if(flush) XFlush(top_level->display);
3183 // XSync(top_level->display, 0);
3188 int BC_WindowBase::hide_window(int flush)
3190 for(int i = 0; i < subwindows->size(); i++)
3192 subwindows->get(i)->hide_window(0);
3195 XUnmapWindow(top_level->display, win);
3196 if(flush) this->flush();
3201 BC_MenuBar* BC_WindowBase::add_menubar(BC_MenuBar *menu_bar)
3203 subwindows->append((BC_SubWindow*)menu_bar);
3205 menu_bar->parent_window = this;
3206 menu_bar->top_level = this->top_level;
3207 menu_bar->initialize();
3211 BC_WindowBase* BC_WindowBase::add_popup(BC_WindowBase *window)
3213 //printf("BC_WindowBase::add_popup window=%p win=%p\n", window, window->win);
3214 if(this != top_level) return top_level->add_popup(window);
3215 popups.append(window);
3219 void BC_WindowBase::remove_popup(BC_WindowBase *window)
3221 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3222 if(this != top_level)
3223 top_level->remove_popup(window);
3225 popups.remove(window);
3226 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3230 BC_WindowBase* BC_WindowBase::add_subwindow(BC_WindowBase *subwindow)
3232 subwindows->append(subwindow);
3234 if(subwindow->bg_color == -1) subwindow->bg_color = this->bg_color;
3236 // parent window must be set before the subwindow initialization
3237 subwindow->parent_window = this;
3238 subwindow->top_level = this->top_level;
3240 // Execute derived initialization
3241 subwindow->initialize();
3246 BC_WindowBase* BC_WindowBase::add_tool(BC_WindowBase *subwindow)
3248 return add_subwindow(subwindow);
3251 int BC_WindowBase::flash(int x, int y, int w, int h, int flush)
3253 if( !top_level->flash_enabled ) return 0;
3254 //printf("BC_WindowBase::flash %d %d %d %d %d\n", __LINE__, w, h, this->w, this->h);
3256 XSetWindowBackgroundPixmap(top_level->display, win, pixmap->opaque_pixmap);
3259 XClearArea(top_level->display, win, x, y, w, h, 0);
3263 XClearWindow(top_level->display, win);
3271 int BC_WindowBase::flash(int flush)
3273 flash(-1, -1, -1, -1, flush);
3277 void BC_WindowBase::flush()
3279 //if(!get_window_lock())
3280 // printf("BC_WindowBase::flush %s not locked\n", top_level->title);
3281 // X gets hosed if Flush/Sync are not user locked (at libX11-1.1.5 / libxcb-1.1.91)
3282 // _XReply deadlocks in condition_wait waiting for xlib lock when waiters!=-1
3283 int locked = get_window_lock();
3284 if( !locked ) lock_window("BC_WindowBase::flush");
3285 XFlush(top_level->display);
3286 if( !locked ) unlock_window();
3289 void BC_WindowBase::sync_display()
3291 int locked = get_window_lock();
3292 if( !locked ) lock_window("BC_WindowBase::sync_display");
3293 XSync(top_level->display, False);
3294 if( !locked ) unlock_window();
3297 int BC_WindowBase::get_window_lock()
3299 #ifdef SINGLE_THREAD
3300 return BC_Display::display_global->get_display_locked();
3302 return top_level->window_lock;
3306 int BC_WindowBase::lock_window(const char *location)
3308 if(top_level && top_level != this)
3310 top_level->lock_window(location);
3315 SET_LOCK(this, title, location);
3316 #ifdef SINGLE_THREAD
3317 BC_Display::lock_display(location);
3319 XLockDisplay(top_level->display);
3320 top_level->display_lock_owner = pthread_self();
3323 ++top_level->window_lock;
3327 printf("BC_WindowBase::lock_window top_level NULL\n");
3332 int BC_WindowBase::unlock_window()
3334 if(top_level && top_level != this)
3336 top_level->unlock_window();
3342 if( !top_level->window_lock ) {
3343 printf("BC_WindowBase::unlock_window %s not locked\n", title);
3346 if( top_level->window_lock > 0 )
3347 if( --top_level->window_lock == 0 )
3348 top_level->display_lock_owner = 0;
3349 #ifdef SINGLE_THREAD
3350 BC_Display::unlock_display();
3352 XUnlockDisplay(top_level->display);
3357 printf("BC_WindowBase::unlock_window top_level NULL\n");
3362 int BC_WindowBase::break_lock()
3364 if( !top_level ) return 0;
3365 if( top_level != this ) return top_level->break_lock();
3366 if( top_level->display_lock_owner != pthread_self() ) return 0;
3367 if( top_level->window_lock != 1 ) return 0;
3370 display_lock_owner = 0;
3371 #ifdef SINGLE_THREAD
3372 BC_Display::unlock_display();
3374 XUnlockDisplay(display);
3379 void BC_WindowBase::set_done(int return_value)
3381 if(done_set) return;
3383 if(window_type != MAIN_WINDOW)
3384 top_level->set_done(return_value);
3387 #ifdef SINGLE_THREAD
3388 this->return_value = return_value;
3389 BC_Display::display_global->arm_completion(this);
3390 completion_lock->unlock();
3391 #else // SINGLE_THREAD
3393 if( !event_thread ) return;
3394 XEvent *event = new_xevent();
3395 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
3396 event->type = ClientMessage;
3397 ptr->message_type = SetDoneXAtom;
3399 this->return_value = return_value;
3400 // May lock up here because XSendEvent doesn't work too well
3401 // asynchronous with XNextEvent.
3402 // This causes BC_WindowEvents to forward a copy of the event to run_window where
3404 // Deletion of event_thread is done at the end of BC_WindowBase::run_window() - by calling the destructor
3410 void BC_WindowBase::close(int return_value)
3412 hide_window(); flush();
3413 set_done(return_value);
3416 int BC_WindowBase::grab(BC_WindowBase *window)
3419 if( window->active_grab ) {
3420 int locked = get_window_lock();
3421 if( locked ) unlock_window();
3422 BC_WindowBase *active_grab = window->active_grab;
3423 active_grab->lock_window("BC_WindowBase::grab(BC_WindowBase");
3424 ret = active_grab->handle_ungrab();
3425 active_grab->unlock_window();
3426 if( locked ) lock_window("BC_WindowBase::grab(BC_WindowBase");
3429 window->active_grab = this;
3430 this->grab_active = window;
3434 int BC_WindowBase::ungrab(BC_WindowBase *window)
3436 if( this != window->active_grab ) return 0;
3437 window->active_grab = 0;
3438 this->grab_active = 0;
3441 int BC_WindowBase::grab_event_count()
3444 #ifndef SINGLE_THREAD
3445 result = grab_active->get_event_count();
3449 int BC_WindowBase::grab_buttons()
3451 XSync(top_level->display, False);
3452 if( XGrabButton(top_level->display, AnyButton, AnyModifier,
3453 top_level->rootwin, True, ButtonPressMask | ButtonReleaseMask,
3454 GrabModeAsync, GrabModeSync, None, None) == GrabSuccess ) {
3455 set_active_subwindow(this);
3460 void BC_WindowBase::ungrab_buttons()
3462 XUngrabButton(top_level->display, AnyButton, AnyModifier, top_level->rootwin);
3463 set_active_subwindow(0);
3466 void BC_WindowBase::grab_cursor()
3468 Cursor cursor_grab = get_cursor_struct(GRABBED_CURSOR);
3469 XGrabPointer(top_level->display, top_level->rootwin, True,
3470 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
3471 GrabModeAsync, GrabModeAsync, None, cursor_grab, CurrentTime);
3473 void BC_WindowBase::ungrab_cursor()
3475 XUngrabPointer(top_level->display, CurrentTime);
3479 // WidthOfScreen/HeightOfScreen of XDefaultScreenOfDisplay
3480 // this is the bounding box of all the screens
3482 int BC_WindowBase::get_root_w(int lock_display)
3484 if(lock_display) lock_window("BC_WindowBase::get_root_w");
3485 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3486 int result = WidthOfScreen(def_screen);
3487 if(lock_display) unlock_window();
3491 int BC_WindowBase::get_root_h(int lock_display)
3493 if(lock_display) lock_window("BC_WindowBase::get_root_h");
3494 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3495 int result = HeightOfScreen(def_screen);
3496 if(lock_display) unlock_window();
3500 XineramaScreenInfo *
3501 BC_WindowBase::get_xinerama_info(int screen)
3503 if( !xinerama_info || !xinerama_screens ) return 0;
3505 for( int i=0; i<xinerama_screens; ++i )
3506 if( xinerama_info[i].screen_number == screen )
3507 return &xinerama_info[i];
3510 int top_x = get_x(), top_y = get_y();
3511 if( BC_DisplayInfo::left_border >= 0 ) top_x += BC_DisplayInfo::left_border;
3512 if( BC_DisplayInfo::top_border >= 0 ) top_y += BC_DisplayInfo::top_border;
3513 for( int i=0; i<xinerama_screens; ++i ) {
3514 int scr_y = top_y - xinerama_info[i].y_org;
3515 if( scr_y < 0 || scr_y >= xinerama_info[i].height ) continue;
3516 int scr_x = top_x - xinerama_info[i].x_org;
3517 if( scr_x >= 0 && scr_x < xinerama_info[i].width )
3518 return &xinerama_info[i];
3523 void BC_WindowBase::get_fullscreen_geometry(int &wx, int &wy, int &ww, int &wh)
3525 XineramaScreenInfo *info = top_level->get_xinerama_info(-1);
3527 wx = info->x_org; wy = info->y_org;
3528 ww = info->width; wh = info->height;
3531 wx = get_screen_x(0, -1);
3532 wy = get_screen_y(0, -1);
3533 int scr_w0 = get_screen_w(0, 0);
3534 int root_w = get_root_w(0);
3535 int root_h = get_root_h(0);
3536 if( root_w > scr_w0 ) { // multi-headed
3537 if( wx >= scr_w0 ) {
3538 // assumes right side is the big one
3539 ww = root_w - scr_w0;
3543 // use same aspect ratio to compute left height
3545 wh = (w*root_h) / (root_w-scr_w0);
3555 int BC_WindowBase::get_screen_x(int lock_display, int screen)
3558 if(lock_display) lock_window("BC_WindowBase::get_screen_x");
3559 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3562 int root_w = get_root_w(0);
3563 int root_h = get_root_h(0);
3564 // Shift X based on position of current window if dual head
3565 if( (float)root_w/root_h > 1.8 ) {
3566 root_w = get_screen_w(0, 0);
3567 if( top_level->get_x() >= root_w )
3572 result = info->x_org;
3573 if(lock_display) unlock_window();
3577 int BC_WindowBase::get_screen_y(int lock_display, int screen)
3579 if(lock_display) lock_window("BC_WindowBase::get_screen_y");
3580 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3581 int result = !info ? 0 : info->y_org;
3582 if(lock_display) unlock_window();
3586 int BC_WindowBase::get_screen_w(int lock_display, int screen)
3589 if(lock_display) lock_window("BC_WindowBase::get_screen_w");
3590 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3592 int width = get_root_w(0);
3593 int height = get_root_h(0);
3594 if( (float)width/height > 1.8 ) {
3595 // If dual head, the screen width is > 16x9
3596 // but we only want to fill one screen
3597 // this code assumes the "big" screen is on the right
3598 int scr_w0 = width / 2;
3600 case 600: scr_w0 = 800; break;
3601 case 720: scr_w0 = 1280; break;
3602 case 1024: scr_w0 = 1280; break;
3603 case 1200: scr_w0 = 1600; break;
3604 case 1080: scr_w0 = 1920; break;
3606 int scr_w1 = width - scr_w0;
3607 result = screen > 0 ? scr_w1 :
3608 screen == 0 ? scr_w0 :
3609 top_level->get_x() < scr_w0 ? scr_w0 : scr_w1;
3615 result = info->width;
3616 if(lock_display) unlock_window();
3620 int BC_WindowBase::get_screen_h(int lock_display, int screen)
3622 if(lock_display) lock_window("BC_WindowBase::get_screen_h");
3623 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3624 int result = info ? info->height : get_root_h(0);
3625 if(lock_display) unlock_window();
3629 // Bottom right corner
3630 int BC_WindowBase::get_x2()
3635 int BC_WindowBase::get_y2()
3640 int BC_WindowBase::get_video_on()
3645 int BC_WindowBase::get_hidden()
3647 return top_level->hidden;
3650 int BC_WindowBase::cursor_inside()
3652 return (top_level->cursor_x >= 0 &&
3653 top_level->cursor_y >= 0 &&
3654 top_level->cursor_x < w &&
3655 top_level->cursor_y < h);
3658 BC_WindowBase* BC_WindowBase::get_top_level()
3663 BC_WindowBase* BC_WindowBase::get_parent()
3665 return parent_window;
3668 int BC_WindowBase::get_color_model()
3670 return top_level->color_model;
3673 BC_Resources* BC_WindowBase::get_resources()
3675 return BC_WindowBase::resources;
3678 BC_Synchronous* BC_WindowBase::get_synchronous()
3680 return BC_WindowBase::resources->get_synchronous();
3683 int BC_WindowBase::get_bg_color()
3688 void BC_WindowBase::set_bg_color(int color)
3690 this->bg_color = color;
3693 BC_Pixmap* BC_WindowBase::get_bg_pixmap()
3698 void BC_WindowBase::set_active_subwindow(BC_WindowBase *subwindow)
3700 top_level->active_subwindow = subwindow;
3703 int BC_WindowBase::activate()
3708 int BC_WindowBase::deactivate()
3710 if(window_type == MAIN_WINDOW)
3712 if( top_level->active_menubar ) {
3713 top_level->active_menubar->deactivate();
3714 top_level->active_menubar = 0;
3716 if( top_level->active_popup_menu ) {
3717 top_level->active_popup_menu->deactivate();
3718 top_level->active_popup_menu = 0;
3720 if( top_level->active_subwindow ) {
3721 top_level->active_subwindow->deactivate();
3722 top_level->active_subwindow = 0;
3724 if( top_level->motion_events && top_level->last_motion_win == this->win )
3725 top_level->motion_events = 0;
3731 int BC_WindowBase::cycle_textboxes(int amount)
3734 BC_WindowBase *new_textbox = 0;
3738 BC_WindowBase *first_textbox = 0;
3739 find_next_textbox(&first_textbox, &new_textbox, result);
3740 if(!new_textbox) new_textbox = first_textbox;
3746 BC_WindowBase *last_textbox = 0;
3747 find_prev_textbox(&last_textbox, &new_textbox, result);
3748 if(!new_textbox) new_textbox = last_textbox;
3752 if(new_textbox != active_subwindow)
3755 new_textbox->activate();
3761 int BC_WindowBase::find_next_textbox(BC_WindowBase **first_textbox, BC_WindowBase **next_textbox, int &result)
3763 // Search subwindows for textbox
3764 for(int i = 0; i < subwindows->total && result < 2; i++)
3766 BC_WindowBase *test_subwindow = subwindows->values[i];
3767 test_subwindow->find_next_textbox(first_textbox, next_textbox, result);
3774 if(!*first_textbox) *first_textbox = this;
3778 if(top_level->active_subwindow == this)
3784 *next_textbox = this;
3791 int BC_WindowBase::find_prev_textbox(BC_WindowBase **last_textbox, BC_WindowBase **prev_textbox, int &result)
3797 if(!*last_textbox) *last_textbox = this;
3801 if(top_level->active_subwindow == this)
3807 *prev_textbox = this;
3812 // Search subwindows for textbox
3813 for(int i = subwindows->total - 1; i >= 0 && result < 2; i--)
3815 BC_WindowBase *test_subwindow = subwindows->values[i];
3816 test_subwindow->find_prev_textbox(last_textbox, prev_textbox, result);
3821 BC_Clipboard* BC_WindowBase::get_clipboard()
3823 #ifdef SINGLE_THREAD
3824 return BC_Display::display_global->clipboard;
3826 return top_level->clipboard;
3830 Atom BC_WindowBase::to_clipboard(const char *data, long len, int clipboard_num)
3832 return get_clipboard()->to_clipboard(this, data, len, clipboard_num);
3835 long BC_WindowBase::from_clipboard(char *data, long maxlen, int clipboard_num)
3837 return get_clipboard()->from_clipboard(data, maxlen, clipboard_num);
3840 long BC_WindowBase::clipboard_len(int clipboard_num)
3842 return get_clipboard()->clipboard_len(clipboard_num);
3845 int BC_WindowBase::do_selection_clear(Window win)
3847 top_level->event_win = win;
3848 return dispatch_selection_clear();
3851 int BC_WindowBase::dispatch_selection_clear()
3854 for( int i=0; i<subwindows->total && !result; ++i )
3855 result = subwindows->values[i]->dispatch_selection_clear();
3857 result = selection_clear_event();
3862 void BC_WindowBase::get_relative_cursor(int &x, int &y, int lock_window)
3864 int abs_x, abs_y, win_x, win_y;
3865 unsigned int temp_mask;
3868 if(lock_window) this->lock_window("BC_WindowBase::get_relative_cursor");
3869 XQueryPointer(top_level->display, top_level->win,
3870 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3873 XTranslateCoordinates(top_level->display, top_level->rootwin,
3874 win, abs_x, abs_y, &x, &y, &temp_win);
3875 if(lock_window) this->unlock_window();
3877 int BC_WindowBase::get_relative_cursor_x(int lock_window)
3880 get_relative_cursor(x, y, lock_window);
3883 int BC_WindowBase::get_relative_cursor_y(int lock_window)
3886 get_relative_cursor(x, y, lock_window);
3890 void BC_WindowBase::get_abs_cursor(int &abs_x, int &abs_y, int lock_window)
3893 unsigned int temp_mask;
3896 if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor");
3897 XQueryPointer(top_level->display, top_level->win,
3898 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3900 if(lock_window) this->unlock_window();
3902 int BC_WindowBase::get_abs_cursor_x(int lock_window)
3905 get_abs_cursor(abs_x, abs_y, lock_window);
3908 int BC_WindowBase::get_abs_cursor_y(int lock_window)
3911 get_abs_cursor(abs_x, abs_y, lock_window);
3915 void BC_WindowBase::get_pop_cursor(int &px, int &py, int lock_window)
3917 int xmargin = xS(100), ymargin = yS(100);
3918 get_abs_cursor(px, py, lock_window);
3919 if( px < xmargin ) px = xmargin;
3920 if( py < ymargin ) py = ymargin;
3921 int wd = get_screen_x(lock_window,-1) + get_screen_w(lock_window,-1) - xmargin;
3922 if( px > wd ) px = wd;
3923 int ht = get_screen_y(lock_window,-1) + get_screen_h(lock_window,-1) - ymargin;
3924 if( py > ht ) py = ht;
3926 int BC_WindowBase::get_pop_cursor_x(int lock_window)
3929 get_pop_cursor(px, py, lock_window);
3932 int BC_WindowBase::get_pop_cursor_y(int lock_window)
3935 get_pop_cursor(px, py, lock_window);
3939 int BC_WindowBase::match_window(Window win)
3941 if (this->win == win) return 1;
3943 for(int i = 0; i < subwindows->total; i++) {
3944 result = subwindows->values[i]->match_window(win);
3945 if (result) return result;
3951 int BC_WindowBase::get_cursor_over_window()
3953 int abs_x, abs_y, win_x, win_y;
3954 unsigned int mask_return;
3955 Window root_return, child_return;
3957 int ret = XQueryPointer(top_level->display, top_level->rootwin,
3958 &root_return, &child_return, &abs_x, &abs_y,
3959 &win_x, &win_y, &mask_return);
3960 if( ret && child_return == None ) ret = 0;
3961 if( ret && win != child_return )
3962 ret = top_level->match_window(child_return);
3963 // query pointer can return a window manager window with this top_level as a child
3964 // for kde this can be two levels deep
3965 unsigned int nchildren_return = 0;
3966 Window parent_return, *children_return = 0;
3967 Window top_win = top_level->win;
3968 while( !ret && top_win != top_level->rootwin && top_win != root_return &&
3969 XQueryTree(top_level->display, top_win, &root_return,
3970 &parent_return, &children_return, &nchildren_return) ) {
3971 if( children_return ) XFree(children_return);
3972 if( (top_win=parent_return) == child_return ) ret = 1;
3977 int BC_WindowBase::cursor_above()
3980 get_relative_cursor(rx, ry);
3981 return rx < 0 || rx >= get_w() ||
3982 ry < 0 || ry >= get_h() ? 0 : 1;
3985 int BC_WindowBase::get_drag_x()
3987 return top_level->drag_x;
3990 int BC_WindowBase::get_drag_y()
3992 return top_level->drag_y;
3995 int BC_WindowBase::get_cursor_x()
3997 return top_level->cursor_x;
4000 int BC_WindowBase::get_cursor_y()
4002 return top_level->cursor_y;
4005 int BC_WindowBase::dump_windows()
4007 printf("\tBC_WindowBase::dump_windows window=%p win=%p '%s', %dx%d+%d+%d %s\n",
4008 this, (void*)this->win, title, w,h,x,y, typeid(*this).name());
4009 for(int i = 0; i < subwindows->size(); i++)
4010 subwindows->get(i)->dump_windows();
4011 for(int i = 0; i < popups.size(); i++) {
4012 BC_WindowBase *p = popups[i];
4013 printf("\tBC_WindowBase::dump_windows popup=%p win=%p '%s', %dx%d+%d+%d %s\n",
4014 p, (void*)p->win, p->title, p->w,p->h,p->x,p->y, typeid(*p).name());
4019 int BC_WindowBase::is_event_win()
4021 return this->win == top_level->event_win;
4024 void BC_WindowBase::set_dragging(int value)
4026 is_dragging = value;
4029 int BC_WindowBase::get_dragging()
4034 int BC_WindowBase::get_buttonpress()
4036 return top_level->button_number;
4039 int BC_WindowBase::get_button_down()
4041 return top_level->button_down;
4044 int BC_WindowBase::alt_down()
4046 return top_level->alt_mask;
4049 int BC_WindowBase::shift_down()
4051 return top_level->shift_mask;
4054 int BC_WindowBase::ctrl_down()
4056 return top_level->ctrl_mask;
4059 wchr_t* BC_WindowBase::get_wkeystring(int *length)
4062 *length = top_level->wkey_string_length;
4063 return top_level->wkey_string;
4066 #ifdef X_HAVE_UTF8_STRING
4067 char* BC_WindowBase::get_keypress_utf8()
4069 return top_level->key_pressed_utf8;
4074 int BC_WindowBase::get_keypress()
4076 return top_level->key_pressed;
4079 int BC_WindowBase::get_double_click()
4081 return top_level->double_click;
4084 int BC_WindowBase::get_triple_click()
4086 return top_level->triple_click;
4089 int BC_WindowBase::get_bgcolor()
4094 int BC_WindowBase::resize_window(int w, int h)
4096 if(this->w == w && this->h == h) return 0;
4098 if(window_type == MAIN_WINDOW && !allow_resize)
4100 XSizeHints size_hints;
4101 size_hints.flags = PSize | PMinSize | PMaxSize;
4102 size_hints.width = w;
4103 size_hints.height = h;
4104 size_hints.min_width = w;
4105 size_hints.max_width = w;
4106 size_hints.min_height = h;
4107 size_hints.max_height = h;
4108 if( this->x > -BC_INFINITY && this->x < BC_INFINITY ) {
4109 size_hints.flags |= PPosition;
4110 size_hints.x = this->x;
4111 size_hints.y = this->y;
4113 XSetNormalHints(top_level->display, win, &size_hints);
4115 XResizeWindow(top_level->display, win, w, h);
4120 pixmap = new BC_Pixmap(this, w, h);
4122 // Propagate to menubar
4123 for(int i = 0; i < subwindows->total; i++)
4125 subwindows->values[i]->dispatch_resize_event(w, h);
4128 draw_background(0, 0, w, h);
4129 if(top_level == this && get_resources()->recursive_resizing)
4130 resize_history.append(new BC_ResizeCall(w, h));
4134 // The only way for resize events to be propagated is by updating the internal w and h
4135 int BC_WindowBase::resize_event(int w, int h)
4137 if(window_type == MAIN_WINDOW)
4145 int BC_WindowBase::reposition_window(int x, int y)
4147 reposition_window(x, y, -1, -1);
4152 int BC_WindowBase::reposition_window(int x, int y, int w, int h)
4156 // Some tools set their own dimensions before calling this, causing the
4157 // resize check to skip.
4161 if(w > 0 && w != this->w)
4167 if(h > 0 && h != this->h)
4173 //printf("BC_WindowBase::reposition_window %d %d %d\n", translation_count, x_correction, y_correction);
4176 printf("BC_WindowBase::reposition_window this->w == %d\n", this->w);
4178 printf("BC_WindowBase::reposition_window this->h == %d\n", this->h);
4180 if(translation_count && window_type == MAIN_WINDOW)
4182 // KDE shifts window right and down.
4183 // FVWM leaves window alone and adds border around it.
4184 XMoveResizeWindow(top_level->display, win,
4185 x - BC_DisplayInfo::auto_reposition_x,
4186 y - BC_DisplayInfo::auto_reposition_y,
4191 XMoveResizeWindow(top_level->display, win, x, y,
4198 pixmap = new BC_Pixmap(this, this->w, this->h);
4199 clear_box(0,0, this->w, this->h);
4200 // Propagate to menubar
4201 for(int i = 0; i < subwindows->total; i++)
4203 subwindows->values[i]->dispatch_resize_event(this->w, this->h);
4206 // draw_background(0, 0, w, h);
4212 int BC_WindowBase::reposition_window_relative(int dx, int dy, int w, int h)
4214 return reposition_window(get_x()+dx, get_y()+dy, w, h);
4217 int BC_WindowBase::reposition_window_relative(int dx, int dy)
4219 return reposition_window_relative(dx, dy, -1, -1);
4222 void BC_WindowBase::set_tooltips(int v)
4224 get_resources()->tooltips_enabled = v;
4227 void BC_WindowBase::set_force_tooltip(int v)
4232 int BC_WindowBase::raise_window(int do_flush)
4234 if( hidden ) return 1;
4235 if( wait_viewable(500) ) return 1;
4236 XRaiseWindow(top_level->display, win);
4237 if(do_flush) XFlush(top_level->display);
4241 int BC_WindowBase::lower_window(int do_flush)
4243 XLowerWindow(top_level->display, win);
4244 if(do_flush) XFlush(top_level->display);
4248 void BC_WindowBase::set_background(VFrame *bitmap)
4250 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
4252 bg_pixmap = new BC_Pixmap(this, bitmap, PIXMAP_OPAQUE);
4253 shared_bg_pixmap = 0;
4254 draw_background(0, 0, w, h);
4257 void BC_WindowBase::put_title(const char *text)
4259 char *cp = this->title, *ep = cp+sizeof(this->title)-1;
4260 for( const unsigned char *bp = (const unsigned char *)text; *bp && cp<ep; ++bp )
4261 *cp++ = *bp >= ' ' ? *bp : ' ';
4265 void BC_WindowBase::set_title(const char *text, int utf8)
4267 // utf8>0: wm + net_wm, utf8=0: wm only, utf<0: net_wm only
4269 const unsigned char *wm_title = (const unsigned char *)title;
4270 int title_len = strlen((const char *)title);
4272 Atom xa_wm_name = XA_WM_NAME;
4273 Atom xa_icon_name = XA_WM_ICON_NAME;
4274 Atom xa_string = XA_STRING;
4275 XChangeProperty(display, win, xa_wm_name, xa_string, 8,
4276 PropModeReplace, wm_title, title_len);
4277 XChangeProperty(display, win, xa_icon_name, xa_string, 8,
4278 PropModeReplace, wm_title, title_len);
4281 Atom xa_net_wm_name = XInternAtom(display, "_NET_WM_NAME", True);
4282 Atom xa_net_icon_name = XInternAtom(display, "_NET_WM_ICON_NAME", True);
4283 Atom xa_utf8_string = XInternAtom(display, "UTF8_STRING", True);
4284 XChangeProperty(display, win, xa_net_wm_name, xa_utf8_string, 8,
4285 PropModeReplace, wm_title, title_len);
4286 XChangeProperty(display, win, xa_net_icon_name, xa_utf8_string, 8,
4287 PropModeReplace, wm_title, title_len);
4293 void BC_WindowBase::set_net_icon(VFrame *data)
4295 int width = data->get_w(), height = data->get_h();
4296 int size = 2 + width * height;
4297 unsigned long *icon_data = new unsigned long[size];
4298 unsigned long *lp = icon_data;
4299 *lp++ = width; *lp++ = height;
4300 uint8_t **rows = data->get_rows();
4301 for( int y=0; y<height; ++y ) {
4302 unsigned *up = (unsigned *)rows[y];
4303 for( int x=0; x<width; ++x )
4304 *lp++ = *(unsigned *)up++;
4306 Atom NetWMIcon = XInternAtom(display, "_NET_WM_ICON", True);
4307 XChangeProperty(top_level->display, top_level->win, NetWMIcon,
4308 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)icon_data, size);
4309 delete [] icon_data;
4312 const char *BC_WindowBase::get_title()
4317 int BC_WindowBase::get_toggle_value()
4319 return toggle_value;
4322 int BC_WindowBase::get_toggle_drag()
4327 int BC_WindowBase::set_icon(VFrame *data)
4329 if(icon_pixmap) delete icon_pixmap;
4330 icon_pixmap = new BC_Pixmap(top_level, data, PIXMAP_ALPHA, 1);
4332 if(icon_window) delete icon_window;
4333 icon_window = new BC_Popup(this, 0, 0,
4334 icon_pixmap->get_w(), icon_pixmap->get_h(),
4335 -1, 1, // All windows are hidden initially
4338 XWMHints wm_hints; memset(&wm_hints, 0, sizeof(wm_hints));
4339 wm_hints.flags = IconPixmapHint; // | IconMaskHint | IconWindowHint;
4340 wm_hints.icon_pixmap = icon_pixmap->get_pixmap();
4341 wm_hints.icon_mask = icon_pixmap->get_alpha();
4342 wm_hints.icon_window = icon_window->win;
4343 if( XGroupLeader ) {
4344 wm_hints.flags |= WindowGroupHint;
4345 wm_hints.window_group = XGroupLeader;
4348 // for(int i = 0; i < 1000; i++)
4349 // printf("02x ", icon_pixmap->get_alpha()->get_row_pointers()[0][i]);
4352 XSetWMHints(top_level->display, top_level->win, &wm_hints);
4355 XSync(top_level->display, 0);
4359 void BC_WindowBase::init_resources(float scale)
4361 if( resources ) return;
4363 const char *env = getenv("BC_SCALE");
4364 if( env ) scale = atof(env);
4365 float x_scale = 1, y_scale = 1;
4367 BC_DisplayInfo info;
4369 int cins = info.xinerama_big_screen();
4370 if( !info.xinerama_geometry(cins, wx, wy, ww, wh) ) {
4371 int sh = ww * 9 / 16;
4372 int sw = wh * 16 / 9;
4373 if( sw < ww ) ww = sw;
4374 if( sh < wh ) wh = sh;
4375 if( (x_scale = ww/1920.) < 1 ) x_scale = 1;
4376 if( (y_scale = wh/1080.) < 1 ) y_scale = 1;
4380 x_scale = y_scale = scale;
4381 // constructor sets BC_WindowBase::resources
4382 new BC_Resources(x_scale, y_scale);
4384 void BC_WindowBase::finit_resources()
4386 delete resources; resources = 0;
4389 int BC_WindowBase::set_w(int w)
4395 int BC_WindowBase::set_h(int h)
4401 int BC_WindowBase::load_defaults(BC_Hash *defaults)
4403 char string[BCTEXTLEN];
4404 int newest_id = - 1;
4405 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4407 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4408 resources->filebox_history[i].path[0] = 0;
4409 defaults->get(string, resources->filebox_history[i].path);
4410 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4411 resources->filebox_history[i].id = defaults->get(string, resources->get_id());
4412 if(resources->filebox_history[i].id > newest_id)
4413 newest_id = resources->filebox_history[i].id;
4416 resources->filebox_id = newest_id + 1;
4417 resources->filebox_mode = defaults->get("FILEBOX_MODE", get_resources()->filebox_mode);
4418 resources->filebox_w = defaults->get("FILEBOX_W", get_resources()->filebox_w);
4419 resources->filebox_h = defaults->get("FILEBOX_H", get_resources()->filebox_h);
4420 resources->filebox_columntype[0] = defaults->get("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4421 resources->filebox_columntype[1] = defaults->get("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4422 resources->filebox_columntype[2] = defaults->get("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4423 resources->filebox_columntype[3] = defaults->get("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4424 resources->filebox_columnwidth[0] = defaults->get("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4425 resources->filebox_columnwidth[1] = defaults->get("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4426 resources->filebox_columnwidth[2] = defaults->get("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4427 resources->filebox_columnwidth[3] = defaults->get("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4428 resources->filebox_size_format = defaults->get("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4429 defaults->get("FILEBOX_FILTER", resources->filebox_filter);
4433 int BC_WindowBase::save_defaults(BC_Hash *defaults)
4435 char string[BCTEXTLEN];
4436 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4438 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4439 defaults->update(string, resources->filebox_history[i].path);
4440 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4441 defaults->update(string, resources->filebox_history[i].id);
4443 defaults->update("FILEBOX_MODE", resources->filebox_mode);
4444 defaults->update("FILEBOX_W", resources->filebox_w);
4445 defaults->update("FILEBOX_H", resources->filebox_h);
4446 defaults->update("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4447 defaults->update("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4448 defaults->update("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4449 defaults->update("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4450 defaults->update("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4451 defaults->update("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4452 defaults->update("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4453 defaults->update("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4454 defaults->update("FILEBOX_FILTER", resources->filebox_filter);
4455 defaults->update("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4461 // For some reason XTranslateCoordinates can take a long time to return.
4462 // We work around this by only calling it when the event windows are different.
4463 void BC_WindowBase::translate_coordinates(Window src_w, Window dest_w,
4464 int src_x, int src_y, int *dest_x_return, int *dest_y_return)
4471 *dest_x_return = src_x;
4472 *dest_y_return = src_y;
4476 XTranslateCoordinates(top_level->display, src_w, dest_w,
4477 src_x, src_y, dest_x_return, dest_y_return, &tempwin);
4478 //printf("BC_WindowBase::translate_coordinates 1 %lld\n", timer.get_difference());
4482 void BC_WindowBase::get_root_coordinates(int x, int y, int *abs_x, int *abs_y)
4484 translate_coordinates(win, top_level->rootwin, x, y, abs_x, abs_y);
4487 void BC_WindowBase::get_win_coordinates(int abs_x, int abs_y, int *x, int *y)
4489 translate_coordinates(top_level->rootwin, win, abs_x, abs_y, x, y);
4493 #ifdef HAVE_LIBXXF86VM
4494 void BC_WindowBase::closest_vm(int *vm, int *width, int *height)
4498 if(XF86VidModeQueryExtension(top_level->display,&foo,&bar)) {
4500 XF86VidModeModeInfo **vm_modelines;
4501 XF86VidModeGetAllModeLines(top_level->display,
4502 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4503 for( i = 0; i < vm_count; i++ ) {
4504 if( vm_modelines[i]->hdisplay < vm_modelines[*vm]->hdisplay &&
4505 vm_modelines[i]->hdisplay >= *width )
4508 display = top_level->display;
4509 if( vm_modelines[*vm]->hdisplay == *width )
4512 *width = vm_modelines[*vm]->hdisplay;
4513 *height = vm_modelines[*vm]->vdisplay;
4518 void BC_WindowBase::scale_vm(int vm)
4520 int foo,bar,dotclock;
4521 if( XF86VidModeQueryExtension(top_level->display,&foo,&bar) ) {
4523 XF86VidModeModeInfo **vm_modelines;
4524 XF86VidModeModeLine vml;
4525 XF86VidModeGetAllModeLines(top_level->display,
4526 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4527 XF86VidModeGetModeLine(top_level->display,
4528 XDefaultScreen(top_level->display), &dotclock,&vml);
4529 orig_modeline.dotclock = dotclock;
4530 orig_modeline.hdisplay = vml.hdisplay;
4531 orig_modeline.hsyncstart = vml.hsyncstart;
4532 orig_modeline.hsyncend = vml.hsyncend;
4533 orig_modeline.htotal = vml.htotal;
4534 orig_modeline.vdisplay = vml.vdisplay;
4535 orig_modeline.vsyncstart = vml.vsyncstart;
4536 orig_modeline.vsyncend = vml.vsyncend;
4537 orig_modeline.vtotal = vml.vtotal;
4538 orig_modeline.flags = vml.flags;
4539 orig_modeline.privsize = vml.privsize;
4540 // orig_modeline.private = vml.private;
4541 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),vm_modelines[vm]);
4542 XF86VidModeSetViewPort(top_level->display,XDefaultScreen(top_level->display),0,0);
4543 XFlush(top_level->display);
4547 void BC_WindowBase::restore_vm()
4549 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),&orig_modeline);
4550 XFlush(top_level->display);
4555 #ifndef SINGLE_THREAD
4556 int BC_WindowBase::get_event_count()
4558 event_lock->lock("BC_WindowBase::get_event_count");
4559 int result = common_events.total;
4560 event_lock->unlock();
4564 XEvent* BC_WindowBase::get_event()
4567 while(!done && !result)
4569 event_condition->lock("BC_WindowBase::get_event");
4570 event_lock->lock("BC_WindowBase::get_event");
4572 if(common_events.total && !done)
4574 result = common_events.values[0];
4575 common_events.remove_number(0);
4578 event_lock->unlock();
4583 void BC_WindowBase::put_event(XEvent *event)
4585 event_lock->lock("BC_WindowBase::put_event");
4586 common_events.append(event);
4587 event_lock->unlock();
4588 event_condition->unlock();
4591 void BC_WindowBase::dequeue_events(Window win)
4593 event_lock->lock("BC_WindowBase::dequeue_events");
4595 int out = 0, total = common_events.size();
4596 for( int in=0; in<total; ++in ) {
4597 if( common_events[in]->xany.window == win ) continue;
4598 common_events[out++] = common_events[in];
4600 common_events.total = out;
4602 event_lock->unlock();
4605 int BC_WindowBase::resend_event(BC_WindowBase *window)
4607 if( resend_event_window ) return 1;
4608 resend_event_window = window;
4614 int BC_WindowBase::resend_event(BC_WindowBase *window)
4619 #endif // SINGLE_THREAD
4621 int BC_WindowBase::get_id()
4627 BC_Pixmap *BC_WindowBase::create_pixmap(VFrame *vframe)
4629 int w = vframe->get_w(), h = vframe->get_h();
4630 BC_Pixmap *icon = new BC_Pixmap(this, w, h);
4631 icon->draw_vframe(vframe, 0,0, w,h, 0,0);
4636 void BC_WindowBase::flicker(int n, int ms)
4638 int color = get_bg_color();
4639 for( int i=2*n; --i>=0; ) {
4640 set_inverse(); set_bg_color(WHITE);
4641 clear_box(0,0, w,h); flash(1);
4642 sync_display(); Timer::delay(ms);
4644 set_bg_color(color);
4648 void BC_WindowBase::focus()
4650 XWindowAttributes xwa;
4651 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4652 if( xwa.map_state == IsViewable )
4653 XSetInputFocus(top_level->display, top_level->win, RevertToParent, CurrentTime);
4656 int BC_WindowBase::wait_viewable(int ms)
4659 XWindowAttributes xwa;
4661 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4662 if( xwa.map_state == IsViewable ) return 0;
4664 } while( timer.get_difference() < ms );