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>
60 #include <X11/extensions/Xvlib.h>
61 #include <X11/extensions/shape.h>
62 #include <X11/XF86keysym.h>
63 #include <X11/Sunkeysym.h>
65 BC_ResizeCall::BC_ResizeCall(int w, int h)
77 int BC_WindowBase::shm_completion_event = -1;
81 BC_Resources BC_WindowBase::resources;
83 Window XGroupLeader = 0;
85 Mutex BC_KeyboardHandlerLock::keyboard_listener_mutex("keyboard_listener",0);
86 ArrayList<BC_KeyboardHandler*> BC_KeyboardHandler::listeners;
88 BC_WindowBase::BC_WindowBase()
90 //printf("BC_WindowBase::BC_WindowBase 1\n");
91 BC_WindowBase::initialize();
94 BC_WindowBase::~BC_WindowBase()
97 BC_Display::lock_display("BC_WindowBase::~BC_WindowBase");
99 if(window_type == MAIN_WINDOW)
100 lock_window("BC_WindowBase::~BC_WindowBase");
103 #ifdef HAVE_LIBXXF86VM
104 if(window_type == VIDMODE_SCALED_WINDOW && vm_switched) {
111 if(window_type != MAIN_WINDOW)
114 XSelectInput(top_level->display, this->win, 0);
115 XSync(top_level->display,0);
116 #ifndef SINGLE_THREAD
117 top_level->dequeue_events(win);
119 // drop active window refs to this
120 if(top_level->active_menubar == this) top_level->active_menubar = 0;
121 if(top_level->active_popup_menu == this) top_level->active_popup_menu = 0;
122 if(top_level->active_subwindow == this) top_level->active_subwindow = 0;
123 // drop motion window refs to this
124 if(top_level->motion_events && top_level->last_motion_win == this->win)
125 top_level->motion_events = 0;
127 // Remove pointer from parent window to this
128 parent_window->subwindows->remove(this);
131 if(grab_active) grab_active->active_grab = 0;
132 if(icon_window) delete icon_window;
133 if(window_type == POPUP_WINDOW)
134 parent_window->remove_popup(this);
136 // Delete the subwindows
139 while(subwindows->total)
141 // Subwindow removes its own pointer
142 delete subwindows->values[0];
149 //printf("delete glx=%08x, win=%08x %s\n", (unsigned)glx_win, (unsigned)win, title);
151 if( get_resources()->get_synchronous() && glx_win != 0 ) {
152 get_resources()->get_synchronous()->delete_window(this);
155 XDestroyWindow(top_level->display, win);
157 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
158 if(icon_pixmap) delete icon_pixmap;
159 if(temp_bitmap) delete temp_bitmap;
160 top_level->active_bitmaps.remove_buffers(this);
161 if(_7segment_pixmaps)
163 for(int i = 0; i < TOTAL_7SEGMENT; i++)
164 delete _7segment_pixmaps[i];
166 delete [] _7segment_pixmaps;
171 if(window_type == MAIN_WINDOW)
173 XFreeGC(display, gc);
174 static XFontStruct *BC_WindowBase::*xfont[] = {
175 &BC_WindowBase::smallfont,
176 &BC_WindowBase::mediumfont,
177 &BC_WindowBase::largefont,
178 &BC_WindowBase::bigfont,
179 &BC_WindowBase::clockfont,
181 for( int i=sizeof(xfont)/sizeof(xfont[0]); --i>=0; )
182 XFreeFont(display, this->*xfont[i]);
185 // prevents a bug when Xft closes with unrefd fonts
186 FcPattern *defaults = FcPatternCreate();
187 FcPatternAddInteger(defaults, "maxunreffonts", 0);
188 XftDefaultSet(display, defaults);
190 static void *BC_WindowBase::*xft_font[] = {
191 &BC_WindowBase::smallfont_xft,
192 &BC_WindowBase::mediumfont_xft,
193 &BC_WindowBase::largefont_xft,
194 &BC_WindowBase::bigfont_xft,
195 &BC_WindowBase::bold_smallfont_xft,
196 &BC_WindowBase::bold_mediumfont_xft,
197 &BC_WindowBase::bold_largefont_xft,
198 &BC_WindowBase::clockfont_xft,
200 for( int i=sizeof(xft_font)/sizeof(xft_font[0]); --i>=0; ) {
201 XftFont *xft = (XftFont *)(this->*xft_font[i]);
202 if( xft ) xftFontClose (display, xft);
210 XFree(xinerama_info);
211 xinerama_screens = 0;
213 if( xvideo_port_id >= 0 )
214 XvUngrabPort(display, xvideo_port_id, CurrentTime);
217 // Must be last reference to display.
218 // _XftDisplayInfo needs a lock.
219 get_resources()->create_window_lock->lock("BC_WindowBase::~BC_WindowBase");
220 XCloseDisplay(display);
221 get_resources()->create_window_lock->unlock();
223 // clipboard uses a different display connection
224 clipboard->stop_clipboard();
228 resize_history.remove_all_objects();
230 #ifndef SINGLE_THREAD
231 common_events.remove_all_objects();
233 delete event_condition;
236 top_level->window_lock = 0;
237 BC_Display::unlock_display();
242 if( glx_fbcfgs_window ) XFree(glx_fbcfgs_window);
243 if( glx_fbcfgs_pbuffer) XFree(glx_fbcfgs_pbuffer);
244 if( glx_fbcfgs_pixmap ) XFree(glx_fbcfgs_pixmap);
247 UNSET_ALL_LOCKS(this)
250 int BC_WindowBase::initialize()
255 display_lock_owner = 0;
260 resend_event_window = 0;
272 xinerama_screens = 0;
277 translation_events = 0;
278 ctrl_mask = shift_mask = alt_mask = 0;
279 cursor_x = cursor_y = button_number = 0;
293 active_popup_menu = 0;
294 active_subwindow = 0;
298 _7segment_pixmaps = 0;
301 // next_repeat_id = 0;
303 current_font = MEDIUMFONT;
304 current_color = BLACK;
305 current_cursor = ARROW_CURSOR;
308 shared_bg_pixmap = 0;
311 window_type = MAIN_WINDOW;
312 translation_count = 0;
313 x_correction = y_correction = 0;
322 #ifdef HAVE_LIBXXF86VM
340 bold_smallfont_xft = 0;
341 bold_mediumfont_xft = 0;
342 bold_largefont_xft = 0;
344 completion_lock = new Condition(0, "BC_WindowBase::completion_lock");
346 // Need these right away since put_event is called before run_window sometimes.
347 event_lock = new Mutex("BC_WindowBase::event_lock");
348 event_condition = new Condition(0, "BC_WindowBase::event_condition");
349 init_lock = new Condition(0, "BC_WindowBase::init_lock");
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);
459 vis = DefaultVisual(display, screen);
461 default_depth = DefaultDepth(display, screen);
463 client_byte_order = (*(const u_int32_t*)"a ") & 0x00000001;
464 server_byte_order = (XImageByteOrder(display) == MSBFirst) ? 0 : 1;
467 // This must be done before fonts to know if antialiasing is available.
470 if(resources.use_shm < 0) resources.initialize_display(this);
471 x_correction = BC_DisplayInfo::get_left_border();
472 y_correction = BC_DisplayInfo::get_top_border();
474 // clamp window placement
475 if(this->x + this->w + x_correction > root_w)
476 this->x = root_w - this->w - x_correction;
477 if(this->y + this->h + y_correction > root_h)
478 this->y = root_h - this->h - y_correction;
479 if(this->x < 0) this->x = 0;
480 if(this->y < 0) this->y = 0;
482 if(this->bg_color == -1)
483 this->bg_color = resources.get_bg_color();
485 // printf("bcwindowbase 1 %s\n", title);
486 // if(window_type == MAIN_WINDOW) sleep(1);
487 // printf("bcwindowbase 10\n");
493 mask = CWEventMask | CWBackPixel | CWColormap | CWCursor;
495 attr.event_mask = DEFAULT_EVENT_MASKS |
496 StructureNotifyMask |
500 attr.background_pixel = get_color(this->bg_color);
501 attr.colormap = cmap;
502 attr.cursor = get_cursor_struct(ARROW_CURSOR);
504 win = XCreateWindow(display, rootwin,
505 this->x, this->y, this->w, this->h, 0,
506 top_level->default_depth, InputOutput,
508 XGetNormalHints(display, win, &size_hints);
510 size_hints.flags = PSize | PMinSize | PMaxSize;
511 size_hints.width = this->w;
512 size_hints.height = this->h;
513 size_hints.min_width = allow_resize ? minw : this->w;
514 size_hints.max_width = allow_resize ? 32767 : this->w;
515 size_hints.min_height = allow_resize ? minh : this->h;
516 size_hints.max_height = allow_resize ? 32767 : this->h;
517 if(x > -BC_INFINITY && x < BC_INFINITY)
519 size_hints.flags |= PPosition;
520 size_hints.x = this->x;
521 size_hints.y = this->y;
523 XSetWMProperties(display, win, 0, 0, 0, 0, &size_hints, 0, 0);
526 #ifndef SINGLE_THREAD
527 clipboard = new BC_Clipboard(this);
528 clipboard->start_clipboard();
534 Atom ClientLeaderXAtom;
535 if (XGroupLeader == 0)
537 const char *instance_name = "cinelerra";
538 const char *class_name = "Cinelerra";
539 XClassHint *class_hints = XAllocClassHint();
540 class_hints->res_name = (char*)instance_name;
541 class_hints->res_class = (char*)class_name;
542 XSetClassHint(top_level->display, win, class_hints);
544 ClientLeaderXAtom = XInternAtom(display, "WM_CLIENT_LEADER", True);
545 XChangeProperty(display, win, ClientLeaderXAtom, XA_WINDOW, 32,
546 PropModeReplace, (unsigned char *)&XGroupLeader, true);
549 set_icon(get_resources()->default_icon);
552 #ifdef HAVE_LIBXXF86VM
553 if(window_type == VIDMODE_SCALED_WINDOW && vm != -1)
560 #ifdef HAVE_LIBXXF86VM
561 if(window_type == POPUP_WINDOW || window_type == VIDMODE_SCALED_WINDOW)
563 if(window_type == POPUP_WINDOW)
566 mask = CWEventMask | CWBackPixel | CWColormap |
567 CWOverrideRedirect | CWSaveUnder | CWCursor;
569 attr.event_mask = DEFAULT_EVENT_MASKS |
573 if(this->bg_color == -1)
574 this->bg_color = resources.get_bg_color();
575 attr.background_pixel = top_level->get_color(bg_color);
576 attr.colormap = top_level->cmap;
577 if(top_level->is_hourglass)
578 attr.cursor = top_level->get_cursor_struct(HOURGLASS_CURSOR);
580 attr.cursor = top_level->get_cursor_struct(ARROW_CURSOR);
581 attr.override_redirect = True;
582 attr.save_under = True;
584 win = XCreateWindow(top_level->display,
585 top_level->rootwin, this->x, this->y, this->w, this->h, 0,
586 top_level->default_depth, InputOutput, top_level->vis, mask,
588 top_level->add_popup(this);
591 if(window_type == SUB_WINDOW)
593 mask = CWEventMask | CWBackPixel | CWCursor;
594 attr.event_mask = DEFAULT_EVENT_MASKS;
595 attr.background_pixel = top_level->get_color(this->bg_color);
596 if(top_level->is_hourglass)
597 attr.cursor = top_level->get_cursor_struct(HOURGLASS_CURSOR);
599 attr.cursor = top_level->get_cursor_struct(ARROW_CURSOR);
600 win = XCreateWindow(top_level->display,
601 parent_window->win, this->x, this->y, this->w, this->h, 0,
602 top_level->default_depth, InputOutput, top_level->vis, mask,
605 if(!hidden) XMapWindow(top_level->display, win);
608 // Create pixmap for all windows
609 pixmap = new BC_Pixmap(this, this->w, this->h);
611 // Set up options for main window
612 if(window_type == MAIN_WINDOW)
614 if(get_resources()->bg_image && !bg_pixmap && bg_color < 0)
616 this->bg_pixmap = new BC_Pixmap(this,
617 get_resources()->bg_image,
621 if(!hidden) show_window();
625 draw_background(0, 0, this->w, this->h);
627 flash(-1, -1, -1, -1, 0);
629 // Set up options for popup window
630 #ifdef HAVE_LIBXXF86VM
631 if(window_type == POPUP_WINDOW || window_type == VIDMODE_SCALED_WINDOW)
633 if(window_type == POPUP_WINDOW)
637 if(!hidden) show_window();
639 get_resources()->create_window_lock->unlock();
645 Display* BC_WindowBase::init_display(const char *display_name)
649 if(display_name && display_name[0] == 0) display_name = NULL;
650 if((display = XOpenDisplay(display_name)) == NULL) {
651 printf("BC_WindowBase::init_display: cannot connect to X server %s\n",
653 if(getenv("DISPLAY") == NULL) {
654 printf(_("'DISPLAY' environment variable not set.\n"));
657 // Try again with default display.
658 if((display = XOpenDisplay(0)) == NULL) {
659 printf("BC_WindowBase::init_display: cannot connect to default X server.\n");
664 static int xsynch = -1;
666 const char *cp = getenv("CIN_XSYNCH");
667 xsynch = !cp ? 0 : atoi(cp);
670 XSynchronize(display, True);
675 Display* BC_WindowBase::get_display()
677 return top_level->display;
680 int BC_WindowBase::get_screen()
682 return top_level->screen;
685 int BC_WindowBase::run_window()
691 // Events may have been sent before run_window so can't initialize them here.
694 set_repeat(get_resources()->tooltip_delay);
695 BC_Display::display_global->new_window(this);
697 // If the first window created, run the display loop in this thread.
698 if(BC_Display::display_global->is_first(this))
700 BC_Display::unlock_display();
701 BC_Display::display_global->loop();
705 BC_Display::unlock_display();
706 completion_lock->lock("BC_WindowBase::run_window");
709 BC_Display::lock_display("BC_WindowBase::run_window");
710 BC_Display::display_global->delete_window(this);
712 unset_all_repeaters();
714 BC_Display::unlock_display();
716 #else // SINGLE_THREAD
721 set_repeat(get_resources()->tooltip_delay);
723 // Start X server events
724 event_thread = new BC_WindowEvents(this);
725 event_thread->start();
731 // Handle common events
737 unset_all_repeaters();
741 event_condition->reset();
742 common_events.remove_all_objects();
746 #endif // SINGLE_THREAD
751 int BC_WindowBase::get_key_masks(unsigned int key_state)
753 // printf("BC_WindowBase::get_key_masks %llx\n",
754 // event->xkey.state);
755 ctrl_mask = (key_state & ControlMask) ? 1 : 0; // ctrl key down
756 shift_mask = (key_state & ShiftMask) ? 1 : 0; // shift key down
757 alt_mask = (key_state & Mod1Mask) ? 1 : 0; // alt key down
762 void BC_WindowBase::add_keyboard_listener(int(BC_WindowBase::*handler)(BC_WindowBase *))
764 BC_KeyboardHandlerLock set;
765 BC_KeyboardHandler::listeners.append(new BC_KeyboardHandler(handler, this));
768 void BC_WindowBase::del_keyboard_listener(int(BC_WindowBase::*handler)(BC_WindowBase *))
770 BC_KeyboardHandlerLock set;
771 int i = BC_KeyboardHandler::listeners.size();
772 while( --i >= 0 && BC_KeyboardHandler::listeners[i]->handler!=handler );
773 if( i >= 0 ) BC_KeyboardHandler::listeners.remove_object_number(i);
776 int BC_KeyboardHandler::run_event(BC_WindowBase *wp)
778 int result = (win->*handler)(wp);
782 int BC_KeyboardHandler::run_listeners(BC_WindowBase *wp)
785 BC_KeyboardHandlerLock set;
786 for( int i=0; !result && i<listeners.size(); ++i ) {
787 BC_KeyboardHandler *listener = listeners[i];
788 result = listener->run_event(wp);
793 void BC_KeyboardHandler::kill_grabs()
795 BC_KeyboardHandlerLock set;
796 for( int i=0; i<listeners.size(); ++i ) {
797 BC_WindowBase *win = listeners[i]->win;
798 if( win->get_window_type() != POPUP_WINDOW ) continue;
799 ((BC_Popup *)win)->ungrab_keyboard();
803 void BC_ActiveBitmaps::reque(XEvent *event)
805 XShmCompletionEvent *shm_ev = (XShmCompletionEvent *)event;
806 ShmSeg shmseg = shm_ev->shmseg;
807 Drawable drawable = shm_ev->drawable;
808 //printf("BC_BitmapImage::reque %08lx\n",shmseg);
809 active_lock.lock("BC_BitmapImage::reque");
810 BC_BitmapImage *bfr = first;
811 while( bfr && bfr->get_shmseg() != shmseg ) bfr = bfr->next;
812 if( bfr && bfr->drawable == drawable )
814 active_lock.unlock();
816 // sadly, X reports two drawable completions and creates false reporting, so no boobytrap
817 // printf("BC_BitmapImage::reque missed shmseg %08x, drawable %08x\n",
818 // (int)shmseg, (int)drawable);
821 if( bfr->drawable != drawable ) return;
822 if( bfr->is_zombie() ) { --BC_Bitmap::zombies; delete bfr; return; }
823 bfr->bitmap->reque(bfr);
826 void BC_ActiveBitmaps::insert(BC_BitmapImage *bfr, Drawable pixmap)
828 active_lock.lock("BC_BitmapImage::insert");
829 bfr->drawable = pixmap;
831 active_lock.unlock();
834 void BC_ActiveBitmaps::remove_buffers(BC_WindowBase *wdw)
836 active_lock.lock("BC_ActiveBitmaps::remove");
837 for( BC_BitmapImage *nxt=0, *bfr=first; bfr; bfr=nxt ) {
839 if( bfr->is_zombie() ) { --BC_Bitmap::zombies; delete bfr; continue; }
840 if( bfr->bitmap->parent_window == wdw ) remove_pointer(bfr);
842 active_lock.unlock();
845 BC_ActiveBitmaps::BC_ActiveBitmaps()
849 BC_ActiveBitmaps::~BC_ActiveBitmaps()
855 int BC_WindowBase::keysym_lookup(XEvent *event)
857 for( int i = 0; i < KEYPRESSLEN; ++i ) keys_return[i] = 0;
858 for( int i = 0; i < 4; ++i ) wkey_string[i] = 0;
860 if( event->xany.send_event && !event->xany.serial ) {
861 keysym = (KeySym) event->xkey.keycode;
862 keys_return[0] = keysym;
865 wkey_string_length = 0;
867 if( input_context ) {
868 wkey_string_length = XwcLookupString(input_context,
869 (XKeyEvent*)event, wkey_string, 4, &keysym, 0);
870 //printf("keysym_lookup 1 %d %d %lx %x %x %x %x\n", wkey_string_length, keysym,
871 // wkey_string[0], wkey_string[1], wkey_string[2], wkey_string[3]);
874 int ret = Xutf8LookupString(input_context, (XKeyEvent*)event,
875 keys_return, KEYPRESSLEN, &keysym, &stat);
876 //printf("keysym_lookup 2 %d %d %lx %x %x\n", ret, stat, keysym, keys_return[0], keys_return[1]);
877 if( stat == XLookupBoth ) return ret;
878 if( stat == XLookupKeySym ) return 0;
880 int ret = XLookupString((XKeyEvent*)event, keys_return, KEYPRESSLEN, &keysym, 0);
881 wkey_string_length = ret;
882 for( int i=0; i<ret; ++i ) wkey_string[i] = keys_return[i];
886 pthread_t locking_task = (pthread_t)-1L;
887 int locking_event = -1;
888 int locking_message = -1;
890 int BC_WindowBase::dispatch_event(XEvent *event)
894 XClientMessageEvent *ptr;
895 int cancel_resize, cancel_translation;
896 volatile static int debug = 0;
900 #ifndef SINGLE_THREAD
901 // If an event is waiting get it, otherwise
902 // wait for next event only if there are no compressed events.
903 if(get_event_count() ||
904 (!motion_events && !resize_events && !translation_events))
907 // Lock out window deletions
908 lock_window("BC_WindowBase::dispatch_event 1");
909 locking_event = event->type;
910 locking_task = pthread_self();
911 locking_message = event->xclient.message_type;
914 // Handle compressed events
916 lock_window("BC_WindowBase::dispatch_event 2");
918 dispatch_resize_event(last_resize_w, last_resize_h);
920 dispatch_motion_event();
921 if(translation_events)
922 dispatch_translation_event();
933 if( debug && event->type != ClientMessage ) {
934 static const char *event_names[] = {
935 "Reply", "Error", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease", "MotionNotify",
936 "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut", "KeymapNotify", "Expose", "GraphicsExpose",
937 "NoExpose", "VisibilityNotify", "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify",
938 "MapRequest", "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
939 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear",
940 "SelectionRequest", "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify",
941 "GenericEvent", "LASTEvent",
943 const int nevents = sizeof(event_names)/sizeof(event_names[0]);
945 printf("BC_WindowBase::dispatch_event %d %s %p %d (%s)\n", __LINE__,
946 title, event, event->type, event->type>=0 && event->type<nevents ?
947 event_names[event->type] : "Unknown");
952 active_grab->lock_window("BC_WindowBase::dispatch_event 3");
953 result = active_grab->grab_event(event);
954 active_grab->unlock_window();
955 if( result ) return result;
956 lock_window("BC_WindowBase::dispatch_event 4");
959 switch(event->type) {
961 // Clear the resize buffer
963 dispatch_resize_event(last_resize_w, last_resize_h);
964 // Clear the motion buffer since this can clear the window
966 dispatch_motion_event();
968 ptr = (XClientMessageEvent*)event;
969 if( ptr->message_type == ProtoXAtom &&
970 (Atom)ptr->data.l[0] == DelWinXAtom ) {
973 else if( ptr->message_type == RepeaterXAtom ) {
974 dispatch_repeat_event(ptr->data.l[0]);
976 else if( ptr->message_type == SetDoneXAtom ) {
980 receive_custom_xatoms((xatom_event *)ptr);
991 dispatch_focus_out();
1005 dispatch_motion_event();
1007 get_key_masks(event->xbutton.state);
1008 cursor_x = event->xbutton.x;
1009 cursor_y = event->xbutton.y;
1010 button_number = event->xbutton.button;
1012 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1013 event_win = event->xany.window;
1014 if (button_number < 6) {
1015 if(button_number < 4)
1017 button_pressed = event->xbutton.button;
1018 button_time1 = button_time2;
1019 button_time2 = button_time3;
1020 button_time3 = event->xbutton.time;
1023 drag_win = event_win;
1024 drag_x1 = cursor_x - get_resources()->drag_radius;
1025 drag_x2 = cursor_x + get_resources()->drag_radius;
1026 drag_y1 = cursor_y - get_resources()->drag_radius;
1027 drag_y2 = cursor_y + get_resources()->drag_radius;
1029 if((long)(button_time3 - button_time1) < resources.double_click * 2)
1032 button_time3 = button_time2 = button_time1 = 0;
1034 if((long)(button_time3 - button_time2) < resources.double_click)
1037 // button_time3 = button_time2 = button_time1 = 0;
1045 dispatch_button_press();
1052 dispatch_motion_event();
1054 get_key_masks(event->xbutton.state);
1055 button_number = event->xbutton.button;
1056 event_win = event->xany.window;
1057 if (button_number < 6)
1059 if(button_number < 4)
1061 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1063 dispatch_button_release();
1068 event_win = event->xany.window;
1069 dispatch_expose_event();
1073 get_key_masks(event->xmotion.state);
1074 // Dispatch previous motion event if this is a subsequent motion from a different window
1075 if(motion_events && last_motion_win != event->xany.window)
1077 dispatch_motion_event();
1080 // Buffer the current motion
1082 last_motion_state = event->xmotion.state;
1083 last_motion_x = event->xmotion.x;
1084 last_motion_y = event->xmotion.y;
1085 last_motion_win = event->xany.window;
1088 case ConfigureNotify:
1089 // printf("BC_WindowBase::dispatch_event %d win=%p this->win=%p\n",
1091 // event->xany.window,
1094 XTranslateCoordinates(top_level->display,
1102 last_resize_w = event->xconfigure.width;
1103 last_resize_h = event->xconfigure.height;
1106 cancel_translation = 0;
1108 // Resize history prevents responses to recursive resize requests
1109 for(int i = 0; i < resize_history.total && !cancel_resize; i++)
1111 if(resize_history.values[i]->w == last_resize_w &&
1112 resize_history.values[i]->h == last_resize_h)
1114 delete resize_history.values[i];
1115 resize_history.remove_number(i);
1120 if(last_resize_w == w && last_resize_h == h)
1128 if((last_translate_x == x && last_translate_y == y))
1129 cancel_translation = 1;
1131 if(!cancel_translation)
1133 translation_events = 1;
1136 translation_count++;
1140 get_key_masks(event->xkey.state);
1141 keys_return[0] = 0; keysym = -1;
1142 if(XFilterEvent(event, win)) {
1145 if( keysym_lookup(event) < 0 ) {
1146 printf("keysym %x\n", (uint32_t)keysym);
1150 //printf("BC_WindowBase::dispatch_event %d keysym=0x%x\n",
1154 // block out control keys
1155 if(keysym > 0xffe0 && keysym < 0xffff) break;
1156 // block out Alt_GR key
1157 if(keysym == 0xfe03) break;
1160 printf("BC_WindowBase::dispatch_event %x\n", (uint32_t)keysym);
1162 #ifdef X_HAVE_UTF8_STRING
1163 //It's Ascii or UTF8?
1164 // if (keysym != 0xffff && (keys_return[0] & 0xff) >= 0x7f )
1165 //printf("BC_WindowBase::dispatch_event %d %02x%02x\n", __LINE__, keys_return[0], keys_return[1]);
1167 if( ((keys_return[1] & 0xff) > 0x80) &&
1168 ((keys_return[0] & 0xff) > 0xC0) ) {
1169 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1170 key_pressed = keysym & 0xff;
1174 // shuttle speed codes
1175 if( keysym >= SKEY_MIN && keysym <= SKEY_MAX ) {
1176 key_pressed = keysym;
1178 else switch( keysym ) {
1179 // block out extra keys
1189 // Translate key codes
1190 case XK_Return: key_pressed = RETURN; break;
1191 case XK_Up: key_pressed = UP; break;
1192 case XK_Down: key_pressed = DOWN; break;
1193 case XK_Left: key_pressed = LEFT; break;
1194 case XK_Right: key_pressed = RIGHT; break;
1195 case XK_Next: key_pressed = PGDN; break;
1196 case XK_Prior: key_pressed = PGUP; break;
1197 case XK_BackSpace: key_pressed = BACKSPACE; break;
1198 case XK_Escape: key_pressed = ESC; break;
1201 key_pressed = LEFTTAB;
1205 case XK_ISO_Left_Tab: key_pressed = LEFTTAB; break;
1206 case XK_underscore: key_pressed = '_'; break;
1207 case XK_asciitilde: key_pressed = '~'; break;
1208 case XK_Delete: key_pressed = DELETE; break;
1209 case XK_Home: key_pressed = HOME; break;
1210 case XK_End: key_pressed = END; break;
1213 case XK_KP_Enter: key_pressed = KPENTER; break;
1214 case XK_KP_Add: key_pressed = KPPLUS; break;
1215 case XK_KP_Subtract: key_pressed = KPMINUS; break;
1216 case XK_KP_Multiply: key_pressed = KPSTAR; break;
1217 case XK_KP_Divide: key_pressed = KPSLASH; break;
1219 case XK_KP_End: key_pressed = KP1; break;
1221 case XK_KP_Down: key_pressed = KP2; break;
1223 case XK_KP_Page_Down: key_pressed = KP3; break;
1225 case XK_KP_Left: key_pressed = KP4; break;
1227 case XK_KP_Begin: key_pressed = KP5; break;
1229 case XK_KP_Right: key_pressed = KP6; break;
1231 case XK_KP_Home: key_pressed = KP7; break;
1233 case XK_KP_Up: key_pressed = KP8; break;
1235 case XK_KP_Page_Up: key_pressed = KP9; break;
1237 case XK_KP_Insert: key_pressed = KPINS; break;
1239 case XK_KP_Delete: key_pressed = KPDEL; break;
1241 case XK_F1: key_pressed = KEY_F1; break;
1242 case XK_F2: key_pressed = KEY_F2; break;
1243 case XK_F3: key_pressed = KEY_F3; break;
1244 case XK_F4: key_pressed = KEY_F4; break;
1245 case XK_F5: key_pressed = KEY_F5; break;
1246 case XK_F6: key_pressed = KEY_F6; break;
1247 case XK_F7: key_pressed = KEY_F7; break;
1248 case XK_F8: key_pressed = KEY_F8; break;
1249 case XK_F9: key_pressed = KEY_F9; break;
1250 case XK_F10: key_pressed = KEY_F10; break;
1251 case XK_F11: key_pressed = KEY_F11; break;
1252 case XK_F12: key_pressed = KEY_F12; break;
1254 case XK_Menu: key_pressed = KPMENU; break; /* menu */
1256 // above case XK_KP_Enter: key_pressed = KPENTER; break; /* check */
1257 case XF86XK_MenuKB: key_pressed = KPMENU; break; /* menu */
1258 // intercepted case XF86XK_PowerDown: key_pressed = KPPOWER; break; /* Power */
1259 case XF86XK_Launch1: key_pressed = KPTV; break; /* TV */
1260 case XF86XK_Launch2: key_pressed = KPDVD; break; /* DVD */
1261 // intercepted case XF86XK_WWW: key_pressed = KPWWEB; break; /* WEB */
1262 case XF86XK_Launch3: key_pressed = KPBOOK; break; /* book */
1263 case XF86XK_Launch4: key_pressed = KPHAND; break; /* hand */
1264 case XF86XK_Reply: key_pressed = KPTMR; break; /* timer */
1265 case SunXK_Front: key_pressed = KPMAXW; break; /* max */
1266 // above case XK_Left: key_pressed = LEFT; break; /* left */
1267 // above case XK_Right: key_pressed = RIGHT; break; /* right */
1268 // above case XK_Down: key_pressed = DOWN; break; /* down */
1269 // above case XK_Up: key_pressed = UP; break; /* up */
1270 // above case XK_SPACE: key_pressed = KPSPACE; break; /* ok */
1271 // intercepted case XF86XK_AudioRaiseVolume: key_pressed = KPVOLU; break; /* VOL + */
1272 // intercepted case XF86XK_AudioMute: key_pressed = KPMUTE; break; /* MUTE */
1273 // intercepted case XF86XK_AudioLowerVolume: key_pressed = KPVOLD; break; /* VOL - */
1274 case XF86XK_ScrollUp: key_pressed = KPCHUP; break; /* CH + */
1275 case XF86XK_ScrollDown: key_pressed = KPCHDN; break; /* CH - */
1276 case XF86XK_AudioRecord: key_pressed = KPRECD; break; /* ( o) red */
1277 case XF86XK_Forward: key_pressed = KPPLAY; break; /* ( >) */
1278 case XK_Redo: key_pressed = KPFWRD; break; /* (>>) */
1279 case XF86XK_Back: key_pressed = KPBACK; break; /* (<<) */
1280 case XK_Cancel: key_pressed = KPSTOP; break; /* ([]) */
1281 case XK_Pause: key_pressed = KPAUSE; break; /* ('') */
1284 key_pressed = keysym & 0xff;
1285 #ifdef X_HAVE_UTF8_STRING
1286 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1291 #ifdef X_HAVE_UTF8_STRING
1293 key_pressed_utf8 = keys_return;
1298 if( top_level == this )
1299 result = BC_KeyboardHandler::run_listeners(this);
1301 //printf("BC_WindowBase::dispatch_event %d %d %x\n", shift_down(), alt_down(), key_pressed);
1303 result = dispatch_keypress_event();
1304 // Handle some default keypresses
1307 if(key_pressed == 'w' ||
1316 XLookupString((XKeyEvent*)event, keys_return, 1, &keysym, 0);
1317 dispatch_keyrelease_event();
1318 // printf("BC_WindowBase::dispatch_event KeyRelease keysym=0x%x keystate=0x%lld\n",
1319 // keysym, event->xkey.state);
1323 if( event->xcrossing.mode != NotifyNormal ) break;
1325 event_win = event->xany.window;
1326 dispatch_cursor_leave();
1330 if( event->xcrossing.mode != NotifyNormal ) break;
1332 if( !cursor_entered ) {
1333 for( int i=0; i<popups.size(); ++i ) { // popups always take focus
1334 if( popups[i]->win == event->xcrossing.window )
1337 if( !cursor_entered && get_resources()->grab_input_focus &&
1338 !event->xcrossing.focus && event->xcrossing.window == win ) {
1341 if( cursor_entered )
1344 event_win = event->xany.window;
1345 cursor_x = event->xcrossing.x;
1346 cursor_y = event->xcrossing.y;
1347 dispatch_cursor_enter();
1353 //printf("100 %s %p %d\n", title, event, event->type);
1354 //if(event->type != ClientMessage) dump();
1356 #ifndef SINGLE_THREAD
1359 if( resend_event_window ) {
1360 resend_event_window->put_event(event);
1361 resend_event_window = 0;
1367 // if(done) completion_lock->unlock();
1370 if(debug) printf("BC_WindowBase::dispatch_event this=%p %d\n", this, __LINE__);
1374 int BC_WindowBase::dispatch_expose_event()
1377 for(int i = 0; i < subwindows->total && !result; i++)
1379 result = subwindows->values[i]->dispatch_expose_event();
1382 // Propagate to user
1383 if(!result) expose_event();
1387 int BC_WindowBase::dispatch_resize_event(int w, int h)
1389 // Can't store new w and h until the event is handles
1390 // because bcfilebox depends on the old w and h to
1391 // reposition widgets.
1392 if( window_type == MAIN_WINDOW ) {
1397 pixmap = new BC_Pixmap(this, w, h);
1398 clear_box(0, 0, w, h);
1401 // Propagate to subwindows
1402 for(int i = 0; i < subwindows->total; i++) {
1403 subwindows->values[i]->dispatch_resize_event(w, h);
1406 // Propagate to user
1409 if( window_type == MAIN_WINDOW ) {
1418 int BC_WindowBase::dispatch_flash()
1421 for(int i = 0; i < subwindows->total; i++)
1422 subwindows->values[i]->dispatch_flash();
1426 int BC_WindowBase::dispatch_translation_event()
1428 translation_events = 0;
1429 if(window_type == MAIN_WINDOW)
1433 x = last_translate_x;
1434 y = last_translate_y;
1435 // Correct for window manager offsets
1440 for(int i = 0; i < subwindows->total; i++)
1442 subwindows->values[i]->dispatch_translation_event();
1445 translation_event();
1449 int BC_WindowBase::dispatch_motion_event()
1454 if(top_level == this)
1457 event_win = last_motion_win;
1458 get_key_masks(last_motion_state);
1461 if(get_button_down() && !active_menubar && !active_popup_menu)
1465 cursor_x = last_motion_x;
1466 cursor_y = last_motion_y;
1467 result = dispatch_drag_motion();
1471 (last_motion_x < drag_x1 || last_motion_x >= drag_x2 ||
1472 last_motion_y < drag_y1 || last_motion_y >= drag_y2))
1477 result = dispatch_drag_start();
1481 cursor_x = last_motion_x;
1482 cursor_y = last_motion_y;
1484 // printf("BC_WindowBase::dispatch_motion_event %d %p %p %p\n",
1487 // active_popup_menu,
1488 // active_subwindow);
1490 if(active_menubar && !result) result = active_menubar->dispatch_motion_event();
1491 if(active_popup_menu && !result) result = active_popup_menu->dispatch_motion_event();
1492 if(active_subwindow && !result) result = active_subwindow->dispatch_motion_event();
1495 // Dispatch in stacking order
1496 for(int i = subwindows->size() - 1; i >= 0 && !result; i--)
1498 result = subwindows->values[i]->dispatch_motion_event();
1501 if(!result) result = cursor_motion_event(); // give to user
1505 int BC_WindowBase::dispatch_keypress_event()
1508 if(top_level == this)
1510 if(active_subwindow) result = active_subwindow->dispatch_keypress_event();
1513 for(int i = 0; i < subwindows->total && !result; i++)
1515 result = subwindows->values[i]->dispatch_keypress_event();
1518 if(!result) result = keypress_event();
1523 int BC_WindowBase::dispatch_keyrelease_event()
1526 if(top_level == this)
1528 if(active_subwindow) result = active_subwindow->dispatch_keyrelease_event();
1531 for(int i = 0; i < subwindows->total && !result; i++)
1533 result = subwindows->values[i]->dispatch_keyrelease_event();
1536 if(!result) result = keyrelease_event();
1541 int BC_WindowBase::dispatch_focus_in()
1543 for(int i = 0; i < subwindows->total; i++)
1545 subwindows->values[i]->dispatch_focus_in();
1553 int BC_WindowBase::dispatch_focus_out()
1555 for(int i = 0; i < subwindows->total; i++)
1557 subwindows->values[i]->dispatch_focus_out();
1565 int BC_WindowBase::get_has_focus()
1567 return top_level->has_focus;
1570 int BC_WindowBase::get_deleting()
1572 if(is_deleting) return 1;
1573 if(parent_window && parent_window->get_deleting()) return 1;
1577 int BC_WindowBase::dispatch_button_press()
1582 if(top_level == this)
1584 if(active_menubar) result = active_menubar->dispatch_button_press();
1585 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_press();
1586 if(active_subwindow && !result) result = active_subwindow->dispatch_button_press();
1589 for(int i = 0; i < subwindows->total && !result; i++)
1591 result = subwindows->values[i]->dispatch_button_press();
1594 if(!result) result = button_press_event();
1600 int BC_WindowBase::dispatch_button_release()
1603 if(top_level == this)
1605 if(active_menubar) result = active_menubar->dispatch_button_release();
1606 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_release();
1607 if(active_subwindow && !result) result = active_subwindow->dispatch_button_release();
1608 if(!result && button_number != 4 && button_number != 5)
1609 result = dispatch_drag_stop();
1612 for(int i = 0; i < subwindows->total && !result; i++)
1614 result = subwindows->values[i]->dispatch_button_release();
1619 result = button_release_event();
1626 int BC_WindowBase::dispatch_repeat_event(int64_t duration)
1629 // all repeat event handlers get called and decide based on activity and duration
1630 // whether to respond
1631 for(int i = 0; i < subwindows->total; i++)
1633 subwindows->values[i]->dispatch_repeat_event(duration);
1637 repeat_event(duration);
1641 // Unlock next repeat signal
1642 if(window_type == MAIN_WINDOW)
1644 #ifdef SINGLE_THREAD
1645 BC_Display::display_global->unlock_repeaters(duration);
1647 for(int i = 0; i < repeaters.total; i++)
1649 if(repeaters.values[i]->delay == duration)
1651 repeaters.values[i]->repeat_lock->unlock();
1659 void BC_WindowBase::unhide_cursor()
1664 if(top_level->is_hourglass)
1665 set_cursor(HOURGLASS_CURSOR, 1, 0);
1667 set_cursor(current_cursor, 1, 0);
1669 cursor_timer->update();
1673 void BC_WindowBase::update_video_cursor()
1675 if(video_on && !is_transparent)
1677 if(cursor_timer->get_difference() > VIDEO_CURSOR_TIMEOUT && !is_transparent)
1680 set_cursor(TRANSPARENT_CURSOR, 1, 1);
1681 cursor_timer->update();
1686 cursor_timer->update();
1691 int BC_WindowBase::dispatch_cursor_leave()
1695 for(int i = 0; i < subwindows->total; i++)
1697 subwindows->values[i]->dispatch_cursor_leave();
1700 cursor_leave_event();
1704 int BC_WindowBase::dispatch_cursor_enter()
1710 if(active_menubar) result = active_menubar->dispatch_cursor_enter();
1711 if(!result && active_popup_menu) result = active_popup_menu->dispatch_cursor_enter();
1712 if(!result && active_subwindow) result = active_subwindow->dispatch_cursor_enter();
1714 for(int i = 0; !result && i < subwindows->total; i++)
1716 result = subwindows->values[i]->dispatch_cursor_enter();
1719 if(!result) result = cursor_enter_event();
1723 int BC_WindowBase::cursor_enter_event()
1728 int BC_WindowBase::cursor_leave_event()
1733 int BC_WindowBase::close_event()
1739 int BC_WindowBase::dispatch_drag_start()
1742 if(active_menubar) result = active_menubar->dispatch_drag_start();
1743 if(!result && active_popup_menu) result = active_popup_menu->dispatch_drag_start();
1744 if(!result && active_subwindow) result = active_subwindow->dispatch_drag_start();
1746 for(int i = 0; i < subwindows->total && !result; i++)
1748 result = subwindows->values[i]->dispatch_drag_start();
1751 if(!result) result = is_dragging = drag_start_event();
1755 int BC_WindowBase::dispatch_drag_stop()
1759 for(int i = 0; i < subwindows->total && !result; i++)
1761 result = subwindows->values[i]->dispatch_drag_stop();
1764 if(is_dragging && !result)
1774 int BC_WindowBase::dispatch_drag_motion()
1777 for(int i = 0; i < subwindows->total && !result; i++)
1779 result = subwindows->values[i]->dispatch_drag_motion();
1782 if(is_dragging && !result)
1784 drag_motion_event();
1792 int BC_WindowBase::show_tooltip(const char *text, int x, int y, int w, int h)
1795 int forced = !text ? force_tooltip : 1;
1796 if( !text ) text = tooltip_text;
1797 if( !text || (!forced && !get_resources()->tooltips_enabled) ) {
1798 top_level->hide_tooltip();
1802 if(w < 0) w = get_text_width(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1803 if(h < 0) h = get_text_height(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1804 // default x,y (win relative)
1805 if( x < 0 ) x = get_w();
1806 if( y < 0 ) y = get_h();
1808 get_root_coordinates(x, y, &wx, &wy);
1809 // keep the tip inside the window/display
1810 int x0 = top_level->get_x(), x1 = x0 + top_level->get_w();
1811 int x2 = top_level->get_screen_x(0, -1) + top_level->get_screen_w(0, -1);
1812 if( x1 > x2 ) x1 = x2;
1813 if( wx < x0 ) wx = x0;
1814 if( wx >= (x1-=w) ) wx = x1;
1815 int y0 = top_level->get_y(), y1 = y0 + top_level->get_h();
1816 int y2 = top_level->get_root_h(0);
1817 if( y1 > y2 ) y1 = y2;
1818 if( wy < y0 ) wy = y0;
1819 if( wy >= (y1-=h) ) wy = y1;
1820 // avoid tip under cursor (flickers)
1822 get_abs_cursor(abs_x,abs_y, 0);
1823 if( wx < abs_x && abs_x < wx+w && wy < abs_y && abs_y < wy+h ) {
1824 if( wx-abs_x < wy-abs_y )
1831 tooltip_popup = new BC_Popup(top_level, wx, wy, w, h,
1832 get_resources()->tooltip_bg_color);
1835 tooltip_popup->reposition_window(wx, wy, w, h);
1838 tooltip_popup->flash();
1839 tooltip_popup->flush();
1843 int BC_WindowBase::hide_tooltip()
1846 for(int i = 0; i < subwindows->total; i++)
1848 subwindows->values[i]->hide_tooltip();
1854 delete tooltip_popup;
1860 const char *BC_WindowBase::get_tooltip()
1862 return tooltip_text;
1865 int BC_WindowBase::set_tooltip(const char *text)
1867 tooltip_text = text;
1869 // Update existing tooltip if it is visible
1873 tooltip_popup->flash();
1877 // signal the event handler to repeat
1878 int BC_WindowBase::set_repeat(int64_t duration)
1882 printf("BC_WindowBase::set_repeat duration=%jd\n", duration);
1885 if(window_type != MAIN_WINDOW) return top_level->set_repeat(duration);
1887 #ifdef SINGLE_THREAD
1888 BC_Display::display_global->set_repeat(this, duration);
1890 // test repeater database for duplicates
1891 for(int i = 0; i < repeaters.total; i++)
1894 if(repeaters.values[i]->delay == duration)
1896 repeaters.values[i]->start_repeating(this);
1901 BC_Repeater *repeater = new BC_Repeater(this, duration);
1902 repeater->initialize();
1903 repeaters.append(repeater);
1904 repeater->start_repeating();
1909 int BC_WindowBase::unset_repeat(int64_t duration)
1911 if(window_type != MAIN_WINDOW) return top_level->unset_repeat(duration);
1913 #ifdef SINGLE_THREAD
1914 BC_Display::display_global->unset_repeat(this, duration);
1916 for(int i = 0; i < repeaters.total; i++)
1918 if(repeaters.values[i]->delay == duration)
1920 repeaters.values[i]->stop_repeating();
1928 int BC_WindowBase::unset_all_repeaters()
1930 #ifdef SINGLE_THREAD
1931 BC_Display::display_global->unset_all_repeaters(this);
1933 for(int i = 0; i < repeaters.total; i++)
1935 repeaters.values[i]->stop_repeating();
1937 repeaters.remove_all_objects();
1942 // long BC_WindowBase::get_repeat_id()
1944 // return top_level->next_repeat_id++;
1947 XEvent *BC_WindowBase::new_xevent()
1949 XEvent *event = new XEvent;
1950 memset(event, 0, sizeof(*event));
1954 #ifndef SINGLE_THREAD
1955 int BC_WindowBase::arm_repeat(int64_t duration)
1957 XEvent *event = new_xevent();
1958 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
1959 ptr->type = ClientMessage;
1960 ptr->message_type = RepeaterXAtom;
1962 ptr->data.l[0] = duration;
1964 // Couldn't use XSendEvent since it locked up randomly.
1970 int BC_WindowBase::receive_custom_xatoms(xatom_event *event)
1975 int BC_WindowBase::send_custom_xatom(xatom_event *event)
1977 #ifndef SINGLE_THREAD
1978 XEvent *myevent = new_xevent();
1979 XClientMessageEvent *ptr = (XClientMessageEvent*)myevent;
1980 ptr->type = ClientMessage;
1981 ptr->message_type = event->message_type;
1982 ptr->format = event->format;
1983 ptr->data.l[0] = event->data.l[0];
1984 ptr->data.l[1] = event->data.l[1];
1985 ptr->data.l[2] = event->data.l[2];
1986 ptr->data.l[3] = event->data.l[3];
1987 ptr->data.l[4] = event->data.l[4];
1996 Atom BC_WindowBase::create_xatom(const char *atom_name)
1998 return XInternAtom(display, atom_name, False);
2001 int BC_WindowBase::get_atoms()
2003 SetDoneXAtom = XInternAtom(display, "BC_REPEAT_EVENT", False);
2004 RepeaterXAtom = XInternAtom(display, "BC_CLOSE_EVENT", False);
2005 DestroyAtom = XInternAtom(display, "BC_DESTROY_WINDOW", False);
2006 DelWinXAtom = XInternAtom(display, "WM_DELETE_WINDOW", False);
2007 if( (ProtoXAtom = XInternAtom(display, "WM_PROTOCOLS", False)) != 0 )
2008 XChangeProperty(display, win, ProtoXAtom, XA_ATOM, 32,
2009 PropModeReplace, (unsigned char *)&DelWinXAtom, True);
2015 void BC_WindowBase::init_cursors()
2017 arrow_cursor = XCreateFontCursor(display, XC_top_left_arrow);
2018 cross_cursor = XCreateFontCursor(display, XC_crosshair);
2019 ibeam_cursor = XCreateFontCursor(display, XC_xterm);
2020 vseparate_cursor = XCreateFontCursor(display, XC_sb_v_double_arrow);
2021 hseparate_cursor = XCreateFontCursor(display, XC_sb_h_double_arrow);
2022 move_cursor = XCreateFontCursor(display, XC_fleur);
2023 left_cursor = XCreateFontCursor(display, XC_sb_left_arrow);
2024 right_cursor = XCreateFontCursor(display, XC_sb_right_arrow);
2025 upright_arrow_cursor = XCreateFontCursor(display, XC_arrow);
2026 upleft_resize_cursor = XCreateFontCursor(display, XC_top_left_corner);
2027 upright_resize_cursor = XCreateFontCursor(display, XC_top_right_corner);
2028 downleft_resize_cursor = XCreateFontCursor(display, XC_bottom_left_corner);
2029 downright_resize_cursor = XCreateFontCursor(display, XC_bottom_right_corner);
2030 hourglass_cursor = XCreateFontCursor(display, XC_watch);
2031 grabbed_cursor = create_grab_cursor();
2033 static char cursor_data[] = { 0,0,0,0, 0,0,0,0 };
2034 Colormap colormap = DefaultColormap(display, screen);
2035 Pixmap pixmap_bottom = XCreateBitmapFromData(display,
2036 rootwin, cursor_data, 8, 8);
2037 XColor black, dummy;
2038 XAllocNamedColor(display, colormap, "black", &black, &dummy);
2039 transparent_cursor = XCreatePixmapCursor(display,
2040 pixmap_bottom, pixmap_bottom, &black, &black, 0, 0);
2041 // XDefineCursor(display, win, transparent_cursor);
2042 XFreePixmap(display, pixmap_bottom);
2045 int BC_WindowBase::evaluate_color_model(int client_byte_order, int server_byte_order, int depth)
2047 int color_model = BC_TRANSPARENCY;
2051 color_model = BC_RGB8;
2054 color_model = (server_byte_order == client_byte_order) ? BC_RGB565 : BC_BGR565;
2057 color_model = server_byte_order ? BC_BGR888 : BC_RGB888;
2060 color_model = server_byte_order ? BC_BGR8888 : BC_ARGB8888;
2066 int BC_WindowBase::init_colors()
2069 current_color_value = current_color_pixel = 0;
2071 // Get the real depth
2074 ximage = XCreateImage(top_level->display,
2076 top_level->default_depth,
2084 bits_per_pixel = ximage->bits_per_pixel;
2085 XDestroyImage(ximage);
2087 color_model = evaluate_color_model(client_byte_order,
2090 // Get the color model
2095 cmap = XCreateColormap(display, rootwin, vis, AllocNone);
2096 create_private_colors();
2099 cmap = DefaultColormap(display, screen);
2100 create_shared_colors();
2103 allocate_color_table();
2107 //cmap = DefaultColormap(display, screen);
2108 cmap = XCreateColormap(display, rootwin, vis, AllocNone );
2114 int BC_WindowBase::create_private_colors()
2119 for(int i = 0; i < 255; i++)
2121 color = (i & 0xc0) << 16;
2122 color += (i & 0x38) << 10;
2123 color += (i & 0x7) << 5;
2124 color_table[i][0] = color;
2126 create_shared_colors(); // overwrite the necessary colors on the table
2131 int BC_WindowBase::create_color(int color)
2133 if(total_colors == 256)
2135 // replace the closest match with an exact match
2136 color_table[get_color_rgb8(color)][0] = color;
2140 // add the color to the table
2141 color_table[total_colors][0] = color;
2147 int BC_WindowBase::create_shared_colors()
2149 create_color(BLACK);
2150 create_color(WHITE);
2152 create_color(LTGREY);
2153 create_color(MEGREY);
2154 create_color(MDGREY);
2155 create_color(DKGREY);
2157 create_color(LTCYAN);
2158 create_color(MECYAN);
2159 create_color(MDCYAN);
2160 create_color(DKCYAN);
2162 create_color(LTGREEN);
2163 create_color(GREEN);
2164 create_color(DKGREEN);
2166 create_color(LTPINK);
2170 create_color(LTBLUE);
2172 create_color(DKBLUE);
2174 create_color(LTYELLOW);
2175 create_color(MEYELLOW);
2176 create_color(MDYELLOW);
2177 create_color(DKYELLOW);
2179 create_color(LTPURPLE);
2180 create_color(MEPURPLE);
2181 create_color(MDPURPLE);
2182 create_color(DKPURPLE);
2184 create_color(FGGREY);
2185 create_color(MNBLUE);
2186 create_color(ORANGE);
2187 create_color(FTGREY);
2192 Cursor BC_WindowBase::create_grab_cursor()
2194 int iw = 23, iw1 = iw-1, iw2 = iw/2;
2195 int ih = 23, ih1 = ih-1, ih2 = ih/2;
2196 VFrame grab(iw,ih,BC_RGB888);
2198 grab.set_pixel_color(RED); // fg
2199 grab.draw_smooth(iw2,0, iw1,0, iw1,ih2);
2200 grab.draw_smooth(iw1,ih2, iw1,ih1, iw2,ih1);
2201 grab.draw_smooth(iw2,ih1, 0,ih1, 0,ih2);
2202 grab.draw_smooth(0,ih2, 0,0, iw2,0);
2203 grab.set_pixel_color(WHITE); // bg
2204 grab.draw_line(0,ih2, iw2-2,ih2);
2205 grab.draw_line(iw2+2,ih2, iw1,ih2);
2206 grab.draw_line(iw2,0, iw2,ih2-2);
2207 grab.draw_line(iw2,ih2+2, iw2,ih1);
2209 int bpl = (iw+7)/8, isz = bpl * ih;
2210 char img[isz]; memset(img, 0, isz);
2211 char msk[isz]; memset(msk, 0, isz);
2212 unsigned char **rows = grab.get_rows();
2213 for( int iy=0; iy<ih; ++iy ) {
2214 char *op = img + iy*bpl;
2215 char *mp = msk + iy*bpl;
2216 unsigned char *ip = rows[iy];
2217 for( int ix=0; ix<iw; ++ix,ip+=3 ) {
2218 if( ip[0] ) mp[ix>>3] |= (1<<(ix&7));
2219 if( !ip[1] ) op[ix>>3] |= (1<<(ix&7));
2222 unsigned long white_pix = WhitePixel(display, screen);
2223 unsigned long black_pix = BlackPixel(display, screen);
2224 Pixmap img_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2225 img, iw,ih, white_pix,black_pix, 1);
2226 Pixmap msk_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2227 msk, iw,ih, white_pix,black_pix, 1);
2230 fc.flags = bc.flags = DoRed | DoGreen | DoBlue;
2231 fc.red = 0xffff; fc.green = fc.blue = 0; // fg
2232 bc.red = 0xffff; bc.green = 0xffff; bc.blue = 0x0000; // bg
2233 Cursor cursor = XCreatePixmapCursor(display, img_xpm,msk_xpm, &fc,&bc, iw2,ih2);
2234 XFreePixmap(display, img_xpm);
2235 XFreePixmap(display, msk_xpm);
2239 int BC_WindowBase::allocate_color_table()
2241 int red, green, blue, color;
2244 for(int i = 0; i < total_colors; i++)
2246 color = color_table[i][0];
2247 red = (color & 0xFF0000) >> 16;
2248 green = (color & 0x00FF00) >> 8;
2249 blue = color & 0xFF;
2251 col.flags = DoRed | DoGreen | DoBlue;
2252 col.red = red<<8 | red;
2253 col.green = green<<8 | green;
2254 col.blue = blue<<8 | blue;
2256 XAllocColor(display, cmap, &col);
2257 color_table[i][1] = col.pixel;
2260 XInstallColormap(display, cmap);
2264 int BC_WindowBase::init_window_shape()
2266 if(bg_pixmap && bg_pixmap->use_alpha())
2268 XShapeCombineMask(top_level->display,
2269 this->win, ShapeBounding, 0, 0,
2270 bg_pixmap->get_alpha(), ShapeSet);
2276 int BC_WindowBase::init_gc()
2278 unsigned long gcmask;
2279 gcmask = GCFont | GCGraphicsExposures;
2282 gcvalues.font = mediumfont->fid; // set the font
2283 gcvalues.graphics_exposures = 0; // prevent expose events for every redraw
2284 gc = XCreateGC(display, rootwin, gcmask, &gcvalues);
2286 // gcmask = GCCapStyle | GCJoinStyle;
2287 // XGetGCValues(display, gc, gcmask, &gcvalues);
2288 // printf("BC_WindowBase::init_gc %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2292 int BC_WindowBase::init_fonts()
2294 if( !(smallfont = XLoadQueryFont(display, _(resources.small_font))) )
2295 if( !(smallfont = XLoadQueryFont(display, _(resources.small_font2))) )
2296 smallfont = XLoadQueryFont(display, "fixed");
2297 if( !(mediumfont = XLoadQueryFont(display, _(resources.medium_font))) )
2298 if( !(mediumfont = XLoadQueryFont(display, _(resources.medium_font2))) )
2299 mediumfont = XLoadQueryFont(display, "fixed");
2300 if( !(largefont = XLoadQueryFont(display, _(resources.large_font))) )
2301 if( !(largefont = XLoadQueryFont(display, _(resources.large_font2))) )
2302 largefont = XLoadQueryFont(display, "fixed");
2303 if( !(bigfont = XLoadQueryFont(display, _(resources.big_font))) )
2304 if( !(bigfont = XLoadQueryFont(display, _(resources.big_font2))) )
2305 bigfont = XLoadQueryFont(display, "fixed");
2307 if((clockfont = XLoadQueryFont(display, _(resources.clock_font))) == NULL)
2308 if((clockfont = XLoadQueryFont(display, _(resources.clock_font2))) == NULL)
2309 clockfont = XLoadQueryFont(display, "fixed");
2312 if(get_resources()->use_fontset)
2317 // FIXME: should check the m,d,n values
2318 smallfontset = XCreateFontSet(display, resources.small_fontset, &m, &n, &d);
2320 smallfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2321 mediumfontset = XCreateFontSet(display, resources.medium_fontset, &m, &n, &d);
2322 if( !mediumfontset )
2323 mediumfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2324 largefontset = XCreateFontSet(display, resources.large_fontset, &m, &n, &d);
2326 largefontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2327 bigfontset = XCreateFontSet(display, resources.big_fontset, &m, &n, &d);
2329 bigfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2330 clockfontset = XCreateFontSet(display, resources.clock_fontset, &m, &n, &d);
2332 clockfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2333 if(clockfontset && bigfontset && largefontset && mediumfontset && smallfontset) {
2334 curr_fontset = mediumfontset;
2335 get_resources()->use_fontset = 1;
2339 get_resources()->use_fontset = 0;
2346 void BC_WindowBase::init_xft()
2349 if( !get_resources()->use_xft ) return;
2350 // apparently, xft is not reentrant, more than this is needed
2351 static Mutex xft_init_lock("BC_WindowBase::xft_init_lock", 0);
2352 xft_init_lock.lock("BC_WindowBase::init_xft");
2353 if(!(smallfont_xft =
2354 (resources.small_font_xft[0] == '-' ?
2355 xftFontOpenXlfd(display, screen, resources.small_font_xft) :
2356 xftFontOpenName(display, screen, resources.small_font_xft))) )
2357 if(!(smallfont_xft =
2358 xftFontOpenXlfd(display, screen, resources.small_font_xft2)))
2359 smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2360 if(!(mediumfont_xft =
2361 (resources.medium_font_xft[0] == '-' ?
2362 xftFontOpenXlfd(display, screen, resources.medium_font_xft) :
2363 xftFontOpenName(display, screen, resources.medium_font_xft))) )
2364 if(!(mediumfont_xft =
2365 xftFontOpenXlfd(display, screen, resources.medium_font_xft2)))
2366 mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2367 if(!(largefont_xft =
2368 (resources.large_font_xft[0] == '-' ?
2369 xftFontOpenXlfd(display, screen, resources.large_font_xft) :
2370 xftFontOpenName(display, screen, resources.large_font_xft))) )
2371 if(!(largefont_xft =
2372 xftFontOpenXlfd(display, screen, resources.large_font_xft2)))
2373 largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2375 (resources.big_font_xft[0] == '-' ?
2376 xftFontOpenXlfd(display, screen, resources.big_font_xft) :
2377 xftFontOpenName(display, screen, resources.big_font_xft))) )
2379 xftFontOpenXlfd(display, screen, resources.big_font_xft2)))
2380 bigfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2381 if(!(clockfont_xft =
2382 (resources.clock_font_xft[0] == '-' ?
2383 xftFontOpenXlfd(display, screen, resources.clock_font_xft) :
2384 xftFontOpenName(display, screen, resources.clock_font_xft))) )
2385 clockfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2388 if(!(bold_smallfont_xft =
2389 (resources.small_b_font_xft[0] == '-' ?
2390 xftFontOpenXlfd(display, screen, resources.small_b_font_xft) :
2391 xftFontOpenName(display, screen, resources.small_b_font_xft))) )
2392 bold_smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2393 if(!(bold_mediumfont_xft =
2394 (resources.medium_b_font_xft[0] == '-' ?
2395 xftFontOpenXlfd(display, screen, resources.medium_b_font_xft) :
2396 xftFontOpenName(display, screen, resources.medium_b_font_xft))) )
2397 bold_mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2398 if(!(bold_largefont_xft =
2399 (resources.large_b_font_xft[0] == '-' ?
2400 xftFontOpenXlfd(display, screen, resources.large_b_font_xft) :
2401 xftFontOpenName(display, screen, resources.large_b_font_xft))) )
2402 bold_largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2404 if( !smallfont_xft || !mediumfont_xft || !largefont_xft || !bigfont_xft ||
2405 !bold_largefont_xft || !bold_mediumfont_xft || !bold_largefont_xft ||
2407 printf("BC_WindowBase::init_fonts: no xft fonts found:"
2408 " %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n",
2409 resources.small_font_xft, smallfont_xft,
2410 resources.medium_font_xft, mediumfont_xft,
2411 resources.large_font_xft, largefont_xft,
2412 resources.big_font_xft, bigfont_xft,
2413 resources.clock_font_xft, clockfont_xft,
2414 resources.small_b_font_xft, bold_smallfont_xft,
2415 resources.medium_b_font_xft, bold_mediumfont_xft,
2416 resources.large_b_font_xft, bold_largefont_xft);
2417 get_resources()->use_xft = 0;
2420 // _XftDisplayInfo needs a lock.
2421 xftDefaultHasRender(display);
2422 xft_init_lock.unlock();
2426 void BC_WindowBase::init_im()
2428 XIMStyles *xim_styles;
2431 if(!(input_method = XOpenIM(display, NULL, NULL, NULL)))
2433 printf("BC_WindowBase::init_im: Could not open input method.\n");
2436 if(XGetIMValues(input_method, XNQueryInputStyle, &xim_styles, NULL) ||
2439 printf("BC_WindowBase::init_im: Input method doesn't support any styles.\n");
2440 XCloseIM(input_method);
2445 for(int z = 0; z < xim_styles->count_styles; z++)
2447 if(xim_styles->supported_styles[z] == (XIMPreeditNothing | XIMStatusNothing))
2449 xim_style = xim_styles->supported_styles[z];
2457 printf("BC_WindowBase::init_im: Input method doesn't support the style we need.\n");
2458 XCloseIM(input_method);
2462 input_context = XCreateIC(input_method, XNInputStyle, xim_style,
2463 XNClientWindow, win, XNFocusWindow, win, NULL);
2466 printf("BC_WindowBase::init_im: Failed to create input context.\n");
2467 XCloseIM(input_method);
2472 void BC_WindowBase::finit_im()
2474 if( input_context ) {
2475 XDestroyIC(input_context);
2478 if( input_method ) {
2479 XCloseIM(input_method);
2485 int BC_WindowBase::get_color(int64_t color)
2487 // return pixel of color
2488 // use this only for drawing subwindows not for bitmaps
2489 int i, test, difference;
2495 return get_color_rgb8(color);
2496 // test last color looked up
2497 if(current_color_value == color)
2498 return current_color_pixel;
2501 current_color_value = color;
2502 for(i = 0; i < total_colors; i++)
2504 if(color_table[i][0] == color)
2506 current_color_pixel = color_table[i][1];
2507 return current_color_pixel;
2511 // find nearest match
2512 difference = 0xFFFFFF;
2514 for(i = 0; i < total_colors; i++)
2516 test = abs((int)(color_table[i][0] - color));
2518 if(test < difference)
2520 current_color_pixel = color_table[i][1];
2524 return current_color_pixel;
2527 return get_color_rgb16(color);
2530 return get_color_bgr16(color);
2534 return client_byte_order == server_byte_order ?
2535 color : get_color_bgr24(color);
2543 int BC_WindowBase::get_color_rgb8(int color)
2547 pixel = (color & 0xc00000) >> 16;
2548 pixel += (color & 0xe000) >> 10;
2549 pixel += (color & 0xe0) >> 5;
2553 int64_t BC_WindowBase::get_color_rgb16(int color)
2556 result = (color & 0xf80000) >> 8;
2557 result += (color & 0xfc00) >> 5;
2558 result += (color & 0xf8) >> 3;
2563 int64_t BC_WindowBase::get_color_bgr16(int color)
2566 result = (color & 0xf80000) >> 19;
2567 result += (color & 0xfc00) >> 5;
2568 result += (color & 0xf8) << 8;
2573 int64_t BC_WindowBase::get_color_bgr24(int color)
2576 result = (color & 0xff) << 16;
2577 result += (color & 0xff00);
2578 result += (color & 0xff0000) >> 16;
2582 void BC_WindowBase::start_video()
2584 cursor_timer->update();
2586 // set_color(BLACK);
2587 // draw_box(0, 0, get_w(), get_h());
2591 void BC_WindowBase::stop_video()
2599 int64_t BC_WindowBase::get_color()
2601 return top_level->current_color;
2604 void BC_WindowBase::set_color(int64_t color)
2606 top_level->current_color = color;
2607 XSetForeground(top_level->display,
2609 top_level->get_color(color));
2612 void BC_WindowBase::set_opaque()
2614 XSetFunction(top_level->display, top_level->gc, GXcopy);
2617 void BC_WindowBase::set_inverse()
2619 XSetFunction(top_level->display, top_level->gc, GXxor);
2622 void BC_WindowBase::set_line_width(int value)
2624 this->line_width = value;
2625 XSetLineAttributes(top_level->display, top_level->gc, value, /* line_width */
2626 line_dashes == 0 ? LineSolid : LineOnOffDash, /* line_style */
2627 line_dashes == 0 ? CapRound : CapNotLast, /* cap_style */
2628 JoinMiter); /* join_style */
2630 if(line_dashes > 0) {
2631 const char dashes = line_dashes;
2632 XSetDashes(top_level->display, top_level->gc, 0, &dashes, 1);
2635 // XGCValues gcvalues;
2636 // unsigned long gcmask;
2637 // gcmask = GCCapStyle | GCJoinStyle;
2638 // XGetGCValues(top_level->display, top_level->gc, gcmask, &gcvalues);
2639 // printf("BC_WindowBase::set_line_width %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2642 void BC_WindowBase::set_line_dashes(int value)
2644 line_dashes = value;
2645 // call XSetLineAttributes
2646 set_line_width(line_width);
2650 Cursor BC_WindowBase::get_cursor_struct(int cursor)
2654 case ARROW_CURSOR: return top_level->arrow_cursor;
2655 case CROSS_CURSOR: return top_level->cross_cursor;
2656 case IBEAM_CURSOR: return top_level->ibeam_cursor;
2657 case VSEPARATE_CURSOR: return top_level->vseparate_cursor;
2658 case HSEPARATE_CURSOR: return top_level->hseparate_cursor;
2659 case MOVE_CURSOR: return top_level->move_cursor;
2660 case LEFT_CURSOR: return top_level->left_cursor;
2661 case RIGHT_CURSOR: return top_level->right_cursor;
2662 case UPRIGHT_ARROW_CURSOR: return top_level->upright_arrow_cursor;
2663 case UPLEFT_RESIZE: return top_level->upleft_resize_cursor;
2664 case UPRIGHT_RESIZE: return top_level->upright_resize_cursor;
2665 case DOWNLEFT_RESIZE: return top_level->downleft_resize_cursor;
2666 case DOWNRIGHT_RESIZE: return top_level->downright_resize_cursor;
2667 case HOURGLASS_CURSOR: return top_level->hourglass_cursor;
2668 case TRANSPARENT_CURSOR: return top_level->transparent_cursor;
2669 case GRABBED_CURSOR: return top_level->grabbed_cursor;
2674 void BC_WindowBase::set_cursor(int cursor, int override, int flush)
2676 // inherit cursor from parent
2679 XUndefineCursor(top_level->display, win);
2680 current_cursor = cursor;
2683 // don't change cursor if overridden
2684 if((!top_level->is_hourglass && !is_transparent) ||
2687 XDefineCursor(top_level->display, win, get_cursor_struct(cursor));
2688 if(flush) this->flush();
2691 if(!override) current_cursor = cursor;
2694 void BC_WindowBase::set_x_cursor(int cursor)
2696 temp_cursor = XCreateFontCursor(top_level->display, cursor);
2697 XDefineCursor(top_level->display, win, temp_cursor);
2698 current_cursor = cursor;
2702 int BC_WindowBase::get_cursor()
2704 return current_cursor;
2707 void BC_WindowBase::start_hourglass()
2709 top_level->start_hourglass_recursive();
2713 void BC_WindowBase::stop_hourglass()
2715 top_level->stop_hourglass_recursive();
2719 void BC_WindowBase::start_hourglass_recursive()
2721 if(this == top_level)
2729 set_cursor(HOURGLASS_CURSOR, 1, 0);
2730 for(int i = 0; i < subwindows->total; i++)
2732 subwindows->values[i]->start_hourglass_recursive();
2737 void BC_WindowBase::stop_hourglass_recursive()
2739 if(this == top_level)
2741 if(hourglass_total == 0) return;
2742 top_level->hourglass_total--;
2745 if(!top_level->hourglass_total)
2747 top_level->is_hourglass = 0;
2749 // Cause set_cursor to perform change
2751 set_cursor(current_cursor, 1, 0);
2753 for(int i = 0; i < subwindows->total; i++)
2755 subwindows->values[i]->stop_hourglass_recursive();
2763 XFontStruct* BC_WindowBase::get_font_struct(int font)
2765 // Clear out unrelated flags
2766 if(font & BOLDFACE) font ^= BOLDFACE;
2769 case SMALLFONT: return top_level->smallfont; break;
2770 case MEDIUMFONT: return top_level->mediumfont; break;
2771 case LARGEFONT: return top_level->largefont; break;
2772 case BIGFONT: return top_level->bigfont; break;
2773 case CLOCKFONT: return top_level->clockfont; break;
2778 XFontSet BC_WindowBase::get_fontset(int font)
2782 if(get_resources()->use_fontset)
2784 switch(font & 0xff) {
2785 case SMALLFONT: fs = top_level->smallfontset; break;
2786 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2787 case LARGEFONT: fs = top_level->largefontset; break;
2788 case BIGFONT: fs = top_level->bigfontset; break;
2789 case CLOCKFONT: fs = top_level->clockfontset; break;
2797 XftFont* BC_WindowBase::get_xft_struct(int font)
2800 case SMALLFONT: return (XftFont*)top_level->smallfont_xft;
2801 case MEDIUMFONT: return (XftFont*)top_level->mediumfont_xft;
2802 case LARGEFONT: return (XftFont*)top_level->largefont_xft;
2803 case BIGFONT: return (XftFont*)top_level->bigfont_xft;
2804 case CLOCKFONT: return (XftFont*)top_level->clockfont_xft;
2805 case MEDIUMFONT_3D: return (XftFont*)top_level->bold_mediumfont_xft;
2806 case SMALLFONT_3D: return (XftFont*)top_level->bold_smallfont_xft;
2807 case LARGEFONT_3D: return (XftFont*)top_level->bold_largefont_xft;
2815 int BC_WindowBase::get_current_font()
2817 return top_level->current_font;
2820 void BC_WindowBase::set_font(int font)
2822 top_level->current_font = font;
2825 if(get_resources()->use_xft) {}
2828 if(get_resources()->use_fontset) {
2832 if(get_font_struct(font))
2834 XSetFont(top_level->display, top_level->gc, get_font_struct(font)->fid);
2840 void BC_WindowBase::set_fontset(int font)
2844 if(get_resources()->use_fontset) {
2846 case SMALLFONT: fs = top_level->smallfontset; break;
2847 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2848 case LARGEFONT: fs = top_level->largefontset; break;
2849 case BIGFONT: fs = top_level->bigfontset; break;
2850 case CLOCKFONT: fs = top_level->clockfontset; break;
2858 XFontSet BC_WindowBase::get_curr_fontset(void)
2860 if(get_resources()->use_fontset)
2861 return curr_fontset;
2865 int BC_WindowBase::get_single_text_width(int font, const char *text, int length)
2868 if(get_resources()->use_xft && get_xft_struct(font))
2871 #ifdef X_HAVE_UTF8_STRING
2872 if(get_resources()->locale_utf8)
2874 xftTextExtentsUtf8(top_level->display,
2875 get_xft_struct(font),
2876 (const XftChar8 *)text,
2883 xftTextExtents8(top_level->display,
2884 get_xft_struct(font),
2885 (const XftChar8 *)text,
2889 return extents.xOff;
2893 if(get_resources()->use_fontset && top_level->get_fontset(font))
2894 return XmbTextEscapement(top_level->get_fontset(font), text, length);
2896 if(get_font_struct(font))
2897 return XTextWidth(get_font_struct(font), text, length);
2903 case MEDIUM_7SEGMENT:
2904 return get_resources()->medium_7segment[0]->get_w() * length;
2914 int BC_WindowBase::get_text_width(int font, const char *text, int length)
2916 int i, j, w = 0, line_w = 0;
2917 if(length < 0) length = strlen(text);
2919 for(i = 0, j = 0; i <= length; i++)
2924 line_w = get_single_text_width(font, &text[j], i - j);
2930 line_w = get_single_text_width(font, &text[j], length - j);
2932 if(line_w > w) w = line_w;
2935 if(i > length && w == 0)
2937 w = get_single_text_width(font, text, length);
2943 int BC_WindowBase::get_text_width(int font, const wchar_t *text, int length)
2946 if( length < 0 ) length = wcslen(text);
2948 for( i=j=0; i<length && text[i]; ++i ) {
2949 if( text[i] != '\n' ) continue;
2951 int lw = get_single_text_width(font, &text[j], i-j);
2952 if( w < lw ) w = lw;
2957 int lw = get_single_text_width(font, &text[j], length-j);
2958 if( w < lw ) w = lw;
2964 int BC_WindowBase::get_text_ascent(int font)
2968 if( (fstruct = get_xft_struct(font)) != 0 )
2969 return fstruct->ascent;
2971 if(get_resources()->use_fontset && top_level->get_fontset(font))
2973 XFontSetExtents *extents;
2975 extents = XExtentsOfFontSet(top_level->get_fontset(font));
2976 return -extents->max_logical_extent.y;
2979 if(get_font_struct(font))
2980 return top_level->get_font_struct(font)->ascent;
2983 case MEDIUM_7SEGMENT:
2984 return get_resources()->medium_7segment[0]->get_h();
2989 int BC_WindowBase::get_text_descent(int font)
2993 if( (fstruct = get_xft_struct(font)) != 0 )
2994 return fstruct->descent;
2996 if(get_resources()->use_fontset && top_level->get_fontset(font)) {
2997 XFontSetExtents *extents;
2998 extents = XExtentsOfFontSet(top_level->get_fontset(font));
2999 return (extents->max_logical_extent.height
3000 + extents->max_logical_extent.y);
3003 if(get_font_struct(font))
3004 return top_level->get_font_struct(font)->descent;
3009 int BC_WindowBase::get_text_height(int font, const char *text)
3014 if( (fstruct = get_xft_struct(font)) != 0 )
3015 rowh = fstruct->height;
3018 rowh = get_text_ascent(font) + get_text_descent(font);
3020 if(!text) return rowh;
3022 // Add height of lines
3023 int h = 0, i, length = strlen(text);
3024 for(i = 0; i <= length; i++)
3035 BC_Bitmap* BC_WindowBase::new_bitmap(int w, int h, int color_model)
3037 if(color_model < 0) color_model = top_level->get_color_model();
3038 return new BC_Bitmap(top_level, w, h, color_model);
3041 void BC_WindowBase::init_wait()
3043 #ifndef SINGLE_THREAD
3044 if(window_type != MAIN_WINDOW)
3045 top_level->init_wait();
3046 init_lock->lock("BC_WindowBase::init_wait");
3047 init_lock->unlock();
3051 int BC_WindowBase::accel_available(int color_model, int lock_it)
3053 if( window_type != MAIN_WINDOW )
3054 return top_level->accel_available(color_model, lock_it);
3056 lock_window("BC_WindowBase::accel_available");
3058 switch(color_model) {
3060 grab_port_id(color_model);
3064 grab_port_id(color_model);
3073 //printf("BC_WindowBase::accel_available %d %d\n", color_model, xvideo_port_id);
3074 return xvideo_port_id >= 0 ? 1 : 0;
3078 int BC_WindowBase::grab_port_id(int color_model)
3080 if( !get_resources()->use_xvideo || // disabled
3081 !get_resources()->use_shm ) // Only local server is fast enough.
3083 if( xvideo_port_id >= 0 )
3084 return xvideo_port_id;
3086 unsigned int ver, rev, reqBase, eventBase, errorBase;
3087 if( Success != XvQueryExtension(display, // XV extension is available
3088 &ver, &rev, &reqBase, &eventBase, &errorBase) )
3091 // XV adaptors are available
3092 unsigned int numAdapt = 0;
3093 XvAdaptorInfo *info = 0;
3094 XvQueryAdaptors(display, DefaultRootWindow(display), &numAdapt, &info);
3098 // Translate from color_model to X color model
3099 int x_color_model = BC_CModels::bc_to_x(color_model);
3101 // Get adaptor with desired color model
3102 for( int i = 0; i < (int)numAdapt && xvideo_port_id == -1; i++) {
3103 if( !(info[i].type & XvImageMask) || !info[i].num_ports ) continue;
3104 // adaptor supports XvImages
3105 int numFormats = 0, numPorts = info[i].num_ports;
3106 XvImageFormatValues *formats =
3107 XvListImageFormats(display, info[i].base_id, &numFormats);
3108 if( !formats ) continue;
3110 for( int j=0; j<numFormats && xvideo_port_id<0; ++j ) {
3111 if( formats[j].id != x_color_model ) continue;
3112 // this adaptor supports the desired format, grab a port
3113 for( int k=0; k<numPorts; ++k ) {
3114 if( Success == XvGrabPort(top_level->display,
3115 info[i].base_id+k, CurrentTime) ) {
3116 //printf("BC_WindowBase::grab_port_id %llx\n", info[i].base_id);
3117 xvideo_port_id = info[i].base_id + k;
3125 XvFreeAdaptorInfo(info);
3127 return xvideo_port_id;
3131 int BC_WindowBase::show_window(int flush)
3133 for(int i = 0; i < subwindows->size(); i++)
3135 subwindows->get(i)->show_window(0);
3138 XMapWindow(top_level->display, win);
3139 if(flush) XFlush(top_level->display);
3140 // XSync(top_level->display, 0);
3145 int BC_WindowBase::hide_window(int flush)
3147 for(int i = 0; i < subwindows->size(); i++)
3149 subwindows->get(i)->hide_window(0);
3152 XUnmapWindow(top_level->display, win);
3153 if(flush) this->flush();
3158 BC_MenuBar* BC_WindowBase::add_menubar(BC_MenuBar *menu_bar)
3160 subwindows->append((BC_SubWindow*)menu_bar);
3162 menu_bar->parent_window = this;
3163 menu_bar->top_level = this->top_level;
3164 menu_bar->initialize();
3168 BC_WindowBase* BC_WindowBase::add_popup(BC_WindowBase *window)
3170 //printf("BC_WindowBase::add_popup window=%p win=%p\n", window, window->win);
3171 if(this != top_level) return top_level->add_popup(window);
3172 popups.append(window);
3176 void BC_WindowBase::remove_popup(BC_WindowBase *window)
3178 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3179 if(this != top_level)
3180 top_level->remove_popup(window);
3182 popups.remove(window);
3183 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3187 BC_WindowBase* BC_WindowBase::add_subwindow(BC_WindowBase *subwindow)
3189 subwindows->append(subwindow);
3191 if(subwindow->bg_color == -1) subwindow->bg_color = this->bg_color;
3193 // parent window must be set before the subwindow initialization
3194 subwindow->parent_window = this;
3195 subwindow->top_level = this->top_level;
3197 // Execute derived initialization
3198 subwindow->initialize();
3203 BC_WindowBase* BC_WindowBase::add_tool(BC_WindowBase *subwindow)
3205 return add_subwindow(subwindow);
3208 int BC_WindowBase::flash(int x, int y, int w, int h, int flush)
3210 if( !top_level->flash_enabled ) return 0;
3211 //printf("BC_WindowBase::flash %d %d %d %d %d\n", __LINE__, w, h, this->w, this->h);
3213 XSetWindowBackgroundPixmap(top_level->display, win, pixmap->opaque_pixmap);
3216 XClearArea(top_level->display, win, x, y, w, h, 0);
3220 XClearWindow(top_level->display, win);
3228 int BC_WindowBase::flash(int flush)
3230 flash(-1, -1, -1, -1, flush);
3234 void BC_WindowBase::flush()
3236 //if(!get_window_lock())
3237 // printf("BC_WindowBase::flush %s not locked\n", top_level->title);
3238 // X gets hosed if Flush/Sync are not user locked (at libX11-1.1.5 / libxcb-1.1.91)
3239 // _XReply deadlocks in condition_wait waiting for xlib lock when waiters!=-1
3240 int locked = get_window_lock();
3241 if( !locked ) lock_window("BC_WindowBase::flush");
3242 XFlush(top_level->display);
3243 if( !locked ) unlock_window();
3246 void BC_WindowBase::sync_display()
3248 int locked = get_window_lock();
3249 if( !locked ) lock_window("BC_WindowBase::sync_display");
3250 XSync(top_level->display, False);
3251 if( !locked ) unlock_window();
3254 int BC_WindowBase::get_window_lock()
3256 #ifdef SINGLE_THREAD
3257 return BC_Display::display_global->get_display_locked();
3259 return top_level->window_lock;
3263 int BC_WindowBase::lock_window(const char *location)
3265 if(top_level && top_level != this)
3267 top_level->lock_window(location);
3272 SET_LOCK(this, title, location);
3273 #ifdef SINGLE_THREAD
3274 BC_Display::lock_display(location);
3276 XLockDisplay(top_level->display);
3277 top_level->display_lock_owner = pthread_self();
3280 ++top_level->window_lock;
3284 printf("BC_WindowBase::lock_window top_level NULL\n");
3289 int BC_WindowBase::unlock_window()
3291 if(top_level && top_level != this)
3293 top_level->unlock_window();
3299 if( !top_level->window_lock ) {
3300 printf("BC_WindowBase::unlock_window %s not locked\n", title);
3303 if( top_level->window_lock > 0 )
3304 if( --top_level->window_lock == 0 )
3305 top_level->display_lock_owner = 0;
3306 #ifdef SINGLE_THREAD
3307 BC_Display::unlock_display();
3309 XUnlockDisplay(top_level->display);
3314 printf("BC_WindowBase::unlock_window top_level NULL\n");
3319 int BC_WindowBase::break_lock()
3321 if( !top_level ) return 0;
3322 if( top_level != this ) return top_level->break_lock();
3323 if( top_level->display_lock_owner != pthread_self() ) return 0;
3324 if( top_level->window_lock != 1 ) return 0;
3327 display_lock_owner = 0;
3328 #ifdef SINGLE_THREAD
3329 BC_Display::unlock_display();
3331 XUnlockDisplay(display);
3336 void BC_WindowBase::set_done(int return_value)
3338 if(done_set) return;
3340 if(window_type != MAIN_WINDOW)
3341 top_level->set_done(return_value);
3344 #ifdef SINGLE_THREAD
3345 this->return_value = return_value;
3346 BC_Display::display_global->arm_completion(this);
3347 completion_lock->unlock();
3348 #else // SINGLE_THREAD
3350 if( !event_thread ) return;
3351 XEvent *event = new_xevent();
3352 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
3353 event->type = ClientMessage;
3354 ptr->message_type = SetDoneXAtom;
3356 this->return_value = return_value;
3357 // May lock up here because XSendEvent doesn't work too well
3358 // asynchronous with XNextEvent.
3359 // This causes BC_WindowEvents to forward a copy of the event to run_window where
3361 // Deletion of event_thread is done at the end of BC_WindowBase::run_window() - by calling the destructor
3367 void BC_WindowBase::close(int return_value)
3369 hide_window(); flush();
3370 set_done(return_value);
3373 int BC_WindowBase::grab(BC_WindowBase *window)
3375 if( window->active_grab && this != window->active_grab ) return 0;
3376 window->active_grab = this;
3377 this->grab_active = window;
3380 int BC_WindowBase::ungrab(BC_WindowBase *window)
3382 if( window->active_grab && this != window->active_grab ) return 0;
3383 window->active_grab = 0;
3384 this->grab_active = 0;
3387 int BC_WindowBase::grab_event_count()
3390 #ifndef SINGLE_THREAD
3391 result = grab_active->get_event_count();
3395 int BC_WindowBase::grab_buttons()
3397 XSync(top_level->display, False);
3398 if( XGrabButton(top_level->display, AnyButton, AnyModifier,
3399 top_level->rootwin, True, ButtonPressMask | ButtonReleaseMask,
3400 GrabModeAsync, GrabModeSync, None, None) == GrabSuccess ) {
3401 set_active_subwindow(this);
3406 void BC_WindowBase::ungrab_buttons()
3408 XUngrabButton(top_level->display, AnyButton, AnyModifier, top_level->rootwin);
3409 set_active_subwindow(0);
3412 void BC_WindowBase::grab_cursor()
3414 Cursor cursor_grab = get_cursor_struct(GRABBED_CURSOR);
3415 XGrabPointer(top_level->display, top_level->rootwin, True,
3416 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
3417 GrabModeAsync, GrabModeAsync, None, cursor_grab, CurrentTime);
3419 void BC_WindowBase::ungrab_cursor()
3421 XUngrabPointer(top_level->display, CurrentTime);
3425 // WidthOfScreen/HeightOfScreen of XDefaultScreenOfDisplay
3426 // this is the bounding box of all the screens
3428 int BC_WindowBase::get_root_w(int lock_display)
3430 if(lock_display) lock_window("BC_WindowBase::get_root_w");
3431 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3432 int result = WidthOfScreen(def_screen);
3433 if(lock_display) unlock_window();
3437 int BC_WindowBase::get_root_h(int lock_display)
3439 if(lock_display) lock_window("BC_WindowBase::get_root_h");
3440 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3441 int result = HeightOfScreen(def_screen);
3442 if(lock_display) unlock_window();
3446 XineramaScreenInfo *
3447 BC_WindowBase::get_xinerama_info(int screen)
3449 if( !xinerama_info || !xinerama_screens ) return 0;
3451 for( int i=0; i<xinerama_screens; ++i )
3452 if( xinerama_info[i].screen_number == screen )
3453 return &xinerama_info[i];
3456 int top_x = get_x(), top_y = get_y();
3457 if( BC_DisplayInfo::left_border >= 0 ) top_x += BC_DisplayInfo::left_border;
3458 if( BC_DisplayInfo::top_border >= 0 ) top_y += BC_DisplayInfo::top_border;
3459 for( int i=0; i<xinerama_screens; ++i ) {
3460 int scr_y = top_y - xinerama_info[i].y_org;
3461 if( scr_y < 0 || scr_y >= xinerama_info[i].height ) continue;
3462 int scr_x = top_x - xinerama_info[i].x_org;
3463 if( scr_x >= 0 && scr_x < xinerama_info[i].width )
3464 return &xinerama_info[i];
3469 void BC_WindowBase::get_fullscreen_geometry(int &wx, int &wy, int &ww, int &wh)
3471 XineramaScreenInfo *info = top_level->get_xinerama_info(-1);
3473 wx = info->x_org; wy = info->y_org;
3474 ww = info->width; wh = info->height;
3477 wx = get_screen_x(0, -1);
3478 wy = get_screen_y(0, -1);
3479 int scr_w0 = get_screen_w(0, 0);
3480 int root_w = get_root_w(0);
3481 int root_h = get_root_h(0);
3482 if( root_w > scr_w0 ) { // multi-headed
3483 if( wx >= scr_w0 ) {
3484 // assumes right side is the big one
3485 ww = root_w - scr_w0;
3489 // use same aspect ratio to compute left height
3491 wh = (w*root_h) / (root_w-scr_w0);
3501 int BC_WindowBase::get_screen_x(int lock_display, int screen)
3504 if(lock_display) lock_window("BC_WindowBase::get_screen_x");
3505 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3508 int root_w = get_root_w(0);
3509 int root_h = get_root_h(0);
3510 // Shift X based on position of current window if dual head
3511 if( (float)root_w/root_h > 1.8 ) {
3512 root_w = get_screen_w(0, 0);
3513 if( top_level->get_x() >= root_w )
3518 result = info->x_org;
3519 if(lock_display) unlock_window();
3523 int BC_WindowBase::get_screen_y(int lock_display, int screen)
3525 if(lock_display) lock_window("BC_WindowBase::get_screen_y");
3526 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3527 int result = !info ? 0 : info->y_org;
3528 if(lock_display) unlock_window();
3532 int BC_WindowBase::get_screen_w(int lock_display, int screen)
3535 if(lock_display) lock_window("BC_WindowBase::get_screen_w");
3536 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3538 int width = get_root_w(0);
3539 int height = get_root_h(0);
3540 if( (float)width/height > 1.8 ) {
3541 // If dual head, the screen width is > 16x9
3542 // but we only want to fill one screen
3543 // this code assumes the "big" screen is on the right
3544 int scr_w0 = width / 2;
3546 case 600: scr_w0 = 800; break;
3547 case 720: scr_w0 = 1280; break;
3548 case 1024: scr_w0 = 1280; break;
3549 case 1200: scr_w0 = 1600; break;
3550 case 1080: scr_w0 = 1920; break;
3552 int scr_w1 = width - scr_w0;
3553 result = screen > 0 ? scr_w1 :
3554 screen == 0 ? scr_w0 :
3555 top_level->get_x() < scr_w0 ? scr_w0 : scr_w1;
3561 result = info->width;
3562 if(lock_display) unlock_window();
3566 int BC_WindowBase::get_screen_h(int lock_display, int screen)
3568 if(lock_display) lock_window("BC_WindowBase::get_screen_h");
3569 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3570 int result = info ? info->height : get_root_h(0);
3571 if(lock_display) unlock_window();
3575 // Bottom right corner
3576 int BC_WindowBase::get_x2()
3581 int BC_WindowBase::get_y2()
3586 int BC_WindowBase::get_video_on()
3591 int BC_WindowBase::get_hidden()
3593 return top_level->hidden;
3596 int BC_WindowBase::cursor_inside()
3598 return (top_level->cursor_x >= 0 &&
3599 top_level->cursor_y >= 0 &&
3600 top_level->cursor_x < w &&
3601 top_level->cursor_y < h);
3604 BC_WindowBase* BC_WindowBase::get_top_level()
3609 BC_WindowBase* BC_WindowBase::get_parent()
3611 return parent_window;
3614 int BC_WindowBase::get_color_model()
3616 return top_level->color_model;
3619 BC_Resources* BC_WindowBase::get_resources()
3621 return &BC_WindowBase::resources;
3624 BC_Synchronous* BC_WindowBase::get_synchronous()
3626 return BC_WindowBase::resources.get_synchronous();
3629 int BC_WindowBase::get_bg_color()
3634 void BC_WindowBase::set_bg_color(int color)
3636 this->bg_color = color;
3639 BC_Pixmap* BC_WindowBase::get_bg_pixmap()
3644 void BC_WindowBase::set_active_subwindow(BC_WindowBase *subwindow)
3646 top_level->active_subwindow = subwindow;
3649 int BC_WindowBase::activate()
3654 int BC_WindowBase::deactivate()
3656 if(window_type == MAIN_WINDOW)
3658 if( top_level->active_menubar ) {
3659 top_level->active_menubar->deactivate();
3660 top_level->active_menubar = 0;
3662 if( top_level->active_popup_menu ) {
3663 top_level->active_popup_menu->deactivate();
3664 top_level->active_popup_menu = 0;
3666 if( top_level->active_subwindow ) {
3667 top_level->active_subwindow->deactivate();
3668 top_level->active_subwindow = 0;
3670 if( top_level->motion_events && top_level->last_motion_win == this->win )
3671 top_level->motion_events = 0;
3677 int BC_WindowBase::cycle_textboxes(int amount)
3680 BC_WindowBase *new_textbox = 0;
3684 BC_WindowBase *first_textbox = 0;
3685 find_next_textbox(&first_textbox, &new_textbox, result);
3686 if(!new_textbox) new_textbox = first_textbox;
3692 BC_WindowBase *last_textbox = 0;
3693 find_prev_textbox(&last_textbox, &new_textbox, result);
3694 if(!new_textbox) new_textbox = last_textbox;
3698 if(new_textbox != active_subwindow)
3701 new_textbox->activate();
3707 int BC_WindowBase::find_next_textbox(BC_WindowBase **first_textbox, BC_WindowBase **next_textbox, int &result)
3709 // Search subwindows for textbox
3710 for(int i = 0; i < subwindows->total && result < 2; i++)
3712 BC_WindowBase *test_subwindow = subwindows->values[i];
3713 test_subwindow->find_next_textbox(first_textbox, next_textbox, result);
3720 if(!*first_textbox) *first_textbox = this;
3724 if(top_level->active_subwindow == this)
3730 *next_textbox = this;
3737 int BC_WindowBase::find_prev_textbox(BC_WindowBase **last_textbox, BC_WindowBase **prev_textbox, int &result)
3743 if(!*last_textbox) *last_textbox = this;
3747 if(top_level->active_subwindow == this)
3753 *prev_textbox = this;
3758 // Search subwindows for textbox
3759 for(int i = subwindows->total - 1; i >= 0 && result < 2; i--)
3761 BC_WindowBase *test_subwindow = subwindows->values[i];
3762 test_subwindow->find_prev_textbox(last_textbox, prev_textbox, result);
3767 BC_Clipboard* BC_WindowBase::get_clipboard()
3769 #ifdef SINGLE_THREAD
3770 return BC_Display::display_global->clipboard;
3772 return top_level->clipboard;
3776 Atom BC_WindowBase::to_clipboard(const char *data, long len, int clipboard_num)
3778 return get_clipboard()->to_clipboard(this, data, len, clipboard_num);
3781 long BC_WindowBase::from_clipboard(char *data, long maxlen, int clipboard_num)
3783 return get_clipboard()->from_clipboard(data, maxlen, clipboard_num);
3786 long BC_WindowBase::clipboard_len(int clipboard_num)
3788 return get_clipboard()->clipboard_len(clipboard_num);
3791 int BC_WindowBase::do_selection_clear(Window win)
3793 top_level->event_win = win;
3794 return dispatch_selection_clear();
3797 int BC_WindowBase::dispatch_selection_clear()
3800 for( int i=0; i<subwindows->total && !result; ++i )
3801 result = subwindows->values[i]->dispatch_selection_clear();
3803 result = selection_clear_event();
3808 void BC_WindowBase::get_relative_cursor(int &x, int &y, int lock_window)
3810 int abs_x, abs_y, win_x, win_y;
3811 unsigned int temp_mask;
3814 if(lock_window) this->lock_window("BC_WindowBase::get_relative_cursor");
3815 XQueryPointer(top_level->display, top_level->win,
3816 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3819 XTranslateCoordinates(top_level->display, top_level->rootwin,
3820 win, abs_x, abs_y, &x, &y, &temp_win);
3821 if(lock_window) this->unlock_window();
3823 int BC_WindowBase::get_relative_cursor_x(int lock_window)
3826 get_relative_cursor(x, y, lock_window);
3829 int BC_WindowBase::get_relative_cursor_y(int lock_window)
3832 get_relative_cursor(x, y, lock_window);
3836 void BC_WindowBase::get_abs_cursor(int &abs_x, int &abs_y, int lock_window)
3839 unsigned int temp_mask;
3842 if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor");
3843 XQueryPointer(top_level->display, top_level->win,
3844 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3846 if(lock_window) this->unlock_window();
3848 int BC_WindowBase::get_abs_cursor_x(int lock_window)
3851 get_abs_cursor(abs_x, abs_y, lock_window);
3854 int BC_WindowBase::get_abs_cursor_y(int lock_window)
3857 get_abs_cursor(abs_x, abs_y, lock_window);
3861 void BC_WindowBase::get_pop_cursor(int &px, int &py, int lock_window)
3864 get_abs_cursor(px, py, lock_window);
3865 if( px < margin ) px = margin;
3866 if( py < margin ) py = margin;
3867 int wd = get_screen_w(lock_window,-1) - margin;
3868 if( px > wd ) px = wd;
3869 int ht = get_screen_h(lock_window,-1) - margin;
3870 if( py > ht ) py = ht;
3872 int BC_WindowBase::get_pop_cursor_x(int lock_window)
3875 get_pop_cursor(px, py, lock_window);
3878 int BC_WindowBase::get_pop_cursor_y(int lock_window)
3881 get_pop_cursor(px, py, lock_window);
3885 int BC_WindowBase::match_window(Window win)
3887 if (this->win == win) return 1;
3889 for(int i = 0; i < subwindows->total; i++) {
3890 result = subwindows->values[i]->match_window(win);
3891 if (result) return result;
3897 int BC_WindowBase::get_cursor_over_window()
3899 int abs_x, abs_y, win_x, win_y;
3900 unsigned int mask_return;
3901 Window root_return, child_return;
3903 int ret = XQueryPointer(top_level->display, top_level->rootwin,
3904 &root_return, &child_return, &abs_x, &abs_y,
3905 &win_x, &win_y, &mask_return);
3906 if( ret && child_return == None ) ret = 0;
3907 if( ret && win != child_return )
3908 ret = top_level->match_window(child_return);
3909 // query pointer can return a window manager window with this top_level as a child
3910 // for kde this can be two levels deep
3911 unsigned int nchildren_return = 0;
3912 Window parent_return, *children_return = 0;
3913 Window top_win = top_level->win;
3914 while( !ret && top_win != top_level->rootwin && top_win != root_return &&
3915 XQueryTree(top_level->display, top_win, &root_return,
3916 &parent_return, &children_return, &nchildren_return) ) {
3917 if( children_return ) XFree(children_return);
3918 if( (top_win=parent_return) == child_return ) ret = 1;
3923 int BC_WindowBase::cursor_above()
3926 get_relative_cursor(rx, ry);
3927 return rx < 0 || rx >= get_w() ||
3928 ry < 0 || ry >= get_h() ? 0 : 1;
3931 int BC_WindowBase::get_drag_x()
3933 return top_level->drag_x;
3936 int BC_WindowBase::get_drag_y()
3938 return top_level->drag_y;
3941 int BC_WindowBase::get_cursor_x()
3943 return top_level->cursor_x;
3946 int BC_WindowBase::get_cursor_y()
3948 return top_level->cursor_y;
3951 int BC_WindowBase::dump_windows()
3953 printf("\tBC_WindowBase::dump_windows window=%p win=%p '%s', %dx%d+%d+%d %s\n",
3954 this, (void*)this->win, title, w,h,x,y, typeid(*this).name());
3955 for(int i = 0; i < subwindows->size(); i++)
3956 subwindows->get(i)->dump_windows();
3957 for(int i = 0; i < popups.size(); i++) {
3958 BC_WindowBase *p = popups[i];
3959 printf("\tBC_WindowBase::dump_windows popup=%p win=%p '%s', %dx%d+%d+%d %s\n",
3960 p, (void*)p->win, p->title, p->w,p->h,p->x,p->y, typeid(*p).name());
3965 int BC_WindowBase::is_event_win()
3967 return this->win == top_level->event_win;
3970 void BC_WindowBase::set_dragging(int value)
3972 is_dragging = value;
3975 int BC_WindowBase::get_dragging()
3980 int BC_WindowBase::get_buttonpress()
3982 return top_level->button_number;
3985 int BC_WindowBase::get_button_down()
3987 return top_level->button_down;
3990 int BC_WindowBase::alt_down()
3992 return top_level->alt_mask;
3995 int BC_WindowBase::shift_down()
3997 return top_level->shift_mask;
4000 int BC_WindowBase::ctrl_down()
4002 return top_level->ctrl_mask;
4005 wchar_t* BC_WindowBase::get_wkeystring(int *length)
4008 *length = top_level->wkey_string_length;
4009 return top_level->wkey_string;
4012 #ifdef X_HAVE_UTF8_STRING
4013 char* BC_WindowBase::get_keypress_utf8()
4015 return top_level->key_pressed_utf8;
4020 int BC_WindowBase::get_keypress()
4022 return top_level->key_pressed;
4025 int BC_WindowBase::get_double_click()
4027 return top_level->double_click;
4030 int BC_WindowBase::get_triple_click()
4032 return top_level->triple_click;
4035 int BC_WindowBase::get_bgcolor()
4040 int BC_WindowBase::resize_window(int w, int h)
4042 if(this->w == w && this->h == h) return 0;
4044 if(window_type == MAIN_WINDOW && !allow_resize)
4046 XSizeHints size_hints;
4047 size_hints.flags = PSize | PMinSize | PMaxSize;
4048 size_hints.width = w;
4049 size_hints.height = h;
4050 size_hints.min_width = w;
4051 size_hints.max_width = w;
4052 size_hints.min_height = h;
4053 size_hints.max_height = h;
4054 XSetNormalHints(top_level->display, win, &size_hints);
4056 XResizeWindow(top_level->display, win, w, h);
4061 pixmap = new BC_Pixmap(this, w, h);
4063 // Propagate to menubar
4064 for(int i = 0; i < subwindows->total; i++)
4066 subwindows->values[i]->dispatch_resize_event(w, h);
4069 draw_background(0, 0, w, h);
4070 if(top_level == this && get_resources()->recursive_resizing)
4071 resize_history.append(new BC_ResizeCall(w, h));
4075 // The only way for resize events to be propagated is by updating the internal w and h
4076 int BC_WindowBase::resize_event(int w, int h)
4078 if(window_type == MAIN_WINDOW)
4086 int BC_WindowBase::reposition_window(int x, int y)
4088 reposition_window(x, y, -1, -1);
4093 int BC_WindowBase::reposition_window(int x, int y, int w, int h)
4097 // Some tools set their own dimensions before calling this, causing the
4098 // resize check to skip.
4102 if(w > 0 && w != this->w)
4108 if(h > 0 && h != this->h)
4114 //printf("BC_WindowBase::reposition_window %d %d %d\n", translation_count, x_correction, y_correction);
4117 printf("BC_WindowBase::reposition_window this->w == %d\n", this->w);
4119 printf("BC_WindowBase::reposition_window this->h == %d\n", this->h);
4121 if(translation_count && window_type == MAIN_WINDOW)
4123 // KDE shifts window right and down.
4124 // FVWM leaves window alone and adds border around it.
4125 XMoveResizeWindow(top_level->display,
4127 x - BC_DisplayInfo::auto_reposition_x,
4128 y - BC_DisplayInfo::auto_reposition_y,
4134 XMoveResizeWindow(top_level->display,
4145 pixmap = new BC_Pixmap(this, this->w, this->h);
4146 clear_box(0,0, this->w, this->h);
4147 // Propagate to menubar
4148 for(int i = 0; i < subwindows->total; i++)
4150 subwindows->values[i]->dispatch_resize_event(this->w, this->h);
4153 // draw_background(0, 0, w, h);
4159 int BC_WindowBase::reposition_window_relative(int dx, int dy, int w, int h)
4161 return reposition_window(get_x()+dx, get_y()+dy, w, h);
4164 int BC_WindowBase::reposition_window_relative(int dx, int dy)
4166 return reposition_window_relative(dx, dy, -1, -1);
4169 void BC_WindowBase::set_tooltips(int v)
4171 get_resources()->tooltips_enabled = v;
4174 void BC_WindowBase::set_force_tooltip(int v)
4179 int BC_WindowBase::raise_window(int do_flush)
4181 XRaiseWindow(top_level->display, win);
4182 if(do_flush) XFlush(top_level->display);
4186 int BC_WindowBase::lower_window(int do_flush)
4188 XLowerWindow(top_level->display, win);
4189 if(do_flush) XFlush(top_level->display);
4193 void BC_WindowBase::set_background(VFrame *bitmap)
4195 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
4197 bg_pixmap = new BC_Pixmap(this, bitmap, PIXMAP_OPAQUE);
4198 shared_bg_pixmap = 0;
4199 draw_background(0, 0, w, h);
4202 void BC_WindowBase::put_title(const char *text)
4204 char *cp = this->title, *ep = cp+sizeof(this->title)-1;
4205 for( const unsigned char *bp = (const unsigned char *)text; *bp && cp<ep; ++bp )
4206 *cp++ = *bp >= ' ' ? *bp : ' ';
4210 void BC_WindowBase::set_title(const char *text, int utf8)
4212 // utf8>0: wm + net_wm, utf8=0: wm only, utf<0: net_wm only
4214 const unsigned char *wm_title = (const unsigned char *)title;
4215 int title_len = strlen((const char *)title);
4217 Atom xa_wm_name = XA_WM_NAME;
4218 Atom xa_icon_name = XA_WM_ICON_NAME;
4219 Atom xa_string = XA_STRING;
4220 XChangeProperty(display, win, xa_wm_name, xa_string, 8,
4221 PropModeReplace, wm_title, title_len);
4222 XChangeProperty(display, win, xa_icon_name, xa_string, 8,
4223 PropModeReplace, wm_title, title_len);
4226 Atom xa_net_wm_name = XInternAtom(display, "_NET_WM_NAME", True);
4227 Atom xa_net_icon_name = XInternAtom(display, "_NET_WM_ICON_NAME", True);
4228 Atom xa_utf8_string = XInternAtom(display, "UTF8_STRING", True);
4229 XChangeProperty(display, win, xa_net_wm_name, xa_utf8_string, 8,
4230 PropModeReplace, wm_title, title_len);
4231 XChangeProperty(display, win, xa_net_icon_name, xa_utf8_string, 8,
4232 PropModeReplace, wm_title, title_len);
4237 const char *BC_WindowBase::get_title()
4242 int BC_WindowBase::get_toggle_value()
4244 return toggle_value;
4247 int BC_WindowBase::get_toggle_drag()
4252 int BC_WindowBase::set_icon(VFrame *data)
4254 if(icon_pixmap) delete icon_pixmap;
4255 icon_pixmap = new BC_Pixmap(top_level, data, PIXMAP_ALPHA, 1);
4257 if(icon_window) delete icon_window;
4258 icon_window = new BC_Popup(this,
4261 icon_pixmap->get_w(),
4262 icon_pixmap->get_h(),
4264 1, // All windows are hidden initially
4268 wm_hints.flags = WindowGroupHint | IconPixmapHint | IconMaskHint | IconWindowHint;
4269 wm_hints.icon_pixmap = icon_pixmap->get_pixmap();
4270 wm_hints.icon_mask = icon_pixmap->get_alpha();
4271 wm_hints.icon_window = icon_window->win;
4272 wm_hints.window_group = XGroupLeader;
4274 // for(int i = 0; i < 1000; i++)
4275 // printf("02x ", icon_pixmap->get_alpha()->get_row_pointers()[0][i]);
4278 XSetWMHints(top_level->display, top_level->win, &wm_hints);
4279 XSync(top_level->display, 0);
4283 int BC_WindowBase::set_w(int w)
4289 int BC_WindowBase::set_h(int h)
4295 int BC_WindowBase::load_defaults(BC_Hash *defaults)
4297 BC_Resources *resources = get_resources();
4298 char string[BCTEXTLEN];
4299 int newest_id = - 1;
4300 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4302 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4303 resources->filebox_history[i].path[0] = 0;
4304 defaults->get(string, resources->filebox_history[i].path);
4305 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4306 resources->filebox_history[i].id = defaults->get(string, resources->get_id());
4307 if(resources->filebox_history[i].id > newest_id)
4308 newest_id = resources->filebox_history[i].id;
4311 resources->filebox_id = newest_id + 1;
4312 resources->filebox_mode = defaults->get("FILEBOX_MODE", get_resources()->filebox_mode);
4313 resources->filebox_w = defaults->get("FILEBOX_W", get_resources()->filebox_w);
4314 resources->filebox_h = defaults->get("FILEBOX_H", get_resources()->filebox_h);
4315 resources->filebox_columntype[0] = defaults->get("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4316 resources->filebox_columntype[1] = defaults->get("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4317 resources->filebox_columntype[2] = defaults->get("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4318 resources->filebox_columntype[3] = defaults->get("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4319 resources->filebox_columnwidth[0] = defaults->get("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4320 resources->filebox_columnwidth[1] = defaults->get("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4321 resources->filebox_columnwidth[2] = defaults->get("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4322 resources->filebox_columnwidth[3] = defaults->get("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4323 resources->filebox_size_format = defaults->get("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4324 defaults->get("FILEBOX_FILTER", resources->filebox_filter);
4328 int BC_WindowBase::save_defaults(BC_Hash *defaults)
4330 BC_Resources *resources = get_resources();
4331 char string[BCTEXTLEN];
4332 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4334 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4335 defaults->update(string, resources->filebox_history[i].path);
4336 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4337 defaults->update(string, resources->filebox_history[i].id);
4339 defaults->update("FILEBOX_MODE", resources->filebox_mode);
4340 defaults->update("FILEBOX_W", resources->filebox_w);
4341 defaults->update("FILEBOX_H", resources->filebox_h);
4342 defaults->update("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4343 defaults->update("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4344 defaults->update("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4345 defaults->update("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4346 defaults->update("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4347 defaults->update("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4348 defaults->update("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4349 defaults->update("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4350 defaults->update("FILEBOX_FILTER", resources->filebox_filter);
4351 defaults->update("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4357 // For some reason XTranslateCoordinates can take a long time to return.
4358 // We work around this by only calling it when the event windows are different.
4359 void BC_WindowBase::translate_coordinates(Window src_w,
4371 *dest_x_return = src_x;
4372 *dest_y_return = src_y;
4376 XTranslateCoordinates(top_level->display,
4384 //printf("BC_WindowBase::translate_coordinates 1 %lld\n", timer.get_difference());
4388 void BC_WindowBase::get_root_coordinates(int x, int y, int *abs_x, int *abs_y)
4390 translate_coordinates(win, top_level->rootwin, x, y, abs_x, abs_y);
4393 void BC_WindowBase::get_win_coordinates(int abs_x, int abs_y, int *x, int *y)
4395 translate_coordinates(top_level->rootwin, win, abs_x, abs_y, x, y);
4403 #ifdef HAVE_LIBXXF86VM
4404 void BC_WindowBase::closest_vm(int *vm, int *width, int *height)
4408 if(XF86VidModeQueryExtension(top_level->display,&foo,&bar)) {
4410 XF86VidModeModeInfo **vm_modelines;
4411 XF86VidModeGetAllModeLines(top_level->display,
4412 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4413 for( i = 0; i < vm_count; i++ ) {
4414 if( vm_modelines[i]->hdisplay < vm_modelines[*vm]->hdisplay &&
4415 vm_modelines[i]->hdisplay >= *width )
4418 display = top_level->display;
4419 if( vm_modelines[*vm]->hdisplay == *width )
4422 *width = vm_modelines[*vm]->hdisplay;
4423 *height = vm_modelines[*vm]->vdisplay;
4428 void BC_WindowBase::scale_vm(int vm)
4430 int foo,bar,dotclock;
4431 if( XF86VidModeQueryExtension(top_level->display,&foo,&bar) ) {
4433 XF86VidModeModeInfo **vm_modelines;
4434 XF86VidModeModeLine vml;
4435 XF86VidModeGetAllModeLines(top_level->display,
4436 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4437 XF86VidModeGetModeLine(top_level->display,
4438 XDefaultScreen(top_level->display), &dotclock,&vml);
4439 orig_modeline.dotclock = dotclock;
4440 orig_modeline.hdisplay = vml.hdisplay;
4441 orig_modeline.hsyncstart = vml.hsyncstart;
4442 orig_modeline.hsyncend = vml.hsyncend;
4443 orig_modeline.htotal = vml.htotal;
4444 orig_modeline.vdisplay = vml.vdisplay;
4445 orig_modeline.vsyncstart = vml.vsyncstart;
4446 orig_modeline.vsyncend = vml.vsyncend;
4447 orig_modeline.vtotal = vml.vtotal;
4448 orig_modeline.flags = vml.flags;
4449 orig_modeline.privsize = vml.privsize;
4450 // orig_modeline.private = vml.private;
4451 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),vm_modelines[vm]);
4452 XF86VidModeSetViewPort(top_level->display,XDefaultScreen(top_level->display),0,0);
4453 XFlush(top_level->display);
4457 void BC_WindowBase::restore_vm()
4459 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),&orig_modeline);
4460 XFlush(top_level->display);
4465 #ifndef SINGLE_THREAD
4466 int BC_WindowBase::get_event_count()
4468 event_lock->lock("BC_WindowBase::get_event_count");
4469 int result = common_events.total;
4470 event_lock->unlock();
4474 XEvent* BC_WindowBase::get_event()
4477 while(!done && !result)
4479 event_condition->lock("BC_WindowBase::get_event");
4480 event_lock->lock("BC_WindowBase::get_event");
4482 if(common_events.total && !done)
4484 result = common_events.values[0];
4485 common_events.remove_number(0);
4488 event_lock->unlock();
4493 void BC_WindowBase::put_event(XEvent *event)
4495 event_lock->lock("BC_WindowBase::put_event");
4496 common_events.append(event);
4497 event_lock->unlock();
4498 event_condition->unlock();
4501 void BC_WindowBase::dequeue_events(Window win)
4503 event_lock->lock("BC_WindowBase::dequeue_events");
4505 int out = 0, total = common_events.size();
4506 for( int in=0; in<total; ++in ) {
4507 if( common_events[in]->xany.window == win ) continue;
4508 common_events[out++] = common_events[in];
4510 common_events.total = out;
4512 event_lock->unlock();
4515 int BC_WindowBase::resend_event(BC_WindowBase *window)
4517 if( resend_event_window ) return 1;
4518 resend_event_window = window;
4524 int BC_WindowBase::resend_event(BC_WindowBase *window)
4529 #endif // SINGLE_THREAD
4531 int BC_WindowBase::get_id()
4537 BC_Pixmap *BC_WindowBase::create_pixmap(VFrame *vframe)
4539 int w = vframe->get_w(), h = vframe->get_h();
4540 BC_Pixmap *icon = new BC_Pixmap(this, w, h);
4541 icon->draw_vframe(vframe, 0,0, w,h, 0,0);
4546 void BC_WindowBase::flicker(int n, int ms)
4548 int color = get_bg_color();
4549 for( int i=2*n; --i>=0; ) {
4550 set_inverse(); set_bg_color(WHITE);
4551 clear_box(0,0, w,h); flash(1);
4552 sync_display(); Timer::delay(ms);
4554 set_bg_color(color);
4558 void BC_WindowBase::focus()
4560 XWindowAttributes xwa;
4561 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4562 if( xwa.map_state == IsViewable )
4563 XSetInputFocus(top_level->display, top_level->win, RevertToParent, CurrentTime);