4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "bcclipboard.h"
24 #include "bcdisplay.h"
25 #include "bcdisplayinfo.h"
26 #include "bcmenubar.h"
29 #include "bcpopupmenu.h"
30 #include "bcrepeater.h"
31 #include "bcresources.h"
32 #include "bcsignals.h"
33 #include "bcsubwindow.h"
34 #include "bcsynchronous.h"
36 #include "bcwindowbase.h"
37 #include "bcwindowevents.h"
38 #include "bccmodels.h"
40 #include "condition.h"
49 #include "workarounds.h"
59 #include <X11/extensions/Xinerama.h>
61 #include <X11/extensions/Xvlib.h>
63 #include <X11/extensions/shape.h>
64 #include <X11/XF86keysym.h>
65 #include <X11/Sunkeysym.h>
67 BC_ResizeCall::BC_ResizeCall(int w, int h)
74 int BC_WindowBase::shm_completion_event = -1;
75 BC_Resources *BC_WindowBase::resources = 0;
76 Window XGroupLeader = 0;
78 Mutex BC_KeyboardHandlerLock::keyboard_listener_mutex("keyboard_listener",0);
79 ArrayList<BC_KeyboardHandler*> BC_KeyboardHandler::listeners;
81 BC_WindowBase::BC_WindowBase()
83 //printf("BC_WindowBase::BC_WindowBase 1\n");
84 BC_WindowBase::initialize();
87 BC_WindowBase::~BC_WindowBase()
90 BC_Display::lock_display("BC_WindowBase::~BC_WindowBase");
92 if(window_type == MAIN_WINDOW)
93 lock_window("BC_WindowBase::~BC_WindowBase");
96 #ifdef HAVE_LIBXXF86VM
97 if(window_type == VIDMODE_SCALED_WINDOW && vm_switched) {
104 if(window_type != MAIN_WINDOW)
107 XSelectInput(top_level->display, this->win, 0);
108 XSync(top_level->display,0);
109 #ifndef SINGLE_THREAD
110 top_level->dequeue_events(win);
112 // drop active window refs to this
113 if(top_level->active_menubar == this) top_level->active_menubar = 0;
114 if(top_level->active_popup_menu == this) top_level->active_popup_menu = 0;
115 if(top_level->active_subwindow == this) top_level->active_subwindow = 0;
116 // drop motion window refs to this
117 if(top_level->motion_events && top_level->last_motion_win == this->win)
118 top_level->motion_events = 0;
120 // Remove pointer from parent window to this
121 parent_window->subwindows->remove(this);
124 if(grab_active) grab_active->active_grab = 0;
125 if(icon_window) delete icon_window;
126 if(window_type == POPUP_WINDOW)
127 parent_window->remove_popup(this);
129 // Delete the subwindows
132 while(subwindows->total)
134 // Subwindow removes its own pointer
135 delete subwindows->values[0];
142 //printf("delete glx=%08x, win=%08x %s\n", (unsigned)glx_win, (unsigned)win, title);
144 if( get_resources()->get_synchronous() && glx_win != 0 ) {
145 if( window_type == MAIN_WINDOW )
147 get_resources()->get_synchronous()->delete_window(this);
148 if( window_type == MAIN_WINDOW )
149 lock_window("BC_WindowBase::delete_window");
152 XDestroyWindow(top_level->display, win);
154 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
155 if(icon_pixmap) delete icon_pixmap;
156 if(temp_bitmap) delete temp_bitmap;
157 top_level->active_bitmaps.remove_buffers(this);
158 if(_7segment_pixmaps)
160 for(int i = 0; i < TOTAL_7SEGMENT; i++)
161 delete _7segment_pixmaps[i];
163 delete [] _7segment_pixmaps;
168 if(window_type == MAIN_WINDOW)
170 XFreeGC(display, gc);
171 static XFontStruct *BC_WindowBase::*xfont[] = {
172 &BC_WindowBase::smallfont,
173 &BC_WindowBase::mediumfont,
174 &BC_WindowBase::largefont,
175 &BC_WindowBase::bigfont,
176 &BC_WindowBase::clockfont,
178 for( int i=sizeof(xfont)/sizeof(xfont[0]); --i>=0; )
179 XFreeFont(display, this->*xfont[i]);
182 // prevents a bug when Xft closes with unrefd fonts
183 FcPattern *defaults = FcPatternCreate();
184 FcPatternAddInteger(defaults, "maxunreffonts", 0);
185 XftDefaultSet(display, defaults);
187 static void *BC_WindowBase::*xft_font[] = {
188 &BC_WindowBase::smallfont_xft,
189 &BC_WindowBase::mediumfont_xft,
190 &BC_WindowBase::largefont_xft,
191 &BC_WindowBase::bigfont_xft,
192 &BC_WindowBase::bold_smallfont_xft,
193 &BC_WindowBase::bold_mediumfont_xft,
194 &BC_WindowBase::bold_largefont_xft,
195 &BC_WindowBase::clockfont_xft,
197 for( int i=sizeof(xft_font)/sizeof(xft_font[0]); --i>=0; ) {
198 XftFont *xft = (XftFont *)(this->*xft_font[i]);
199 if( xft ) xftFontClose (display, xft);
207 XFree(xinerama_info);
208 xinerama_screens = 0;
211 if( xvideo_port_id >= 0 )
212 XvUngrabPort(display, xvideo_port_id, CurrentTime);
215 // Must be last reference to display.
216 // _XftDisplayInfo needs a lock.
217 get_resources()->create_window_lock->lock("BC_WindowBase::~BC_WindowBase");
218 XCloseDisplay(display);
219 get_resources()->create_window_lock->unlock();
221 // clipboard uses a different display connection
222 clipboard->stop_clipboard();
226 resize_history.remove_all_objects();
229 #ifndef SINGLE_THREAD
230 common_events.remove_all_objects();
232 delete event_condition;
235 top_level->window_lock = 0;
236 BC_Display::unlock_display();
241 if( glx_fbcfgs_window ) XFree(glx_fbcfgs_window);
242 if( glx_fbcfgs_pbuffer) XFree(glx_fbcfgs_pbuffer);
243 if( glx_fbcfgs_pixmap ) XFree(glx_fbcfgs_pixmap);
246 UNSET_ALL_LOCKS(this)
249 int BC_WindowBase::initialize()
254 display_lock_owner = 0;
259 resend_event_window = 0;
271 xinerama_screens = 0;
276 translation_events = 0;
277 ctrl_mask = shift_mask = alt_mask = 0;
278 cursor_x = cursor_y = button_number = 0;
292 active_popup_menu = 0;
293 active_subwindow = 0;
297 _7segment_pixmaps = 0;
300 // next_repeat_id = 0;
302 current_font = MEDIUMFONT;
303 current_color = BLACK;
304 current_cursor = ARROW_CURSOR;
307 shared_bg_pixmap = 0;
310 window_type = MAIN_WINDOW;
311 translation_count = 0;
312 x_correction = y_correction = 0;
321 #ifdef HAVE_LIBXXF86VM
339 bold_smallfont_xft = 0;
340 bold_mediumfont_xft = 0;
341 bold_largefont_xft = 0;
343 completion_lock = new Condition(0, "BC_WindowBase::completion_lock");
345 // Need these right away since put_event is called before run_window sometimes.
346 event_lock = new Mutex("BC_WindowBase::event_lock");
347 event_condition = new Condition(0, "BC_WindowBase::event_condition");
348 init_lock = new Condition(0, "BC_WindowBase::init_lock");
350 grab_lock = new Mutex("BC_WindowBase::grab_lock");
352 cursor_timer = new Timer;
355 glx_fbcfgs_window = 0; n_fbcfgs_window = 0;
356 glx_fbcfgs_pbuffer = 0; n_fbcfgs_pbuffer = 0;
357 glx_fbcfgs_pixmap = 0; n_fbcfgs_pixmap = 0;
371 #define DEFAULT_EVENT_MASKS EnterWindowMask | \
374 ButtonReleaseMask | \
375 PointerMotionMask | \
379 int BC_WindowBase::create_window(BC_WindowBase *parent_window, const char *title,
380 int x, int y, int w, int h, int minw, int minh, int allow_resize,
381 int private_color, int hide, int bg_color, const char *display_name,
382 int window_type, BC_Pixmap *bg_pixmap, int group_it)
384 XSetWindowAttributes attr;
386 XSizeHints size_hints;
389 #ifdef HAVE_LIBXXF86VM
393 id = get_resources()->get_id();
394 if(parent_window) top_level = parent_window->top_level;
395 if( top_level ) lock_window("BC_WindowBase::create_window");
396 get_resources()->create_window_lock->lock("BC_WindowBase::create_window");
398 #ifdef HAVE_LIBXXF86VM
399 if(window_type == VIDMODE_SCALED_WINDOW)
400 closest_vm(&vm,&w,&h);
407 this->bg_color = bg_color;
408 this->window_type = window_type;
410 this->private_color = private_color;
411 this->parent_window = parent_window;
412 this->bg_pixmap = bg_pixmap;
413 this->allow_resize = allow_resize;
415 strcpy(this->display_name, display_name);
417 this->display_name[0] = 0;
420 if(bg_pixmap) shared_bg_pixmap = 1;
422 subwindows = new BC_SubWindowList;
424 if(window_type == MAIN_WINDOW)
427 parent_window = this;
431 display = BC_Display::get_display(display_name);
432 BC_Display::lock_display("BC_WindowBase::create_window");
433 // BC_Display::display_global->new_window(this);
436 // get the display connection
438 // This function must be the first Xlib
439 // function a multi-threaded program calls
441 display = init_display(display_name);
442 if( shm_completion_event < 0 ) shm_completion_event =
443 ShmCompletion + XShmGetEventBase(display);
445 lock_window("BC_WindowBase::create_window 1");
447 screen = DefaultScreen(display);
448 rootwin = RootWindow(display, screen);
449 // window placement boundaries
450 if( !xinerama_screens && XineramaIsActive(display) )
451 xinerama_info = XineramaQueryScreens(display, &xinerama_screens);
452 root_w = get_root_w(0);
453 root_h = get_root_h(0);
456 vis = get_glx_visual(display);
460 int mask = VisualDepthMask | VisualClassMask;
461 static XVisualInfo vinfo;
462 memset(&vinfo, 0, sizeof(vinfo));
464 vinfo.c_class = TrueColor;
466 XVisualInfo *vis_info = XGetVisualInfo(display, mask, &vinfo, &nitems);
467 vis = vis_info && nitems>0 ? vis_info[0].visual : 0;
468 if( vis_info ) XFree(vis_info);
471 vis = DefaultVisual(display, screen);
472 default_depth = DefaultDepth(display, screen);
474 client_byte_order = (*(const u_int32_t*)"a ") & 0x00000001;
475 server_byte_order = (XImageByteOrder(display) == MSBFirst) ? 0 : 1;
478 // This must be done before fonts to know if antialiasing is available.
481 if(resources->use_shm < 0) resources->initialize_display(this);
482 x_correction = BC_DisplayInfo::get_left_border();
483 y_correction = BC_DisplayInfo::get_top_border();
485 // clamp window placement
486 if(this->x + this->w + x_correction > root_w)
487 this->x = root_w - this->w - x_correction;
488 if(this->y + this->h + y_correction > root_h)
489 this->y = root_h - this->h - y_correction;
490 if(this->x < 0) this->x = 0;
491 if(this->y < 0) this->y = 0;
493 if(this->bg_color == -1)
494 this->bg_color = resources->get_bg_color();
496 // printf("bcwindowbase 1 %s\n", title);
497 // if(window_type == MAIN_WINDOW) sleep(1);
498 // printf("bcwindowbase 10\n");
504 mask = CWEventMask | CWBackPixel | CWColormap | CWCursor;
506 attr.event_mask = DEFAULT_EVENT_MASKS |
507 StructureNotifyMask |
511 attr.background_pixel = get_color(this->bg_color);
512 attr.colormap = cmap;
513 attr.cursor = get_cursor_struct(ARROW_CURSOR);
515 win = XCreateWindow(display, rootwin,
516 this->x, this->y, this->w, this->h, 0,
517 top_level->default_depth, InputOutput,
519 XGetNormalHints(display, win, &size_hints);
521 size_hints.flags = PSize | PMinSize | PMaxSize;
522 size_hints.width = this->w;
523 size_hints.height = this->h;
524 size_hints.min_width = allow_resize ? minw : this->w;
525 size_hints.max_width = allow_resize ? 32767 : this->w;
526 size_hints.min_height = allow_resize ? minh : this->h;
527 size_hints.max_height = allow_resize ? 32767 : this->h;
528 if(x > -BC_INFINITY && x < BC_INFINITY)
530 size_hints.flags |= PPosition;
531 size_hints.x = this->x;
532 size_hints.y = this->y;
534 XSetWMProperties(display, win, 0, 0, 0, 0, &size_hints, 0, 0);
537 #ifndef SINGLE_THREAD
538 clipboard = new BC_Clipboard(this);
539 clipboard->start_clipboard();
545 Atom ClientLeaderXAtom;
546 if (XGroupLeader == 0)
548 const char *instance_name = "cinelerra";
549 const char *class_name = "Cinelerra";
550 XClassHint *class_hints = XAllocClassHint();
551 class_hints->res_name = (char*)instance_name;
552 class_hints->res_class = (char*)class_name;
553 XSetClassHint(top_level->display, win, class_hints);
555 ClientLeaderXAtom = XInternAtom(display, "WM_CLIENT_LEADER", True);
556 XChangeProperty(display, win, ClientLeaderXAtom, XA_WINDOW, 32,
557 PropModeReplace, (unsigned char *)&XGroupLeader, true);
560 set_icon(get_resources()->default_icon);
563 #ifdef HAVE_LIBXXF86VM
564 if(window_type == VIDMODE_SCALED_WINDOW && vm != -1)
571 #ifdef HAVE_LIBXXF86VM
572 if(window_type == POPUP_WINDOW || window_type == VIDMODE_SCALED_WINDOW)
574 if(window_type == POPUP_WINDOW)
577 mask = CWEventMask | CWBackPixel | CWColormap |
578 CWOverrideRedirect | CWSaveUnder | CWCursor;
580 attr.event_mask = DEFAULT_EVENT_MASKS | ExposureMask |
581 KeyPressMask | KeyReleaseMask;
583 if(this->bg_color == -1)
584 this->bg_color = resources->get_bg_color();
585 attr.background_pixel = top_level->get_color(bg_color);
586 attr.colormap = top_level->cmap;
587 if(top_level->is_hourglass)
588 attr.cursor = top_level->get_cursor_struct(HOURGLASS_CURSOR);
590 attr.cursor = top_level->get_cursor_struct(ARROW_CURSOR);
591 attr.override_redirect = True;
592 attr.save_under = True;
594 win = XCreateWindow(top_level->display,
595 top_level->rootwin, this->x, this->y, this->w, this->h, 0,
596 top_level->default_depth, InputOutput, top_level->vis, mask,
598 top_level->add_popup(this);
601 if(window_type == SUB_WINDOW)
603 mask = CWEventMask | CWBackPixel | CWCursor;
604 attr.event_mask = DEFAULT_EVENT_MASKS;
605 attr.background_pixel = top_level->get_color(this->bg_color);
606 if(top_level->is_hourglass)
607 attr.cursor = top_level->get_cursor_struct(HOURGLASS_CURSOR);
609 attr.cursor = top_level->get_cursor_struct(ARROW_CURSOR);
610 win = XCreateWindow(top_level->display,
611 parent_window->win, this->x, this->y, this->w, this->h, 0,
612 top_level->default_depth, InputOutput, top_level->vis, mask,
615 if(!hidden) XMapWindow(top_level->display, win);
618 // Create pixmap for all windows
619 pixmap = new BC_Pixmap(this, this->w, this->h);
621 // Set up options for main window
622 if(window_type == MAIN_WINDOW)
624 if(get_resources()->bg_image && !bg_pixmap && bg_color < 0)
626 this->bg_pixmap = new BC_Pixmap(this,
627 get_resources()->bg_image,
631 if(!hidden) show_window();
635 draw_background(0, 0, this->w, this->h);
637 flash(-1, -1, -1, -1, 0);
639 // Set up options for popup window
640 #ifdef HAVE_LIBXXF86VM
641 if(window_type == POPUP_WINDOW || window_type == VIDMODE_SCALED_WINDOW)
643 if(window_type == POPUP_WINDOW)
647 if(!hidden) show_window();
649 get_resources()->create_window_lock->unlock();
655 Display* BC_WindowBase::init_display(const char *display_name)
659 if(display_name && display_name[0] == 0) display_name = NULL;
660 if((display = XOpenDisplay(display_name)) == NULL) {
661 printf("BC_WindowBase::init_display: cannot connect to X server %s\n",
663 if(getenv("DISPLAY") == NULL) {
664 printf(_("'DISPLAY' environment variable not set.\n"));
667 // Try again with default display.
668 if((display = XOpenDisplay(0)) == NULL) {
669 printf("BC_WindowBase::init_display: cannot connect to default X server.\n");
674 static int xsynch = -1;
676 const char *cp = getenv("CIN_XSYNCH");
677 xsynch = !cp ? 0 : atoi(cp);
680 XSynchronize(display, True);
685 Display* BC_WindowBase::get_display()
687 return top_level->display;
690 int BC_WindowBase::get_screen()
692 return top_level->screen;
695 int BC_WindowBase::run_window()
701 // Events may have been sent before run_window so can't initialize them here.
704 set_repeat(get_resources()->tooltip_delay);
705 BC_Display::display_global->new_window(this);
707 // If the first window created, run the display loop in this thread.
708 if(BC_Display::display_global->is_first(this))
710 BC_Display::unlock_display();
711 BC_Display::display_global->loop();
715 BC_Display::unlock_display();
716 completion_lock->lock("BC_WindowBase::run_window");
719 BC_Display::lock_display("BC_WindowBase::run_window");
720 BC_Display::display_global->delete_window(this);
722 unset_all_repeaters();
724 BC_Display::unlock_display();
726 #else // SINGLE_THREAD
731 set_repeat(get_resources()->tooltip_delay);
733 // Start X server events
734 event_thread = new BC_WindowEvents(this);
735 event_thread->start();
741 // Handle common events
746 unset_all_repeaters();
750 event_condition->reset();
751 common_events.remove_all_objects();
755 #endif // SINGLE_THREAD
760 int BC_WindowBase::get_key_masks(unsigned int key_state)
762 // printf("BC_WindowBase::get_key_masks %llx\n",
763 // event->xkey.state);
764 ctrl_mask = (key_state & ControlMask) ? 1 : 0; // ctrl key down
765 shift_mask = (key_state & ShiftMask) ? 1 : 0; // shift key down
766 alt_mask = (key_state & Mod1Mask) ? 1 : 0; // alt key down
771 void BC_WindowBase::add_keyboard_listener(int(BC_WindowBase::*handler)(BC_WindowBase *))
773 BC_KeyboardHandlerLock set;
774 BC_KeyboardHandler::listeners.append(new BC_KeyboardHandler(handler, this));
777 void BC_WindowBase::del_keyboard_listener(int(BC_WindowBase::*handler)(BC_WindowBase *))
779 BC_KeyboardHandlerLock set;
780 int i = BC_KeyboardHandler::listeners.size();
781 while( --i >= 0 && BC_KeyboardHandler::listeners[i]->handler!=handler );
782 if( i >= 0 ) BC_KeyboardHandler::listeners.remove_object_number(i);
785 int BC_KeyboardHandler::run_event(BC_WindowBase *wp)
787 int result = (win->*handler)(wp);
791 int BC_KeyboardHandler::run_listeners(BC_WindowBase *wp)
794 BC_KeyboardHandlerLock set;
795 for( int i=0; !result && i<listeners.size(); ++i ) {
796 BC_KeyboardHandler *listener = listeners[i];
797 result = listener->run_event(wp);
802 void BC_KeyboardHandler::kill_grabs()
804 BC_KeyboardHandlerLock set;
805 for( int i=0; i<listeners.size(); ++i ) {
806 BC_WindowBase *win = listeners[i]->win;
807 if( win->get_window_type() != POPUP_WINDOW ) continue;
808 ((BC_Popup *)win)->ungrab_keyboard();
812 void BC_ActiveBitmaps::reque(XEvent *event)
814 XShmCompletionEvent *shm_ev = (XShmCompletionEvent *)event;
815 ShmSeg shmseg = shm_ev->shmseg;
816 Drawable drawable = shm_ev->drawable;
817 //printf("BC_BitmapImage::reque %08lx\n",shmseg);
818 active_lock.lock("BC_BitmapImage::reque");
819 BC_BitmapImage *bfr = first;
820 while( bfr && bfr->get_shmseg() != shmseg ) bfr = bfr->next;
821 if( bfr && bfr->drawable == drawable )
823 active_lock.unlock();
825 // sadly, X reports two drawable completions and creates false reporting, so no boobytrap
826 // printf("BC_BitmapImage::reque missed shmseg %08x, drawable %08x\n",
827 // (int)shmseg, (int)drawable);
830 if( bfr->drawable != drawable ) return;
831 if( bfr->is_zombie() ) { --BC_Bitmap::zombies; delete bfr; return; }
832 bfr->bitmap->reque(bfr);
835 void BC_ActiveBitmaps::insert(BC_BitmapImage *bfr, Drawable pixmap)
837 active_lock.lock("BC_BitmapImage::insert");
838 bfr->drawable = pixmap;
840 active_lock.unlock();
843 void BC_ActiveBitmaps::remove_buffers(BC_WindowBase *wdw)
845 active_lock.lock("BC_ActiveBitmaps::remove");
846 for( BC_BitmapImage *nxt=0, *bfr=first; bfr; bfr=nxt ) {
848 if( bfr->is_zombie() ) { --BC_Bitmap::zombies; delete bfr; continue; }
849 if( bfr->bitmap->parent_window == wdw ) remove_pointer(bfr);
851 active_lock.unlock();
854 BC_ActiveBitmaps::BC_ActiveBitmaps()
858 BC_ActiveBitmaps::~BC_ActiveBitmaps()
864 int BC_WindowBase::keysym_lookup(XEvent *event)
866 for( int i = 0; i < KEYPRESSLEN; ++i ) keys_return[i] = 0;
867 for( int i = 0; i < 4; ++i ) wkey_string[i] = 0;
869 if( event->xany.send_event && !event->xany.serial ) {
870 keysym = (KeySym) event->xkey.keycode;
871 keys_return[0] = keysym;
874 wkey_string_length = 0;
876 if( input_context ) {
878 wkey_string_length = XwcLookupString(input_context,
879 (XKeyEvent*)event, wkey, 4, &keysym, 0);
880 for( int i=0; i<wkey_string_length; ++i )
881 wkey_string[i] = wkey[i];
882 //printf("keysym_lookup 1 %d %d %lx %x %x %x %x\n", wkey_string_length, keysym,
883 // wkey_string[0], wkey_string[1], wkey_string[2], wkey_string[3]);
886 int ret = Xutf8LookupString(input_context, (XKeyEvent*)event,
887 keys_return, KEYPRESSLEN, &keysym, &stat);
888 //printf("keysym_lookup 2 %d %d %lx %x %x\n", ret, stat, keysym, keys_return[0], keys_return[1]);
889 if( stat == XLookupBoth ) return ret;
890 if( stat == XLookupKeySym ) return 0;
892 int ret = XLookupString((XKeyEvent*)event, keys_return, KEYPRESSLEN, &keysym, 0);
893 wkey_string_length = ret;
894 for( int i=0; i<ret; ++i ) wkey_string[i] = keys_return[i];
898 pthread_t locking_task = (pthread_t)-1L;
899 int locking_event = -1;
900 int locking_message = -1;
902 int BC_WindowBase::dispatch_event()
906 XClientMessageEvent *ptr;
907 int cancel_resize, cancel_translation;
908 volatile static int debug = 0;
913 #ifndef SINGLE_THREAD
914 // If an event is waiting get it, otherwise
915 // wait for next event only if there are no compressed events.
916 if(get_event_count() ||
917 (!motion_events && !resize_events && !translation_events))
920 // Lock out window deletions
921 lock_window("BC_WindowBase::dispatch_event 1");
922 locking_event = event->type;
923 locking_task = pthread_self();
924 locking_message = event->xclient.message_type;
927 // Handle compressed events
929 lock_window("BC_WindowBase::dispatch_event 2");
931 dispatch_resize_event(last_resize_w, last_resize_h);
933 dispatch_motion_event();
934 if(translation_events)
935 dispatch_translation_event();
946 if( debug && event->type != ClientMessage ) {
947 static const char *event_names[] = {
948 "Reply", "Error", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease", "MotionNotify",
949 "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut", "KeymapNotify", "Expose", "GraphicsExpose",
950 "NoExpose", "VisibilityNotify", "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify",
951 "MapRequest", "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
952 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear",
953 "SelectionRequest", "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify",
954 "GenericEvent", "LASTEvent",
956 const int nevents = sizeof(event_names)/sizeof(event_names[0]);
958 printf("BC_WindowBase::dispatch_event %d %s %p %d (%s)\n", __LINE__,
959 title, event, event->type, event->type>=0 && event->type<nevents ?
960 event_names[event->type] : "Unknown");
964 grab_lock->lock("BC_WindowBase::dispatch_event 3");
968 active_grab->lock_window("BC_WindowBase::dispatch_event 3");
969 result = active_grab->grab_event(event);
970 active_grab->unlock_window();
973 if( result ) return result;
974 lock_window("BC_WindowBase::dispatch_event 4");
977 switch(event->type) {
979 // Clear the resize buffer
981 dispatch_resize_event(last_resize_w, last_resize_h);
982 // Clear the motion buffer since this can clear the window
984 dispatch_motion_event();
986 ptr = (XClientMessageEvent*)event;
987 if( ptr->message_type == ProtoXAtom &&
988 (Atom)ptr->data.l[0] == DelWinXAtom ) {
991 else if( ptr->message_type == RepeaterXAtom ) {
992 dispatch_repeat_event(ptr->data.l[0]);
994 else if( ptr->message_type == SetDoneXAtom ) {
998 receive_custom_xatoms((xatom_event *)ptr);
1004 dispatch_focus_in();
1009 dispatch_focus_out();
1023 dispatch_motion_event();
1025 get_key_masks(event->xbutton.state);
1026 cursor_x = event->xbutton.x;
1027 cursor_y = event->xbutton.y;
1028 button_number = event->xbutton.button;
1030 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1031 event_win = event->xany.window;
1032 if( button_number < 6 ) {
1033 if( button_number < 4 )
1035 button_pressed = event->xbutton.button;
1036 button_time1 = button_time2;
1037 button_time2 = button_time3;
1038 button_time3 = event->xbutton.time;
1041 drag_win = event_win;
1042 drag_x1 = cursor_x - get_resources()->drag_radius;
1043 drag_x2 = cursor_x + get_resources()->drag_radius;
1044 drag_y1 = cursor_y - get_resources()->drag_radius;
1045 drag_y2 = cursor_y + get_resources()->drag_radius;
1046 if( button_number < 4 ) {
1047 if((long)(button_time3 - button_time1) < resources->double_click * 2) {
1049 button_time3 = button_time2 = button_time1 = 0;
1051 if((long)(button_time3 - button_time2) < resources->double_click) {
1053 // button_time3 = button_time2 = button_time1 = 0;
1060 dispatch_button_press();
1067 dispatch_motion_event();
1069 get_key_masks(event->xbutton.state);
1070 button_number = event->xbutton.button;
1071 event_win = event->xany.window;
1072 if (button_number < 6)
1074 if(button_number < 4)
1076 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1078 dispatch_button_release();
1083 event_win = event->xany.window;
1085 for( int i=0; !result && i<popups.size(); ++i ) { // popups take focus
1086 if( popups[i]->win == event_win )
1087 result = popups[i]->dispatch_expose_event();
1090 result = dispatch_expose_event();
1094 get_key_masks(event->xmotion.state);
1095 // Dispatch previous motion event if this is a subsequent motion from a different window
1096 if(motion_events && last_motion_win != event->xany.window)
1098 dispatch_motion_event();
1101 // Buffer the current motion
1103 last_motion_state = event->xmotion.state;
1104 last_motion_x = event->xmotion.x;
1105 last_motion_y = event->xmotion.y;
1106 last_motion_win = event->xany.window;
1109 case ConfigureNotify:
1110 // printf("BC_WindowBase::dispatch_event %d win=%p this->win=%p\n",
1112 // event->xany.window,
1115 XTranslateCoordinates(top_level->display,
1123 last_resize_w = event->xconfigure.width;
1124 last_resize_h = event->xconfigure.height;
1127 cancel_translation = 0;
1129 // Resize history prevents responses to recursive resize requests
1130 for(int i = 0; i < resize_history.total && !cancel_resize; i++)
1132 if(resize_history.values[i]->w == last_resize_w &&
1133 resize_history.values[i]->h == last_resize_h)
1135 delete resize_history.values[i];
1136 resize_history.remove_number(i);
1141 if(last_resize_w == w && last_resize_h == h)
1149 if((last_translate_x == x && last_translate_y == y))
1150 cancel_translation = 1;
1152 if(!cancel_translation)
1154 translation_events = 1;
1157 translation_count++;
1161 get_key_masks(event->xkey.state);
1162 keys_return[0] = 0; keysym = -1;
1163 if(XFilterEvent(event, win)) {
1166 if( keysym_lookup(event) < 0 ) {
1167 printf("keysym %x\n", (uint32_t)keysym);
1171 //printf("BC_WindowBase::dispatch_event %d keysym=0x%x\n",
1175 // block out control keys
1176 if(keysym > 0xffe0 && keysym < 0xffff) break;
1177 // block out Alt_GR key
1178 if(keysym == 0xfe03) break;
1181 printf("BC_WindowBase::dispatch_event %x\n", (uint32_t)keysym);
1183 #ifdef X_HAVE_UTF8_STRING
1184 //It's Ascii or UTF8?
1185 // if (keysym != 0xffff && (keys_return[0] & 0xff) >= 0x7f )
1186 //printf("BC_WindowBase::dispatch_event %d %02x%02x\n", __LINE__, keys_return[0], keys_return[1]);
1188 if( ((keys_return[1] & 0xff) > 0x80) &&
1189 ((keys_return[0] & 0xff) > 0xC0) ) {
1190 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1191 key_pressed = keysym & 0xff;
1195 // shuttle speed codes
1196 if( keysym >= SKEY_MIN && keysym <= SKEY_MAX ) {
1197 key_pressed = keysym;
1199 else switch( keysym ) {
1200 // block out extra keys
1210 // Translate key codes
1211 case XK_Return: key_pressed = RETURN; break;
1212 case XK_Up: key_pressed = UP; break;
1213 case XK_Down: key_pressed = DOWN; break;
1214 case XK_Left: key_pressed = LEFT; break;
1215 case XK_Right: key_pressed = RIGHT; break;
1216 case XK_Next: key_pressed = PGDN; break;
1217 case XK_Prior: key_pressed = PGUP; break;
1218 case XK_BackSpace: key_pressed = BACKSPACE; break;
1219 case XK_Escape: key_pressed = ESC; break;
1222 key_pressed = LEFTTAB;
1226 case XK_ISO_Left_Tab: key_pressed = LEFTTAB; break;
1227 case XK_underscore: key_pressed = '_'; break;
1228 case XK_asciitilde: key_pressed = '~'; break;
1229 case XK_Delete: key_pressed = DELETE; break;
1230 case XK_Home: key_pressed = HOME; break;
1231 case XK_End: key_pressed = END; break;
1234 case XK_KP_Enter: key_pressed = KPENTER; break;
1235 case XK_KP_Add: key_pressed = KPPLUS; break;
1236 case XK_KP_Subtract: key_pressed = KPMINUS; break;
1237 case XK_KP_Multiply: key_pressed = KPSTAR; break;
1238 case XK_KP_Divide: key_pressed = KPSLASH; break;
1240 case XK_KP_End: key_pressed = KP1; break;
1242 case XK_KP_Down: key_pressed = KP2; break;
1244 case XK_KP_Page_Down: key_pressed = KP3; break;
1246 case XK_KP_Left: key_pressed = KP4; break;
1248 case XK_KP_Begin: key_pressed = KP5; break;
1250 case XK_KP_Right: key_pressed = KP6; break;
1252 case XK_KP_Home: key_pressed = KP7; break;
1254 case XK_KP_Up: key_pressed = KP8; break;
1256 case XK_KP_Page_Up: key_pressed = KP9; break;
1258 case XK_KP_Insert: key_pressed = KPINS; break;
1260 case XK_KP_Delete: key_pressed = KPDEL; break;
1262 case XK_F1: key_pressed = KEY_F1; break;
1263 case XK_F2: key_pressed = KEY_F2; break;
1264 case XK_F3: key_pressed = KEY_F3; break;
1265 case XK_F4: key_pressed = KEY_F4; break;
1266 case XK_F5: key_pressed = KEY_F5; break;
1267 case XK_F6: key_pressed = KEY_F6; break;
1268 case XK_F7: key_pressed = KEY_F7; break;
1269 case XK_F8: key_pressed = KEY_F8; break;
1270 case XK_F9: key_pressed = KEY_F9; break;
1271 case XK_F10: key_pressed = KEY_F10; break;
1272 case XK_F11: key_pressed = KEY_F11; break;
1273 case XK_F12: key_pressed = KEY_F12; break;
1275 case XK_Menu: key_pressed = KPMENU; break; /* menu */
1278 key_pressed = keysym & 0xff;
1279 #ifdef X_HAVE_UTF8_STRING
1280 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1285 #ifdef X_HAVE_UTF8_STRING
1287 key_pressed_utf8 = keys_return;
1292 if( top_level == this )
1293 result = BC_KeyboardHandler::run_listeners(this);
1295 //printf("BC_WindowBase::dispatch_event %d %d %x\n", shift_down(), alt_down(), key_pressed);
1297 result = dispatch_keypress_event();
1298 // Handle some default keypresses
1301 if(key_pressed == 'w' ||
1310 XLookupString((XKeyEvent*)event, keys_return, 1, &keysym, 0);
1311 dispatch_keyrelease_event();
1312 // printf("BC_WindowBase::dispatch_event KeyRelease keysym=0x%x keystate=0x%lld\n",
1313 // keysym, event->xkey.state);
1317 if( event->xcrossing.mode != NotifyNormal ) break;
1319 event_win = event->xany.window;
1320 dispatch_cursor_leave();
1324 if( event->xcrossing.mode != NotifyNormal ) break;
1326 if( !cursor_entered ) {
1327 for( int i=0; i<popups.size(); ++i ) { // popups always take focus
1328 if( popups[i]->win == event->xcrossing.window )
1331 if( !cursor_entered && get_resources()->grab_input_focus &&
1332 !event->xcrossing.focus && event->xcrossing.window == win ) {
1335 if( cursor_entered )
1338 event_win = event->xany.window;
1339 cursor_x = event->xcrossing.x;
1340 cursor_y = event->xcrossing.y;
1341 dispatch_cursor_enter();
1347 //printf("100 %s %p %d\n", title, event, event->type);
1348 //if(event->type != ClientMessage) dump();
1350 #ifndef SINGLE_THREAD
1353 if( resend_event_window ) {
1354 resend_event_window->put_event(event);
1355 resend_event_window = 0;
1361 // if(done) completion_lock->unlock();
1364 if(debug) printf("BC_WindowBase::dispatch_event this=%p %d\n", this, __LINE__);
1368 int BC_WindowBase::dispatch_expose_event()
1371 for(int i = 0; i < subwindows->total && !result; i++)
1373 result = subwindows->values[i]->dispatch_expose_event();
1376 // Propagate to user
1377 if(!result) expose_event();
1381 int BC_WindowBase::dispatch_resize_event(int w, int h)
1383 // Can't store new w and h until the event is handles
1384 // because bcfilebox depends on the old w and h to
1385 // reposition widgets.
1386 if( window_type == MAIN_WINDOW ) {
1391 pixmap = new BC_Pixmap(this, w, h);
1392 clear_box(0, 0, w, h);
1395 // Propagate to subwindows
1396 for(int i = 0; i < subwindows->total; i++) {
1397 subwindows->values[i]->dispatch_resize_event(w, h);
1400 // Propagate to user
1403 if( window_type == MAIN_WINDOW ) {
1412 int BC_WindowBase::dispatch_flash()
1415 for(int i = 0; i < subwindows->total; i++)
1416 subwindows->values[i]->dispatch_flash();
1420 int BC_WindowBase::dispatch_translation_event()
1422 translation_events = 0;
1423 if(window_type == MAIN_WINDOW)
1427 x = last_translate_x;
1428 y = last_translate_y;
1429 // Correct for window manager offsets
1434 for(int i = 0; i < subwindows->total; i++)
1436 subwindows->values[i]->dispatch_translation_event();
1439 translation_event();
1443 int BC_WindowBase::dispatch_motion_event()
1448 if(top_level == this)
1451 event_win = last_motion_win;
1452 get_key_masks(last_motion_state);
1455 if(get_button_down() && !active_menubar && !active_popup_menu)
1459 cursor_x = last_motion_x;
1460 cursor_y = last_motion_y;
1461 result = dispatch_drag_motion();
1465 (last_motion_x < drag_x1 || last_motion_x >= drag_x2 ||
1466 last_motion_y < drag_y1 || last_motion_y >= drag_y2))
1471 result = dispatch_drag_start();
1475 cursor_x = last_motion_x;
1476 cursor_y = last_motion_y;
1478 // printf("BC_WindowBase::dispatch_motion_event %d %p %p %p\n",
1481 // active_popup_menu,
1482 // active_subwindow);
1484 if(active_menubar && !result) result = active_menubar->dispatch_motion_event();
1485 if(active_popup_menu && !result) result = active_popup_menu->dispatch_motion_event();
1486 if(active_subwindow && !result) result = active_subwindow->dispatch_motion_event();
1489 // Dispatch in stacking order
1490 for(int i = subwindows->size() - 1; i >= 0 && !result; i--)
1492 result = subwindows->values[i]->dispatch_motion_event();
1495 if(!result) result = cursor_motion_event(); // give to user
1499 int BC_WindowBase::dispatch_keypress_event()
1502 if(top_level == this)
1504 if(active_subwindow) result = active_subwindow->dispatch_keypress_event();
1507 for(int i = 0; i < subwindows->total && !result; i++)
1509 result = subwindows->values[i]->dispatch_keypress_event();
1512 if(!result) result = keypress_event();
1517 int BC_WindowBase::dispatch_keyrelease_event()
1520 if(top_level == this)
1522 if(active_subwindow) result = active_subwindow->dispatch_keyrelease_event();
1525 for(int i = 0; i < subwindows->total && !result; i++)
1527 result = subwindows->values[i]->dispatch_keyrelease_event();
1530 if(!result) result = keyrelease_event();
1535 int BC_WindowBase::dispatch_focus_in()
1537 for(int i = 0; i < subwindows->total; i++)
1539 subwindows->values[i]->dispatch_focus_in();
1547 int BC_WindowBase::dispatch_focus_out()
1549 for(int i = 0; i < subwindows->total; i++)
1551 subwindows->values[i]->dispatch_focus_out();
1559 int BC_WindowBase::get_has_focus()
1561 return top_level->has_focus;
1564 int BC_WindowBase::get_deleting()
1566 if(is_deleting) return 1;
1567 if(parent_window && parent_window->get_deleting()) return 1;
1571 int BC_WindowBase::dispatch_button_press()
1576 if(top_level == this)
1578 if(active_menubar) result = active_menubar->dispatch_button_press();
1579 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_press();
1580 if(active_subwindow && !result) result = active_subwindow->dispatch_button_press();
1583 for(int i = 0; i < subwindows->total && !result; i++)
1585 result = subwindows->values[i]->dispatch_button_press();
1588 if(!result) result = button_press_event();
1594 int BC_WindowBase::dispatch_button_release()
1597 if(top_level == this)
1599 if(active_menubar) result = active_menubar->dispatch_button_release();
1600 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_release();
1601 if(active_subwindow && !result) result = active_subwindow->dispatch_button_release();
1602 if(!result && button_number != 4 && button_number != 5)
1603 result = dispatch_drag_stop();
1606 for(int i = 0; i < subwindows->total && !result; i++)
1608 result = subwindows->values[i]->dispatch_button_release();
1613 result = button_release_event();
1620 int BC_WindowBase::dispatch_repeat_event(int64_t duration)
1623 // all repeat event handlers get called and decide based on activity and duration
1624 // whether to respond
1625 for(int i = 0; i < subwindows->total; i++)
1627 subwindows->values[i]->dispatch_repeat_event(duration);
1631 repeat_event(duration);
1635 // Unlock next repeat signal
1636 if(window_type == MAIN_WINDOW)
1638 #ifdef SINGLE_THREAD
1639 BC_Display::display_global->unlock_repeaters(duration);
1641 for(int i = 0; i < repeaters.total; i++)
1643 if(repeaters.values[i]->delay == duration)
1645 repeaters.values[i]->repeat_lock->unlock();
1653 void BC_WindowBase::unhide_cursor()
1658 if(top_level->is_hourglass)
1659 set_cursor(HOURGLASS_CURSOR, 1, 0);
1661 set_cursor(current_cursor, 1, 0);
1663 cursor_timer->update();
1667 void BC_WindowBase::update_video_cursor()
1669 if(video_on && !is_transparent)
1671 if(cursor_timer->get_difference() > VIDEO_CURSOR_TIMEOUT && !is_transparent)
1674 set_cursor(TRANSPARENT_CURSOR, 1, 1);
1675 cursor_timer->update();
1680 cursor_timer->update();
1685 int BC_WindowBase::dispatch_cursor_leave()
1689 for(int i = 0; i < subwindows->total; i++)
1691 subwindows->values[i]->dispatch_cursor_leave();
1694 cursor_leave_event();
1698 int BC_WindowBase::dispatch_cursor_enter()
1704 if(active_menubar) result = active_menubar->dispatch_cursor_enter();
1705 if(!result && active_popup_menu) result = active_popup_menu->dispatch_cursor_enter();
1706 if(!result && active_subwindow) result = active_subwindow->dispatch_cursor_enter();
1708 for(int i = 0; !result && i < subwindows->total; i++)
1710 result = subwindows->values[i]->dispatch_cursor_enter();
1713 if(!result) result = cursor_enter_event();
1717 int BC_WindowBase::cursor_enter_event()
1722 int BC_WindowBase::cursor_leave_event()
1727 int BC_WindowBase::close_event()
1733 int BC_WindowBase::dispatch_drag_start()
1736 if(active_menubar) result = active_menubar->dispatch_drag_start();
1737 if(!result && active_popup_menu) result = active_popup_menu->dispatch_drag_start();
1738 if(!result && active_subwindow) result = active_subwindow->dispatch_drag_start();
1740 for(int i = 0; i < subwindows->total && !result; i++)
1742 result = subwindows->values[i]->dispatch_drag_start();
1745 if(!result) result = is_dragging = drag_start_event();
1749 int BC_WindowBase::dispatch_drag_stop()
1753 for(int i = 0; i < subwindows->total && !result; i++)
1755 result = subwindows->values[i]->dispatch_drag_stop();
1758 if(is_dragging && !result)
1768 int BC_WindowBase::dispatch_drag_motion()
1771 for(int i = 0; i < subwindows->total && !result; i++)
1773 result = subwindows->values[i]->dispatch_drag_motion();
1776 if(is_dragging && !result)
1778 drag_motion_event();
1786 int BC_WindowBase::show_tooltip(const char *text, int x, int y, int w, int h)
1789 int forced = !text ? force_tooltip : 1;
1790 if( !text ) text = tooltip_text;
1791 if( !text || (!forced && !get_resources()->tooltips_enabled) ) {
1792 top_level->hide_tooltip();
1796 if(w < 0) w = get_text_width(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1797 if(h < 0) h = get_text_height(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1798 // default x,y (win relative)
1799 if( x < 0 ) x = get_w();
1800 if( y < 0 ) y = get_h();
1802 get_root_coordinates(x, y, &wx, &wy);
1803 // keep the tip inside the window/display
1804 int x0 = top_level->get_x(), x1 = x0 + top_level->get_w();
1805 int x2 = top_level->get_screen_x(0, -1) + top_level->get_screen_w(0, -1);
1806 if( x1 > x2 ) x1 = x2;
1807 if( wx < x0 ) wx = x0;
1808 if( wx >= (x1-=w) ) wx = x1;
1809 int y0 = top_level->get_y(), y1 = y0 + top_level->get_h();
1810 int y2 = top_level->get_root_h(0);
1811 if( y1 > y2 ) y1 = y2;
1812 if( wy < y0 ) wy = y0;
1813 if( wy >= (y1-=h) ) wy = y1;
1814 // avoid tip under cursor (flickers)
1816 get_abs_cursor(abs_x,abs_y, 0);
1817 if( wx < abs_x && abs_x < wx+w && wy < abs_y && abs_y < wy+h ) {
1818 if( wx-abs_x < wy-abs_y )
1825 tooltip_popup = new BC_Popup(top_level, wx, wy, w, h,
1826 get_resources()->tooltip_bg_color);
1829 tooltip_popup->reposition_window(wx, wy, w, h);
1832 tooltip_popup->flash();
1833 tooltip_popup->flush();
1837 int BC_WindowBase::hide_tooltip()
1840 for(int i = 0; i < subwindows->total; i++)
1842 subwindows->values[i]->hide_tooltip();
1848 delete tooltip_popup;
1854 const char *BC_WindowBase::get_tooltip()
1856 return tooltip_text;
1859 int BC_WindowBase::set_tooltip(const char *text)
1861 tooltip_text = text;
1863 // Update existing tooltip if it is visible
1867 tooltip_popup->flash();
1871 // signal the event handler to repeat
1872 int BC_WindowBase::set_repeat(int64_t duration)
1876 printf("BC_WindowBase::set_repeat duration=%jd\n", duration);
1879 if(window_type != MAIN_WINDOW) return top_level->set_repeat(duration);
1881 #ifdef SINGLE_THREAD
1882 BC_Display::display_global->set_repeat(this, duration);
1884 // test repeater database for duplicates
1885 for(int i = 0; i < repeaters.total; i++)
1888 if(repeaters.values[i]->delay == duration)
1890 repeaters.values[i]->start_repeating(this);
1895 BC_Repeater *repeater = new BC_Repeater(this, duration);
1896 repeater->initialize();
1897 repeaters.append(repeater);
1898 repeater->start_repeating();
1903 int BC_WindowBase::unset_repeat(int64_t duration)
1905 if(window_type != MAIN_WINDOW) return top_level->unset_repeat(duration);
1907 #ifdef SINGLE_THREAD
1908 BC_Display::display_global->unset_repeat(this, duration);
1910 for(int i = 0; i < repeaters.total; i++)
1912 if(repeaters.values[i]->delay == duration)
1914 repeaters.values[i]->stop_repeating();
1922 int BC_WindowBase::unset_all_repeaters()
1924 #ifdef SINGLE_THREAD
1925 BC_Display::display_global->unset_all_repeaters(this);
1927 for(int i = 0; i < repeaters.total; i++)
1929 repeaters.values[i]->stop_repeating();
1931 repeaters.remove_all_objects();
1936 // long BC_WindowBase::get_repeat_id()
1938 // return top_level->next_repeat_id++;
1941 XEvent *BC_WindowBase::new_xevent()
1943 XEvent *event = new XEvent;
1944 memset(event, 0, sizeof(*event));
1948 #ifndef SINGLE_THREAD
1949 int BC_WindowBase::arm_repeat(int64_t duration)
1951 XEvent *event = new_xevent();
1952 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
1953 ptr->type = ClientMessage;
1954 ptr->message_type = RepeaterXAtom;
1956 ptr->data.l[0] = duration;
1958 // Couldn't use XSendEvent since it locked up randomly.
1964 int BC_WindowBase::receive_custom_xatoms(xatom_event *event)
1969 int BC_WindowBase::send_custom_xatom(xatom_event *event)
1971 #ifndef SINGLE_THREAD
1972 XEvent *myevent = new_xevent();
1973 XClientMessageEvent *ptr = (XClientMessageEvent*)myevent;
1974 ptr->type = ClientMessage;
1975 ptr->message_type = event->message_type;
1976 ptr->format = event->format;
1977 ptr->data.l[0] = event->data.l[0];
1978 ptr->data.l[1] = event->data.l[1];
1979 ptr->data.l[2] = event->data.l[2];
1980 ptr->data.l[3] = event->data.l[3];
1981 ptr->data.l[4] = event->data.l[4];
1990 Atom BC_WindowBase::create_xatom(const char *atom_name)
1992 return XInternAtom(display, atom_name, False);
1995 int BC_WindowBase::get_atoms()
1997 SetDoneXAtom = XInternAtom(display, "BC_REPEAT_EVENT", False);
1998 RepeaterXAtom = XInternAtom(display, "BC_CLOSE_EVENT", False);
1999 DestroyAtom = XInternAtom(display, "BC_DESTROY_WINDOW", False);
2000 DelWinXAtom = XInternAtom(display, "WM_DELETE_WINDOW", False);
2001 if( (ProtoXAtom = XInternAtom(display, "WM_PROTOCOLS", False)) != 0 )
2002 XChangeProperty(display, win, ProtoXAtom, XA_ATOM, 32,
2003 PropModeReplace, (unsigned char *)&DelWinXAtom, True);
2009 void BC_WindowBase::init_cursors()
2011 arrow_cursor = XCreateFontCursor(display, XC_top_left_arrow);
2012 cross_cursor = XCreateFontCursor(display, XC_crosshair);
2013 ibeam_cursor = XCreateFontCursor(display, XC_xterm);
2014 vseparate_cursor = XCreateFontCursor(display, XC_sb_v_double_arrow);
2015 hseparate_cursor = XCreateFontCursor(display, XC_sb_h_double_arrow);
2016 move_cursor = XCreateFontCursor(display, XC_fleur);
2017 left_cursor = XCreateFontCursor(display, XC_sb_left_arrow);
2018 right_cursor = XCreateFontCursor(display, XC_sb_right_arrow);
2019 upright_arrow_cursor = XCreateFontCursor(display, XC_arrow);
2020 upleft_resize_cursor = XCreateFontCursor(display, XC_top_left_corner);
2021 upright_resize_cursor = XCreateFontCursor(display, XC_top_right_corner);
2022 downleft_resize_cursor = XCreateFontCursor(display, XC_bottom_left_corner);
2023 downright_resize_cursor = XCreateFontCursor(display, XC_bottom_right_corner);
2024 hourglass_cursor = XCreateFontCursor(display, XC_watch);
2025 grabbed_cursor = create_grab_cursor();
2027 static char cursor_data[] = { 0,0,0,0, 0,0,0,0 };
2028 Colormap colormap = DefaultColormap(display, screen);
2029 Pixmap pixmap_bottom = XCreateBitmapFromData(display,
2030 rootwin, cursor_data, 8, 8);
2031 XColor black, dummy;
2032 XAllocNamedColor(display, colormap, "black", &black, &dummy);
2033 transparent_cursor = XCreatePixmapCursor(display,
2034 pixmap_bottom, pixmap_bottom, &black, &black, 0, 0);
2035 // XDefineCursor(display, win, transparent_cursor);
2036 XFreePixmap(display, pixmap_bottom);
2039 int BC_WindowBase::evaluate_color_model(int client_byte_order, int server_byte_order, int depth)
2041 int color_model = BC_TRANSPARENCY;
2045 color_model = BC_RGB8;
2048 color_model = (server_byte_order == client_byte_order) ? BC_RGB565 : BC_BGR565;
2051 color_model = server_byte_order ? BC_BGR888 : BC_RGB888;
2054 color_model = server_byte_order ? BC_BGR8888 : BC_ARGB8888;
2060 int BC_WindowBase::init_colors()
2063 current_color_value = current_color_pixel = 0;
2065 // Get the real depth
2068 ximage = XCreateImage(top_level->display,
2069 top_level->vis, top_level->default_depth,
2070 ZPixmap, 0, data, 16, 16, 8, 0);
2071 bits_per_pixel = ximage->bits_per_pixel;
2072 XDestroyImage(ximage);
2074 color_model = evaluate_color_model(client_byte_order,
2077 // Get the color model
2082 cmap = XCreateColormap(display, rootwin, vis, AllocNone);
2083 create_private_colors();
2086 cmap = DefaultColormap(display, screen);
2087 create_shared_colors();
2090 allocate_color_table();
2094 //cmap = DefaultColormap(display, screen);
2095 cmap = XCreateColormap(display, rootwin, vis, AllocNone );
2101 int BC_WindowBase::create_private_colors()
2106 for(int i = 0; i < 255; i++)
2108 color = (i & 0xc0) << 16;
2109 color += (i & 0x38) << 10;
2110 color += (i & 0x7) << 5;
2111 color_table[i][0] = color;
2113 create_shared_colors(); // overwrite the necessary colors on the table
2118 int BC_WindowBase::create_color(int color)
2120 if(total_colors == 256)
2122 // replace the closest match with an exact match
2123 color_table[get_color_rgb8(color)][0] = color;
2127 // add the color to the table
2128 color_table[total_colors][0] = color;
2134 int BC_WindowBase::create_shared_colors()
2136 create_color(BLACK);
2137 create_color(WHITE);
2139 create_color(LTGREY);
2140 create_color(MEGREY);
2141 create_color(MDGREY);
2142 create_color(DKGREY);
2144 create_color(LTCYAN);
2145 create_color(MECYAN);
2146 create_color(MDCYAN);
2147 create_color(DKCYAN);
2149 create_color(LTGREEN);
2150 create_color(GREEN);
2151 create_color(DKGREEN);
2153 create_color(LTPINK);
2157 create_color(LTBLUE);
2159 create_color(DKBLUE);
2161 create_color(LTYELLOW);
2162 create_color(MEYELLOW);
2163 create_color(MDYELLOW);
2164 create_color(DKYELLOW);
2166 create_color(LTPURPLE);
2167 create_color(MEPURPLE);
2168 create_color(MDPURPLE);
2169 create_color(DKPURPLE);
2171 create_color(FGGREY);
2172 create_color(MNBLUE);
2173 create_color(ORANGE);
2174 create_color(FTGREY);
2179 Cursor BC_WindowBase::create_grab_cursor()
2181 int iw = 23, iw1 = iw-1, iw2 = iw/2;
2182 int ih = 23, ih1 = ih-1, ih2 = ih/2;
2183 VFrame grab(iw,ih,BC_RGB888);
2185 grab.set_pixel_color(RED); // fg
2186 grab.draw_smooth(iw2,0, iw1,0, iw1,ih2);
2187 grab.draw_smooth(iw1,ih2, iw1,ih1, iw2,ih1);
2188 grab.draw_smooth(iw2,ih1, 0,ih1, 0,ih2);
2189 grab.draw_smooth(0,ih2, 0,0, iw2,0);
2190 grab.set_pixel_color(WHITE); // bg
2191 grab.draw_line(0,ih2, iw2-2,ih2);
2192 grab.draw_line(iw2+2,ih2, iw1,ih2);
2193 grab.draw_line(iw2,0, iw2,ih2-2);
2194 grab.draw_line(iw2,ih2+2, iw2,ih1);
2196 int bpl = (iw+7)/8, isz = bpl * ih;
2197 char img[isz]; memset(img, 0, isz);
2198 char msk[isz]; memset(msk, 0, isz);
2199 unsigned char **rows = grab.get_rows();
2200 for( int iy=0; iy<ih; ++iy ) {
2201 char *op = img + iy*bpl;
2202 char *mp = msk + iy*bpl;
2203 unsigned char *ip = rows[iy];
2204 for( int ix=0; ix<iw; ++ix,ip+=3 ) {
2205 if( ip[0] ) mp[ix>>3] |= (1<<(ix&7));
2206 if( !ip[1] ) op[ix>>3] |= (1<<(ix&7));
2209 unsigned long white_pix = WhitePixel(display, screen);
2210 unsigned long black_pix = BlackPixel(display, screen);
2211 Pixmap img_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2212 img, iw,ih, white_pix,black_pix, 1);
2213 Pixmap msk_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2214 msk, iw,ih, white_pix,black_pix, 1);
2217 fc.flags = bc.flags = DoRed | DoGreen | DoBlue;
2218 fc.red = 0xffff; fc.green = fc.blue = 0; // fg
2219 bc.red = 0xffff; bc.green = 0xffff; bc.blue = 0x0000; // bg
2220 Cursor cursor = XCreatePixmapCursor(display, img_xpm,msk_xpm, &fc,&bc, iw2,ih2);
2221 XFreePixmap(display, img_xpm);
2222 XFreePixmap(display, msk_xpm);
2226 int BC_WindowBase::allocate_color_table()
2228 int red, green, blue, color;
2231 for(int i = 0; i < total_colors; i++)
2233 color = color_table[i][0];
2234 red = (color & 0xFF0000) >> 16;
2235 green = (color & 0x00FF00) >> 8;
2236 blue = color & 0xFF;
2238 col.flags = DoRed | DoGreen | DoBlue;
2239 col.red = red<<8 | red;
2240 col.green = green<<8 | green;
2241 col.blue = blue<<8 | blue;
2243 XAllocColor(display, cmap, &col);
2244 color_table[i][1] = col.pixel;
2247 XInstallColormap(display, cmap);
2251 int BC_WindowBase::init_window_shape()
2253 if(bg_pixmap && bg_pixmap->use_alpha())
2255 XShapeCombineMask(top_level->display,
2256 this->win, ShapeBounding, 0, 0,
2257 bg_pixmap->get_alpha(), ShapeSet);
2263 int BC_WindowBase::init_gc()
2265 unsigned long gcmask;
2266 gcmask = GCFont | GCGraphicsExposures;
2269 gcvalues.font = mediumfont->fid; // set the font
2270 gcvalues.graphics_exposures = 0; // prevent expose events for every redraw
2271 gc = XCreateGC(display, rootwin, gcmask, &gcvalues);
2273 // gcmask = GCCapStyle | GCJoinStyle;
2274 // XGetGCValues(display, gc, gcmask, &gcvalues);
2275 // printf("BC_WindowBase::init_gc %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2279 int BC_WindowBase::init_fonts()
2281 if( !(smallfont = XLoadQueryFont(display, _(resources->small_font))) )
2282 if( !(smallfont = XLoadQueryFont(display, _(resources->small_font2))) )
2283 smallfont = XLoadQueryFont(display, "fixed");
2284 if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font))) )
2285 if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font2))) )
2286 mediumfont = XLoadQueryFont(display, "fixed");
2287 if( !(largefont = XLoadQueryFont(display, _(resources->large_font))) )
2288 if( !(largefont = XLoadQueryFont(display, _(resources->large_font2))) )
2289 largefont = XLoadQueryFont(display, "fixed");
2290 if( !(bigfont = XLoadQueryFont(display, _(resources->big_font))) )
2291 if( !(bigfont = XLoadQueryFont(display, _(resources->big_font2))) )
2292 bigfont = XLoadQueryFont(display, "fixed");
2294 if((clockfont = XLoadQueryFont(display, _(resources->clock_font))) == NULL)
2295 if((clockfont = XLoadQueryFont(display, _(resources->clock_font2))) == NULL)
2296 clockfont = XLoadQueryFont(display, "fixed");
2299 if(get_resources()->use_fontset)
2304 // FIXME: should check the m,d,n values
2305 smallfontset = XCreateFontSet(display, resources->small_fontset, &m, &n, &d);
2307 smallfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2308 mediumfontset = XCreateFontSet(display, resources->medium_fontset, &m, &n, &d);
2309 if( !mediumfontset )
2310 mediumfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2311 largefontset = XCreateFontSet(display, resources->large_fontset, &m, &n, &d);
2313 largefontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2314 bigfontset = XCreateFontSet(display, resources->big_fontset, &m, &n, &d);
2316 bigfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2317 clockfontset = XCreateFontSet(display, resources->clock_fontset, &m, &n, &d);
2319 clockfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2320 if(clockfontset && bigfontset && largefontset && mediumfontset && smallfontset) {
2321 curr_fontset = mediumfontset;
2322 get_resources()->use_fontset = 1;
2326 get_resources()->use_fontset = 0;
2333 void BC_WindowBase::init_xft()
2336 if( !get_resources()->use_xft ) return;
2337 // apparently, xft is not reentrant, more than this is needed
2338 static Mutex xft_init_lock("BC_WindowBase::xft_init_lock", 0);
2339 xft_init_lock.lock("BC_WindowBase::init_xft");
2340 if(!(smallfont_xft =
2341 (resources->small_font_xft[0] == '-' ?
2342 xftFontOpenXlfd(display, screen, resources->small_font_xft) :
2343 xftFontOpenName(display, screen, resources->small_font_xft))) )
2344 if(!(smallfont_xft =
2345 xftFontOpenXlfd(display, screen, resources->small_font_xft2)))
2346 smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2347 if(!(mediumfont_xft =
2348 (resources->medium_font_xft[0] == '-' ?
2349 xftFontOpenXlfd(display, screen, resources->medium_font_xft) :
2350 xftFontOpenName(display, screen, resources->medium_font_xft))) )
2351 if(!(mediumfont_xft =
2352 xftFontOpenXlfd(display, screen, resources->medium_font_xft2)))
2353 mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2354 if(!(largefont_xft =
2355 (resources->large_font_xft[0] == '-' ?
2356 xftFontOpenXlfd(display, screen, resources->large_font_xft) :
2357 xftFontOpenName(display, screen, resources->large_font_xft))) )
2358 if(!(largefont_xft =
2359 xftFontOpenXlfd(display, screen, resources->large_font_xft2)))
2360 largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2362 (resources->big_font_xft[0] == '-' ?
2363 xftFontOpenXlfd(display, screen, resources->big_font_xft) :
2364 xftFontOpenName(display, screen, resources->big_font_xft))) )
2366 xftFontOpenXlfd(display, screen, resources->big_font_xft2)))
2367 bigfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2368 if(!(clockfont_xft =
2369 (resources->clock_font_xft[0] == '-' ?
2370 xftFontOpenXlfd(display, screen, resources->clock_font_xft) :
2371 xftFontOpenName(display, screen, resources->clock_font_xft))) )
2372 clockfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2375 if(!(bold_smallfont_xft =
2376 (resources->small_b_font_xft[0] == '-' ?
2377 xftFontOpenXlfd(display, screen, resources->small_b_font_xft) :
2378 xftFontOpenName(display, screen, resources->small_b_font_xft))) )
2379 bold_smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2380 if(!(bold_mediumfont_xft =
2381 (resources->medium_b_font_xft[0] == '-' ?
2382 xftFontOpenXlfd(display, screen, resources->medium_b_font_xft) :
2383 xftFontOpenName(display, screen, resources->medium_b_font_xft))) )
2384 bold_mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2385 if(!(bold_largefont_xft =
2386 (resources->large_b_font_xft[0] == '-' ?
2387 xftFontOpenXlfd(display, screen, resources->large_b_font_xft) :
2388 xftFontOpenName(display, screen, resources->large_b_font_xft))) )
2389 bold_largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2391 if( !smallfont_xft || !mediumfont_xft || !largefont_xft || !bigfont_xft ||
2392 !bold_largefont_xft || !bold_mediumfont_xft || !bold_largefont_xft ||
2394 printf("BC_WindowBase::init_fonts: no xft fonts found:"
2395 " %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n",
2396 resources->small_font_xft, smallfont_xft,
2397 resources->medium_font_xft, mediumfont_xft,
2398 resources->large_font_xft, largefont_xft,
2399 resources->big_font_xft, bigfont_xft,
2400 resources->clock_font_xft, clockfont_xft,
2401 resources->small_b_font_xft, bold_smallfont_xft,
2402 resources->medium_b_font_xft, bold_mediumfont_xft,
2403 resources->large_b_font_xft, bold_largefont_xft);
2404 get_resources()->use_xft = 0;
2407 // _XftDisplayInfo needs a lock.
2408 xftDefaultHasRender(display);
2409 xft_init_lock.unlock();
2413 void BC_WindowBase::init_glyphs()
2415 // draw all ascii char glyphs
2416 // There are problems with some/my graphics boards/drivers
2417 // which cause some glyphs to be munged if draws occur while
2418 // the font is being loaded. This code fills the font caches
2419 // by drawing all the ascii glyphs before the system starts.
2420 // Not a fix, but much better than nothing.
2421 static int inited = 0;
2422 if( inited ) return;
2423 XGrabServer(display);
2426 int cur_font = current_font;
2427 // locale encodings, needed glyphs to be preloaded
2428 const char *text = _( // ascii 0x20...0x7e
2429 " !\"#$%&'()*+,-./0123456789:;<=>?"
2430 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
2431 "`abcdefghijklmnopqrstuvwxyz{|}~");
2432 for( int font=SMALLFONT; font<=LARGEFONT; ++font ) {
2434 draw_text(5,5, text);
2437 XUngrabServer(display);
2440 void BC_WindowBase::init_im()
2442 XIMStyles *xim_styles;
2445 if(!(input_method = XOpenIM(display, NULL, NULL, NULL)))
2447 printf("BC_WindowBase::init_im: Could not open input method.\n");
2450 if(XGetIMValues(input_method, XNQueryInputStyle, &xim_styles, NULL) ||
2453 printf("BC_WindowBase::init_im: Input method doesn't support any styles.\n");
2454 XCloseIM(input_method);
2459 for(int z = 0; z < xim_styles->count_styles; z++)
2461 if(xim_styles->supported_styles[z] == (XIMPreeditNothing | XIMStatusNothing))
2463 xim_style = xim_styles->supported_styles[z];
2471 printf("BC_WindowBase::init_im: Input method doesn't support the style we need.\n");
2472 XCloseIM(input_method);
2476 input_context = XCreateIC(input_method, XNInputStyle, xim_style,
2477 XNClientWindow, win, XNFocusWindow, win, NULL);
2480 printf("BC_WindowBase::init_im: Failed to create input context.\n");
2481 XCloseIM(input_method);
2486 void BC_WindowBase::finit_im()
2488 if( input_context ) {
2489 XDestroyIC(input_context);
2492 if( input_method ) {
2493 XCloseIM(input_method);
2499 int BC_WindowBase::get_color(int64_t color)
2501 // return pixel of color
2502 // use this only for drawing subwindows not for bitmaps
2503 int i, test, difference;
2509 return get_color_rgb8(color);
2510 // test last color looked up
2511 if(current_color_value == color)
2512 return current_color_pixel;
2515 current_color_value = color;
2516 for(i = 0; i < total_colors; i++)
2518 if(color_table[i][0] == color)
2520 current_color_pixel = color_table[i][1];
2521 return current_color_pixel;
2525 // find nearest match
2526 difference = 0xFFFFFF;
2528 for(i = 0; i < total_colors; i++)
2530 test = abs((int)(color_table[i][0] - color));
2532 if(test < difference)
2534 current_color_pixel = color_table[i][1];
2538 return current_color_pixel;
2541 return get_color_rgb16(color);
2544 return get_color_bgr16(color);
2548 return client_byte_order == server_byte_order ?
2549 color : get_color_bgr24(color);
2557 int BC_WindowBase::get_color_rgb8(int color)
2561 pixel = (color & 0xc00000) >> 16;
2562 pixel += (color & 0xe000) >> 10;
2563 pixel += (color & 0xe0) >> 5;
2567 int64_t BC_WindowBase::get_color_rgb16(int color)
2570 result = (color & 0xf80000) >> 8;
2571 result += (color & 0xfc00) >> 5;
2572 result += (color & 0xf8) >> 3;
2577 int64_t BC_WindowBase::get_color_bgr16(int color)
2580 result = (color & 0xf80000) >> 19;
2581 result += (color & 0xfc00) >> 5;
2582 result += (color & 0xf8) << 8;
2587 int64_t BC_WindowBase::get_color_bgr24(int color)
2590 result = (color & 0xff) << 16;
2591 result += (color & 0xff00);
2592 result += (color & 0xff0000) >> 16;
2596 void BC_WindowBase::start_video()
2598 cursor_timer->update();
2600 // set_color(BLACK);
2601 // draw_box(0, 0, get_w(), get_h());
2605 void BC_WindowBase::stop_video()
2613 int64_t BC_WindowBase::get_color()
2615 return top_level->current_color;
2618 void BC_WindowBase::set_color(int64_t color)
2620 top_level->current_color = color;
2621 XSetForeground(top_level->display,
2623 top_level->get_color(color));
2626 void BC_WindowBase::set_opaque()
2628 XSetFunction(top_level->display, top_level->gc, GXcopy);
2631 void BC_WindowBase::set_inverse()
2633 XSetFunction(top_level->display, top_level->gc, GXxor);
2636 void BC_WindowBase::set_line_width(int value)
2638 this->line_width = value;
2639 XSetLineAttributes(top_level->display, top_level->gc, value, /* line_width */
2640 line_dashes == 0 ? LineSolid : LineOnOffDash, /* line_style */
2641 line_dashes == 0 ? CapRound : CapNotLast, /* cap_style */
2642 JoinMiter); /* join_style */
2644 if(line_dashes > 0) {
2645 const char dashes = line_dashes;
2646 XSetDashes(top_level->display, top_level->gc, 0, &dashes, 1);
2649 // XGCValues gcvalues;
2650 // unsigned long gcmask;
2651 // gcmask = GCCapStyle | GCJoinStyle;
2652 // XGetGCValues(top_level->display, top_level->gc, gcmask, &gcvalues);
2653 // printf("BC_WindowBase::set_line_width %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2656 void BC_WindowBase::set_line_dashes(int value)
2658 line_dashes = value;
2659 // call XSetLineAttributes
2660 set_line_width(line_width);
2664 Cursor BC_WindowBase::get_cursor_struct(int cursor)
2668 case ARROW_CURSOR: return top_level->arrow_cursor;
2669 case CROSS_CURSOR: return top_level->cross_cursor;
2670 case IBEAM_CURSOR: return top_level->ibeam_cursor;
2671 case VSEPARATE_CURSOR: return top_level->vseparate_cursor;
2672 case HSEPARATE_CURSOR: return top_level->hseparate_cursor;
2673 case MOVE_CURSOR: return top_level->move_cursor;
2674 case LEFT_CURSOR: return top_level->left_cursor;
2675 case RIGHT_CURSOR: return top_level->right_cursor;
2676 case UPRIGHT_ARROW_CURSOR: return top_level->upright_arrow_cursor;
2677 case UPLEFT_RESIZE: return top_level->upleft_resize_cursor;
2678 case UPRIGHT_RESIZE: return top_level->upright_resize_cursor;
2679 case DOWNLEFT_RESIZE: return top_level->downleft_resize_cursor;
2680 case DOWNRIGHT_RESIZE: return top_level->downright_resize_cursor;
2681 case HOURGLASS_CURSOR: return top_level->hourglass_cursor;
2682 case TRANSPARENT_CURSOR: return top_level->transparent_cursor;
2683 case GRABBED_CURSOR: return top_level->grabbed_cursor;
2688 void BC_WindowBase::set_cursor(int cursor, int override, int flush)
2690 // inherit cursor from parent
2693 XUndefineCursor(top_level->display, win);
2694 current_cursor = cursor;
2697 // don't change cursor if overridden
2698 if((!top_level->is_hourglass && !is_transparent) ||
2701 XDefineCursor(top_level->display, win, get_cursor_struct(cursor));
2702 if(flush) this->flush();
2705 if(!override) current_cursor = cursor;
2708 void BC_WindowBase::set_x_cursor(int cursor)
2710 temp_cursor = XCreateFontCursor(top_level->display, cursor);
2711 XDefineCursor(top_level->display, win, temp_cursor);
2712 current_cursor = cursor;
2716 int BC_WindowBase::get_cursor()
2718 return current_cursor;
2721 void BC_WindowBase::start_hourglass()
2723 top_level->start_hourglass_recursive();
2727 void BC_WindowBase::stop_hourglass()
2729 top_level->stop_hourglass_recursive();
2733 void BC_WindowBase::start_hourglass_recursive()
2735 if(this == top_level)
2743 set_cursor(HOURGLASS_CURSOR, 1, 0);
2744 for(int i = 0; i < subwindows->total; i++)
2746 subwindows->values[i]->start_hourglass_recursive();
2751 void BC_WindowBase::stop_hourglass_recursive()
2753 if(this == top_level)
2755 if(hourglass_total == 0) return;
2756 top_level->hourglass_total--;
2759 if(!top_level->hourglass_total)
2761 top_level->is_hourglass = 0;
2763 // Cause set_cursor to perform change
2765 set_cursor(current_cursor, 1, 0);
2767 for(int i = 0; i < subwindows->total; i++)
2769 subwindows->values[i]->stop_hourglass_recursive();
2777 XFontStruct* BC_WindowBase::get_font_struct(int font)
2779 // Clear out unrelated flags
2780 if(font & BOLDFACE) font ^= BOLDFACE;
2783 case SMALLFONT: return top_level->smallfont; break;
2784 case MEDIUMFONT: return top_level->mediumfont; break;
2785 case LARGEFONT: return top_level->largefont; break;
2786 case BIGFONT: return top_level->bigfont; break;
2787 case CLOCKFONT: return top_level->clockfont; break;
2792 XFontSet BC_WindowBase::get_fontset(int font)
2796 if(get_resources()->use_fontset)
2798 switch(font & 0xff) {
2799 case SMALLFONT: fs = top_level->smallfontset; break;
2800 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2801 case LARGEFONT: fs = top_level->largefontset; break;
2802 case BIGFONT: fs = top_level->bigfontset; break;
2803 case CLOCKFONT: fs = top_level->clockfontset; break;
2811 XftFont* BC_WindowBase::get_xft_struct(int font)
2814 case SMALLFONT: return (XftFont*)top_level->smallfont_xft;
2815 case MEDIUMFONT: return (XftFont*)top_level->mediumfont_xft;
2816 case LARGEFONT: return (XftFont*)top_level->largefont_xft;
2817 case BIGFONT: return (XftFont*)top_level->bigfont_xft;
2818 case CLOCKFONT: return (XftFont*)top_level->clockfont_xft;
2819 case MEDIUMFONT_3D: return (XftFont*)top_level->bold_mediumfont_xft;
2820 case SMALLFONT_3D: return (XftFont*)top_level->bold_smallfont_xft;
2821 case LARGEFONT_3D: return (XftFont*)top_level->bold_largefont_xft;
2829 int BC_WindowBase::get_current_font()
2831 return top_level->current_font;
2834 void BC_WindowBase::set_font(int font)
2836 top_level->current_font = font;
2839 if(get_resources()->use_xft) {}
2842 if(get_resources()->use_fontset) {
2846 if(get_font_struct(font))
2848 XSetFont(top_level->display, top_level->gc, get_font_struct(font)->fid);
2854 void BC_WindowBase::set_fontset(int font)
2858 if(get_resources()->use_fontset) {
2860 case SMALLFONT: fs = top_level->smallfontset; break;
2861 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2862 case LARGEFONT: fs = top_level->largefontset; break;
2863 case BIGFONT: fs = top_level->bigfontset; break;
2864 case CLOCKFONT: fs = top_level->clockfontset; break;
2872 XFontSet BC_WindowBase::get_curr_fontset(void)
2874 if(get_resources()->use_fontset)
2875 return curr_fontset;
2879 int BC_WindowBase::get_single_text_width(int font, const char *text, int length)
2882 if(get_resources()->use_xft && get_xft_struct(font))
2885 #ifdef X_HAVE_UTF8_STRING
2886 if(get_resources()->locale_utf8)
2888 xftTextExtentsUtf8(top_level->display,
2889 get_xft_struct(font),
2890 (const XftChar8 *)text,
2897 xftTextExtents8(top_level->display,
2898 get_xft_struct(font),
2899 (const XftChar8 *)text,
2903 return extents.xOff;
2907 if(get_resources()->use_fontset && top_level->get_fontset(font))
2908 return XmbTextEscapement(top_level->get_fontset(font), text, length);
2910 if(get_font_struct(font))
2911 return XTextWidth(get_font_struct(font), text, length);
2917 case MEDIUM_7SEGMENT:
2918 return get_resources()->medium_7segment[0]->get_w() * length;
2928 int BC_WindowBase::get_text_width(int font, const char *text, int length)
2930 int i, j, w = 0, line_w = 0;
2931 if(length < 0) length = strlen(text);
2933 for(i = 0, j = 0; i <= length; i++)
2938 line_w = get_single_text_width(font, &text[j], i - j);
2944 line_w = get_single_text_width(font, &text[j], length - j);
2946 if(line_w > w) w = line_w;
2949 if(i > length && w == 0)
2951 w = get_single_text_width(font, text, length);
2957 int BC_WindowBase::get_text_width(int font, const wchr_t *text, int length)
2960 if( length < 0 ) length = wstrlen(text);
2962 for( i=j=0; i<length && text[i]; ++i ) {
2963 if( text[i] != '\n' ) continue;
2965 int lw = get_single_text_width(font, &text[j], i-j);
2966 if( w < lw ) w = lw;
2971 int lw = get_single_text_width(font, &text[j], length-j);
2972 if( w < lw ) w = lw;
2978 int BC_WindowBase::get_text_ascent(int font)
2982 if( (fstruct = get_xft_struct(font)) != 0 )
2983 return fstruct->ascent;
2985 if(get_resources()->use_fontset && top_level->get_fontset(font))
2987 XFontSetExtents *extents;
2989 extents = XExtentsOfFontSet(top_level->get_fontset(font));
2990 return -extents->max_logical_extent.y;
2993 if(get_font_struct(font))
2994 return top_level->get_font_struct(font)->ascent;
2997 case MEDIUM_7SEGMENT:
2998 return get_resources()->medium_7segment[0]->get_h();
3003 int BC_WindowBase::get_text_descent(int font)
3007 if( (fstruct = get_xft_struct(font)) != 0 )
3008 return fstruct->descent;
3010 if(get_resources()->use_fontset && top_level->get_fontset(font)) {
3011 XFontSetExtents *extents;
3012 extents = XExtentsOfFontSet(top_level->get_fontset(font));
3013 return (extents->max_logical_extent.height
3014 + extents->max_logical_extent.y);
3017 if(get_font_struct(font))
3018 return top_level->get_font_struct(font)->descent;
3023 int BC_WindowBase::get_text_height(int font, const char *text)
3028 if( (fstruct = get_xft_struct(font)) != 0 )
3029 rowh = fstruct->height;
3032 rowh = get_text_ascent(font) + get_text_descent(font);
3034 if(!text) return rowh;
3036 // Add height of lines
3037 int h = 0, i, length = strlen(text);
3038 for(i = 0; i <= length; i++)
3049 // truncate the text with ... & return a new string
3050 char *BC_WindowBase::get_truncated_text(int font, const char *text, int max_w)
3052 char *result = cstrdup(text);
3053 int text_w = get_text_width(font, text);
3054 int ci = -1, len = strlen(text);
3055 if( text_w > max_w ) {
3056 // get center of string
3057 int cx = text_w/2, best = INT_MAX;
3058 for( int i=1; i<=len; ++i ) {
3059 int cw = get_text_width(font, text, i);
3060 if( abs(cw-cx) < abs(best-cx) ) {
3065 if( ci > 0 && ci < len-1 ) {
3066 // insert ... in the center
3067 result[ci-1] = result[ci] = result[ci+1] = '.';
3069 while( ci-2>=0 && ci+2<(int)strlen(result) &&
3070 get_text_width(font, result) > max_w ) {
3071 // take away a character from the longer side
3072 int left_w = get_text_width(font, result, ci-2);
3073 int right_w = get_text_width(font, result + ci+3);
3074 int i = left_w > right_w ? --ci-1 : ci+2;
3075 while( (result[i]=result[i+1])!=0 ) ++i;
3082 BC_Bitmap* BC_WindowBase::new_bitmap(int w, int h, int color_model)
3084 if(color_model < 0) color_model = top_level->get_color_model();
3085 return new BC_Bitmap(top_level, w, h, color_model);
3088 void BC_WindowBase::init_wait()
3090 #ifndef SINGLE_THREAD
3091 if(window_type != MAIN_WINDOW)
3092 top_level->init_wait();
3093 init_lock->lock("BC_WindowBase::init_wait");
3094 init_lock->unlock();
3098 int BC_WindowBase::accel_available(int color_model, int lock_it)
3100 if( window_type != MAIN_WINDOW )
3101 return top_level->accel_available(color_model, lock_it);
3103 lock_window("BC_WindowBase::accel_available");
3105 switch(color_model) {
3107 grab_port_id(color_model);
3111 grab_port_id(color_model);
3120 //printf("BC_WindowBase::accel_available %d %d\n", color_model, xvideo_port_id);
3121 return xvideo_port_id >= 0 ? 1 : 0;
3125 int BC_WindowBase::grab_port_id(int color_model)
3128 if( !get_resources()->use_xvideo || // disabled
3129 !get_resources()->use_shm ) // Only local server is fast enough.
3131 if( xvideo_port_id >= 0 )
3132 return xvideo_port_id;
3134 unsigned int ver, rev, reqBase, eventBase, errorBase;
3135 if( Success != XvQueryExtension(display, // XV extension is available
3136 &ver, &rev, &reqBase, &eventBase, &errorBase) )
3139 // XV adaptors are available
3140 unsigned int numAdapt = 0;
3141 XvAdaptorInfo *info = 0;
3142 XvQueryAdaptors(display, DefaultRootWindow(display), &numAdapt, &info);
3146 // Translate from color_model to X color model
3147 int x_color_model = BC_CModels::bc_to_x(color_model);
3149 // Get adaptor with desired color model
3150 for( int i = 0; i < (int)numAdapt && xvideo_port_id == -1; i++) {
3151 if( !(info[i].type & XvImageMask) || !info[i].num_ports ) continue;
3152 // adaptor supports XvImages
3153 int numFormats = 0, numPorts = info[i].num_ports;
3154 XvImageFormatValues *formats =
3155 XvListImageFormats(display, info[i].base_id, &numFormats);
3156 if( !formats ) continue;
3158 for( int j=0; j<numFormats && xvideo_port_id<0; ++j ) {
3159 if( formats[j].id != x_color_model ) continue;
3160 // this adaptor supports the desired format, grab a port
3161 for( int k=0; k<numPorts; ++k ) {
3162 if( Success == XvGrabPort(top_level->display,
3163 info[i].base_id+k, CurrentTime) ) {
3164 //printf("BC_WindowBase::grab_port_id %llx\n", info[i].base_id);
3165 xvideo_port_id = info[i].base_id + k;
3173 XvFreeAdaptorInfo(info);
3174 return xvideo_port_id;
3181 int BC_WindowBase::show_window(int flush)
3183 for(int i = 0; i < subwindows->size(); i++)
3185 subwindows->get(i)->show_window(0);
3188 XMapWindow(top_level->display, win);
3189 if(flush) XFlush(top_level->display);
3190 // XSync(top_level->display, 0);
3195 int BC_WindowBase::hide_window(int flush)
3197 for(int i = 0; i < subwindows->size(); i++)
3199 subwindows->get(i)->hide_window(0);
3202 XUnmapWindow(top_level->display, win);
3203 if(flush) this->flush();
3208 BC_MenuBar* BC_WindowBase::add_menubar(BC_MenuBar *menu_bar)
3210 subwindows->append((BC_SubWindow*)menu_bar);
3212 menu_bar->parent_window = this;
3213 menu_bar->top_level = this->top_level;
3214 menu_bar->initialize();
3218 BC_WindowBase* BC_WindowBase::add_popup(BC_WindowBase *window)
3220 //printf("BC_WindowBase::add_popup window=%p win=%p\n", window, window->win);
3221 if(this != top_level) return top_level->add_popup(window);
3222 popups.append(window);
3226 void BC_WindowBase::remove_popup(BC_WindowBase *window)
3228 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3229 if(this != top_level)
3230 top_level->remove_popup(window);
3232 popups.remove(window);
3233 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3237 BC_WindowBase* BC_WindowBase::add_subwindow(BC_WindowBase *subwindow)
3239 subwindows->append(subwindow);
3241 if(subwindow->bg_color == -1) subwindow->bg_color = this->bg_color;
3243 // parent window must be set before the subwindow initialization
3244 subwindow->parent_window = this;
3245 subwindow->top_level = this->top_level;
3247 // Execute derived initialization
3248 subwindow->initialize();
3253 BC_WindowBase* BC_WindowBase::add_tool(BC_WindowBase *subwindow)
3255 return add_subwindow(subwindow);
3258 int BC_WindowBase::flash(int x, int y, int w, int h, int flush)
3260 if( !top_level->flash_enabled ) return 0;
3261 //printf("BC_WindowBase::flash %d %d %d %d %d\n", __LINE__, w, h, this->w, this->h);
3263 XSetWindowBackgroundPixmap(top_level->display, win, pixmap->opaque_pixmap);
3266 XClearArea(top_level->display, win, x, y, w, h, 0);
3270 XClearWindow(top_level->display, win);
3278 int BC_WindowBase::flash(int flush)
3280 flash(-1, -1, -1, -1, flush);
3284 void BC_WindowBase::flush()
3286 //if(!get_window_lock())
3287 // printf("BC_WindowBase::flush %s not locked\n", top_level->title);
3288 // X gets hosed if Flush/Sync are not user locked (at libX11-1.1.5 / libxcb-1.1.91)
3289 // _XReply deadlocks in condition_wait waiting for xlib lock when waiters!=-1
3290 int locked = get_window_lock();
3291 if( !locked ) lock_window("BC_WindowBase::flush");
3292 XFlush(top_level->display);
3293 if( !locked ) unlock_window();
3296 void BC_WindowBase::sync_display()
3298 int locked = get_window_lock();
3299 if( !locked ) lock_window("BC_WindowBase::sync_display");
3300 XSync(top_level->display, False);
3301 if( !locked ) unlock_window();
3304 int BC_WindowBase::get_window_lock()
3306 #ifdef SINGLE_THREAD
3307 return BC_Display::display_global->get_display_locked();
3309 return top_level->window_lock;
3313 int BC_WindowBase::lock_window(const char *location)
3315 if(top_level && top_level != this)
3317 top_level->lock_window(location);
3322 SET_LOCK(this, title, location);
3323 #ifdef SINGLE_THREAD
3324 BC_Display::lock_display(location);
3326 XLockDisplay(top_level->display);
3327 top_level->display_lock_owner = pthread_self();
3330 ++top_level->window_lock;
3334 printf("BC_WindowBase::lock_window top_level NULL\n");
3339 int BC_WindowBase::unlock_window()
3341 if(top_level && top_level != this)
3343 top_level->unlock_window();
3349 if( !top_level->window_lock ) {
3350 printf("BC_WindowBase::unlock_window %s not locked\n", title);
3353 if( top_level->window_lock > 0 )
3354 if( --top_level->window_lock == 0 )
3355 top_level->display_lock_owner = 0;
3356 #ifdef SINGLE_THREAD
3357 BC_Display::unlock_display();
3359 XUnlockDisplay(top_level->display);
3364 printf("BC_WindowBase::unlock_window top_level NULL\n");
3369 int BC_WindowBase::break_lock()
3371 if( !top_level ) return 0;
3372 if( top_level != this ) return top_level->break_lock();
3373 if( top_level->display_lock_owner != pthread_self() ) return 0;
3374 if( top_level->window_lock != 1 ) return 0;
3377 display_lock_owner = 0;
3378 #ifdef SINGLE_THREAD
3379 BC_Display::unlock_display();
3381 XUnlockDisplay(display);
3386 void BC_WindowBase::set_done(int return_value)
3388 if(done_set) return;
3390 if(window_type != MAIN_WINDOW)
3391 top_level->set_done(return_value);
3394 #ifdef SINGLE_THREAD
3395 this->return_value = return_value;
3396 BC_Display::display_global->arm_completion(this);
3397 completion_lock->unlock();
3398 #else // SINGLE_THREAD
3400 if( !event_thread ) return;
3401 XEvent *event = new_xevent();
3402 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
3403 event->type = ClientMessage;
3404 ptr->message_type = SetDoneXAtom;
3406 this->return_value = return_value;
3407 // May lock up here because XSendEvent doesn't work too well
3408 // asynchronous with XNextEvent.
3409 // This causes BC_WindowEvents to forward a copy of the event to run_window where
3411 // Deletion of event_thread is done at the end of BC_WindowBase::run_window() - by calling the destructor
3417 void BC_WindowBase::close(int return_value)
3419 hide_window(); flush();
3420 set_done(return_value);
3423 int BC_WindowBase::grab(BC_WindowBase *window)
3426 BC_WindowBase *grab_window = window->active_grab;
3428 int locked = get_window_lock();
3429 if( locked ) unlock_window();
3430 grab_window->lock_window("BC_WindowBase::grab(BC_WindowBase");
3431 grab_window->handle_ungrab();
3432 grab_window->unlock_window();
3433 if( locked ) lock_window("BC_WindowBase::grab(BC_WindowBase");
3435 window->grab_lock->lock("BC_WindowBase::grab");
3436 if( !window->active_grab ) {
3437 window->active_grab = this;
3438 this->grab_active = window;
3441 window->grab_lock->unlock();
3444 int BC_WindowBase::ungrab(BC_WindowBase *window)
3447 window->grab_lock->lock("BC_WindowBase::ungrab");
3448 if( this == window->active_grab ) {
3449 window->active_grab = 0;
3450 this->grab_active = 0;
3453 window->grab_lock->unlock();
3456 int BC_WindowBase::grab_event_count()
3459 #ifndef SINGLE_THREAD
3460 result = grab_active->get_event_count();
3464 int BC_WindowBase::grab_buttons()
3466 XSync(top_level->display, False);
3467 if( XGrabButton(top_level->display, AnyButton, AnyModifier,
3468 top_level->rootwin, True, ButtonPressMask | ButtonReleaseMask,
3469 GrabModeAsync, GrabModeSync, None, None) == GrabSuccess ) {
3470 set_active_subwindow(this);
3475 void BC_WindowBase::ungrab_buttons()
3477 XUngrabButton(top_level->display, AnyButton, AnyModifier, top_level->rootwin);
3478 set_active_subwindow(0);
3481 void BC_WindowBase::grab_cursor()
3483 Cursor cursor_grab = get_cursor_struct(GRABBED_CURSOR);
3484 XGrabPointer(top_level->display, top_level->rootwin, True,
3485 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
3486 GrabModeAsync, GrabModeAsync, None, cursor_grab, CurrentTime);
3488 void BC_WindowBase::ungrab_cursor()
3490 XUngrabPointer(top_level->display, CurrentTime);
3494 // WidthOfScreen/HeightOfScreen of XDefaultScreenOfDisplay
3495 // this is the bounding box of all the screens
3497 int BC_WindowBase::get_root_w(int lock_display)
3499 if(lock_display) lock_window("BC_WindowBase::get_root_w");
3500 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3501 int result = WidthOfScreen(def_screen);
3502 if(lock_display) unlock_window();
3506 int BC_WindowBase::get_root_h(int lock_display)
3508 if(lock_display) lock_window("BC_WindowBase::get_root_h");
3509 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3510 int result = HeightOfScreen(def_screen);
3511 if(lock_display) unlock_window();
3515 XineramaScreenInfo *
3516 BC_WindowBase::get_xinerama_info(int screen)
3518 if( !xinerama_info || !xinerama_screens ) return 0;
3520 for( int i=0; i<xinerama_screens; ++i )
3521 if( xinerama_info[i].screen_number == screen )
3522 return &xinerama_info[i];
3525 int top_x = get_x(), top_y = get_y();
3526 if( BC_DisplayInfo::left_border >= 0 ) top_x += BC_DisplayInfo::left_border;
3527 if( BC_DisplayInfo::top_border >= 0 ) top_y += BC_DisplayInfo::top_border;
3528 for( int i=0; i<xinerama_screens; ++i ) {
3529 int scr_y = top_y - xinerama_info[i].y_org;
3530 if( scr_y < 0 || scr_y >= xinerama_info[i].height ) continue;
3531 int scr_x = top_x - xinerama_info[i].x_org;
3532 if( scr_x >= 0 && scr_x < xinerama_info[i].width )
3533 return &xinerama_info[i];
3538 void BC_WindowBase::get_fullscreen_geometry(int &wx, int &wy, int &ww, int &wh)
3540 XineramaScreenInfo *info = top_level->get_xinerama_info(-1);
3542 wx = info->x_org; wy = info->y_org;
3543 ww = info->width; wh = info->height;
3546 wx = get_screen_x(0, -1);
3547 wy = get_screen_y(0, -1);
3548 int scr_w0 = get_screen_w(0, 0);
3549 int root_w = get_root_w(0);
3550 int root_h = get_root_h(0);
3551 if( root_w > scr_w0 ) { // multi-headed
3552 if( wx >= scr_w0 ) {
3553 // assumes right side is the big one
3554 ww = root_w - scr_w0;
3558 // use same aspect ratio to compute left height
3560 wh = (w*root_h) / (root_w-scr_w0);
3570 int BC_WindowBase::get_screen_x(int lock_display, int screen)
3573 if(lock_display) lock_window("BC_WindowBase::get_screen_x");
3574 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3577 int root_w = get_root_w(0);
3578 int root_h = get_root_h(0);
3579 // Shift X based on position of current window if dual head
3580 if( (float)root_w/root_h > 1.8 ) {
3581 root_w = get_screen_w(0, 0);
3582 if( top_level->get_x() >= root_w )
3587 result = info->x_org;
3588 if(lock_display) unlock_window();
3592 int BC_WindowBase::get_screen_y(int lock_display, int screen)
3594 if(lock_display) lock_window("BC_WindowBase::get_screen_y");
3595 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3596 int result = !info ? 0 : info->y_org;
3597 if(lock_display) unlock_window();
3601 int BC_WindowBase::get_screen_w(int lock_display, int screen)
3604 if(lock_display) lock_window("BC_WindowBase::get_screen_w");
3605 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3607 int width = get_root_w(0);
3608 int height = get_root_h(0);
3609 if( (float)width/height > 1.8 ) {
3610 // If dual head, the screen width is > 16x9
3611 // but we only want to fill one screen
3612 // this code assumes the "big" screen is on the right
3613 int scr_w0 = width / 2;
3615 case 600: scr_w0 = 800; break;
3616 case 720: scr_w0 = 1280; break;
3617 case 1024: scr_w0 = 1280; break;
3618 case 1200: scr_w0 = 1600; break;
3619 case 1080: scr_w0 = 1920; break;
3621 int scr_w1 = width - scr_w0;
3622 result = screen > 0 ? scr_w1 :
3623 screen == 0 ? scr_w0 :
3624 top_level->get_x() < scr_w0 ? scr_w0 : scr_w1;
3630 result = info->width;
3631 if(lock_display) unlock_window();
3635 int BC_WindowBase::get_screen_h(int lock_display, int screen)
3637 if(lock_display) lock_window("BC_WindowBase::get_screen_h");
3638 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3639 int result = info ? info->height : get_root_h(0);
3640 if(lock_display) unlock_window();
3644 // Bottom right corner
3645 int BC_WindowBase::get_x2()
3650 int BC_WindowBase::get_y2()
3655 int BC_WindowBase::get_video_on()
3660 int BC_WindowBase::get_hidden()
3662 return top_level->hidden;
3665 int BC_WindowBase::cursor_inside()
3667 return (top_level->cursor_x >= 0 &&
3668 top_level->cursor_y >= 0 &&
3669 top_level->cursor_x < w &&
3670 top_level->cursor_y < h);
3673 BC_WindowBase* BC_WindowBase::get_top_level()
3678 BC_WindowBase* BC_WindowBase::get_parent()
3680 return parent_window;
3683 int BC_WindowBase::get_color_model()
3685 return top_level->color_model;
3688 BC_Resources* BC_WindowBase::get_resources()
3690 return BC_WindowBase::resources;
3693 BC_Synchronous* BC_WindowBase::get_synchronous()
3695 return BC_WindowBase::resources->get_synchronous();
3698 int BC_WindowBase::get_bg_color()
3703 void BC_WindowBase::set_bg_color(int color)
3705 this->bg_color = color;
3708 BC_Pixmap* BC_WindowBase::get_bg_pixmap()
3713 void BC_WindowBase::set_active_subwindow(BC_WindowBase *subwindow)
3715 top_level->active_subwindow = subwindow;
3718 int BC_WindowBase::activate()
3723 int BC_WindowBase::deactivate()
3725 if(window_type == MAIN_WINDOW)
3727 if( top_level->active_menubar ) {
3728 top_level->active_menubar->deactivate();
3729 top_level->active_menubar = 0;
3731 if( top_level->active_popup_menu ) {
3732 top_level->active_popup_menu->deactivate();
3733 top_level->active_popup_menu = 0;
3735 if( top_level->active_subwindow ) {
3736 top_level->active_subwindow->deactivate();
3737 top_level->active_subwindow = 0;
3739 if( top_level->motion_events && top_level->last_motion_win == this->win )
3740 top_level->motion_events = 0;
3746 int BC_WindowBase::cycle_textboxes(int amount)
3749 BC_WindowBase *new_textbox = 0;
3753 BC_WindowBase *first_textbox = 0;
3754 find_next_textbox(&first_textbox, &new_textbox, result);
3755 if(!new_textbox) new_textbox = first_textbox;
3761 BC_WindowBase *last_textbox = 0;
3762 find_prev_textbox(&last_textbox, &new_textbox, result);
3763 if(!new_textbox) new_textbox = last_textbox;
3767 if(new_textbox != active_subwindow)
3770 new_textbox->activate();
3776 int BC_WindowBase::find_next_textbox(BC_WindowBase **first_textbox, BC_WindowBase **next_textbox, int &result)
3778 // Search subwindows for textbox
3779 for(int i = 0; i < subwindows->total && result < 2; i++)
3781 BC_WindowBase *test_subwindow = subwindows->values[i];
3782 test_subwindow->find_next_textbox(first_textbox, next_textbox, result);
3789 if(!*first_textbox) *first_textbox = this;
3793 if(top_level->active_subwindow == this)
3799 *next_textbox = this;
3806 int BC_WindowBase::find_prev_textbox(BC_WindowBase **last_textbox, BC_WindowBase **prev_textbox, int &result)
3812 if(!*last_textbox) *last_textbox = this;
3816 if(top_level->active_subwindow == this)
3822 *prev_textbox = this;
3827 // Search subwindows for textbox
3828 for(int i = subwindows->total - 1; i >= 0 && result < 2; i--)
3830 BC_WindowBase *test_subwindow = subwindows->values[i];
3831 test_subwindow->find_prev_textbox(last_textbox, prev_textbox, result);
3836 BC_Clipboard* BC_WindowBase::get_clipboard()
3838 #ifdef SINGLE_THREAD
3839 return BC_Display::display_global->clipboard;
3841 return top_level->clipboard;
3845 Atom BC_WindowBase::to_clipboard(const char *data, long len, int clipboard_num)
3847 return get_clipboard()->to_clipboard(this, data, len, clipboard_num);
3850 long BC_WindowBase::from_clipboard(char *data, long maxlen, int clipboard_num)
3852 return get_clipboard()->from_clipboard(data, maxlen, clipboard_num);
3855 long BC_WindowBase::clipboard_len(int clipboard_num)
3857 return get_clipboard()->clipboard_len(clipboard_num);
3860 int BC_WindowBase::do_selection_clear(Window win)
3862 top_level->event_win = win;
3863 return dispatch_selection_clear();
3866 int BC_WindowBase::dispatch_selection_clear()
3869 for( int i=0; i<subwindows->total && !result; ++i )
3870 result = subwindows->values[i]->dispatch_selection_clear();
3872 result = selection_clear_event();
3877 void BC_WindowBase::get_relative_cursor(int &x, int &y, int lock_window)
3879 int abs_x, abs_y, win_x, win_y;
3880 unsigned int temp_mask;
3883 if(lock_window) this->lock_window("BC_WindowBase::get_relative_cursor");
3884 XQueryPointer(top_level->display, top_level->win,
3885 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3888 XTranslateCoordinates(top_level->display, top_level->rootwin,
3889 win, abs_x, abs_y, &x, &y, &temp_win);
3890 if(lock_window) this->unlock_window();
3892 int BC_WindowBase::get_relative_cursor_x(int lock_window)
3895 get_relative_cursor(x, y, lock_window);
3898 int BC_WindowBase::get_relative_cursor_y(int lock_window)
3901 get_relative_cursor(x, y, lock_window);
3905 void BC_WindowBase::get_abs_cursor(int &abs_x, int &abs_y, int lock_window)
3908 unsigned int temp_mask;
3911 if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor");
3912 XQueryPointer(top_level->display, top_level->win,
3913 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3915 if(lock_window) this->unlock_window();
3917 int BC_WindowBase::get_abs_cursor_x(int lock_window)
3920 get_abs_cursor(abs_x, abs_y, lock_window);
3923 int BC_WindowBase::get_abs_cursor_y(int lock_window)
3926 get_abs_cursor(abs_x, abs_y, lock_window);
3930 void BC_WindowBase::get_pop_cursor(int &px, int &py, int lock_window)
3932 int xmargin = xS(100), ymargin = yS(100);
3933 get_abs_cursor(px, py, lock_window);
3934 if( px < xmargin ) px = xmargin;
3935 if( py < ymargin ) py = ymargin;
3936 int wd = get_screen_x(lock_window,-1) + get_screen_w(lock_window,-1) - xmargin;
3937 if( px > wd ) px = wd;
3938 int ht = get_screen_y(lock_window,-1) + get_screen_h(lock_window,-1) - ymargin;
3939 if( py > ht ) py = ht;
3941 int BC_WindowBase::get_pop_cursor_x(int lock_window)
3944 get_pop_cursor(px, py, lock_window);
3947 int BC_WindowBase::get_pop_cursor_y(int lock_window)
3950 get_pop_cursor(px, py, lock_window);
3954 int BC_WindowBase::match_window(Window win)
3956 if (this->win == win) return 1;
3958 for(int i = 0; i < subwindows->total; i++) {
3959 result = subwindows->values[i]->match_window(win);
3960 if (result) return result;
3966 int BC_WindowBase::get_cursor_over_window()
3968 int abs_x, abs_y, win_x, win_y;
3969 unsigned int mask_return;
3970 Window root_return, child_return;
3972 int ret = XQueryPointer(top_level->display, top_level->rootwin,
3973 &root_return, &child_return, &abs_x, &abs_y,
3974 &win_x, &win_y, &mask_return);
3975 if( ret && child_return == None ) ret = 0;
3976 if( ret && win != child_return )
3977 ret = top_level->match_window(child_return);
3978 // query pointer can return a window manager window with this top_level as a child
3979 // for kde this can be two levels deep
3980 unsigned int nchildren_return = 0;
3981 Window parent_return, *children_return = 0;
3982 Window top_win = top_level->win;
3983 while( !ret && top_win != top_level->rootwin && top_win != root_return &&
3984 XQueryTree(top_level->display, top_win, &root_return,
3985 &parent_return, &children_return, &nchildren_return) ) {
3986 if( children_return ) XFree(children_return);
3987 if( (top_win=parent_return) == child_return ) ret = 1;
3992 int BC_WindowBase::cursor_above()
3995 get_relative_cursor(rx, ry);
3996 return rx < 0 || rx >= get_w() ||
3997 ry < 0 || ry >= get_h() ? 0 : 1;
4000 int BC_WindowBase::get_drag_x()
4002 return top_level->drag_x;
4005 int BC_WindowBase::get_drag_y()
4007 return top_level->drag_y;
4010 int BC_WindowBase::get_cursor_x()
4012 return top_level->cursor_x;
4015 int BC_WindowBase::get_cursor_y()
4017 return top_level->cursor_y;
4020 int BC_WindowBase::dump_windows()
4022 printf("\tBC_WindowBase::dump_windows window=%p win=%p '%s', %dx%d+%d+%d %s\n",
4023 this, (void*)this->win, title, w,h,x,y, typeid(*this).name());
4024 for(int i = 0; i < subwindows->size(); i++)
4025 subwindows->get(i)->dump_windows();
4026 for(int i = 0; i < popups.size(); i++) {
4027 BC_WindowBase *p = popups[i];
4028 printf("\tBC_WindowBase::dump_windows popup=%p win=%p '%s', %dx%d+%d+%d %s\n",
4029 p, (void*)p->win, p->title, p->w,p->h,p->x,p->y, typeid(*p).name());
4034 int BC_WindowBase::is_event_win()
4036 return this->win == top_level->event_win;
4039 void BC_WindowBase::set_dragging(int value)
4041 is_dragging = value;
4044 int BC_WindowBase::get_dragging()
4049 int BC_WindowBase::get_buttonpress()
4051 return top_level->button_number;
4054 int BC_WindowBase::get_button_down()
4056 return top_level->button_down;
4059 int BC_WindowBase::alt_down()
4061 return top_level->alt_mask;
4064 int BC_WindowBase::shift_down()
4066 return top_level->shift_mask;
4069 int BC_WindowBase::ctrl_down()
4071 return top_level->ctrl_mask;
4074 wchr_t* BC_WindowBase::get_wkeystring(int *length)
4077 *length = top_level->wkey_string_length;
4078 return top_level->wkey_string;
4081 #ifdef X_HAVE_UTF8_STRING
4082 char* BC_WindowBase::get_keypress_utf8()
4084 return top_level->key_pressed_utf8;
4089 int BC_WindowBase::get_keypress()
4091 return top_level->key_pressed;
4094 int BC_WindowBase::get_double_click()
4096 return top_level->double_click;
4099 int BC_WindowBase::get_triple_click()
4101 return top_level->triple_click;
4104 int BC_WindowBase::get_bgcolor()
4109 int BC_WindowBase::resize_window(int w, int h)
4111 if(this->w == w && this->h == h) return 0;
4113 if(window_type == MAIN_WINDOW && !allow_resize)
4115 XSizeHints size_hints;
4116 size_hints.flags = PSize | PMinSize | PMaxSize;
4117 size_hints.width = w;
4118 size_hints.height = h;
4119 size_hints.min_width = w;
4120 size_hints.max_width = w;
4121 size_hints.min_height = h;
4122 size_hints.max_height = h;
4123 if( this->x > -BC_INFINITY && this->x < BC_INFINITY ) {
4124 size_hints.flags |= PPosition;
4125 size_hints.x = this->x;
4126 size_hints.y = this->y;
4128 XSetNormalHints(top_level->display, win, &size_hints);
4130 XResizeWindow(top_level->display, win, w, h);
4135 pixmap = new BC_Pixmap(this, w, h);
4137 // Propagate to menubar
4138 for(int i = 0; i < subwindows->total; i++)
4140 subwindows->values[i]->dispatch_resize_event(w, h);
4143 draw_background(0, 0, w, h);
4144 if(top_level == this && get_resources()->recursive_resizing)
4145 resize_history.append(new BC_ResizeCall(w, h));
4149 // The only way for resize events to be propagated is by updating the internal w and h
4150 int BC_WindowBase::resize_event(int w, int h)
4152 if(window_type == MAIN_WINDOW)
4160 int BC_WindowBase::reposition_window(int x, int y)
4162 reposition_window(x, y, -1, -1);
4167 int BC_WindowBase::reposition_window(int x, int y, int w, int h)
4171 // Some tools set their own dimensions before calling this, causing the
4172 // resize check to skip.
4176 if(w > 0 && w != this->w)
4182 if(h > 0 && h != this->h)
4188 //printf("BC_WindowBase::reposition_window %d %d %d\n", translation_count, x_correction, y_correction);
4191 printf("BC_WindowBase::reposition_window this->w == %d\n", this->w);
4193 printf("BC_WindowBase::reposition_window this->h == %d\n", this->h);
4195 if(translation_count && window_type == MAIN_WINDOW)
4197 // KDE shifts window right and down.
4198 // FVWM leaves window alone and adds border around it.
4199 XMoveResizeWindow(top_level->display, win,
4200 x - BC_DisplayInfo::auto_reposition_x,
4201 y - BC_DisplayInfo::auto_reposition_y,
4206 XMoveResizeWindow(top_level->display, win, x, y,
4213 pixmap = new BC_Pixmap(this, this->w, this->h);
4214 clear_box(0,0, this->w, this->h);
4215 // Propagate to menubar
4216 for(int i = 0; i < subwindows->total; i++)
4218 subwindows->values[i]->dispatch_resize_event(this->w, this->h);
4221 // draw_background(0, 0, w, h);
4227 int BC_WindowBase::reposition_window_relative(int dx, int dy, int w, int h)
4229 return reposition_window(get_x()+dx, get_y()+dy, w, h);
4232 int BC_WindowBase::reposition_window_relative(int dx, int dy)
4234 return reposition_window_relative(dx, dy, -1, -1);
4237 void BC_WindowBase::set_tooltips(int v)
4239 get_resources()->tooltips_enabled = v;
4242 void BC_WindowBase::set_force_tooltip(int v)
4247 int BC_WindowBase::raise_window(int do_flush)
4249 if( hidden ) return 1;
4250 if( wait_viewable(500) ) return 1;
4251 XRaiseWindow(top_level->display, win);
4252 if(do_flush) XFlush(top_level->display);
4256 int BC_WindowBase::lower_window(int do_flush)
4258 XLowerWindow(top_level->display, win);
4259 if(do_flush) XFlush(top_level->display);
4263 void BC_WindowBase::set_background(VFrame *bitmap)
4265 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
4267 bg_pixmap = new BC_Pixmap(this, bitmap, PIXMAP_OPAQUE);
4268 shared_bg_pixmap = 0;
4269 draw_background(0, 0, w, h);
4272 void BC_WindowBase::put_title(const char *text)
4274 char *cp = this->title, *ep = cp+sizeof(this->title)-1;
4275 for( const unsigned char *bp = (const unsigned char *)text; *bp && cp<ep; ++bp )
4276 *cp++ = *bp >= ' ' ? *bp : ' ';
4280 void BC_WindowBase::set_title(const char *text, int utf8)
4282 // utf8>0: wm + net_wm, utf8=0: wm only, utf<0: net_wm only
4284 const unsigned char *wm_title = (const unsigned char *)title;
4285 int title_len = strlen((const char *)title);
4287 Atom xa_wm_name = XA_WM_NAME;
4288 Atom xa_icon_name = XA_WM_ICON_NAME;
4289 Atom xa_string = XA_STRING;
4290 XChangeProperty(display, win, xa_wm_name, xa_string, 8,
4291 PropModeReplace, wm_title, title_len);
4292 XChangeProperty(display, win, xa_icon_name, xa_string, 8,
4293 PropModeReplace, wm_title, title_len);
4296 Atom xa_net_wm_name = XInternAtom(display, "_NET_WM_NAME", True);
4297 Atom xa_net_icon_name = XInternAtom(display, "_NET_WM_ICON_NAME", True);
4298 Atom xa_utf8_string = XInternAtom(display, "UTF8_STRING", True);
4299 XChangeProperty(display, win, xa_net_wm_name, xa_utf8_string, 8,
4300 PropModeReplace, wm_title, title_len);
4301 XChangeProperty(display, win, xa_net_icon_name, xa_utf8_string, 8,
4302 PropModeReplace, wm_title, title_len);
4308 void BC_WindowBase::set_net_icon(VFrame *data)
4310 int width = data->get_w(), height = data->get_h();
4311 int size = 2 + width * height;
4312 unsigned long *icon_data = new unsigned long[size];
4313 unsigned long *lp = icon_data;
4314 *lp++ = width; *lp++ = height;
4315 uint8_t **rows = data->get_rows();
4316 for( int y=0; y<height; ++y ) {
4317 unsigned *up = (unsigned *)rows[y];
4318 for( int x=0; x<width; ++x )
4319 *lp++ = *(unsigned *)up++;
4321 Atom NetWMIcon = XInternAtom(display, "_NET_WM_ICON", True);
4322 XChangeProperty(top_level->display, top_level->win, NetWMIcon,
4323 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)icon_data, size);
4324 delete [] icon_data;
4327 const char *BC_WindowBase::get_title()
4332 int BC_WindowBase::get_toggle_value()
4334 return toggle_value;
4337 int BC_WindowBase::get_toggle_drag()
4342 int BC_WindowBase::set_icon(VFrame *data)
4344 if(icon_pixmap) delete icon_pixmap;
4345 icon_pixmap = new BC_Pixmap(top_level, data, PIXMAP_ALPHA, 1);
4347 if(icon_window) delete icon_window;
4348 icon_window = new BC_Popup(this, 0, 0,
4349 icon_pixmap->get_w(), icon_pixmap->get_h(),
4350 -1, 1, // All windows are hidden initially
4353 XWMHints wm_hints; memset(&wm_hints, 0, sizeof(wm_hints));
4354 wm_hints.flags = IconPixmapHint; // | IconMaskHint | IconWindowHint;
4355 wm_hints.icon_pixmap = icon_pixmap->get_pixmap();
4356 wm_hints.icon_mask = icon_pixmap->get_alpha();
4357 wm_hints.icon_window = icon_window->win;
4358 if( XGroupLeader ) {
4359 wm_hints.flags |= WindowGroupHint;
4360 wm_hints.window_group = XGroupLeader;
4363 // for(int i = 0; i < 1000; i++)
4364 // printf("02x ", icon_pixmap->get_alpha()->get_row_pointers()[0][i]);
4367 XSetWMHints(top_level->display, top_level->win, &wm_hints);
4370 XSync(top_level->display, 0);
4374 void BC_WindowBase::init_resources(float scale)
4376 if( resources ) return;
4378 const char *env = getenv("BC_SCALE");
4379 if( env ) scale = atof(env);
4380 float x_scale = 1, y_scale = 1;
4382 BC_DisplayInfo info;
4384 int cins = info.xinerama_big_screen();
4385 if( !info.xinerama_geometry(cins, wx, wy, ww, wh) ) {
4386 int sh = ww * 9 / 16;
4387 int sw = wh * 16 / 9;
4388 if( sw < ww ) ww = sw;
4389 if( sh < wh ) wh = sh;
4390 if( (x_scale = ww/1920.) < 1 ) x_scale = 1;
4391 if( (y_scale = wh/1080.) < 1 ) y_scale = 1;
4395 x_scale = y_scale = scale;
4396 // constructor sets BC_WindowBase::resources
4397 new BC_Resources(x_scale, y_scale);
4399 void BC_WindowBase::finit_resources()
4401 delete resources; resources = 0;
4404 int BC_WindowBase::set_w(int w)
4410 int BC_WindowBase::set_h(int h)
4416 int BC_WindowBase::load_defaults(BC_Hash *defaults)
4418 char string[BCTEXTLEN];
4419 int newest_id = - 1;
4420 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4422 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4423 resources->filebox_history[i].path[0] = 0;
4424 defaults->get(string, resources->filebox_history[i].path);
4425 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4426 resources->filebox_history[i].id = defaults->get(string, resources->get_id());
4427 if(resources->filebox_history[i].id > newest_id)
4428 newest_id = resources->filebox_history[i].id;
4431 resources->filebox_id = newest_id + 1;
4432 resources->filebox_mode = defaults->get("FILEBOX_MODE", get_resources()->filebox_mode);
4433 resources->filebox_w = defaults->get("FILEBOX_W", get_resources()->filebox_w);
4434 resources->filebox_h = defaults->get("FILEBOX_H", get_resources()->filebox_h);
4435 resources->filebox_columntype[0] = defaults->get("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4436 resources->filebox_columntype[1] = defaults->get("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4437 resources->filebox_columntype[2] = defaults->get("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4438 resources->filebox_columntype[3] = defaults->get("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4439 resources->filebox_columnwidth[0] = defaults->get("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4440 resources->filebox_columnwidth[1] = defaults->get("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4441 resources->filebox_columnwidth[2] = defaults->get("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4442 resources->filebox_columnwidth[3] = defaults->get("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4443 resources->filebox_size_format = defaults->get("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4444 defaults->get("FILEBOX_FILTER", resources->filebox_filter);
4448 int BC_WindowBase::save_defaults(BC_Hash *defaults)
4450 char string[BCTEXTLEN];
4451 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4453 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4454 defaults->update(string, resources->filebox_history[i].path);
4455 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4456 defaults->update(string, resources->filebox_history[i].id);
4458 defaults->update("FILEBOX_MODE", resources->filebox_mode);
4459 defaults->update("FILEBOX_W", resources->filebox_w);
4460 defaults->update("FILEBOX_H", resources->filebox_h);
4461 defaults->update("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4462 defaults->update("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4463 defaults->update("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4464 defaults->update("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4465 defaults->update("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4466 defaults->update("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4467 defaults->update("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4468 defaults->update("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4469 defaults->update("FILEBOX_FILTER", resources->filebox_filter);
4470 defaults->update("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4476 // For some reason XTranslateCoordinates can take a long time to return.
4477 // We work around this by only calling it when the event windows are different.
4478 void BC_WindowBase::translate_coordinates(Window src_w, Window dest_w,
4479 int src_x, int src_y, int *dest_x_return, int *dest_y_return)
4486 *dest_x_return = src_x;
4487 *dest_y_return = src_y;
4491 XTranslateCoordinates(top_level->display, src_w, dest_w,
4492 src_x, src_y, dest_x_return, dest_y_return, &tempwin);
4493 //printf("BC_WindowBase::translate_coordinates 1 %lld\n", timer.get_difference());
4497 void BC_WindowBase::get_root_coordinates(int x, int y, int *abs_x, int *abs_y)
4499 translate_coordinates(win, top_level->rootwin, x, y, abs_x, abs_y);
4502 void BC_WindowBase::get_win_coordinates(int abs_x, int abs_y, int *x, int *y)
4504 translate_coordinates(top_level->rootwin, win, abs_x, abs_y, x, y);
4508 #ifdef HAVE_LIBXXF86VM
4509 void BC_WindowBase::closest_vm(int *vm, int *width, int *height)
4513 if(XF86VidModeQueryExtension(top_level->display,&foo,&bar)) {
4515 XF86VidModeModeInfo **vm_modelines;
4516 XF86VidModeGetAllModeLines(top_level->display,
4517 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4518 for( i = 0; i < vm_count; i++ ) {
4519 if( vm_modelines[i]->hdisplay < vm_modelines[*vm]->hdisplay &&
4520 vm_modelines[i]->hdisplay >= *width )
4523 display = top_level->display;
4524 if( vm_modelines[*vm]->hdisplay == *width )
4527 *width = vm_modelines[*vm]->hdisplay;
4528 *height = vm_modelines[*vm]->vdisplay;
4533 void BC_WindowBase::scale_vm(int vm)
4535 int foo,bar,dotclock;
4536 if( XF86VidModeQueryExtension(top_level->display,&foo,&bar) ) {
4538 XF86VidModeModeInfo **vm_modelines;
4539 XF86VidModeModeLine vml;
4540 XF86VidModeGetAllModeLines(top_level->display,
4541 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4542 XF86VidModeGetModeLine(top_level->display,
4543 XDefaultScreen(top_level->display), &dotclock,&vml);
4544 orig_modeline.dotclock = dotclock;
4545 orig_modeline.hdisplay = vml.hdisplay;
4546 orig_modeline.hsyncstart = vml.hsyncstart;
4547 orig_modeline.hsyncend = vml.hsyncend;
4548 orig_modeline.htotal = vml.htotal;
4549 orig_modeline.vdisplay = vml.vdisplay;
4550 orig_modeline.vsyncstart = vml.vsyncstart;
4551 orig_modeline.vsyncend = vml.vsyncend;
4552 orig_modeline.vtotal = vml.vtotal;
4553 orig_modeline.flags = vml.flags;
4554 orig_modeline.privsize = vml.privsize;
4555 // orig_modeline.private = vml.private;
4556 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),vm_modelines[vm]);
4557 XF86VidModeSetViewPort(top_level->display,XDefaultScreen(top_level->display),0,0);
4558 XFlush(top_level->display);
4562 void BC_WindowBase::restore_vm()
4564 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),&orig_modeline);
4565 XFlush(top_level->display);
4570 #ifndef SINGLE_THREAD
4571 int BC_WindowBase::get_event_count()
4573 event_lock->lock("BC_WindowBase::get_event_count");
4574 int result = common_events.total;
4575 event_lock->unlock();
4579 XEvent* BC_WindowBase::get_event()
4582 while(!done && !result)
4584 event_condition->lock("BC_WindowBase::get_event");
4585 event_lock->lock("BC_WindowBase::get_event");
4587 if(common_events.total && !done)
4589 result = common_events.values[0];
4590 common_events.remove_number(0);
4593 event_lock->unlock();
4598 void BC_WindowBase::put_event(XEvent *event)
4600 event_lock->lock("BC_WindowBase::put_event");
4601 common_events.append(event);
4602 event_lock->unlock();
4603 event_condition->unlock();
4606 void BC_WindowBase::dequeue_events(Window win)
4608 event_lock->lock("BC_WindowBase::dequeue_events");
4610 int out = 0, total = common_events.size();
4611 for( int in=0; in<total; ++in ) {
4612 if( common_events[in]->xany.window == win ) continue;
4613 common_events[out++] = common_events[in];
4615 common_events.total = out;
4617 event_lock->unlock();
4620 int BC_WindowBase::resend_event(BC_WindowBase *window)
4622 if( resend_event_window ) return 1;
4623 resend_event_window = window;
4629 int BC_WindowBase::resend_event(BC_WindowBase *window)
4634 #endif // SINGLE_THREAD
4636 int BC_WindowBase::get_id()
4642 BC_Pixmap *BC_WindowBase::create_pixmap(VFrame *vframe)
4644 int w = vframe->get_w(), h = vframe->get_h();
4645 BC_Pixmap *icon = new BC_Pixmap(this, w, h);
4646 icon->draw_vframe(vframe, 0,0, w,h, 0,0);
4651 void BC_WindowBase::flicker(int n, int ms)
4653 int color = get_bg_color();
4654 for( int i=2*n; --i>=0; ) {
4655 set_inverse(); set_bg_color(WHITE);
4656 clear_box(0,0, w,h); flash(1);
4657 sync_display(); Timer::delay(ms);
4659 set_bg_color(color);
4663 void BC_WindowBase::focus()
4665 XWindowAttributes xwa;
4666 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4667 if( xwa.map_state == IsViewable )
4668 XSetInputFocus(top_level->display, top_level->win, RevertToParent, CurrentTime);
4671 int BC_WindowBase::wait_viewable(int ms)
4674 XWindowAttributes xwa;
4676 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4677 if( xwa.map_state == IsViewable ) return 0;
4679 } while( timer.get_difference() < ms );