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");
967 active_grab->lock_window("BC_WindowBase::dispatch_event 3");
968 result = active_grab->grab_event(event);
969 active_grab->unlock_window();
972 if( result ) return result;
973 lock_window("BC_WindowBase::dispatch_event 4");
976 switch(event->type) {
978 // Clear the resize buffer
980 dispatch_resize_event(last_resize_w, last_resize_h);
981 // Clear the motion buffer since this can clear the window
983 dispatch_motion_event();
985 ptr = (XClientMessageEvent*)event;
986 if( ptr->message_type == ProtoXAtom &&
987 (Atom)ptr->data.l[0] == DelWinXAtom ) {
990 else if( ptr->message_type == RepeaterXAtom ) {
991 dispatch_repeat_event(ptr->data.l[0]);
993 else if( ptr->message_type == SetDoneXAtom ) {
997 receive_custom_xatoms((xatom_event *)ptr);
1003 dispatch_focus_in();
1008 dispatch_focus_out();
1022 dispatch_motion_event();
1024 get_key_masks(event->xbutton.state);
1025 cursor_x = event->xbutton.x;
1026 cursor_y = event->xbutton.y;
1027 button_number = event->xbutton.button;
1029 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1030 event_win = event->xany.window;
1031 if( button_number < 6 ) {
1032 if( button_number < 4 )
1034 button_pressed = event->xbutton.button;
1035 button_time1 = button_time2;
1036 button_time2 = button_time3;
1037 button_time3 = event->xbutton.time;
1040 drag_win = event_win;
1041 drag_x1 = cursor_x - get_resources()->drag_radius;
1042 drag_x2 = cursor_x + get_resources()->drag_radius;
1043 drag_y1 = cursor_y - get_resources()->drag_radius;
1044 drag_y2 = cursor_y + get_resources()->drag_radius;
1045 if( button_number < 4 ) {
1046 if((long)(button_time3 - button_time1) < resources->double_click * 2) {
1048 button_time3 = button_time2 = button_time1 = 0;
1050 if((long)(button_time3 - button_time2) < resources->double_click) {
1052 // button_time3 = button_time2 = button_time1 = 0;
1059 dispatch_button_press();
1066 dispatch_motion_event();
1068 get_key_masks(event->xbutton.state);
1069 button_number = event->xbutton.button;
1070 event_win = event->xany.window;
1071 if (button_number < 6)
1073 if(button_number < 4)
1075 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1077 dispatch_button_release();
1082 event_win = event->xany.window;
1084 for( int i=0; !result && i<popups.size(); ++i ) { // popups take focus
1085 if( popups[i]->win == event_win )
1086 result = popups[i]->dispatch_expose_event();
1089 result = dispatch_expose_event();
1093 get_key_masks(event->xmotion.state);
1094 // Dispatch previous motion event if this is a subsequent motion from a different window
1095 if(motion_events && last_motion_win != event->xany.window)
1097 dispatch_motion_event();
1100 // Buffer the current motion
1102 last_motion_state = event->xmotion.state;
1103 last_motion_x = event->xmotion.x;
1104 last_motion_y = event->xmotion.y;
1105 last_motion_win = event->xany.window;
1108 case ConfigureNotify:
1109 // printf("BC_WindowBase::dispatch_event %d win=%p this->win=%p\n",
1111 // event->xany.window,
1114 XTranslateCoordinates(top_level->display,
1122 last_resize_w = event->xconfigure.width;
1123 last_resize_h = event->xconfigure.height;
1126 cancel_translation = 0;
1128 // Resize history prevents responses to recursive resize requests
1129 for(int i = 0; i < resize_history.total && !cancel_resize; i++)
1131 if(resize_history.values[i]->w == last_resize_w &&
1132 resize_history.values[i]->h == last_resize_h)
1134 delete resize_history.values[i];
1135 resize_history.remove_number(i);
1140 if(last_resize_w == w && last_resize_h == h)
1148 if((last_translate_x == x && last_translate_y == y))
1149 cancel_translation = 1;
1151 if(!cancel_translation)
1153 translation_events = 1;
1156 translation_count++;
1160 get_key_masks(event->xkey.state);
1161 keys_return[0] = 0; keysym = -1;
1162 if(XFilterEvent(event, win)) {
1165 if( keysym_lookup(event) < 0 ) {
1166 printf("keysym %x\n", (uint32_t)keysym);
1170 //printf("BC_WindowBase::dispatch_event %d keysym=0x%x\n",
1174 // block out control keys
1175 if(keysym > 0xffe0 && keysym < 0xffff) break;
1176 // block out Alt_GR key
1177 if(keysym == 0xfe03) break;
1180 printf("BC_WindowBase::dispatch_event %x\n", (uint32_t)keysym);
1182 #ifdef X_HAVE_UTF8_STRING
1183 //It's Ascii or UTF8?
1184 // if (keysym != 0xffff && (keys_return[0] & 0xff) >= 0x7f )
1185 //printf("BC_WindowBase::dispatch_event %d %02x%02x\n", __LINE__, keys_return[0], keys_return[1]);
1187 if( ((keys_return[1] & 0xff) > 0x80) &&
1188 ((keys_return[0] & 0xff) > 0xC0) ) {
1189 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1190 key_pressed = keysym & 0xff;
1194 // shuttle speed codes
1195 if( keysym >= SKEY_MIN && keysym <= SKEY_MAX ) {
1196 key_pressed = keysym;
1198 else switch( keysym ) {
1199 // block out extra keys
1209 // Translate key codes
1210 case XK_Return: key_pressed = RETURN; break;
1211 case XK_Up: key_pressed = UP; break;
1212 case XK_Down: key_pressed = DOWN; break;
1213 case XK_Left: key_pressed = LEFT; break;
1214 case XK_Right: key_pressed = RIGHT; break;
1215 case XK_Next: key_pressed = PGDN; break;
1216 case XK_Prior: key_pressed = PGUP; break;
1217 case XK_BackSpace: key_pressed = BACKSPACE; break;
1218 case XK_Escape: key_pressed = ESC; break;
1221 key_pressed = LEFTTAB;
1225 case XK_ISO_Left_Tab: key_pressed = LEFTTAB; break;
1226 case XK_underscore: key_pressed = '_'; break;
1227 case XK_asciitilde: key_pressed = '~'; break;
1228 case XK_Delete: key_pressed = DELETE; break;
1229 case XK_Home: key_pressed = HOME; break;
1230 case XK_End: key_pressed = END; break;
1233 case XK_KP_Enter: key_pressed = KPENTER; break;
1234 case XK_KP_Add: key_pressed = KPPLUS; break;
1235 case XK_KP_Subtract: key_pressed = KPMINUS; break;
1236 case XK_KP_Multiply: key_pressed = KPSTAR; break;
1237 case XK_KP_Divide: key_pressed = KPSLASH; break;
1239 case XK_KP_End: key_pressed = KP1; break;
1241 case XK_KP_Down: key_pressed = KP2; break;
1243 case XK_KP_Page_Down: key_pressed = KP3; break;
1245 case XK_KP_Left: key_pressed = KP4; break;
1247 case XK_KP_Begin: key_pressed = KP5; break;
1249 case XK_KP_Right: key_pressed = KP6; break;
1251 case XK_KP_Home: key_pressed = KP7; break;
1253 case XK_KP_Up: key_pressed = KP8; break;
1255 case XK_KP_Page_Up: key_pressed = KP9; break;
1257 case XK_KP_Insert: key_pressed = KPINS; break;
1259 case XK_KP_Delete: key_pressed = KPDEL; break;
1261 case XK_F1: key_pressed = KEY_F1; break;
1262 case XK_F2: key_pressed = KEY_F2; break;
1263 case XK_F3: key_pressed = KEY_F3; break;
1264 case XK_F4: key_pressed = KEY_F4; break;
1265 case XK_F5: key_pressed = KEY_F5; break;
1266 case XK_F6: key_pressed = KEY_F6; break;
1267 case XK_F7: key_pressed = KEY_F7; break;
1268 case XK_F8: key_pressed = KEY_F8; break;
1269 case XK_F9: key_pressed = KEY_F9; break;
1270 case XK_F10: key_pressed = KEY_F10; break;
1271 case XK_F11: key_pressed = KEY_F11; break;
1272 case XK_F12: key_pressed = KEY_F12; break;
1274 case XK_Menu: key_pressed = KPMENU; break; /* menu */
1277 key_pressed = keysym & 0xff;
1278 #ifdef X_HAVE_UTF8_STRING
1279 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1284 #ifdef X_HAVE_UTF8_STRING
1286 key_pressed_utf8 = keys_return;
1291 if( top_level == this )
1292 result = BC_KeyboardHandler::run_listeners(this);
1294 //printf("BC_WindowBase::dispatch_event %d %d %x\n", shift_down(), alt_down(), key_pressed);
1296 result = dispatch_keypress_event();
1297 // Handle some default keypresses
1300 if(key_pressed == 'w' ||
1309 XLookupString((XKeyEvent*)event, keys_return, 1, &keysym, 0);
1310 dispatch_keyrelease_event();
1311 // printf("BC_WindowBase::dispatch_event KeyRelease keysym=0x%x keystate=0x%lld\n",
1312 // keysym, event->xkey.state);
1316 if( event->xcrossing.mode != NotifyNormal ) break;
1318 event_win = event->xany.window;
1319 dispatch_cursor_leave();
1323 if( event->xcrossing.mode != NotifyNormal ) break;
1325 if( !cursor_entered ) {
1326 for( int i=0; i<popups.size(); ++i ) { // popups always take focus
1327 if( popups[i]->win == event->xcrossing.window )
1330 if( !cursor_entered && get_resources()->grab_input_focus &&
1331 !event->xcrossing.focus && event->xcrossing.window == win ) {
1334 if( cursor_entered )
1337 event_win = event->xany.window;
1338 cursor_x = event->xcrossing.x;
1339 cursor_y = event->xcrossing.y;
1340 dispatch_cursor_enter();
1346 //printf("100 %s %p %d\n", title, event, event->type);
1347 //if(event->type != ClientMessage) dump();
1349 #ifndef SINGLE_THREAD
1352 if( resend_event_window ) {
1353 resend_event_window->put_event(event);
1354 resend_event_window = 0;
1360 // if(done) completion_lock->unlock();
1363 if(debug) printf("BC_WindowBase::dispatch_event this=%p %d\n", this, __LINE__);
1367 int BC_WindowBase::dispatch_expose_event()
1370 for(int i = 0; i < subwindows->total && !result; i++)
1372 result = subwindows->values[i]->dispatch_expose_event();
1375 // Propagate to user
1376 if(!result) expose_event();
1380 int BC_WindowBase::dispatch_resize_event(int w, int h)
1382 // Can't store new w and h until the event is handles
1383 // because bcfilebox depends on the old w and h to
1384 // reposition widgets.
1385 if( window_type == MAIN_WINDOW ) {
1390 pixmap = new BC_Pixmap(this, w, h);
1391 clear_box(0, 0, w, h);
1394 // Propagate to subwindows
1395 for(int i = 0; i < subwindows->total; i++) {
1396 subwindows->values[i]->dispatch_resize_event(w, h);
1399 // Propagate to user
1402 if( window_type == MAIN_WINDOW ) {
1411 int BC_WindowBase::dispatch_flash()
1414 for(int i = 0; i < subwindows->total; i++)
1415 subwindows->values[i]->dispatch_flash();
1419 int BC_WindowBase::dispatch_translation_event()
1421 translation_events = 0;
1422 if(window_type == MAIN_WINDOW)
1426 x = last_translate_x;
1427 y = last_translate_y;
1428 // Correct for window manager offsets
1433 for(int i = 0; i < subwindows->total; i++)
1435 subwindows->values[i]->dispatch_translation_event();
1438 translation_event();
1442 int BC_WindowBase::dispatch_motion_event()
1447 if(top_level == this)
1450 event_win = last_motion_win;
1451 get_key_masks(last_motion_state);
1454 if(get_button_down() && !active_menubar && !active_popup_menu)
1458 cursor_x = last_motion_x;
1459 cursor_y = last_motion_y;
1460 result = dispatch_drag_motion();
1464 (last_motion_x < drag_x1 || last_motion_x >= drag_x2 ||
1465 last_motion_y < drag_y1 || last_motion_y >= drag_y2))
1470 result = dispatch_drag_start();
1474 cursor_x = last_motion_x;
1475 cursor_y = last_motion_y;
1477 // printf("BC_WindowBase::dispatch_motion_event %d %p %p %p\n",
1480 // active_popup_menu,
1481 // active_subwindow);
1483 if(active_menubar && !result) result = active_menubar->dispatch_motion_event();
1484 if(active_popup_menu && !result) result = active_popup_menu->dispatch_motion_event();
1485 if(active_subwindow && !result) result = active_subwindow->dispatch_motion_event();
1488 // Dispatch in stacking order
1489 for(int i = subwindows->size() - 1; i >= 0 && !result; i--)
1491 result = subwindows->values[i]->dispatch_motion_event();
1494 if(!result) result = cursor_motion_event(); // give to user
1498 int BC_WindowBase::dispatch_keypress_event()
1501 if(top_level == this)
1503 if(active_subwindow) result = active_subwindow->dispatch_keypress_event();
1506 for(int i = 0; i < subwindows->total && !result; i++)
1508 result = subwindows->values[i]->dispatch_keypress_event();
1511 if(!result) result = keypress_event();
1516 int BC_WindowBase::dispatch_keyrelease_event()
1519 if(top_level == this)
1521 if(active_subwindow) result = active_subwindow->dispatch_keyrelease_event();
1524 for(int i = 0; i < subwindows->total && !result; i++)
1526 result = subwindows->values[i]->dispatch_keyrelease_event();
1529 if(!result) result = keyrelease_event();
1534 int BC_WindowBase::dispatch_focus_in()
1536 for(int i = 0; i < subwindows->total; i++)
1538 subwindows->values[i]->dispatch_focus_in();
1546 int BC_WindowBase::dispatch_focus_out()
1548 for(int i = 0; i < subwindows->total; i++)
1550 subwindows->values[i]->dispatch_focus_out();
1558 int BC_WindowBase::get_has_focus()
1560 return top_level->has_focus;
1563 int BC_WindowBase::get_deleting()
1565 if(is_deleting) return 1;
1566 if(parent_window && parent_window->get_deleting()) return 1;
1570 int BC_WindowBase::dispatch_button_press()
1575 if(top_level == this)
1577 if(active_menubar) result = active_menubar->dispatch_button_press();
1578 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_press();
1579 if(active_subwindow && !result) result = active_subwindow->dispatch_button_press();
1582 for(int i = 0; i < subwindows->total && !result; i++)
1584 result = subwindows->values[i]->dispatch_button_press();
1587 if(!result) result = button_press_event();
1593 int BC_WindowBase::dispatch_button_release()
1596 if(top_level == this)
1598 if(active_menubar) result = active_menubar->dispatch_button_release();
1599 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_release();
1600 if(active_subwindow && !result) result = active_subwindow->dispatch_button_release();
1601 if(!result && button_number != 4 && button_number != 5)
1602 result = dispatch_drag_stop();
1605 for(int i = 0; i < subwindows->total && !result; i++)
1607 result = subwindows->values[i]->dispatch_button_release();
1612 result = button_release_event();
1619 int BC_WindowBase::dispatch_repeat_event(int64_t duration)
1622 // all repeat event handlers get called and decide based on activity and duration
1623 // whether to respond
1624 for(int i = 0; i < subwindows->total; i++)
1626 subwindows->values[i]->dispatch_repeat_event(duration);
1630 repeat_event(duration);
1634 // Unlock next repeat signal
1635 if(window_type == MAIN_WINDOW)
1637 #ifdef SINGLE_THREAD
1638 BC_Display::display_global->unlock_repeaters(duration);
1640 for(int i = 0; i < repeaters.total; i++)
1642 if(repeaters.values[i]->delay == duration)
1644 repeaters.values[i]->repeat_lock->unlock();
1652 void BC_WindowBase::unhide_cursor()
1657 if(top_level->is_hourglass)
1658 set_cursor(HOURGLASS_CURSOR, 1, 0);
1660 set_cursor(current_cursor, 1, 0);
1662 cursor_timer->update();
1666 void BC_WindowBase::update_video_cursor()
1668 if(video_on && !is_transparent)
1670 if(cursor_timer->get_difference() > VIDEO_CURSOR_TIMEOUT && !is_transparent)
1673 set_cursor(TRANSPARENT_CURSOR, 1, 1);
1674 cursor_timer->update();
1679 cursor_timer->update();
1684 int BC_WindowBase::dispatch_cursor_leave()
1688 for(int i = 0; i < subwindows->total; i++)
1690 subwindows->values[i]->dispatch_cursor_leave();
1693 cursor_leave_event();
1697 int BC_WindowBase::dispatch_cursor_enter()
1703 if(active_menubar) result = active_menubar->dispatch_cursor_enter();
1704 if(!result && active_popup_menu) result = active_popup_menu->dispatch_cursor_enter();
1705 if(!result && active_subwindow) result = active_subwindow->dispatch_cursor_enter();
1707 for(int i = 0; !result && i < subwindows->total; i++)
1709 result = subwindows->values[i]->dispatch_cursor_enter();
1712 if(!result) result = cursor_enter_event();
1716 int BC_WindowBase::cursor_enter_event()
1721 int BC_WindowBase::cursor_leave_event()
1726 int BC_WindowBase::close_event()
1732 int BC_WindowBase::dispatch_drag_start()
1735 if(active_menubar) result = active_menubar->dispatch_drag_start();
1736 if(!result && active_popup_menu) result = active_popup_menu->dispatch_drag_start();
1737 if(!result && active_subwindow) result = active_subwindow->dispatch_drag_start();
1739 for(int i = 0; i < subwindows->total && !result; i++)
1741 result = subwindows->values[i]->dispatch_drag_start();
1744 if(!result) result = is_dragging = drag_start_event();
1748 int BC_WindowBase::dispatch_drag_stop()
1752 for(int i = 0; i < subwindows->total && !result; i++)
1754 result = subwindows->values[i]->dispatch_drag_stop();
1757 if(is_dragging && !result)
1767 int BC_WindowBase::dispatch_drag_motion()
1770 for(int i = 0; i < subwindows->total && !result; i++)
1772 result = subwindows->values[i]->dispatch_drag_motion();
1775 if(is_dragging && !result)
1777 drag_motion_event();
1785 int BC_WindowBase::show_tooltip(const char *text, int x, int y, int w, int h)
1788 int forced = !text ? force_tooltip : 1;
1789 if( !text ) text = tooltip_text;
1790 if( !text || (!forced && !get_resources()->tooltips_enabled) ) {
1791 top_level->hide_tooltip();
1795 if(w < 0) w = get_text_width(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1796 if(h < 0) h = get_text_height(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1797 // default x,y (win relative)
1798 if( x < 0 ) x = get_w();
1799 if( y < 0 ) y = get_h();
1801 get_root_coordinates(x, y, &wx, &wy);
1802 // keep the tip inside the window/display
1803 int x0 = top_level->get_x(), x1 = x0 + top_level->get_w();
1804 int x2 = top_level->get_screen_x(0, -1) + top_level->get_screen_w(0, -1);
1805 if( x1 > x2 ) x1 = x2;
1806 if( wx < x0 ) wx = x0;
1807 if( wx >= (x1-=w) ) wx = x1;
1808 int y0 = top_level->get_y(), y1 = y0 + top_level->get_h();
1809 int y2 = top_level->get_root_h(0);
1810 if( y1 > y2 ) y1 = y2;
1811 if( wy < y0 ) wy = y0;
1812 if( wy >= (y1-=h) ) wy = y1;
1813 // avoid tip under cursor (flickers)
1815 get_abs_cursor(abs_x,abs_y, 0);
1816 if( wx < abs_x && abs_x < wx+w && wy < abs_y && abs_y < wy+h ) {
1817 if( wx-abs_x < wy-abs_y )
1824 tooltip_popup = new BC_Popup(top_level, wx, wy, w, h,
1825 get_resources()->tooltip_bg_color);
1828 tooltip_popup->reposition_window(wx, wy, w, h);
1831 tooltip_popup->flash();
1832 tooltip_popup->flush();
1836 int BC_WindowBase::hide_tooltip()
1839 for(int i = 0; i < subwindows->total; i++)
1841 subwindows->values[i]->hide_tooltip();
1847 delete tooltip_popup;
1853 const char *BC_WindowBase::get_tooltip()
1855 return tooltip_text;
1858 int BC_WindowBase::set_tooltip(const char *text)
1860 tooltip_text = text;
1862 // Update existing tooltip if it is visible
1866 tooltip_popup->flash();
1870 // signal the event handler to repeat
1871 int BC_WindowBase::set_repeat(int64_t duration)
1875 printf("BC_WindowBase::set_repeat duration=%jd\n", duration);
1878 if(window_type != MAIN_WINDOW) return top_level->set_repeat(duration);
1880 #ifdef SINGLE_THREAD
1881 BC_Display::display_global->set_repeat(this, duration);
1883 // test repeater database for duplicates
1884 for(int i = 0; i < repeaters.total; i++)
1887 if(repeaters.values[i]->delay == duration)
1889 repeaters.values[i]->start_repeating(this);
1894 BC_Repeater *repeater = new BC_Repeater(this, duration);
1895 repeater->initialize();
1896 repeaters.append(repeater);
1897 repeater->start_repeating();
1902 int BC_WindowBase::unset_repeat(int64_t duration)
1904 if(window_type != MAIN_WINDOW) return top_level->unset_repeat(duration);
1906 #ifdef SINGLE_THREAD
1907 BC_Display::display_global->unset_repeat(this, duration);
1909 for(int i = 0; i < repeaters.total; i++)
1911 if(repeaters.values[i]->delay == duration)
1913 repeaters.values[i]->stop_repeating();
1921 int BC_WindowBase::unset_all_repeaters()
1923 #ifdef SINGLE_THREAD
1924 BC_Display::display_global->unset_all_repeaters(this);
1926 for(int i = 0; i < repeaters.total; i++)
1928 repeaters.values[i]->stop_repeating();
1930 repeaters.remove_all_objects();
1935 // long BC_WindowBase::get_repeat_id()
1937 // return top_level->next_repeat_id++;
1940 XEvent *BC_WindowBase::new_xevent()
1942 XEvent *event = new XEvent;
1943 memset(event, 0, sizeof(*event));
1947 #ifndef SINGLE_THREAD
1948 int BC_WindowBase::arm_repeat(int64_t duration)
1950 XEvent *event = new_xevent();
1951 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
1952 ptr->type = ClientMessage;
1953 ptr->message_type = RepeaterXAtom;
1955 ptr->data.l[0] = duration;
1957 // Couldn't use XSendEvent since it locked up randomly.
1963 int BC_WindowBase::receive_custom_xatoms(xatom_event *event)
1968 int BC_WindowBase::send_custom_xatom(xatom_event *event)
1970 #ifndef SINGLE_THREAD
1971 XEvent *myevent = new_xevent();
1972 XClientMessageEvent *ptr = (XClientMessageEvent*)myevent;
1973 ptr->type = ClientMessage;
1974 ptr->message_type = event->message_type;
1975 ptr->format = event->format;
1976 ptr->data.l[0] = event->data.l[0];
1977 ptr->data.l[1] = event->data.l[1];
1978 ptr->data.l[2] = event->data.l[2];
1979 ptr->data.l[3] = event->data.l[3];
1980 ptr->data.l[4] = event->data.l[4];
1989 Atom BC_WindowBase::create_xatom(const char *atom_name)
1991 return XInternAtom(display, atom_name, False);
1994 int BC_WindowBase::get_atoms()
1996 SetDoneXAtom = XInternAtom(display, "BC_REPEAT_EVENT", False);
1997 RepeaterXAtom = XInternAtom(display, "BC_CLOSE_EVENT", False);
1998 DestroyAtom = XInternAtom(display, "BC_DESTROY_WINDOW", False);
1999 DelWinXAtom = XInternAtom(display, "WM_DELETE_WINDOW", False);
2000 if( (ProtoXAtom = XInternAtom(display, "WM_PROTOCOLS", False)) != 0 )
2001 XChangeProperty(display, win, ProtoXAtom, XA_ATOM, 32,
2002 PropModeReplace, (unsigned char *)&DelWinXAtom, True);
2008 void BC_WindowBase::init_cursors()
2010 arrow_cursor = XCreateFontCursor(display, XC_top_left_arrow);
2011 cross_cursor = XCreateFontCursor(display, XC_crosshair);
2012 ibeam_cursor = XCreateFontCursor(display, XC_xterm);
2013 vseparate_cursor = XCreateFontCursor(display, XC_sb_v_double_arrow);
2014 hseparate_cursor = XCreateFontCursor(display, XC_sb_h_double_arrow);
2015 move_cursor = XCreateFontCursor(display, XC_fleur);
2016 left_cursor = XCreateFontCursor(display, XC_sb_left_arrow);
2017 right_cursor = XCreateFontCursor(display, XC_sb_right_arrow);
2018 upright_arrow_cursor = XCreateFontCursor(display, XC_arrow);
2019 upleft_resize_cursor = XCreateFontCursor(display, XC_top_left_corner);
2020 upright_resize_cursor = XCreateFontCursor(display, XC_top_right_corner);
2021 downleft_resize_cursor = XCreateFontCursor(display, XC_bottom_left_corner);
2022 downright_resize_cursor = XCreateFontCursor(display, XC_bottom_right_corner);
2023 hourglass_cursor = XCreateFontCursor(display, XC_watch);
2024 grabbed_cursor = create_grab_cursor();
2026 static char cursor_data[] = { 0,0,0,0, 0,0,0,0 };
2027 Colormap colormap = DefaultColormap(display, screen);
2028 Pixmap pixmap_bottom = XCreateBitmapFromData(display,
2029 rootwin, cursor_data, 8, 8);
2030 XColor black, dummy;
2031 XAllocNamedColor(display, colormap, "black", &black, &dummy);
2032 transparent_cursor = XCreatePixmapCursor(display,
2033 pixmap_bottom, pixmap_bottom, &black, &black, 0, 0);
2034 // XDefineCursor(display, win, transparent_cursor);
2035 XFreePixmap(display, pixmap_bottom);
2038 int BC_WindowBase::evaluate_color_model(int client_byte_order, int server_byte_order, int depth)
2040 int color_model = BC_TRANSPARENCY;
2044 color_model = BC_RGB8;
2047 color_model = (server_byte_order == client_byte_order) ? BC_RGB565 : BC_BGR565;
2050 color_model = server_byte_order ? BC_BGR888 : BC_RGB888;
2053 color_model = server_byte_order ? BC_BGR8888 : BC_ARGB8888;
2059 int BC_WindowBase::init_colors()
2062 current_color_value = current_color_pixel = 0;
2064 // Get the real depth
2067 ximage = XCreateImage(top_level->display,
2068 top_level->vis, top_level->default_depth,
2069 ZPixmap, 0, data, 16, 16, 8, 0);
2070 bits_per_pixel = ximage->bits_per_pixel;
2071 XDestroyImage(ximage);
2073 color_model = evaluate_color_model(client_byte_order,
2076 // Get the color model
2081 cmap = XCreateColormap(display, rootwin, vis, AllocNone);
2082 create_private_colors();
2085 cmap = DefaultColormap(display, screen);
2086 create_shared_colors();
2089 allocate_color_table();
2093 //cmap = DefaultColormap(display, screen);
2094 cmap = XCreateColormap(display, rootwin, vis, AllocNone );
2100 int BC_WindowBase::create_private_colors()
2105 for(int i = 0; i < 255; i++)
2107 color = (i & 0xc0) << 16;
2108 color += (i & 0x38) << 10;
2109 color += (i & 0x7) << 5;
2110 color_table[i][0] = color;
2112 create_shared_colors(); // overwrite the necessary colors on the table
2117 int BC_WindowBase::create_color(int color)
2119 if(total_colors == 256)
2121 // replace the closest match with an exact match
2122 color_table[get_color_rgb8(color)][0] = color;
2126 // add the color to the table
2127 color_table[total_colors][0] = color;
2133 int BC_WindowBase::create_shared_colors()
2135 create_color(BLACK);
2136 create_color(WHITE);
2138 create_color(LTGREY);
2139 create_color(MEGREY);
2140 create_color(MDGREY);
2141 create_color(DKGREY);
2143 create_color(LTCYAN);
2144 create_color(MECYAN);
2145 create_color(MDCYAN);
2146 create_color(DKCYAN);
2148 create_color(LTGREEN);
2149 create_color(GREEN);
2150 create_color(DKGREEN);
2152 create_color(LTPINK);
2156 create_color(LTBLUE);
2158 create_color(DKBLUE);
2160 create_color(LTYELLOW);
2161 create_color(MEYELLOW);
2162 create_color(MDYELLOW);
2163 create_color(DKYELLOW);
2165 create_color(LTPURPLE);
2166 create_color(MEPURPLE);
2167 create_color(MDPURPLE);
2168 create_color(DKPURPLE);
2170 create_color(FGGREY);
2171 create_color(MNBLUE);
2172 create_color(ORANGE);
2173 create_color(FTGREY);
2178 Cursor BC_WindowBase::create_grab_cursor()
2180 int iw = 23, iw1 = iw-1, iw2 = iw/2;
2181 int ih = 23, ih1 = ih-1, ih2 = ih/2;
2182 VFrame grab(iw,ih,BC_RGB888);
2184 grab.set_pixel_color(RED); // fg
2185 grab.draw_smooth(iw2,0, iw1,0, iw1,ih2);
2186 grab.draw_smooth(iw1,ih2, iw1,ih1, iw2,ih1);
2187 grab.draw_smooth(iw2,ih1, 0,ih1, 0,ih2);
2188 grab.draw_smooth(0,ih2, 0,0, iw2,0);
2189 grab.set_pixel_color(WHITE); // bg
2190 grab.draw_line(0,ih2, iw2-2,ih2);
2191 grab.draw_line(iw2+2,ih2, iw1,ih2);
2192 grab.draw_line(iw2,0, iw2,ih2-2);
2193 grab.draw_line(iw2,ih2+2, iw2,ih1);
2195 int bpl = (iw+7)/8, isz = bpl * ih;
2196 char img[isz]; memset(img, 0, isz);
2197 char msk[isz]; memset(msk, 0, isz);
2198 unsigned char **rows = grab.get_rows();
2199 for( int iy=0; iy<ih; ++iy ) {
2200 char *op = img + iy*bpl;
2201 char *mp = msk + iy*bpl;
2202 unsigned char *ip = rows[iy];
2203 for( int ix=0; ix<iw; ++ix,ip+=3 ) {
2204 if( ip[0] ) mp[ix>>3] |= (1<<(ix&7));
2205 if( !ip[1] ) op[ix>>3] |= (1<<(ix&7));
2208 unsigned long white_pix = WhitePixel(display, screen);
2209 unsigned long black_pix = BlackPixel(display, screen);
2210 Pixmap img_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2211 img, iw,ih, white_pix,black_pix, 1);
2212 Pixmap msk_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2213 msk, iw,ih, white_pix,black_pix, 1);
2216 fc.flags = bc.flags = DoRed | DoGreen | DoBlue;
2217 fc.red = 0xffff; fc.green = fc.blue = 0; // fg
2218 bc.red = 0xffff; bc.green = 0xffff; bc.blue = 0x0000; // bg
2219 Cursor cursor = XCreatePixmapCursor(display, img_xpm,msk_xpm, &fc,&bc, iw2,ih2);
2220 XFreePixmap(display, img_xpm);
2221 XFreePixmap(display, msk_xpm);
2225 int BC_WindowBase::allocate_color_table()
2227 int red, green, blue, color;
2230 for(int i = 0; i < total_colors; i++)
2232 color = color_table[i][0];
2233 red = (color & 0xFF0000) >> 16;
2234 green = (color & 0x00FF00) >> 8;
2235 blue = color & 0xFF;
2237 col.flags = DoRed | DoGreen | DoBlue;
2238 col.red = red<<8 | red;
2239 col.green = green<<8 | green;
2240 col.blue = blue<<8 | blue;
2242 XAllocColor(display, cmap, &col);
2243 color_table[i][1] = col.pixel;
2246 XInstallColormap(display, cmap);
2250 int BC_WindowBase::init_window_shape()
2252 if(bg_pixmap && bg_pixmap->use_alpha())
2254 XShapeCombineMask(top_level->display,
2255 this->win, ShapeBounding, 0, 0,
2256 bg_pixmap->get_alpha(), ShapeSet);
2262 int BC_WindowBase::init_gc()
2264 unsigned long gcmask;
2265 gcmask = GCFont | GCGraphicsExposures;
2268 gcvalues.font = mediumfont->fid; // set the font
2269 gcvalues.graphics_exposures = 0; // prevent expose events for every redraw
2270 gc = XCreateGC(display, rootwin, gcmask, &gcvalues);
2272 // gcmask = GCCapStyle | GCJoinStyle;
2273 // XGetGCValues(display, gc, gcmask, &gcvalues);
2274 // printf("BC_WindowBase::init_gc %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2278 int BC_WindowBase::init_fonts()
2280 if( !(smallfont = XLoadQueryFont(display, _(resources->small_font))) )
2281 if( !(smallfont = XLoadQueryFont(display, _(resources->small_font2))) )
2282 smallfont = XLoadQueryFont(display, "fixed");
2283 if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font))) )
2284 if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font2))) )
2285 mediumfont = XLoadQueryFont(display, "fixed");
2286 if( !(largefont = XLoadQueryFont(display, _(resources->large_font))) )
2287 if( !(largefont = XLoadQueryFont(display, _(resources->large_font2))) )
2288 largefont = XLoadQueryFont(display, "fixed");
2289 if( !(bigfont = XLoadQueryFont(display, _(resources->big_font))) )
2290 if( !(bigfont = XLoadQueryFont(display, _(resources->big_font2))) )
2291 bigfont = XLoadQueryFont(display, "fixed");
2293 if((clockfont = XLoadQueryFont(display, _(resources->clock_font))) == NULL)
2294 if((clockfont = XLoadQueryFont(display, _(resources->clock_font2))) == NULL)
2295 clockfont = XLoadQueryFont(display, "fixed");
2298 if(get_resources()->use_fontset)
2303 // FIXME: should check the m,d,n values
2304 smallfontset = XCreateFontSet(display, resources->small_fontset, &m, &n, &d);
2306 smallfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2307 mediumfontset = XCreateFontSet(display, resources->medium_fontset, &m, &n, &d);
2308 if( !mediumfontset )
2309 mediumfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2310 largefontset = XCreateFontSet(display, resources->large_fontset, &m, &n, &d);
2312 largefontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2313 bigfontset = XCreateFontSet(display, resources->big_fontset, &m, &n, &d);
2315 bigfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2316 clockfontset = XCreateFontSet(display, resources->clock_fontset, &m, &n, &d);
2318 clockfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2319 if(clockfontset && bigfontset && largefontset && mediumfontset && smallfontset) {
2320 curr_fontset = mediumfontset;
2321 get_resources()->use_fontset = 1;
2325 get_resources()->use_fontset = 0;
2332 void BC_WindowBase::init_xft()
2335 if( !get_resources()->use_xft ) return;
2336 // apparently, xft is not reentrant, more than this is needed
2337 static Mutex xft_init_lock("BC_WindowBase::xft_init_lock", 0);
2338 xft_init_lock.lock("BC_WindowBase::init_xft");
2339 if(!(smallfont_xft =
2340 (resources->small_font_xft[0] == '-' ?
2341 xftFontOpenXlfd(display, screen, resources->small_font_xft) :
2342 xftFontOpenName(display, screen, resources->small_font_xft))) )
2343 if(!(smallfont_xft =
2344 xftFontOpenXlfd(display, screen, resources->small_font_xft2)))
2345 smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2346 if(!(mediumfont_xft =
2347 (resources->medium_font_xft[0] == '-' ?
2348 xftFontOpenXlfd(display, screen, resources->medium_font_xft) :
2349 xftFontOpenName(display, screen, resources->medium_font_xft))) )
2350 if(!(mediumfont_xft =
2351 xftFontOpenXlfd(display, screen, resources->medium_font_xft2)))
2352 mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2353 if(!(largefont_xft =
2354 (resources->large_font_xft[0] == '-' ?
2355 xftFontOpenXlfd(display, screen, resources->large_font_xft) :
2356 xftFontOpenName(display, screen, resources->large_font_xft))) )
2357 if(!(largefont_xft =
2358 xftFontOpenXlfd(display, screen, resources->large_font_xft2)))
2359 largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2361 (resources->big_font_xft[0] == '-' ?
2362 xftFontOpenXlfd(display, screen, resources->big_font_xft) :
2363 xftFontOpenName(display, screen, resources->big_font_xft))) )
2365 xftFontOpenXlfd(display, screen, resources->big_font_xft2)))
2366 bigfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2367 if(!(clockfont_xft =
2368 (resources->clock_font_xft[0] == '-' ?
2369 xftFontOpenXlfd(display, screen, resources->clock_font_xft) :
2370 xftFontOpenName(display, screen, resources->clock_font_xft))) )
2371 clockfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2374 if(!(bold_smallfont_xft =
2375 (resources->small_b_font_xft[0] == '-' ?
2376 xftFontOpenXlfd(display, screen, resources->small_b_font_xft) :
2377 xftFontOpenName(display, screen, resources->small_b_font_xft))) )
2378 bold_smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2379 if(!(bold_mediumfont_xft =
2380 (resources->medium_b_font_xft[0] == '-' ?
2381 xftFontOpenXlfd(display, screen, resources->medium_b_font_xft) :
2382 xftFontOpenName(display, screen, resources->medium_b_font_xft))) )
2383 bold_mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2384 if(!(bold_largefont_xft =
2385 (resources->large_b_font_xft[0] == '-' ?
2386 xftFontOpenXlfd(display, screen, resources->large_b_font_xft) :
2387 xftFontOpenName(display, screen, resources->large_b_font_xft))) )
2388 bold_largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2390 if( !smallfont_xft || !mediumfont_xft || !largefont_xft || !bigfont_xft ||
2391 !bold_largefont_xft || !bold_mediumfont_xft || !bold_largefont_xft ||
2393 printf("BC_WindowBase::init_fonts: no xft fonts found:"
2394 " %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n",
2395 resources->small_font_xft, smallfont_xft,
2396 resources->medium_font_xft, mediumfont_xft,
2397 resources->large_font_xft, largefont_xft,
2398 resources->big_font_xft, bigfont_xft,
2399 resources->clock_font_xft, clockfont_xft,
2400 resources->small_b_font_xft, bold_smallfont_xft,
2401 resources->medium_b_font_xft, bold_mediumfont_xft,
2402 resources->large_b_font_xft, bold_largefont_xft);
2403 get_resources()->use_xft = 0;
2406 // _XftDisplayInfo needs a lock.
2407 xftDefaultHasRender(display);
2408 xft_init_lock.unlock();
2412 void BC_WindowBase::init_glyphs()
2414 // draw all ascii char glyphs
2415 // There are problems with some/my graphics boards/drivers
2416 // which cause some glyphs to be munged if draws occur while
2417 // the font is being loaded. This code fills the font caches
2418 // by drawing all the ascii glyphs before the system starts.
2419 // Not a fix, but much better than nothing.
2420 static int inited = 0;
2421 if( inited ) return;
2422 XGrabServer(display);
2425 int cur_font = current_font;
2426 // locale encodings, needed glyphs to be preloaded
2427 const char *text = _( // ascii 0x20...0x7e
2428 " !\"#$%&'()*+,-./0123456789:;<=>?"
2429 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
2430 "`abcdefghijklmnopqrstuvwxyz{|}~");
2431 for( int font=SMALLFONT; font<=LARGEFONT; ++font ) {
2433 draw_text(5,5, text);
2436 XUngrabServer(display);
2439 void BC_WindowBase::init_im()
2441 XIMStyles *xim_styles;
2444 if(!(input_method = XOpenIM(display, NULL, NULL, NULL)))
2446 printf("BC_WindowBase::init_im: Could not open input method.\n");
2449 if(XGetIMValues(input_method, XNQueryInputStyle, &xim_styles, NULL) ||
2452 printf("BC_WindowBase::init_im: Input method doesn't support any styles.\n");
2453 XCloseIM(input_method);
2458 for(int z = 0; z < xim_styles->count_styles; z++)
2460 if(xim_styles->supported_styles[z] == (XIMPreeditNothing | XIMStatusNothing))
2462 xim_style = xim_styles->supported_styles[z];
2470 printf("BC_WindowBase::init_im: Input method doesn't support the style we need.\n");
2471 XCloseIM(input_method);
2475 input_context = XCreateIC(input_method, XNInputStyle, xim_style,
2476 XNClientWindow, win, XNFocusWindow, win, NULL);
2479 printf("BC_WindowBase::init_im: Failed to create input context.\n");
2480 XCloseIM(input_method);
2485 void BC_WindowBase::finit_im()
2487 if( input_context ) {
2488 XDestroyIC(input_context);
2491 if( input_method ) {
2492 XCloseIM(input_method);
2498 int BC_WindowBase::get_color(int64_t color)
2500 // return pixel of color
2501 // use this only for drawing subwindows not for bitmaps
2502 int i, test, difference;
2508 return get_color_rgb8(color);
2509 // test last color looked up
2510 if(current_color_value == color)
2511 return current_color_pixel;
2514 current_color_value = color;
2515 for(i = 0; i < total_colors; i++)
2517 if(color_table[i][0] == color)
2519 current_color_pixel = color_table[i][1];
2520 return current_color_pixel;
2524 // find nearest match
2525 difference = 0xFFFFFF;
2527 for(i = 0; i < total_colors; i++)
2529 test = abs((int)(color_table[i][0] - color));
2531 if(test < difference)
2533 current_color_pixel = color_table[i][1];
2537 return current_color_pixel;
2540 return get_color_rgb16(color);
2543 return get_color_bgr16(color);
2547 return client_byte_order == server_byte_order ?
2548 color : get_color_bgr24(color);
2556 int BC_WindowBase::get_color_rgb8(int color)
2560 pixel = (color & 0xc00000) >> 16;
2561 pixel += (color & 0xe000) >> 10;
2562 pixel += (color & 0xe0) >> 5;
2566 int64_t BC_WindowBase::get_color_rgb16(int color)
2569 result = (color & 0xf80000) >> 8;
2570 result += (color & 0xfc00) >> 5;
2571 result += (color & 0xf8) >> 3;
2576 int64_t BC_WindowBase::get_color_bgr16(int color)
2579 result = (color & 0xf80000) >> 19;
2580 result += (color & 0xfc00) >> 5;
2581 result += (color & 0xf8) << 8;
2586 int64_t BC_WindowBase::get_color_bgr24(int color)
2589 result = (color & 0xff) << 16;
2590 result += (color & 0xff00);
2591 result += (color & 0xff0000) >> 16;
2595 void BC_WindowBase::start_video()
2597 cursor_timer->update();
2599 // set_color(BLACK);
2600 // draw_box(0, 0, get_w(), get_h());
2604 void BC_WindowBase::stop_video()
2612 int64_t BC_WindowBase::get_color()
2614 return top_level->current_color;
2617 void BC_WindowBase::set_color(int64_t color)
2619 top_level->current_color = color;
2620 XSetForeground(top_level->display,
2622 top_level->get_color(color));
2625 void BC_WindowBase::set_opaque()
2627 XSetFunction(top_level->display, top_level->gc, GXcopy);
2630 void BC_WindowBase::set_inverse()
2632 XSetFunction(top_level->display, top_level->gc, GXxor);
2635 void BC_WindowBase::set_line_width(int value)
2637 this->line_width = value;
2638 XSetLineAttributes(top_level->display, top_level->gc, value, /* line_width */
2639 line_dashes == 0 ? LineSolid : LineOnOffDash, /* line_style */
2640 line_dashes == 0 ? CapRound : CapNotLast, /* cap_style */
2641 JoinMiter); /* join_style */
2643 if(line_dashes > 0) {
2644 const char dashes = line_dashes;
2645 XSetDashes(top_level->display, top_level->gc, 0, &dashes, 1);
2648 // XGCValues gcvalues;
2649 // unsigned long gcmask;
2650 // gcmask = GCCapStyle | GCJoinStyle;
2651 // XGetGCValues(top_level->display, top_level->gc, gcmask, &gcvalues);
2652 // printf("BC_WindowBase::set_line_width %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2655 void BC_WindowBase::set_line_dashes(int value)
2657 line_dashes = value;
2658 // call XSetLineAttributes
2659 set_line_width(line_width);
2663 Cursor BC_WindowBase::get_cursor_struct(int cursor)
2667 case ARROW_CURSOR: return top_level->arrow_cursor;
2668 case CROSS_CURSOR: return top_level->cross_cursor;
2669 case IBEAM_CURSOR: return top_level->ibeam_cursor;
2670 case VSEPARATE_CURSOR: return top_level->vseparate_cursor;
2671 case HSEPARATE_CURSOR: return top_level->hseparate_cursor;
2672 case MOVE_CURSOR: return top_level->move_cursor;
2673 case LEFT_CURSOR: return top_level->left_cursor;
2674 case RIGHT_CURSOR: return top_level->right_cursor;
2675 case UPRIGHT_ARROW_CURSOR: return top_level->upright_arrow_cursor;
2676 case UPLEFT_RESIZE: return top_level->upleft_resize_cursor;
2677 case UPRIGHT_RESIZE: return top_level->upright_resize_cursor;
2678 case DOWNLEFT_RESIZE: return top_level->downleft_resize_cursor;
2679 case DOWNRIGHT_RESIZE: return top_level->downright_resize_cursor;
2680 case HOURGLASS_CURSOR: return top_level->hourglass_cursor;
2681 case TRANSPARENT_CURSOR: return top_level->transparent_cursor;
2682 case GRABBED_CURSOR: return top_level->grabbed_cursor;
2687 void BC_WindowBase::set_cursor(int cursor, int override, int flush)
2689 // inherit cursor from parent
2692 XUndefineCursor(top_level->display, win);
2693 current_cursor = cursor;
2696 // don't change cursor if overridden
2697 if((!top_level->is_hourglass && !is_transparent) ||
2700 XDefineCursor(top_level->display, win, get_cursor_struct(cursor));
2701 if(flush) this->flush();
2704 if(!override) current_cursor = cursor;
2707 void BC_WindowBase::set_x_cursor(int cursor)
2709 temp_cursor = XCreateFontCursor(top_level->display, cursor);
2710 XDefineCursor(top_level->display, win, temp_cursor);
2711 current_cursor = cursor;
2715 int BC_WindowBase::get_cursor()
2717 return current_cursor;
2720 void BC_WindowBase::start_hourglass()
2722 top_level->start_hourglass_recursive();
2726 void BC_WindowBase::stop_hourglass()
2728 top_level->stop_hourglass_recursive();
2732 void BC_WindowBase::start_hourglass_recursive()
2734 if(this == top_level)
2742 set_cursor(HOURGLASS_CURSOR, 1, 0);
2743 for(int i = 0; i < subwindows->total; i++)
2745 subwindows->values[i]->start_hourglass_recursive();
2750 void BC_WindowBase::stop_hourglass_recursive()
2752 if(this == top_level)
2754 if(hourglass_total == 0) return;
2755 top_level->hourglass_total--;
2758 if(!top_level->hourglass_total)
2760 top_level->is_hourglass = 0;
2762 // Cause set_cursor to perform change
2764 set_cursor(current_cursor, 1, 0);
2766 for(int i = 0; i < subwindows->total; i++)
2768 subwindows->values[i]->stop_hourglass_recursive();
2776 XFontStruct* BC_WindowBase::get_font_struct(int font)
2778 // Clear out unrelated flags
2779 if(font & BOLDFACE) font ^= BOLDFACE;
2782 case SMALLFONT: return top_level->smallfont; break;
2783 case MEDIUMFONT: return top_level->mediumfont; break;
2784 case LARGEFONT: return top_level->largefont; break;
2785 case BIGFONT: return top_level->bigfont; break;
2786 case CLOCKFONT: return top_level->clockfont; break;
2791 XFontSet BC_WindowBase::get_fontset(int font)
2795 if(get_resources()->use_fontset)
2797 switch(font & 0xff) {
2798 case SMALLFONT: fs = top_level->smallfontset; break;
2799 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2800 case LARGEFONT: fs = top_level->largefontset; break;
2801 case BIGFONT: fs = top_level->bigfontset; break;
2802 case CLOCKFONT: fs = top_level->clockfontset; break;
2810 XftFont* BC_WindowBase::get_xft_struct(int font)
2813 case SMALLFONT: return (XftFont*)top_level->smallfont_xft;
2814 case MEDIUMFONT: return (XftFont*)top_level->mediumfont_xft;
2815 case LARGEFONT: return (XftFont*)top_level->largefont_xft;
2816 case BIGFONT: return (XftFont*)top_level->bigfont_xft;
2817 case CLOCKFONT: return (XftFont*)top_level->clockfont_xft;
2818 case MEDIUMFONT_3D: return (XftFont*)top_level->bold_mediumfont_xft;
2819 case SMALLFONT_3D: return (XftFont*)top_level->bold_smallfont_xft;
2820 case LARGEFONT_3D: return (XftFont*)top_level->bold_largefont_xft;
2828 int BC_WindowBase::get_current_font()
2830 return top_level->current_font;
2833 void BC_WindowBase::set_font(int font)
2835 top_level->current_font = font;
2838 if(get_resources()->use_xft) {}
2841 if(get_resources()->use_fontset) {
2845 if(get_font_struct(font))
2847 XSetFont(top_level->display, top_level->gc, get_font_struct(font)->fid);
2853 void BC_WindowBase::set_fontset(int font)
2857 if(get_resources()->use_fontset) {
2859 case SMALLFONT: fs = top_level->smallfontset; break;
2860 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2861 case LARGEFONT: fs = top_level->largefontset; break;
2862 case BIGFONT: fs = top_level->bigfontset; break;
2863 case CLOCKFONT: fs = top_level->clockfontset; break;
2871 XFontSet BC_WindowBase::get_curr_fontset(void)
2873 if(get_resources()->use_fontset)
2874 return curr_fontset;
2878 int BC_WindowBase::get_single_text_width(int font, const char *text, int length)
2881 if(get_resources()->use_xft && get_xft_struct(font))
2884 #ifdef X_HAVE_UTF8_STRING
2885 if(get_resources()->locale_utf8)
2887 xftTextExtentsUtf8(top_level->display,
2888 get_xft_struct(font),
2889 (const XftChar8 *)text,
2896 xftTextExtents8(top_level->display,
2897 get_xft_struct(font),
2898 (const XftChar8 *)text,
2902 return extents.xOff;
2906 if(get_resources()->use_fontset && top_level->get_fontset(font))
2907 return XmbTextEscapement(top_level->get_fontset(font), text, length);
2909 if(get_font_struct(font))
2910 return XTextWidth(get_font_struct(font), text, length);
2916 case MEDIUM_7SEGMENT:
2917 return get_resources()->medium_7segment[0]->get_w() * length;
2927 int BC_WindowBase::get_text_width(int font, const char *text, int length)
2929 int i, j, w = 0, line_w = 0;
2930 if(length < 0) length = strlen(text);
2932 for(i = 0, j = 0; i <= length; i++)
2937 line_w = get_single_text_width(font, &text[j], i - j);
2943 line_w = get_single_text_width(font, &text[j], length - j);
2945 if(line_w > w) w = line_w;
2948 if(i > length && w == 0)
2950 w = get_single_text_width(font, text, length);
2956 int BC_WindowBase::get_text_width(int font, const wchr_t *text, int length)
2959 if( length < 0 ) length = wstrlen(text);
2961 for( i=j=0; i<length && text[i]; ++i ) {
2962 if( text[i] != '\n' ) continue;
2964 int lw = get_single_text_width(font, &text[j], i-j);
2965 if( w < lw ) w = lw;
2970 int lw = get_single_text_width(font, &text[j], length-j);
2971 if( w < lw ) w = lw;
2977 int BC_WindowBase::get_text_ascent(int font)
2981 if( (fstruct = get_xft_struct(font)) != 0 )
2982 return fstruct->ascent;
2984 if(get_resources()->use_fontset && top_level->get_fontset(font))
2986 XFontSetExtents *extents;
2988 extents = XExtentsOfFontSet(top_level->get_fontset(font));
2989 return -extents->max_logical_extent.y;
2992 if(get_font_struct(font))
2993 return top_level->get_font_struct(font)->ascent;
2996 case MEDIUM_7SEGMENT:
2997 return get_resources()->medium_7segment[0]->get_h();
3002 int BC_WindowBase::get_text_descent(int font)
3006 if( (fstruct = get_xft_struct(font)) != 0 )
3007 return fstruct->descent;
3009 if(get_resources()->use_fontset && top_level->get_fontset(font)) {
3010 XFontSetExtents *extents;
3011 extents = XExtentsOfFontSet(top_level->get_fontset(font));
3012 return (extents->max_logical_extent.height
3013 + extents->max_logical_extent.y);
3016 if(get_font_struct(font))
3017 return top_level->get_font_struct(font)->descent;
3022 int BC_WindowBase::get_text_height(int font, const char *text)
3027 if( (fstruct = get_xft_struct(font)) != 0 )
3028 rowh = fstruct->height;
3031 rowh = get_text_ascent(font) + get_text_descent(font);
3033 if(!text) return rowh;
3035 // Add height of lines
3036 int h = 0, i, length = strlen(text);
3037 for(i = 0; i <= length; i++)
3048 // truncate the text with ... & return a new string
3049 char *BC_WindowBase::get_truncated_text(int font, const char *text, int max_w)
3051 char *result = cstrdup(text);
3052 int text_w = get_text_width(font, text);
3053 int ci = -1, len = strlen(text);
3054 if( text_w > max_w ) {
3055 // get center of string
3056 int cx = text_w/2, best = INT_MAX;
3057 for( int i=1; i<=len; ++i ) {
3058 int cw = get_text_width(font, text, i);
3059 if( abs(cw-cx) < abs(best-cx) ) {
3064 if( ci > 0 && ci < len-1 ) {
3065 // insert ... in the center
3066 result[ci-1] = result[ci] = result[ci+1] = '.';
3068 while( ci-2>=0 && ci+2<(int)strlen(result) &&
3069 get_text_width(font, result) > max_w ) {
3070 // take away a character from the longer side
3071 int left_w = get_text_width(font, result, ci-2);
3072 int right_w = get_text_width(font, result + ci+3);
3073 int i = left_w > right_w ? --ci-1 : ci+2;
3074 while( (result[i]=result[i+1])!=0 ) ++i;
3081 BC_Bitmap* BC_WindowBase::new_bitmap(int w, int h, int color_model)
3083 if(color_model < 0) color_model = top_level->get_color_model();
3084 return new BC_Bitmap(top_level, w, h, color_model);
3087 void BC_WindowBase::init_wait()
3089 #ifndef SINGLE_THREAD
3090 if(window_type != MAIN_WINDOW)
3091 top_level->init_wait();
3092 init_lock->lock("BC_WindowBase::init_wait");
3093 init_lock->unlock();
3097 int BC_WindowBase::accel_available(int color_model, int lock_it)
3099 if( window_type != MAIN_WINDOW )
3100 return top_level->accel_available(color_model, lock_it);
3102 lock_window("BC_WindowBase::accel_available");
3104 switch(color_model) {
3106 grab_port_id(color_model);
3110 grab_port_id(color_model);
3119 //printf("BC_WindowBase::accel_available %d %d\n", color_model, xvideo_port_id);
3120 return xvideo_port_id >= 0 ? 1 : 0;
3124 int BC_WindowBase::grab_port_id(int color_model)
3127 if( !get_resources()->use_xvideo || // disabled
3128 !get_resources()->use_shm ) // Only local server is fast enough.
3130 if( xvideo_port_id >= 0 )
3131 return xvideo_port_id;
3133 unsigned int ver, rev, reqBase, eventBase, errorBase;
3134 if( Success != XvQueryExtension(display, // XV extension is available
3135 &ver, &rev, &reqBase, &eventBase, &errorBase) )
3138 // XV adaptors are available
3139 unsigned int numAdapt = 0;
3140 XvAdaptorInfo *info = 0;
3141 XvQueryAdaptors(display, DefaultRootWindow(display), &numAdapt, &info);
3145 // Translate from color_model to X color model
3146 int x_color_model = BC_CModels::bc_to_x(color_model);
3148 // Get adaptor with desired color model
3149 for( int i = 0; i < (int)numAdapt && xvideo_port_id == -1; i++) {
3150 if( !(info[i].type & XvImageMask) || !info[i].num_ports ) continue;
3151 // adaptor supports XvImages
3152 int numFormats = 0, numPorts = info[i].num_ports;
3153 XvImageFormatValues *formats =
3154 XvListImageFormats(display, info[i].base_id, &numFormats);
3155 if( !formats ) continue;
3157 for( int j=0; j<numFormats && xvideo_port_id<0; ++j ) {
3158 if( formats[j].id != x_color_model ) continue;
3159 // this adaptor supports the desired format, grab a port
3160 for( int k=0; k<numPorts; ++k ) {
3161 if( Success == XvGrabPort(top_level->display,
3162 info[i].base_id+k, CurrentTime) ) {
3163 //printf("BC_WindowBase::grab_port_id %llx\n", info[i].base_id);
3164 xvideo_port_id = info[i].base_id + k;
3172 XvFreeAdaptorInfo(info);
3173 return xvideo_port_id;
3180 int BC_WindowBase::show_window(int flush)
3182 for(int i = 0; i < subwindows->size(); i++)
3184 subwindows->get(i)->show_window(0);
3187 XMapWindow(top_level->display, win);
3188 if(flush) XFlush(top_level->display);
3189 // XSync(top_level->display, 0);
3194 int BC_WindowBase::hide_window(int flush)
3196 for(int i = 0; i < subwindows->size(); i++)
3198 subwindows->get(i)->hide_window(0);
3201 XUnmapWindow(top_level->display, win);
3202 if(flush) this->flush();
3207 BC_MenuBar* BC_WindowBase::add_menubar(BC_MenuBar *menu_bar)
3209 subwindows->append((BC_SubWindow*)menu_bar);
3211 menu_bar->parent_window = this;
3212 menu_bar->top_level = this->top_level;
3213 menu_bar->initialize();
3217 BC_WindowBase* BC_WindowBase::add_popup(BC_WindowBase *window)
3219 //printf("BC_WindowBase::add_popup window=%p win=%p\n", window, window->win);
3220 if(this != top_level) return top_level->add_popup(window);
3221 popups.append(window);
3225 void BC_WindowBase::remove_popup(BC_WindowBase *window)
3227 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3228 if(this != top_level)
3229 top_level->remove_popup(window);
3231 popups.remove(window);
3232 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3236 BC_WindowBase* BC_WindowBase::add_subwindow(BC_WindowBase *subwindow)
3238 subwindows->append(subwindow);
3240 if(subwindow->bg_color == -1) subwindow->bg_color = this->bg_color;
3242 // parent window must be set before the subwindow initialization
3243 subwindow->parent_window = this;
3244 subwindow->top_level = this->top_level;
3246 // Execute derived initialization
3247 subwindow->initialize();
3252 BC_WindowBase* BC_WindowBase::add_tool(BC_WindowBase *subwindow)
3254 return add_subwindow(subwindow);
3257 int BC_WindowBase::flash(int x, int y, int w, int h, int flush)
3259 if( !top_level->flash_enabled ) return 0;
3260 //printf("BC_WindowBase::flash %d %d %d %d %d\n", __LINE__, w, h, this->w, this->h);
3262 XSetWindowBackgroundPixmap(top_level->display, win, pixmap->opaque_pixmap);
3265 XClearArea(top_level->display, win, x, y, w, h, 0);
3269 XClearWindow(top_level->display, win);
3277 int BC_WindowBase::flash(int flush)
3279 flash(-1, -1, -1, -1, flush);
3283 void BC_WindowBase::flush()
3285 //if(!get_window_lock())
3286 // printf("BC_WindowBase::flush %s not locked\n", top_level->title);
3287 // X gets hosed if Flush/Sync are not user locked (at libX11-1.1.5 / libxcb-1.1.91)
3288 // _XReply deadlocks in condition_wait waiting for xlib lock when waiters!=-1
3289 int locked = get_window_lock();
3290 if( !locked ) lock_window("BC_WindowBase::flush");
3291 XFlush(top_level->display);
3292 if( !locked ) unlock_window();
3295 void BC_WindowBase::sync_display()
3297 int locked = get_window_lock();
3298 if( !locked ) lock_window("BC_WindowBase::sync_display");
3299 XSync(top_level->display, False);
3300 if( !locked ) unlock_window();
3303 int BC_WindowBase::get_window_lock()
3305 #ifdef SINGLE_THREAD
3306 return BC_Display::display_global->get_display_locked();
3308 return top_level->window_lock;
3312 int BC_WindowBase::lock_window(const char *location)
3314 if(top_level && top_level != this)
3316 top_level->lock_window(location);
3321 SET_LOCK(this, title, location);
3322 #ifdef SINGLE_THREAD
3323 BC_Display::lock_display(location);
3325 XLockDisplay(top_level->display);
3326 top_level->display_lock_owner = pthread_self();
3329 ++top_level->window_lock;
3333 printf("BC_WindowBase::lock_window top_level NULL\n");
3338 int BC_WindowBase::unlock_window()
3340 if(top_level && top_level != this)
3342 top_level->unlock_window();
3348 if( !top_level->window_lock ) {
3349 printf("BC_WindowBase::unlock_window %s not locked\n", title);
3352 if( top_level->window_lock > 0 )
3353 if( --top_level->window_lock == 0 )
3354 top_level->display_lock_owner = 0;
3355 #ifdef SINGLE_THREAD
3356 BC_Display::unlock_display();
3358 XUnlockDisplay(top_level->display);
3363 printf("BC_WindowBase::unlock_window top_level NULL\n");
3368 int BC_WindowBase::break_lock()
3370 if( !top_level ) return 0;
3371 if( top_level != this ) return top_level->break_lock();
3372 if( top_level->display_lock_owner != pthread_self() ) return 0;
3373 if( top_level->window_lock != 1 ) return 0;
3376 display_lock_owner = 0;
3377 #ifdef SINGLE_THREAD
3378 BC_Display::unlock_display();
3380 XUnlockDisplay(display);
3385 void BC_WindowBase::set_done(int return_value)
3387 if(done_set) return;
3389 if(window_type != MAIN_WINDOW)
3390 top_level->set_done(return_value);
3393 #ifdef SINGLE_THREAD
3394 this->return_value = return_value;
3395 BC_Display::display_global->arm_completion(this);
3396 completion_lock->unlock();
3397 #else // SINGLE_THREAD
3399 if( !event_thread ) return;
3400 XEvent *event = new_xevent();
3401 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
3402 event->type = ClientMessage;
3403 ptr->message_type = SetDoneXAtom;
3405 this->return_value = return_value;
3406 // May lock up here because XSendEvent doesn't work too well
3407 // asynchronous with XNextEvent.
3408 // This causes BC_WindowEvents to forward a copy of the event to run_window where
3410 // Deletion of event_thread is done at the end of BC_WindowBase::run_window() - by calling the destructor
3416 void BC_WindowBase::close(int return_value)
3418 hide_window(); flush();
3419 set_done(return_value);
3422 int BC_WindowBase::grab(BC_WindowBase *window)
3425 BC_WindowBase *grab_window = window->active_grab;
3427 int locked = get_window_lock();
3428 if( locked ) unlock_window();
3429 grab_window->lock_window("BC_WindowBase::grab(BC_WindowBase");
3430 grab_window->handle_ungrab();
3431 grab_window->unlock_window();
3432 if( locked ) lock_window("BC_WindowBase::grab(BC_WindowBase");
3434 window->grab_lock->lock("BC_WindowBase::grab");
3435 if( !window->active_grab ) {
3436 window->active_grab = this;
3437 this->grab_active = window;
3440 window->grab_lock->unlock();
3443 int BC_WindowBase::ungrab(BC_WindowBase *window)
3446 window->grab_lock->lock("BC_WindowBase::ungrab");
3447 if( this == window->active_grab ) {
3448 window->active_grab = 0;
3449 this->grab_active = 0;
3452 window->grab_lock->unlock();
3455 int BC_WindowBase::grab_event_count()
3458 #ifndef SINGLE_THREAD
3459 result = grab_active->get_event_count();
3463 int BC_WindowBase::grab_buttons()
3465 XSync(top_level->display, False);
3466 if( XGrabButton(top_level->display, AnyButton, AnyModifier,
3467 top_level->rootwin, True, ButtonPressMask | ButtonReleaseMask,
3468 GrabModeAsync, GrabModeSync, None, None) == GrabSuccess ) {
3469 set_active_subwindow(this);
3474 void BC_WindowBase::ungrab_buttons()
3476 XUngrabButton(top_level->display, AnyButton, AnyModifier, top_level->rootwin);
3477 set_active_subwindow(0);
3480 void BC_WindowBase::grab_cursor()
3482 Cursor cursor_grab = get_cursor_struct(GRABBED_CURSOR);
3483 XGrabPointer(top_level->display, top_level->rootwin, True,
3484 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
3485 GrabModeAsync, GrabModeAsync, None, cursor_grab, CurrentTime);
3487 void BC_WindowBase::ungrab_cursor()
3489 XUngrabPointer(top_level->display, CurrentTime);
3493 // WidthOfScreen/HeightOfScreen of XDefaultScreenOfDisplay
3494 // this is the bounding box of all the screens
3496 int BC_WindowBase::get_root_w(int lock_display)
3498 if(lock_display) lock_window("BC_WindowBase::get_root_w");
3499 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3500 int result = WidthOfScreen(def_screen);
3501 if(lock_display) unlock_window();
3505 int BC_WindowBase::get_root_h(int lock_display)
3507 if(lock_display) lock_window("BC_WindowBase::get_root_h");
3508 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3509 int result = HeightOfScreen(def_screen);
3510 if(lock_display) unlock_window();
3514 XineramaScreenInfo *
3515 BC_WindowBase::get_xinerama_info(int screen)
3517 if( !xinerama_info || !xinerama_screens ) return 0;
3519 for( int i=0; i<xinerama_screens; ++i )
3520 if( xinerama_info[i].screen_number == screen )
3521 return &xinerama_info[i];
3524 int top_x = get_x(), top_y = get_y();
3525 if( BC_DisplayInfo::left_border >= 0 ) top_x += BC_DisplayInfo::left_border;
3526 if( BC_DisplayInfo::top_border >= 0 ) top_y += BC_DisplayInfo::top_border;
3527 for( int i=0; i<xinerama_screens; ++i ) {
3528 int scr_y = top_y - xinerama_info[i].y_org;
3529 if( scr_y < 0 || scr_y >= xinerama_info[i].height ) continue;
3530 int scr_x = top_x - xinerama_info[i].x_org;
3531 if( scr_x >= 0 && scr_x < xinerama_info[i].width )
3532 return &xinerama_info[i];
3537 void BC_WindowBase::get_fullscreen_geometry(int &wx, int &wy, int &ww, int &wh)
3539 XineramaScreenInfo *info = top_level->get_xinerama_info(-1);
3541 wx = info->x_org; wy = info->y_org;
3542 ww = info->width; wh = info->height;
3545 wx = get_screen_x(0, -1);
3546 wy = get_screen_y(0, -1);
3547 int scr_w0 = get_screen_w(0, 0);
3548 int root_w = get_root_w(0);
3549 int root_h = get_root_h(0);
3550 if( root_w > scr_w0 ) { // multi-headed
3551 if( wx >= scr_w0 ) {
3552 // assumes right side is the big one
3553 ww = root_w - scr_w0;
3557 // use same aspect ratio to compute left height
3559 wh = (w*root_h) / (root_w-scr_w0);
3569 int BC_WindowBase::get_screen_x(int lock_display, int screen)
3572 if(lock_display) lock_window("BC_WindowBase::get_screen_x");
3573 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3576 int root_w = get_root_w(0);
3577 int root_h = get_root_h(0);
3578 // Shift X based on position of current window if dual head
3579 if( (float)root_w/root_h > 1.8 ) {
3580 root_w = get_screen_w(0, 0);
3581 if( top_level->get_x() >= root_w )
3586 result = info->x_org;
3587 if(lock_display) unlock_window();
3591 int BC_WindowBase::get_screen_y(int lock_display, int screen)
3593 if(lock_display) lock_window("BC_WindowBase::get_screen_y");
3594 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3595 int result = !info ? 0 : info->y_org;
3596 if(lock_display) unlock_window();
3600 int BC_WindowBase::get_screen_w(int lock_display, int screen)
3603 if(lock_display) lock_window("BC_WindowBase::get_screen_w");
3604 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3606 int width = get_root_w(0);
3607 int height = get_root_h(0);
3608 if( (float)width/height > 1.8 ) {
3609 // If dual head, the screen width is > 16x9
3610 // but we only want to fill one screen
3611 // this code assumes the "big" screen is on the right
3612 int scr_w0 = width / 2;
3614 case 600: scr_w0 = 800; break;
3615 case 720: scr_w0 = 1280; break;
3616 case 1024: scr_w0 = 1280; break;
3617 case 1200: scr_w0 = 1600; break;
3618 case 1080: scr_w0 = 1920; break;
3620 int scr_w1 = width - scr_w0;
3621 result = screen > 0 ? scr_w1 :
3622 screen == 0 ? scr_w0 :
3623 top_level->get_x() < scr_w0 ? scr_w0 : scr_w1;
3629 result = info->width;
3630 if(lock_display) unlock_window();
3634 int BC_WindowBase::get_screen_h(int lock_display, int screen)
3636 if(lock_display) lock_window("BC_WindowBase::get_screen_h");
3637 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3638 int result = info ? info->height : get_root_h(0);
3639 if(lock_display) unlock_window();
3643 // Bottom right corner
3644 int BC_WindowBase::get_x2()
3649 int BC_WindowBase::get_y2()
3654 int BC_WindowBase::get_video_on()
3659 int BC_WindowBase::get_hidden()
3661 return top_level->hidden;
3664 int BC_WindowBase::cursor_inside()
3666 return (top_level->cursor_x >= 0 &&
3667 top_level->cursor_y >= 0 &&
3668 top_level->cursor_x < w &&
3669 top_level->cursor_y < h);
3672 BC_WindowBase* BC_WindowBase::get_top_level()
3677 BC_WindowBase* BC_WindowBase::get_parent()
3679 return parent_window;
3682 int BC_WindowBase::get_color_model()
3684 return top_level->color_model;
3687 BC_Resources* BC_WindowBase::get_resources()
3689 return BC_WindowBase::resources;
3692 BC_Synchronous* BC_WindowBase::get_synchronous()
3694 return BC_WindowBase::resources->get_synchronous();
3697 int BC_WindowBase::get_bg_color()
3702 void BC_WindowBase::set_bg_color(int color)
3704 this->bg_color = color;
3707 BC_Pixmap* BC_WindowBase::get_bg_pixmap()
3712 void BC_WindowBase::set_active_subwindow(BC_WindowBase *subwindow)
3714 top_level->active_subwindow = subwindow;
3717 int BC_WindowBase::activate()
3722 int BC_WindowBase::deactivate()
3724 if(window_type == MAIN_WINDOW)
3726 if( top_level->active_menubar ) {
3727 top_level->active_menubar->deactivate();
3728 top_level->active_menubar = 0;
3730 if( top_level->active_popup_menu ) {
3731 top_level->active_popup_menu->deactivate();
3732 top_level->active_popup_menu = 0;
3734 if( top_level->active_subwindow ) {
3735 top_level->active_subwindow->deactivate();
3736 top_level->active_subwindow = 0;
3738 if( top_level->motion_events && top_level->last_motion_win == this->win )
3739 top_level->motion_events = 0;
3745 int BC_WindowBase::cycle_textboxes(int amount)
3748 BC_WindowBase *new_textbox = 0;
3752 BC_WindowBase *first_textbox = 0;
3753 find_next_textbox(&first_textbox, &new_textbox, result);
3754 if(!new_textbox) new_textbox = first_textbox;
3760 BC_WindowBase *last_textbox = 0;
3761 find_prev_textbox(&last_textbox, &new_textbox, result);
3762 if(!new_textbox) new_textbox = last_textbox;
3766 if(new_textbox != active_subwindow)
3769 new_textbox->activate();
3775 int BC_WindowBase::find_next_textbox(BC_WindowBase **first_textbox, BC_WindowBase **next_textbox, int &result)
3777 // Search subwindows for textbox
3778 for(int i = 0; i < subwindows->total && result < 2; i++)
3780 BC_WindowBase *test_subwindow = subwindows->values[i];
3781 test_subwindow->find_next_textbox(first_textbox, next_textbox, result);
3788 if(!*first_textbox) *first_textbox = this;
3792 if(top_level->active_subwindow == this)
3798 *next_textbox = this;
3805 int BC_WindowBase::find_prev_textbox(BC_WindowBase **last_textbox, BC_WindowBase **prev_textbox, int &result)
3811 if(!*last_textbox) *last_textbox = this;
3815 if(top_level->active_subwindow == this)
3821 *prev_textbox = this;
3826 // Search subwindows for textbox
3827 for(int i = subwindows->total - 1; i >= 0 && result < 2; i--)
3829 BC_WindowBase *test_subwindow = subwindows->values[i];
3830 test_subwindow->find_prev_textbox(last_textbox, prev_textbox, result);
3835 BC_Clipboard* BC_WindowBase::get_clipboard()
3837 #ifdef SINGLE_THREAD
3838 return BC_Display::display_global->clipboard;
3840 return top_level->clipboard;
3844 Atom BC_WindowBase::to_clipboard(const char *data, long len, int clipboard_num)
3846 return get_clipboard()->to_clipboard(this, data, len, clipboard_num);
3849 long BC_WindowBase::from_clipboard(char *data, long maxlen, int clipboard_num)
3851 return get_clipboard()->from_clipboard(data, maxlen, clipboard_num);
3854 long BC_WindowBase::clipboard_len(int clipboard_num)
3856 return get_clipboard()->clipboard_len(clipboard_num);
3859 int BC_WindowBase::do_selection_clear(Window win)
3861 top_level->event_win = win;
3862 return dispatch_selection_clear();
3865 int BC_WindowBase::dispatch_selection_clear()
3868 for( int i=0; i<subwindows->total && !result; ++i )
3869 result = subwindows->values[i]->dispatch_selection_clear();
3871 result = selection_clear_event();
3876 void BC_WindowBase::get_relative_cursor(int &x, int &y, int lock_window)
3878 int abs_x, abs_y, win_x, win_y;
3879 unsigned int temp_mask;
3882 if(lock_window) this->lock_window("BC_WindowBase::get_relative_cursor");
3883 XQueryPointer(top_level->display, top_level->win,
3884 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3887 XTranslateCoordinates(top_level->display, top_level->rootwin,
3888 win, abs_x, abs_y, &x, &y, &temp_win);
3889 if(lock_window) this->unlock_window();
3891 int BC_WindowBase::get_relative_cursor_x(int lock_window)
3894 get_relative_cursor(x, y, lock_window);
3897 int BC_WindowBase::get_relative_cursor_y(int lock_window)
3900 get_relative_cursor(x, y, lock_window);
3904 void BC_WindowBase::get_abs_cursor(int &abs_x, int &abs_y, int lock_window)
3907 unsigned int temp_mask;
3910 if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor");
3911 XQueryPointer(top_level->display, top_level->win,
3912 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3914 if(lock_window) this->unlock_window();
3916 int BC_WindowBase::get_abs_cursor_x(int lock_window)
3919 get_abs_cursor(abs_x, abs_y, lock_window);
3922 int BC_WindowBase::get_abs_cursor_y(int lock_window)
3925 get_abs_cursor(abs_x, abs_y, lock_window);
3929 void BC_WindowBase::get_pop_cursor(int &px, int &py, int lock_window)
3931 int xmargin = xS(100), ymargin = yS(100);
3932 get_abs_cursor(px, py, lock_window);
3933 if( px < xmargin ) px = xmargin;
3934 if( py < ymargin ) py = ymargin;
3935 int wd = get_screen_x(lock_window,-1) + get_screen_w(lock_window,-1) - xmargin;
3936 if( px > wd ) px = wd;
3937 int ht = get_screen_y(lock_window,-1) + get_screen_h(lock_window,-1) - ymargin;
3938 if( py > ht ) py = ht;
3940 int BC_WindowBase::get_pop_cursor_x(int lock_window)
3943 get_pop_cursor(px, py, lock_window);
3946 int BC_WindowBase::get_pop_cursor_y(int lock_window)
3949 get_pop_cursor(px, py, lock_window);
3953 int BC_WindowBase::match_window(Window win)
3955 if (this->win == win) return 1;
3957 for(int i = 0; i < subwindows->total; i++) {
3958 result = subwindows->values[i]->match_window(win);
3959 if (result) return result;
3965 int BC_WindowBase::get_cursor_over_window()
3967 int abs_x, abs_y, win_x, win_y;
3968 unsigned int mask_return;
3969 Window root_return, child_return;
3971 int ret = XQueryPointer(top_level->display, top_level->rootwin,
3972 &root_return, &child_return, &abs_x, &abs_y,
3973 &win_x, &win_y, &mask_return);
3974 if( ret && child_return == None ) ret = 0;
3975 if( ret && win != child_return )
3976 ret = top_level->match_window(child_return);
3977 // query pointer can return a window manager window with this top_level as a child
3978 // for kde this can be two levels deep
3979 unsigned int nchildren_return = 0;
3980 Window parent_return, *children_return = 0;
3981 Window top_win = top_level->win;
3982 while( !ret && top_win != top_level->rootwin && top_win != root_return &&
3983 XQueryTree(top_level->display, top_win, &root_return,
3984 &parent_return, &children_return, &nchildren_return) ) {
3985 if( children_return ) XFree(children_return);
3986 if( (top_win=parent_return) == child_return ) ret = 1;
3991 int BC_WindowBase::cursor_above()
3994 get_relative_cursor(rx, ry);
3995 return rx < 0 || rx >= get_w() ||
3996 ry < 0 || ry >= get_h() ? 0 : 1;
3999 int BC_WindowBase::get_drag_x()
4001 return top_level->drag_x;
4004 int BC_WindowBase::get_drag_y()
4006 return top_level->drag_y;
4009 int BC_WindowBase::get_cursor_x()
4011 return top_level->cursor_x;
4014 int BC_WindowBase::get_cursor_y()
4016 return top_level->cursor_y;
4019 int BC_WindowBase::dump_windows()
4021 printf("\tBC_WindowBase::dump_windows window=%p win=%p '%s', %dx%d+%d+%d %s\n",
4022 this, (void*)this->win, title, w,h,x,y, typeid(*this).name());
4023 for(int i = 0; i < subwindows->size(); i++)
4024 subwindows->get(i)->dump_windows();
4025 for(int i = 0; i < popups.size(); i++) {
4026 BC_WindowBase *p = popups[i];
4027 printf("\tBC_WindowBase::dump_windows popup=%p win=%p '%s', %dx%d+%d+%d %s\n",
4028 p, (void*)p->win, p->title, p->w,p->h,p->x,p->y, typeid(*p).name());
4033 int BC_WindowBase::is_event_win()
4035 return this->win == top_level->event_win;
4038 void BC_WindowBase::set_dragging(int value)
4040 is_dragging = value;
4043 int BC_WindowBase::get_dragging()
4048 int BC_WindowBase::get_buttonpress()
4050 return top_level->button_number;
4053 int BC_WindowBase::get_button_down()
4055 return top_level->button_down;
4058 int BC_WindowBase::alt_down()
4060 return top_level->alt_mask;
4063 int BC_WindowBase::shift_down()
4065 return top_level->shift_mask;
4068 int BC_WindowBase::ctrl_down()
4070 return top_level->ctrl_mask;
4073 wchr_t* BC_WindowBase::get_wkeystring(int *length)
4076 *length = top_level->wkey_string_length;
4077 return top_level->wkey_string;
4080 #ifdef X_HAVE_UTF8_STRING
4081 char* BC_WindowBase::get_keypress_utf8()
4083 return top_level->key_pressed_utf8;
4088 int BC_WindowBase::get_keypress()
4090 return top_level->key_pressed;
4093 int BC_WindowBase::get_double_click()
4095 return top_level->double_click;
4098 int BC_WindowBase::get_triple_click()
4100 return top_level->triple_click;
4103 int BC_WindowBase::get_bgcolor()
4108 int BC_WindowBase::resize_window(int w, int h)
4110 if(this->w == w && this->h == h) return 0;
4112 if(window_type == MAIN_WINDOW && !allow_resize)
4114 XSizeHints size_hints;
4115 size_hints.flags = PSize | PMinSize | PMaxSize;
4116 size_hints.width = w;
4117 size_hints.height = h;
4118 size_hints.min_width = w;
4119 size_hints.max_width = w;
4120 size_hints.min_height = h;
4121 size_hints.max_height = h;
4122 if( this->x > -BC_INFINITY && this->x < BC_INFINITY ) {
4123 size_hints.flags |= PPosition;
4124 size_hints.x = this->x;
4125 size_hints.y = this->y;
4127 XSetNormalHints(top_level->display, win, &size_hints);
4129 XResizeWindow(top_level->display, win, w, h);
4134 pixmap = new BC_Pixmap(this, w, h);
4136 // Propagate to menubar
4137 for(int i = 0; i < subwindows->total; i++)
4139 subwindows->values[i]->dispatch_resize_event(w, h);
4142 draw_background(0, 0, w, h);
4143 if(top_level == this && get_resources()->recursive_resizing)
4144 resize_history.append(new BC_ResizeCall(w, h));
4148 // The only way for resize events to be propagated is by updating the internal w and h
4149 int BC_WindowBase::resize_event(int w, int h)
4151 if(window_type == MAIN_WINDOW)
4159 int BC_WindowBase::reposition_window(int x, int y)
4161 reposition_window(x, y, -1, -1);
4166 int BC_WindowBase::reposition_window(int x, int y, int w, int h)
4170 // Some tools set their own dimensions before calling this, causing the
4171 // resize check to skip.
4175 if(w > 0 && w != this->w)
4181 if(h > 0 && h != this->h)
4187 //printf("BC_WindowBase::reposition_window %d %d %d\n", translation_count, x_correction, y_correction);
4190 printf("BC_WindowBase::reposition_window this->w == %d\n", this->w);
4192 printf("BC_WindowBase::reposition_window this->h == %d\n", this->h);
4194 if(translation_count && window_type == MAIN_WINDOW)
4196 // KDE shifts window right and down.
4197 // FVWM leaves window alone and adds border around it.
4198 XMoveResizeWindow(top_level->display, win,
4199 x - BC_DisplayInfo::auto_reposition_x,
4200 y - BC_DisplayInfo::auto_reposition_y,
4205 XMoveResizeWindow(top_level->display, win, x, y,
4212 pixmap = new BC_Pixmap(this, this->w, this->h);
4213 clear_box(0,0, this->w, this->h);
4214 // Propagate to menubar
4215 for(int i = 0; i < subwindows->total; i++)
4217 subwindows->values[i]->dispatch_resize_event(this->w, this->h);
4220 // draw_background(0, 0, w, h);
4226 int BC_WindowBase::reposition_window_relative(int dx, int dy, int w, int h)
4228 return reposition_window(get_x()+dx, get_y()+dy, w, h);
4231 int BC_WindowBase::reposition_window_relative(int dx, int dy)
4233 return reposition_window_relative(dx, dy, -1, -1);
4236 void BC_WindowBase::set_tooltips(int v)
4238 get_resources()->tooltips_enabled = v;
4241 void BC_WindowBase::set_force_tooltip(int v)
4246 int BC_WindowBase::raise_window(int do_flush)
4248 if( hidden ) return 1;
4249 if( wait_viewable(500) ) return 1;
4250 XRaiseWindow(top_level->display, win);
4251 if(do_flush) XFlush(top_level->display);
4255 int BC_WindowBase::lower_window(int do_flush)
4257 XLowerWindow(top_level->display, win);
4258 if(do_flush) XFlush(top_level->display);
4262 void BC_WindowBase::set_background(VFrame *bitmap)
4264 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
4266 bg_pixmap = new BC_Pixmap(this, bitmap, PIXMAP_OPAQUE);
4267 shared_bg_pixmap = 0;
4268 draw_background(0, 0, w, h);
4271 void BC_WindowBase::put_title(const char *text)
4273 char *cp = this->title, *ep = cp+sizeof(this->title)-1;
4274 for( const unsigned char *bp = (const unsigned char *)text; *bp && cp<ep; ++bp )
4275 *cp++ = *bp >= ' ' ? *bp : ' ';
4279 void BC_WindowBase::set_title(const char *text, int utf8)
4281 // utf8>0: wm + net_wm, utf8=0: wm only, utf<0: net_wm only
4283 const unsigned char *wm_title = (const unsigned char *)title;
4284 int title_len = strlen((const char *)title);
4286 Atom xa_wm_name = XA_WM_NAME;
4287 Atom xa_icon_name = XA_WM_ICON_NAME;
4288 Atom xa_string = XA_STRING;
4289 XChangeProperty(display, win, xa_wm_name, xa_string, 8,
4290 PropModeReplace, wm_title, title_len);
4291 XChangeProperty(display, win, xa_icon_name, xa_string, 8,
4292 PropModeReplace, wm_title, title_len);
4295 Atom xa_net_wm_name = XInternAtom(display, "_NET_WM_NAME", True);
4296 Atom xa_net_icon_name = XInternAtom(display, "_NET_WM_ICON_NAME", True);
4297 Atom xa_utf8_string = XInternAtom(display, "UTF8_STRING", True);
4298 XChangeProperty(display, win, xa_net_wm_name, xa_utf8_string, 8,
4299 PropModeReplace, wm_title, title_len);
4300 XChangeProperty(display, win, xa_net_icon_name, xa_utf8_string, 8,
4301 PropModeReplace, wm_title, title_len);
4307 void BC_WindowBase::set_net_icon(VFrame *data)
4309 int width = data->get_w(), height = data->get_h();
4310 int size = 2 + width * height;
4311 unsigned long *icon_data = new unsigned long[size];
4312 unsigned long *lp = icon_data;
4313 *lp++ = width; *lp++ = height;
4314 uint8_t **rows = data->get_rows();
4315 for( int y=0; y<height; ++y ) {
4316 unsigned *up = (unsigned *)rows[y];
4317 for( int x=0; x<width; ++x )
4318 *lp++ = *(unsigned *)up++;
4320 Atom NetWMIcon = XInternAtom(display, "_NET_WM_ICON", True);
4321 XChangeProperty(top_level->display, top_level->win, NetWMIcon,
4322 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)icon_data, size);
4323 delete [] icon_data;
4326 const char *BC_WindowBase::get_title()
4331 int BC_WindowBase::get_toggle_value()
4333 return toggle_value;
4336 int BC_WindowBase::get_toggle_drag()
4341 int BC_WindowBase::set_icon(VFrame *data)
4343 if(icon_pixmap) delete icon_pixmap;
4344 icon_pixmap = new BC_Pixmap(top_level, data, PIXMAP_ALPHA, 1);
4346 if(icon_window) delete icon_window;
4347 icon_window = new BC_Popup(this, 0, 0,
4348 icon_pixmap->get_w(), icon_pixmap->get_h(),
4349 -1, 1, // All windows are hidden initially
4352 XWMHints wm_hints; memset(&wm_hints, 0, sizeof(wm_hints));
4353 wm_hints.flags = IconPixmapHint; // | IconMaskHint | IconWindowHint;
4354 wm_hints.icon_pixmap = icon_pixmap->get_pixmap();
4355 wm_hints.icon_mask = icon_pixmap->get_alpha();
4356 wm_hints.icon_window = icon_window->win;
4357 if( XGroupLeader ) {
4358 wm_hints.flags |= WindowGroupHint;
4359 wm_hints.window_group = XGroupLeader;
4362 // for(int i = 0; i < 1000; i++)
4363 // printf("02x ", icon_pixmap->get_alpha()->get_row_pointers()[0][i]);
4366 XSetWMHints(top_level->display, top_level->win, &wm_hints);
4369 XSync(top_level->display, 0);
4373 void BC_WindowBase::init_resources(float scale)
4375 if( resources ) return;
4377 const char *env = getenv("BC_SCALE");
4378 if( env ) scale = atof(env);
4379 float x_scale = 1, y_scale = 1;
4381 BC_DisplayInfo info;
4383 int cins = info.xinerama_big_screen();
4384 if( !info.xinerama_geometry(cins, wx, wy, ww, wh) ) {
4385 int sh = ww * 9 / 16;
4386 int sw = wh * 16 / 9;
4387 if( sw < ww ) ww = sw;
4388 if( sh < wh ) wh = sh;
4389 if( (x_scale = ww/1920.) < 1 ) x_scale = 1;
4390 if( (y_scale = wh/1080.) < 1 ) y_scale = 1;
4394 x_scale = y_scale = scale;
4395 // constructor sets BC_WindowBase::resources
4396 new BC_Resources(x_scale, y_scale);
4398 void BC_WindowBase::finit_resources()
4400 delete resources; resources = 0;
4403 int BC_WindowBase::set_w(int w)
4409 int BC_WindowBase::set_h(int h)
4415 int BC_WindowBase::load_defaults(BC_Hash *defaults)
4417 char string[BCTEXTLEN];
4418 int newest_id = - 1;
4419 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4421 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4422 resources->filebox_history[i].path[0] = 0;
4423 defaults->get(string, resources->filebox_history[i].path);
4424 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4425 resources->filebox_history[i].id = defaults->get(string, resources->get_id());
4426 if(resources->filebox_history[i].id > newest_id)
4427 newest_id = resources->filebox_history[i].id;
4430 resources->filebox_id = newest_id + 1;
4431 resources->filebox_mode = defaults->get("FILEBOX_MODE", get_resources()->filebox_mode);
4432 resources->filebox_w = defaults->get("FILEBOX_W", get_resources()->filebox_w);
4433 resources->filebox_h = defaults->get("FILEBOX_H", get_resources()->filebox_h);
4434 resources->filebox_columntype[0] = defaults->get("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4435 resources->filebox_columntype[1] = defaults->get("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4436 resources->filebox_columntype[2] = defaults->get("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4437 resources->filebox_columntype[3] = defaults->get("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4438 resources->filebox_columnwidth[0] = defaults->get("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4439 resources->filebox_columnwidth[1] = defaults->get("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4440 resources->filebox_columnwidth[2] = defaults->get("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4441 resources->filebox_columnwidth[3] = defaults->get("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4442 resources->filebox_size_format = defaults->get("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4443 defaults->get("FILEBOX_FILTER", resources->filebox_filter);
4447 int BC_WindowBase::save_defaults(BC_Hash *defaults)
4449 char string[BCTEXTLEN];
4450 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4452 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4453 defaults->update(string, resources->filebox_history[i].path);
4454 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4455 defaults->update(string, resources->filebox_history[i].id);
4457 defaults->update("FILEBOX_MODE", resources->filebox_mode);
4458 defaults->update("FILEBOX_W", resources->filebox_w);
4459 defaults->update("FILEBOX_H", resources->filebox_h);
4460 defaults->update("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4461 defaults->update("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4462 defaults->update("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4463 defaults->update("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4464 defaults->update("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4465 defaults->update("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4466 defaults->update("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4467 defaults->update("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4468 defaults->update("FILEBOX_FILTER", resources->filebox_filter);
4469 defaults->update("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4475 // For some reason XTranslateCoordinates can take a long time to return.
4476 // We work around this by only calling it when the event windows are different.
4477 void BC_WindowBase::translate_coordinates(Window src_w, Window dest_w,
4478 int src_x, int src_y, int *dest_x_return, int *dest_y_return)
4485 *dest_x_return = src_x;
4486 *dest_y_return = src_y;
4490 XTranslateCoordinates(top_level->display, src_w, dest_w,
4491 src_x, src_y, dest_x_return, dest_y_return, &tempwin);
4492 //printf("BC_WindowBase::translate_coordinates 1 %lld\n", timer.get_difference());
4496 void BC_WindowBase::get_root_coordinates(int x, int y, int *abs_x, int *abs_y)
4498 translate_coordinates(win, top_level->rootwin, x, y, abs_x, abs_y);
4501 void BC_WindowBase::get_win_coordinates(int abs_x, int abs_y, int *x, int *y)
4503 translate_coordinates(top_level->rootwin, win, abs_x, abs_y, x, y);
4507 #ifdef HAVE_LIBXXF86VM
4508 void BC_WindowBase::closest_vm(int *vm, int *width, int *height)
4512 if(XF86VidModeQueryExtension(top_level->display,&foo,&bar)) {
4514 XF86VidModeModeInfo **vm_modelines;
4515 XF86VidModeGetAllModeLines(top_level->display,
4516 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4517 for( i = 0; i < vm_count; i++ ) {
4518 if( vm_modelines[i]->hdisplay < vm_modelines[*vm]->hdisplay &&
4519 vm_modelines[i]->hdisplay >= *width )
4522 display = top_level->display;
4523 if( vm_modelines[*vm]->hdisplay == *width )
4526 *width = vm_modelines[*vm]->hdisplay;
4527 *height = vm_modelines[*vm]->vdisplay;
4532 void BC_WindowBase::scale_vm(int vm)
4534 int foo,bar,dotclock;
4535 if( XF86VidModeQueryExtension(top_level->display,&foo,&bar) ) {
4537 XF86VidModeModeInfo **vm_modelines;
4538 XF86VidModeModeLine vml;
4539 XF86VidModeGetAllModeLines(top_level->display,
4540 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4541 XF86VidModeGetModeLine(top_level->display,
4542 XDefaultScreen(top_level->display), &dotclock,&vml);
4543 orig_modeline.dotclock = dotclock;
4544 orig_modeline.hdisplay = vml.hdisplay;
4545 orig_modeline.hsyncstart = vml.hsyncstart;
4546 orig_modeline.hsyncend = vml.hsyncend;
4547 orig_modeline.htotal = vml.htotal;
4548 orig_modeline.vdisplay = vml.vdisplay;
4549 orig_modeline.vsyncstart = vml.vsyncstart;
4550 orig_modeline.vsyncend = vml.vsyncend;
4551 orig_modeline.vtotal = vml.vtotal;
4552 orig_modeline.flags = vml.flags;
4553 orig_modeline.privsize = vml.privsize;
4554 // orig_modeline.private = vml.private;
4555 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),vm_modelines[vm]);
4556 XF86VidModeSetViewPort(top_level->display,XDefaultScreen(top_level->display),0,0);
4557 XFlush(top_level->display);
4561 void BC_WindowBase::restore_vm()
4563 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),&orig_modeline);
4564 XFlush(top_level->display);
4569 #ifndef SINGLE_THREAD
4570 int BC_WindowBase::get_event_count()
4572 event_lock->lock("BC_WindowBase::get_event_count");
4573 int result = common_events.total;
4574 event_lock->unlock();
4578 XEvent* BC_WindowBase::get_event()
4581 while(!done && !result)
4583 event_condition->lock("BC_WindowBase::get_event");
4584 event_lock->lock("BC_WindowBase::get_event");
4586 if(common_events.total && !done)
4588 result = common_events.values[0];
4589 common_events.remove_number(0);
4592 event_lock->unlock();
4597 void BC_WindowBase::put_event(XEvent *event)
4599 event_lock->lock("BC_WindowBase::put_event");
4600 common_events.append(event);
4601 event_lock->unlock();
4602 event_condition->unlock();
4605 void BC_WindowBase::dequeue_events(Window win)
4607 event_lock->lock("BC_WindowBase::dequeue_events");
4609 int out = 0, total = common_events.size();
4610 for( int in=0; in<total; ++in ) {
4611 if( common_events[in]->xany.window == win ) continue;
4612 common_events[out++] = common_events[in];
4614 common_events.total = out;
4616 event_lock->unlock();
4619 int BC_WindowBase::resend_event(BC_WindowBase *window)
4621 if( resend_event_window ) return 1;
4622 resend_event_window = window;
4628 int BC_WindowBase::resend_event(BC_WindowBase *window)
4633 #endif // SINGLE_THREAD
4635 int BC_WindowBase::get_id()
4641 BC_Pixmap *BC_WindowBase::create_pixmap(VFrame *vframe)
4643 int w = vframe->get_w(), h = vframe->get_h();
4644 BC_Pixmap *icon = new BC_Pixmap(this, w, h);
4645 icon->draw_vframe(vframe, 0,0, w,h, 0,0);
4650 void BC_WindowBase::flicker(int n, int ms)
4652 int color = get_bg_color();
4653 for( int i=2*n; --i>=0; ) {
4654 set_inverse(); set_bg_color(WHITE);
4655 clear_box(0,0, w,h); flash(1);
4656 sync_display(); Timer::delay(ms);
4658 set_bg_color(color);
4662 void BC_WindowBase::focus()
4664 XWindowAttributes xwa;
4665 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4666 if( xwa.map_state == IsViewable )
4667 XSetInputFocus(top_level->display, top_level->win, RevertToParent, CurrentTime);
4670 int BC_WindowBase::wait_viewable(int ms)
4673 XWindowAttributes xwa;
4675 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4676 if( xwa.map_state == IsViewable ) return 0;
4678 } while( timer.get_difference() < ms );