4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "bcclipboard.h"
24 #include "bcdisplay.h"
25 #include "bcdisplayinfo.h"
26 #include "bcmenubar.h"
29 #include "bcpopupmenu.h"
30 #include "bcrepeater.h"
31 #include "bcresources.h"
32 #include "bcsignals.h"
33 #include "bcsubwindow.h"
34 #include "bcsynchronous.h"
36 #include "bcwindowbase.h"
37 #include "bcwindowevents.h"
38 #include "bccmodels.h"
40 #include "condition.h"
49 #include "workarounds.h"
59 #include <X11/extensions/Xinerama.h>
61 #include <X11/extensions/Xvlib.h>
63 #include <X11/extensions/shape.h>
64 #include <X11/XF86keysym.h>
65 #include <X11/Sunkeysym.h>
67 BC_ResizeCall::BC_ResizeCall(int w, int h)
74 int BC_WindowBase::shm_completion_event = -1;
75 BC_Resources *BC_WindowBase::resources = 0;
76 Window XGroupLeader = 0;
78 Mutex BC_KeyboardHandlerLock::keyboard_listener_mutex("keyboard_listener",0);
79 ArrayList<BC_KeyboardHandler*> BC_KeyboardHandler::listeners;
81 BC_WindowBase::BC_WindowBase()
83 //printf("BC_WindowBase::BC_WindowBase 1\n");
84 BC_WindowBase::initialize();
87 BC_WindowBase::~BC_WindowBase()
90 BC_Display::lock_display("BC_WindowBase::~BC_WindowBase");
92 if(window_type == MAIN_WINDOW)
93 lock_window("BC_WindowBase::~BC_WindowBase");
96 #ifdef HAVE_LIBXXF86VM
97 if(window_type == VIDMODE_SCALED_WINDOW && vm_switched) {
104 if(window_type != MAIN_WINDOW)
107 XSelectInput(top_level->display, this->win, 0);
108 XSync(top_level->display,0);
109 #ifndef SINGLE_THREAD
110 top_level->dequeue_events(win);
112 // drop active window refs to this
113 if(top_level->active_menubar == this) top_level->active_menubar = 0;
114 if(top_level->active_popup_menu == this) top_level->active_popup_menu = 0;
115 if(top_level->active_subwindow == this) top_level->active_subwindow = 0;
116 // drop motion window refs to this
117 if(top_level->motion_events && top_level->last_motion_win == this->win)
118 top_level->motion_events = 0;
120 // Remove pointer from parent window to this
121 parent_window->subwindows->remove(this);
124 if(grab_active) grab_active->active_grab = 0;
125 if(icon_window) delete icon_window;
126 if(window_type == POPUP_WINDOW)
127 parent_window->remove_popup(this);
129 // Delete the subwindows
132 while(subwindows->total)
134 // Subwindow removes its own pointer
135 delete subwindows->values[0];
142 //printf("delete glx=%08x, win=%08x %s\n", (unsigned)glx_win, (unsigned)win, title);
144 if( get_resources()->get_synchronous() && glx_win != 0 ) {
145 if( window_type == MAIN_WINDOW )
147 get_resources()->get_synchronous()->delete_window(this);
148 if( window_type == MAIN_WINDOW )
149 lock_window("BC_WindowBase::delete_window");
152 XDestroyWindow(top_level->display, win);
154 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
155 if(icon_pixmap) delete icon_pixmap;
156 if(temp_bitmap) delete temp_bitmap;
157 top_level->active_bitmaps.remove_buffers(this);
158 if(_7segment_pixmaps)
160 for(int i = 0; i < TOTAL_7SEGMENT; i++)
161 delete _7segment_pixmaps[i];
163 delete [] _7segment_pixmaps;
168 if(window_type == MAIN_WINDOW)
170 XFreeGC(display, gc);
171 static XFontStruct *BC_WindowBase::*xfont[] = {
172 &BC_WindowBase::smallfont,
173 &BC_WindowBase::mediumfont,
174 &BC_WindowBase::largefont,
175 &BC_WindowBase::bigfont,
176 &BC_WindowBase::clockfont,
178 for( int i=sizeof(xfont)/sizeof(xfont[0]); --i>=0; )
179 XFreeFont(display, this->*xfont[i]);
182 // prevents a bug when Xft closes with unrefd fonts
183 FcPattern *defaults = FcPatternCreate();
184 FcPatternAddInteger(defaults, "maxunreffonts", 0);
185 XftDefaultSet(display, defaults);
187 static void *BC_WindowBase::*xft_font[] = {
188 &BC_WindowBase::smallfont_xft,
189 &BC_WindowBase::mediumfont_xft,
190 &BC_WindowBase::largefont_xft,
191 &BC_WindowBase::bigfont_xft,
192 &BC_WindowBase::bold_smallfont_xft,
193 &BC_WindowBase::bold_mediumfont_xft,
194 &BC_WindowBase::bold_largefont_xft,
195 &BC_WindowBase::clockfont_xft,
197 for( int i=sizeof(xft_font)/sizeof(xft_font[0]); --i>=0; ) {
198 XftFont *xft = (XftFont *)(this->*xft_font[i]);
199 if( xft ) xftFontClose (display, xft);
207 XFree(xinerama_info);
208 xinerama_screens = 0;
211 if( xvideo_port_id >= 0 )
212 XvUngrabPort(display, xvideo_port_id, CurrentTime);
215 // Must be last reference to display.
216 // _XftDisplayInfo needs a lock.
217 get_resources()->create_window_lock->lock("BC_WindowBase::~BC_WindowBase");
218 XCloseDisplay(display);
219 get_resources()->create_window_lock->unlock();
221 // clipboard uses a different display connection
222 clipboard->stop_clipboard();
226 resize_history.remove_all_objects();
228 #ifndef SINGLE_THREAD
229 common_events.remove_all_objects();
231 delete event_condition;
234 top_level->window_lock = 0;
235 BC_Display::unlock_display();
240 if( glx_fbcfgs_window ) XFree(glx_fbcfgs_window);
241 if( glx_fbcfgs_pbuffer) XFree(glx_fbcfgs_pbuffer);
242 if( glx_fbcfgs_pixmap ) XFree(glx_fbcfgs_pixmap);
245 UNSET_ALL_LOCKS(this)
248 int BC_WindowBase::initialize()
253 display_lock_owner = 0;
258 resend_event_window = 0;
270 xinerama_screens = 0;
275 translation_events = 0;
276 ctrl_mask = shift_mask = alt_mask = 0;
277 cursor_x = cursor_y = button_number = 0;
291 active_popup_menu = 0;
292 active_subwindow = 0;
296 _7segment_pixmaps = 0;
299 // next_repeat_id = 0;
301 current_font = MEDIUMFONT;
302 current_color = BLACK;
303 current_cursor = ARROW_CURSOR;
306 shared_bg_pixmap = 0;
309 window_type = MAIN_WINDOW;
310 translation_count = 0;
311 x_correction = y_correction = 0;
320 #ifdef HAVE_LIBXXF86VM
338 bold_smallfont_xft = 0;
339 bold_mediumfont_xft = 0;
340 bold_largefont_xft = 0;
342 completion_lock = new Condition(0, "BC_WindowBase::completion_lock");
344 // Need these right away since put_event is called before run_window sometimes.
345 event_lock = new Mutex("BC_WindowBase::event_lock");
346 event_condition = new Condition(0, "BC_WindowBase::event_condition");
347 init_lock = new Condition(0, "BC_WindowBase::init_lock");
350 cursor_timer = new Timer;
353 glx_fbcfgs_window = 0; n_fbcfgs_window = 0;
354 glx_fbcfgs_pbuffer = 0; n_fbcfgs_pbuffer = 0;
355 glx_fbcfgs_pixmap = 0; n_fbcfgs_pixmap = 0;
369 #define DEFAULT_EVENT_MASKS EnterWindowMask | \
372 ButtonReleaseMask | \
373 PointerMotionMask | \
377 int BC_WindowBase::create_window(BC_WindowBase *parent_window, const char *title,
378 int x, int y, int w, int h, int minw, int minh, int allow_resize,
379 int private_color, int hide, int bg_color, const char *display_name,
380 int window_type, BC_Pixmap *bg_pixmap, int group_it)
382 XSetWindowAttributes attr;
384 XSizeHints size_hints;
387 #ifdef HAVE_LIBXXF86VM
391 id = get_resources()->get_id();
392 if(parent_window) top_level = parent_window->top_level;
393 if( top_level ) lock_window("BC_WindowBase::create_window");
394 get_resources()->create_window_lock->lock("BC_WindowBase::create_window");
396 #ifdef HAVE_LIBXXF86VM
397 if(window_type == VIDMODE_SCALED_WINDOW)
398 closest_vm(&vm,&w,&h);
405 this->bg_color = bg_color;
406 this->window_type = window_type;
408 this->private_color = private_color;
409 this->parent_window = parent_window;
410 this->bg_pixmap = bg_pixmap;
411 this->allow_resize = allow_resize;
413 strcpy(this->display_name, display_name);
415 this->display_name[0] = 0;
418 if(bg_pixmap) shared_bg_pixmap = 1;
420 subwindows = new BC_SubWindowList;
422 if(window_type == MAIN_WINDOW)
425 parent_window = this;
429 display = BC_Display::get_display(display_name);
430 BC_Display::lock_display("BC_WindowBase::create_window");
431 // BC_Display::display_global->new_window(this);
434 // get the display connection
436 // This function must be the first Xlib
437 // function a multi-threaded program calls
439 display = init_display(display_name);
440 if( shm_completion_event < 0 ) shm_completion_event =
441 ShmCompletion + XShmGetEventBase(display);
443 lock_window("BC_WindowBase::create_window 1");
445 screen = DefaultScreen(display);
446 rootwin = RootWindow(display, screen);
447 // window placement boundaries
448 if( !xinerama_screens && XineramaIsActive(display) )
449 xinerama_info = XineramaQueryScreens(display, &xinerama_screens);
450 root_w = get_root_w(0);
451 root_h = get_root_h(0);
454 vis = get_glx_visual(display);
458 int mask = VisualDepthMask | VisualClassMask;
459 static XVisualInfo vinfo;
460 memset(&vinfo, 0, sizeof(vinfo));
462 vinfo.c_class = TrueColor;
464 XVisualInfo *vis_info = XGetVisualInfo(display, mask, &vinfo, &nitems);
465 vis = vis_info && nitems>0 ? vis_info[0].visual : 0;
466 if( vis_info ) XFree(vis_info);
469 vis = DefaultVisual(display, screen);
470 default_depth = DefaultDepth(display, screen);
472 client_byte_order = (*(const u_int32_t*)"a ") & 0x00000001;
473 server_byte_order = (XImageByteOrder(display) == MSBFirst) ? 0 : 1;
476 // This must be done before fonts to know if antialiasing is available.
479 if(resources->use_shm < 0) resources->initialize_display(this);
480 x_correction = BC_DisplayInfo::get_left_border();
481 y_correction = BC_DisplayInfo::get_top_border();
483 // clamp window placement
484 if(this->x + this->w + x_correction > root_w)
485 this->x = root_w - this->w - x_correction;
486 if(this->y + this->h + y_correction > root_h)
487 this->y = root_h - this->h - y_correction;
488 if(this->x < 0) this->x = 0;
489 if(this->y < 0) this->y = 0;
491 if(this->bg_color == -1)
492 this->bg_color = resources->get_bg_color();
494 // printf("bcwindowbase 1 %s\n", title);
495 // if(window_type == MAIN_WINDOW) sleep(1);
496 // printf("bcwindowbase 10\n");
502 mask = CWEventMask | CWBackPixel | CWColormap | CWCursor;
504 attr.event_mask = DEFAULT_EVENT_MASKS |
505 StructureNotifyMask |
509 attr.background_pixel = get_color(this->bg_color);
510 attr.colormap = cmap;
511 attr.cursor = get_cursor_struct(ARROW_CURSOR);
513 win = XCreateWindow(display, rootwin,
514 this->x, this->y, this->w, this->h, 0,
515 top_level->default_depth, InputOutput,
517 XGetNormalHints(display, win, &size_hints);
519 size_hints.flags = PSize | PMinSize | PMaxSize;
520 size_hints.width = this->w;
521 size_hints.height = this->h;
522 size_hints.min_width = allow_resize ? minw : this->w;
523 size_hints.max_width = allow_resize ? 32767 : this->w;
524 size_hints.min_height = allow_resize ? minh : this->h;
525 size_hints.max_height = allow_resize ? 32767 : this->h;
526 if(x > -BC_INFINITY && x < BC_INFINITY)
528 size_hints.flags |= PPosition;
529 size_hints.x = this->x;
530 size_hints.y = this->y;
532 XSetWMProperties(display, win, 0, 0, 0, 0, &size_hints, 0, 0);
535 #ifndef SINGLE_THREAD
536 clipboard = new BC_Clipboard(this);
537 clipboard->start_clipboard();
543 Atom ClientLeaderXAtom;
544 if (XGroupLeader == 0)
546 const char *instance_name = "cinelerra";
547 const char *class_name = "Cinelerra";
548 XClassHint *class_hints = XAllocClassHint();
549 class_hints->res_name = (char*)instance_name;
550 class_hints->res_class = (char*)class_name;
551 XSetClassHint(top_level->display, win, class_hints);
553 ClientLeaderXAtom = XInternAtom(display, "WM_CLIENT_LEADER", True);
554 XChangeProperty(display, win, ClientLeaderXAtom, XA_WINDOW, 32,
555 PropModeReplace, (unsigned char *)&XGroupLeader, true);
558 set_icon(get_resources()->default_icon);
561 #ifdef HAVE_LIBXXF86VM
562 if(window_type == VIDMODE_SCALED_WINDOW && vm != -1)
569 #ifdef HAVE_LIBXXF86VM
570 if(window_type == POPUP_WINDOW || window_type == VIDMODE_SCALED_WINDOW)
572 if(window_type == POPUP_WINDOW)
575 mask = CWEventMask | CWBackPixel | CWColormap |
576 CWOverrideRedirect | CWSaveUnder | CWCursor;
578 attr.event_mask = DEFAULT_EVENT_MASKS | ExposureMask |
579 KeyPressMask | KeyReleaseMask;
581 if(this->bg_color == -1)
582 this->bg_color = resources->get_bg_color();
583 attr.background_pixel = top_level->get_color(bg_color);
584 attr.colormap = top_level->cmap;
585 if(top_level->is_hourglass)
586 attr.cursor = top_level->get_cursor_struct(HOURGLASS_CURSOR);
588 attr.cursor = top_level->get_cursor_struct(ARROW_CURSOR);
589 attr.override_redirect = True;
590 attr.save_under = True;
592 win = XCreateWindow(top_level->display,
593 top_level->rootwin, this->x, this->y, this->w, this->h, 0,
594 top_level->default_depth, InputOutput, top_level->vis, mask,
596 top_level->add_popup(this);
599 if(window_type == SUB_WINDOW)
601 mask = CWEventMask | CWBackPixel | CWCursor;
602 attr.event_mask = DEFAULT_EVENT_MASKS;
603 attr.background_pixel = top_level->get_color(this->bg_color);
604 if(top_level->is_hourglass)
605 attr.cursor = top_level->get_cursor_struct(HOURGLASS_CURSOR);
607 attr.cursor = top_level->get_cursor_struct(ARROW_CURSOR);
608 win = XCreateWindow(top_level->display,
609 parent_window->win, this->x, this->y, this->w, this->h, 0,
610 top_level->default_depth, InputOutput, top_level->vis, mask,
613 if(!hidden) XMapWindow(top_level->display, win);
616 // Create pixmap for all windows
617 pixmap = new BC_Pixmap(this, this->w, this->h);
619 // Set up options for main window
620 if(window_type == MAIN_WINDOW)
622 if(get_resources()->bg_image && !bg_pixmap && bg_color < 0)
624 this->bg_pixmap = new BC_Pixmap(this,
625 get_resources()->bg_image,
629 if(!hidden) show_window();
633 draw_background(0, 0, this->w, this->h);
635 flash(-1, -1, -1, -1, 0);
637 // Set up options for popup window
638 #ifdef HAVE_LIBXXF86VM
639 if(window_type == POPUP_WINDOW || window_type == VIDMODE_SCALED_WINDOW)
641 if(window_type == POPUP_WINDOW)
645 if(!hidden) show_window();
647 get_resources()->create_window_lock->unlock();
653 Display* BC_WindowBase::init_display(const char *display_name)
657 if(display_name && display_name[0] == 0) display_name = NULL;
658 if((display = XOpenDisplay(display_name)) == NULL) {
659 printf("BC_WindowBase::init_display: cannot connect to X server %s\n",
661 if(getenv("DISPLAY") == NULL) {
662 printf(_("'DISPLAY' environment variable not set.\n"));
665 // Try again with default display.
666 if((display = XOpenDisplay(0)) == NULL) {
667 printf("BC_WindowBase::init_display: cannot connect to default X server.\n");
672 static int xsynch = -1;
674 const char *cp = getenv("CIN_XSYNCH");
675 xsynch = !cp ? 0 : atoi(cp);
678 XSynchronize(display, True);
683 Display* BC_WindowBase::get_display()
685 return top_level->display;
688 int BC_WindowBase::get_screen()
690 return top_level->screen;
693 int BC_WindowBase::run_window()
699 // Events may have been sent before run_window so can't initialize them here.
702 set_repeat(get_resources()->tooltip_delay);
703 BC_Display::display_global->new_window(this);
705 // If the first window created, run the display loop in this thread.
706 if(BC_Display::display_global->is_first(this))
708 BC_Display::unlock_display();
709 BC_Display::display_global->loop();
713 BC_Display::unlock_display();
714 completion_lock->lock("BC_WindowBase::run_window");
717 BC_Display::lock_display("BC_WindowBase::run_window");
718 BC_Display::display_global->delete_window(this);
720 unset_all_repeaters();
722 BC_Display::unlock_display();
724 #else // SINGLE_THREAD
729 set_repeat(get_resources()->tooltip_delay);
731 // Start X server events
732 event_thread = new BC_WindowEvents(this);
733 event_thread->start();
739 // Handle common events
744 unset_all_repeaters();
748 event_condition->reset();
749 common_events.remove_all_objects();
753 #endif // SINGLE_THREAD
758 int BC_WindowBase::get_key_masks(unsigned int key_state)
760 // printf("BC_WindowBase::get_key_masks %llx\n",
761 // event->xkey.state);
762 ctrl_mask = (key_state & ControlMask) ? 1 : 0; // ctrl key down
763 shift_mask = (key_state & ShiftMask) ? 1 : 0; // shift key down
764 alt_mask = (key_state & Mod1Mask) ? 1 : 0; // alt key down
769 void BC_WindowBase::add_keyboard_listener(int(BC_WindowBase::*handler)(BC_WindowBase *))
771 BC_KeyboardHandlerLock set;
772 BC_KeyboardHandler::listeners.append(new BC_KeyboardHandler(handler, this));
775 void BC_WindowBase::del_keyboard_listener(int(BC_WindowBase::*handler)(BC_WindowBase *))
777 BC_KeyboardHandlerLock set;
778 int i = BC_KeyboardHandler::listeners.size();
779 while( --i >= 0 && BC_KeyboardHandler::listeners[i]->handler!=handler );
780 if( i >= 0 ) BC_KeyboardHandler::listeners.remove_object_number(i);
783 int BC_KeyboardHandler::run_event(BC_WindowBase *wp)
785 int result = (win->*handler)(wp);
789 int BC_KeyboardHandler::run_listeners(BC_WindowBase *wp)
792 BC_KeyboardHandlerLock set;
793 for( int i=0; !result && i<listeners.size(); ++i ) {
794 BC_KeyboardHandler *listener = listeners[i];
795 result = listener->run_event(wp);
800 void BC_KeyboardHandler::kill_grabs()
802 BC_KeyboardHandlerLock set;
803 for( int i=0; i<listeners.size(); ++i ) {
804 BC_WindowBase *win = listeners[i]->win;
805 if( win->get_window_type() != POPUP_WINDOW ) continue;
806 ((BC_Popup *)win)->ungrab_keyboard();
810 void BC_ActiveBitmaps::reque(XEvent *event)
812 XShmCompletionEvent *shm_ev = (XShmCompletionEvent *)event;
813 ShmSeg shmseg = shm_ev->shmseg;
814 Drawable drawable = shm_ev->drawable;
815 //printf("BC_BitmapImage::reque %08lx\n",shmseg);
816 active_lock.lock("BC_BitmapImage::reque");
817 BC_BitmapImage *bfr = first;
818 while( bfr && bfr->get_shmseg() != shmseg ) bfr = bfr->next;
819 if( bfr && bfr->drawable == drawable )
821 active_lock.unlock();
823 // sadly, X reports two drawable completions and creates false reporting, so no boobytrap
824 // printf("BC_BitmapImage::reque missed shmseg %08x, drawable %08x\n",
825 // (int)shmseg, (int)drawable);
828 if( bfr->drawable != drawable ) return;
829 if( bfr->is_zombie() ) { --BC_Bitmap::zombies; delete bfr; return; }
830 bfr->bitmap->reque(bfr);
833 void BC_ActiveBitmaps::insert(BC_BitmapImage *bfr, Drawable pixmap)
835 active_lock.lock("BC_BitmapImage::insert");
836 bfr->drawable = pixmap;
838 active_lock.unlock();
841 void BC_ActiveBitmaps::remove_buffers(BC_WindowBase *wdw)
843 active_lock.lock("BC_ActiveBitmaps::remove");
844 for( BC_BitmapImage *nxt=0, *bfr=first; bfr; bfr=nxt ) {
846 if( bfr->is_zombie() ) { --BC_Bitmap::zombies; delete bfr; continue; }
847 if( bfr->bitmap->parent_window == wdw ) remove_pointer(bfr);
849 active_lock.unlock();
852 BC_ActiveBitmaps::BC_ActiveBitmaps()
856 BC_ActiveBitmaps::~BC_ActiveBitmaps()
862 int BC_WindowBase::keysym_lookup(XEvent *event)
864 for( int i = 0; i < KEYPRESSLEN; ++i ) keys_return[i] = 0;
865 for( int i = 0; i < 4; ++i ) wkey_string[i] = 0;
867 if( event->xany.send_event && !event->xany.serial ) {
868 keysym = (KeySym) event->xkey.keycode;
869 keys_return[0] = keysym;
872 wkey_string_length = 0;
874 if( input_context ) {
876 wkey_string_length = XwcLookupString(input_context,
877 (XKeyEvent*)event, wkey, 4, &keysym, 0);
878 for( int i=0; i<wkey_string_length; ++i )
879 wkey_string[i] = wkey[i];
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 */
1274 key_pressed = keysym & 0xff;
1275 #ifdef X_HAVE_UTF8_STRING
1276 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1281 #ifdef X_HAVE_UTF8_STRING
1283 key_pressed_utf8 = keys_return;
1288 if( top_level == this )
1289 result = BC_KeyboardHandler::run_listeners(this);
1291 //printf("BC_WindowBase::dispatch_event %d %d %x\n", shift_down(), alt_down(), key_pressed);
1293 result = dispatch_keypress_event();
1294 // Handle some default keypresses
1297 if(key_pressed == 'w' ||
1306 XLookupString((XKeyEvent*)event, keys_return, 1, &keysym, 0);
1307 dispatch_keyrelease_event();
1308 // printf("BC_WindowBase::dispatch_event KeyRelease keysym=0x%x keystate=0x%lld\n",
1309 // keysym, event->xkey.state);
1313 if( event->xcrossing.mode != NotifyNormal ) break;
1315 event_win = event->xany.window;
1316 dispatch_cursor_leave();
1320 if( event->xcrossing.mode != NotifyNormal ) break;
1322 if( !cursor_entered ) {
1323 for( int i=0; i<popups.size(); ++i ) { // popups always take focus
1324 if( popups[i]->win == event->xcrossing.window )
1327 if( !cursor_entered && get_resources()->grab_input_focus &&
1328 !event->xcrossing.focus && event->xcrossing.window == win ) {
1331 if( cursor_entered )
1334 event_win = event->xany.window;
1335 cursor_x = event->xcrossing.x;
1336 cursor_y = event->xcrossing.y;
1337 dispatch_cursor_enter();
1343 //printf("100 %s %p %d\n", title, event, event->type);
1344 //if(event->type != ClientMessage) dump();
1346 #ifndef SINGLE_THREAD
1349 if( resend_event_window ) {
1350 resend_event_window->put_event(event);
1351 resend_event_window = 0;
1357 // if(done) completion_lock->unlock();
1360 if(debug) printf("BC_WindowBase::dispatch_event this=%p %d\n", this, __LINE__);
1364 int BC_WindowBase::dispatch_expose_event()
1367 for(int i = 0; i < subwindows->total && !result; i++)
1369 result = subwindows->values[i]->dispatch_expose_event();
1372 // Propagate to user
1373 if(!result) expose_event();
1377 int BC_WindowBase::dispatch_resize_event(int w, int h)
1379 // Can't store new w and h until the event is handles
1380 // because bcfilebox depends on the old w and h to
1381 // reposition widgets.
1382 if( window_type == MAIN_WINDOW ) {
1387 pixmap = new BC_Pixmap(this, w, h);
1388 clear_box(0, 0, w, h);
1391 // Propagate to subwindows
1392 for(int i = 0; i < subwindows->total; i++) {
1393 subwindows->values[i]->dispatch_resize_event(w, h);
1396 // Propagate to user
1399 if( window_type == MAIN_WINDOW ) {
1408 int BC_WindowBase::dispatch_flash()
1411 for(int i = 0; i < subwindows->total; i++)
1412 subwindows->values[i]->dispatch_flash();
1416 int BC_WindowBase::dispatch_translation_event()
1418 translation_events = 0;
1419 if(window_type == MAIN_WINDOW)
1423 x = last_translate_x;
1424 y = last_translate_y;
1425 // Correct for window manager offsets
1430 for(int i = 0; i < subwindows->total; i++)
1432 subwindows->values[i]->dispatch_translation_event();
1435 translation_event();
1439 int BC_WindowBase::dispatch_motion_event()
1444 if(top_level == this)
1447 event_win = last_motion_win;
1448 get_key_masks(last_motion_state);
1451 if(get_button_down() && !active_menubar && !active_popup_menu)
1455 cursor_x = last_motion_x;
1456 cursor_y = last_motion_y;
1457 result = dispatch_drag_motion();
1461 (last_motion_x < drag_x1 || last_motion_x >= drag_x2 ||
1462 last_motion_y < drag_y1 || last_motion_y >= drag_y2))
1467 result = dispatch_drag_start();
1471 cursor_x = last_motion_x;
1472 cursor_y = last_motion_y;
1474 // printf("BC_WindowBase::dispatch_motion_event %d %p %p %p\n",
1477 // active_popup_menu,
1478 // active_subwindow);
1480 if(active_menubar && !result) result = active_menubar->dispatch_motion_event();
1481 if(active_popup_menu && !result) result = active_popup_menu->dispatch_motion_event();
1482 if(active_subwindow && !result) result = active_subwindow->dispatch_motion_event();
1485 // Dispatch in stacking order
1486 for(int i = subwindows->size() - 1; i >= 0 && !result; i--)
1488 result = subwindows->values[i]->dispatch_motion_event();
1491 if(!result) result = cursor_motion_event(); // give to user
1495 int BC_WindowBase::dispatch_keypress_event()
1498 if(top_level == this)
1500 if(active_subwindow) result = active_subwindow->dispatch_keypress_event();
1503 for(int i = 0; i < subwindows->total && !result; i++)
1505 result = subwindows->values[i]->dispatch_keypress_event();
1508 if(!result) result = keypress_event();
1513 int BC_WindowBase::dispatch_keyrelease_event()
1516 if(top_level == this)
1518 if(active_subwindow) result = active_subwindow->dispatch_keyrelease_event();
1521 for(int i = 0; i < subwindows->total && !result; i++)
1523 result = subwindows->values[i]->dispatch_keyrelease_event();
1526 if(!result) result = keyrelease_event();
1531 int BC_WindowBase::dispatch_focus_in()
1533 for(int i = 0; i < subwindows->total; i++)
1535 subwindows->values[i]->dispatch_focus_in();
1543 int BC_WindowBase::dispatch_focus_out()
1545 for(int i = 0; i < subwindows->total; i++)
1547 subwindows->values[i]->dispatch_focus_out();
1555 int BC_WindowBase::get_has_focus()
1557 return top_level->has_focus;
1560 int BC_WindowBase::get_deleting()
1562 if(is_deleting) return 1;
1563 if(parent_window && parent_window->get_deleting()) return 1;
1567 int BC_WindowBase::dispatch_button_press()
1572 if(top_level == this)
1574 if(active_menubar) result = active_menubar->dispatch_button_press();
1575 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_press();
1576 if(active_subwindow && !result) result = active_subwindow->dispatch_button_press();
1579 for(int i = 0; i < subwindows->total && !result; i++)
1581 result = subwindows->values[i]->dispatch_button_press();
1584 if(!result) result = button_press_event();
1590 int BC_WindowBase::dispatch_button_release()
1593 if(top_level == this)
1595 if(active_menubar) result = active_menubar->dispatch_button_release();
1596 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_release();
1597 if(active_subwindow && !result) result = active_subwindow->dispatch_button_release();
1598 if(!result && button_number != 4 && button_number != 5)
1599 result = dispatch_drag_stop();
1602 for(int i = 0; i < subwindows->total && !result; i++)
1604 result = subwindows->values[i]->dispatch_button_release();
1609 result = button_release_event();
1616 int BC_WindowBase::dispatch_repeat_event(int64_t duration)
1619 // all repeat event handlers get called and decide based on activity and duration
1620 // whether to respond
1621 for(int i = 0; i < subwindows->total; i++)
1623 subwindows->values[i]->dispatch_repeat_event(duration);
1627 repeat_event(duration);
1631 // Unlock next repeat signal
1632 if(window_type == MAIN_WINDOW)
1634 #ifdef SINGLE_THREAD
1635 BC_Display::display_global->unlock_repeaters(duration);
1637 for(int i = 0; i < repeaters.total; i++)
1639 if(repeaters.values[i]->delay == duration)
1641 repeaters.values[i]->repeat_lock->unlock();
1649 void BC_WindowBase::unhide_cursor()
1654 if(top_level->is_hourglass)
1655 set_cursor(HOURGLASS_CURSOR, 1, 0);
1657 set_cursor(current_cursor, 1, 0);
1659 cursor_timer->update();
1663 void BC_WindowBase::update_video_cursor()
1665 if(video_on && !is_transparent)
1667 if(cursor_timer->get_difference() > VIDEO_CURSOR_TIMEOUT && !is_transparent)
1670 set_cursor(TRANSPARENT_CURSOR, 1, 1);
1671 cursor_timer->update();
1676 cursor_timer->update();
1681 int BC_WindowBase::dispatch_cursor_leave()
1685 for(int i = 0; i < subwindows->total; i++)
1687 subwindows->values[i]->dispatch_cursor_leave();
1690 cursor_leave_event();
1694 int BC_WindowBase::dispatch_cursor_enter()
1700 if(active_menubar) result = active_menubar->dispatch_cursor_enter();
1701 if(!result && active_popup_menu) result = active_popup_menu->dispatch_cursor_enter();
1702 if(!result && active_subwindow) result = active_subwindow->dispatch_cursor_enter();
1704 for(int i = 0; !result && i < subwindows->total; i++)
1706 result = subwindows->values[i]->dispatch_cursor_enter();
1709 if(!result) result = cursor_enter_event();
1713 int BC_WindowBase::cursor_enter_event()
1718 int BC_WindowBase::cursor_leave_event()
1723 int BC_WindowBase::close_event()
1729 int BC_WindowBase::dispatch_drag_start()
1732 if(active_menubar) result = active_menubar->dispatch_drag_start();
1733 if(!result && active_popup_menu) result = active_popup_menu->dispatch_drag_start();
1734 if(!result && active_subwindow) result = active_subwindow->dispatch_drag_start();
1736 for(int i = 0; i < subwindows->total && !result; i++)
1738 result = subwindows->values[i]->dispatch_drag_start();
1741 if(!result) result = is_dragging = drag_start_event();
1745 int BC_WindowBase::dispatch_drag_stop()
1749 for(int i = 0; i < subwindows->total && !result; i++)
1751 result = subwindows->values[i]->dispatch_drag_stop();
1754 if(is_dragging && !result)
1764 int BC_WindowBase::dispatch_drag_motion()
1767 for(int i = 0; i < subwindows->total && !result; i++)
1769 result = subwindows->values[i]->dispatch_drag_motion();
1772 if(is_dragging && !result)
1774 drag_motion_event();
1782 int BC_WindowBase::show_tooltip(const char *text, int x, int y, int w, int h)
1785 int forced = !text ? force_tooltip : 1;
1786 if( !text ) text = tooltip_text;
1787 if( !text || (!forced && !get_resources()->tooltips_enabled) ) {
1788 top_level->hide_tooltip();
1792 if(w < 0) w = get_text_width(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1793 if(h < 0) h = get_text_height(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1794 // default x,y (win relative)
1795 if( x < 0 ) x = get_w();
1796 if( y < 0 ) y = get_h();
1798 get_root_coordinates(x, y, &wx, &wy);
1799 // keep the tip inside the window/display
1800 int x0 = top_level->get_x(), x1 = x0 + top_level->get_w();
1801 int x2 = top_level->get_screen_x(0, -1) + top_level->get_screen_w(0, -1);
1802 if( x1 > x2 ) x1 = x2;
1803 if( wx < x0 ) wx = x0;
1804 if( wx >= (x1-=w) ) wx = x1;
1805 int y0 = top_level->get_y(), y1 = y0 + top_level->get_h();
1806 int y2 = top_level->get_root_h(0);
1807 if( y1 > y2 ) y1 = y2;
1808 if( wy < y0 ) wy = y0;
1809 if( wy >= (y1-=h) ) wy = y1;
1810 // avoid tip under cursor (flickers)
1812 get_abs_cursor(abs_x,abs_y, 0);
1813 if( wx < abs_x && abs_x < wx+w && wy < abs_y && abs_y < wy+h ) {
1814 if( wx-abs_x < wy-abs_y )
1821 tooltip_popup = new BC_Popup(top_level, wx, wy, w, h,
1822 get_resources()->tooltip_bg_color);
1825 tooltip_popup->reposition_window(wx, wy, w, h);
1828 tooltip_popup->flash();
1829 tooltip_popup->flush();
1833 int BC_WindowBase::hide_tooltip()
1836 for(int i = 0; i < subwindows->total; i++)
1838 subwindows->values[i]->hide_tooltip();
1844 delete tooltip_popup;
1850 const char *BC_WindowBase::get_tooltip()
1852 return tooltip_text;
1855 int BC_WindowBase::set_tooltip(const char *text)
1857 tooltip_text = text;
1859 // Update existing tooltip if it is visible
1863 tooltip_popup->flash();
1867 // signal the event handler to repeat
1868 int BC_WindowBase::set_repeat(int64_t duration)
1872 printf("BC_WindowBase::set_repeat duration=%jd\n", duration);
1875 if(window_type != MAIN_WINDOW) return top_level->set_repeat(duration);
1877 #ifdef SINGLE_THREAD
1878 BC_Display::display_global->set_repeat(this, duration);
1880 // test repeater database for duplicates
1881 for(int i = 0; i < repeaters.total; i++)
1884 if(repeaters.values[i]->delay == duration)
1886 repeaters.values[i]->start_repeating(this);
1891 BC_Repeater *repeater = new BC_Repeater(this, duration);
1892 repeater->initialize();
1893 repeaters.append(repeater);
1894 repeater->start_repeating();
1899 int BC_WindowBase::unset_repeat(int64_t duration)
1901 if(window_type != MAIN_WINDOW) return top_level->unset_repeat(duration);
1903 #ifdef SINGLE_THREAD
1904 BC_Display::display_global->unset_repeat(this, duration);
1906 for(int i = 0; i < repeaters.total; i++)
1908 if(repeaters.values[i]->delay == duration)
1910 repeaters.values[i]->stop_repeating();
1918 int BC_WindowBase::unset_all_repeaters()
1920 #ifdef SINGLE_THREAD
1921 BC_Display::display_global->unset_all_repeaters(this);
1923 for(int i = 0; i < repeaters.total; i++)
1925 repeaters.values[i]->stop_repeating();
1927 repeaters.remove_all_objects();
1932 // long BC_WindowBase::get_repeat_id()
1934 // return top_level->next_repeat_id++;
1937 XEvent *BC_WindowBase::new_xevent()
1939 XEvent *event = new XEvent;
1940 memset(event, 0, sizeof(*event));
1944 #ifndef SINGLE_THREAD
1945 int BC_WindowBase::arm_repeat(int64_t duration)
1947 XEvent *event = new_xevent();
1948 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
1949 ptr->type = ClientMessage;
1950 ptr->message_type = RepeaterXAtom;
1952 ptr->data.l[0] = duration;
1954 // Couldn't use XSendEvent since it locked up randomly.
1960 int BC_WindowBase::receive_custom_xatoms(xatom_event *event)
1965 int BC_WindowBase::send_custom_xatom(xatom_event *event)
1967 #ifndef SINGLE_THREAD
1968 XEvent *myevent = new_xevent();
1969 XClientMessageEvent *ptr = (XClientMessageEvent*)myevent;
1970 ptr->type = ClientMessage;
1971 ptr->message_type = event->message_type;
1972 ptr->format = event->format;
1973 ptr->data.l[0] = event->data.l[0];
1974 ptr->data.l[1] = event->data.l[1];
1975 ptr->data.l[2] = event->data.l[2];
1976 ptr->data.l[3] = event->data.l[3];
1977 ptr->data.l[4] = event->data.l[4];
1986 Atom BC_WindowBase::create_xatom(const char *atom_name)
1988 return XInternAtom(display, atom_name, False);
1991 int BC_WindowBase::get_atoms()
1993 SetDoneXAtom = XInternAtom(display, "BC_REPEAT_EVENT", False);
1994 RepeaterXAtom = XInternAtom(display, "BC_CLOSE_EVENT", False);
1995 DestroyAtom = XInternAtom(display, "BC_DESTROY_WINDOW", False);
1996 DelWinXAtom = XInternAtom(display, "WM_DELETE_WINDOW", False);
1997 if( (ProtoXAtom = XInternAtom(display, "WM_PROTOCOLS", False)) != 0 )
1998 XChangeProperty(display, win, ProtoXAtom, XA_ATOM, 32,
1999 PropModeReplace, (unsigned char *)&DelWinXAtom, True);
2005 void BC_WindowBase::init_cursors()
2007 arrow_cursor = XCreateFontCursor(display, XC_top_left_arrow);
2008 cross_cursor = XCreateFontCursor(display, XC_crosshair);
2009 ibeam_cursor = XCreateFontCursor(display, XC_xterm);
2010 vseparate_cursor = XCreateFontCursor(display, XC_sb_v_double_arrow);
2011 hseparate_cursor = XCreateFontCursor(display, XC_sb_h_double_arrow);
2012 move_cursor = XCreateFontCursor(display, XC_fleur);
2013 left_cursor = XCreateFontCursor(display, XC_sb_left_arrow);
2014 right_cursor = XCreateFontCursor(display, XC_sb_right_arrow);
2015 upright_arrow_cursor = XCreateFontCursor(display, XC_arrow);
2016 upleft_resize_cursor = XCreateFontCursor(display, XC_top_left_corner);
2017 upright_resize_cursor = XCreateFontCursor(display, XC_top_right_corner);
2018 downleft_resize_cursor = XCreateFontCursor(display, XC_bottom_left_corner);
2019 downright_resize_cursor = XCreateFontCursor(display, XC_bottom_right_corner);
2020 hourglass_cursor = XCreateFontCursor(display, XC_watch);
2021 grabbed_cursor = create_grab_cursor();
2023 static char cursor_data[] = { 0,0,0,0, 0,0,0,0 };
2024 Colormap colormap = DefaultColormap(display, screen);
2025 Pixmap pixmap_bottom = XCreateBitmapFromData(display,
2026 rootwin, cursor_data, 8, 8);
2027 XColor black, dummy;
2028 XAllocNamedColor(display, colormap, "black", &black, &dummy);
2029 transparent_cursor = XCreatePixmapCursor(display,
2030 pixmap_bottom, pixmap_bottom, &black, &black, 0, 0);
2031 // XDefineCursor(display, win, transparent_cursor);
2032 XFreePixmap(display, pixmap_bottom);
2035 int BC_WindowBase::evaluate_color_model(int client_byte_order, int server_byte_order, int depth)
2037 int color_model = BC_TRANSPARENCY;
2041 color_model = BC_RGB8;
2044 color_model = (server_byte_order == client_byte_order) ? BC_RGB565 : BC_BGR565;
2047 color_model = server_byte_order ? BC_BGR888 : BC_RGB888;
2050 color_model = server_byte_order ? BC_BGR8888 : BC_ARGB8888;
2056 int BC_WindowBase::init_colors()
2059 current_color_value = current_color_pixel = 0;
2061 // Get the real depth
2064 ximage = XCreateImage(top_level->display,
2065 top_level->vis, top_level->default_depth,
2066 ZPixmap, 0, data, 16, 16, 8, 0);
2067 bits_per_pixel = ximage->bits_per_pixel;
2068 XDestroyImage(ximage);
2070 color_model = evaluate_color_model(client_byte_order,
2073 // Get the color model
2078 cmap = XCreateColormap(display, rootwin, vis, AllocNone);
2079 create_private_colors();
2082 cmap = DefaultColormap(display, screen);
2083 create_shared_colors();
2086 allocate_color_table();
2090 //cmap = DefaultColormap(display, screen);
2091 cmap = XCreateColormap(display, rootwin, vis, AllocNone );
2097 int BC_WindowBase::create_private_colors()
2102 for(int i = 0; i < 255; i++)
2104 color = (i & 0xc0) << 16;
2105 color += (i & 0x38) << 10;
2106 color += (i & 0x7) << 5;
2107 color_table[i][0] = color;
2109 create_shared_colors(); // overwrite the necessary colors on the table
2114 int BC_WindowBase::create_color(int color)
2116 if(total_colors == 256)
2118 // replace the closest match with an exact match
2119 color_table[get_color_rgb8(color)][0] = color;
2123 // add the color to the table
2124 color_table[total_colors][0] = color;
2130 int BC_WindowBase::create_shared_colors()
2132 create_color(BLACK);
2133 create_color(WHITE);
2135 create_color(LTGREY);
2136 create_color(MEGREY);
2137 create_color(MDGREY);
2138 create_color(DKGREY);
2140 create_color(LTCYAN);
2141 create_color(MECYAN);
2142 create_color(MDCYAN);
2143 create_color(DKCYAN);
2145 create_color(LTGREEN);
2146 create_color(GREEN);
2147 create_color(DKGREEN);
2149 create_color(LTPINK);
2153 create_color(LTBLUE);
2155 create_color(DKBLUE);
2157 create_color(LTYELLOW);
2158 create_color(MEYELLOW);
2159 create_color(MDYELLOW);
2160 create_color(DKYELLOW);
2162 create_color(LTPURPLE);
2163 create_color(MEPURPLE);
2164 create_color(MDPURPLE);
2165 create_color(DKPURPLE);
2167 create_color(FGGREY);
2168 create_color(MNBLUE);
2169 create_color(ORANGE);
2170 create_color(FTGREY);
2175 Cursor BC_WindowBase::create_grab_cursor()
2177 int iw = 23, iw1 = iw-1, iw2 = iw/2;
2178 int ih = 23, ih1 = ih-1, ih2 = ih/2;
2179 VFrame grab(iw,ih,BC_RGB888);
2181 grab.set_pixel_color(RED); // fg
2182 grab.draw_smooth(iw2,0, iw1,0, iw1,ih2);
2183 grab.draw_smooth(iw1,ih2, iw1,ih1, iw2,ih1);
2184 grab.draw_smooth(iw2,ih1, 0,ih1, 0,ih2);
2185 grab.draw_smooth(0,ih2, 0,0, iw2,0);
2186 grab.set_pixel_color(WHITE); // bg
2187 grab.draw_line(0,ih2, iw2-2,ih2);
2188 grab.draw_line(iw2+2,ih2, iw1,ih2);
2189 grab.draw_line(iw2,0, iw2,ih2-2);
2190 grab.draw_line(iw2,ih2+2, iw2,ih1);
2192 int bpl = (iw+7)/8, isz = bpl * ih;
2193 char img[isz]; memset(img, 0, isz);
2194 char msk[isz]; memset(msk, 0, isz);
2195 unsigned char **rows = grab.get_rows();
2196 for( int iy=0; iy<ih; ++iy ) {
2197 char *op = img + iy*bpl;
2198 char *mp = msk + iy*bpl;
2199 unsigned char *ip = rows[iy];
2200 for( int ix=0; ix<iw; ++ix,ip+=3 ) {
2201 if( ip[0] ) mp[ix>>3] |= (1<<(ix&7));
2202 if( !ip[1] ) op[ix>>3] |= (1<<(ix&7));
2205 unsigned long white_pix = WhitePixel(display, screen);
2206 unsigned long black_pix = BlackPixel(display, screen);
2207 Pixmap img_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2208 img, iw,ih, white_pix,black_pix, 1);
2209 Pixmap msk_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2210 msk, iw,ih, white_pix,black_pix, 1);
2213 fc.flags = bc.flags = DoRed | DoGreen | DoBlue;
2214 fc.red = 0xffff; fc.green = fc.blue = 0; // fg
2215 bc.red = 0xffff; bc.green = 0xffff; bc.blue = 0x0000; // bg
2216 Cursor cursor = XCreatePixmapCursor(display, img_xpm,msk_xpm, &fc,&bc, iw2,ih2);
2217 XFreePixmap(display, img_xpm);
2218 XFreePixmap(display, msk_xpm);
2222 int BC_WindowBase::allocate_color_table()
2224 int red, green, blue, color;
2227 for(int i = 0; i < total_colors; i++)
2229 color = color_table[i][0];
2230 red = (color & 0xFF0000) >> 16;
2231 green = (color & 0x00FF00) >> 8;
2232 blue = color & 0xFF;
2234 col.flags = DoRed | DoGreen | DoBlue;
2235 col.red = red<<8 | red;
2236 col.green = green<<8 | green;
2237 col.blue = blue<<8 | blue;
2239 XAllocColor(display, cmap, &col);
2240 color_table[i][1] = col.pixel;
2243 XInstallColormap(display, cmap);
2247 int BC_WindowBase::init_window_shape()
2249 if(bg_pixmap && bg_pixmap->use_alpha())
2251 XShapeCombineMask(top_level->display,
2252 this->win, ShapeBounding, 0, 0,
2253 bg_pixmap->get_alpha(), ShapeSet);
2259 int BC_WindowBase::init_gc()
2261 unsigned long gcmask;
2262 gcmask = GCFont | GCGraphicsExposures;
2265 gcvalues.font = mediumfont->fid; // set the font
2266 gcvalues.graphics_exposures = 0; // prevent expose events for every redraw
2267 gc = XCreateGC(display, rootwin, gcmask, &gcvalues);
2269 // gcmask = GCCapStyle | GCJoinStyle;
2270 // XGetGCValues(display, gc, gcmask, &gcvalues);
2271 // printf("BC_WindowBase::init_gc %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2275 int BC_WindowBase::init_fonts()
2277 if( !(smallfont = XLoadQueryFont(display, _(resources->small_font))) )
2278 if( !(smallfont = XLoadQueryFont(display, _(resources->small_font2))) )
2279 smallfont = XLoadQueryFont(display, "fixed");
2280 if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font))) )
2281 if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font2))) )
2282 mediumfont = XLoadQueryFont(display, "fixed");
2283 if( !(largefont = XLoadQueryFont(display, _(resources->large_font))) )
2284 if( !(largefont = XLoadQueryFont(display, _(resources->large_font2))) )
2285 largefont = XLoadQueryFont(display, "fixed");
2286 if( !(bigfont = XLoadQueryFont(display, _(resources->big_font))) )
2287 if( !(bigfont = XLoadQueryFont(display, _(resources->big_font2))) )
2288 bigfont = XLoadQueryFont(display, "fixed");
2290 if((clockfont = XLoadQueryFont(display, _(resources->clock_font))) == NULL)
2291 if((clockfont = XLoadQueryFont(display, _(resources->clock_font2))) == NULL)
2292 clockfont = XLoadQueryFont(display, "fixed");
2295 if(get_resources()->use_fontset)
2300 // FIXME: should check the m,d,n values
2301 smallfontset = XCreateFontSet(display, resources->small_fontset, &m, &n, &d);
2303 smallfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2304 mediumfontset = XCreateFontSet(display, resources->medium_fontset, &m, &n, &d);
2305 if( !mediumfontset )
2306 mediumfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2307 largefontset = XCreateFontSet(display, resources->large_fontset, &m, &n, &d);
2309 largefontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2310 bigfontset = XCreateFontSet(display, resources->big_fontset, &m, &n, &d);
2312 bigfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2313 clockfontset = XCreateFontSet(display, resources->clock_fontset, &m, &n, &d);
2315 clockfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2316 if(clockfontset && bigfontset && largefontset && mediumfontset && smallfontset) {
2317 curr_fontset = mediumfontset;
2318 get_resources()->use_fontset = 1;
2322 get_resources()->use_fontset = 0;
2329 void BC_WindowBase::init_xft()
2332 if( !get_resources()->use_xft ) return;
2333 // apparently, xft is not reentrant, more than this is needed
2334 static Mutex xft_init_lock("BC_WindowBase::xft_init_lock", 0);
2335 xft_init_lock.lock("BC_WindowBase::init_xft");
2336 if(!(smallfont_xft =
2337 (resources->small_font_xft[0] == '-' ?
2338 xftFontOpenXlfd(display, screen, resources->small_font_xft) :
2339 xftFontOpenName(display, screen, resources->small_font_xft))) )
2340 if(!(smallfont_xft =
2341 xftFontOpenXlfd(display, screen, resources->small_font_xft2)))
2342 smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2343 if(!(mediumfont_xft =
2344 (resources->medium_font_xft[0] == '-' ?
2345 xftFontOpenXlfd(display, screen, resources->medium_font_xft) :
2346 xftFontOpenName(display, screen, resources->medium_font_xft))) )
2347 if(!(mediumfont_xft =
2348 xftFontOpenXlfd(display, screen, resources->medium_font_xft2)))
2349 mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2350 if(!(largefont_xft =
2351 (resources->large_font_xft[0] == '-' ?
2352 xftFontOpenXlfd(display, screen, resources->large_font_xft) :
2353 xftFontOpenName(display, screen, resources->large_font_xft))) )
2354 if(!(largefont_xft =
2355 xftFontOpenXlfd(display, screen, resources->large_font_xft2)))
2356 largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2358 (resources->big_font_xft[0] == '-' ?
2359 xftFontOpenXlfd(display, screen, resources->big_font_xft) :
2360 xftFontOpenName(display, screen, resources->big_font_xft))) )
2362 xftFontOpenXlfd(display, screen, resources->big_font_xft2)))
2363 bigfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2364 if(!(clockfont_xft =
2365 (resources->clock_font_xft[0] == '-' ?
2366 xftFontOpenXlfd(display, screen, resources->clock_font_xft) :
2367 xftFontOpenName(display, screen, resources->clock_font_xft))) )
2368 clockfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2371 if(!(bold_smallfont_xft =
2372 (resources->small_b_font_xft[0] == '-' ?
2373 xftFontOpenXlfd(display, screen, resources->small_b_font_xft) :
2374 xftFontOpenName(display, screen, resources->small_b_font_xft))) )
2375 bold_smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2376 if(!(bold_mediumfont_xft =
2377 (resources->medium_b_font_xft[0] == '-' ?
2378 xftFontOpenXlfd(display, screen, resources->medium_b_font_xft) :
2379 xftFontOpenName(display, screen, resources->medium_b_font_xft))) )
2380 bold_mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2381 if(!(bold_largefont_xft =
2382 (resources->large_b_font_xft[0] == '-' ?
2383 xftFontOpenXlfd(display, screen, resources->large_b_font_xft) :
2384 xftFontOpenName(display, screen, resources->large_b_font_xft))) )
2385 bold_largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2387 if( !smallfont_xft || !mediumfont_xft || !largefont_xft || !bigfont_xft ||
2388 !bold_largefont_xft || !bold_mediumfont_xft || !bold_largefont_xft ||
2390 printf("BC_WindowBase::init_fonts: no xft fonts found:"
2391 " %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n",
2392 resources->small_font_xft, smallfont_xft,
2393 resources->medium_font_xft, mediumfont_xft,
2394 resources->large_font_xft, largefont_xft,
2395 resources->big_font_xft, bigfont_xft,
2396 resources->clock_font_xft, clockfont_xft,
2397 resources->small_b_font_xft, bold_smallfont_xft,
2398 resources->medium_b_font_xft, bold_mediumfont_xft,
2399 resources->large_b_font_xft, bold_largefont_xft);
2400 get_resources()->use_xft = 0;
2403 // _XftDisplayInfo needs a lock.
2404 xftDefaultHasRender(display);
2405 xft_init_lock.unlock();
2409 void BC_WindowBase::init_glyphs()
2411 // draw all ascii char glyphs
2412 // There are problems with some/my graphics boards/drivers
2413 // which cause some glyphs to be munged if draws occur while
2414 // the font is being loaded. This code fills the font caches
2415 // by drawing all the ascii glyphs before the system starts.
2416 // Not a fix, but much better than nothing.
2417 static int inited = 0;
2418 if( inited ) return;
2419 XGrabServer(display);
2422 int cur_font = current_font;
2423 // locale encodings, needed glyphs to be preloaded
2424 const char *text = _( // ascii 0x20...0x7e
2425 " !\"#$%&'()*+,-./0123456789:;<=>?"
2426 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
2427 "`abcdefghijklmnopqrstuvwxyz{|}~");
2428 for( int font=SMALLFONT; font<=LARGEFONT; ++font ) {
2430 draw_text(5,5, text);
2433 XUngrabServer(display);
2436 void BC_WindowBase::init_im()
2438 XIMStyles *xim_styles;
2441 if(!(input_method = XOpenIM(display, NULL, NULL, NULL)))
2443 printf("BC_WindowBase::init_im: Could not open input method.\n");
2446 if(XGetIMValues(input_method, XNQueryInputStyle, &xim_styles, NULL) ||
2449 printf("BC_WindowBase::init_im: Input method doesn't support any styles.\n");
2450 XCloseIM(input_method);
2455 for(int z = 0; z < xim_styles->count_styles; z++)
2457 if(xim_styles->supported_styles[z] == (XIMPreeditNothing | XIMStatusNothing))
2459 xim_style = xim_styles->supported_styles[z];
2467 printf("BC_WindowBase::init_im: Input method doesn't support the style we need.\n");
2468 XCloseIM(input_method);
2472 input_context = XCreateIC(input_method, XNInputStyle, xim_style,
2473 XNClientWindow, win, XNFocusWindow, win, NULL);
2476 printf("BC_WindowBase::init_im: Failed to create input context.\n");
2477 XCloseIM(input_method);
2482 void BC_WindowBase::finit_im()
2484 if( input_context ) {
2485 XDestroyIC(input_context);
2488 if( input_method ) {
2489 XCloseIM(input_method);
2495 int BC_WindowBase::get_color(int64_t color)
2497 // return pixel of color
2498 // use this only for drawing subwindows not for bitmaps
2499 int i, test, difference;
2505 return get_color_rgb8(color);
2506 // test last color looked up
2507 if(current_color_value == color)
2508 return current_color_pixel;
2511 current_color_value = color;
2512 for(i = 0; i < total_colors; i++)
2514 if(color_table[i][0] == color)
2516 current_color_pixel = color_table[i][1];
2517 return current_color_pixel;
2521 // find nearest match
2522 difference = 0xFFFFFF;
2524 for(i = 0; i < total_colors; i++)
2526 test = abs((int)(color_table[i][0] - color));
2528 if(test < difference)
2530 current_color_pixel = color_table[i][1];
2534 return current_color_pixel;
2537 return get_color_rgb16(color);
2540 return get_color_bgr16(color);
2544 return client_byte_order == server_byte_order ?
2545 color : get_color_bgr24(color);
2553 int BC_WindowBase::get_color_rgb8(int color)
2557 pixel = (color & 0xc00000) >> 16;
2558 pixel += (color & 0xe000) >> 10;
2559 pixel += (color & 0xe0) >> 5;
2563 int64_t BC_WindowBase::get_color_rgb16(int color)
2566 result = (color & 0xf80000) >> 8;
2567 result += (color & 0xfc00) >> 5;
2568 result += (color & 0xf8) >> 3;
2573 int64_t BC_WindowBase::get_color_bgr16(int color)
2576 result = (color & 0xf80000) >> 19;
2577 result += (color & 0xfc00) >> 5;
2578 result += (color & 0xf8) << 8;
2583 int64_t BC_WindowBase::get_color_bgr24(int color)
2586 result = (color & 0xff) << 16;
2587 result += (color & 0xff00);
2588 result += (color & 0xff0000) >> 16;
2592 void BC_WindowBase::start_video()
2594 cursor_timer->update();
2596 // set_color(BLACK);
2597 // draw_box(0, 0, get_w(), get_h());
2601 void BC_WindowBase::stop_video()
2609 int64_t BC_WindowBase::get_color()
2611 return top_level->current_color;
2614 void BC_WindowBase::set_color(int64_t color)
2616 top_level->current_color = color;
2617 XSetForeground(top_level->display,
2619 top_level->get_color(color));
2622 void BC_WindowBase::set_opaque()
2624 XSetFunction(top_level->display, top_level->gc, GXcopy);
2627 void BC_WindowBase::set_inverse()
2629 XSetFunction(top_level->display, top_level->gc, GXxor);
2632 void BC_WindowBase::set_line_width(int value)
2634 this->line_width = value;
2635 XSetLineAttributes(top_level->display, top_level->gc, value, /* line_width */
2636 line_dashes == 0 ? LineSolid : LineOnOffDash, /* line_style */
2637 line_dashes == 0 ? CapRound : CapNotLast, /* cap_style */
2638 JoinMiter); /* join_style */
2640 if(line_dashes > 0) {
2641 const char dashes = line_dashes;
2642 XSetDashes(top_level->display, top_level->gc, 0, &dashes, 1);
2645 // XGCValues gcvalues;
2646 // unsigned long gcmask;
2647 // gcmask = GCCapStyle | GCJoinStyle;
2648 // XGetGCValues(top_level->display, top_level->gc, gcmask, &gcvalues);
2649 // printf("BC_WindowBase::set_line_width %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2652 void BC_WindowBase::set_line_dashes(int value)
2654 line_dashes = value;
2655 // call XSetLineAttributes
2656 set_line_width(line_width);
2660 Cursor BC_WindowBase::get_cursor_struct(int cursor)
2664 case ARROW_CURSOR: return top_level->arrow_cursor;
2665 case CROSS_CURSOR: return top_level->cross_cursor;
2666 case IBEAM_CURSOR: return top_level->ibeam_cursor;
2667 case VSEPARATE_CURSOR: return top_level->vseparate_cursor;
2668 case HSEPARATE_CURSOR: return top_level->hseparate_cursor;
2669 case MOVE_CURSOR: return top_level->move_cursor;
2670 case LEFT_CURSOR: return top_level->left_cursor;
2671 case RIGHT_CURSOR: return top_level->right_cursor;
2672 case UPRIGHT_ARROW_CURSOR: return top_level->upright_arrow_cursor;
2673 case UPLEFT_RESIZE: return top_level->upleft_resize_cursor;
2674 case UPRIGHT_RESIZE: return top_level->upright_resize_cursor;
2675 case DOWNLEFT_RESIZE: return top_level->downleft_resize_cursor;
2676 case DOWNRIGHT_RESIZE: return top_level->downright_resize_cursor;
2677 case HOURGLASS_CURSOR: return top_level->hourglass_cursor;
2678 case TRANSPARENT_CURSOR: return top_level->transparent_cursor;
2679 case GRABBED_CURSOR: return top_level->grabbed_cursor;
2684 void BC_WindowBase::set_cursor(int cursor, int override, int flush)
2686 // inherit cursor from parent
2689 XUndefineCursor(top_level->display, win);
2690 current_cursor = cursor;
2693 // don't change cursor if overridden
2694 if((!top_level->is_hourglass && !is_transparent) ||
2697 XDefineCursor(top_level->display, win, get_cursor_struct(cursor));
2698 if(flush) this->flush();
2701 if(!override) current_cursor = cursor;
2704 void BC_WindowBase::set_x_cursor(int cursor)
2706 temp_cursor = XCreateFontCursor(top_level->display, cursor);
2707 XDefineCursor(top_level->display, win, temp_cursor);
2708 current_cursor = cursor;
2712 int BC_WindowBase::get_cursor()
2714 return current_cursor;
2717 void BC_WindowBase::start_hourglass()
2719 top_level->start_hourglass_recursive();
2723 void BC_WindowBase::stop_hourglass()
2725 top_level->stop_hourglass_recursive();
2729 void BC_WindowBase::start_hourglass_recursive()
2731 if(this == top_level)
2739 set_cursor(HOURGLASS_CURSOR, 1, 0);
2740 for(int i = 0; i < subwindows->total; i++)
2742 subwindows->values[i]->start_hourglass_recursive();
2747 void BC_WindowBase::stop_hourglass_recursive()
2749 if(this == top_level)
2751 if(hourglass_total == 0) return;
2752 top_level->hourglass_total--;
2755 if(!top_level->hourglass_total)
2757 top_level->is_hourglass = 0;
2759 // Cause set_cursor to perform change
2761 set_cursor(current_cursor, 1, 0);
2763 for(int i = 0; i < subwindows->total; i++)
2765 subwindows->values[i]->stop_hourglass_recursive();
2773 XFontStruct* BC_WindowBase::get_font_struct(int font)
2775 // Clear out unrelated flags
2776 if(font & BOLDFACE) font ^= BOLDFACE;
2779 case SMALLFONT: return top_level->smallfont; break;
2780 case MEDIUMFONT: return top_level->mediumfont; break;
2781 case LARGEFONT: return top_level->largefont; break;
2782 case BIGFONT: return top_level->bigfont; break;
2783 case CLOCKFONT: return top_level->clockfont; break;
2788 XFontSet BC_WindowBase::get_fontset(int font)
2792 if(get_resources()->use_fontset)
2794 switch(font & 0xff) {
2795 case SMALLFONT: fs = top_level->smallfontset; break;
2796 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2797 case LARGEFONT: fs = top_level->largefontset; break;
2798 case BIGFONT: fs = top_level->bigfontset; break;
2799 case CLOCKFONT: fs = top_level->clockfontset; break;
2807 XftFont* BC_WindowBase::get_xft_struct(int font)
2810 case SMALLFONT: return (XftFont*)top_level->smallfont_xft;
2811 case MEDIUMFONT: return (XftFont*)top_level->mediumfont_xft;
2812 case LARGEFONT: return (XftFont*)top_level->largefont_xft;
2813 case BIGFONT: return (XftFont*)top_level->bigfont_xft;
2814 case CLOCKFONT: return (XftFont*)top_level->clockfont_xft;
2815 case MEDIUMFONT_3D: return (XftFont*)top_level->bold_mediumfont_xft;
2816 case SMALLFONT_3D: return (XftFont*)top_level->bold_smallfont_xft;
2817 case LARGEFONT_3D: return (XftFont*)top_level->bold_largefont_xft;
2825 int BC_WindowBase::get_current_font()
2827 return top_level->current_font;
2830 void BC_WindowBase::set_font(int font)
2832 top_level->current_font = font;
2835 if(get_resources()->use_xft) {}
2838 if(get_resources()->use_fontset) {
2842 if(get_font_struct(font))
2844 XSetFont(top_level->display, top_level->gc, get_font_struct(font)->fid);
2850 void BC_WindowBase::set_fontset(int font)
2854 if(get_resources()->use_fontset) {
2856 case SMALLFONT: fs = top_level->smallfontset; break;
2857 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2858 case LARGEFONT: fs = top_level->largefontset; break;
2859 case BIGFONT: fs = top_level->bigfontset; break;
2860 case CLOCKFONT: fs = top_level->clockfontset; break;
2868 XFontSet BC_WindowBase::get_curr_fontset(void)
2870 if(get_resources()->use_fontset)
2871 return curr_fontset;
2875 int BC_WindowBase::get_single_text_width(int font, const char *text, int length)
2878 if(get_resources()->use_xft && get_xft_struct(font))
2881 #ifdef X_HAVE_UTF8_STRING
2882 if(get_resources()->locale_utf8)
2884 xftTextExtentsUtf8(top_level->display,
2885 get_xft_struct(font),
2886 (const XftChar8 *)text,
2893 xftTextExtents8(top_level->display,
2894 get_xft_struct(font),
2895 (const XftChar8 *)text,
2899 return extents.xOff;
2903 if(get_resources()->use_fontset && top_level->get_fontset(font))
2904 return XmbTextEscapement(top_level->get_fontset(font), text, length);
2906 if(get_font_struct(font))
2907 return XTextWidth(get_font_struct(font), text, length);
2913 case MEDIUM_7SEGMENT:
2914 return get_resources()->medium_7segment[0]->get_w() * length;
2924 int BC_WindowBase::get_text_width(int font, const char *text, int length)
2926 int i, j, w = 0, line_w = 0;
2927 if(length < 0) length = strlen(text);
2929 for(i = 0, j = 0; i <= length; i++)
2934 line_w = get_single_text_width(font, &text[j], i - j);
2940 line_w = get_single_text_width(font, &text[j], length - j);
2942 if(line_w > w) w = line_w;
2945 if(i > length && w == 0)
2947 w = get_single_text_width(font, text, length);
2953 int BC_WindowBase::get_text_width(int font, const wchr_t *text, int length)
2956 if( length < 0 ) length = wstrlen(text);
2958 for( i=j=0; i<length && text[i]; ++i ) {
2959 if( text[i] != '\n' ) continue;
2961 int lw = get_single_text_width(font, &text[j], i-j);
2962 if( w < lw ) w = lw;
2967 int lw = get_single_text_width(font, &text[j], length-j);
2968 if( w < lw ) w = lw;
2974 int BC_WindowBase::get_text_ascent(int font)
2978 if( (fstruct = get_xft_struct(font)) != 0 )
2979 return fstruct->ascent;
2981 if(get_resources()->use_fontset && top_level->get_fontset(font))
2983 XFontSetExtents *extents;
2985 extents = XExtentsOfFontSet(top_level->get_fontset(font));
2986 return -extents->max_logical_extent.y;
2989 if(get_font_struct(font))
2990 return top_level->get_font_struct(font)->ascent;
2993 case MEDIUM_7SEGMENT:
2994 return get_resources()->medium_7segment[0]->get_h();
2999 int BC_WindowBase::get_text_descent(int font)
3003 if( (fstruct = get_xft_struct(font)) != 0 )
3004 return fstruct->descent;
3006 if(get_resources()->use_fontset && top_level->get_fontset(font)) {
3007 XFontSetExtents *extents;
3008 extents = XExtentsOfFontSet(top_level->get_fontset(font));
3009 return (extents->max_logical_extent.height
3010 + extents->max_logical_extent.y);
3013 if(get_font_struct(font))
3014 return top_level->get_font_struct(font)->descent;
3019 int BC_WindowBase::get_text_height(int font, const char *text)
3024 if( (fstruct = get_xft_struct(font)) != 0 )
3025 rowh = fstruct->height;
3028 rowh = get_text_ascent(font) + get_text_descent(font);
3030 if(!text) return rowh;
3032 // Add height of lines
3033 int h = 0, i, length = strlen(text);
3034 for(i = 0; i <= length; i++)
3045 // truncate the text with ... & return a new string
3046 char *BC_WindowBase::get_truncated_text(int font, const char *text, int max_w)
3048 char *result = cstrdup(text);
3049 int text_w = get_text_width(font, text);
3050 int ci = -1, len = strlen(text);
3051 if( text_w > max_w ) {
3052 // get center of string
3053 int cx = text_w/2, best = INT_MAX;
3054 for( int i=1; i<=len; ++i ) {
3055 int cw = get_text_width(font, text, i);
3056 if( abs(cw-cx) < abs(best-cx) ) {
3061 if( ci > 0 && ci < len-1 ) {
3062 // insert ... in the center
3063 result[ci-1] = result[ci] = result[ci+1] = '.';
3065 while( ci-2>=0 && ci+2<(int)strlen(result) &&
3066 get_text_width(font, result) > max_w ) {
3067 // take away a character from the longer side
3068 int left_w = get_text_width(font, result, ci-2);
3069 int right_w = get_text_width(font, result + ci+3);
3070 int i = left_w > right_w ? --ci-1 : ci+2;
3071 while( (result[i]=result[i+1])!=0 ) ++i;
3078 BC_Bitmap* BC_WindowBase::new_bitmap(int w, int h, int color_model)
3080 if(color_model < 0) color_model = top_level->get_color_model();
3081 return new BC_Bitmap(top_level, w, h, color_model);
3084 void BC_WindowBase::init_wait()
3086 #ifndef SINGLE_THREAD
3087 if(window_type != MAIN_WINDOW)
3088 top_level->init_wait();
3089 init_lock->lock("BC_WindowBase::init_wait");
3090 init_lock->unlock();
3094 int BC_WindowBase::accel_available(int color_model, int lock_it)
3096 if( window_type != MAIN_WINDOW )
3097 return top_level->accel_available(color_model, lock_it);
3099 lock_window("BC_WindowBase::accel_available");
3101 switch(color_model) {
3103 grab_port_id(color_model);
3107 grab_port_id(color_model);
3116 //printf("BC_WindowBase::accel_available %d %d\n", color_model, xvideo_port_id);
3117 return xvideo_port_id >= 0 ? 1 : 0;
3121 int BC_WindowBase::grab_port_id(int color_model)
3124 if( !get_resources()->use_xvideo || // disabled
3125 !get_resources()->use_shm ) // Only local server is fast enough.
3127 if( xvideo_port_id >= 0 )
3128 return xvideo_port_id;
3130 unsigned int ver, rev, reqBase, eventBase, errorBase;
3131 if( Success != XvQueryExtension(display, // XV extension is available
3132 &ver, &rev, &reqBase, &eventBase, &errorBase) )
3135 // XV adaptors are available
3136 unsigned int numAdapt = 0;
3137 XvAdaptorInfo *info = 0;
3138 XvQueryAdaptors(display, DefaultRootWindow(display), &numAdapt, &info);
3142 // Translate from color_model to X color model
3143 int x_color_model = BC_CModels::bc_to_x(color_model);
3145 // Get adaptor with desired color model
3146 for( int i = 0; i < (int)numAdapt && xvideo_port_id == -1; i++) {
3147 if( !(info[i].type & XvImageMask) || !info[i].num_ports ) continue;
3148 // adaptor supports XvImages
3149 int numFormats = 0, numPorts = info[i].num_ports;
3150 XvImageFormatValues *formats =
3151 XvListImageFormats(display, info[i].base_id, &numFormats);
3152 if( !formats ) continue;
3154 for( int j=0; j<numFormats && xvideo_port_id<0; ++j ) {
3155 if( formats[j].id != x_color_model ) continue;
3156 // this adaptor supports the desired format, grab a port
3157 for( int k=0; k<numPorts; ++k ) {
3158 if( Success == XvGrabPort(top_level->display,
3159 info[i].base_id+k, CurrentTime) ) {
3160 //printf("BC_WindowBase::grab_port_id %llx\n", info[i].base_id);
3161 xvideo_port_id = info[i].base_id + k;
3169 XvFreeAdaptorInfo(info);
3170 return xvideo_port_id;
3177 int BC_WindowBase::show_window(int flush)
3179 for(int i = 0; i < subwindows->size(); i++)
3181 subwindows->get(i)->show_window(0);
3184 XMapWindow(top_level->display, win);
3185 if(flush) XFlush(top_level->display);
3186 // XSync(top_level->display, 0);
3191 int BC_WindowBase::hide_window(int flush)
3193 for(int i = 0; i < subwindows->size(); i++)
3195 subwindows->get(i)->hide_window(0);
3198 XUnmapWindow(top_level->display, win);
3199 if(flush) this->flush();
3204 BC_MenuBar* BC_WindowBase::add_menubar(BC_MenuBar *menu_bar)
3206 subwindows->append((BC_SubWindow*)menu_bar);
3208 menu_bar->parent_window = this;
3209 menu_bar->top_level = this->top_level;
3210 menu_bar->initialize();
3214 BC_WindowBase* BC_WindowBase::add_popup(BC_WindowBase *window)
3216 //printf("BC_WindowBase::add_popup window=%p win=%p\n", window, window->win);
3217 if(this != top_level) return top_level->add_popup(window);
3218 popups.append(window);
3222 void BC_WindowBase::remove_popup(BC_WindowBase *window)
3224 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3225 if(this != top_level)
3226 top_level->remove_popup(window);
3228 popups.remove(window);
3229 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3233 BC_WindowBase* BC_WindowBase::add_subwindow(BC_WindowBase *subwindow)
3235 subwindows->append(subwindow);
3237 if(subwindow->bg_color == -1) subwindow->bg_color = this->bg_color;
3239 // parent window must be set before the subwindow initialization
3240 subwindow->parent_window = this;
3241 subwindow->top_level = this->top_level;
3243 // Execute derived initialization
3244 subwindow->initialize();
3249 BC_WindowBase* BC_WindowBase::add_tool(BC_WindowBase *subwindow)
3251 return add_subwindow(subwindow);
3254 int BC_WindowBase::flash(int x, int y, int w, int h, int flush)
3256 if( !top_level->flash_enabled ) return 0;
3257 //printf("BC_WindowBase::flash %d %d %d %d %d\n", __LINE__, w, h, this->w, this->h);
3259 XSetWindowBackgroundPixmap(top_level->display, win, pixmap->opaque_pixmap);
3262 XClearArea(top_level->display, win, x, y, w, h, 0);
3266 XClearWindow(top_level->display, win);
3274 int BC_WindowBase::flash(int flush)
3276 flash(-1, -1, -1, -1, flush);
3280 void BC_WindowBase::flush()
3282 //if(!get_window_lock())
3283 // printf("BC_WindowBase::flush %s not locked\n", top_level->title);
3284 // X gets hosed if Flush/Sync are not user locked (at libX11-1.1.5 / libxcb-1.1.91)
3285 // _XReply deadlocks in condition_wait waiting for xlib lock when waiters!=-1
3286 int locked = get_window_lock();
3287 if( !locked ) lock_window("BC_WindowBase::flush");
3288 XFlush(top_level->display);
3289 if( !locked ) unlock_window();
3292 void BC_WindowBase::sync_display()
3294 int locked = get_window_lock();
3295 if( !locked ) lock_window("BC_WindowBase::sync_display");
3296 XSync(top_level->display, False);
3297 if( !locked ) unlock_window();
3300 int BC_WindowBase::get_window_lock()
3302 #ifdef SINGLE_THREAD
3303 return BC_Display::display_global->get_display_locked();
3305 return top_level->window_lock;
3309 int BC_WindowBase::lock_window(const char *location)
3311 if(top_level && top_level != this)
3313 top_level->lock_window(location);
3318 SET_LOCK(this, title, location);
3319 #ifdef SINGLE_THREAD
3320 BC_Display::lock_display(location);
3322 XLockDisplay(top_level->display);
3323 top_level->display_lock_owner = pthread_self();
3326 ++top_level->window_lock;
3330 printf("BC_WindowBase::lock_window top_level NULL\n");
3335 int BC_WindowBase::unlock_window()
3337 if(top_level && top_level != this)
3339 top_level->unlock_window();
3345 if( !top_level->window_lock ) {
3346 printf("BC_WindowBase::unlock_window %s not locked\n", title);
3349 if( top_level->window_lock > 0 )
3350 if( --top_level->window_lock == 0 )
3351 top_level->display_lock_owner = 0;
3352 #ifdef SINGLE_THREAD
3353 BC_Display::unlock_display();
3355 XUnlockDisplay(top_level->display);
3360 printf("BC_WindowBase::unlock_window top_level NULL\n");
3365 int BC_WindowBase::break_lock()
3367 if( !top_level ) return 0;
3368 if( top_level != this ) return top_level->break_lock();
3369 if( top_level->display_lock_owner != pthread_self() ) return 0;
3370 if( top_level->window_lock != 1 ) return 0;
3373 display_lock_owner = 0;
3374 #ifdef SINGLE_THREAD
3375 BC_Display::unlock_display();
3377 XUnlockDisplay(display);
3382 void BC_WindowBase::set_done(int return_value)
3384 if(done_set) return;
3386 if(window_type != MAIN_WINDOW)
3387 top_level->set_done(return_value);
3390 #ifdef SINGLE_THREAD
3391 this->return_value = return_value;
3392 BC_Display::display_global->arm_completion(this);
3393 completion_lock->unlock();
3394 #else // SINGLE_THREAD
3396 if( !event_thread ) return;
3397 XEvent *event = new_xevent();
3398 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
3399 event->type = ClientMessage;
3400 ptr->message_type = SetDoneXAtom;
3402 this->return_value = return_value;
3403 // May lock up here because XSendEvent doesn't work too well
3404 // asynchronous with XNextEvent.
3405 // This causes BC_WindowEvents to forward a copy of the event to run_window where
3407 // Deletion of event_thread is done at the end of BC_WindowBase::run_window() - by calling the destructor
3413 void BC_WindowBase::close(int return_value)
3415 hide_window(); flush();
3416 set_done(return_value);
3419 int BC_WindowBase::grab(BC_WindowBase *window)
3421 if( window->active_grab && this != window->active_grab ) return 0;
3422 window->active_grab = this;
3423 this->grab_active = window;
3426 int BC_WindowBase::ungrab(BC_WindowBase *window)
3428 if( window->active_grab && this != window->active_grab ) return 0;
3429 window->active_grab = 0;
3430 this->grab_active = 0;
3433 int BC_WindowBase::grab_event_count()
3436 #ifndef SINGLE_THREAD
3437 result = grab_active->get_event_count();
3441 int BC_WindowBase::grab_buttons()
3443 XSync(top_level->display, False);
3444 if( XGrabButton(top_level->display, AnyButton, AnyModifier,
3445 top_level->rootwin, True, ButtonPressMask | ButtonReleaseMask,
3446 GrabModeAsync, GrabModeSync, None, None) == GrabSuccess ) {
3447 set_active_subwindow(this);
3452 void BC_WindowBase::ungrab_buttons()
3454 XUngrabButton(top_level->display, AnyButton, AnyModifier, top_level->rootwin);
3455 set_active_subwindow(0);
3458 void BC_WindowBase::grab_cursor()
3460 Cursor cursor_grab = get_cursor_struct(GRABBED_CURSOR);
3461 XGrabPointer(top_level->display, top_level->rootwin, True,
3462 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
3463 GrabModeAsync, GrabModeAsync, None, cursor_grab, CurrentTime);
3465 void BC_WindowBase::ungrab_cursor()
3467 XUngrabPointer(top_level->display, CurrentTime);
3471 // WidthOfScreen/HeightOfScreen of XDefaultScreenOfDisplay
3472 // this is the bounding box of all the screens
3474 int BC_WindowBase::get_root_w(int lock_display)
3476 if(lock_display) lock_window("BC_WindowBase::get_root_w");
3477 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3478 int result = WidthOfScreen(def_screen);
3479 if(lock_display) unlock_window();
3483 int BC_WindowBase::get_root_h(int lock_display)
3485 if(lock_display) lock_window("BC_WindowBase::get_root_h");
3486 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3487 int result = HeightOfScreen(def_screen);
3488 if(lock_display) unlock_window();
3492 XineramaScreenInfo *
3493 BC_WindowBase::get_xinerama_info(int screen)
3495 if( !xinerama_info || !xinerama_screens ) return 0;
3497 for( int i=0; i<xinerama_screens; ++i )
3498 if( xinerama_info[i].screen_number == screen )
3499 return &xinerama_info[i];
3502 int top_x = get_x(), top_y = get_y();
3503 if( BC_DisplayInfo::left_border >= 0 ) top_x += BC_DisplayInfo::left_border;
3504 if( BC_DisplayInfo::top_border >= 0 ) top_y += BC_DisplayInfo::top_border;
3505 for( int i=0; i<xinerama_screens; ++i ) {
3506 int scr_y = top_y - xinerama_info[i].y_org;
3507 if( scr_y < 0 || scr_y >= xinerama_info[i].height ) continue;
3508 int scr_x = top_x - xinerama_info[i].x_org;
3509 if( scr_x >= 0 && scr_x < xinerama_info[i].width )
3510 return &xinerama_info[i];
3515 void BC_WindowBase::get_fullscreen_geometry(int &wx, int &wy, int &ww, int &wh)
3517 XineramaScreenInfo *info = top_level->get_xinerama_info(-1);
3519 wx = info->x_org; wy = info->y_org;
3520 ww = info->width; wh = info->height;
3523 wx = get_screen_x(0, -1);
3524 wy = get_screen_y(0, -1);
3525 int scr_w0 = get_screen_w(0, 0);
3526 int root_w = get_root_w(0);
3527 int root_h = get_root_h(0);
3528 if( root_w > scr_w0 ) { // multi-headed
3529 if( wx >= scr_w0 ) {
3530 // assumes right side is the big one
3531 ww = root_w - scr_w0;
3535 // use same aspect ratio to compute left height
3537 wh = (w*root_h) / (root_w-scr_w0);
3547 int BC_WindowBase::get_screen_x(int lock_display, int screen)
3550 if(lock_display) lock_window("BC_WindowBase::get_screen_x");
3551 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3554 int root_w = get_root_w(0);
3555 int root_h = get_root_h(0);
3556 // Shift X based on position of current window if dual head
3557 if( (float)root_w/root_h > 1.8 ) {
3558 root_w = get_screen_w(0, 0);
3559 if( top_level->get_x() >= root_w )
3564 result = info->x_org;
3565 if(lock_display) unlock_window();
3569 int BC_WindowBase::get_screen_y(int lock_display, int screen)
3571 if(lock_display) lock_window("BC_WindowBase::get_screen_y");
3572 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3573 int result = !info ? 0 : info->y_org;
3574 if(lock_display) unlock_window();
3578 int BC_WindowBase::get_screen_w(int lock_display, int screen)
3581 if(lock_display) lock_window("BC_WindowBase::get_screen_w");
3582 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3584 int width = get_root_w(0);
3585 int height = get_root_h(0);
3586 if( (float)width/height > 1.8 ) {
3587 // If dual head, the screen width is > 16x9
3588 // but we only want to fill one screen
3589 // this code assumes the "big" screen is on the right
3590 int scr_w0 = width / 2;
3592 case 600: scr_w0 = 800; break;
3593 case 720: scr_w0 = 1280; break;
3594 case 1024: scr_w0 = 1280; break;
3595 case 1200: scr_w0 = 1600; break;
3596 case 1080: scr_w0 = 1920; break;
3598 int scr_w1 = width - scr_w0;
3599 result = screen > 0 ? scr_w1 :
3600 screen == 0 ? scr_w0 :
3601 top_level->get_x() < scr_w0 ? scr_w0 : scr_w1;
3607 result = info->width;
3608 if(lock_display) unlock_window();
3612 int BC_WindowBase::get_screen_h(int lock_display, int screen)
3614 if(lock_display) lock_window("BC_WindowBase::get_screen_h");
3615 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3616 int result = info ? info->height : get_root_h(0);
3617 if(lock_display) unlock_window();
3621 // Bottom right corner
3622 int BC_WindowBase::get_x2()
3627 int BC_WindowBase::get_y2()
3632 int BC_WindowBase::get_video_on()
3637 int BC_WindowBase::get_hidden()
3639 return top_level->hidden;
3642 int BC_WindowBase::cursor_inside()
3644 return (top_level->cursor_x >= 0 &&
3645 top_level->cursor_y >= 0 &&
3646 top_level->cursor_x < w &&
3647 top_level->cursor_y < h);
3650 BC_WindowBase* BC_WindowBase::get_top_level()
3655 BC_WindowBase* BC_WindowBase::get_parent()
3657 return parent_window;
3660 int BC_WindowBase::get_color_model()
3662 return top_level->color_model;
3665 BC_Resources* BC_WindowBase::get_resources()
3667 return BC_WindowBase::resources;
3670 BC_Synchronous* BC_WindowBase::get_synchronous()
3672 return BC_WindowBase::resources->get_synchronous();
3675 int BC_WindowBase::get_bg_color()
3680 void BC_WindowBase::set_bg_color(int color)
3682 this->bg_color = color;
3685 BC_Pixmap* BC_WindowBase::get_bg_pixmap()
3690 void BC_WindowBase::set_active_subwindow(BC_WindowBase *subwindow)
3692 top_level->active_subwindow = subwindow;
3695 int BC_WindowBase::activate()
3700 int BC_WindowBase::deactivate()
3702 if(window_type == MAIN_WINDOW)
3704 if( top_level->active_menubar ) {
3705 top_level->active_menubar->deactivate();
3706 top_level->active_menubar = 0;
3708 if( top_level->active_popup_menu ) {
3709 top_level->active_popup_menu->deactivate();
3710 top_level->active_popup_menu = 0;
3712 if( top_level->active_subwindow ) {
3713 top_level->active_subwindow->deactivate();
3714 top_level->active_subwindow = 0;
3716 if( top_level->motion_events && top_level->last_motion_win == this->win )
3717 top_level->motion_events = 0;
3723 int BC_WindowBase::cycle_textboxes(int amount)
3726 BC_WindowBase *new_textbox = 0;
3730 BC_WindowBase *first_textbox = 0;
3731 find_next_textbox(&first_textbox, &new_textbox, result);
3732 if(!new_textbox) new_textbox = first_textbox;
3738 BC_WindowBase *last_textbox = 0;
3739 find_prev_textbox(&last_textbox, &new_textbox, result);
3740 if(!new_textbox) new_textbox = last_textbox;
3744 if(new_textbox != active_subwindow)
3747 new_textbox->activate();
3753 int BC_WindowBase::find_next_textbox(BC_WindowBase **first_textbox, BC_WindowBase **next_textbox, int &result)
3755 // Search subwindows for textbox
3756 for(int i = 0; i < subwindows->total && result < 2; i++)
3758 BC_WindowBase *test_subwindow = subwindows->values[i];
3759 test_subwindow->find_next_textbox(first_textbox, next_textbox, result);
3766 if(!*first_textbox) *first_textbox = this;
3770 if(top_level->active_subwindow == this)
3776 *next_textbox = this;
3783 int BC_WindowBase::find_prev_textbox(BC_WindowBase **last_textbox, BC_WindowBase **prev_textbox, int &result)
3789 if(!*last_textbox) *last_textbox = this;
3793 if(top_level->active_subwindow == this)
3799 *prev_textbox = this;
3804 // Search subwindows for textbox
3805 for(int i = subwindows->total - 1; i >= 0 && result < 2; i--)
3807 BC_WindowBase *test_subwindow = subwindows->values[i];
3808 test_subwindow->find_prev_textbox(last_textbox, prev_textbox, result);
3813 BC_Clipboard* BC_WindowBase::get_clipboard()
3815 #ifdef SINGLE_THREAD
3816 return BC_Display::display_global->clipboard;
3818 return top_level->clipboard;
3822 Atom BC_WindowBase::to_clipboard(const char *data, long len, int clipboard_num)
3824 return get_clipboard()->to_clipboard(this, data, len, clipboard_num);
3827 long BC_WindowBase::from_clipboard(char *data, long maxlen, int clipboard_num)
3829 return get_clipboard()->from_clipboard(data, maxlen, clipboard_num);
3832 long BC_WindowBase::clipboard_len(int clipboard_num)
3834 return get_clipboard()->clipboard_len(clipboard_num);
3837 int BC_WindowBase::do_selection_clear(Window win)
3839 top_level->event_win = win;
3840 return dispatch_selection_clear();
3843 int BC_WindowBase::dispatch_selection_clear()
3846 for( int i=0; i<subwindows->total && !result; ++i )
3847 result = subwindows->values[i]->dispatch_selection_clear();
3849 result = selection_clear_event();
3854 void BC_WindowBase::get_relative_cursor(int &x, int &y, int lock_window)
3856 int abs_x, abs_y, win_x, win_y;
3857 unsigned int temp_mask;
3860 if(lock_window) this->lock_window("BC_WindowBase::get_relative_cursor");
3861 XQueryPointer(top_level->display, top_level->win,
3862 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3865 XTranslateCoordinates(top_level->display, top_level->rootwin,
3866 win, abs_x, abs_y, &x, &y, &temp_win);
3867 if(lock_window) this->unlock_window();
3869 int BC_WindowBase::get_relative_cursor_x(int lock_window)
3872 get_relative_cursor(x, y, lock_window);
3875 int BC_WindowBase::get_relative_cursor_y(int lock_window)
3878 get_relative_cursor(x, y, lock_window);
3882 void BC_WindowBase::get_abs_cursor(int &abs_x, int &abs_y, int lock_window)
3885 unsigned int temp_mask;
3888 if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor");
3889 XQueryPointer(top_level->display, top_level->win,
3890 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3892 if(lock_window) this->unlock_window();
3894 int BC_WindowBase::get_abs_cursor_x(int lock_window)
3897 get_abs_cursor(abs_x, abs_y, lock_window);
3900 int BC_WindowBase::get_abs_cursor_y(int lock_window)
3903 get_abs_cursor(abs_x, abs_y, lock_window);
3907 void BC_WindowBase::get_pop_cursor(int &px, int &py, int lock_window)
3909 int xmargin = xS(100), ymargin = yS(100);
3910 get_abs_cursor(px, py, lock_window);
3911 if( px < xmargin ) px = xmargin;
3912 if( py < ymargin ) py = ymargin;
3913 int wd = get_screen_x(lock_window,-1) + get_screen_w(lock_window,-1) - xmargin;
3914 if( px > wd ) px = wd;
3915 int ht = get_screen_y(lock_window,-1) + get_screen_h(lock_window,-1) - ymargin;
3916 if( py > ht ) py = ht;
3918 int BC_WindowBase::get_pop_cursor_x(int lock_window)
3921 get_pop_cursor(px, py, lock_window);
3924 int BC_WindowBase::get_pop_cursor_y(int lock_window)
3927 get_pop_cursor(px, py, lock_window);
3931 int BC_WindowBase::match_window(Window win)
3933 if (this->win == win) return 1;
3935 for(int i = 0; i < subwindows->total; i++) {
3936 result = subwindows->values[i]->match_window(win);
3937 if (result) return result;
3943 int BC_WindowBase::get_cursor_over_window()
3945 int abs_x, abs_y, win_x, win_y;
3946 unsigned int mask_return;
3947 Window root_return, child_return;
3949 int ret = XQueryPointer(top_level->display, top_level->rootwin,
3950 &root_return, &child_return, &abs_x, &abs_y,
3951 &win_x, &win_y, &mask_return);
3952 if( ret && child_return == None ) ret = 0;
3953 if( ret && win != child_return )
3954 ret = top_level->match_window(child_return);
3955 // query pointer can return a window manager window with this top_level as a child
3956 // for kde this can be two levels deep
3957 unsigned int nchildren_return = 0;
3958 Window parent_return, *children_return = 0;
3959 Window top_win = top_level->win;
3960 while( !ret && top_win != top_level->rootwin && top_win != root_return &&
3961 XQueryTree(top_level->display, top_win, &root_return,
3962 &parent_return, &children_return, &nchildren_return) ) {
3963 if( children_return ) XFree(children_return);
3964 if( (top_win=parent_return) == child_return ) ret = 1;
3969 int BC_WindowBase::cursor_above()
3972 get_relative_cursor(rx, ry);
3973 return rx < 0 || rx >= get_w() ||
3974 ry < 0 || ry >= get_h() ? 0 : 1;
3977 int BC_WindowBase::get_drag_x()
3979 return top_level->drag_x;
3982 int BC_WindowBase::get_drag_y()
3984 return top_level->drag_y;
3987 int BC_WindowBase::get_cursor_x()
3989 return top_level->cursor_x;
3992 int BC_WindowBase::get_cursor_y()
3994 return top_level->cursor_y;
3997 int BC_WindowBase::dump_windows()
3999 printf("\tBC_WindowBase::dump_windows window=%p win=%p '%s', %dx%d+%d+%d %s\n",
4000 this, (void*)this->win, title, w,h,x,y, typeid(*this).name());
4001 for(int i = 0; i < subwindows->size(); i++)
4002 subwindows->get(i)->dump_windows();
4003 for(int i = 0; i < popups.size(); i++) {
4004 BC_WindowBase *p = popups[i];
4005 printf("\tBC_WindowBase::dump_windows popup=%p win=%p '%s', %dx%d+%d+%d %s\n",
4006 p, (void*)p->win, p->title, p->w,p->h,p->x,p->y, typeid(*p).name());
4011 int BC_WindowBase::is_event_win()
4013 return this->win == top_level->event_win;
4016 void BC_WindowBase::set_dragging(int value)
4018 is_dragging = value;
4021 int BC_WindowBase::get_dragging()
4026 int BC_WindowBase::get_buttonpress()
4028 return top_level->button_number;
4031 int BC_WindowBase::get_button_down()
4033 return top_level->button_down;
4036 int BC_WindowBase::alt_down()
4038 return top_level->alt_mask;
4041 int BC_WindowBase::shift_down()
4043 return top_level->shift_mask;
4046 int BC_WindowBase::ctrl_down()
4048 return top_level->ctrl_mask;
4051 wchr_t* BC_WindowBase::get_wkeystring(int *length)
4054 *length = top_level->wkey_string_length;
4055 return top_level->wkey_string;
4058 #ifdef X_HAVE_UTF8_STRING
4059 char* BC_WindowBase::get_keypress_utf8()
4061 return top_level->key_pressed_utf8;
4066 int BC_WindowBase::get_keypress()
4068 return top_level->key_pressed;
4071 int BC_WindowBase::get_double_click()
4073 return top_level->double_click;
4076 int BC_WindowBase::get_triple_click()
4078 return top_level->triple_click;
4081 int BC_WindowBase::get_bgcolor()
4086 int BC_WindowBase::resize_window(int w, int h)
4088 if(this->w == w && this->h == h) return 0;
4090 if(window_type == MAIN_WINDOW && !allow_resize)
4092 XSizeHints size_hints;
4093 size_hints.flags = PSize | PMinSize | PMaxSize;
4094 size_hints.width = w;
4095 size_hints.height = h;
4096 size_hints.min_width = w;
4097 size_hints.max_width = w;
4098 size_hints.min_height = h;
4099 size_hints.max_height = h;
4100 if( this->x > -BC_INFINITY && this->x < BC_INFINITY ) {
4101 size_hints.flags |= PPosition;
4102 size_hints.x = this->x;
4103 size_hints.y = this->y;
4105 XSetNormalHints(top_level->display, win, &size_hints);
4107 XResizeWindow(top_level->display, win, w, h);
4112 pixmap = new BC_Pixmap(this, w, h);
4114 // Propagate to menubar
4115 for(int i = 0; i < subwindows->total; i++)
4117 subwindows->values[i]->dispatch_resize_event(w, h);
4120 draw_background(0, 0, w, h);
4121 if(top_level == this && get_resources()->recursive_resizing)
4122 resize_history.append(new BC_ResizeCall(w, h));
4126 // The only way for resize events to be propagated is by updating the internal w and h
4127 int BC_WindowBase::resize_event(int w, int h)
4129 if(window_type == MAIN_WINDOW)
4137 int BC_WindowBase::reposition_window(int x, int y)
4139 reposition_window(x, y, -1, -1);
4144 int BC_WindowBase::reposition_window(int x, int y, int w, int h)
4148 // Some tools set their own dimensions before calling this, causing the
4149 // resize check to skip.
4153 if(w > 0 && w != this->w)
4159 if(h > 0 && h != this->h)
4165 //printf("BC_WindowBase::reposition_window %d %d %d\n", translation_count, x_correction, y_correction);
4168 printf("BC_WindowBase::reposition_window this->w == %d\n", this->w);
4170 printf("BC_WindowBase::reposition_window this->h == %d\n", this->h);
4172 if(translation_count && window_type == MAIN_WINDOW)
4174 // KDE shifts window right and down.
4175 // FVWM leaves window alone and adds border around it.
4176 XMoveResizeWindow(top_level->display, win,
4177 x - BC_DisplayInfo::auto_reposition_x,
4178 y - BC_DisplayInfo::auto_reposition_y,
4183 XMoveResizeWindow(top_level->display, win, x, y,
4190 pixmap = new BC_Pixmap(this, this->w, this->h);
4191 clear_box(0,0, this->w, this->h);
4192 // Propagate to menubar
4193 for(int i = 0; i < subwindows->total; i++)
4195 subwindows->values[i]->dispatch_resize_event(this->w, this->h);
4198 // draw_background(0, 0, w, h);
4204 int BC_WindowBase::reposition_window_relative(int dx, int dy, int w, int h)
4206 return reposition_window(get_x()+dx, get_y()+dy, w, h);
4209 int BC_WindowBase::reposition_window_relative(int dx, int dy)
4211 return reposition_window_relative(dx, dy, -1, -1);
4214 void BC_WindowBase::set_tooltips(int v)
4216 get_resources()->tooltips_enabled = v;
4219 void BC_WindowBase::set_force_tooltip(int v)
4224 int BC_WindowBase::raise_window(int do_flush)
4226 if( hidden ) return 1;
4227 if( wait_viewable(500) ) return 1;
4228 XRaiseWindow(top_level->display, win);
4229 if(do_flush) XFlush(top_level->display);
4233 int BC_WindowBase::lower_window(int do_flush)
4235 XLowerWindow(top_level->display, win);
4236 if(do_flush) XFlush(top_level->display);
4240 void BC_WindowBase::set_background(VFrame *bitmap)
4242 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
4244 bg_pixmap = new BC_Pixmap(this, bitmap, PIXMAP_OPAQUE);
4245 shared_bg_pixmap = 0;
4246 draw_background(0, 0, w, h);
4249 void BC_WindowBase::put_title(const char *text)
4251 char *cp = this->title, *ep = cp+sizeof(this->title)-1;
4252 for( const unsigned char *bp = (const unsigned char *)text; *bp && cp<ep; ++bp )
4253 *cp++ = *bp >= ' ' ? *bp : ' ';
4257 void BC_WindowBase::set_title(const char *text, int utf8)
4259 // utf8>0: wm + net_wm, utf8=0: wm only, utf<0: net_wm only
4261 const unsigned char *wm_title = (const unsigned char *)title;
4262 int title_len = strlen((const char *)title);
4264 Atom xa_wm_name = XA_WM_NAME;
4265 Atom xa_icon_name = XA_WM_ICON_NAME;
4266 Atom xa_string = XA_STRING;
4267 XChangeProperty(display, win, xa_wm_name, xa_string, 8,
4268 PropModeReplace, wm_title, title_len);
4269 XChangeProperty(display, win, xa_icon_name, xa_string, 8,
4270 PropModeReplace, wm_title, title_len);
4273 Atom xa_net_wm_name = XInternAtom(display, "_NET_WM_NAME", True);
4274 Atom xa_net_icon_name = XInternAtom(display, "_NET_WM_ICON_NAME", True);
4275 Atom xa_utf8_string = XInternAtom(display, "UTF8_STRING", True);
4276 XChangeProperty(display, win, xa_net_wm_name, xa_utf8_string, 8,
4277 PropModeReplace, wm_title, title_len);
4278 XChangeProperty(display, win, xa_net_icon_name, xa_utf8_string, 8,
4279 PropModeReplace, wm_title, title_len);
4285 void BC_WindowBase::set_net_icon(VFrame *data)
4287 int width = data->get_w(), height = data->get_h();
4288 int size = 2 + width * height;
4289 unsigned long *icon_data = new unsigned long[size];
4290 unsigned long *lp = icon_data;
4291 *lp++ = width; *lp++ = height;
4292 uint8_t **rows = data->get_rows();
4293 for( int y=0; y<height; ++y ) {
4294 unsigned *up = (unsigned *)rows[y];
4295 for( int x=0; x<width; ++x )
4296 *lp++ = *(unsigned *)up++;
4298 Atom NetWMIcon = XInternAtom(display, "_NET_WM_ICON", True);
4299 XChangeProperty(top_level->display, top_level->win, NetWMIcon,
4300 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)icon_data, size);
4301 delete [] icon_data;
4304 const char *BC_WindowBase::get_title()
4309 int BC_WindowBase::get_toggle_value()
4311 return toggle_value;
4314 int BC_WindowBase::get_toggle_drag()
4319 int BC_WindowBase::set_icon(VFrame *data)
4321 if(icon_pixmap) delete icon_pixmap;
4322 icon_pixmap = new BC_Pixmap(top_level, data, PIXMAP_ALPHA, 1);
4324 if(icon_window) delete icon_window;
4325 icon_window = new BC_Popup(this, 0, 0,
4326 icon_pixmap->get_w(), icon_pixmap->get_h(),
4327 -1, 1, // All windows are hidden initially
4330 XWMHints wm_hints; memset(&wm_hints, 0, sizeof(wm_hints));
4331 wm_hints.flags = IconPixmapHint; // | IconMaskHint | IconWindowHint;
4332 wm_hints.icon_pixmap = icon_pixmap->get_pixmap();
4333 wm_hints.icon_mask = icon_pixmap->get_alpha();
4334 wm_hints.icon_window = icon_window->win;
4335 if( XGroupLeader ) {
4336 wm_hints.flags |= WindowGroupHint;
4337 wm_hints.window_group = XGroupLeader;
4340 // for(int i = 0; i < 1000; i++)
4341 // printf("02x ", icon_pixmap->get_alpha()->get_row_pointers()[0][i]);
4344 XSetWMHints(top_level->display, top_level->win, &wm_hints);
4347 XSync(top_level->display, 0);
4351 void BC_WindowBase::init_resources(float scale)
4353 if( resources ) return;
4355 const char *env = getenv("BC_SCALE");
4356 if( env ) scale = atof(env);
4357 float x_scale = 1, y_scale = 1;
4359 BC_DisplayInfo info;
4361 int cins = info.xinerama_big_screen();
4362 if( !info.xinerama_geometry(cins, wx, wy, ww, wh) ) {
4363 if( (x_scale = ww/1920.) < 1 ) x_scale = 1;
4364 if( (y_scale = wh/1080.) < 1 ) y_scale = 1;
4368 x_scale = y_scale = scale;
4369 // constructor sets BC_WindowBase::resources
4370 new BC_Resources(x_scale, y_scale);
4372 void BC_WindowBase::finit_resources()
4374 delete resources; resources = 0;
4377 int BC_WindowBase::set_w(int w)
4383 int BC_WindowBase::set_h(int h)
4389 int BC_WindowBase::load_defaults(BC_Hash *defaults)
4391 char string[BCTEXTLEN];
4392 int newest_id = - 1;
4393 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4395 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4396 resources->filebox_history[i].path[0] = 0;
4397 defaults->get(string, resources->filebox_history[i].path);
4398 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4399 resources->filebox_history[i].id = defaults->get(string, resources->get_id());
4400 if(resources->filebox_history[i].id > newest_id)
4401 newest_id = resources->filebox_history[i].id;
4404 resources->filebox_id = newest_id + 1;
4405 resources->filebox_mode = defaults->get("FILEBOX_MODE", get_resources()->filebox_mode);
4406 resources->filebox_w = defaults->get("FILEBOX_W", get_resources()->filebox_w);
4407 resources->filebox_h = defaults->get("FILEBOX_H", get_resources()->filebox_h);
4408 resources->filebox_columntype[0] = defaults->get("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4409 resources->filebox_columntype[1] = defaults->get("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4410 resources->filebox_columntype[2] = defaults->get("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4411 resources->filebox_columntype[3] = defaults->get("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4412 resources->filebox_columnwidth[0] = defaults->get("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4413 resources->filebox_columnwidth[1] = defaults->get("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4414 resources->filebox_columnwidth[2] = defaults->get("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4415 resources->filebox_columnwidth[3] = defaults->get("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4416 resources->filebox_size_format = defaults->get("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4417 defaults->get("FILEBOX_FILTER", resources->filebox_filter);
4421 int BC_WindowBase::save_defaults(BC_Hash *defaults)
4423 char string[BCTEXTLEN];
4424 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4426 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4427 defaults->update(string, resources->filebox_history[i].path);
4428 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4429 defaults->update(string, resources->filebox_history[i].id);
4431 defaults->update("FILEBOX_MODE", resources->filebox_mode);
4432 defaults->update("FILEBOX_W", resources->filebox_w);
4433 defaults->update("FILEBOX_H", resources->filebox_h);
4434 defaults->update("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4435 defaults->update("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4436 defaults->update("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4437 defaults->update("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4438 defaults->update("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4439 defaults->update("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4440 defaults->update("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4441 defaults->update("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4442 defaults->update("FILEBOX_FILTER", resources->filebox_filter);
4443 defaults->update("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4449 // For some reason XTranslateCoordinates can take a long time to return.
4450 // We work around this by only calling it when the event windows are different.
4451 void BC_WindowBase::translate_coordinates(Window src_w, Window dest_w,
4452 int src_x, int src_y, int *dest_x_return, int *dest_y_return)
4459 *dest_x_return = src_x;
4460 *dest_y_return = src_y;
4464 XTranslateCoordinates(top_level->display, src_w, dest_w,
4465 src_x, src_y, dest_x_return, dest_y_return, &tempwin);
4466 //printf("BC_WindowBase::translate_coordinates 1 %lld\n", timer.get_difference());
4470 void BC_WindowBase::get_root_coordinates(int x, int y, int *abs_x, int *abs_y)
4472 translate_coordinates(win, top_level->rootwin, x, y, abs_x, abs_y);
4475 void BC_WindowBase::get_win_coordinates(int abs_x, int abs_y, int *x, int *y)
4477 translate_coordinates(top_level->rootwin, win, abs_x, abs_y, x, y);
4481 #ifdef HAVE_LIBXXF86VM
4482 void BC_WindowBase::closest_vm(int *vm, int *width, int *height)
4486 if(XF86VidModeQueryExtension(top_level->display,&foo,&bar)) {
4488 XF86VidModeModeInfo **vm_modelines;
4489 XF86VidModeGetAllModeLines(top_level->display,
4490 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4491 for( i = 0; i < vm_count; i++ ) {
4492 if( vm_modelines[i]->hdisplay < vm_modelines[*vm]->hdisplay &&
4493 vm_modelines[i]->hdisplay >= *width )
4496 display = top_level->display;
4497 if( vm_modelines[*vm]->hdisplay == *width )
4500 *width = vm_modelines[*vm]->hdisplay;
4501 *height = vm_modelines[*vm]->vdisplay;
4506 void BC_WindowBase::scale_vm(int vm)
4508 int foo,bar,dotclock;
4509 if( XF86VidModeQueryExtension(top_level->display,&foo,&bar) ) {
4511 XF86VidModeModeInfo **vm_modelines;
4512 XF86VidModeModeLine vml;
4513 XF86VidModeGetAllModeLines(top_level->display,
4514 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4515 XF86VidModeGetModeLine(top_level->display,
4516 XDefaultScreen(top_level->display), &dotclock,&vml);
4517 orig_modeline.dotclock = dotclock;
4518 orig_modeline.hdisplay = vml.hdisplay;
4519 orig_modeline.hsyncstart = vml.hsyncstart;
4520 orig_modeline.hsyncend = vml.hsyncend;
4521 orig_modeline.htotal = vml.htotal;
4522 orig_modeline.vdisplay = vml.vdisplay;
4523 orig_modeline.vsyncstart = vml.vsyncstart;
4524 orig_modeline.vsyncend = vml.vsyncend;
4525 orig_modeline.vtotal = vml.vtotal;
4526 orig_modeline.flags = vml.flags;
4527 orig_modeline.privsize = vml.privsize;
4528 // orig_modeline.private = vml.private;
4529 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),vm_modelines[vm]);
4530 XF86VidModeSetViewPort(top_level->display,XDefaultScreen(top_level->display),0,0);
4531 XFlush(top_level->display);
4535 void BC_WindowBase::restore_vm()
4537 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),&orig_modeline);
4538 XFlush(top_level->display);
4543 #ifndef SINGLE_THREAD
4544 int BC_WindowBase::get_event_count()
4546 event_lock->lock("BC_WindowBase::get_event_count");
4547 int result = common_events.total;
4548 event_lock->unlock();
4552 XEvent* BC_WindowBase::get_event()
4555 while(!done && !result)
4557 event_condition->lock("BC_WindowBase::get_event");
4558 event_lock->lock("BC_WindowBase::get_event");
4560 if(common_events.total && !done)
4562 result = common_events.values[0];
4563 common_events.remove_number(0);
4566 event_lock->unlock();
4571 void BC_WindowBase::put_event(XEvent *event)
4573 event_lock->lock("BC_WindowBase::put_event");
4574 common_events.append(event);
4575 event_lock->unlock();
4576 event_condition->unlock();
4579 void BC_WindowBase::dequeue_events(Window win)
4581 event_lock->lock("BC_WindowBase::dequeue_events");
4583 int out = 0, total = common_events.size();
4584 for( int in=0; in<total; ++in ) {
4585 if( common_events[in]->xany.window == win ) continue;
4586 common_events[out++] = common_events[in];
4588 common_events.total = out;
4590 event_lock->unlock();
4593 int BC_WindowBase::resend_event(BC_WindowBase *window)
4595 if( resend_event_window ) return 1;
4596 resend_event_window = window;
4602 int BC_WindowBase::resend_event(BC_WindowBase *window)
4607 #endif // SINGLE_THREAD
4609 int BC_WindowBase::get_id()
4615 BC_Pixmap *BC_WindowBase::create_pixmap(VFrame *vframe)
4617 int w = vframe->get_w(), h = vframe->get_h();
4618 BC_Pixmap *icon = new BC_Pixmap(this, w, h);
4619 icon->draw_vframe(vframe, 0,0, w,h, 0,0);
4624 void BC_WindowBase::flicker(int n, int ms)
4626 int color = get_bg_color();
4627 for( int i=2*n; --i>=0; ) {
4628 set_inverse(); set_bg_color(WHITE);
4629 clear_box(0,0, w,h); flash(1);
4630 sync_display(); Timer::delay(ms);
4632 set_bg_color(color);
4636 void BC_WindowBase::focus()
4638 XWindowAttributes xwa;
4639 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4640 if( xwa.map_state == IsViewable )
4641 XSetInputFocus(top_level->display, top_level->win, RevertToParent, CurrentTime);
4644 int BC_WindowBase::wait_viewable(int ms)
4647 XWindowAttributes xwa;
4649 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4650 if( xwa.map_state == IsViewable ) return 0;
4652 } while( timer.get_difference() < ms );