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 if( window_type == MAIN_WINDOW )
154 get_resources()->get_synchronous()->delete_window(this);
155 if( window_type == MAIN_WINDOW )
156 lock_window("BC_WindowBase::delete_window");
159 XDestroyWindow(top_level->display, win);
161 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
162 if(icon_pixmap) delete icon_pixmap;
163 if(temp_bitmap) delete temp_bitmap;
164 top_level->active_bitmaps.remove_buffers(this);
165 if(_7segment_pixmaps)
167 for(int i = 0; i < TOTAL_7SEGMENT; i++)
168 delete _7segment_pixmaps[i];
170 delete [] _7segment_pixmaps;
175 if(window_type == MAIN_WINDOW)
177 XFreeGC(display, gc);
178 static XFontStruct *BC_WindowBase::*xfont[] = {
179 &BC_WindowBase::smallfont,
180 &BC_WindowBase::mediumfont,
181 &BC_WindowBase::largefont,
182 &BC_WindowBase::bigfont,
183 &BC_WindowBase::clockfont,
185 for( int i=sizeof(xfont)/sizeof(xfont[0]); --i>=0; )
186 XFreeFont(display, this->*xfont[i]);
189 // prevents a bug when Xft closes with unrefd fonts
190 FcPattern *defaults = FcPatternCreate();
191 FcPatternAddInteger(defaults, "maxunreffonts", 0);
192 XftDefaultSet(display, defaults);
194 static void *BC_WindowBase::*xft_font[] = {
195 &BC_WindowBase::smallfont_xft,
196 &BC_WindowBase::mediumfont_xft,
197 &BC_WindowBase::largefont_xft,
198 &BC_WindowBase::bigfont_xft,
199 &BC_WindowBase::bold_smallfont_xft,
200 &BC_WindowBase::bold_mediumfont_xft,
201 &BC_WindowBase::bold_largefont_xft,
202 &BC_WindowBase::clockfont_xft,
204 for( int i=sizeof(xft_font)/sizeof(xft_font[0]); --i>=0; ) {
205 XftFont *xft = (XftFont *)(this->*xft_font[i]);
206 if( xft ) xftFontClose (display, xft);
214 XFree(xinerama_info);
215 xinerama_screens = 0;
217 if( xvideo_port_id >= 0 )
218 XvUngrabPort(display, xvideo_port_id, CurrentTime);
221 // Must be last reference to display.
222 // _XftDisplayInfo needs a lock.
223 get_resources()->create_window_lock->lock("BC_WindowBase::~BC_WindowBase");
224 XCloseDisplay(display);
225 get_resources()->create_window_lock->unlock();
227 // clipboard uses a different display connection
228 clipboard->stop_clipboard();
232 resize_history.remove_all_objects();
234 #ifndef SINGLE_THREAD
235 common_events.remove_all_objects();
237 delete event_condition;
240 top_level->window_lock = 0;
241 BC_Display::unlock_display();
246 if( glx_fbcfgs_window ) XFree(glx_fbcfgs_window);
247 if( glx_fbcfgs_pbuffer) XFree(glx_fbcfgs_pbuffer);
248 if( glx_fbcfgs_pixmap ) XFree(glx_fbcfgs_pixmap);
251 UNSET_ALL_LOCKS(this)
254 int BC_WindowBase::initialize()
259 display_lock_owner = 0;
264 resend_event_window = 0;
276 xinerama_screens = 0;
281 translation_events = 0;
282 ctrl_mask = shift_mask = alt_mask = 0;
283 cursor_x = cursor_y = button_number = 0;
297 active_popup_menu = 0;
298 active_subwindow = 0;
302 _7segment_pixmaps = 0;
305 // next_repeat_id = 0;
307 current_font = MEDIUMFONT;
308 current_color = BLACK;
309 current_cursor = ARROW_CURSOR;
312 shared_bg_pixmap = 0;
315 window_type = MAIN_WINDOW;
316 translation_count = 0;
317 x_correction = y_correction = 0;
326 #ifdef HAVE_LIBXXF86VM
344 bold_smallfont_xft = 0;
345 bold_mediumfont_xft = 0;
346 bold_largefont_xft = 0;
348 completion_lock = new Condition(0, "BC_WindowBase::completion_lock");
350 // Need these right away since put_event is called before run_window sometimes.
351 event_lock = new Mutex("BC_WindowBase::event_lock");
352 event_condition = new Condition(0, "BC_WindowBase::event_condition");
353 init_lock = new Condition(0, "BC_WindowBase::init_lock");
356 cursor_timer = new Timer;
359 glx_fbcfgs_window = 0; n_fbcfgs_window = 0;
360 glx_fbcfgs_pbuffer = 0; n_fbcfgs_pbuffer = 0;
361 glx_fbcfgs_pixmap = 0; n_fbcfgs_pixmap = 0;
375 #define DEFAULT_EVENT_MASKS EnterWindowMask | \
378 ButtonReleaseMask | \
379 PointerMotionMask | \
383 int BC_WindowBase::create_window(BC_WindowBase *parent_window, const char *title,
384 int x, int y, int w, int h, int minw, int minh, int allow_resize,
385 int private_color, int hide, int bg_color, const char *display_name,
386 int window_type, BC_Pixmap *bg_pixmap, int group_it)
388 XSetWindowAttributes attr;
390 XSizeHints size_hints;
393 #ifdef HAVE_LIBXXF86VM
397 id = get_resources()->get_id();
398 if(parent_window) top_level = parent_window->top_level;
399 if( top_level ) lock_window("BC_WindowBase::create_window");
400 get_resources()->create_window_lock->lock("BC_WindowBase::create_window");
402 #ifdef HAVE_LIBXXF86VM
403 if(window_type == VIDMODE_SCALED_WINDOW)
404 closest_vm(&vm,&w,&h);
411 this->bg_color = bg_color;
412 this->window_type = window_type;
414 this->private_color = private_color;
415 this->parent_window = parent_window;
416 this->bg_pixmap = bg_pixmap;
417 this->allow_resize = allow_resize;
419 strcpy(this->display_name, display_name);
421 this->display_name[0] = 0;
424 if(bg_pixmap) shared_bg_pixmap = 1;
426 subwindows = new BC_SubWindowList;
428 if(window_type == MAIN_WINDOW)
431 parent_window = this;
435 display = BC_Display::get_display(display_name);
436 BC_Display::lock_display("BC_WindowBase::create_window");
437 // BC_Display::display_global->new_window(this);
440 // get the display connection
442 // This function must be the first Xlib
443 // function a multi-threaded program calls
445 display = init_display(display_name);
446 if( shm_completion_event < 0 ) shm_completion_event =
447 ShmCompletion + XShmGetEventBase(display);
449 lock_window("BC_WindowBase::create_window 1");
451 screen = DefaultScreen(display);
452 rootwin = RootWindow(display, screen);
453 // window placement boundaries
454 if( !xinerama_screens && XineramaIsActive(display) )
455 xinerama_info = XineramaQueryScreens(display, &xinerama_screens);
456 root_w = get_root_w(0);
457 root_h = get_root_h(0);
460 vis = get_glx_visual(display);
464 int mask = VisualDepthMask | VisualClassMask;
465 static XVisualInfo vinfo = { .depth = 24, .c_class = DirectColor, };
467 XVisualInfo *vis_info = XGetVisualInfo(display, mask, &vinfo, &nitems);
468 vis = vis_info && nitems>0 ? vis_info[0].visual : 0;
469 if( vis_info ) XFree(vis_info);
472 vis = DefaultVisual(display, screen);
473 default_depth = DefaultDepth(display, screen);
475 client_byte_order = (*(const u_int32_t*)"a ") & 0x00000001;
476 server_byte_order = (XImageByteOrder(display) == MSBFirst) ? 0 : 1;
479 // This must be done before fonts to know if antialiasing is available.
482 if(resources.use_shm < 0) resources.initialize_display(this);
483 x_correction = BC_DisplayInfo::get_left_border();
484 y_correction = BC_DisplayInfo::get_top_border();
486 // clamp window placement
487 if(this->x + this->w + x_correction > root_w)
488 this->x = root_w - this->w - x_correction;
489 if(this->y + this->h + y_correction > root_h)
490 this->y = root_h - this->h - y_correction;
491 if(this->x < 0) this->x = 0;
492 if(this->y < 0) this->y = 0;
494 if(this->bg_color == -1)
495 this->bg_color = resources.get_bg_color();
497 // printf("bcwindowbase 1 %s\n", title);
498 // if(window_type == MAIN_WINDOW) sleep(1);
499 // printf("bcwindowbase 10\n");
505 mask = CWEventMask | CWBackPixel | CWColormap | CWCursor;
507 attr.event_mask = DEFAULT_EVENT_MASKS |
508 StructureNotifyMask |
512 attr.background_pixel = get_color(this->bg_color);
513 attr.colormap = cmap;
514 attr.cursor = get_cursor_struct(ARROW_CURSOR);
516 win = XCreateWindow(display, rootwin,
517 this->x, this->y, this->w, this->h, 0,
518 top_level->default_depth, InputOutput,
520 XGetNormalHints(display, win, &size_hints);
522 size_hints.flags = PSize | PMinSize | PMaxSize;
523 size_hints.width = this->w;
524 size_hints.height = this->h;
525 size_hints.min_width = allow_resize ? minw : this->w;
526 size_hints.max_width = allow_resize ? 32767 : this->w;
527 size_hints.min_height = allow_resize ? minh : this->h;
528 size_hints.max_height = allow_resize ? 32767 : this->h;
529 if(x > -BC_INFINITY && x < BC_INFINITY)
531 size_hints.flags |= PPosition;
532 size_hints.x = this->x;
533 size_hints.y = this->y;
535 XSetWMProperties(display, win, 0, 0, 0, 0, &size_hints, 0, 0);
538 #ifndef SINGLE_THREAD
539 clipboard = new BC_Clipboard(this);
540 clipboard->start_clipboard();
546 Atom ClientLeaderXAtom;
547 if (XGroupLeader == 0)
549 const char *instance_name = "cinelerra";
550 const char *class_name = "Cinelerra";
551 XClassHint *class_hints = XAllocClassHint();
552 class_hints->res_name = (char*)instance_name;
553 class_hints->res_class = (char*)class_name;
554 XSetClassHint(top_level->display, win, class_hints);
556 ClientLeaderXAtom = XInternAtom(display, "WM_CLIENT_LEADER", True);
557 XChangeProperty(display, win, ClientLeaderXAtom, XA_WINDOW, 32,
558 PropModeReplace, (unsigned char *)&XGroupLeader, true);
561 set_icon(get_resources()->default_icon);
564 #ifdef HAVE_LIBXXF86VM
565 if(window_type == VIDMODE_SCALED_WINDOW && vm != -1)
572 #ifdef HAVE_LIBXXF86VM
573 if(window_type == POPUP_WINDOW || window_type == VIDMODE_SCALED_WINDOW)
575 if(window_type == POPUP_WINDOW)
578 mask = CWEventMask | CWBackPixel | CWColormap |
579 CWOverrideRedirect | CWSaveUnder | CWCursor;
581 attr.event_mask = DEFAULT_EVENT_MASKS | ExposureMask |
582 KeyPressMask | KeyReleaseMask;
584 if(this->bg_color == -1)
585 this->bg_color = resources.get_bg_color();
586 attr.background_pixel = top_level->get_color(bg_color);
587 attr.colormap = top_level->cmap;
588 if(top_level->is_hourglass)
589 attr.cursor = top_level->get_cursor_struct(HOURGLASS_CURSOR);
591 attr.cursor = top_level->get_cursor_struct(ARROW_CURSOR);
592 attr.override_redirect = True;
593 attr.save_under = True;
595 win = XCreateWindow(top_level->display,
596 top_level->rootwin, this->x, this->y, this->w, this->h, 0,
597 top_level->default_depth, InputOutput, top_level->vis, mask,
599 top_level->add_popup(this);
602 if(window_type == SUB_WINDOW)
604 mask = CWEventMask | CWBackPixel | CWCursor;
605 attr.event_mask = DEFAULT_EVENT_MASKS;
606 attr.background_pixel = top_level->get_color(this->bg_color);
607 if(top_level->is_hourglass)
608 attr.cursor = top_level->get_cursor_struct(HOURGLASS_CURSOR);
610 attr.cursor = top_level->get_cursor_struct(ARROW_CURSOR);
611 win = XCreateWindow(top_level->display,
612 parent_window->win, this->x, this->y, this->w, this->h, 0,
613 top_level->default_depth, InputOutput, top_level->vis, mask,
616 if(!hidden) XMapWindow(top_level->display, win);
619 // Create pixmap for all windows
620 pixmap = new BC_Pixmap(this, this->w, this->h);
622 // Set up options for main window
623 if(window_type == MAIN_WINDOW)
625 if(get_resources()->bg_image && !bg_pixmap && bg_color < 0)
627 this->bg_pixmap = new BC_Pixmap(this,
628 get_resources()->bg_image,
632 if(!hidden) show_window();
636 draw_background(0, 0, this->w, this->h);
638 flash(-1, -1, -1, -1, 0);
640 // Set up options for popup window
641 #ifdef HAVE_LIBXXF86VM
642 if(window_type == POPUP_WINDOW || window_type == VIDMODE_SCALED_WINDOW)
644 if(window_type == POPUP_WINDOW)
648 if(!hidden) show_window();
650 get_resources()->create_window_lock->unlock();
656 Display* BC_WindowBase::init_display(const char *display_name)
660 if(display_name && display_name[0] == 0) display_name = NULL;
661 if((display = XOpenDisplay(display_name)) == NULL) {
662 printf("BC_WindowBase::init_display: cannot connect to X server %s\n",
664 if(getenv("DISPLAY") == NULL) {
665 printf(_("'DISPLAY' environment variable not set.\n"));
668 // Try again with default display.
669 if((display = XOpenDisplay(0)) == NULL) {
670 printf("BC_WindowBase::init_display: cannot connect to default X server.\n");
675 static int xsynch = -1;
677 const char *cp = getenv("CIN_XSYNCH");
678 xsynch = !cp ? 0 : atoi(cp);
681 XSynchronize(display, True);
686 Display* BC_WindowBase::get_display()
688 return top_level->display;
691 int BC_WindowBase::get_screen()
693 return top_level->screen;
696 int BC_WindowBase::run_window()
702 // Events may have been sent before run_window so can't initialize them here.
705 set_repeat(get_resources()->tooltip_delay);
706 BC_Display::display_global->new_window(this);
708 // If the first window created, run the display loop in this thread.
709 if(BC_Display::display_global->is_first(this))
711 BC_Display::unlock_display();
712 BC_Display::display_global->loop();
716 BC_Display::unlock_display();
717 completion_lock->lock("BC_WindowBase::run_window");
720 BC_Display::lock_display("BC_WindowBase::run_window");
721 BC_Display::display_global->delete_window(this);
723 unset_all_repeaters();
725 BC_Display::unlock_display();
727 #else // SINGLE_THREAD
732 set_repeat(get_resources()->tooltip_delay);
734 // Start X server events
735 event_thread = new BC_WindowEvents(this);
736 event_thread->start();
742 // Handle common events
747 unset_all_repeaters();
751 event_condition->reset();
752 common_events.remove_all_objects();
756 #endif // SINGLE_THREAD
761 int BC_WindowBase::get_key_masks(unsigned int key_state)
763 // printf("BC_WindowBase::get_key_masks %llx\n",
764 // event->xkey.state);
765 ctrl_mask = (key_state & ControlMask) ? 1 : 0; // ctrl key down
766 shift_mask = (key_state & ShiftMask) ? 1 : 0; // shift key down
767 alt_mask = (key_state & Mod1Mask) ? 1 : 0; // alt key down
772 void BC_WindowBase::add_keyboard_listener(int(BC_WindowBase::*handler)(BC_WindowBase *))
774 BC_KeyboardHandlerLock set;
775 BC_KeyboardHandler::listeners.append(new BC_KeyboardHandler(handler, this));
778 void BC_WindowBase::del_keyboard_listener(int(BC_WindowBase::*handler)(BC_WindowBase *))
780 BC_KeyboardHandlerLock set;
781 int i = BC_KeyboardHandler::listeners.size();
782 while( --i >= 0 && BC_KeyboardHandler::listeners[i]->handler!=handler );
783 if( i >= 0 ) BC_KeyboardHandler::listeners.remove_object_number(i);
786 int BC_KeyboardHandler::run_event(BC_WindowBase *wp)
788 int result = (win->*handler)(wp);
792 int BC_KeyboardHandler::run_listeners(BC_WindowBase *wp)
795 BC_KeyboardHandlerLock set;
796 for( int i=0; !result && i<listeners.size(); ++i ) {
797 BC_KeyboardHandler *listener = listeners[i];
798 result = listener->run_event(wp);
803 void BC_KeyboardHandler::kill_grabs()
805 BC_KeyboardHandlerLock set;
806 for( int i=0; i<listeners.size(); ++i ) {
807 BC_WindowBase *win = listeners[i]->win;
808 if( win->get_window_type() != POPUP_WINDOW ) continue;
809 ((BC_Popup *)win)->ungrab_keyboard();
813 void BC_ActiveBitmaps::reque(XEvent *event)
815 XShmCompletionEvent *shm_ev = (XShmCompletionEvent *)event;
816 ShmSeg shmseg = shm_ev->shmseg;
817 Drawable drawable = shm_ev->drawable;
818 //printf("BC_BitmapImage::reque %08lx\n",shmseg);
819 active_lock.lock("BC_BitmapImage::reque");
820 BC_BitmapImage *bfr = first;
821 while( bfr && bfr->get_shmseg() != shmseg ) bfr = bfr->next;
822 if( bfr && bfr->drawable == drawable )
824 active_lock.unlock();
826 // sadly, X reports two drawable completions and creates false reporting, so no boobytrap
827 // printf("BC_BitmapImage::reque missed shmseg %08x, drawable %08x\n",
828 // (int)shmseg, (int)drawable);
831 if( bfr->drawable != drawable ) return;
832 if( bfr->is_zombie() ) { --BC_Bitmap::zombies; delete bfr; return; }
833 bfr->bitmap->reque(bfr);
836 void BC_ActiveBitmaps::insert(BC_BitmapImage *bfr, Drawable pixmap)
838 active_lock.lock("BC_BitmapImage::insert");
839 bfr->drawable = pixmap;
841 active_lock.unlock();
844 void BC_ActiveBitmaps::remove_buffers(BC_WindowBase *wdw)
846 active_lock.lock("BC_ActiveBitmaps::remove");
847 for( BC_BitmapImage *nxt=0, *bfr=first; bfr; bfr=nxt ) {
849 if( bfr->is_zombie() ) { --BC_Bitmap::zombies; delete bfr; continue; }
850 if( bfr->bitmap->parent_window == wdw ) remove_pointer(bfr);
852 active_lock.unlock();
855 BC_ActiveBitmaps::BC_ActiveBitmaps()
859 BC_ActiveBitmaps::~BC_ActiveBitmaps()
865 int BC_WindowBase::keysym_lookup(XEvent *event)
867 for( int i = 0; i < KEYPRESSLEN; ++i ) keys_return[i] = 0;
868 for( int i = 0; i < 4; ++i ) wkey_string[i] = 0;
870 if( event->xany.send_event && !event->xany.serial ) {
871 keysym = (KeySym) event->xkey.keycode;
872 keys_return[0] = keysym;
875 wkey_string_length = 0;
877 if( input_context ) {
878 wkey_string_length = XwcLookupString(input_context,
879 (XKeyEvent*)event, wkey_string, 4, &keysym, 0);
880 //printf("keysym_lookup 1 %d %d %lx %x %x %x %x\n", wkey_string_length, keysym,
881 // wkey_string[0], wkey_string[1], wkey_string[2], wkey_string[3]);
884 int ret = Xutf8LookupString(input_context, (XKeyEvent*)event,
885 keys_return, KEYPRESSLEN, &keysym, &stat);
886 //printf("keysym_lookup 2 %d %d %lx %x %x\n", ret, stat, keysym, keys_return[0], keys_return[1]);
887 if( stat == XLookupBoth ) return ret;
888 if( stat == XLookupKeySym ) return 0;
890 int ret = XLookupString((XKeyEvent*)event, keys_return, KEYPRESSLEN, &keysym, 0);
891 wkey_string_length = ret;
892 for( int i=0; i<ret; ++i ) wkey_string[i] = keys_return[i];
896 pthread_t locking_task = (pthread_t)-1L;
897 int locking_event = -1;
898 int locking_message = -1;
900 int BC_WindowBase::dispatch_event()
904 XClientMessageEvent *ptr;
905 int cancel_resize, cancel_translation;
906 volatile static int debug = 0;
911 #ifndef SINGLE_THREAD
912 // If an event is waiting get it, otherwise
913 // wait for next event only if there are no compressed events.
914 if(get_event_count() ||
915 (!motion_events && !resize_events && !translation_events))
918 // Lock out window deletions
919 lock_window("BC_WindowBase::dispatch_event 1");
920 locking_event = event->type;
921 locking_task = pthread_self();
922 locking_message = event->xclient.message_type;
925 // Handle compressed events
927 lock_window("BC_WindowBase::dispatch_event 2");
929 dispatch_resize_event(last_resize_w, last_resize_h);
931 dispatch_motion_event();
932 if(translation_events)
933 dispatch_translation_event();
944 if( debug && event->type != ClientMessage ) {
945 static const char *event_names[] = {
946 "Reply", "Error", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease", "MotionNotify",
947 "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut", "KeymapNotify", "Expose", "GraphicsExpose",
948 "NoExpose", "VisibilityNotify", "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify",
949 "MapRequest", "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
950 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear",
951 "SelectionRequest", "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify",
952 "GenericEvent", "LASTEvent",
954 const int nevents = sizeof(event_names)/sizeof(event_names[0]);
956 printf("BC_WindowBase::dispatch_event %d %s %p %d (%s)\n", __LINE__,
957 title, event, event->type, event->type>=0 && event->type<nevents ?
958 event_names[event->type] : "Unknown");
963 active_grab->lock_window("BC_WindowBase::dispatch_event 3");
964 result = active_grab->grab_event(event);
965 active_grab->unlock_window();
966 if( result ) return result;
967 lock_window("BC_WindowBase::dispatch_event 4");
970 switch(event->type) {
972 // Clear the resize buffer
974 dispatch_resize_event(last_resize_w, last_resize_h);
975 // Clear the motion buffer since this can clear the window
977 dispatch_motion_event();
979 ptr = (XClientMessageEvent*)event;
980 if( ptr->message_type == ProtoXAtom &&
981 (Atom)ptr->data.l[0] == DelWinXAtom ) {
984 else if( ptr->message_type == RepeaterXAtom ) {
985 dispatch_repeat_event(ptr->data.l[0]);
987 else if( ptr->message_type == SetDoneXAtom ) {
991 receive_custom_xatoms((xatom_event *)ptr);
1002 dispatch_focus_out();
1016 dispatch_motion_event();
1018 get_key_masks(event->xbutton.state);
1019 cursor_x = event->xbutton.x;
1020 cursor_y = event->xbutton.y;
1021 button_number = event->xbutton.button;
1023 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1024 event_win = event->xany.window;
1025 if (button_number < 6) {
1026 if(button_number < 4)
1028 button_pressed = event->xbutton.button;
1029 button_time1 = button_time2;
1030 button_time2 = button_time3;
1031 button_time3 = event->xbutton.time;
1034 drag_win = event_win;
1035 drag_x1 = cursor_x - get_resources()->drag_radius;
1036 drag_x2 = cursor_x + get_resources()->drag_radius;
1037 drag_y1 = cursor_y - get_resources()->drag_radius;
1038 drag_y2 = cursor_y + get_resources()->drag_radius;
1040 if((long)(button_time3 - button_time1) < resources.double_click * 2)
1043 button_time3 = button_time2 = button_time1 = 0;
1045 if((long)(button_time3 - button_time2) < resources.double_click)
1048 // button_time3 = button_time2 = button_time1 = 0;
1056 dispatch_button_press();
1063 dispatch_motion_event();
1065 get_key_masks(event->xbutton.state);
1066 button_number = event->xbutton.button;
1067 event_win = event->xany.window;
1068 if (button_number < 6)
1070 if(button_number < 4)
1072 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1074 dispatch_button_release();
1079 event_win = event->xany.window;
1081 for( int i=0; !result && i<popups.size(); ++i ) { // popups take focus
1082 if( popups[i]->win == event_win )
1083 result = popups[i]->dispatch_expose_event();
1086 result = 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 if( this->x > -BC_INFINITY && this->x < BC_INFINITY ) {
4072 size_hints.flags |= PPosition;
4073 size_hints.x = this->x;
4074 size_hints.y = this->y;
4076 XSetNormalHints(top_level->display, win, &size_hints);
4078 XResizeWindow(top_level->display, win, w, h);
4083 pixmap = new BC_Pixmap(this, w, h);
4085 // Propagate to menubar
4086 for(int i = 0; i < subwindows->total; i++)
4088 subwindows->values[i]->dispatch_resize_event(w, h);
4091 draw_background(0, 0, w, h);
4092 if(top_level == this && get_resources()->recursive_resizing)
4093 resize_history.append(new BC_ResizeCall(w, h));
4097 // The only way for resize events to be propagated is by updating the internal w and h
4098 int BC_WindowBase::resize_event(int w, int h)
4100 if(window_type == MAIN_WINDOW)
4108 int BC_WindowBase::reposition_window(int x, int y)
4110 reposition_window(x, y, -1, -1);
4115 int BC_WindowBase::reposition_window(int x, int y, int w, int h)
4119 // Some tools set their own dimensions before calling this, causing the
4120 // resize check to skip.
4124 if(w > 0 && w != this->w)
4130 if(h > 0 && h != this->h)
4136 //printf("BC_WindowBase::reposition_window %d %d %d\n", translation_count, x_correction, y_correction);
4139 printf("BC_WindowBase::reposition_window this->w == %d\n", this->w);
4141 printf("BC_WindowBase::reposition_window this->h == %d\n", this->h);
4143 if(translation_count && window_type == MAIN_WINDOW)
4145 // KDE shifts window right and down.
4146 // FVWM leaves window alone and adds border around it.
4147 XMoveResizeWindow(top_level->display,
4149 x - BC_DisplayInfo::auto_reposition_x,
4150 y - BC_DisplayInfo::auto_reposition_y,
4156 XMoveResizeWindow(top_level->display,
4167 pixmap = new BC_Pixmap(this, this->w, this->h);
4168 clear_box(0,0, this->w, this->h);
4169 // Propagate to menubar
4170 for(int i = 0; i < subwindows->total; i++)
4172 subwindows->values[i]->dispatch_resize_event(this->w, this->h);
4175 // draw_background(0, 0, w, h);
4181 int BC_WindowBase::reposition_window_relative(int dx, int dy, int w, int h)
4183 return reposition_window(get_x()+dx, get_y()+dy, w, h);
4186 int BC_WindowBase::reposition_window_relative(int dx, int dy)
4188 return reposition_window_relative(dx, dy, -1, -1);
4191 void BC_WindowBase::set_tooltips(int v)
4193 get_resources()->tooltips_enabled = v;
4196 void BC_WindowBase::set_force_tooltip(int v)
4201 int BC_WindowBase::raise_window(int do_flush)
4203 XRaiseWindow(top_level->display, win);
4204 if(do_flush) XFlush(top_level->display);
4208 int BC_WindowBase::lower_window(int do_flush)
4210 XLowerWindow(top_level->display, win);
4211 if(do_flush) XFlush(top_level->display);
4215 void BC_WindowBase::set_background(VFrame *bitmap)
4217 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
4219 bg_pixmap = new BC_Pixmap(this, bitmap, PIXMAP_OPAQUE);
4220 shared_bg_pixmap = 0;
4221 draw_background(0, 0, w, h);
4224 void BC_WindowBase::put_title(const char *text)
4226 char *cp = this->title, *ep = cp+sizeof(this->title)-1;
4227 for( const unsigned char *bp = (const unsigned char *)text; *bp && cp<ep; ++bp )
4228 *cp++ = *bp >= ' ' ? *bp : ' ';
4232 void BC_WindowBase::set_title(const char *text, int utf8)
4234 // utf8>0: wm + net_wm, utf8=0: wm only, utf<0: net_wm only
4236 const unsigned char *wm_title = (const unsigned char *)title;
4237 int title_len = strlen((const char *)title);
4239 Atom xa_wm_name = XA_WM_NAME;
4240 Atom xa_icon_name = XA_WM_ICON_NAME;
4241 Atom xa_string = XA_STRING;
4242 XChangeProperty(display, win, xa_wm_name, xa_string, 8,
4243 PropModeReplace, wm_title, title_len);
4244 XChangeProperty(display, win, xa_icon_name, xa_string, 8,
4245 PropModeReplace, wm_title, title_len);
4248 Atom xa_net_wm_name = XInternAtom(display, "_NET_WM_NAME", True);
4249 Atom xa_net_icon_name = XInternAtom(display, "_NET_WM_ICON_NAME", True);
4250 Atom xa_utf8_string = XInternAtom(display, "UTF8_STRING", True);
4251 XChangeProperty(display, win, xa_net_wm_name, xa_utf8_string, 8,
4252 PropModeReplace, wm_title, title_len);
4253 XChangeProperty(display, win, xa_net_icon_name, xa_utf8_string, 8,
4254 PropModeReplace, wm_title, title_len);
4259 const char *BC_WindowBase::get_title()
4264 int BC_WindowBase::get_toggle_value()
4266 return toggle_value;
4269 int BC_WindowBase::get_toggle_drag()
4274 int BC_WindowBase::set_icon(VFrame *data)
4276 if(icon_pixmap) delete icon_pixmap;
4277 icon_pixmap = new BC_Pixmap(top_level, data, PIXMAP_ALPHA, 1);
4279 if(icon_window) delete icon_window;
4280 icon_window = new BC_Popup(this,
4283 icon_pixmap->get_w(),
4284 icon_pixmap->get_h(),
4286 1, // All windows are hidden initially
4290 wm_hints.flags = WindowGroupHint | IconPixmapHint | IconMaskHint | IconWindowHint;
4291 wm_hints.icon_pixmap = icon_pixmap->get_pixmap();
4292 wm_hints.icon_mask = icon_pixmap->get_alpha();
4293 wm_hints.icon_window = icon_window->win;
4294 wm_hints.window_group = XGroupLeader;
4296 // for(int i = 0; i < 1000; i++)
4297 // printf("02x ", icon_pixmap->get_alpha()->get_row_pointers()[0][i]);
4300 XSetWMHints(top_level->display, top_level->win, &wm_hints);
4301 XSync(top_level->display, 0);
4305 int BC_WindowBase::set_w(int w)
4311 int BC_WindowBase::set_h(int h)
4317 int BC_WindowBase::load_defaults(BC_Hash *defaults)
4319 BC_Resources *resources = get_resources();
4320 char string[BCTEXTLEN];
4321 int newest_id = - 1;
4322 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4324 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4325 resources->filebox_history[i].path[0] = 0;
4326 defaults->get(string, resources->filebox_history[i].path);
4327 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4328 resources->filebox_history[i].id = defaults->get(string, resources->get_id());
4329 if(resources->filebox_history[i].id > newest_id)
4330 newest_id = resources->filebox_history[i].id;
4333 resources->filebox_id = newest_id + 1;
4334 resources->filebox_mode = defaults->get("FILEBOX_MODE", get_resources()->filebox_mode);
4335 resources->filebox_w = defaults->get("FILEBOX_W", get_resources()->filebox_w);
4336 resources->filebox_h = defaults->get("FILEBOX_H", get_resources()->filebox_h);
4337 resources->filebox_columntype[0] = defaults->get("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4338 resources->filebox_columntype[1] = defaults->get("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4339 resources->filebox_columntype[2] = defaults->get("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4340 resources->filebox_columntype[3] = defaults->get("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4341 resources->filebox_columnwidth[0] = defaults->get("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4342 resources->filebox_columnwidth[1] = defaults->get("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4343 resources->filebox_columnwidth[2] = defaults->get("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4344 resources->filebox_columnwidth[3] = defaults->get("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4345 resources->filebox_size_format = defaults->get("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4346 defaults->get("FILEBOX_FILTER", resources->filebox_filter);
4350 int BC_WindowBase::save_defaults(BC_Hash *defaults)
4352 BC_Resources *resources = get_resources();
4353 char string[BCTEXTLEN];
4354 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4356 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4357 defaults->update(string, resources->filebox_history[i].path);
4358 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4359 defaults->update(string, resources->filebox_history[i].id);
4361 defaults->update("FILEBOX_MODE", resources->filebox_mode);
4362 defaults->update("FILEBOX_W", resources->filebox_w);
4363 defaults->update("FILEBOX_H", resources->filebox_h);
4364 defaults->update("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4365 defaults->update("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4366 defaults->update("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4367 defaults->update("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4368 defaults->update("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4369 defaults->update("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4370 defaults->update("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4371 defaults->update("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4372 defaults->update("FILEBOX_FILTER", resources->filebox_filter);
4373 defaults->update("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4379 // For some reason XTranslateCoordinates can take a long time to return.
4380 // We work around this by only calling it when the event windows are different.
4381 void BC_WindowBase::translate_coordinates(Window src_w,
4393 *dest_x_return = src_x;
4394 *dest_y_return = src_y;
4398 XTranslateCoordinates(top_level->display,
4406 //printf("BC_WindowBase::translate_coordinates 1 %lld\n", timer.get_difference());
4410 void BC_WindowBase::get_root_coordinates(int x, int y, int *abs_x, int *abs_y)
4412 translate_coordinates(win, top_level->rootwin, x, y, abs_x, abs_y);
4415 void BC_WindowBase::get_win_coordinates(int abs_x, int abs_y, int *x, int *y)
4417 translate_coordinates(top_level->rootwin, win, abs_x, abs_y, x, y);
4425 #ifdef HAVE_LIBXXF86VM
4426 void BC_WindowBase::closest_vm(int *vm, int *width, int *height)
4430 if(XF86VidModeQueryExtension(top_level->display,&foo,&bar)) {
4432 XF86VidModeModeInfo **vm_modelines;
4433 XF86VidModeGetAllModeLines(top_level->display,
4434 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4435 for( i = 0; i < vm_count; i++ ) {
4436 if( vm_modelines[i]->hdisplay < vm_modelines[*vm]->hdisplay &&
4437 vm_modelines[i]->hdisplay >= *width )
4440 display = top_level->display;
4441 if( vm_modelines[*vm]->hdisplay == *width )
4444 *width = vm_modelines[*vm]->hdisplay;
4445 *height = vm_modelines[*vm]->vdisplay;
4450 void BC_WindowBase::scale_vm(int vm)
4452 int foo,bar,dotclock;
4453 if( XF86VidModeQueryExtension(top_level->display,&foo,&bar) ) {
4455 XF86VidModeModeInfo **vm_modelines;
4456 XF86VidModeModeLine vml;
4457 XF86VidModeGetAllModeLines(top_level->display,
4458 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4459 XF86VidModeGetModeLine(top_level->display,
4460 XDefaultScreen(top_level->display), &dotclock,&vml);
4461 orig_modeline.dotclock = dotclock;
4462 orig_modeline.hdisplay = vml.hdisplay;
4463 orig_modeline.hsyncstart = vml.hsyncstart;
4464 orig_modeline.hsyncend = vml.hsyncend;
4465 orig_modeline.htotal = vml.htotal;
4466 orig_modeline.vdisplay = vml.vdisplay;
4467 orig_modeline.vsyncstart = vml.vsyncstart;
4468 orig_modeline.vsyncend = vml.vsyncend;
4469 orig_modeline.vtotal = vml.vtotal;
4470 orig_modeline.flags = vml.flags;
4471 orig_modeline.privsize = vml.privsize;
4472 // orig_modeline.private = vml.private;
4473 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),vm_modelines[vm]);
4474 XF86VidModeSetViewPort(top_level->display,XDefaultScreen(top_level->display),0,0);
4475 XFlush(top_level->display);
4479 void BC_WindowBase::restore_vm()
4481 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),&orig_modeline);
4482 XFlush(top_level->display);
4487 #ifndef SINGLE_THREAD
4488 int BC_WindowBase::get_event_count()
4490 event_lock->lock("BC_WindowBase::get_event_count");
4491 int result = common_events.total;
4492 event_lock->unlock();
4496 XEvent* BC_WindowBase::get_event()
4499 while(!done && !result)
4501 event_condition->lock("BC_WindowBase::get_event");
4502 event_lock->lock("BC_WindowBase::get_event");
4504 if(common_events.total && !done)
4506 result = common_events.values[0];
4507 common_events.remove_number(0);
4510 event_lock->unlock();
4515 void BC_WindowBase::put_event(XEvent *event)
4517 event_lock->lock("BC_WindowBase::put_event");
4518 common_events.append(event);
4519 event_lock->unlock();
4520 event_condition->unlock();
4523 void BC_WindowBase::dequeue_events(Window win)
4525 event_lock->lock("BC_WindowBase::dequeue_events");
4527 int out = 0, total = common_events.size();
4528 for( int in=0; in<total; ++in ) {
4529 if( common_events[in]->xany.window == win ) continue;
4530 common_events[out++] = common_events[in];
4532 common_events.total = out;
4534 event_lock->unlock();
4537 int BC_WindowBase::resend_event(BC_WindowBase *window)
4539 if( resend_event_window ) return 1;
4540 resend_event_window = window;
4546 int BC_WindowBase::resend_event(BC_WindowBase *window)
4551 #endif // SINGLE_THREAD
4553 int BC_WindowBase::get_id()
4559 BC_Pixmap *BC_WindowBase::create_pixmap(VFrame *vframe)
4561 int w = vframe->get_w(), h = vframe->get_h();
4562 BC_Pixmap *icon = new BC_Pixmap(this, w, h);
4563 icon->draw_vframe(vframe, 0,0, w,h, 0,0);
4568 void BC_WindowBase::flicker(int n, int ms)
4570 int color = get_bg_color();
4571 for( int i=2*n; --i>=0; ) {
4572 set_inverse(); set_bg_color(WHITE);
4573 clear_box(0,0, w,h); flash(1);
4574 sync_display(); Timer::delay(ms);
4576 set_bg_color(color);
4580 void BC_WindowBase::focus()
4582 XWindowAttributes xwa;
4583 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4584 if( xwa.map_state == IsViewable )
4585 XSetInputFocus(top_level->display, top_level->win, RevertToParent, CurrentTime);