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;
1039 if( button_number < 4 ) {
1040 if((long)(button_time3 - button_time1) < resources->double_click * 2) {
1042 button_time3 = button_time2 = button_time1 = 0;
1044 if((long)(button_time3 - button_time2) < resources->double_click) {
1046 // button_time3 = button_time2 = button_time1 = 0;
1053 dispatch_button_press();
1060 dispatch_motion_event();
1062 get_key_masks(event->xbutton.state);
1063 button_number = event->xbutton.button;
1064 event_win = event->xany.window;
1065 if (button_number < 6)
1067 if(button_number < 4)
1069 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1071 dispatch_button_release();
1076 event_win = event->xany.window;
1078 for( int i=0; !result && i<popups.size(); ++i ) { // popups take focus
1079 if( popups[i]->win == event_win )
1080 result = popups[i]->dispatch_expose_event();
1083 result = dispatch_expose_event();
1087 get_key_masks(event->xmotion.state);
1088 // Dispatch previous motion event if this is a subsequent motion from a different window
1089 if(motion_events && last_motion_win != event->xany.window)
1091 dispatch_motion_event();
1094 // Buffer the current motion
1096 last_motion_state = event->xmotion.state;
1097 last_motion_x = event->xmotion.x;
1098 last_motion_y = event->xmotion.y;
1099 last_motion_win = event->xany.window;
1102 case ConfigureNotify:
1103 // printf("BC_WindowBase::dispatch_event %d win=%p this->win=%p\n",
1105 // event->xany.window,
1108 XTranslateCoordinates(top_level->display,
1116 last_resize_w = event->xconfigure.width;
1117 last_resize_h = event->xconfigure.height;
1120 cancel_translation = 0;
1122 // Resize history prevents responses to recursive resize requests
1123 for(int i = 0; i < resize_history.total && !cancel_resize; i++)
1125 if(resize_history.values[i]->w == last_resize_w &&
1126 resize_history.values[i]->h == last_resize_h)
1128 delete resize_history.values[i];
1129 resize_history.remove_number(i);
1134 if(last_resize_w == w && last_resize_h == h)
1142 if((last_translate_x == x && last_translate_y == y))
1143 cancel_translation = 1;
1145 if(!cancel_translation)
1147 translation_events = 1;
1150 translation_count++;
1154 get_key_masks(event->xkey.state);
1155 keys_return[0] = 0; keysym = -1;
1156 if(XFilterEvent(event, win)) {
1159 if( keysym_lookup(event) < 0 ) {
1160 printf("keysym %x\n", (uint32_t)keysym);
1164 //printf("BC_WindowBase::dispatch_event %d keysym=0x%x\n",
1168 // block out control keys
1169 if(keysym > 0xffe0 && keysym < 0xffff) break;
1170 // block out Alt_GR key
1171 if(keysym == 0xfe03) break;
1174 printf("BC_WindowBase::dispatch_event %x\n", (uint32_t)keysym);
1176 #ifdef X_HAVE_UTF8_STRING
1177 //It's Ascii or UTF8?
1178 // if (keysym != 0xffff && (keys_return[0] & 0xff) >= 0x7f )
1179 //printf("BC_WindowBase::dispatch_event %d %02x%02x\n", __LINE__, keys_return[0], keys_return[1]);
1181 if( ((keys_return[1] & 0xff) > 0x80) &&
1182 ((keys_return[0] & 0xff) > 0xC0) ) {
1183 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1184 key_pressed = keysym & 0xff;
1188 // shuttle speed codes
1189 if( keysym >= SKEY_MIN && keysym <= SKEY_MAX ) {
1190 key_pressed = keysym;
1192 else switch( keysym ) {
1193 // block out extra keys
1203 // Translate key codes
1204 case XK_Return: key_pressed = RETURN; break;
1205 case XK_Up: key_pressed = UP; break;
1206 case XK_Down: key_pressed = DOWN; break;
1207 case XK_Left: key_pressed = LEFT; break;
1208 case XK_Right: key_pressed = RIGHT; break;
1209 case XK_Next: key_pressed = PGDN; break;
1210 case XK_Prior: key_pressed = PGUP; break;
1211 case XK_BackSpace: key_pressed = BACKSPACE; break;
1212 case XK_Escape: key_pressed = ESC; break;
1215 key_pressed = LEFTTAB;
1219 case XK_ISO_Left_Tab: key_pressed = LEFTTAB; break;
1220 case XK_underscore: key_pressed = '_'; break;
1221 case XK_asciitilde: key_pressed = '~'; break;
1222 case XK_Delete: key_pressed = DELETE; break;
1223 case XK_Home: key_pressed = HOME; break;
1224 case XK_End: key_pressed = END; break;
1227 case XK_KP_Enter: key_pressed = KPENTER; break;
1228 case XK_KP_Add: key_pressed = KPPLUS; break;
1229 case XK_KP_Subtract: key_pressed = KPMINUS; break;
1230 case XK_KP_Multiply: key_pressed = KPSTAR; break;
1231 case XK_KP_Divide: key_pressed = KPSLASH; break;
1233 case XK_KP_End: key_pressed = KP1; break;
1235 case XK_KP_Down: key_pressed = KP2; break;
1237 case XK_KP_Page_Down: key_pressed = KP3; break;
1239 case XK_KP_Left: key_pressed = KP4; break;
1241 case XK_KP_Begin: key_pressed = KP5; break;
1243 case XK_KP_Right: key_pressed = KP6; break;
1245 case XK_KP_Home: key_pressed = KP7; break;
1247 case XK_KP_Up: key_pressed = KP8; break;
1249 case XK_KP_Page_Up: key_pressed = KP9; break;
1251 case XK_KP_Insert: key_pressed = KPINS; break;
1253 case XK_KP_Delete: key_pressed = KPDEL; break;
1255 case XK_F1: key_pressed = KEY_F1; break;
1256 case XK_F2: key_pressed = KEY_F2; break;
1257 case XK_F3: key_pressed = KEY_F3; break;
1258 case XK_F4: key_pressed = KEY_F4; break;
1259 case XK_F5: key_pressed = KEY_F5; break;
1260 case XK_F6: key_pressed = KEY_F6; break;
1261 case XK_F7: key_pressed = KEY_F7; break;
1262 case XK_F8: key_pressed = KEY_F8; break;
1263 case XK_F9: key_pressed = KEY_F9; break;
1264 case XK_F10: key_pressed = KEY_F10; break;
1265 case XK_F11: key_pressed = KEY_F11; break;
1266 case XK_F12: key_pressed = KEY_F12; break;
1268 case XK_Menu: key_pressed = KPMENU; break; /* menu */
1271 key_pressed = keysym & 0xff;
1272 #ifdef X_HAVE_UTF8_STRING
1273 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1278 #ifdef X_HAVE_UTF8_STRING
1280 key_pressed_utf8 = keys_return;
1285 if( top_level == this )
1286 result = BC_KeyboardHandler::run_listeners(this);
1288 //printf("BC_WindowBase::dispatch_event %d %d %x\n", shift_down(), alt_down(), key_pressed);
1290 result = dispatch_keypress_event();
1291 // Handle some default keypresses
1294 if(key_pressed == 'w' ||
1303 XLookupString((XKeyEvent*)event, keys_return, 1, &keysym, 0);
1304 dispatch_keyrelease_event();
1305 // printf("BC_WindowBase::dispatch_event KeyRelease keysym=0x%x keystate=0x%lld\n",
1306 // keysym, event->xkey.state);
1310 if( event->xcrossing.mode != NotifyNormal ) break;
1312 event_win = event->xany.window;
1313 dispatch_cursor_leave();
1317 if( event->xcrossing.mode != NotifyNormal ) break;
1319 if( !cursor_entered ) {
1320 for( int i=0; i<popups.size(); ++i ) { // popups always take focus
1321 if( popups[i]->win == event->xcrossing.window )
1324 if( !cursor_entered && get_resources()->grab_input_focus &&
1325 !event->xcrossing.focus && event->xcrossing.window == win ) {
1328 if( cursor_entered )
1331 event_win = event->xany.window;
1332 cursor_x = event->xcrossing.x;
1333 cursor_y = event->xcrossing.y;
1334 dispatch_cursor_enter();
1340 //printf("100 %s %p %d\n", title, event, event->type);
1341 //if(event->type != ClientMessage) dump();
1343 #ifndef SINGLE_THREAD
1346 if( resend_event_window ) {
1347 resend_event_window->put_event(event);
1348 resend_event_window = 0;
1354 // if(done) completion_lock->unlock();
1357 if(debug) printf("BC_WindowBase::dispatch_event this=%p %d\n", this, __LINE__);
1361 int BC_WindowBase::dispatch_expose_event()
1364 for(int i = 0; i < subwindows->total && !result; i++)
1366 result = subwindows->values[i]->dispatch_expose_event();
1369 // Propagate to user
1370 if(!result) expose_event();
1374 int BC_WindowBase::dispatch_resize_event(int w, int h)
1376 // Can't store new w and h until the event is handles
1377 // because bcfilebox depends on the old w and h to
1378 // reposition widgets.
1379 if( window_type == MAIN_WINDOW ) {
1384 pixmap = new BC_Pixmap(this, w, h);
1385 clear_box(0, 0, w, h);
1388 // Propagate to subwindows
1389 for(int i = 0; i < subwindows->total; i++) {
1390 subwindows->values[i]->dispatch_resize_event(w, h);
1393 // Propagate to user
1396 if( window_type == MAIN_WINDOW ) {
1405 int BC_WindowBase::dispatch_flash()
1408 for(int i = 0; i < subwindows->total; i++)
1409 subwindows->values[i]->dispatch_flash();
1413 int BC_WindowBase::dispatch_translation_event()
1415 translation_events = 0;
1416 if(window_type == MAIN_WINDOW)
1420 x = last_translate_x;
1421 y = last_translate_y;
1422 // Correct for window manager offsets
1427 for(int i = 0; i < subwindows->total; i++)
1429 subwindows->values[i]->dispatch_translation_event();
1432 translation_event();
1436 int BC_WindowBase::dispatch_motion_event()
1441 if(top_level == this)
1444 event_win = last_motion_win;
1445 get_key_masks(last_motion_state);
1448 if(get_button_down() && !active_menubar && !active_popup_menu)
1452 cursor_x = last_motion_x;
1453 cursor_y = last_motion_y;
1454 result = dispatch_drag_motion();
1458 (last_motion_x < drag_x1 || last_motion_x >= drag_x2 ||
1459 last_motion_y < drag_y1 || last_motion_y >= drag_y2))
1464 result = dispatch_drag_start();
1468 cursor_x = last_motion_x;
1469 cursor_y = last_motion_y;
1471 // printf("BC_WindowBase::dispatch_motion_event %d %p %p %p\n",
1474 // active_popup_menu,
1475 // active_subwindow);
1477 if(active_menubar && !result) result = active_menubar->dispatch_motion_event();
1478 if(active_popup_menu && !result) result = active_popup_menu->dispatch_motion_event();
1479 if(active_subwindow && !result) result = active_subwindow->dispatch_motion_event();
1482 // Dispatch in stacking order
1483 for(int i = subwindows->size() - 1; i >= 0 && !result; i--)
1485 result = subwindows->values[i]->dispatch_motion_event();
1488 if(!result) result = cursor_motion_event(); // give to user
1492 int BC_WindowBase::dispatch_keypress_event()
1495 if(top_level == this)
1497 if(active_subwindow) result = active_subwindow->dispatch_keypress_event();
1500 for(int i = 0; i < subwindows->total && !result; i++)
1502 result = subwindows->values[i]->dispatch_keypress_event();
1505 if(!result) result = keypress_event();
1510 int BC_WindowBase::dispatch_keyrelease_event()
1513 if(top_level == this)
1515 if(active_subwindow) result = active_subwindow->dispatch_keyrelease_event();
1518 for(int i = 0; i < subwindows->total && !result; i++)
1520 result = subwindows->values[i]->dispatch_keyrelease_event();
1523 if(!result) result = keyrelease_event();
1528 int BC_WindowBase::dispatch_focus_in()
1530 for(int i = 0; i < subwindows->total; i++)
1532 subwindows->values[i]->dispatch_focus_in();
1540 int BC_WindowBase::dispatch_focus_out()
1542 for(int i = 0; i < subwindows->total; i++)
1544 subwindows->values[i]->dispatch_focus_out();
1552 int BC_WindowBase::get_has_focus()
1554 return top_level->has_focus;
1557 int BC_WindowBase::get_deleting()
1559 if(is_deleting) return 1;
1560 if(parent_window && parent_window->get_deleting()) return 1;
1564 int BC_WindowBase::dispatch_button_press()
1569 if(top_level == this)
1571 if(active_menubar) result = active_menubar->dispatch_button_press();
1572 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_press();
1573 if(active_subwindow && !result) result = active_subwindow->dispatch_button_press();
1576 for(int i = 0; i < subwindows->total && !result; i++)
1578 result = subwindows->values[i]->dispatch_button_press();
1581 if(!result) result = button_press_event();
1587 int BC_WindowBase::dispatch_button_release()
1590 if(top_level == this)
1592 if(active_menubar) result = active_menubar->dispatch_button_release();
1593 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_release();
1594 if(active_subwindow && !result) result = active_subwindow->dispatch_button_release();
1595 if(!result && button_number != 4 && button_number != 5)
1596 result = dispatch_drag_stop();
1599 for(int i = 0; i < subwindows->total && !result; i++)
1601 result = subwindows->values[i]->dispatch_button_release();
1606 result = button_release_event();
1613 int BC_WindowBase::dispatch_repeat_event(int64_t duration)
1616 // all repeat event handlers get called and decide based on activity and duration
1617 // whether to respond
1618 for(int i = 0; i < subwindows->total; i++)
1620 subwindows->values[i]->dispatch_repeat_event(duration);
1624 repeat_event(duration);
1628 // Unlock next repeat signal
1629 if(window_type == MAIN_WINDOW)
1631 #ifdef SINGLE_THREAD
1632 BC_Display::display_global->unlock_repeaters(duration);
1634 for(int i = 0; i < repeaters.total; i++)
1636 if(repeaters.values[i]->delay == duration)
1638 repeaters.values[i]->repeat_lock->unlock();
1646 void BC_WindowBase::unhide_cursor()
1651 if(top_level->is_hourglass)
1652 set_cursor(HOURGLASS_CURSOR, 1, 0);
1654 set_cursor(current_cursor, 1, 0);
1656 cursor_timer->update();
1660 void BC_WindowBase::update_video_cursor()
1662 if(video_on && !is_transparent)
1664 if(cursor_timer->get_difference() > VIDEO_CURSOR_TIMEOUT && !is_transparent)
1667 set_cursor(TRANSPARENT_CURSOR, 1, 1);
1668 cursor_timer->update();
1673 cursor_timer->update();
1678 int BC_WindowBase::dispatch_cursor_leave()
1682 for(int i = 0; i < subwindows->total; i++)
1684 subwindows->values[i]->dispatch_cursor_leave();
1687 cursor_leave_event();
1691 int BC_WindowBase::dispatch_cursor_enter()
1697 if(active_menubar) result = active_menubar->dispatch_cursor_enter();
1698 if(!result && active_popup_menu) result = active_popup_menu->dispatch_cursor_enter();
1699 if(!result && active_subwindow) result = active_subwindow->dispatch_cursor_enter();
1701 for(int i = 0; !result && i < subwindows->total; i++)
1703 result = subwindows->values[i]->dispatch_cursor_enter();
1706 if(!result) result = cursor_enter_event();
1710 int BC_WindowBase::cursor_enter_event()
1715 int BC_WindowBase::cursor_leave_event()
1720 int BC_WindowBase::close_event()
1726 int BC_WindowBase::dispatch_drag_start()
1729 if(active_menubar) result = active_menubar->dispatch_drag_start();
1730 if(!result && active_popup_menu) result = active_popup_menu->dispatch_drag_start();
1731 if(!result && active_subwindow) result = active_subwindow->dispatch_drag_start();
1733 for(int i = 0; i < subwindows->total && !result; i++)
1735 result = subwindows->values[i]->dispatch_drag_start();
1738 if(!result) result = is_dragging = drag_start_event();
1742 int BC_WindowBase::dispatch_drag_stop()
1746 for(int i = 0; i < subwindows->total && !result; i++)
1748 result = subwindows->values[i]->dispatch_drag_stop();
1751 if(is_dragging && !result)
1761 int BC_WindowBase::dispatch_drag_motion()
1764 for(int i = 0; i < subwindows->total && !result; i++)
1766 result = subwindows->values[i]->dispatch_drag_motion();
1769 if(is_dragging && !result)
1771 drag_motion_event();
1779 int BC_WindowBase::show_tooltip(const char *text, int x, int y, int w, int h)
1782 int forced = !text ? force_tooltip : 1;
1783 if( !text ) text = tooltip_text;
1784 if( !text || (!forced && !get_resources()->tooltips_enabled) ) {
1785 top_level->hide_tooltip();
1789 if(w < 0) w = get_text_width(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1790 if(h < 0) h = get_text_height(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1791 // default x,y (win relative)
1792 if( x < 0 ) x = get_w();
1793 if( y < 0 ) y = get_h();
1795 get_root_coordinates(x, y, &wx, &wy);
1796 // keep the tip inside the window/display
1797 int x0 = top_level->get_x(), x1 = x0 + top_level->get_w();
1798 int x2 = top_level->get_screen_x(0, -1) + top_level->get_screen_w(0, -1);
1799 if( x1 > x2 ) x1 = x2;
1800 if( wx < x0 ) wx = x0;
1801 if( wx >= (x1-=w) ) wx = x1;
1802 int y0 = top_level->get_y(), y1 = y0 + top_level->get_h();
1803 int y2 = top_level->get_root_h(0);
1804 if( y1 > y2 ) y1 = y2;
1805 if( wy < y0 ) wy = y0;
1806 if( wy >= (y1-=h) ) wy = y1;
1807 // avoid tip under cursor (flickers)
1809 get_abs_cursor(abs_x,abs_y, 0);
1810 if( wx < abs_x && abs_x < wx+w && wy < abs_y && abs_y < wy+h ) {
1811 if( wx-abs_x < wy-abs_y )
1818 tooltip_popup = new BC_Popup(top_level, wx, wy, w, h,
1819 get_resources()->tooltip_bg_color);
1822 tooltip_popup->reposition_window(wx, wy, w, h);
1825 tooltip_popup->flash();
1826 tooltip_popup->flush();
1830 int BC_WindowBase::hide_tooltip()
1833 for(int i = 0; i < subwindows->total; i++)
1835 subwindows->values[i]->hide_tooltip();
1841 delete tooltip_popup;
1847 const char *BC_WindowBase::get_tooltip()
1849 return tooltip_text;
1852 int BC_WindowBase::set_tooltip(const char *text)
1854 tooltip_text = text;
1856 // Update existing tooltip if it is visible
1860 tooltip_popup->flash();
1864 // signal the event handler to repeat
1865 int BC_WindowBase::set_repeat(int64_t duration)
1869 printf("BC_WindowBase::set_repeat duration=%jd\n", duration);
1872 if(window_type != MAIN_WINDOW) return top_level->set_repeat(duration);
1874 #ifdef SINGLE_THREAD
1875 BC_Display::display_global->set_repeat(this, duration);
1877 // test repeater database for duplicates
1878 for(int i = 0; i < repeaters.total; i++)
1881 if(repeaters.values[i]->delay == duration)
1883 repeaters.values[i]->start_repeating(this);
1888 BC_Repeater *repeater = new BC_Repeater(this, duration);
1889 repeater->initialize();
1890 repeaters.append(repeater);
1891 repeater->start_repeating();
1896 int BC_WindowBase::unset_repeat(int64_t duration)
1898 if(window_type != MAIN_WINDOW) return top_level->unset_repeat(duration);
1900 #ifdef SINGLE_THREAD
1901 BC_Display::display_global->unset_repeat(this, duration);
1903 for(int i = 0; i < repeaters.total; i++)
1905 if(repeaters.values[i]->delay == duration)
1907 repeaters.values[i]->stop_repeating();
1915 int BC_WindowBase::unset_all_repeaters()
1917 #ifdef SINGLE_THREAD
1918 BC_Display::display_global->unset_all_repeaters(this);
1920 for(int i = 0; i < repeaters.total; i++)
1922 repeaters.values[i]->stop_repeating();
1924 repeaters.remove_all_objects();
1929 // long BC_WindowBase::get_repeat_id()
1931 // return top_level->next_repeat_id++;
1934 XEvent *BC_WindowBase::new_xevent()
1936 XEvent *event = new XEvent;
1937 memset(event, 0, sizeof(*event));
1941 #ifndef SINGLE_THREAD
1942 int BC_WindowBase::arm_repeat(int64_t duration)
1944 XEvent *event = new_xevent();
1945 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
1946 ptr->type = ClientMessage;
1947 ptr->message_type = RepeaterXAtom;
1949 ptr->data.l[0] = duration;
1951 // Couldn't use XSendEvent since it locked up randomly.
1957 int BC_WindowBase::receive_custom_xatoms(xatom_event *event)
1962 int BC_WindowBase::send_custom_xatom(xatom_event *event)
1964 #ifndef SINGLE_THREAD
1965 XEvent *myevent = new_xevent();
1966 XClientMessageEvent *ptr = (XClientMessageEvent*)myevent;
1967 ptr->type = ClientMessage;
1968 ptr->message_type = event->message_type;
1969 ptr->format = event->format;
1970 ptr->data.l[0] = event->data.l[0];
1971 ptr->data.l[1] = event->data.l[1];
1972 ptr->data.l[2] = event->data.l[2];
1973 ptr->data.l[3] = event->data.l[3];
1974 ptr->data.l[4] = event->data.l[4];
1983 Atom BC_WindowBase::create_xatom(const char *atom_name)
1985 return XInternAtom(display, atom_name, False);
1988 int BC_WindowBase::get_atoms()
1990 SetDoneXAtom = XInternAtom(display, "BC_REPEAT_EVENT", False);
1991 RepeaterXAtom = XInternAtom(display, "BC_CLOSE_EVENT", False);
1992 DestroyAtom = XInternAtom(display, "BC_DESTROY_WINDOW", False);
1993 DelWinXAtom = XInternAtom(display, "WM_DELETE_WINDOW", False);
1994 if( (ProtoXAtom = XInternAtom(display, "WM_PROTOCOLS", False)) != 0 )
1995 XChangeProperty(display, win, ProtoXAtom, XA_ATOM, 32,
1996 PropModeReplace, (unsigned char *)&DelWinXAtom, True);
2002 void BC_WindowBase::init_cursors()
2004 arrow_cursor = XCreateFontCursor(display, XC_top_left_arrow);
2005 cross_cursor = XCreateFontCursor(display, XC_crosshair);
2006 ibeam_cursor = XCreateFontCursor(display, XC_xterm);
2007 vseparate_cursor = XCreateFontCursor(display, XC_sb_v_double_arrow);
2008 hseparate_cursor = XCreateFontCursor(display, XC_sb_h_double_arrow);
2009 move_cursor = XCreateFontCursor(display, XC_fleur);
2010 left_cursor = XCreateFontCursor(display, XC_sb_left_arrow);
2011 right_cursor = XCreateFontCursor(display, XC_sb_right_arrow);
2012 upright_arrow_cursor = XCreateFontCursor(display, XC_arrow);
2013 upleft_resize_cursor = XCreateFontCursor(display, XC_top_left_corner);
2014 upright_resize_cursor = XCreateFontCursor(display, XC_top_right_corner);
2015 downleft_resize_cursor = XCreateFontCursor(display, XC_bottom_left_corner);
2016 downright_resize_cursor = XCreateFontCursor(display, XC_bottom_right_corner);
2017 hourglass_cursor = XCreateFontCursor(display, XC_watch);
2018 grabbed_cursor = create_grab_cursor();
2020 static char cursor_data[] = { 0,0,0,0, 0,0,0,0 };
2021 Colormap colormap = DefaultColormap(display, screen);
2022 Pixmap pixmap_bottom = XCreateBitmapFromData(display,
2023 rootwin, cursor_data, 8, 8);
2024 XColor black, dummy;
2025 XAllocNamedColor(display, colormap, "black", &black, &dummy);
2026 transparent_cursor = XCreatePixmapCursor(display,
2027 pixmap_bottom, pixmap_bottom, &black, &black, 0, 0);
2028 // XDefineCursor(display, win, transparent_cursor);
2029 XFreePixmap(display, pixmap_bottom);
2032 int BC_WindowBase::evaluate_color_model(int client_byte_order, int server_byte_order, int depth)
2034 int color_model = BC_TRANSPARENCY;
2038 color_model = BC_RGB8;
2041 color_model = (server_byte_order == client_byte_order) ? BC_RGB565 : BC_BGR565;
2044 color_model = server_byte_order ? BC_BGR888 : BC_RGB888;
2047 color_model = server_byte_order ? BC_BGR8888 : BC_ARGB8888;
2053 int BC_WindowBase::init_colors()
2056 current_color_value = current_color_pixel = 0;
2058 // Get the real depth
2061 ximage = XCreateImage(top_level->display,
2062 top_level->vis, top_level->default_depth,
2063 ZPixmap, 0, data, 16, 16, 8, 0);
2064 bits_per_pixel = ximage->bits_per_pixel;
2065 XDestroyImage(ximage);
2067 color_model = evaluate_color_model(client_byte_order,
2070 // Get the color model
2075 cmap = XCreateColormap(display, rootwin, vis, AllocNone);
2076 create_private_colors();
2079 cmap = DefaultColormap(display, screen);
2080 create_shared_colors();
2083 allocate_color_table();
2087 //cmap = DefaultColormap(display, screen);
2088 cmap = XCreateColormap(display, rootwin, vis, AllocNone );
2094 int BC_WindowBase::create_private_colors()
2099 for(int i = 0; i < 255; i++)
2101 color = (i & 0xc0) << 16;
2102 color += (i & 0x38) << 10;
2103 color += (i & 0x7) << 5;
2104 color_table[i][0] = color;
2106 create_shared_colors(); // overwrite the necessary colors on the table
2111 int BC_WindowBase::create_color(int color)
2113 if(total_colors == 256)
2115 // replace the closest match with an exact match
2116 color_table[get_color_rgb8(color)][0] = color;
2120 // add the color to the table
2121 color_table[total_colors][0] = color;
2127 int BC_WindowBase::create_shared_colors()
2129 create_color(BLACK);
2130 create_color(WHITE);
2132 create_color(LTGREY);
2133 create_color(MEGREY);
2134 create_color(MDGREY);
2135 create_color(DKGREY);
2137 create_color(LTCYAN);
2138 create_color(MECYAN);
2139 create_color(MDCYAN);
2140 create_color(DKCYAN);
2142 create_color(LTGREEN);
2143 create_color(GREEN);
2144 create_color(DKGREEN);
2146 create_color(LTPINK);
2150 create_color(LTBLUE);
2152 create_color(DKBLUE);
2154 create_color(LTYELLOW);
2155 create_color(MEYELLOW);
2156 create_color(MDYELLOW);
2157 create_color(DKYELLOW);
2159 create_color(LTPURPLE);
2160 create_color(MEPURPLE);
2161 create_color(MDPURPLE);
2162 create_color(DKPURPLE);
2164 create_color(FGGREY);
2165 create_color(MNBLUE);
2166 create_color(ORANGE);
2167 create_color(FTGREY);
2172 Cursor BC_WindowBase::create_grab_cursor()
2174 int iw = 23, iw1 = iw-1, iw2 = iw/2;
2175 int ih = 23, ih1 = ih-1, ih2 = ih/2;
2176 VFrame grab(iw,ih,BC_RGB888);
2178 grab.set_pixel_color(RED); // fg
2179 grab.draw_smooth(iw2,0, iw1,0, iw1,ih2);
2180 grab.draw_smooth(iw1,ih2, iw1,ih1, iw2,ih1);
2181 grab.draw_smooth(iw2,ih1, 0,ih1, 0,ih2);
2182 grab.draw_smooth(0,ih2, 0,0, iw2,0);
2183 grab.set_pixel_color(WHITE); // bg
2184 grab.draw_line(0,ih2, iw2-2,ih2);
2185 grab.draw_line(iw2+2,ih2, iw1,ih2);
2186 grab.draw_line(iw2,0, iw2,ih2-2);
2187 grab.draw_line(iw2,ih2+2, iw2,ih1);
2189 int bpl = (iw+7)/8, isz = bpl * ih;
2190 char img[isz]; memset(img, 0, isz);
2191 char msk[isz]; memset(msk, 0, isz);
2192 unsigned char **rows = grab.get_rows();
2193 for( int iy=0; iy<ih; ++iy ) {
2194 char *op = img + iy*bpl;
2195 char *mp = msk + iy*bpl;
2196 unsigned char *ip = rows[iy];
2197 for( int ix=0; ix<iw; ++ix,ip+=3 ) {
2198 if( ip[0] ) mp[ix>>3] |= (1<<(ix&7));
2199 if( !ip[1] ) op[ix>>3] |= (1<<(ix&7));
2202 unsigned long white_pix = WhitePixel(display, screen);
2203 unsigned long black_pix = BlackPixel(display, screen);
2204 Pixmap img_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2205 img, iw,ih, white_pix,black_pix, 1);
2206 Pixmap msk_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2207 msk, iw,ih, white_pix,black_pix, 1);
2210 fc.flags = bc.flags = DoRed | DoGreen | DoBlue;
2211 fc.red = 0xffff; fc.green = fc.blue = 0; // fg
2212 bc.red = 0xffff; bc.green = 0xffff; bc.blue = 0x0000; // bg
2213 Cursor cursor = XCreatePixmapCursor(display, img_xpm,msk_xpm, &fc,&bc, iw2,ih2);
2214 XFreePixmap(display, img_xpm);
2215 XFreePixmap(display, msk_xpm);
2219 int BC_WindowBase::allocate_color_table()
2221 int red, green, blue, color;
2224 for(int i = 0; i < total_colors; i++)
2226 color = color_table[i][0];
2227 red = (color & 0xFF0000) >> 16;
2228 green = (color & 0x00FF00) >> 8;
2229 blue = color & 0xFF;
2231 col.flags = DoRed | DoGreen | DoBlue;
2232 col.red = red<<8 | red;
2233 col.green = green<<8 | green;
2234 col.blue = blue<<8 | blue;
2236 XAllocColor(display, cmap, &col);
2237 color_table[i][1] = col.pixel;
2240 XInstallColormap(display, cmap);
2244 int BC_WindowBase::init_window_shape()
2246 if(bg_pixmap && bg_pixmap->use_alpha())
2248 XShapeCombineMask(top_level->display,
2249 this->win, ShapeBounding, 0, 0,
2250 bg_pixmap->get_alpha(), ShapeSet);
2256 int BC_WindowBase::init_gc()
2258 unsigned long gcmask;
2259 gcmask = GCFont | GCGraphicsExposures;
2262 gcvalues.font = mediumfont->fid; // set the font
2263 gcvalues.graphics_exposures = 0; // prevent expose events for every redraw
2264 gc = XCreateGC(display, rootwin, gcmask, &gcvalues);
2266 // gcmask = GCCapStyle | GCJoinStyle;
2267 // XGetGCValues(display, gc, gcmask, &gcvalues);
2268 // printf("BC_WindowBase::init_gc %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2272 int BC_WindowBase::init_fonts()
2274 if( !(smallfont = XLoadQueryFont(display, _(resources->small_font))) )
2275 if( !(smallfont = XLoadQueryFont(display, _(resources->small_font2))) )
2276 smallfont = XLoadQueryFont(display, "fixed");
2277 if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font))) )
2278 if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font2))) )
2279 mediumfont = XLoadQueryFont(display, "fixed");
2280 if( !(largefont = XLoadQueryFont(display, _(resources->large_font))) )
2281 if( !(largefont = XLoadQueryFont(display, _(resources->large_font2))) )
2282 largefont = XLoadQueryFont(display, "fixed");
2283 if( !(bigfont = XLoadQueryFont(display, _(resources->big_font))) )
2284 if( !(bigfont = XLoadQueryFont(display, _(resources->big_font2))) )
2285 bigfont = XLoadQueryFont(display, "fixed");
2287 if((clockfont = XLoadQueryFont(display, _(resources->clock_font))) == NULL)
2288 if((clockfont = XLoadQueryFont(display, _(resources->clock_font2))) == NULL)
2289 clockfont = XLoadQueryFont(display, "fixed");
2292 if(get_resources()->use_fontset)
2297 // FIXME: should check the m,d,n values
2298 smallfontset = XCreateFontSet(display, resources->small_fontset, &m, &n, &d);
2300 smallfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2301 mediumfontset = XCreateFontSet(display, resources->medium_fontset, &m, &n, &d);
2302 if( !mediumfontset )
2303 mediumfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2304 largefontset = XCreateFontSet(display, resources->large_fontset, &m, &n, &d);
2306 largefontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2307 bigfontset = XCreateFontSet(display, resources->big_fontset, &m, &n, &d);
2309 bigfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2310 clockfontset = XCreateFontSet(display, resources->clock_fontset, &m, &n, &d);
2312 clockfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2313 if(clockfontset && bigfontset && largefontset && mediumfontset && smallfontset) {
2314 curr_fontset = mediumfontset;
2315 get_resources()->use_fontset = 1;
2319 get_resources()->use_fontset = 0;
2326 void BC_WindowBase::init_xft()
2329 if( !get_resources()->use_xft ) return;
2330 // apparently, xft is not reentrant, more than this is needed
2331 static Mutex xft_init_lock("BC_WindowBase::xft_init_lock", 0);
2332 xft_init_lock.lock("BC_WindowBase::init_xft");
2333 if(!(smallfont_xft =
2334 (resources->small_font_xft[0] == '-' ?
2335 xftFontOpenXlfd(display, screen, resources->small_font_xft) :
2336 xftFontOpenName(display, screen, resources->small_font_xft))) )
2337 if(!(smallfont_xft =
2338 xftFontOpenXlfd(display, screen, resources->small_font_xft2)))
2339 smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2340 if(!(mediumfont_xft =
2341 (resources->medium_font_xft[0] == '-' ?
2342 xftFontOpenXlfd(display, screen, resources->medium_font_xft) :
2343 xftFontOpenName(display, screen, resources->medium_font_xft))) )
2344 if(!(mediumfont_xft =
2345 xftFontOpenXlfd(display, screen, resources->medium_font_xft2)))
2346 mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2347 if(!(largefont_xft =
2348 (resources->large_font_xft[0] == '-' ?
2349 xftFontOpenXlfd(display, screen, resources->large_font_xft) :
2350 xftFontOpenName(display, screen, resources->large_font_xft))) )
2351 if(!(largefont_xft =
2352 xftFontOpenXlfd(display, screen, resources->large_font_xft2)))
2353 largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2355 (resources->big_font_xft[0] == '-' ?
2356 xftFontOpenXlfd(display, screen, resources->big_font_xft) :
2357 xftFontOpenName(display, screen, resources->big_font_xft))) )
2359 xftFontOpenXlfd(display, screen, resources->big_font_xft2)))
2360 bigfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2361 if(!(clockfont_xft =
2362 (resources->clock_font_xft[0] == '-' ?
2363 xftFontOpenXlfd(display, screen, resources->clock_font_xft) :
2364 xftFontOpenName(display, screen, resources->clock_font_xft))) )
2365 clockfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2368 if(!(bold_smallfont_xft =
2369 (resources->small_b_font_xft[0] == '-' ?
2370 xftFontOpenXlfd(display, screen, resources->small_b_font_xft) :
2371 xftFontOpenName(display, screen, resources->small_b_font_xft))) )
2372 bold_smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2373 if(!(bold_mediumfont_xft =
2374 (resources->medium_b_font_xft[0] == '-' ?
2375 xftFontOpenXlfd(display, screen, resources->medium_b_font_xft) :
2376 xftFontOpenName(display, screen, resources->medium_b_font_xft))) )
2377 bold_mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2378 if(!(bold_largefont_xft =
2379 (resources->large_b_font_xft[0] == '-' ?
2380 xftFontOpenXlfd(display, screen, resources->large_b_font_xft) :
2381 xftFontOpenName(display, screen, resources->large_b_font_xft))) )
2382 bold_largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2384 if( !smallfont_xft || !mediumfont_xft || !largefont_xft || !bigfont_xft ||
2385 !bold_largefont_xft || !bold_mediumfont_xft || !bold_largefont_xft ||
2387 printf("BC_WindowBase::init_fonts: no xft fonts found:"
2388 " %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n",
2389 resources->small_font_xft, smallfont_xft,
2390 resources->medium_font_xft, mediumfont_xft,
2391 resources->large_font_xft, largefont_xft,
2392 resources->big_font_xft, bigfont_xft,
2393 resources->clock_font_xft, clockfont_xft,
2394 resources->small_b_font_xft, bold_smallfont_xft,
2395 resources->medium_b_font_xft, bold_mediumfont_xft,
2396 resources->large_b_font_xft, bold_largefont_xft);
2397 get_resources()->use_xft = 0;
2400 // _XftDisplayInfo needs a lock.
2401 xftDefaultHasRender(display);
2402 xft_init_lock.unlock();
2406 void BC_WindowBase::init_glyphs()
2408 // draw all ascii char glyphs
2409 // There are problems with some/my graphics boards/drivers
2410 // which cause some glyphs to be munged if draws occur while
2411 // the font is being loaded. This code fills the font caches
2412 // by drawing all the ascii glyphs before the system starts.
2413 // Not a fix, but much better than nothing.
2414 static int inited = 0;
2415 if( inited ) return;
2416 XGrabServer(display);
2419 int cur_font = current_font;
2420 // locale encodings, needed glyphs to be preloaded
2421 const char *text = _( // ascii 0x20...0x7e
2422 " !\"#$%&'()*+,-./0123456789:;<=>?"
2423 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
2424 "`abcdefghijklmnopqrstuvwxyz{|}~");
2425 for( int font=SMALLFONT; font<=LARGEFONT; ++font ) {
2427 draw_text(5,5, text);
2430 XUngrabServer(display);
2433 void BC_WindowBase::init_im()
2435 XIMStyles *xim_styles;
2438 if(!(input_method = XOpenIM(display, NULL, NULL, NULL)))
2440 printf("BC_WindowBase::init_im: Could not open input method.\n");
2443 if(XGetIMValues(input_method, XNQueryInputStyle, &xim_styles, NULL) ||
2446 printf("BC_WindowBase::init_im: Input method doesn't support any styles.\n");
2447 XCloseIM(input_method);
2452 for(int z = 0; z < xim_styles->count_styles; z++)
2454 if(xim_styles->supported_styles[z] == (XIMPreeditNothing | XIMStatusNothing))
2456 xim_style = xim_styles->supported_styles[z];
2464 printf("BC_WindowBase::init_im: Input method doesn't support the style we need.\n");
2465 XCloseIM(input_method);
2469 input_context = XCreateIC(input_method, XNInputStyle, xim_style,
2470 XNClientWindow, win, XNFocusWindow, win, NULL);
2473 printf("BC_WindowBase::init_im: Failed to create input context.\n");
2474 XCloseIM(input_method);
2479 void BC_WindowBase::finit_im()
2481 if( input_context ) {
2482 XDestroyIC(input_context);
2485 if( input_method ) {
2486 XCloseIM(input_method);
2492 int BC_WindowBase::get_color(int64_t color)
2494 // return pixel of color
2495 // use this only for drawing subwindows not for bitmaps
2496 int i, test, difference;
2502 return get_color_rgb8(color);
2503 // test last color looked up
2504 if(current_color_value == color)
2505 return current_color_pixel;
2508 current_color_value = color;
2509 for(i = 0; i < total_colors; i++)
2511 if(color_table[i][0] == color)
2513 current_color_pixel = color_table[i][1];
2514 return current_color_pixel;
2518 // find nearest match
2519 difference = 0xFFFFFF;
2521 for(i = 0; i < total_colors; i++)
2523 test = abs((int)(color_table[i][0] - color));
2525 if(test < difference)
2527 current_color_pixel = color_table[i][1];
2531 return current_color_pixel;
2534 return get_color_rgb16(color);
2537 return get_color_bgr16(color);
2541 return client_byte_order == server_byte_order ?
2542 color : get_color_bgr24(color);
2550 int BC_WindowBase::get_color_rgb8(int color)
2554 pixel = (color & 0xc00000) >> 16;
2555 pixel += (color & 0xe000) >> 10;
2556 pixel += (color & 0xe0) >> 5;
2560 int64_t BC_WindowBase::get_color_rgb16(int color)
2563 result = (color & 0xf80000) >> 8;
2564 result += (color & 0xfc00) >> 5;
2565 result += (color & 0xf8) >> 3;
2570 int64_t BC_WindowBase::get_color_bgr16(int color)
2573 result = (color & 0xf80000) >> 19;
2574 result += (color & 0xfc00) >> 5;
2575 result += (color & 0xf8) << 8;
2580 int64_t BC_WindowBase::get_color_bgr24(int color)
2583 result = (color & 0xff) << 16;
2584 result += (color & 0xff00);
2585 result += (color & 0xff0000) >> 16;
2589 void BC_WindowBase::start_video()
2591 cursor_timer->update();
2593 // set_color(BLACK);
2594 // draw_box(0, 0, get_w(), get_h());
2598 void BC_WindowBase::stop_video()
2606 int64_t BC_WindowBase::get_color()
2608 return top_level->current_color;
2611 void BC_WindowBase::set_color(int64_t color)
2613 top_level->current_color = color;
2614 XSetForeground(top_level->display,
2616 top_level->get_color(color));
2619 void BC_WindowBase::set_opaque()
2621 XSetFunction(top_level->display, top_level->gc, GXcopy);
2624 void BC_WindowBase::set_inverse()
2626 XSetFunction(top_level->display, top_level->gc, GXxor);
2629 void BC_WindowBase::set_line_width(int value)
2631 this->line_width = value;
2632 XSetLineAttributes(top_level->display, top_level->gc, value, /* line_width */
2633 line_dashes == 0 ? LineSolid : LineOnOffDash, /* line_style */
2634 line_dashes == 0 ? CapRound : CapNotLast, /* cap_style */
2635 JoinMiter); /* join_style */
2637 if(line_dashes > 0) {
2638 const char dashes = line_dashes;
2639 XSetDashes(top_level->display, top_level->gc, 0, &dashes, 1);
2642 // XGCValues gcvalues;
2643 // unsigned long gcmask;
2644 // gcmask = GCCapStyle | GCJoinStyle;
2645 // XGetGCValues(top_level->display, top_level->gc, gcmask, &gcvalues);
2646 // printf("BC_WindowBase::set_line_width %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2649 void BC_WindowBase::set_line_dashes(int value)
2651 line_dashes = value;
2652 // call XSetLineAttributes
2653 set_line_width(line_width);
2657 Cursor BC_WindowBase::get_cursor_struct(int cursor)
2661 case ARROW_CURSOR: return top_level->arrow_cursor;
2662 case CROSS_CURSOR: return top_level->cross_cursor;
2663 case IBEAM_CURSOR: return top_level->ibeam_cursor;
2664 case VSEPARATE_CURSOR: return top_level->vseparate_cursor;
2665 case HSEPARATE_CURSOR: return top_level->hseparate_cursor;
2666 case MOVE_CURSOR: return top_level->move_cursor;
2667 case LEFT_CURSOR: return top_level->left_cursor;
2668 case RIGHT_CURSOR: return top_level->right_cursor;
2669 case UPRIGHT_ARROW_CURSOR: return top_level->upright_arrow_cursor;
2670 case UPLEFT_RESIZE: return top_level->upleft_resize_cursor;
2671 case UPRIGHT_RESIZE: return top_level->upright_resize_cursor;
2672 case DOWNLEFT_RESIZE: return top_level->downleft_resize_cursor;
2673 case DOWNRIGHT_RESIZE: return top_level->downright_resize_cursor;
2674 case HOURGLASS_CURSOR: return top_level->hourglass_cursor;
2675 case TRANSPARENT_CURSOR: return top_level->transparent_cursor;
2676 case GRABBED_CURSOR: return top_level->grabbed_cursor;
2681 void BC_WindowBase::set_cursor(int cursor, int override, int flush)
2683 // inherit cursor from parent
2686 XUndefineCursor(top_level->display, win);
2687 current_cursor = cursor;
2690 // don't change cursor if overridden
2691 if((!top_level->is_hourglass && !is_transparent) ||
2694 XDefineCursor(top_level->display, win, get_cursor_struct(cursor));
2695 if(flush) this->flush();
2698 if(!override) current_cursor = cursor;
2701 void BC_WindowBase::set_x_cursor(int cursor)
2703 temp_cursor = XCreateFontCursor(top_level->display, cursor);
2704 XDefineCursor(top_level->display, win, temp_cursor);
2705 current_cursor = cursor;
2709 int BC_WindowBase::get_cursor()
2711 return current_cursor;
2714 void BC_WindowBase::start_hourglass()
2716 top_level->start_hourglass_recursive();
2720 void BC_WindowBase::stop_hourglass()
2722 top_level->stop_hourglass_recursive();
2726 void BC_WindowBase::start_hourglass_recursive()
2728 if(this == top_level)
2736 set_cursor(HOURGLASS_CURSOR, 1, 0);
2737 for(int i = 0; i < subwindows->total; i++)
2739 subwindows->values[i]->start_hourglass_recursive();
2744 void BC_WindowBase::stop_hourglass_recursive()
2746 if(this == top_level)
2748 if(hourglass_total == 0) return;
2749 top_level->hourglass_total--;
2752 if(!top_level->hourglass_total)
2754 top_level->is_hourglass = 0;
2756 // Cause set_cursor to perform change
2758 set_cursor(current_cursor, 1, 0);
2760 for(int i = 0; i < subwindows->total; i++)
2762 subwindows->values[i]->stop_hourglass_recursive();
2770 XFontStruct* BC_WindowBase::get_font_struct(int font)
2772 // Clear out unrelated flags
2773 if(font & BOLDFACE) font ^= BOLDFACE;
2776 case SMALLFONT: return top_level->smallfont; break;
2777 case MEDIUMFONT: return top_level->mediumfont; break;
2778 case LARGEFONT: return top_level->largefont; break;
2779 case BIGFONT: return top_level->bigfont; break;
2780 case CLOCKFONT: return top_level->clockfont; break;
2785 XFontSet BC_WindowBase::get_fontset(int font)
2789 if(get_resources()->use_fontset)
2791 switch(font & 0xff) {
2792 case SMALLFONT: fs = top_level->smallfontset; break;
2793 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2794 case LARGEFONT: fs = top_level->largefontset; break;
2795 case BIGFONT: fs = top_level->bigfontset; break;
2796 case CLOCKFONT: fs = top_level->clockfontset; break;
2804 XftFont* BC_WindowBase::get_xft_struct(int font)
2807 case SMALLFONT: return (XftFont*)top_level->smallfont_xft;
2808 case MEDIUMFONT: return (XftFont*)top_level->mediumfont_xft;
2809 case LARGEFONT: return (XftFont*)top_level->largefont_xft;
2810 case BIGFONT: return (XftFont*)top_level->bigfont_xft;
2811 case CLOCKFONT: return (XftFont*)top_level->clockfont_xft;
2812 case MEDIUMFONT_3D: return (XftFont*)top_level->bold_mediumfont_xft;
2813 case SMALLFONT_3D: return (XftFont*)top_level->bold_smallfont_xft;
2814 case LARGEFONT_3D: return (XftFont*)top_level->bold_largefont_xft;
2822 int BC_WindowBase::get_current_font()
2824 return top_level->current_font;
2827 void BC_WindowBase::set_font(int font)
2829 top_level->current_font = font;
2832 if(get_resources()->use_xft) {}
2835 if(get_resources()->use_fontset) {
2839 if(get_font_struct(font))
2841 XSetFont(top_level->display, top_level->gc, get_font_struct(font)->fid);
2847 void BC_WindowBase::set_fontset(int font)
2851 if(get_resources()->use_fontset) {
2853 case SMALLFONT: fs = top_level->smallfontset; break;
2854 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2855 case LARGEFONT: fs = top_level->largefontset; break;
2856 case BIGFONT: fs = top_level->bigfontset; break;
2857 case CLOCKFONT: fs = top_level->clockfontset; break;
2865 XFontSet BC_WindowBase::get_curr_fontset(void)
2867 if(get_resources()->use_fontset)
2868 return curr_fontset;
2872 int BC_WindowBase::get_single_text_width(int font, const char *text, int length)
2875 if(get_resources()->use_xft && get_xft_struct(font))
2878 #ifdef X_HAVE_UTF8_STRING
2879 if(get_resources()->locale_utf8)
2881 xftTextExtentsUtf8(top_level->display,
2882 get_xft_struct(font),
2883 (const XftChar8 *)text,
2890 xftTextExtents8(top_level->display,
2891 get_xft_struct(font),
2892 (const XftChar8 *)text,
2896 return extents.xOff;
2900 if(get_resources()->use_fontset && top_level->get_fontset(font))
2901 return XmbTextEscapement(top_level->get_fontset(font), text, length);
2903 if(get_font_struct(font))
2904 return XTextWidth(get_font_struct(font), text, length);
2910 case MEDIUM_7SEGMENT:
2911 return get_resources()->medium_7segment[0]->get_w() * length;
2921 int BC_WindowBase::get_text_width(int font, const char *text, int length)
2923 int i, j, w = 0, line_w = 0;
2924 if(length < 0) length = strlen(text);
2926 for(i = 0, j = 0; i <= length; i++)
2931 line_w = get_single_text_width(font, &text[j], i - j);
2937 line_w = get_single_text_width(font, &text[j], length - j);
2939 if(line_w > w) w = line_w;
2942 if(i > length && w == 0)
2944 w = get_single_text_width(font, text, length);
2950 int BC_WindowBase::get_text_width(int font, const wchr_t *text, int length)
2953 if( length < 0 ) length = wstrlen(text);
2955 for( i=j=0; i<length && text[i]; ++i ) {
2956 if( text[i] != '\n' ) continue;
2958 int lw = get_single_text_width(font, &text[j], i-j);
2959 if( w < lw ) w = lw;
2964 int lw = get_single_text_width(font, &text[j], length-j);
2965 if( w < lw ) w = lw;
2971 int BC_WindowBase::get_text_ascent(int font)
2975 if( (fstruct = get_xft_struct(font)) != 0 )
2976 return fstruct->ascent;
2978 if(get_resources()->use_fontset && top_level->get_fontset(font))
2980 XFontSetExtents *extents;
2982 extents = XExtentsOfFontSet(top_level->get_fontset(font));
2983 return -extents->max_logical_extent.y;
2986 if(get_font_struct(font))
2987 return top_level->get_font_struct(font)->ascent;
2990 case MEDIUM_7SEGMENT:
2991 return get_resources()->medium_7segment[0]->get_h();
2996 int BC_WindowBase::get_text_descent(int font)
3000 if( (fstruct = get_xft_struct(font)) != 0 )
3001 return fstruct->descent;
3003 if(get_resources()->use_fontset && top_level->get_fontset(font)) {
3004 XFontSetExtents *extents;
3005 extents = XExtentsOfFontSet(top_level->get_fontset(font));
3006 return (extents->max_logical_extent.height
3007 + extents->max_logical_extent.y);
3010 if(get_font_struct(font))
3011 return top_level->get_font_struct(font)->descent;
3016 int BC_WindowBase::get_text_height(int font, const char *text)
3021 if( (fstruct = get_xft_struct(font)) != 0 )
3022 rowh = fstruct->height;
3025 rowh = get_text_ascent(font) + get_text_descent(font);
3027 if(!text) return rowh;
3029 // Add height of lines
3030 int h = 0, i, length = strlen(text);
3031 for(i = 0; i <= length; i++)
3042 // truncate the text with ... & return a new string
3043 char *BC_WindowBase::get_truncated_text(int font, const char *text, int max_w)
3045 char *result = cstrdup(text);
3046 int text_w = get_text_width(font, text);
3047 int ci = -1, len = strlen(text);
3048 if( text_w > max_w ) {
3049 // get center of string
3050 int cx = text_w/2, best = INT_MAX;
3051 for( int i=1; i<=len; ++i ) {
3052 int cw = get_text_width(font, text, i);
3053 if( abs(cw-cx) < abs(best-cx) ) {
3058 if( ci > 0 && ci < len-1 ) {
3059 // insert ... in the center
3060 result[ci-1] = result[ci] = result[ci+1] = '.';
3062 while( ci-2>=0 && ci+2<(int)strlen(result) &&
3063 get_text_width(font, result) > max_w ) {
3064 // take away a character from the longer side
3065 int left_w = get_text_width(font, result, ci-2);
3066 int right_w = get_text_width(font, result + ci+3);
3067 int i = left_w > right_w ? --ci-1 : ci+2;
3068 while( (result[i]=result[i+1])!=0 ) ++i;
3075 BC_Bitmap* BC_WindowBase::new_bitmap(int w, int h, int color_model)
3077 if(color_model < 0) color_model = top_level->get_color_model();
3078 return new BC_Bitmap(top_level, w, h, color_model);
3081 void BC_WindowBase::init_wait()
3083 #ifndef SINGLE_THREAD
3084 if(window_type != MAIN_WINDOW)
3085 top_level->init_wait();
3086 init_lock->lock("BC_WindowBase::init_wait");
3087 init_lock->unlock();
3091 int BC_WindowBase::accel_available(int color_model, int lock_it)
3093 if( window_type != MAIN_WINDOW )
3094 return top_level->accel_available(color_model, lock_it);
3096 lock_window("BC_WindowBase::accel_available");
3098 switch(color_model) {
3100 grab_port_id(color_model);
3104 grab_port_id(color_model);
3113 //printf("BC_WindowBase::accel_available %d %d\n", color_model, xvideo_port_id);
3114 return xvideo_port_id >= 0 ? 1 : 0;
3118 int BC_WindowBase::grab_port_id(int color_model)
3121 if( !get_resources()->use_xvideo || // disabled
3122 !get_resources()->use_shm ) // Only local server is fast enough.
3124 if( xvideo_port_id >= 0 )
3125 return xvideo_port_id;
3127 unsigned int ver, rev, reqBase, eventBase, errorBase;
3128 if( Success != XvQueryExtension(display, // XV extension is available
3129 &ver, &rev, &reqBase, &eventBase, &errorBase) )
3132 // XV adaptors are available
3133 unsigned int numAdapt = 0;
3134 XvAdaptorInfo *info = 0;
3135 XvQueryAdaptors(display, DefaultRootWindow(display), &numAdapt, &info);
3139 // Translate from color_model to X color model
3140 int x_color_model = BC_CModels::bc_to_x(color_model);
3142 // Get adaptor with desired color model
3143 for( int i = 0; i < (int)numAdapt && xvideo_port_id == -1; i++) {
3144 if( !(info[i].type & XvImageMask) || !info[i].num_ports ) continue;
3145 // adaptor supports XvImages
3146 int numFormats = 0, numPorts = info[i].num_ports;
3147 XvImageFormatValues *formats =
3148 XvListImageFormats(display, info[i].base_id, &numFormats);
3149 if( !formats ) continue;
3151 for( int j=0; j<numFormats && xvideo_port_id<0; ++j ) {
3152 if( formats[j].id != x_color_model ) continue;
3153 // this adaptor supports the desired format, grab a port
3154 for( int k=0; k<numPorts; ++k ) {
3155 if( Success == XvGrabPort(top_level->display,
3156 info[i].base_id+k, CurrentTime) ) {
3157 //printf("BC_WindowBase::grab_port_id %llx\n", info[i].base_id);
3158 xvideo_port_id = info[i].base_id + k;
3166 XvFreeAdaptorInfo(info);
3167 return xvideo_port_id;
3174 int BC_WindowBase::show_window(int flush)
3176 for(int i = 0; i < subwindows->size(); i++)
3178 subwindows->get(i)->show_window(0);
3181 XMapWindow(top_level->display, win);
3182 if(flush) XFlush(top_level->display);
3183 // XSync(top_level->display, 0);
3188 int BC_WindowBase::hide_window(int flush)
3190 for(int i = 0; i < subwindows->size(); i++)
3192 subwindows->get(i)->hide_window(0);
3195 XUnmapWindow(top_level->display, win);
3196 if(flush) this->flush();
3201 BC_MenuBar* BC_WindowBase::add_menubar(BC_MenuBar *menu_bar)
3203 subwindows->append((BC_SubWindow*)menu_bar);
3205 menu_bar->parent_window = this;
3206 menu_bar->top_level = this->top_level;
3207 menu_bar->initialize();
3211 BC_WindowBase* BC_WindowBase::add_popup(BC_WindowBase *window)
3213 //printf("BC_WindowBase::add_popup window=%p win=%p\n", window, window->win);
3214 if(this != top_level) return top_level->add_popup(window);
3215 popups.append(window);
3219 void BC_WindowBase::remove_popup(BC_WindowBase *window)
3221 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3222 if(this != top_level)
3223 top_level->remove_popup(window);
3225 popups.remove(window);
3226 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3230 BC_WindowBase* BC_WindowBase::add_subwindow(BC_WindowBase *subwindow)
3232 subwindows->append(subwindow);
3234 if(subwindow->bg_color == -1) subwindow->bg_color = this->bg_color;
3236 // parent window must be set before the subwindow initialization
3237 subwindow->parent_window = this;
3238 subwindow->top_level = this->top_level;
3240 // Execute derived initialization
3241 subwindow->initialize();
3246 BC_WindowBase* BC_WindowBase::add_tool(BC_WindowBase *subwindow)
3248 return add_subwindow(subwindow);
3251 int BC_WindowBase::flash(int x, int y, int w, int h, int flush)
3253 if( !top_level->flash_enabled ) return 0;
3254 //printf("BC_WindowBase::flash %d %d %d %d %d\n", __LINE__, w, h, this->w, this->h);
3256 XSetWindowBackgroundPixmap(top_level->display, win, pixmap->opaque_pixmap);
3259 XClearArea(top_level->display, win, x, y, w, h, 0);
3263 XClearWindow(top_level->display, win);
3271 int BC_WindowBase::flash(int flush)
3273 flash(-1, -1, -1, -1, flush);
3277 void BC_WindowBase::flush()
3279 //if(!get_window_lock())
3280 // printf("BC_WindowBase::flush %s not locked\n", top_level->title);
3281 // X gets hosed if Flush/Sync are not user locked (at libX11-1.1.5 / libxcb-1.1.91)
3282 // _XReply deadlocks in condition_wait waiting for xlib lock when waiters!=-1
3283 int locked = get_window_lock();
3284 if( !locked ) lock_window("BC_WindowBase::flush");
3285 XFlush(top_level->display);
3286 if( !locked ) unlock_window();
3289 void BC_WindowBase::sync_display()
3291 int locked = get_window_lock();
3292 if( !locked ) lock_window("BC_WindowBase::sync_display");
3293 XSync(top_level->display, False);
3294 if( !locked ) unlock_window();
3297 int BC_WindowBase::get_window_lock()
3299 #ifdef SINGLE_THREAD
3300 return BC_Display::display_global->get_display_locked();
3302 return top_level->window_lock;
3306 int BC_WindowBase::lock_window(const char *location)
3308 if(top_level && top_level != this)
3310 top_level->lock_window(location);
3315 SET_LOCK(this, title, location);
3316 #ifdef SINGLE_THREAD
3317 BC_Display::lock_display(location);
3319 XLockDisplay(top_level->display);
3320 top_level->display_lock_owner = pthread_self();
3323 ++top_level->window_lock;
3327 printf("BC_WindowBase::lock_window top_level NULL\n");
3332 int BC_WindowBase::unlock_window()
3334 if(top_level && top_level != this)
3336 top_level->unlock_window();
3342 if( !top_level->window_lock ) {
3343 printf("BC_WindowBase::unlock_window %s not locked\n", title);
3346 if( top_level->window_lock > 0 )
3347 if( --top_level->window_lock == 0 )
3348 top_level->display_lock_owner = 0;
3349 #ifdef SINGLE_THREAD
3350 BC_Display::unlock_display();
3352 XUnlockDisplay(top_level->display);
3357 printf("BC_WindowBase::unlock_window top_level NULL\n");
3362 int BC_WindowBase::break_lock()
3364 if( !top_level ) return 0;
3365 if( top_level != this ) return top_level->break_lock();
3366 if( top_level->display_lock_owner != pthread_self() ) return 0;
3367 if( top_level->window_lock != 1 ) return 0;
3370 display_lock_owner = 0;
3371 #ifdef SINGLE_THREAD
3372 BC_Display::unlock_display();
3374 XUnlockDisplay(display);
3379 void BC_WindowBase::set_done(int return_value)
3381 if(done_set) return;
3383 if(window_type != MAIN_WINDOW)
3384 top_level->set_done(return_value);
3387 #ifdef SINGLE_THREAD
3388 this->return_value = return_value;
3389 BC_Display::display_global->arm_completion(this);
3390 completion_lock->unlock();
3391 #else // SINGLE_THREAD
3393 if( !event_thread ) return;
3394 XEvent *event = new_xevent();
3395 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
3396 event->type = ClientMessage;
3397 ptr->message_type = SetDoneXAtom;
3399 this->return_value = return_value;
3400 // May lock up here because XSendEvent doesn't work too well
3401 // asynchronous with XNextEvent.
3402 // This causes BC_WindowEvents to forward a copy of the event to run_window where
3404 // Deletion of event_thread is done at the end of BC_WindowBase::run_window() - by calling the destructor
3410 void BC_WindowBase::close(int return_value)
3412 hide_window(); flush();
3413 set_done(return_value);
3416 int BC_WindowBase::grab(BC_WindowBase *window)
3418 if( window->active_grab && this != window->active_grab ) return 0;
3419 window->active_grab = this;
3420 this->grab_active = window;
3423 int BC_WindowBase::ungrab(BC_WindowBase *window)
3425 if( window->active_grab && this != window->active_grab ) return 0;
3426 window->active_grab = 0;
3427 this->grab_active = 0;
3430 int BC_WindowBase::grab_event_count()
3433 #ifndef SINGLE_THREAD
3434 result = grab_active->get_event_count();
3438 int BC_WindowBase::grab_buttons()
3440 XSync(top_level->display, False);
3441 if( XGrabButton(top_level->display, AnyButton, AnyModifier,
3442 top_level->rootwin, True, ButtonPressMask | ButtonReleaseMask,
3443 GrabModeAsync, GrabModeSync, None, None) == GrabSuccess ) {
3444 set_active_subwindow(this);
3449 void BC_WindowBase::ungrab_buttons()
3451 XUngrabButton(top_level->display, AnyButton, AnyModifier, top_level->rootwin);
3452 set_active_subwindow(0);
3455 void BC_WindowBase::grab_cursor()
3457 Cursor cursor_grab = get_cursor_struct(GRABBED_CURSOR);
3458 XGrabPointer(top_level->display, top_level->rootwin, True,
3459 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
3460 GrabModeAsync, GrabModeAsync, None, cursor_grab, CurrentTime);
3462 void BC_WindowBase::ungrab_cursor()
3464 XUngrabPointer(top_level->display, CurrentTime);
3468 // WidthOfScreen/HeightOfScreen of XDefaultScreenOfDisplay
3469 // this is the bounding box of all the screens
3471 int BC_WindowBase::get_root_w(int lock_display)
3473 if(lock_display) lock_window("BC_WindowBase::get_root_w");
3474 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3475 int result = WidthOfScreen(def_screen);
3476 if(lock_display) unlock_window();
3480 int BC_WindowBase::get_root_h(int lock_display)
3482 if(lock_display) lock_window("BC_WindowBase::get_root_h");
3483 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3484 int result = HeightOfScreen(def_screen);
3485 if(lock_display) unlock_window();
3489 XineramaScreenInfo *
3490 BC_WindowBase::get_xinerama_info(int screen)
3492 if( !xinerama_info || !xinerama_screens ) return 0;
3494 for( int i=0; i<xinerama_screens; ++i )
3495 if( xinerama_info[i].screen_number == screen )
3496 return &xinerama_info[i];
3499 int top_x = get_x(), top_y = get_y();
3500 if( BC_DisplayInfo::left_border >= 0 ) top_x += BC_DisplayInfo::left_border;
3501 if( BC_DisplayInfo::top_border >= 0 ) top_y += BC_DisplayInfo::top_border;
3502 for( int i=0; i<xinerama_screens; ++i ) {
3503 int scr_y = top_y - xinerama_info[i].y_org;
3504 if( scr_y < 0 || scr_y >= xinerama_info[i].height ) continue;
3505 int scr_x = top_x - xinerama_info[i].x_org;
3506 if( scr_x >= 0 && scr_x < xinerama_info[i].width )
3507 return &xinerama_info[i];
3512 void BC_WindowBase::get_fullscreen_geometry(int &wx, int &wy, int &ww, int &wh)
3514 XineramaScreenInfo *info = top_level->get_xinerama_info(-1);
3516 wx = info->x_org; wy = info->y_org;
3517 ww = info->width; wh = info->height;
3520 wx = get_screen_x(0, -1);
3521 wy = get_screen_y(0, -1);
3522 int scr_w0 = get_screen_w(0, 0);
3523 int root_w = get_root_w(0);
3524 int root_h = get_root_h(0);
3525 if( root_w > scr_w0 ) { // multi-headed
3526 if( wx >= scr_w0 ) {
3527 // assumes right side is the big one
3528 ww = root_w - scr_w0;
3532 // use same aspect ratio to compute left height
3534 wh = (w*root_h) / (root_w-scr_w0);
3544 int BC_WindowBase::get_screen_x(int lock_display, int screen)
3547 if(lock_display) lock_window("BC_WindowBase::get_screen_x");
3548 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3551 int root_w = get_root_w(0);
3552 int root_h = get_root_h(0);
3553 // Shift X based on position of current window if dual head
3554 if( (float)root_w/root_h > 1.8 ) {
3555 root_w = get_screen_w(0, 0);
3556 if( top_level->get_x() >= root_w )
3561 result = info->x_org;
3562 if(lock_display) unlock_window();
3566 int BC_WindowBase::get_screen_y(int lock_display, int screen)
3568 if(lock_display) lock_window("BC_WindowBase::get_screen_y");
3569 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3570 int result = !info ? 0 : info->y_org;
3571 if(lock_display) unlock_window();
3575 int BC_WindowBase::get_screen_w(int lock_display, int screen)
3578 if(lock_display) lock_window("BC_WindowBase::get_screen_w");
3579 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3581 int width = get_root_w(0);
3582 int height = get_root_h(0);
3583 if( (float)width/height > 1.8 ) {
3584 // If dual head, the screen width is > 16x9
3585 // but we only want to fill one screen
3586 // this code assumes the "big" screen is on the right
3587 int scr_w0 = width / 2;
3589 case 600: scr_w0 = 800; break;
3590 case 720: scr_w0 = 1280; break;
3591 case 1024: scr_w0 = 1280; break;
3592 case 1200: scr_w0 = 1600; break;
3593 case 1080: scr_w0 = 1920; break;
3595 int scr_w1 = width - scr_w0;
3596 result = screen > 0 ? scr_w1 :
3597 screen == 0 ? scr_w0 :
3598 top_level->get_x() < scr_w0 ? scr_w0 : scr_w1;
3604 result = info->width;
3605 if(lock_display) unlock_window();
3609 int BC_WindowBase::get_screen_h(int lock_display, int screen)
3611 if(lock_display) lock_window("BC_WindowBase::get_screen_h");
3612 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3613 int result = info ? info->height : get_root_h(0);
3614 if(lock_display) unlock_window();
3618 // Bottom right corner
3619 int BC_WindowBase::get_x2()
3624 int BC_WindowBase::get_y2()
3629 int BC_WindowBase::get_video_on()
3634 int BC_WindowBase::get_hidden()
3636 return top_level->hidden;
3639 int BC_WindowBase::cursor_inside()
3641 return (top_level->cursor_x >= 0 &&
3642 top_level->cursor_y >= 0 &&
3643 top_level->cursor_x < w &&
3644 top_level->cursor_y < h);
3647 BC_WindowBase* BC_WindowBase::get_top_level()
3652 BC_WindowBase* BC_WindowBase::get_parent()
3654 return parent_window;
3657 int BC_WindowBase::get_color_model()
3659 return top_level->color_model;
3662 BC_Resources* BC_WindowBase::get_resources()
3664 return BC_WindowBase::resources;
3667 BC_Synchronous* BC_WindowBase::get_synchronous()
3669 return BC_WindowBase::resources->get_synchronous();
3672 int BC_WindowBase::get_bg_color()
3677 void BC_WindowBase::set_bg_color(int color)
3679 this->bg_color = color;
3682 BC_Pixmap* BC_WindowBase::get_bg_pixmap()
3687 void BC_WindowBase::set_active_subwindow(BC_WindowBase *subwindow)
3689 top_level->active_subwindow = subwindow;
3692 int BC_WindowBase::activate()
3697 int BC_WindowBase::deactivate()
3699 if(window_type == MAIN_WINDOW)
3701 if( top_level->active_menubar ) {
3702 top_level->active_menubar->deactivate();
3703 top_level->active_menubar = 0;
3705 if( top_level->active_popup_menu ) {
3706 top_level->active_popup_menu->deactivate();
3707 top_level->active_popup_menu = 0;
3709 if( top_level->active_subwindow ) {
3710 top_level->active_subwindow->deactivate();
3711 top_level->active_subwindow = 0;
3713 if( top_level->motion_events && top_level->last_motion_win == this->win )
3714 top_level->motion_events = 0;
3720 int BC_WindowBase::cycle_textboxes(int amount)
3723 BC_WindowBase *new_textbox = 0;
3727 BC_WindowBase *first_textbox = 0;
3728 find_next_textbox(&first_textbox, &new_textbox, result);
3729 if(!new_textbox) new_textbox = first_textbox;
3735 BC_WindowBase *last_textbox = 0;
3736 find_prev_textbox(&last_textbox, &new_textbox, result);
3737 if(!new_textbox) new_textbox = last_textbox;
3741 if(new_textbox != active_subwindow)
3744 new_textbox->activate();
3750 int BC_WindowBase::find_next_textbox(BC_WindowBase **first_textbox, BC_WindowBase **next_textbox, int &result)
3752 // Search subwindows for textbox
3753 for(int i = 0; i < subwindows->total && result < 2; i++)
3755 BC_WindowBase *test_subwindow = subwindows->values[i];
3756 test_subwindow->find_next_textbox(first_textbox, next_textbox, result);
3763 if(!*first_textbox) *first_textbox = this;
3767 if(top_level->active_subwindow == this)
3773 *next_textbox = this;
3780 int BC_WindowBase::find_prev_textbox(BC_WindowBase **last_textbox, BC_WindowBase **prev_textbox, int &result)
3786 if(!*last_textbox) *last_textbox = this;
3790 if(top_level->active_subwindow == this)
3796 *prev_textbox = this;
3801 // Search subwindows for textbox
3802 for(int i = subwindows->total - 1; i >= 0 && result < 2; i--)
3804 BC_WindowBase *test_subwindow = subwindows->values[i];
3805 test_subwindow->find_prev_textbox(last_textbox, prev_textbox, result);
3810 BC_Clipboard* BC_WindowBase::get_clipboard()
3812 #ifdef SINGLE_THREAD
3813 return BC_Display::display_global->clipboard;
3815 return top_level->clipboard;
3819 Atom BC_WindowBase::to_clipboard(const char *data, long len, int clipboard_num)
3821 return get_clipboard()->to_clipboard(this, data, len, clipboard_num);
3824 long BC_WindowBase::from_clipboard(char *data, long maxlen, int clipboard_num)
3826 return get_clipboard()->from_clipboard(data, maxlen, clipboard_num);
3829 long BC_WindowBase::clipboard_len(int clipboard_num)
3831 return get_clipboard()->clipboard_len(clipboard_num);
3834 int BC_WindowBase::do_selection_clear(Window win)
3836 top_level->event_win = win;
3837 return dispatch_selection_clear();
3840 int BC_WindowBase::dispatch_selection_clear()
3843 for( int i=0; i<subwindows->total && !result; ++i )
3844 result = subwindows->values[i]->dispatch_selection_clear();
3846 result = selection_clear_event();
3851 void BC_WindowBase::get_relative_cursor(int &x, int &y, int lock_window)
3853 int abs_x, abs_y, win_x, win_y;
3854 unsigned int temp_mask;
3857 if(lock_window) this->lock_window("BC_WindowBase::get_relative_cursor");
3858 XQueryPointer(top_level->display, top_level->win,
3859 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3862 XTranslateCoordinates(top_level->display, top_level->rootwin,
3863 win, abs_x, abs_y, &x, &y, &temp_win);
3864 if(lock_window) this->unlock_window();
3866 int BC_WindowBase::get_relative_cursor_x(int lock_window)
3869 get_relative_cursor(x, y, lock_window);
3872 int BC_WindowBase::get_relative_cursor_y(int lock_window)
3875 get_relative_cursor(x, y, lock_window);
3879 void BC_WindowBase::get_abs_cursor(int &abs_x, int &abs_y, int lock_window)
3882 unsigned int temp_mask;
3885 if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor");
3886 XQueryPointer(top_level->display, top_level->win,
3887 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3889 if(lock_window) this->unlock_window();
3891 int BC_WindowBase::get_abs_cursor_x(int lock_window)
3894 get_abs_cursor(abs_x, abs_y, lock_window);
3897 int BC_WindowBase::get_abs_cursor_y(int lock_window)
3900 get_abs_cursor(abs_x, abs_y, lock_window);
3904 void BC_WindowBase::get_pop_cursor(int &px, int &py, int lock_window)
3906 int xmargin = xS(100), ymargin = yS(100);
3907 get_abs_cursor(px, py, lock_window);
3908 if( px < xmargin ) px = xmargin;
3909 if( py < ymargin ) py = ymargin;
3910 int wd = get_screen_x(lock_window,-1) + get_screen_w(lock_window,-1) - xmargin;
3911 if( px > wd ) px = wd;
3912 int ht = get_screen_y(lock_window,-1) + get_screen_h(lock_window,-1) - ymargin;
3913 if( py > ht ) py = ht;
3915 int BC_WindowBase::get_pop_cursor_x(int lock_window)
3918 get_pop_cursor(px, py, lock_window);
3921 int BC_WindowBase::get_pop_cursor_y(int lock_window)
3924 get_pop_cursor(px, py, lock_window);
3928 int BC_WindowBase::match_window(Window win)
3930 if (this->win == win) return 1;
3932 for(int i = 0; i < subwindows->total; i++) {
3933 result = subwindows->values[i]->match_window(win);
3934 if (result) return result;
3940 int BC_WindowBase::get_cursor_over_window()
3942 int abs_x, abs_y, win_x, win_y;
3943 unsigned int mask_return;
3944 Window root_return, child_return;
3946 int ret = XQueryPointer(top_level->display, top_level->rootwin,
3947 &root_return, &child_return, &abs_x, &abs_y,
3948 &win_x, &win_y, &mask_return);
3949 if( ret && child_return == None ) ret = 0;
3950 if( ret && win != child_return )
3951 ret = top_level->match_window(child_return);
3952 // query pointer can return a window manager window with this top_level as a child
3953 // for kde this can be two levels deep
3954 unsigned int nchildren_return = 0;
3955 Window parent_return, *children_return = 0;
3956 Window top_win = top_level->win;
3957 while( !ret && top_win != top_level->rootwin && top_win != root_return &&
3958 XQueryTree(top_level->display, top_win, &root_return,
3959 &parent_return, &children_return, &nchildren_return) ) {
3960 if( children_return ) XFree(children_return);
3961 if( (top_win=parent_return) == child_return ) ret = 1;
3966 int BC_WindowBase::cursor_above()
3969 get_relative_cursor(rx, ry);
3970 return rx < 0 || rx >= get_w() ||
3971 ry < 0 || ry >= get_h() ? 0 : 1;
3974 int BC_WindowBase::get_drag_x()
3976 return top_level->drag_x;
3979 int BC_WindowBase::get_drag_y()
3981 return top_level->drag_y;
3984 int BC_WindowBase::get_cursor_x()
3986 return top_level->cursor_x;
3989 int BC_WindowBase::get_cursor_y()
3991 return top_level->cursor_y;
3994 int BC_WindowBase::dump_windows()
3996 printf("\tBC_WindowBase::dump_windows window=%p win=%p '%s', %dx%d+%d+%d %s\n",
3997 this, (void*)this->win, title, w,h,x,y, typeid(*this).name());
3998 for(int i = 0; i < subwindows->size(); i++)
3999 subwindows->get(i)->dump_windows();
4000 for(int i = 0; i < popups.size(); i++) {
4001 BC_WindowBase *p = popups[i];
4002 printf("\tBC_WindowBase::dump_windows popup=%p win=%p '%s', %dx%d+%d+%d %s\n",
4003 p, (void*)p->win, p->title, p->w,p->h,p->x,p->y, typeid(*p).name());
4008 int BC_WindowBase::is_event_win()
4010 return this->win == top_level->event_win;
4013 void BC_WindowBase::set_dragging(int value)
4015 is_dragging = value;
4018 int BC_WindowBase::get_dragging()
4023 int BC_WindowBase::get_buttonpress()
4025 return top_level->button_number;
4028 int BC_WindowBase::get_button_down()
4030 return top_level->button_down;
4033 int BC_WindowBase::alt_down()
4035 return top_level->alt_mask;
4038 int BC_WindowBase::shift_down()
4040 return top_level->shift_mask;
4043 int BC_WindowBase::ctrl_down()
4045 return top_level->ctrl_mask;
4048 wchr_t* BC_WindowBase::get_wkeystring(int *length)
4051 *length = top_level->wkey_string_length;
4052 return top_level->wkey_string;
4055 #ifdef X_HAVE_UTF8_STRING
4056 char* BC_WindowBase::get_keypress_utf8()
4058 return top_level->key_pressed_utf8;
4063 int BC_WindowBase::get_keypress()
4065 return top_level->key_pressed;
4068 int BC_WindowBase::get_double_click()
4070 return top_level->double_click;
4073 int BC_WindowBase::get_triple_click()
4075 return top_level->triple_click;
4078 int BC_WindowBase::get_bgcolor()
4083 int BC_WindowBase::resize_window(int w, int h)
4085 if(this->w == w && this->h == h) return 0;
4087 if(window_type == MAIN_WINDOW && !allow_resize)
4089 XSizeHints size_hints;
4090 size_hints.flags = PSize | PMinSize | PMaxSize;
4091 size_hints.width = w;
4092 size_hints.height = h;
4093 size_hints.min_width = w;
4094 size_hints.max_width = w;
4095 size_hints.min_height = h;
4096 size_hints.max_height = h;
4097 if( this->x > -BC_INFINITY && this->x < BC_INFINITY ) {
4098 size_hints.flags |= PPosition;
4099 size_hints.x = this->x;
4100 size_hints.y = this->y;
4102 XSetNormalHints(top_level->display, win, &size_hints);
4104 XResizeWindow(top_level->display, win, w, h);
4109 pixmap = new BC_Pixmap(this, w, h);
4111 // Propagate to menubar
4112 for(int i = 0; i < subwindows->total; i++)
4114 subwindows->values[i]->dispatch_resize_event(w, h);
4117 draw_background(0, 0, w, h);
4118 if(top_level == this && get_resources()->recursive_resizing)
4119 resize_history.append(new BC_ResizeCall(w, h));
4123 // The only way for resize events to be propagated is by updating the internal w and h
4124 int BC_WindowBase::resize_event(int w, int h)
4126 if(window_type == MAIN_WINDOW)
4134 int BC_WindowBase::reposition_window(int x, int y)
4136 reposition_window(x, y, -1, -1);
4141 int BC_WindowBase::reposition_window(int x, int y, int w, int h)
4145 // Some tools set their own dimensions before calling this, causing the
4146 // resize check to skip.
4150 if(w > 0 && w != this->w)
4156 if(h > 0 && h != this->h)
4162 //printf("BC_WindowBase::reposition_window %d %d %d\n", translation_count, x_correction, y_correction);
4165 printf("BC_WindowBase::reposition_window this->w == %d\n", this->w);
4167 printf("BC_WindowBase::reposition_window this->h == %d\n", this->h);
4169 if(translation_count && window_type == MAIN_WINDOW)
4171 // KDE shifts window right and down.
4172 // FVWM leaves window alone and adds border around it.
4173 XMoveResizeWindow(top_level->display, win,
4174 x - BC_DisplayInfo::auto_reposition_x,
4175 y - BC_DisplayInfo::auto_reposition_y,
4180 XMoveResizeWindow(top_level->display, win, x, y,
4187 pixmap = new BC_Pixmap(this, this->w, this->h);
4188 clear_box(0,0, this->w, this->h);
4189 // Propagate to menubar
4190 for(int i = 0; i < subwindows->total; i++)
4192 subwindows->values[i]->dispatch_resize_event(this->w, this->h);
4195 // draw_background(0, 0, w, h);
4201 int BC_WindowBase::reposition_window_relative(int dx, int dy, int w, int h)
4203 return reposition_window(get_x()+dx, get_y()+dy, w, h);
4206 int BC_WindowBase::reposition_window_relative(int dx, int dy)
4208 return reposition_window_relative(dx, dy, -1, -1);
4211 void BC_WindowBase::set_tooltips(int v)
4213 get_resources()->tooltips_enabled = v;
4216 void BC_WindowBase::set_force_tooltip(int v)
4221 int BC_WindowBase::raise_window(int do_flush)
4223 if( hidden ) return 1;
4224 if( wait_viewable(500) ) return 1;
4225 XRaiseWindow(top_level->display, win);
4226 if(do_flush) XFlush(top_level->display);
4230 int BC_WindowBase::lower_window(int do_flush)
4232 XLowerWindow(top_level->display, win);
4233 if(do_flush) XFlush(top_level->display);
4237 void BC_WindowBase::set_background(VFrame *bitmap)
4239 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
4241 bg_pixmap = new BC_Pixmap(this, bitmap, PIXMAP_OPAQUE);
4242 shared_bg_pixmap = 0;
4243 draw_background(0, 0, w, h);
4246 void BC_WindowBase::put_title(const char *text)
4248 char *cp = this->title, *ep = cp+sizeof(this->title)-1;
4249 for( const unsigned char *bp = (const unsigned char *)text; *bp && cp<ep; ++bp )
4250 *cp++ = *bp >= ' ' ? *bp : ' ';
4254 void BC_WindowBase::set_title(const char *text, int utf8)
4256 // utf8>0: wm + net_wm, utf8=0: wm only, utf<0: net_wm only
4258 const unsigned char *wm_title = (const unsigned char *)title;
4259 int title_len = strlen((const char *)title);
4261 Atom xa_wm_name = XA_WM_NAME;
4262 Atom xa_icon_name = XA_WM_ICON_NAME;
4263 Atom xa_string = XA_STRING;
4264 XChangeProperty(display, win, xa_wm_name, xa_string, 8,
4265 PropModeReplace, wm_title, title_len);
4266 XChangeProperty(display, win, xa_icon_name, xa_string, 8,
4267 PropModeReplace, wm_title, title_len);
4270 Atom xa_net_wm_name = XInternAtom(display, "_NET_WM_NAME", True);
4271 Atom xa_net_icon_name = XInternAtom(display, "_NET_WM_ICON_NAME", True);
4272 Atom xa_utf8_string = XInternAtom(display, "UTF8_STRING", True);
4273 XChangeProperty(display, win, xa_net_wm_name, xa_utf8_string, 8,
4274 PropModeReplace, wm_title, title_len);
4275 XChangeProperty(display, win, xa_net_icon_name, xa_utf8_string, 8,
4276 PropModeReplace, wm_title, title_len);
4282 void BC_WindowBase::set_net_icon(VFrame *data)
4284 int width = data->get_w(), height = data->get_h();
4285 int size = 2 + width * height;
4286 unsigned long *icon_data = new unsigned long[size];
4287 unsigned long *lp = icon_data;
4288 *lp++ = width; *lp++ = height;
4289 uint8_t **rows = data->get_rows();
4290 for( int y=0; y<height; ++y ) {
4291 unsigned *up = (unsigned *)rows[y];
4292 for( int x=0; x<width; ++x )
4293 *lp++ = *(unsigned *)up++;
4295 Atom NetWMIcon = XInternAtom(display, "_NET_WM_ICON", True);
4296 XChangeProperty(top_level->display, top_level->win, NetWMIcon,
4297 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)icon_data, size);
4298 delete [] icon_data;
4301 const char *BC_WindowBase::get_title()
4306 int BC_WindowBase::get_toggle_value()
4308 return toggle_value;
4311 int BC_WindowBase::get_toggle_drag()
4316 int BC_WindowBase::set_icon(VFrame *data)
4318 if(icon_pixmap) delete icon_pixmap;
4319 icon_pixmap = new BC_Pixmap(top_level, data, PIXMAP_ALPHA, 1);
4321 if(icon_window) delete icon_window;
4322 icon_window = new BC_Popup(this, 0, 0,
4323 icon_pixmap->get_w(), icon_pixmap->get_h(),
4324 -1, 1, // All windows are hidden initially
4327 XWMHints wm_hints; memset(&wm_hints, 0, sizeof(wm_hints));
4328 wm_hints.flags = IconPixmapHint; // | IconMaskHint | IconWindowHint;
4329 wm_hints.icon_pixmap = icon_pixmap->get_pixmap();
4330 wm_hints.icon_mask = icon_pixmap->get_alpha();
4331 wm_hints.icon_window = icon_window->win;
4332 if( XGroupLeader ) {
4333 wm_hints.flags |= WindowGroupHint;
4334 wm_hints.window_group = XGroupLeader;
4337 // for(int i = 0; i < 1000; i++)
4338 // printf("02x ", icon_pixmap->get_alpha()->get_row_pointers()[0][i]);
4341 XSetWMHints(top_level->display, top_level->win, &wm_hints);
4344 XSync(top_level->display, 0);
4348 void BC_WindowBase::init_resources(float scale)
4350 if( resources ) return;
4352 const char *env = getenv("BC_SCALE");
4353 if( env ) scale = atof(env);
4354 float x_scale = 1, y_scale = 1;
4356 BC_DisplayInfo info;
4358 int cins = info.xinerama_big_screen();
4359 if( !info.xinerama_geometry(cins, wx, wy, ww, wh) ) {
4360 if( (x_scale = ww/1920.) < 1 ) x_scale = 1;
4361 if( (y_scale = wh/1080.) < 1 ) y_scale = 1;
4365 x_scale = y_scale = scale;
4366 // constructor sets BC_WindowBase::resources
4367 new BC_Resources(x_scale, y_scale);
4369 void BC_WindowBase::finit_resources()
4371 delete resources; resources = 0;
4374 int BC_WindowBase::set_w(int w)
4380 int BC_WindowBase::set_h(int h)
4386 int BC_WindowBase::load_defaults(BC_Hash *defaults)
4388 char string[BCTEXTLEN];
4389 int newest_id = - 1;
4390 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4392 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4393 resources->filebox_history[i].path[0] = 0;
4394 defaults->get(string, resources->filebox_history[i].path);
4395 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4396 resources->filebox_history[i].id = defaults->get(string, resources->get_id());
4397 if(resources->filebox_history[i].id > newest_id)
4398 newest_id = resources->filebox_history[i].id;
4401 resources->filebox_id = newest_id + 1;
4402 resources->filebox_mode = defaults->get("FILEBOX_MODE", get_resources()->filebox_mode);
4403 resources->filebox_w = defaults->get("FILEBOX_W", get_resources()->filebox_w);
4404 resources->filebox_h = defaults->get("FILEBOX_H", get_resources()->filebox_h);
4405 resources->filebox_columntype[0] = defaults->get("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4406 resources->filebox_columntype[1] = defaults->get("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4407 resources->filebox_columntype[2] = defaults->get("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4408 resources->filebox_columntype[3] = defaults->get("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4409 resources->filebox_columnwidth[0] = defaults->get("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4410 resources->filebox_columnwidth[1] = defaults->get("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4411 resources->filebox_columnwidth[2] = defaults->get("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4412 resources->filebox_columnwidth[3] = defaults->get("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4413 resources->filebox_size_format = defaults->get("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4414 defaults->get("FILEBOX_FILTER", resources->filebox_filter);
4418 int BC_WindowBase::save_defaults(BC_Hash *defaults)
4420 char string[BCTEXTLEN];
4421 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4423 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4424 defaults->update(string, resources->filebox_history[i].path);
4425 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4426 defaults->update(string, resources->filebox_history[i].id);
4428 defaults->update("FILEBOX_MODE", resources->filebox_mode);
4429 defaults->update("FILEBOX_W", resources->filebox_w);
4430 defaults->update("FILEBOX_H", resources->filebox_h);
4431 defaults->update("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4432 defaults->update("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4433 defaults->update("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4434 defaults->update("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4435 defaults->update("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4436 defaults->update("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4437 defaults->update("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4438 defaults->update("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4439 defaults->update("FILEBOX_FILTER", resources->filebox_filter);
4440 defaults->update("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4446 // For some reason XTranslateCoordinates can take a long time to return.
4447 // We work around this by only calling it when the event windows are different.
4448 void BC_WindowBase::translate_coordinates(Window src_w, Window dest_w,
4449 int src_x, int src_y, int *dest_x_return, int *dest_y_return)
4456 *dest_x_return = src_x;
4457 *dest_y_return = src_y;
4461 XTranslateCoordinates(top_level->display, src_w, dest_w,
4462 src_x, src_y, dest_x_return, dest_y_return, &tempwin);
4463 //printf("BC_WindowBase::translate_coordinates 1 %lld\n", timer.get_difference());
4467 void BC_WindowBase::get_root_coordinates(int x, int y, int *abs_x, int *abs_y)
4469 translate_coordinates(win, top_level->rootwin, x, y, abs_x, abs_y);
4472 void BC_WindowBase::get_win_coordinates(int abs_x, int abs_y, int *x, int *y)
4474 translate_coordinates(top_level->rootwin, win, abs_x, abs_y, x, y);
4478 #ifdef HAVE_LIBXXF86VM
4479 void BC_WindowBase::closest_vm(int *vm, int *width, int *height)
4483 if(XF86VidModeQueryExtension(top_level->display,&foo,&bar)) {
4485 XF86VidModeModeInfo **vm_modelines;
4486 XF86VidModeGetAllModeLines(top_level->display,
4487 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4488 for( i = 0; i < vm_count; i++ ) {
4489 if( vm_modelines[i]->hdisplay < vm_modelines[*vm]->hdisplay &&
4490 vm_modelines[i]->hdisplay >= *width )
4493 display = top_level->display;
4494 if( vm_modelines[*vm]->hdisplay == *width )
4497 *width = vm_modelines[*vm]->hdisplay;
4498 *height = vm_modelines[*vm]->vdisplay;
4503 void BC_WindowBase::scale_vm(int vm)
4505 int foo,bar,dotclock;
4506 if( XF86VidModeQueryExtension(top_level->display,&foo,&bar) ) {
4508 XF86VidModeModeInfo **vm_modelines;
4509 XF86VidModeModeLine vml;
4510 XF86VidModeGetAllModeLines(top_level->display,
4511 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4512 XF86VidModeGetModeLine(top_level->display,
4513 XDefaultScreen(top_level->display), &dotclock,&vml);
4514 orig_modeline.dotclock = dotclock;
4515 orig_modeline.hdisplay = vml.hdisplay;
4516 orig_modeline.hsyncstart = vml.hsyncstart;
4517 orig_modeline.hsyncend = vml.hsyncend;
4518 orig_modeline.htotal = vml.htotal;
4519 orig_modeline.vdisplay = vml.vdisplay;
4520 orig_modeline.vsyncstart = vml.vsyncstart;
4521 orig_modeline.vsyncend = vml.vsyncend;
4522 orig_modeline.vtotal = vml.vtotal;
4523 orig_modeline.flags = vml.flags;
4524 orig_modeline.privsize = vml.privsize;
4525 // orig_modeline.private = vml.private;
4526 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),vm_modelines[vm]);
4527 XF86VidModeSetViewPort(top_level->display,XDefaultScreen(top_level->display),0,0);
4528 XFlush(top_level->display);
4532 void BC_WindowBase::restore_vm()
4534 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),&orig_modeline);
4535 XFlush(top_level->display);
4540 #ifndef SINGLE_THREAD
4541 int BC_WindowBase::get_event_count()
4543 event_lock->lock("BC_WindowBase::get_event_count");
4544 int result = common_events.total;
4545 event_lock->unlock();
4549 XEvent* BC_WindowBase::get_event()
4552 while(!done && !result)
4554 event_condition->lock("BC_WindowBase::get_event");
4555 event_lock->lock("BC_WindowBase::get_event");
4557 if(common_events.total && !done)
4559 result = common_events.values[0];
4560 common_events.remove_number(0);
4563 event_lock->unlock();
4568 void BC_WindowBase::put_event(XEvent *event)
4570 event_lock->lock("BC_WindowBase::put_event");
4571 common_events.append(event);
4572 event_lock->unlock();
4573 event_condition->unlock();
4576 void BC_WindowBase::dequeue_events(Window win)
4578 event_lock->lock("BC_WindowBase::dequeue_events");
4580 int out = 0, total = common_events.size();
4581 for( int in=0; in<total; ++in ) {
4582 if( common_events[in]->xany.window == win ) continue;
4583 common_events[out++] = common_events[in];
4585 common_events.total = out;
4587 event_lock->unlock();
4590 int BC_WindowBase::resend_event(BC_WindowBase *window)
4592 if( resend_event_window ) return 1;
4593 resend_event_window = window;
4599 int BC_WindowBase::resend_event(BC_WindowBase *window)
4604 #endif // SINGLE_THREAD
4606 int BC_WindowBase::get_id()
4612 BC_Pixmap *BC_WindowBase::create_pixmap(VFrame *vframe)
4614 int w = vframe->get_w(), h = vframe->get_h();
4615 BC_Pixmap *icon = new BC_Pixmap(this, w, h);
4616 icon->draw_vframe(vframe, 0,0, w,h, 0,0);
4621 void BC_WindowBase::flicker(int n, int ms)
4623 int color = get_bg_color();
4624 for( int i=2*n; --i>=0; ) {
4625 set_inverse(); set_bg_color(WHITE);
4626 clear_box(0,0, w,h); flash(1);
4627 sync_display(); Timer::delay(ms);
4629 set_bg_color(color);
4633 void BC_WindowBase::focus()
4635 XWindowAttributes xwa;
4636 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4637 if( xwa.map_state == IsViewable )
4638 XSetInputFocus(top_level->display, top_level->win, RevertToParent, CurrentTime);
4641 int BC_WindowBase::wait_viewable(int ms)
4644 XWindowAttributes xwa;
4646 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4647 if( xwa.map_state == IsViewable ) return 0;
4649 } while( timer.get_difference() < ms );