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
962 if(resize_events) dispatch_resize_event(last_resize_w, last_resize_h);
963 // Clear the motion buffer since this can clear the window
966 dispatch_motion_event();
969 ptr = (XClientMessageEvent*)event;
972 if(ptr->message_type == ProtoXAtom &&
973 (Atom)ptr->data.l[0] == DelWinXAtom)
978 if(ptr->message_type == RepeaterXAtom)
980 dispatch_repeat_event(ptr->data.l[0]);
981 // Make sure the repeater still exists.
982 // for(int i = 0; i < repeaters.total; i++)
984 // if(repeaters.values[i]->repeat_id == ptr->data.l[0])
986 // dispatch_repeat_event_master(ptr->data.l[0]);
992 if(ptr->message_type == SetDoneXAtom)
996 { // We currently use X marshalling for xatom events, we can switch to something else later
997 receive_custom_xatoms((xatom_event *)ptr);
1003 dispatch_focus_in();
1008 dispatch_focus_out();
1022 dispatch_motion_event();
1024 get_key_masks(event->xbutton.state);
1025 cursor_x = event->xbutton.x;
1026 cursor_y = event->xbutton.y;
1027 button_number = event->xbutton.button;
1029 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1030 event_win = event->xany.window;
1031 if (button_number < 6) {
1032 if(button_number < 4)
1034 button_pressed = event->xbutton.button;
1035 button_time1 = button_time2;
1036 button_time2 = button_time3;
1037 button_time3 = event->xbutton.time;
1040 drag_win = event_win;
1041 drag_x1 = cursor_x - get_resources()->drag_radius;
1042 drag_x2 = cursor_x + get_resources()->drag_radius;
1043 drag_y1 = cursor_y - get_resources()->drag_radius;
1044 drag_y2 = cursor_y + get_resources()->drag_radius;
1046 if((long)(button_time3 - button_time1) < resources.double_click * 2)
1049 button_time3 = button_time2 = button_time1 = 0;
1051 if((long)(button_time3 - button_time2) < resources.double_click)
1054 // button_time3 = button_time2 = button_time1 = 0;
1062 dispatch_button_press();
1069 dispatch_motion_event();
1071 get_key_masks(event->xbutton.state);
1072 button_number = event->xbutton.button;
1073 event_win = event->xany.window;
1074 if (button_number < 6)
1076 if(button_number < 4)
1078 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1080 dispatch_button_release();
1085 event_win = event->xany.window;
1086 dispatch_expose_event();
1090 get_key_masks(event->xmotion.state);
1091 // Dispatch previous motion event if this is a subsequent motion from a different window
1092 if(motion_events && last_motion_win != event->xany.window)
1094 dispatch_motion_event();
1097 // Buffer the current motion
1099 last_motion_state = event->xmotion.state;
1100 last_motion_x = event->xmotion.x;
1101 last_motion_y = event->xmotion.y;
1102 last_motion_win = event->xany.window;
1105 case ConfigureNotify:
1106 // printf("BC_WindowBase::dispatch_event %d win=%p this->win=%p\n",
1108 // event->xany.window,
1111 XTranslateCoordinates(top_level->display,
1119 last_resize_w = event->xconfigure.width;
1120 last_resize_h = event->xconfigure.height;
1123 cancel_translation = 0;
1125 // Resize history prevents responses to recursive resize requests
1126 for(int i = 0; i < resize_history.total && !cancel_resize; i++)
1128 if(resize_history.values[i]->w == last_resize_w &&
1129 resize_history.values[i]->h == last_resize_h)
1131 delete resize_history.values[i];
1132 resize_history.remove_number(i);
1137 if(last_resize_w == w && last_resize_h == h)
1145 if((last_translate_x == x && last_translate_y == y))
1146 cancel_translation = 1;
1148 if(!cancel_translation)
1150 translation_events = 1;
1153 translation_count++;
1157 get_key_masks(event->xkey.state);
1158 keys_return[0] = 0; keysym = -1;
1159 if(XFilterEvent(event, win)) {
1162 if( keysym_lookup(event) < 0 ) {
1163 printf("keysym %x\n", (uint32_t)keysym);
1167 //printf("BC_WindowBase::dispatch_event %d keysym=0x%x\n",
1171 // block out control keys
1172 if(keysym > 0xffe0 && keysym < 0xffff) break;
1173 // block out Alt_GR key
1174 if(keysym == 0xfe03) break;
1177 printf("BC_WindowBase::dispatch_event %x\n", (uint32_t)keysym);
1179 #ifdef X_HAVE_UTF8_STRING
1180 //It's Ascii or UTF8?
1181 // if (keysym != 0xffff && (keys_return[0] & 0xff) >= 0x7f )
1182 //printf("BC_WindowBase::dispatch_event %d %02x%02x\n", __LINE__, keys_return[0], keys_return[1]);
1184 if( ((keys_return[1] & 0xff) > 0x80) &&
1185 ((keys_return[0] & 0xff) > 0xC0) ) {
1186 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1187 key_pressed = keysym & 0xff;
1191 // shuttle speed codes
1192 if( keysym >= SKEY_MIN && keysym <= SKEY_MAX ) {
1193 key_pressed = keysym;
1195 else switch( keysym ) {
1196 // block out extra keys
1206 // Translate key codes
1207 case XK_Return: key_pressed = RETURN; break;
1208 case XK_Up: key_pressed = UP; break;
1209 case XK_Down: key_pressed = DOWN; break;
1210 case XK_Left: key_pressed = LEFT; break;
1211 case XK_Right: key_pressed = RIGHT; break;
1212 case XK_Next: key_pressed = PGDN; break;
1213 case XK_Prior: key_pressed = PGUP; break;
1214 case XK_BackSpace: key_pressed = BACKSPACE; break;
1215 case XK_Escape: key_pressed = ESC; break;
1218 key_pressed = LEFTTAB;
1222 case XK_ISO_Left_Tab: key_pressed = LEFTTAB; break;
1223 case XK_underscore: key_pressed = '_'; break;
1224 case XK_asciitilde: key_pressed = '~'; break;
1225 case XK_Delete: key_pressed = DELETE; break;
1226 case XK_Home: key_pressed = HOME; break;
1227 case XK_End: key_pressed = END; break;
1230 case XK_KP_Enter: key_pressed = KPENTER; break;
1231 case XK_KP_Add: key_pressed = KPPLUS; break;
1232 case XK_KP_Subtract: key_pressed = KPMINUS; break;
1233 case XK_KP_Multiply: key_pressed = KPSTAR; break;
1234 case XK_KP_Divide: key_pressed = KPSLASH; break;
1236 case XK_KP_End: key_pressed = KP1; break;
1238 case XK_KP_Down: key_pressed = KP2; break;
1240 case XK_KP_Page_Down: key_pressed = KP3; break;
1242 case XK_KP_Left: key_pressed = KP4; break;
1244 case XK_KP_Begin: key_pressed = KP5; break;
1246 case XK_KP_Right: key_pressed = KP6; break;
1248 case XK_KP_Home: key_pressed = KP7; break;
1250 case XK_KP_Up: key_pressed = KP8; break;
1252 case XK_KP_Page_Up: key_pressed = KP9; break;
1254 case XK_KP_Insert: key_pressed = KPINS; break;
1256 case XK_KP_Delete: key_pressed = KPDEL; break;
1258 case XK_F1: key_pressed = KEY_F1; break;
1259 case XK_F2: key_pressed = KEY_F2; break;
1260 case XK_F3: key_pressed = KEY_F3; break;
1261 case XK_F4: key_pressed = KEY_F4; break;
1262 case XK_F5: key_pressed = KEY_F5; break;
1263 case XK_F6: key_pressed = KEY_F6; break;
1264 case XK_F7: key_pressed = KEY_F7; break;
1265 case XK_F8: key_pressed = KEY_F8; break;
1266 case XK_F9: key_pressed = KEY_F9; break;
1267 case XK_F10: key_pressed = KEY_F10; break;
1268 case XK_F11: key_pressed = KEY_F11; break;
1269 case XK_F12: key_pressed = KEY_F12; break;
1271 case XK_Menu: key_pressed = KPMENU; break; /* menu */
1273 // above case XK_KP_Enter: key_pressed = KPENTER; break; /* check */
1274 case XF86XK_MenuKB: key_pressed = KPMENU; break; /* menu */
1275 // intercepted case XF86XK_PowerDown: key_pressed = KPPOWER; break; /* Power */
1276 case XF86XK_Launch1: key_pressed = KPTV; break; /* TV */
1277 case XF86XK_Launch2: key_pressed = KPDVD; break; /* DVD */
1278 // intercepted case XF86XK_WWW: key_pressed = KPWWEB; break; /* WEB */
1279 case XF86XK_Launch3: key_pressed = KPBOOK; break; /* book */
1280 case XF86XK_Launch4: key_pressed = KPHAND; break; /* hand */
1281 case XF86XK_Reply: key_pressed = KPTMR; break; /* timer */
1282 case SunXK_Front: key_pressed = KPMAXW; break; /* max */
1283 // above case XK_Left: key_pressed = LEFT; break; /* left */
1284 // above case XK_Right: key_pressed = RIGHT; break; /* right */
1285 // above case XK_Down: key_pressed = DOWN; break; /* down */
1286 // above case XK_Up: key_pressed = UP; break; /* up */
1287 // above case XK_SPACE: key_pressed = KPSPACE; break; /* ok */
1288 // intercepted case XF86XK_AudioRaiseVolume: key_pressed = KPVOLU; break; /* VOL + */
1289 // intercepted case XF86XK_AudioMute: key_pressed = KPMUTE; break; /* MUTE */
1290 // intercepted case XF86XK_AudioLowerVolume: key_pressed = KPVOLD; break; /* VOL - */
1291 case XF86XK_ScrollUp: key_pressed = KPCHUP; break; /* CH + */
1292 case XF86XK_ScrollDown: key_pressed = KPCHDN; break; /* CH - */
1293 case XF86XK_AudioRecord: key_pressed = KPRECD; break; /* ( o) red */
1294 case XF86XK_Forward: key_pressed = KPPLAY; break; /* ( >) */
1295 case XK_Redo: key_pressed = KPFWRD; break; /* (>>) */
1296 case XF86XK_Back: key_pressed = KPBACK; break; /* (<<) */
1297 case XK_Cancel: key_pressed = KPSTOP; break; /* ([]) */
1298 case XK_Pause: key_pressed = KPAUSE; break; /* ('') */
1301 key_pressed = keysym & 0xff;
1302 #ifdef X_HAVE_UTF8_STRING
1303 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1308 #ifdef X_HAVE_UTF8_STRING
1310 key_pressed_utf8 = keys_return;
1315 if( top_level == this )
1316 result = BC_KeyboardHandler::run_listeners(this);
1318 //printf("BC_WindowBase::dispatch_event %d %d %x\n", shift_down(), alt_down(), key_pressed);
1320 result = dispatch_keypress_event();
1321 // Handle some default keypresses
1324 if(key_pressed == 'w' ||
1333 XLookupString((XKeyEvent*)event, keys_return, 1, &keysym, 0);
1334 dispatch_keyrelease_event();
1335 // printf("BC_WindowBase::dispatch_event KeyRelease keysym=0x%x keystate=0x%lld\n",
1336 // keysym, event->xkey.state);
1340 if( event->xcrossing.mode != NotifyNormal ) break;
1342 event_win = event->xany.window;
1343 dispatch_cursor_leave();
1347 if( event->xcrossing.mode != NotifyNormal ) break;
1349 if( !cursor_entered ) {
1350 for( int i=0; i<popups.size(); ++i ) { // popups always take focus
1351 if( popups[i]->win == event->xcrossing.window )
1354 if( !cursor_entered && get_resources()->grab_input_focus &&
1355 !event->xcrossing.focus && event->xcrossing.window == win ) {
1358 if( cursor_entered )
1361 event_win = event->xany.window;
1362 cursor_x = event->xcrossing.x;
1363 cursor_y = event->xcrossing.y;
1364 dispatch_cursor_enter();
1370 //printf("100 %s %p %d\n", title, event, event->type);
1371 //if(event->type != ClientMessage) dump();
1373 #ifndef SINGLE_THREAD
1376 if( resend_event_window ) {
1377 resend_event_window->put_event(event);
1378 resend_event_window = 0;
1384 // if(done) completion_lock->unlock();
1387 if(debug) printf("BC_WindowBase::dispatch_event this=%p %d\n", this, __LINE__);
1391 int BC_WindowBase::dispatch_expose_event()
1394 for(int i = 0; i < subwindows->total && !result; i++)
1396 result = subwindows->values[i]->dispatch_expose_event();
1399 // Propagate to user
1400 if(!result) expose_event();
1404 int BC_WindowBase::dispatch_resize_event(int w, int h)
1406 // Can't store new w and h until the event is handles
1407 // because bcfilebox depends on the old w and h to
1408 // reposition widgets.
1409 if( window_type == MAIN_WINDOW ) {
1414 pixmap = new BC_Pixmap(this, w, h);
1415 clear_box(0, 0, w, h);
1418 // Propagate to subwindows
1419 for(int i = 0; i < subwindows->total; i++) {
1420 subwindows->values[i]->dispatch_resize_event(w, h);
1423 // Propagate to user
1426 if( window_type == MAIN_WINDOW ) {
1435 int BC_WindowBase::dispatch_flash()
1438 for(int i = 0; i < subwindows->total; i++)
1439 subwindows->values[i]->dispatch_flash();
1443 int BC_WindowBase::dispatch_translation_event()
1445 translation_events = 0;
1446 if(window_type == MAIN_WINDOW)
1450 x = last_translate_x;
1451 y = last_translate_y;
1452 // Correct for window manager offsets
1457 for(int i = 0; i < subwindows->total; i++)
1459 subwindows->values[i]->dispatch_translation_event();
1462 translation_event();
1466 int BC_WindowBase::dispatch_motion_event()
1471 if(top_level == this)
1474 event_win = last_motion_win;
1475 get_key_masks(last_motion_state);
1478 if(get_button_down() && !active_menubar && !active_popup_menu)
1482 cursor_x = last_motion_x;
1483 cursor_y = last_motion_y;
1484 result = dispatch_drag_motion();
1488 (last_motion_x < drag_x1 || last_motion_x >= drag_x2 ||
1489 last_motion_y < drag_y1 || last_motion_y >= drag_y2))
1494 result = dispatch_drag_start();
1498 cursor_x = last_motion_x;
1499 cursor_y = last_motion_y;
1501 // printf("BC_WindowBase::dispatch_motion_event %d %p %p %p\n",
1504 // active_popup_menu,
1505 // active_subwindow);
1507 if(active_menubar && !result) result = active_menubar->dispatch_motion_event();
1508 if(active_popup_menu && !result) result = active_popup_menu->dispatch_motion_event();
1509 if(active_subwindow && !result) result = active_subwindow->dispatch_motion_event();
1512 // Dispatch in stacking order
1513 for(int i = subwindows->size() - 1; i >= 0 && !result; i--)
1515 result = subwindows->values[i]->dispatch_motion_event();
1518 if(!result) result = cursor_motion_event(); // give to user
1522 int BC_WindowBase::dispatch_keypress_event()
1525 if(top_level == this)
1527 if(active_subwindow) result = active_subwindow->dispatch_keypress_event();
1530 for(int i = 0; i < subwindows->total && !result; i++)
1532 result = subwindows->values[i]->dispatch_keypress_event();
1535 if(!result) result = keypress_event();
1540 int BC_WindowBase::dispatch_keyrelease_event()
1543 if(top_level == this)
1545 if(active_subwindow) result = active_subwindow->dispatch_keyrelease_event();
1548 for(int i = 0; i < subwindows->total && !result; i++)
1550 result = subwindows->values[i]->dispatch_keyrelease_event();
1553 if(!result) result = keyrelease_event();
1558 int BC_WindowBase::dispatch_focus_in()
1560 for(int i = 0; i < subwindows->total; i++)
1562 subwindows->values[i]->dispatch_focus_in();
1570 int BC_WindowBase::dispatch_focus_out()
1572 for(int i = 0; i < subwindows->total; i++)
1574 subwindows->values[i]->dispatch_focus_out();
1582 int BC_WindowBase::get_has_focus()
1584 return top_level->has_focus;
1587 int BC_WindowBase::get_deleting()
1589 if(is_deleting) return 1;
1590 if(parent_window && parent_window->get_deleting()) return 1;
1594 int BC_WindowBase::dispatch_button_press()
1599 if(top_level == this)
1601 if(active_menubar) result = active_menubar->dispatch_button_press();
1602 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_press();
1603 if(active_subwindow && !result) result = active_subwindow->dispatch_button_press();
1606 for(int i = 0; i < subwindows->total && !result; i++)
1608 result = subwindows->values[i]->dispatch_button_press();
1611 if(!result) result = button_press_event();
1617 int BC_WindowBase::dispatch_button_release()
1620 if(top_level == this)
1622 if(active_menubar) result = active_menubar->dispatch_button_release();
1623 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_release();
1624 if(active_subwindow && !result) result = active_subwindow->dispatch_button_release();
1625 if(!result && button_number != 4 && button_number != 5)
1626 result = dispatch_drag_stop();
1629 for(int i = 0; i < subwindows->total && !result; i++)
1631 result = subwindows->values[i]->dispatch_button_release();
1636 result = button_release_event();
1643 int BC_WindowBase::dispatch_repeat_event(int64_t duration)
1646 // all repeat event handlers get called and decide based on activity and duration
1647 // whether to respond
1648 for(int i = 0; i < subwindows->total; i++)
1650 subwindows->values[i]->dispatch_repeat_event(duration);
1654 repeat_event(duration);
1658 // Unlock next repeat signal
1659 if(window_type == MAIN_WINDOW)
1661 #ifdef SINGLE_THREAD
1662 BC_Display::display_global->unlock_repeaters(duration);
1664 for(int i = 0; i < repeaters.total; i++)
1666 if(repeaters.values[i]->delay == duration)
1668 repeaters.values[i]->repeat_lock->unlock();
1676 void BC_WindowBase::unhide_cursor()
1681 if(top_level->is_hourglass)
1682 set_cursor(HOURGLASS_CURSOR, 1, 0);
1684 set_cursor(current_cursor, 1, 0);
1686 cursor_timer->update();
1690 void BC_WindowBase::update_video_cursor()
1692 if(video_on && !is_transparent)
1694 if(cursor_timer->get_difference() > VIDEO_CURSOR_TIMEOUT && !is_transparent)
1697 set_cursor(TRANSPARENT_CURSOR, 1, 1);
1698 cursor_timer->update();
1703 cursor_timer->update();
1708 int BC_WindowBase::dispatch_cursor_leave()
1712 for(int i = 0; i < subwindows->total; i++)
1714 subwindows->values[i]->dispatch_cursor_leave();
1717 cursor_leave_event();
1721 int BC_WindowBase::dispatch_cursor_enter()
1727 if(active_menubar) result = active_menubar->dispatch_cursor_enter();
1728 if(!result && active_popup_menu) result = active_popup_menu->dispatch_cursor_enter();
1729 if(!result && active_subwindow) result = active_subwindow->dispatch_cursor_enter();
1731 for(int i = 0; !result && i < subwindows->total; i++)
1733 result = subwindows->values[i]->dispatch_cursor_enter();
1736 if(!result) result = cursor_enter_event();
1740 int BC_WindowBase::cursor_enter_event()
1745 int BC_WindowBase::cursor_leave_event()
1750 int BC_WindowBase::close_event()
1756 int BC_WindowBase::dispatch_drag_start()
1759 if(active_menubar) result = active_menubar->dispatch_drag_start();
1760 if(!result && active_popup_menu) result = active_popup_menu->dispatch_drag_start();
1761 if(!result && active_subwindow) result = active_subwindow->dispatch_drag_start();
1763 for(int i = 0; i < subwindows->total && !result; i++)
1765 result = subwindows->values[i]->dispatch_drag_start();
1768 if(!result) result = is_dragging = drag_start_event();
1772 int BC_WindowBase::dispatch_drag_stop()
1776 for(int i = 0; i < subwindows->total && !result; i++)
1778 result = subwindows->values[i]->dispatch_drag_stop();
1781 if(is_dragging && !result)
1791 int BC_WindowBase::dispatch_drag_motion()
1794 for(int i = 0; i < subwindows->total && !result; i++)
1796 result = subwindows->values[i]->dispatch_drag_motion();
1799 if(is_dragging && !result)
1801 drag_motion_event();
1809 int BC_WindowBase::show_tooltip(const char *text, int x, int y, int w, int h)
1812 int forced = !text ? force_tooltip : 1;
1813 if( !text ) text = tooltip_text;
1814 if( !text || (!forced && !get_resources()->tooltips_enabled) ) {
1815 top_level->hide_tooltip();
1819 if(w < 0) w = get_text_width(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1820 if(h < 0) h = get_text_height(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1821 // default x,y (win relative)
1822 if( x < 0 ) x = get_w();
1823 if( y < 0 ) y = get_h();
1825 get_root_coordinates(x, y, &wx, &wy);
1826 // keep the tip inside the window/display
1827 int x0 = top_level->get_x(), x1 = x0 + top_level->get_w();
1828 int x2 = top_level->get_screen_x(0, -1) + top_level->get_screen_w(0, -1);
1829 if( x1 > x2 ) x1 = x2;
1830 if( wx < x0 ) wx = x0;
1831 if( wx >= (x1-=w) ) wx = x1;
1832 int y0 = top_level->get_y(), y1 = y0 + top_level->get_h();
1833 int y2 = top_level->get_root_h(0);
1834 if( y1 > y2 ) y1 = y2;
1835 if( wy < y0 ) wy = y0;
1836 if( wy >= (y1-=h) ) wy = y1;
1837 // avoid tip under cursor (flickers)
1839 get_abs_cursor(abs_x,abs_y, 0);
1840 if( wx < abs_x && abs_x < wx+w && wy < abs_y && abs_y < wy+h ) {
1841 if( wx-abs_x < wy-abs_y )
1848 tooltip_popup = new BC_Popup(top_level, wx, wy, w, h,
1849 get_resources()->tooltip_bg_color);
1852 tooltip_popup->reposition_window(wx, wy, w, h);
1855 tooltip_popup->flash();
1856 tooltip_popup->flush();
1860 int BC_WindowBase::hide_tooltip()
1863 for(int i = 0; i < subwindows->total; i++)
1865 subwindows->values[i]->hide_tooltip();
1871 delete tooltip_popup;
1877 const char *BC_WindowBase::get_tooltip()
1879 return tooltip_text;
1882 int BC_WindowBase::set_tooltip(const char *text)
1884 tooltip_text = text;
1886 // Update existing tooltip if it is visible
1890 tooltip_popup->flash();
1894 // signal the event handler to repeat
1895 int BC_WindowBase::set_repeat(int64_t duration)
1899 printf("BC_WindowBase::set_repeat duration=%jd\n", duration);
1902 if(window_type != MAIN_WINDOW) return top_level->set_repeat(duration);
1904 #ifdef SINGLE_THREAD
1905 BC_Display::display_global->set_repeat(this, duration);
1907 // test repeater database for duplicates
1908 for(int i = 0; i < repeaters.total; i++)
1911 if(repeaters.values[i]->delay == duration)
1913 repeaters.values[i]->start_repeating(this);
1918 BC_Repeater *repeater = new BC_Repeater(this, duration);
1919 repeater->initialize();
1920 repeaters.append(repeater);
1921 repeater->start_repeating();
1926 int BC_WindowBase::unset_repeat(int64_t duration)
1928 if(window_type != MAIN_WINDOW) return top_level->unset_repeat(duration);
1930 #ifdef SINGLE_THREAD
1931 BC_Display::display_global->unset_repeat(this, duration);
1933 for(int i = 0; i < repeaters.total; i++)
1935 if(repeaters.values[i]->delay == duration)
1937 repeaters.values[i]->stop_repeating();
1945 int BC_WindowBase::unset_all_repeaters()
1947 #ifdef SINGLE_THREAD
1948 BC_Display::display_global->unset_all_repeaters(this);
1950 for(int i = 0; i < repeaters.total; i++)
1952 repeaters.values[i]->stop_repeating();
1954 repeaters.remove_all_objects();
1959 // long BC_WindowBase::get_repeat_id()
1961 // return top_level->next_repeat_id++;
1964 XEvent *BC_WindowBase::new_xevent()
1966 XEvent *event = new XEvent;
1967 memset(event, 0, sizeof(*event));
1971 #ifndef SINGLE_THREAD
1972 int BC_WindowBase::arm_repeat(int64_t duration)
1974 XEvent *event = new_xevent();
1975 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
1976 ptr->type = ClientMessage;
1977 ptr->message_type = RepeaterXAtom;
1979 ptr->data.l[0] = duration;
1981 // Couldn't use XSendEvent since it locked up randomly.
1987 int BC_WindowBase::receive_custom_xatoms(xatom_event *event)
1992 int BC_WindowBase::send_custom_xatom(xatom_event *event)
1994 #ifndef SINGLE_THREAD
1995 XEvent *myevent = new_xevent();
1996 XClientMessageEvent *ptr = (XClientMessageEvent*)myevent;
1997 ptr->type = ClientMessage;
1998 ptr->message_type = event->message_type;
1999 ptr->format = event->format;
2000 ptr->data.l[0] = event->data.l[0];
2001 ptr->data.l[1] = event->data.l[1];
2002 ptr->data.l[2] = event->data.l[2];
2003 ptr->data.l[3] = event->data.l[3];
2004 ptr->data.l[4] = event->data.l[4];
2013 Atom BC_WindowBase::create_xatom(const char *atom_name)
2015 return XInternAtom(display, atom_name, False);
2018 int BC_WindowBase::get_atoms()
2020 SetDoneXAtom = XInternAtom(display, "BC_REPEAT_EVENT", False);
2021 RepeaterXAtom = XInternAtom(display, "BC_CLOSE_EVENT", False);
2022 DestroyAtom = XInternAtom(display, "BC_DESTROY_WINDOW", False);
2023 DelWinXAtom = XInternAtom(display, "WM_DELETE_WINDOW", False);
2024 if( (ProtoXAtom = XInternAtom(display, "WM_PROTOCOLS", False)) != 0 )
2025 XChangeProperty(display, win, ProtoXAtom, XA_ATOM, 32,
2026 PropModeReplace, (unsigned char *)&DelWinXAtom, True);
2032 void BC_WindowBase::init_cursors()
2034 arrow_cursor = XCreateFontCursor(display, XC_top_left_arrow);
2035 cross_cursor = XCreateFontCursor(display, XC_crosshair);
2036 ibeam_cursor = XCreateFontCursor(display, XC_xterm);
2037 vseparate_cursor = XCreateFontCursor(display, XC_sb_v_double_arrow);
2038 hseparate_cursor = XCreateFontCursor(display, XC_sb_h_double_arrow);
2039 move_cursor = XCreateFontCursor(display, XC_fleur);
2040 left_cursor = XCreateFontCursor(display, XC_sb_left_arrow);
2041 right_cursor = XCreateFontCursor(display, XC_sb_right_arrow);
2042 upright_arrow_cursor = XCreateFontCursor(display, XC_arrow);
2043 upleft_resize_cursor = XCreateFontCursor(display, XC_top_left_corner);
2044 upright_resize_cursor = XCreateFontCursor(display, XC_top_right_corner);
2045 downleft_resize_cursor = XCreateFontCursor(display, XC_bottom_left_corner);
2046 downright_resize_cursor = XCreateFontCursor(display, XC_bottom_right_corner);
2047 hourglass_cursor = XCreateFontCursor(display, XC_watch);
2048 grabbed_cursor = create_grab_cursor();
2050 static char cursor_data[] = { 0,0,0,0, 0,0,0,0 };
2051 Colormap colormap = DefaultColormap(display, screen);
2052 Pixmap pixmap_bottom = XCreateBitmapFromData(display,
2053 rootwin, cursor_data, 8, 8);
2054 XColor black, dummy;
2055 XAllocNamedColor(display, colormap, "black", &black, &dummy);
2056 transparent_cursor = XCreatePixmapCursor(display,
2057 pixmap_bottom, pixmap_bottom, &black, &black, 0, 0);
2058 // XDefineCursor(display, win, transparent_cursor);
2059 XFreePixmap(display, pixmap_bottom);
2062 int BC_WindowBase::evaluate_color_model(int client_byte_order, int server_byte_order, int depth)
2064 int color_model = BC_TRANSPARENCY;
2068 color_model = BC_RGB8;
2071 color_model = (server_byte_order == client_byte_order) ? BC_RGB565 : BC_BGR565;
2074 color_model = server_byte_order ? BC_BGR888 : BC_RGB888;
2077 color_model = server_byte_order ? BC_BGR8888 : BC_ARGB8888;
2083 int BC_WindowBase::init_colors()
2086 current_color_value = current_color_pixel = 0;
2088 // Get the real depth
2091 ximage = XCreateImage(top_level->display,
2093 top_level->default_depth,
2101 bits_per_pixel = ximage->bits_per_pixel;
2102 XDestroyImage(ximage);
2104 color_model = evaluate_color_model(client_byte_order,
2107 // Get the color model
2112 cmap = XCreateColormap(display, rootwin, vis, AllocNone);
2113 create_private_colors();
2116 cmap = DefaultColormap(display, screen);
2117 create_shared_colors();
2120 allocate_color_table();
2124 //cmap = DefaultColormap(display, screen);
2125 cmap = XCreateColormap(display, rootwin, vis, AllocNone );
2131 int BC_WindowBase::create_private_colors()
2136 for(int i = 0; i < 255; i++)
2138 color = (i & 0xc0) << 16;
2139 color += (i & 0x38) << 10;
2140 color += (i & 0x7) << 5;
2141 color_table[i][0] = color;
2143 create_shared_colors(); // overwrite the necessary colors on the table
2148 int BC_WindowBase::create_color(int color)
2150 if(total_colors == 256)
2152 // replace the closest match with an exact match
2153 color_table[get_color_rgb8(color)][0] = color;
2157 // add the color to the table
2158 color_table[total_colors][0] = color;
2164 int BC_WindowBase::create_shared_colors()
2166 create_color(BLACK);
2167 create_color(WHITE);
2169 create_color(LTGREY);
2170 create_color(MEGREY);
2171 create_color(MDGREY);
2172 create_color(DKGREY);
2174 create_color(LTCYAN);
2175 create_color(MECYAN);
2176 create_color(MDCYAN);
2177 create_color(DKCYAN);
2179 create_color(LTGREEN);
2180 create_color(GREEN);
2181 create_color(DKGREEN);
2183 create_color(LTPINK);
2187 create_color(LTBLUE);
2189 create_color(DKBLUE);
2191 create_color(LTYELLOW);
2192 create_color(MEYELLOW);
2193 create_color(MDYELLOW);
2194 create_color(DKYELLOW);
2196 create_color(LTPURPLE);
2197 create_color(MEPURPLE);
2198 create_color(MDPURPLE);
2199 create_color(DKPURPLE);
2201 create_color(FGGREY);
2202 create_color(MNBLUE);
2203 create_color(ORANGE);
2204 create_color(FTGREY);
2209 Cursor BC_WindowBase::create_grab_cursor()
2211 int iw = 23, iw1 = iw-1, iw2 = iw/2;
2212 int ih = 23, ih1 = ih-1, ih2 = ih/2;
2213 VFrame grab(iw,ih,BC_RGB888);
2215 grab.set_pixel_color(RED); // fg
2216 grab.draw_smooth(iw2,0, iw1,0, iw1,ih2);
2217 grab.draw_smooth(iw1,ih2, iw1,ih1, iw2,ih1);
2218 grab.draw_smooth(iw2,ih1, 0,ih1, 0,ih2);
2219 grab.draw_smooth(0,ih2, 0,0, iw2,0);
2220 grab.set_pixel_color(WHITE); // bg
2221 grab.draw_line(0,ih2, iw2-2,ih2);
2222 grab.draw_line(iw2+2,ih2, iw1,ih2);
2223 grab.draw_line(iw2,0, iw2,ih2-2);
2224 grab.draw_line(iw2,ih2+2, iw2,ih1);
2226 int bpl = (iw+7)/8, isz = bpl * ih;
2227 char img[isz]; memset(img, 0, isz);
2228 char msk[isz]; memset(msk, 0, isz);
2229 unsigned char **rows = grab.get_rows();
2230 for( int iy=0; iy<ih; ++iy ) {
2231 char *op = img + iy*bpl;
2232 char *mp = msk + iy*bpl;
2233 unsigned char *ip = rows[iy];
2234 for( int ix=0; ix<iw; ++ix,ip+=3 ) {
2235 if( ip[0] ) mp[ix>>3] |= (1<<(ix&7));
2236 if( !ip[1] ) op[ix>>3] |= (1<<(ix&7));
2239 unsigned long white_pix = WhitePixel(display, screen);
2240 unsigned long black_pix = BlackPixel(display, screen);
2241 Pixmap img_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2242 img, iw,ih, white_pix,black_pix, 1);
2243 Pixmap msk_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2244 msk, iw,ih, white_pix,black_pix, 1);
2247 fc.flags = bc.flags = DoRed | DoGreen | DoBlue;
2248 fc.red = 0xffff; fc.green = fc.blue = 0; // fg
2249 bc.red = 0xffff; bc.green = 0xffff; bc.blue = 0x0000; // bg
2250 Cursor cursor = XCreatePixmapCursor(display, img_xpm,msk_xpm, &fc,&bc, iw2,ih2);
2251 XFreePixmap(display, img_xpm);
2252 XFreePixmap(display, msk_xpm);
2256 int BC_WindowBase::allocate_color_table()
2258 int red, green, blue, color;
2261 for(int i = 0; i < total_colors; i++)
2263 color = color_table[i][0];
2264 red = (color & 0xFF0000) >> 16;
2265 green = (color & 0x00FF00) >> 8;
2266 blue = color & 0xFF;
2268 col.flags = DoRed | DoGreen | DoBlue;
2269 col.red = red<<8 | red;
2270 col.green = green<<8 | green;
2271 col.blue = blue<<8 | blue;
2273 XAllocColor(display, cmap, &col);
2274 color_table[i][1] = col.pixel;
2277 XInstallColormap(display, cmap);
2281 int BC_WindowBase::init_window_shape()
2283 if(bg_pixmap && bg_pixmap->use_alpha())
2285 XShapeCombineMask(top_level->display,
2286 this->win, ShapeBounding, 0, 0,
2287 bg_pixmap->get_alpha(), ShapeSet);
2293 int BC_WindowBase::init_gc()
2295 unsigned long gcmask;
2296 gcmask = GCFont | GCGraphicsExposures;
2299 gcvalues.font = mediumfont->fid; // set the font
2300 gcvalues.graphics_exposures = 0; // prevent expose events for every redraw
2301 gc = XCreateGC(display, rootwin, gcmask, &gcvalues);
2303 // gcmask = GCCapStyle | GCJoinStyle;
2304 // XGetGCValues(display, gc, gcmask, &gcvalues);
2305 // printf("BC_WindowBase::init_gc %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2309 int BC_WindowBase::init_fonts()
2311 if( !(smallfont = XLoadQueryFont(display, _(resources.small_font))) )
2312 if( !(smallfont = XLoadQueryFont(display, _(resources.small_font2))) )
2313 smallfont = XLoadQueryFont(display, "fixed");
2314 if( !(mediumfont = XLoadQueryFont(display, _(resources.medium_font))) )
2315 if( !(mediumfont = XLoadQueryFont(display, _(resources.medium_font2))) )
2316 mediumfont = XLoadQueryFont(display, "fixed");
2317 if( !(largefont = XLoadQueryFont(display, _(resources.large_font))) )
2318 if( !(largefont = XLoadQueryFont(display, _(resources.large_font2))) )
2319 largefont = XLoadQueryFont(display, "fixed");
2320 if( !(bigfont = XLoadQueryFont(display, _(resources.big_font))) )
2321 if( !(bigfont = XLoadQueryFont(display, _(resources.big_font2))) )
2322 bigfont = XLoadQueryFont(display, "fixed");
2324 if((clockfont = XLoadQueryFont(display, _(resources.clock_font))) == NULL)
2325 if((clockfont = XLoadQueryFont(display, _(resources.clock_font2))) == NULL)
2326 clockfont = XLoadQueryFont(display, "fixed");
2329 if(get_resources()->use_fontset)
2334 // FIXME: should check the m,d,n values
2335 smallfontset = XCreateFontSet(display, resources.small_fontset, &m, &n, &d);
2337 smallfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2338 mediumfontset = XCreateFontSet(display, resources.medium_fontset, &m, &n, &d);
2339 if( !mediumfontset )
2340 mediumfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2341 largefontset = XCreateFontSet(display, resources.large_fontset, &m, &n, &d);
2343 largefontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2344 bigfontset = XCreateFontSet(display, resources.big_fontset, &m, &n, &d);
2346 bigfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2347 clockfontset = XCreateFontSet(display, resources.clock_fontset, &m, &n, &d);
2349 clockfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2350 if(clockfontset && bigfontset && largefontset && mediumfontset && smallfontset) {
2351 curr_fontset = mediumfontset;
2352 get_resources()->use_fontset = 1;
2356 get_resources()->use_fontset = 0;
2363 void BC_WindowBase::init_xft()
2366 if( !get_resources()->use_xft ) return;
2367 // apparently, xft is not reentrant, more than this is needed
2368 static Mutex xft_init_lock("BC_WindowBase::xft_init_lock", 0);
2369 xft_init_lock.lock("BC_WindowBase::init_xft");
2370 if(!(smallfont_xft =
2371 (resources.small_font_xft[0] == '-' ?
2372 xftFontOpenXlfd(display, screen, resources.small_font_xft) :
2373 xftFontOpenName(display, screen, resources.small_font_xft))) )
2374 if(!(smallfont_xft =
2375 xftFontOpenXlfd(display, screen, resources.small_font_xft2)))
2376 smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2377 if(!(mediumfont_xft =
2378 (resources.medium_font_xft[0] == '-' ?
2379 xftFontOpenXlfd(display, screen, resources.medium_font_xft) :
2380 xftFontOpenName(display, screen, resources.medium_font_xft))) )
2381 if(!(mediumfont_xft =
2382 xftFontOpenXlfd(display, screen, resources.medium_font_xft2)))
2383 mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2384 if(!(largefont_xft =
2385 (resources.large_font_xft[0] == '-' ?
2386 xftFontOpenXlfd(display, screen, resources.large_font_xft) :
2387 xftFontOpenName(display, screen, resources.large_font_xft))) )
2388 if(!(largefont_xft =
2389 xftFontOpenXlfd(display, screen, resources.large_font_xft2)))
2390 largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2392 (resources.big_font_xft[0] == '-' ?
2393 xftFontOpenXlfd(display, screen, resources.big_font_xft) :
2394 xftFontOpenName(display, screen, resources.big_font_xft))) )
2396 xftFontOpenXlfd(display, screen, resources.big_font_xft2)))
2397 bigfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2398 if(!(clockfont_xft =
2399 (resources.clock_font_xft[0] == '-' ?
2400 xftFontOpenXlfd(display, screen, resources.clock_font_xft) :
2401 xftFontOpenName(display, screen, resources.clock_font_xft))) )
2402 clockfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2405 if(!(bold_smallfont_xft =
2406 (resources.small_b_font_xft[0] == '-' ?
2407 xftFontOpenXlfd(display, screen, resources.small_b_font_xft) :
2408 xftFontOpenName(display, screen, resources.small_b_font_xft))) )
2409 bold_smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2410 if(!(bold_mediumfont_xft =
2411 (resources.medium_b_font_xft[0] == '-' ?
2412 xftFontOpenXlfd(display, screen, resources.medium_b_font_xft) :
2413 xftFontOpenName(display, screen, resources.medium_b_font_xft))) )
2414 bold_mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2415 if(!(bold_largefont_xft =
2416 (resources.large_b_font_xft[0] == '-' ?
2417 xftFontOpenXlfd(display, screen, resources.large_b_font_xft) :
2418 xftFontOpenName(display, screen, resources.large_b_font_xft))) )
2419 bold_largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2421 if( !smallfont_xft || !mediumfont_xft || !largefont_xft || !bigfont_xft ||
2422 !bold_largefont_xft || !bold_mediumfont_xft || !bold_largefont_xft ||
2424 printf("BC_WindowBase::init_fonts: no xft fonts found:"
2425 " %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n",
2426 resources.small_font_xft, smallfont_xft,
2427 resources.medium_font_xft, mediumfont_xft,
2428 resources.large_font_xft, largefont_xft,
2429 resources.big_font_xft, bigfont_xft,
2430 resources.clock_font_xft, clockfont_xft,
2431 resources.small_b_font_xft, bold_smallfont_xft,
2432 resources.medium_b_font_xft, bold_mediumfont_xft,
2433 resources.large_b_font_xft, bold_largefont_xft);
2434 get_resources()->use_xft = 0;
2437 // _XftDisplayInfo needs a lock.
2438 xftDefaultHasRender(display);
2439 xft_init_lock.unlock();
2443 void BC_WindowBase::init_im()
2445 XIMStyles *xim_styles;
2448 if(!(input_method = XOpenIM(display, NULL, NULL, NULL)))
2450 printf("BC_WindowBase::init_im: Could not open input method.\n");
2453 if(XGetIMValues(input_method, XNQueryInputStyle, &xim_styles, NULL) ||
2456 printf("BC_WindowBase::init_im: Input method doesn't support any styles.\n");
2457 XCloseIM(input_method);
2462 for(int z = 0; z < xim_styles->count_styles; z++)
2464 if(xim_styles->supported_styles[z] == (XIMPreeditNothing | XIMStatusNothing))
2466 xim_style = xim_styles->supported_styles[z];
2474 printf("BC_WindowBase::init_im: Input method doesn't support the style we need.\n");
2475 XCloseIM(input_method);
2479 input_context = XCreateIC(input_method, XNInputStyle, xim_style,
2480 XNClientWindow, win, XNFocusWindow, win, NULL);
2483 printf("BC_WindowBase::init_im: Failed to create input context.\n");
2484 XCloseIM(input_method);
2489 void BC_WindowBase::finit_im()
2491 if( input_context ) {
2492 XDestroyIC(input_context);
2495 if( input_method ) {
2496 XCloseIM(input_method);
2502 int BC_WindowBase::get_color(int64_t color)
2504 // return pixel of color
2505 // use this only for drawing subwindows not for bitmaps
2506 int i, test, difference;
2512 return get_color_rgb8(color);
2513 // test last color looked up
2514 if(current_color_value == color)
2515 return current_color_pixel;
2518 current_color_value = color;
2519 for(i = 0; i < total_colors; i++)
2521 if(color_table[i][0] == color)
2523 current_color_pixel = color_table[i][1];
2524 return current_color_pixel;
2528 // find nearest match
2529 difference = 0xFFFFFF;
2531 for(i = 0; i < total_colors; i++)
2533 test = abs((int)(color_table[i][0] - color));
2535 if(test < difference)
2537 current_color_pixel = color_table[i][1];
2541 return current_color_pixel;
2544 return get_color_rgb16(color);
2547 return get_color_bgr16(color);
2551 return client_byte_order == server_byte_order ?
2552 color : get_color_bgr24(color);
2560 int BC_WindowBase::get_color_rgb8(int color)
2564 pixel = (color & 0xc00000) >> 16;
2565 pixel += (color & 0xe000) >> 10;
2566 pixel += (color & 0xe0) >> 5;
2570 int64_t BC_WindowBase::get_color_rgb16(int color)
2573 result = (color & 0xf80000) >> 8;
2574 result += (color & 0xfc00) >> 5;
2575 result += (color & 0xf8) >> 3;
2580 int64_t BC_WindowBase::get_color_bgr16(int color)
2583 result = (color & 0xf80000) >> 19;
2584 result += (color & 0xfc00) >> 5;
2585 result += (color & 0xf8) << 8;
2590 int64_t BC_WindowBase::get_color_bgr24(int color)
2593 result = (color & 0xff) << 16;
2594 result += (color & 0xff00);
2595 result += (color & 0xff0000) >> 16;
2599 void BC_WindowBase::start_video()
2601 cursor_timer->update();
2603 // set_color(BLACK);
2604 // draw_box(0, 0, get_w(), get_h());
2608 void BC_WindowBase::stop_video()
2616 int64_t BC_WindowBase::get_color()
2618 return top_level->current_color;
2621 void BC_WindowBase::set_color(int64_t color)
2623 top_level->current_color = color;
2624 XSetForeground(top_level->display,
2626 top_level->get_color(color));
2629 void BC_WindowBase::set_opaque()
2631 XSetFunction(top_level->display, top_level->gc, GXcopy);
2634 void BC_WindowBase::set_inverse()
2636 XSetFunction(top_level->display, top_level->gc, GXxor);
2639 void BC_WindowBase::set_line_width(int value)
2641 this->line_width = value;
2642 XSetLineAttributes(top_level->display, top_level->gc, value, /* line_width */
2643 line_dashes == 0 ? LineSolid : LineOnOffDash, /* line_style */
2644 line_dashes == 0 ? CapRound : CapNotLast, /* cap_style */
2645 JoinMiter); /* join_style */
2647 if(line_dashes > 0) {
2648 const char dashes = line_dashes;
2649 XSetDashes(top_level->display, top_level->gc, 0, &dashes, 1);
2652 // XGCValues gcvalues;
2653 // unsigned long gcmask;
2654 // gcmask = GCCapStyle | GCJoinStyle;
2655 // XGetGCValues(top_level->display, top_level->gc, gcmask, &gcvalues);
2656 // printf("BC_WindowBase::set_line_width %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2659 void BC_WindowBase::set_line_dashes(int value)
2661 line_dashes = value;
2662 // call XSetLineAttributes
2663 set_line_width(line_width);
2667 Cursor BC_WindowBase::get_cursor_struct(int cursor)
2671 case ARROW_CURSOR: return top_level->arrow_cursor;
2672 case CROSS_CURSOR: return top_level->cross_cursor;
2673 case IBEAM_CURSOR: return top_level->ibeam_cursor;
2674 case VSEPARATE_CURSOR: return top_level->vseparate_cursor;
2675 case HSEPARATE_CURSOR: return top_level->hseparate_cursor;
2676 case MOVE_CURSOR: return top_level->move_cursor;
2677 case LEFT_CURSOR: return top_level->left_cursor;
2678 case RIGHT_CURSOR: return top_level->right_cursor;
2679 case UPRIGHT_ARROW_CURSOR: return top_level->upright_arrow_cursor;
2680 case UPLEFT_RESIZE: return top_level->upleft_resize_cursor;
2681 case UPRIGHT_RESIZE: return top_level->upright_resize_cursor;
2682 case DOWNLEFT_RESIZE: return top_level->downleft_resize_cursor;
2683 case DOWNRIGHT_RESIZE: return top_level->downright_resize_cursor;
2684 case HOURGLASS_CURSOR: return top_level->hourglass_cursor;
2685 case TRANSPARENT_CURSOR: return top_level->transparent_cursor;
2686 case GRABBED_CURSOR: return top_level->grabbed_cursor;
2691 void BC_WindowBase::set_cursor(int cursor, int override, int flush)
2693 // inherit cursor from parent
2696 XUndefineCursor(top_level->display, win);
2697 current_cursor = cursor;
2700 // don't change cursor if overridden
2701 if((!top_level->is_hourglass && !is_transparent) ||
2704 XDefineCursor(top_level->display, win, get_cursor_struct(cursor));
2705 if(flush) this->flush();
2708 if(!override) current_cursor = cursor;
2711 void BC_WindowBase::set_x_cursor(int cursor)
2713 temp_cursor = XCreateFontCursor(top_level->display, cursor);
2714 XDefineCursor(top_level->display, win, temp_cursor);
2715 current_cursor = cursor;
2719 int BC_WindowBase::get_cursor()
2721 return current_cursor;
2724 void BC_WindowBase::start_hourglass()
2726 top_level->start_hourglass_recursive();
2730 void BC_WindowBase::stop_hourglass()
2732 top_level->stop_hourglass_recursive();
2736 void BC_WindowBase::start_hourglass_recursive()
2738 if(this == top_level)
2746 set_cursor(HOURGLASS_CURSOR, 1, 0);
2747 for(int i = 0; i < subwindows->total; i++)
2749 subwindows->values[i]->start_hourglass_recursive();
2754 void BC_WindowBase::stop_hourglass_recursive()
2756 if(this == top_level)
2758 if(hourglass_total == 0) return;
2759 top_level->hourglass_total--;
2762 if(!top_level->hourglass_total)
2764 top_level->is_hourglass = 0;
2766 // Cause set_cursor to perform change
2768 set_cursor(current_cursor, 1, 0);
2770 for(int i = 0; i < subwindows->total; i++)
2772 subwindows->values[i]->stop_hourglass_recursive();
2780 XFontStruct* BC_WindowBase::get_font_struct(int font)
2782 // Clear out unrelated flags
2783 if(font & BOLDFACE) font ^= BOLDFACE;
2786 case SMALLFONT: return top_level->smallfont; break;
2787 case MEDIUMFONT: return top_level->mediumfont; break;
2788 case LARGEFONT: return top_level->largefont; break;
2789 case BIGFONT: return top_level->bigfont; break;
2790 case CLOCKFONT: return top_level->clockfont; break;
2795 XFontSet BC_WindowBase::get_fontset(int font)
2799 if(get_resources()->use_fontset)
2801 switch(font & 0xff) {
2802 case SMALLFONT: fs = top_level->smallfontset; break;
2803 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2804 case LARGEFONT: fs = top_level->largefontset; break;
2805 case BIGFONT: fs = top_level->bigfontset; break;
2806 case CLOCKFONT: fs = top_level->clockfontset; break;
2814 XftFont* BC_WindowBase::get_xft_struct(int font)
2817 case SMALLFONT: return (XftFont*)top_level->smallfont_xft;
2818 case MEDIUMFONT: return (XftFont*)top_level->mediumfont_xft;
2819 case LARGEFONT: return (XftFont*)top_level->largefont_xft;
2820 case BIGFONT: return (XftFont*)top_level->bigfont_xft;
2821 case CLOCKFONT: return (XftFont*)top_level->clockfont_xft;
2822 case MEDIUMFONT_3D: return (XftFont*)top_level->bold_mediumfont_xft;
2823 case SMALLFONT_3D: return (XftFont*)top_level->bold_smallfont_xft;
2824 case LARGEFONT_3D: return (XftFont*)top_level->bold_largefont_xft;
2832 int BC_WindowBase::get_current_font()
2834 return top_level->current_font;
2837 void BC_WindowBase::set_font(int font)
2839 top_level->current_font = font;
2842 if(get_resources()->use_xft) {}
2845 if(get_resources()->use_fontset) {
2849 if(get_font_struct(font))
2851 XSetFont(top_level->display, top_level->gc, get_font_struct(font)->fid);
2857 void BC_WindowBase::set_fontset(int font)
2861 if(get_resources()->use_fontset) {
2863 case SMALLFONT: fs = top_level->smallfontset; break;
2864 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2865 case LARGEFONT: fs = top_level->largefontset; break;
2866 case BIGFONT: fs = top_level->bigfontset; break;
2867 case CLOCKFONT: fs = top_level->clockfontset; break;
2875 XFontSet BC_WindowBase::get_curr_fontset(void)
2877 if(get_resources()->use_fontset)
2878 return curr_fontset;
2882 int BC_WindowBase::get_single_text_width(int font, const char *text, int length)
2885 if(get_resources()->use_xft && get_xft_struct(font))
2888 #ifdef X_HAVE_UTF8_STRING
2889 if(get_resources()->locale_utf8)
2891 xftTextExtentsUtf8(top_level->display,
2892 get_xft_struct(font),
2893 (const XftChar8 *)text,
2900 xftTextExtents8(top_level->display,
2901 get_xft_struct(font),
2902 (const XftChar8 *)text,
2906 return extents.xOff;
2910 if(get_resources()->use_fontset && top_level->get_fontset(font))
2911 return XmbTextEscapement(top_level->get_fontset(font), text, length);
2913 if(get_font_struct(font))
2914 return XTextWidth(get_font_struct(font), text, length);
2920 case MEDIUM_7SEGMENT:
2921 return get_resources()->medium_7segment[0]->get_w() * length;
2931 int BC_WindowBase::get_text_width(int font, const char *text, int length)
2933 int i, j, w = 0, line_w = 0;
2934 if(length < 0) length = strlen(text);
2936 for(i = 0, j = 0; i <= length; i++)
2941 line_w = get_single_text_width(font, &text[j], i - j);
2947 line_w = get_single_text_width(font, &text[j], length - j);
2949 if(line_w > w) w = line_w;
2952 if(i > length && w == 0)
2954 w = get_single_text_width(font, text, length);
2960 int BC_WindowBase::get_text_width(int font, const wchar_t *text, int length)
2963 if( length < 0 ) length = wcslen(text);
2965 for( i=j=0; i<length && text[i]; ++i ) {
2966 if( text[i] != '\n' ) continue;
2968 int lw = get_single_text_width(font, &text[j], i-j);
2969 if( w < lw ) w = lw;
2974 int lw = get_single_text_width(font, &text[j], length-j);
2975 if( w < lw ) w = lw;
2981 int BC_WindowBase::get_text_ascent(int font)
2985 if( (fstruct = get_xft_struct(font)) != 0 )
2986 return fstruct->ascent;
2988 if(get_resources()->use_fontset && top_level->get_fontset(font))
2990 XFontSetExtents *extents;
2992 extents = XExtentsOfFontSet(top_level->get_fontset(font));
2993 return -extents->max_logical_extent.y;
2996 if(get_font_struct(font))
2997 return top_level->get_font_struct(font)->ascent;
3000 case MEDIUM_7SEGMENT:
3001 return get_resources()->medium_7segment[0]->get_h();
3006 int BC_WindowBase::get_text_descent(int font)
3010 if( (fstruct = get_xft_struct(font)) != 0 )
3011 return fstruct->descent;
3013 if(get_resources()->use_fontset && top_level->get_fontset(font)) {
3014 XFontSetExtents *extents;
3015 extents = XExtentsOfFontSet(top_level->get_fontset(font));
3016 return (extents->max_logical_extent.height
3017 + extents->max_logical_extent.y);
3020 if(get_font_struct(font))
3021 return top_level->get_font_struct(font)->descent;
3026 int BC_WindowBase::get_text_height(int font, const char *text)
3031 if( (fstruct = get_xft_struct(font)) != 0 )
3032 rowh = fstruct->height;
3035 rowh = get_text_ascent(font) + get_text_descent(font);
3037 if(!text) return rowh;
3039 // Add height of lines
3040 int h = 0, i, length = strlen(text);
3041 for(i = 0; i <= length; i++)
3052 BC_Bitmap* BC_WindowBase::new_bitmap(int w, int h, int color_model)
3054 if(color_model < 0) color_model = top_level->get_color_model();
3055 return new BC_Bitmap(top_level, w, h, color_model);
3058 void BC_WindowBase::init_wait()
3060 #ifndef SINGLE_THREAD
3061 if(window_type != MAIN_WINDOW)
3062 top_level->init_wait();
3063 init_lock->lock("BC_WindowBase::init_wait");
3064 init_lock->unlock();
3068 int BC_WindowBase::accel_available(int color_model, int lock_it)
3070 if( window_type != MAIN_WINDOW )
3071 return top_level->accel_available(color_model, lock_it);
3073 lock_window("BC_WindowBase::accel_available");
3075 switch(color_model) {
3077 grab_port_id(color_model);
3081 grab_port_id(color_model);
3090 //printf("BC_WindowBase::accel_available %d %d\n", color_model, xvideo_port_id);
3091 return xvideo_port_id >= 0 ? 1 : 0;
3095 int BC_WindowBase::grab_port_id(int color_model)
3097 if( !get_resources()->use_xvideo || // disabled
3098 !get_resources()->use_shm ) // Only local server is fast enough.
3100 if( xvideo_port_id >= 0 )
3101 return xvideo_port_id;
3103 unsigned int ver, rev, reqBase, eventBase, errorBase;
3104 if( Success != XvQueryExtension(display, // XV extension is available
3105 &ver, &rev, &reqBase, &eventBase, &errorBase) )
3108 // XV adaptors are available
3109 unsigned int numAdapt = 0;
3110 XvAdaptorInfo *info = 0;
3111 XvQueryAdaptors(display, DefaultRootWindow(display), &numAdapt, &info);
3115 // Translate from color_model to X color model
3116 int x_color_model = BC_CModels::bc_to_x(color_model);
3118 // Get adaptor with desired color model
3119 for( int i = 0; i < (int)numAdapt && xvideo_port_id == -1; i++) {
3120 if( !(info[i].type & XvImageMask) || !info[i].num_ports ) continue;
3121 // adaptor supports XvImages
3122 int numFormats = 0, numPorts = info[i].num_ports;
3123 XvImageFormatValues *formats =
3124 XvListImageFormats(display, info[i].base_id, &numFormats);
3125 if( !formats ) continue;
3127 for( int j=0; j<numFormats && xvideo_port_id<0; ++j ) {
3128 if( formats[j].id != x_color_model ) continue;
3129 // this adaptor supports the desired format, grab a port
3130 for( int k=0; k<numPorts; ++k ) {
3131 if( Success == XvGrabPort(top_level->display,
3132 info[i].base_id+k, CurrentTime) ) {
3133 //printf("BC_WindowBase::grab_port_id %llx\n", info[i].base_id);
3134 xvideo_port_id = info[i].base_id + k;
3142 XvFreeAdaptorInfo(info);
3144 return xvideo_port_id;
3148 int BC_WindowBase::show_window(int flush)
3150 for(int i = 0; i < subwindows->size(); i++)
3152 subwindows->get(i)->show_window(0);
3155 XMapWindow(top_level->display, win);
3156 if(flush) XFlush(top_level->display);
3157 // XSync(top_level->display, 0);
3162 int BC_WindowBase::hide_window(int flush)
3164 for(int i = 0; i < subwindows->size(); i++)
3166 subwindows->get(i)->hide_window(0);
3169 XUnmapWindow(top_level->display, win);
3170 if(flush) this->flush();
3175 BC_MenuBar* BC_WindowBase::add_menubar(BC_MenuBar *menu_bar)
3177 subwindows->append((BC_SubWindow*)menu_bar);
3179 menu_bar->parent_window = this;
3180 menu_bar->top_level = this->top_level;
3181 menu_bar->initialize();
3185 BC_WindowBase* BC_WindowBase::add_popup(BC_WindowBase *window)
3187 //printf("BC_WindowBase::add_popup window=%p win=%p\n", window, window->win);
3188 if(this != top_level) return top_level->add_popup(window);
3189 popups.append(window);
3193 void BC_WindowBase::remove_popup(BC_WindowBase *window)
3195 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3196 if(this != top_level)
3197 top_level->remove_popup(window);
3199 popups.remove(window);
3200 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3204 BC_WindowBase* BC_WindowBase::add_subwindow(BC_WindowBase *subwindow)
3206 subwindows->append(subwindow);
3208 if(subwindow->bg_color == -1) subwindow->bg_color = this->bg_color;
3210 // parent window must be set before the subwindow initialization
3211 subwindow->parent_window = this;
3212 subwindow->top_level = this->top_level;
3214 // Execute derived initialization
3215 subwindow->initialize();
3220 BC_WindowBase* BC_WindowBase::add_tool(BC_WindowBase *subwindow)
3222 return add_subwindow(subwindow);
3225 int BC_WindowBase::flash(int x, int y, int w, int h, int flush)
3227 if( !top_level->flash_enabled ) return 0;
3228 //printf("BC_WindowBase::flash %d %d %d %d %d\n", __LINE__, w, h, this->w, this->h);
3230 XSetWindowBackgroundPixmap(top_level->display, win, pixmap->opaque_pixmap);
3233 XClearArea(top_level->display, win, x, y, w, h, 0);
3237 XClearWindow(top_level->display, win);
3245 int BC_WindowBase::flash(int flush)
3247 flash(-1, -1, -1, -1, flush);
3251 void BC_WindowBase::flush()
3253 //if(!get_window_lock())
3254 // printf("BC_WindowBase::flush %s not locked\n", top_level->title);
3255 // X gets hosed if Flush/Sync are not user locked (at libX11-1.1.5 / libxcb-1.1.91)
3256 // _XReply deadlocks in condition_wait waiting for xlib lock when waiters!=-1
3257 int locked = get_window_lock();
3258 if( !locked ) lock_window("BC_WindowBase::flush");
3259 XFlush(top_level->display);
3260 if( !locked ) unlock_window();
3263 void BC_WindowBase::sync_display()
3265 int locked = get_window_lock();
3266 if( !locked ) lock_window("BC_WindowBase::sync_display");
3267 XSync(top_level->display, False);
3268 if( !locked ) unlock_window();
3271 int BC_WindowBase::get_window_lock()
3273 #ifdef SINGLE_THREAD
3274 return BC_Display::display_global->get_display_locked();
3276 return top_level->window_lock;
3280 int BC_WindowBase::lock_window(const char *location)
3282 if(top_level && top_level != this)
3284 top_level->lock_window(location);
3289 SET_LOCK(this, title, location);
3290 #ifdef SINGLE_THREAD
3291 BC_Display::lock_display(location);
3293 XLockDisplay(top_level->display);
3294 top_level->display_lock_owner = pthread_self();
3297 ++top_level->window_lock;
3301 printf("BC_WindowBase::lock_window top_level NULL\n");
3306 int BC_WindowBase::unlock_window()
3308 if(top_level && top_level != this)
3310 top_level->unlock_window();
3316 if( !top_level->window_lock ) {
3317 printf("BC_WindowBase::unlock_window %s not locked\n", title);
3320 if( top_level->window_lock > 0 )
3321 if( --top_level->window_lock == 0 )
3322 top_level->display_lock_owner = 0;
3323 #ifdef SINGLE_THREAD
3324 BC_Display::unlock_display();
3326 XUnlockDisplay(top_level->display);
3331 printf("BC_WindowBase::unlock_window top_level NULL\n");
3336 int BC_WindowBase::break_lock()
3338 if( !top_level ) return 0;
3339 if( top_level != this ) return top_level->break_lock();
3340 if( top_level->display_lock_owner != pthread_self() ) return 0;
3341 if( top_level->window_lock != 1 ) return 0;
3344 display_lock_owner = 0;
3345 #ifdef SINGLE_THREAD
3346 BC_Display::unlock_display();
3348 XUnlockDisplay(display);
3353 void BC_WindowBase::set_done(int return_value)
3355 if(done_set) return;
3357 if(window_type != MAIN_WINDOW)
3358 top_level->set_done(return_value);
3361 #ifdef SINGLE_THREAD
3362 this->return_value = return_value;
3363 BC_Display::display_global->arm_completion(this);
3364 completion_lock->unlock();
3365 #else // SINGLE_THREAD
3367 if( !event_thread ) return;
3368 XEvent *event = new_xevent();
3369 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
3370 event->type = ClientMessage;
3371 ptr->message_type = SetDoneXAtom;
3373 this->return_value = return_value;
3374 // May lock up here because XSendEvent doesn't work too well
3375 // asynchronous with XNextEvent.
3376 // This causes BC_WindowEvents to forward a copy of the event to run_window where
3378 // Deletion of event_thread is done at the end of BC_WindowBase::run_window() - by calling the destructor
3384 void BC_WindowBase::close(int return_value)
3386 hide_window(); flush();
3387 set_done(return_value);
3390 int BC_WindowBase::grab(BC_WindowBase *window)
3392 if( window->active_grab && this != window->active_grab ) return 0;
3393 window->active_grab = this;
3394 this->grab_active = window;
3397 int BC_WindowBase::ungrab(BC_WindowBase *window)
3399 if( window->active_grab && this != window->active_grab ) return 0;
3400 window->active_grab = 0;
3401 this->grab_active = 0;
3404 int BC_WindowBase::grab_event_count()
3407 #ifndef SINGLE_THREAD
3408 result = grab_active->get_event_count();
3412 int BC_WindowBase::grab_buttons()
3414 XSync(top_level->display, False);
3415 if( XGrabButton(top_level->display, AnyButton, AnyModifier,
3416 top_level->rootwin, True, ButtonPressMask | ButtonReleaseMask,
3417 GrabModeAsync, GrabModeSync, None, None) == GrabSuccess ) {
3418 set_active_subwindow(this);
3423 void BC_WindowBase::ungrab_buttons()
3425 XUngrabButton(top_level->display, AnyButton, AnyModifier, top_level->rootwin);
3426 set_active_subwindow(0);
3429 void BC_WindowBase::grab_cursor()
3431 Cursor cursor_grab = get_cursor_struct(GRABBED_CURSOR);
3432 XGrabPointer(top_level->display, top_level->rootwin, True,
3433 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
3434 GrabModeAsync, GrabModeAsync, None, cursor_grab, CurrentTime);
3436 void BC_WindowBase::ungrab_cursor()
3438 XUngrabPointer(top_level->display, CurrentTime);
3442 // WidthOfScreen/HeightOfScreen of XDefaultScreenOfDisplay
3443 // this is the bounding box of all the screens
3445 int BC_WindowBase::get_root_w(int lock_display)
3447 if(lock_display) lock_window("BC_WindowBase::get_root_w");
3448 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3449 int result = WidthOfScreen(def_screen);
3450 if(lock_display) unlock_window();
3454 int BC_WindowBase::get_root_h(int lock_display)
3456 if(lock_display) lock_window("BC_WindowBase::get_root_h");
3457 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3458 int result = HeightOfScreen(def_screen);
3459 if(lock_display) unlock_window();
3463 XineramaScreenInfo *
3464 BC_WindowBase::get_xinerama_info(int screen)
3466 if( !xinerama_info || !xinerama_screens ) return 0;
3468 for( int i=0; i<xinerama_screens; ++i )
3469 if( xinerama_info[i].screen_number == screen )
3470 return &xinerama_info[i];
3473 int top_x = get_x(), top_y = get_y();
3474 if( BC_DisplayInfo::left_border >= 0 ) top_x += BC_DisplayInfo::left_border;
3475 if( BC_DisplayInfo::top_border >= 0 ) top_y += BC_DisplayInfo::top_border;
3476 for( int i=0; i<xinerama_screens; ++i ) {
3477 int scr_y = top_y - xinerama_info[i].y_org;
3478 if( scr_y < 0 || scr_y >= xinerama_info[i].height ) continue;
3479 int scr_x = top_x - xinerama_info[i].x_org;
3480 if( scr_x >= 0 && scr_x < xinerama_info[i].width )
3481 return &xinerama_info[i];
3486 void BC_WindowBase::get_fullscreen_geometry(int &wx, int &wy, int &ww, int &wh)
3488 XineramaScreenInfo *info = top_level->get_xinerama_info(-1);
3490 wx = info->x_org; wy = info->y_org;
3491 ww = info->width; wh = info->height;
3494 wx = get_screen_x(0, -1);
3495 wy = get_screen_y(0, -1);
3496 int scr_w0 = get_screen_w(0, 0);
3497 int root_w = get_root_w(0);
3498 int root_h = get_root_h(0);
3499 if( root_w > scr_w0 ) { // multi-headed
3500 if( wx >= scr_w0 ) {
3501 // assumes right side is the big one
3502 ww = root_w - scr_w0;
3506 // use same aspect ratio to compute left height
3508 wh = (w*root_h) / (root_w-scr_w0);
3518 int BC_WindowBase::get_screen_x(int lock_display, int screen)
3521 if(lock_display) lock_window("BC_WindowBase::get_screen_x");
3522 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3525 int root_w = get_root_w(0);
3526 int root_h = get_root_h(0);
3527 // Shift X based on position of current window if dual head
3528 if( (float)root_w/root_h > 1.8 ) {
3529 root_w = get_screen_w(0, 0);
3530 if( top_level->get_x() >= root_w )
3535 result = info->x_org;
3536 if(lock_display) unlock_window();
3540 int BC_WindowBase::get_screen_y(int lock_display, int screen)
3542 if(lock_display) lock_window("BC_WindowBase::get_screen_y");
3543 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3544 int result = !info ? 0 : info->y_org;
3545 if(lock_display) unlock_window();
3549 int BC_WindowBase::get_screen_w(int lock_display, int screen)
3552 if(lock_display) lock_window("BC_WindowBase::get_screen_w");
3553 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3555 int width = get_root_w(0);
3556 int height = get_root_h(0);
3557 if( (float)width/height > 1.8 ) {
3558 // If dual head, the screen width is > 16x9
3559 // but we only want to fill one screen
3560 // this code assumes the "big" screen is on the right
3561 int scr_w0 = width / 2;
3563 case 600: scr_w0 = 800; break;
3564 case 720: scr_w0 = 1280; break;
3565 case 1024: scr_w0 = 1280; break;
3566 case 1200: scr_w0 = 1600; break;
3567 case 1080: scr_w0 = 1920; break;
3569 int scr_w1 = width - scr_w0;
3570 result = screen > 0 ? scr_w1 :
3571 screen == 0 ? scr_w0 :
3572 top_level->get_x() < scr_w0 ? scr_w0 : scr_w1;
3578 result = info->width;
3579 if(lock_display) unlock_window();
3583 int BC_WindowBase::get_screen_h(int lock_display, int screen)
3585 if(lock_display) lock_window("BC_WindowBase::get_screen_h");
3586 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3587 int result = info ? info->height : get_root_h(0);
3588 if(lock_display) unlock_window();
3592 // Bottom right corner
3593 int BC_WindowBase::get_x2()
3598 int BC_WindowBase::get_y2()
3603 int BC_WindowBase::get_video_on()
3608 int BC_WindowBase::get_hidden()
3610 return top_level->hidden;
3613 int BC_WindowBase::cursor_inside()
3615 return (top_level->cursor_x >= 0 &&
3616 top_level->cursor_y >= 0 &&
3617 top_level->cursor_x < w &&
3618 top_level->cursor_y < h);
3621 BC_WindowBase* BC_WindowBase::get_top_level()
3626 BC_WindowBase* BC_WindowBase::get_parent()
3628 return parent_window;
3631 int BC_WindowBase::get_color_model()
3633 return top_level->color_model;
3636 BC_Resources* BC_WindowBase::get_resources()
3638 return &BC_WindowBase::resources;
3641 BC_Synchronous* BC_WindowBase::get_synchronous()
3643 return BC_WindowBase::resources.get_synchronous();
3646 int BC_WindowBase::get_bg_color()
3651 void BC_WindowBase::set_bg_color(int color)
3653 this->bg_color = color;
3656 BC_Pixmap* BC_WindowBase::get_bg_pixmap()
3661 void BC_WindowBase::set_active_subwindow(BC_WindowBase *subwindow)
3663 top_level->active_subwindow = subwindow;
3666 int BC_WindowBase::activate()
3671 int BC_WindowBase::deactivate()
3673 if(window_type == MAIN_WINDOW)
3675 if( top_level->active_menubar ) {
3676 top_level->active_menubar->deactivate();
3677 top_level->active_menubar = 0;
3679 if( top_level->active_popup_menu ) {
3680 top_level->active_popup_menu->deactivate();
3681 top_level->active_popup_menu = 0;
3683 if( top_level->active_subwindow ) {
3684 top_level->active_subwindow->deactivate();
3685 top_level->active_subwindow = 0;
3687 if( top_level->motion_events && top_level->last_motion_win == this->win )
3688 top_level->motion_events = 0;
3694 int BC_WindowBase::cycle_textboxes(int amount)
3697 BC_WindowBase *new_textbox = 0;
3701 BC_WindowBase *first_textbox = 0;
3702 find_next_textbox(&first_textbox, &new_textbox, result);
3703 if(!new_textbox) new_textbox = first_textbox;
3709 BC_WindowBase *last_textbox = 0;
3710 find_prev_textbox(&last_textbox, &new_textbox, result);
3711 if(!new_textbox) new_textbox = last_textbox;
3715 if(new_textbox != active_subwindow)
3718 new_textbox->activate();
3724 int BC_WindowBase::find_next_textbox(BC_WindowBase **first_textbox, BC_WindowBase **next_textbox, int &result)
3726 // Search subwindows for textbox
3727 for(int i = 0; i < subwindows->total && result < 2; i++)
3729 BC_WindowBase *test_subwindow = subwindows->values[i];
3730 test_subwindow->find_next_textbox(first_textbox, next_textbox, result);
3737 if(!*first_textbox) *first_textbox = this;
3741 if(top_level->active_subwindow == this)
3747 *next_textbox = this;
3754 int BC_WindowBase::find_prev_textbox(BC_WindowBase **last_textbox, BC_WindowBase **prev_textbox, int &result)
3760 if(!*last_textbox) *last_textbox = this;
3764 if(top_level->active_subwindow == this)
3770 *prev_textbox = this;
3775 // Search subwindows for textbox
3776 for(int i = subwindows->total - 1; i >= 0 && result < 2; i--)
3778 BC_WindowBase *test_subwindow = subwindows->values[i];
3779 test_subwindow->find_prev_textbox(last_textbox, prev_textbox, result);
3784 BC_Clipboard* BC_WindowBase::get_clipboard()
3786 #ifdef SINGLE_THREAD
3787 return BC_Display::display_global->clipboard;
3789 return top_level->clipboard;
3793 Atom BC_WindowBase::to_clipboard(const char *data, long len, int clipboard_num)
3795 return get_clipboard()->to_clipboard(this, data, len, clipboard_num);
3798 long BC_WindowBase::from_clipboard(char *data, long maxlen, int clipboard_num)
3800 return get_clipboard()->from_clipboard(data, maxlen, clipboard_num);
3803 long BC_WindowBase::clipboard_len(int clipboard_num)
3805 return get_clipboard()->clipboard_len(clipboard_num);
3808 int BC_WindowBase::do_selection_clear(Window win)
3810 top_level->event_win = win;
3811 return dispatch_selection_clear();
3814 int BC_WindowBase::dispatch_selection_clear()
3817 for( int i=0; i<subwindows->total && !result; ++i )
3818 result = subwindows->values[i]->dispatch_selection_clear();
3820 result = selection_clear_event();
3825 void BC_WindowBase::get_relative_cursor(int &x, int &y, int lock_window)
3827 int abs_x, abs_y, win_x, win_y;
3828 unsigned int temp_mask;
3831 if(lock_window) this->lock_window("BC_WindowBase::get_relative_cursor");
3832 XQueryPointer(top_level->display, top_level->win,
3833 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3836 XTranslateCoordinates(top_level->display, top_level->rootwin,
3837 win, abs_x, abs_y, &x, &y, &temp_win);
3838 if(lock_window) this->unlock_window();
3840 int BC_WindowBase::get_relative_cursor_x(int lock_window)
3843 get_relative_cursor(x, y, lock_window);
3846 int BC_WindowBase::get_relative_cursor_y(int lock_window)
3849 get_relative_cursor(x, y, lock_window);
3853 void BC_WindowBase::get_abs_cursor(int &abs_x, int &abs_y, int lock_window)
3856 unsigned int temp_mask;
3859 if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor");
3860 XQueryPointer(top_level->display, top_level->win,
3861 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3863 if(lock_window) this->unlock_window();
3865 int BC_WindowBase::get_abs_cursor_x(int lock_window)
3868 get_abs_cursor(abs_x, abs_y, lock_window);
3871 int BC_WindowBase::get_abs_cursor_y(int lock_window)
3874 get_abs_cursor(abs_x, abs_y, lock_window);
3878 void BC_WindowBase::get_pop_cursor(int &px, int &py, int lock_window)
3881 get_abs_cursor(px, py, lock_window);
3882 if( px < margin ) px = margin;
3883 if( py < margin ) py = margin;
3884 int wd = get_screen_w(lock_window,-1) - margin;
3885 if( px > wd ) px = wd;
3886 int ht = get_screen_h(lock_window,-1) - margin;
3887 if( py > ht ) py = ht;
3889 int BC_WindowBase::get_pop_cursor_x(int lock_window)
3892 get_pop_cursor(px, py, lock_window);
3895 int BC_WindowBase::get_pop_cursor_y(int lock_window)
3898 get_pop_cursor(px, py, lock_window);
3902 int BC_WindowBase::match_window(Window win)
3904 if (this->win == win) return 1;
3906 for(int i = 0; i < subwindows->total; i++) {
3907 result = subwindows->values[i]->match_window(win);
3908 if (result) return result;
3914 int BC_WindowBase::get_cursor_over_window()
3916 int abs_x, abs_y, win_x, win_y;
3917 unsigned int mask_return;
3918 Window root_return, child_return;
3920 int ret = XQueryPointer(top_level->display, top_level->rootwin,
3921 &root_return, &child_return, &abs_x, &abs_y,
3922 &win_x, &win_y, &mask_return);
3923 if( ret && child_return == None ) ret = 0;
3924 if( ret && win != child_return )
3925 ret = top_level->match_window(child_return);
3926 // query pointer can return a window manager window with this top_level as a child
3927 // for kde this can be two levels deep
3928 unsigned int nchildren_return = 0;
3929 Window parent_return, *children_return = 0;
3930 Window top_win = top_level->win;
3931 while( !ret && top_win != top_level->rootwin && top_win != root_return &&
3932 XQueryTree(top_level->display, top_win, &root_return,
3933 &parent_return, &children_return, &nchildren_return) ) {
3934 if( children_return ) XFree(children_return);
3935 if( (top_win=parent_return) == child_return ) ret = 1;
3940 int BC_WindowBase::cursor_above()
3943 get_relative_cursor(rx, ry);
3944 return rx < 0 || rx >= get_w() ||
3945 ry < 0 || ry >= get_h() ? 0 : 1;
3948 int BC_WindowBase::get_drag_x()
3950 return top_level->drag_x;
3953 int BC_WindowBase::get_drag_y()
3955 return top_level->drag_y;
3958 int BC_WindowBase::get_cursor_x()
3960 return top_level->cursor_x;
3963 int BC_WindowBase::get_cursor_y()
3965 return top_level->cursor_y;
3968 int BC_WindowBase::dump_windows()
3970 printf("\tBC_WindowBase::dump_windows window=%p win=%p '%s', %dx%d+%d+%d %s\n",
3971 this, (void*)this->win, title, w,h,x,y, typeid(*this).name());
3972 for(int i = 0; i < subwindows->size(); i++)
3973 subwindows->get(i)->dump_windows();
3974 for(int i = 0; i < popups.size(); i++) {
3975 BC_WindowBase *p = popups[i];
3976 printf("\tBC_WindowBase::dump_windows popup=%p win=%p '%s', %dx%d+%d+%d %s\n",
3977 p, (void*)p->win, p->title, p->w,p->h,p->x,p->y, typeid(*p).name());
3982 int BC_WindowBase::is_event_win()
3984 return this->win == top_level->event_win;
3987 void BC_WindowBase::set_dragging(int value)
3989 is_dragging = value;
3992 int BC_WindowBase::get_dragging()
3997 int BC_WindowBase::get_buttonpress()
3999 return top_level->button_number;
4002 int BC_WindowBase::get_button_down()
4004 return top_level->button_down;
4007 int BC_WindowBase::alt_down()
4009 return top_level->alt_mask;
4012 int BC_WindowBase::shift_down()
4014 return top_level->shift_mask;
4017 int BC_WindowBase::ctrl_down()
4019 return top_level->ctrl_mask;
4022 wchar_t* BC_WindowBase::get_wkeystring(int *length)
4025 *length = top_level->wkey_string_length;
4026 return top_level->wkey_string;
4029 #ifdef X_HAVE_UTF8_STRING
4030 char* BC_WindowBase::get_keypress_utf8()
4032 return top_level->key_pressed_utf8;
4037 int BC_WindowBase::get_keypress()
4039 return top_level->key_pressed;
4042 int BC_WindowBase::get_double_click()
4044 return top_level->double_click;
4047 int BC_WindowBase::get_triple_click()
4049 return top_level->triple_click;
4052 int BC_WindowBase::get_bgcolor()
4057 int BC_WindowBase::resize_window(int w, int h)
4059 if(this->w == w && this->h == h) return 0;
4061 if(window_type == MAIN_WINDOW && !allow_resize)
4063 XSizeHints size_hints;
4064 size_hints.flags = PSize | PMinSize | PMaxSize;
4065 size_hints.width = w;
4066 size_hints.height = h;
4067 size_hints.min_width = w;
4068 size_hints.max_width = w;
4069 size_hints.min_height = h;
4070 size_hints.max_height = h;
4071 XSetNormalHints(top_level->display, win, &size_hints);
4073 XResizeWindow(top_level->display, win, w, h);
4078 pixmap = new BC_Pixmap(this, w, h);
4080 // Propagate to menubar
4081 for(int i = 0; i < subwindows->total; i++)
4083 subwindows->values[i]->dispatch_resize_event(w, h);
4086 draw_background(0, 0, w, h);
4087 if(top_level == this && get_resources()->recursive_resizing)
4088 resize_history.append(new BC_ResizeCall(w, h));
4092 // The only way for resize events to be propagated is by updating the internal w and h
4093 int BC_WindowBase::resize_event(int w, int h)
4095 if(window_type == MAIN_WINDOW)
4103 int BC_WindowBase::reposition_window(int x, int y)
4105 reposition_window(x, y, -1, -1);
4110 int BC_WindowBase::reposition_window(int x, int y, int w, int h)
4114 // Some tools set their own dimensions before calling this, causing the
4115 // resize check to skip.
4119 if(w > 0 && w != this->w)
4125 if(h > 0 && h != this->h)
4131 //printf("BC_WindowBase::reposition_window %d %d %d\n", translation_count, x_correction, y_correction);
4134 printf("BC_WindowBase::reposition_window this->w == %d\n", this->w);
4136 printf("BC_WindowBase::reposition_window this->h == %d\n", this->h);
4138 if(translation_count && window_type == MAIN_WINDOW)
4140 // KDE shifts window right and down.
4141 // FVWM leaves window alone and adds border around it.
4142 XMoveResizeWindow(top_level->display,
4144 x - BC_DisplayInfo::auto_reposition_x,
4145 y - BC_DisplayInfo::auto_reposition_y,
4151 XMoveResizeWindow(top_level->display,
4162 pixmap = new BC_Pixmap(this, this->w, this->h);
4163 clear_box(0,0, this->w, this->h);
4164 // Propagate to menubar
4165 for(int i = 0; i < subwindows->total; i++)
4167 subwindows->values[i]->dispatch_resize_event(this->w, this->h);
4170 // draw_background(0, 0, w, h);
4176 int BC_WindowBase::reposition_window_relative(int dx, int dy, int w, int h)
4178 return reposition_window(get_x()+dx, get_y()+dy, w, h);
4181 int BC_WindowBase::reposition_window_relative(int dx, int dy)
4183 return reposition_window_relative(dx, dy, -1, -1);
4186 void BC_WindowBase::set_tooltips(int v)
4188 get_resources()->tooltips_enabled = v;
4191 void BC_WindowBase::set_force_tooltip(int v)
4196 int BC_WindowBase::raise_window(int do_flush)
4198 XRaiseWindow(top_level->display, win);
4199 if(do_flush) XFlush(top_level->display);
4203 int BC_WindowBase::lower_window(int do_flush)
4205 XLowerWindow(top_level->display, win);
4206 if(do_flush) XFlush(top_level->display);
4210 void BC_WindowBase::set_background(VFrame *bitmap)
4212 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
4214 bg_pixmap = new BC_Pixmap(this, bitmap, PIXMAP_OPAQUE);
4215 shared_bg_pixmap = 0;
4216 draw_background(0, 0, w, h);
4219 void BC_WindowBase::put_title(const char *text)
4221 char *cp = this->title, *ep = cp+sizeof(this->title)-1;
4222 for( const unsigned char *bp = (const unsigned char *)text; *bp && cp<ep; ++bp )
4223 *cp++ = *bp >= ' ' ? *bp : ' ';
4227 void BC_WindowBase::set_title(const char *text, int utf8)
4229 // utf8>0: wm + net_wm, utf8=0: wm only, utf<0: net_wm only
4231 const unsigned char *wm_title = (const unsigned char *)title;
4232 int title_len = strlen((const char *)title);
4234 Atom xa_wm_name = XA_WM_NAME;
4235 Atom xa_icon_name = XA_WM_ICON_NAME;
4236 Atom xa_string = XA_STRING;
4237 XChangeProperty(display, win, xa_wm_name, xa_string, 8,
4238 PropModeReplace, wm_title, title_len);
4239 XChangeProperty(display, win, xa_icon_name, xa_string, 8,
4240 PropModeReplace, wm_title, title_len);
4243 Atom xa_net_wm_name = XInternAtom(display, "_NET_WM_NAME", True);
4244 Atom xa_net_icon_name = XInternAtom(display, "_NET_WM_ICON_NAME", True);
4245 Atom xa_utf8_string = XInternAtom(display, "UTF8_STRING", True);
4246 XChangeProperty(display, win, xa_net_wm_name, xa_utf8_string, 8,
4247 PropModeReplace, wm_title, title_len);
4248 XChangeProperty(display, win, xa_net_icon_name, xa_utf8_string, 8,
4249 PropModeReplace, wm_title, title_len);
4254 const char *BC_WindowBase::get_title()
4259 int BC_WindowBase::get_toggle_value()
4261 return toggle_value;
4264 int BC_WindowBase::get_toggle_drag()
4269 int BC_WindowBase::set_icon(VFrame *data)
4271 if(icon_pixmap) delete icon_pixmap;
4272 icon_pixmap = new BC_Pixmap(top_level, data, PIXMAP_ALPHA, 1);
4274 if(icon_window) delete icon_window;
4275 icon_window = new BC_Popup(this,
4278 icon_pixmap->get_w(),
4279 icon_pixmap->get_h(),
4281 1, // All windows are hidden initially
4285 wm_hints.flags = WindowGroupHint | IconPixmapHint | IconMaskHint | IconWindowHint;
4286 wm_hints.icon_pixmap = icon_pixmap->get_pixmap();
4287 wm_hints.icon_mask = icon_pixmap->get_alpha();
4288 wm_hints.icon_window = icon_window->win;
4289 wm_hints.window_group = XGroupLeader;
4291 // for(int i = 0; i < 1000; i++)
4292 // printf("02x ", icon_pixmap->get_alpha()->get_row_pointers()[0][i]);
4295 XSetWMHints(top_level->display, top_level->win, &wm_hints);
4296 XSync(top_level->display, 0);
4300 int BC_WindowBase::set_w(int w)
4306 int BC_WindowBase::set_h(int h)
4312 int BC_WindowBase::load_defaults(BC_Hash *defaults)
4314 BC_Resources *resources = get_resources();
4315 char string[BCTEXTLEN];
4316 int newest_id = - 1;
4317 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4319 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4320 resources->filebox_history[i].path[0] = 0;
4321 defaults->get(string, resources->filebox_history[i].path);
4322 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4323 resources->filebox_history[i].id = defaults->get(string, resources->get_id());
4324 if(resources->filebox_history[i].id > newest_id)
4325 newest_id = resources->filebox_history[i].id;
4328 resources->filebox_id = newest_id + 1;
4329 resources->filebox_mode = defaults->get("FILEBOX_MODE", get_resources()->filebox_mode);
4330 resources->filebox_w = defaults->get("FILEBOX_W", get_resources()->filebox_w);
4331 resources->filebox_h = defaults->get("FILEBOX_H", get_resources()->filebox_h);
4332 resources->filebox_columntype[0] = defaults->get("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4333 resources->filebox_columntype[1] = defaults->get("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4334 resources->filebox_columntype[2] = defaults->get("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4335 resources->filebox_columntype[3] = defaults->get("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4336 resources->filebox_columnwidth[0] = defaults->get("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4337 resources->filebox_columnwidth[1] = defaults->get("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4338 resources->filebox_columnwidth[2] = defaults->get("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4339 resources->filebox_columnwidth[3] = defaults->get("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4340 resources->filebox_size_format = defaults->get("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4341 defaults->get("FILEBOX_FILTER", resources->filebox_filter);
4345 int BC_WindowBase::save_defaults(BC_Hash *defaults)
4347 BC_Resources *resources = get_resources();
4348 char string[BCTEXTLEN];
4349 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4351 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4352 defaults->update(string, resources->filebox_history[i].path);
4353 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4354 defaults->update(string, resources->filebox_history[i].id);
4356 defaults->update("FILEBOX_MODE", resources->filebox_mode);
4357 defaults->update("FILEBOX_W", resources->filebox_w);
4358 defaults->update("FILEBOX_H", resources->filebox_h);
4359 defaults->update("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4360 defaults->update("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4361 defaults->update("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4362 defaults->update("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4363 defaults->update("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4364 defaults->update("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4365 defaults->update("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4366 defaults->update("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4367 defaults->update("FILEBOX_FILTER", resources->filebox_filter);
4368 defaults->update("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4374 // For some reason XTranslateCoordinates can take a long time to return.
4375 // We work around this by only calling it when the event windows are different.
4376 void BC_WindowBase::translate_coordinates(Window src_w,
4388 *dest_x_return = src_x;
4389 *dest_y_return = src_y;
4393 XTranslateCoordinates(top_level->display,
4401 //printf("BC_WindowBase::translate_coordinates 1 %lld\n", timer.get_difference());
4405 void BC_WindowBase::get_root_coordinates(int x, int y, int *abs_x, int *abs_y)
4407 translate_coordinates(win, top_level->rootwin, x, y, abs_x, abs_y);
4410 void BC_WindowBase::get_win_coordinates(int abs_x, int abs_y, int *x, int *y)
4412 translate_coordinates(top_level->rootwin, win, abs_x, abs_y, x, y);
4420 #ifdef HAVE_LIBXXF86VM
4421 void BC_WindowBase::closest_vm(int *vm, int *width, int *height)
4425 if(XF86VidModeQueryExtension(top_level->display,&foo,&bar)) {
4427 XF86VidModeModeInfo **vm_modelines;
4428 XF86VidModeGetAllModeLines(top_level->display,
4429 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4430 for( i = 0; i < vm_count; i++ ) {
4431 if( vm_modelines[i]->hdisplay < vm_modelines[*vm]->hdisplay &&
4432 vm_modelines[i]->hdisplay >= *width )
4435 display = top_level->display;
4436 if( vm_modelines[*vm]->hdisplay == *width )
4439 *width = vm_modelines[*vm]->hdisplay;
4440 *height = vm_modelines[*vm]->vdisplay;
4445 void BC_WindowBase::scale_vm(int vm)
4447 int foo,bar,dotclock;
4448 if( XF86VidModeQueryExtension(top_level->display,&foo,&bar) ) {
4450 XF86VidModeModeInfo **vm_modelines;
4451 XF86VidModeModeLine vml;
4452 XF86VidModeGetAllModeLines(top_level->display,
4453 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4454 XF86VidModeGetModeLine(top_level->display,
4455 XDefaultScreen(top_level->display), &dotclock,&vml);
4456 orig_modeline.dotclock = dotclock;
4457 orig_modeline.hdisplay = vml.hdisplay;
4458 orig_modeline.hsyncstart = vml.hsyncstart;
4459 orig_modeline.hsyncend = vml.hsyncend;
4460 orig_modeline.htotal = vml.htotal;
4461 orig_modeline.vdisplay = vml.vdisplay;
4462 orig_modeline.vsyncstart = vml.vsyncstart;
4463 orig_modeline.vsyncend = vml.vsyncend;
4464 orig_modeline.vtotal = vml.vtotal;
4465 orig_modeline.flags = vml.flags;
4466 orig_modeline.privsize = vml.privsize;
4467 // orig_modeline.private = vml.private;
4468 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),vm_modelines[vm]);
4469 XF86VidModeSetViewPort(top_level->display,XDefaultScreen(top_level->display),0,0);
4470 XFlush(top_level->display);
4474 void BC_WindowBase::restore_vm()
4476 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),&orig_modeline);
4477 XFlush(top_level->display);
4482 #ifndef SINGLE_THREAD
4483 int BC_WindowBase::get_event_count()
4485 event_lock->lock("BC_WindowBase::get_event_count");
4486 int result = common_events.total;
4487 event_lock->unlock();
4491 XEvent* BC_WindowBase::get_event()
4494 while(!done && !result)
4496 event_condition->lock("BC_WindowBase::get_event");
4497 event_lock->lock("BC_WindowBase::get_event");
4499 if(common_events.total && !done)
4501 result = common_events.values[0];
4502 common_events.remove_number(0);
4505 event_lock->unlock();
4510 void BC_WindowBase::put_event(XEvent *event)
4512 event_lock->lock("BC_WindowBase::put_event");
4513 common_events.append(event);
4514 event_lock->unlock();
4515 event_condition->unlock();
4518 void BC_WindowBase::dequeue_events(Window win)
4520 event_lock->lock("BC_WindowBase::dequeue_events");
4522 int out = 0, total = common_events.size();
4523 for( int in=0; in<total; ++in ) {
4524 if( common_events[in]->xany.window == win ) continue;
4525 common_events[out++] = common_events[in];
4527 common_events.total = out;
4529 event_lock->unlock();
4532 int BC_WindowBase::resend_event(BC_WindowBase *window)
4534 if( resend_event_window ) return 1;
4535 resend_event_window = window;
4541 int BC_WindowBase::resend_event(BC_WindowBase *window)
4546 #endif // SINGLE_THREAD
4548 int BC_WindowBase::get_id()
4554 BC_Pixmap *BC_WindowBase::create_pixmap(VFrame *vframe)
4556 int w = vframe->get_w(), h = vframe->get_h();
4557 BC_Pixmap *icon = new BC_Pixmap(this, w, h);
4558 icon->draw_vframe(vframe, 0,0, w,h, 0,0);
4563 void BC_WindowBase::flicker(int n, int ms)
4565 int color = get_bg_color();
4566 for( int i=2*n; --i>=0; ) {
4567 set_inverse(); set_bg_color(WHITE);
4568 clear_box(0,0, w,h); flash(1);
4569 sync_display(); Timer::delay(ms);
4571 set_bg_color(color);
4575 void BC_WindowBase::focus()
4577 XWindowAttributes xwa;
4578 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4579 if( xwa.map_state == IsViewable )
4580 XSetInputFocus(top_level->display, top_level->win, RevertToParent, CurrentTime);