4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "bcclipboard.h"
24 #include "bcdisplay.h"
25 #include "bcdisplayinfo.h"
26 #include "bcmenubar.h"
29 #include "bcpopupmenu.h"
30 #include "bcrepeater.h"
31 #include "bcresources.h"
32 #include "bcsignals.h"
33 #include "bcsubwindow.h"
34 #include "bcsynchronous.h"
36 #include "bcwindowbase.h"
37 #include "bcwindowevents.h"
38 #include "bccmodels.h"
40 #include "condition.h"
49 #include "workarounds.h"
59 #include <X11/extensions/Xinerama.h>
60 #include <X11/extensions/Xvlib.h>
61 #include <X11/extensions/shape.h>
62 #include <X11/XF86keysym.h>
63 #include <X11/Sunkeysym.h>
65 BC_ResizeCall::BC_ResizeCall(int w, int h)
72 int BC_WindowBase::shm_completion_event = -1;
73 BC_Resources *BC_WindowBase::resources = 0;
74 Window XGroupLeader = 0;
76 Mutex BC_KeyboardHandlerLock::keyboard_listener_mutex("keyboard_listener",0);
77 ArrayList<BC_KeyboardHandler*> BC_KeyboardHandler::listeners;
79 BC_WindowBase::BC_WindowBase()
81 //printf("BC_WindowBase::BC_WindowBase 1\n");
82 BC_WindowBase::initialize();
85 BC_WindowBase::~BC_WindowBase()
88 BC_Display::lock_display("BC_WindowBase::~BC_WindowBase");
90 if(window_type == MAIN_WINDOW)
91 lock_window("BC_WindowBase::~BC_WindowBase");
94 #ifdef HAVE_LIBXXF86VM
95 if(window_type == VIDMODE_SCALED_WINDOW && vm_switched) {
102 if(window_type != MAIN_WINDOW)
105 XSelectInput(top_level->display, this->win, 0);
106 XSync(top_level->display,0);
107 #ifndef SINGLE_THREAD
108 top_level->dequeue_events(win);
110 // drop active window refs to this
111 if(top_level->active_menubar == this) top_level->active_menubar = 0;
112 if(top_level->active_popup_menu == this) top_level->active_popup_menu = 0;
113 if(top_level->active_subwindow == this) top_level->active_subwindow = 0;
114 // drop motion window refs to this
115 if(top_level->motion_events && top_level->last_motion_win == this->win)
116 top_level->motion_events = 0;
118 // Remove pointer from parent window to this
119 parent_window->subwindows->remove(this);
122 if(grab_active) grab_active->active_grab = 0;
123 if(icon_window) delete icon_window;
124 if(window_type == POPUP_WINDOW)
125 parent_window->remove_popup(this);
127 // Delete the subwindows
130 while(subwindows->total)
132 // Subwindow removes its own pointer
133 delete subwindows->values[0];
140 //printf("delete glx=%08x, win=%08x %s\n", (unsigned)glx_win, (unsigned)win, title);
142 if( get_resources()->get_synchronous() && glx_win != 0 ) {
143 if( window_type == MAIN_WINDOW )
145 get_resources()->get_synchronous()->delete_window(this);
146 if( window_type == MAIN_WINDOW )
147 lock_window("BC_WindowBase::delete_window");
150 XDestroyWindow(top_level->display, win);
152 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
153 if(icon_pixmap) delete icon_pixmap;
154 if(temp_bitmap) delete temp_bitmap;
155 top_level->active_bitmaps.remove_buffers(this);
156 if(_7segment_pixmaps)
158 for(int i = 0; i < TOTAL_7SEGMENT; i++)
159 delete _7segment_pixmaps[i];
161 delete [] _7segment_pixmaps;
166 if(window_type == MAIN_WINDOW)
168 XFreeGC(display, gc);
169 static XFontStruct *BC_WindowBase::*xfont[] = {
170 &BC_WindowBase::smallfont,
171 &BC_WindowBase::mediumfont,
172 &BC_WindowBase::largefont,
173 &BC_WindowBase::bigfont,
174 &BC_WindowBase::clockfont,
176 for( int i=sizeof(xfont)/sizeof(xfont[0]); --i>=0; )
177 XFreeFont(display, this->*xfont[i]);
180 // prevents a bug when Xft closes with unrefd fonts
181 FcPattern *defaults = FcPatternCreate();
182 FcPatternAddInteger(defaults, "maxunreffonts", 0);
183 XftDefaultSet(display, defaults);
185 static void *BC_WindowBase::*xft_font[] = {
186 &BC_WindowBase::smallfont_xft,
187 &BC_WindowBase::mediumfont_xft,
188 &BC_WindowBase::largefont_xft,
189 &BC_WindowBase::bigfont_xft,
190 &BC_WindowBase::bold_smallfont_xft,
191 &BC_WindowBase::bold_mediumfont_xft,
192 &BC_WindowBase::bold_largefont_xft,
193 &BC_WindowBase::clockfont_xft,
195 for( int i=sizeof(xft_font)/sizeof(xft_font[0]); --i>=0; ) {
196 XftFont *xft = (XftFont *)(this->*xft_font[i]);
197 if( xft ) xftFontClose (display, xft);
205 XFree(xinerama_info);
206 xinerama_screens = 0;
208 if( xvideo_port_id >= 0 )
209 XvUngrabPort(display, xvideo_port_id, CurrentTime);
212 // Must be last reference to display.
213 // _XftDisplayInfo needs a lock.
214 get_resources()->create_window_lock->lock("BC_WindowBase::~BC_WindowBase");
215 XCloseDisplay(display);
216 get_resources()->create_window_lock->unlock();
218 // clipboard uses a different display connection
219 clipboard->stop_clipboard();
223 resize_history.remove_all_objects();
225 #ifndef SINGLE_THREAD
226 common_events.remove_all_objects();
228 delete event_condition;
231 top_level->window_lock = 0;
232 BC_Display::unlock_display();
237 if( glx_fbcfgs_window ) XFree(glx_fbcfgs_window);
238 if( glx_fbcfgs_pbuffer) XFree(glx_fbcfgs_pbuffer);
239 if( glx_fbcfgs_pixmap ) XFree(glx_fbcfgs_pixmap);
242 UNSET_ALL_LOCKS(this)
245 int BC_WindowBase::initialize()
250 display_lock_owner = 0;
255 resend_event_window = 0;
267 xinerama_screens = 0;
272 translation_events = 0;
273 ctrl_mask = shift_mask = alt_mask = 0;
274 cursor_x = cursor_y = button_number = 0;
288 active_popup_menu = 0;
289 active_subwindow = 0;
293 _7segment_pixmaps = 0;
296 // next_repeat_id = 0;
298 current_font = MEDIUMFONT;
299 current_color = BLACK;
300 current_cursor = ARROW_CURSOR;
303 shared_bg_pixmap = 0;
306 window_type = MAIN_WINDOW;
307 translation_count = 0;
308 x_correction = y_correction = 0;
317 #ifdef HAVE_LIBXXF86VM
335 bold_smallfont_xft = 0;
336 bold_mediumfont_xft = 0;
337 bold_largefont_xft = 0;
339 completion_lock = new Condition(0, "BC_WindowBase::completion_lock");
341 // Need these right away since put_event is called before run_window sometimes.
342 event_lock = new Mutex("BC_WindowBase::event_lock");
343 event_condition = new Condition(0, "BC_WindowBase::event_condition");
344 init_lock = new Condition(0, "BC_WindowBase::init_lock");
347 cursor_timer = new Timer;
350 glx_fbcfgs_window = 0; n_fbcfgs_window = 0;
351 glx_fbcfgs_pbuffer = 0; n_fbcfgs_pbuffer = 0;
352 glx_fbcfgs_pixmap = 0; n_fbcfgs_pixmap = 0;
366 #define DEFAULT_EVENT_MASKS EnterWindowMask | \
369 ButtonReleaseMask | \
370 PointerMotionMask | \
374 int BC_WindowBase::create_window(BC_WindowBase *parent_window, const char *title,
375 int x, int y, int w, int h, int minw, int minh, int allow_resize,
376 int private_color, int hide, int bg_color, const char *display_name,
377 int window_type, BC_Pixmap *bg_pixmap, int group_it)
379 XSetWindowAttributes attr;
381 XSizeHints size_hints;
384 #ifdef HAVE_LIBXXF86VM
388 id = get_resources()->get_id();
389 if(parent_window) top_level = parent_window->top_level;
390 if( top_level ) lock_window("BC_WindowBase::create_window");
391 get_resources()->create_window_lock->lock("BC_WindowBase::create_window");
393 #ifdef HAVE_LIBXXF86VM
394 if(window_type == VIDMODE_SCALED_WINDOW)
395 closest_vm(&vm,&w,&h);
402 this->bg_color = bg_color;
403 this->window_type = window_type;
405 this->private_color = private_color;
406 this->parent_window = parent_window;
407 this->bg_pixmap = bg_pixmap;
408 this->allow_resize = allow_resize;
410 strcpy(this->display_name, display_name);
412 this->display_name[0] = 0;
415 if(bg_pixmap) shared_bg_pixmap = 1;
417 subwindows = new BC_SubWindowList;
419 if(window_type == MAIN_WINDOW)
422 parent_window = this;
426 display = BC_Display::get_display(display_name);
427 BC_Display::lock_display("BC_WindowBase::create_window");
428 // BC_Display::display_global->new_window(this);
431 // get the display connection
433 // This function must be the first Xlib
434 // function a multi-threaded program calls
436 display = init_display(display_name);
437 if( shm_completion_event < 0 ) shm_completion_event =
438 ShmCompletion + XShmGetEventBase(display);
440 lock_window("BC_WindowBase::create_window 1");
442 screen = DefaultScreen(display);
443 rootwin = RootWindow(display, screen);
444 // window placement boundaries
445 if( !xinerama_screens && XineramaIsActive(display) )
446 xinerama_info = XineramaQueryScreens(display, &xinerama_screens);
447 root_w = get_root_w(0);
448 root_h = get_root_h(0);
451 vis = get_glx_visual(display);
455 int mask = VisualDepthMask | VisualClassMask;
456 static XVisualInfo vinfo;
457 memset(&vinfo, 0, sizeof(vinfo));
459 vinfo.c_class = TrueColor;
461 XVisualInfo *vis_info = XGetVisualInfo(display, mask, &vinfo, &nitems);
462 vis = vis_info && nitems>0 ? vis_info[0].visual : 0;
463 if( vis_info ) XFree(vis_info);
466 vis = DefaultVisual(display, screen);
467 default_depth = DefaultDepth(display, screen);
469 client_byte_order = (*(const u_int32_t*)"a ") & 0x00000001;
470 server_byte_order = (XImageByteOrder(display) == MSBFirst) ? 0 : 1;
473 // This must be done before fonts to know if antialiasing is available.
476 if(resources->use_shm < 0) resources->initialize_display(this);
477 x_correction = BC_DisplayInfo::get_left_border();
478 y_correction = BC_DisplayInfo::get_top_border();
480 // clamp window placement
481 if(this->x + this->w + x_correction > root_w)
482 this->x = root_w - this->w - x_correction;
483 if(this->y + this->h + y_correction > root_h)
484 this->y = root_h - this->h - y_correction;
485 if(this->x < 0) this->x = 0;
486 if(this->y < 0) this->y = 0;
488 if(this->bg_color == -1)
489 this->bg_color = resources->get_bg_color();
491 // printf("bcwindowbase 1 %s\n", title);
492 // if(window_type == MAIN_WINDOW) sleep(1);
493 // printf("bcwindowbase 10\n");
499 mask = CWEventMask | CWBackPixel | CWColormap | CWCursor;
501 attr.event_mask = DEFAULT_EVENT_MASKS |
502 StructureNotifyMask |
506 attr.background_pixel = get_color(this->bg_color);
507 attr.colormap = cmap;
508 attr.cursor = get_cursor_struct(ARROW_CURSOR);
510 win = XCreateWindow(display, rootwin,
511 this->x, this->y, this->w, this->h, 0,
512 top_level->default_depth, InputOutput,
514 XGetNormalHints(display, win, &size_hints);
516 size_hints.flags = PSize | PMinSize | PMaxSize;
517 size_hints.width = this->w;
518 size_hints.height = this->h;
519 size_hints.min_width = allow_resize ? minw : this->w;
520 size_hints.max_width = allow_resize ? 32767 : this->w;
521 size_hints.min_height = allow_resize ? minh : this->h;
522 size_hints.max_height = allow_resize ? 32767 : this->h;
523 if(x > -BC_INFINITY && x < BC_INFINITY)
525 size_hints.flags |= PPosition;
526 size_hints.x = this->x;
527 size_hints.y = this->y;
529 XSetWMProperties(display, win, 0, 0, 0, 0, &size_hints, 0, 0);
532 #ifndef SINGLE_THREAD
533 clipboard = new BC_Clipboard(this);
534 clipboard->start_clipboard();
540 Atom ClientLeaderXAtom;
541 if (XGroupLeader == 0)
543 const char *instance_name = "cinelerra";
544 const char *class_name = "Cinelerra";
545 XClassHint *class_hints = XAllocClassHint();
546 class_hints->res_name = (char*)instance_name;
547 class_hints->res_class = (char*)class_name;
548 XSetClassHint(top_level->display, win, class_hints);
550 ClientLeaderXAtom = XInternAtom(display, "WM_CLIENT_LEADER", True);
551 XChangeProperty(display, win, ClientLeaderXAtom, XA_WINDOW, 32,
552 PropModeReplace, (unsigned char *)&XGroupLeader, true);
555 set_icon(get_resources()->default_icon);
558 #ifdef HAVE_LIBXXF86VM
559 if(window_type == VIDMODE_SCALED_WINDOW && vm != -1)
566 #ifdef HAVE_LIBXXF86VM
567 if(window_type == POPUP_WINDOW || window_type == VIDMODE_SCALED_WINDOW)
569 if(window_type == POPUP_WINDOW)
572 mask = CWEventMask | CWBackPixel | CWColormap |
573 CWOverrideRedirect | CWSaveUnder | CWCursor;
575 attr.event_mask = DEFAULT_EVENT_MASKS | ExposureMask |
576 KeyPressMask | KeyReleaseMask;
578 if(this->bg_color == -1)
579 this->bg_color = resources->get_bg_color();
580 attr.background_pixel = top_level->get_color(bg_color);
581 attr.colormap = top_level->cmap;
582 if(top_level->is_hourglass)
583 attr.cursor = top_level->get_cursor_struct(HOURGLASS_CURSOR);
585 attr.cursor = top_level->get_cursor_struct(ARROW_CURSOR);
586 attr.override_redirect = True;
587 attr.save_under = True;
589 win = XCreateWindow(top_level->display,
590 top_level->rootwin, this->x, this->y, this->w, this->h, 0,
591 top_level->default_depth, InputOutput, top_level->vis, mask,
593 top_level->add_popup(this);
596 if(window_type == SUB_WINDOW)
598 mask = CWEventMask | CWBackPixel | CWCursor;
599 attr.event_mask = DEFAULT_EVENT_MASKS;
600 attr.background_pixel = top_level->get_color(this->bg_color);
601 if(top_level->is_hourglass)
602 attr.cursor = top_level->get_cursor_struct(HOURGLASS_CURSOR);
604 attr.cursor = top_level->get_cursor_struct(ARROW_CURSOR);
605 win = XCreateWindow(top_level->display,
606 parent_window->win, this->x, this->y, this->w, this->h, 0,
607 top_level->default_depth, InputOutput, top_level->vis, mask,
610 if(!hidden) XMapWindow(top_level->display, win);
613 // Create pixmap for all windows
614 pixmap = new BC_Pixmap(this, this->w, this->h);
616 // Set up options for main window
617 if(window_type == MAIN_WINDOW)
619 if(get_resources()->bg_image && !bg_pixmap && bg_color < 0)
621 this->bg_pixmap = new BC_Pixmap(this,
622 get_resources()->bg_image,
626 if(!hidden) show_window();
630 draw_background(0, 0, this->w, this->h);
632 flash(-1, -1, -1, -1, 0);
634 // Set up options for popup window
635 #ifdef HAVE_LIBXXF86VM
636 if(window_type == POPUP_WINDOW || window_type == VIDMODE_SCALED_WINDOW)
638 if(window_type == POPUP_WINDOW)
642 if(!hidden) show_window();
644 get_resources()->create_window_lock->unlock();
650 Display* BC_WindowBase::init_display(const char *display_name)
654 if(display_name && display_name[0] == 0) display_name = NULL;
655 if((display = XOpenDisplay(display_name)) == NULL) {
656 printf("BC_WindowBase::init_display: cannot connect to X server %s\n",
658 if(getenv("DISPLAY") == NULL) {
659 printf(_("'DISPLAY' environment variable not set.\n"));
662 // Try again with default display.
663 if((display = XOpenDisplay(0)) == NULL) {
664 printf("BC_WindowBase::init_display: cannot connect to default X server.\n");
669 static int xsynch = -1;
671 const char *cp = getenv("CIN_XSYNCH");
672 xsynch = !cp ? 0 : atoi(cp);
675 XSynchronize(display, True);
680 Display* BC_WindowBase::get_display()
682 return top_level->display;
685 int BC_WindowBase::get_screen()
687 return top_level->screen;
690 int BC_WindowBase::run_window()
696 // Events may have been sent before run_window so can't initialize them here.
699 set_repeat(get_resources()->tooltip_delay);
700 BC_Display::display_global->new_window(this);
702 // If the first window created, run the display loop in this thread.
703 if(BC_Display::display_global->is_first(this))
705 BC_Display::unlock_display();
706 BC_Display::display_global->loop();
710 BC_Display::unlock_display();
711 completion_lock->lock("BC_WindowBase::run_window");
714 BC_Display::lock_display("BC_WindowBase::run_window");
715 BC_Display::display_global->delete_window(this);
717 unset_all_repeaters();
719 BC_Display::unlock_display();
721 #else // SINGLE_THREAD
726 set_repeat(get_resources()->tooltip_delay);
728 // Start X server events
729 event_thread = new BC_WindowEvents(this);
730 event_thread->start();
736 // Handle common events
741 unset_all_repeaters();
745 event_condition->reset();
746 common_events.remove_all_objects();
750 #endif // SINGLE_THREAD
755 int BC_WindowBase::get_key_masks(unsigned int key_state)
757 // printf("BC_WindowBase::get_key_masks %llx\n",
758 // event->xkey.state);
759 ctrl_mask = (key_state & ControlMask) ? 1 : 0; // ctrl key down
760 shift_mask = (key_state & ShiftMask) ? 1 : 0; // shift key down
761 alt_mask = (key_state & Mod1Mask) ? 1 : 0; // alt key down
766 void BC_WindowBase::add_keyboard_listener(int(BC_WindowBase::*handler)(BC_WindowBase *))
768 BC_KeyboardHandlerLock set;
769 BC_KeyboardHandler::listeners.append(new BC_KeyboardHandler(handler, this));
772 void BC_WindowBase::del_keyboard_listener(int(BC_WindowBase::*handler)(BC_WindowBase *))
774 BC_KeyboardHandlerLock set;
775 int i = BC_KeyboardHandler::listeners.size();
776 while( --i >= 0 && BC_KeyboardHandler::listeners[i]->handler!=handler );
777 if( i >= 0 ) BC_KeyboardHandler::listeners.remove_object_number(i);
780 int BC_KeyboardHandler::run_event(BC_WindowBase *wp)
782 int result = (win->*handler)(wp);
786 int BC_KeyboardHandler::run_listeners(BC_WindowBase *wp)
789 BC_KeyboardHandlerLock set;
790 for( int i=0; !result && i<listeners.size(); ++i ) {
791 BC_KeyboardHandler *listener = listeners[i];
792 result = listener->run_event(wp);
797 void BC_KeyboardHandler::kill_grabs()
799 BC_KeyboardHandlerLock set;
800 for( int i=0; i<listeners.size(); ++i ) {
801 BC_WindowBase *win = listeners[i]->win;
802 if( win->get_window_type() != POPUP_WINDOW ) continue;
803 ((BC_Popup *)win)->ungrab_keyboard();
807 void BC_ActiveBitmaps::reque(XEvent *event)
809 XShmCompletionEvent *shm_ev = (XShmCompletionEvent *)event;
810 ShmSeg shmseg = shm_ev->shmseg;
811 Drawable drawable = shm_ev->drawable;
812 //printf("BC_BitmapImage::reque %08lx\n",shmseg);
813 active_lock.lock("BC_BitmapImage::reque");
814 BC_BitmapImage *bfr = first;
815 while( bfr && bfr->get_shmseg() != shmseg ) bfr = bfr->next;
816 if( bfr && bfr->drawable == drawable )
818 active_lock.unlock();
820 // sadly, X reports two drawable completions and creates false reporting, so no boobytrap
821 // printf("BC_BitmapImage::reque missed shmseg %08x, drawable %08x\n",
822 // (int)shmseg, (int)drawable);
825 if( bfr->drawable != drawable ) return;
826 if( bfr->is_zombie() ) { --BC_Bitmap::zombies; delete bfr; return; }
827 bfr->bitmap->reque(bfr);
830 void BC_ActiveBitmaps::insert(BC_BitmapImage *bfr, Drawable pixmap)
832 active_lock.lock("BC_BitmapImage::insert");
833 bfr->drawable = pixmap;
835 active_lock.unlock();
838 void BC_ActiveBitmaps::remove_buffers(BC_WindowBase *wdw)
840 active_lock.lock("BC_ActiveBitmaps::remove");
841 for( BC_BitmapImage *nxt=0, *bfr=first; bfr; bfr=nxt ) {
843 if( bfr->is_zombie() ) { --BC_Bitmap::zombies; delete bfr; continue; }
844 if( bfr->bitmap->parent_window == wdw ) remove_pointer(bfr);
846 active_lock.unlock();
849 BC_ActiveBitmaps::BC_ActiveBitmaps()
853 BC_ActiveBitmaps::~BC_ActiveBitmaps()
859 int BC_WindowBase::keysym_lookup(XEvent *event)
861 for( int i = 0; i < KEYPRESSLEN; ++i ) keys_return[i] = 0;
862 for( int i = 0; i < 4; ++i ) wkey_string[i] = 0;
864 if( event->xany.send_event && !event->xany.serial ) {
865 keysym = (KeySym) event->xkey.keycode;
866 keys_return[0] = keysym;
869 wkey_string_length = 0;
871 if( input_context ) {
872 wkey_string_length = XwcLookupString(input_context,
873 (XKeyEvent*)event, wkey_string, 4, &keysym, 0);
874 //printf("keysym_lookup 1 %d %d %lx %x %x %x %x\n", wkey_string_length, keysym,
875 // wkey_string[0], wkey_string[1], wkey_string[2], wkey_string[3]);
878 int ret = Xutf8LookupString(input_context, (XKeyEvent*)event,
879 keys_return, KEYPRESSLEN, &keysym, &stat);
880 //printf("keysym_lookup 2 %d %d %lx %x %x\n", ret, stat, keysym, keys_return[0], keys_return[1]);
881 if( stat == XLookupBoth ) return ret;
882 if( stat == XLookupKeySym ) return 0;
884 int ret = XLookupString((XKeyEvent*)event, keys_return, KEYPRESSLEN, &keysym, 0);
885 wkey_string_length = ret;
886 for( int i=0; i<ret; ++i ) wkey_string[i] = keys_return[i];
890 pthread_t locking_task = (pthread_t)-1L;
891 int locking_event = -1;
892 int locking_message = -1;
894 int BC_WindowBase::dispatch_event()
898 XClientMessageEvent *ptr;
899 int cancel_resize, cancel_translation;
900 volatile static int debug = 0;
905 #ifndef SINGLE_THREAD
906 // If an event is waiting get it, otherwise
907 // wait for next event only if there are no compressed events.
908 if(get_event_count() ||
909 (!motion_events && !resize_events && !translation_events))
912 // Lock out window deletions
913 lock_window("BC_WindowBase::dispatch_event 1");
914 locking_event = event->type;
915 locking_task = pthread_self();
916 locking_message = event->xclient.message_type;
919 // Handle compressed events
921 lock_window("BC_WindowBase::dispatch_event 2");
923 dispatch_resize_event(last_resize_w, last_resize_h);
925 dispatch_motion_event();
926 if(translation_events)
927 dispatch_translation_event();
938 if( debug && event->type != ClientMessage ) {
939 static const char *event_names[] = {
940 "Reply", "Error", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease", "MotionNotify",
941 "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut", "KeymapNotify", "Expose", "GraphicsExpose",
942 "NoExpose", "VisibilityNotify", "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify",
943 "MapRequest", "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
944 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear",
945 "SelectionRequest", "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify",
946 "GenericEvent", "LASTEvent",
948 const int nevents = sizeof(event_names)/sizeof(event_names[0]);
950 printf("BC_WindowBase::dispatch_event %d %s %p %d (%s)\n", __LINE__,
951 title, event, event->type, event->type>=0 && event->type<nevents ?
952 event_names[event->type] : "Unknown");
957 active_grab->lock_window("BC_WindowBase::dispatch_event 3");
958 result = active_grab->grab_event(event);
959 active_grab->unlock_window();
960 if( result ) return result;
961 lock_window("BC_WindowBase::dispatch_event 4");
964 switch(event->type) {
966 // Clear the resize buffer
968 dispatch_resize_event(last_resize_w, last_resize_h);
969 // Clear the motion buffer since this can clear the window
971 dispatch_motion_event();
973 ptr = (XClientMessageEvent*)event;
974 if( ptr->message_type == ProtoXAtom &&
975 (Atom)ptr->data.l[0] == DelWinXAtom ) {
978 else if( ptr->message_type == RepeaterXAtom ) {
979 dispatch_repeat_event(ptr->data.l[0]);
981 else if( ptr->message_type == SetDoneXAtom ) {
985 receive_custom_xatoms((xatom_event *)ptr);
996 dispatch_focus_out();
1010 dispatch_motion_event();
1012 get_key_masks(event->xbutton.state);
1013 cursor_x = event->xbutton.x;
1014 cursor_y = event->xbutton.y;
1015 button_number = event->xbutton.button;
1017 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1018 event_win = event->xany.window;
1019 if (button_number < 6) {
1020 if(button_number < 4)
1022 button_pressed = event->xbutton.button;
1023 button_time1 = button_time2;
1024 button_time2 = button_time3;
1025 button_time3 = event->xbutton.time;
1028 drag_win = event_win;
1029 drag_x1 = cursor_x - get_resources()->drag_radius;
1030 drag_x2 = cursor_x + get_resources()->drag_radius;
1031 drag_y1 = cursor_y - get_resources()->drag_radius;
1032 drag_y2 = cursor_y + get_resources()->drag_radius;
1034 if((long)(button_time3 - button_time1) < resources->double_click * 2)
1037 button_time3 = button_time2 = button_time1 = 0;
1039 if((long)(button_time3 - button_time2) < resources->double_click)
1042 // button_time3 = button_time2 = button_time1 = 0;
1050 dispatch_button_press();
1057 dispatch_motion_event();
1059 get_key_masks(event->xbutton.state);
1060 button_number = event->xbutton.button;
1061 event_win = event->xany.window;
1062 if (button_number < 6)
1064 if(button_number < 4)
1066 //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number);
1068 dispatch_button_release();
1073 event_win = event->xany.window;
1075 for( int i=0; !result && i<popups.size(); ++i ) { // popups take focus
1076 if( popups[i]->win == event_win )
1077 result = popups[i]->dispatch_expose_event();
1080 result = dispatch_expose_event();
1084 get_key_masks(event->xmotion.state);
1085 // Dispatch previous motion event if this is a subsequent motion from a different window
1086 if(motion_events && last_motion_win != event->xany.window)
1088 dispatch_motion_event();
1091 // Buffer the current motion
1093 last_motion_state = event->xmotion.state;
1094 last_motion_x = event->xmotion.x;
1095 last_motion_y = event->xmotion.y;
1096 last_motion_win = event->xany.window;
1099 case ConfigureNotify:
1100 // printf("BC_WindowBase::dispatch_event %d win=%p this->win=%p\n",
1102 // event->xany.window,
1105 XTranslateCoordinates(top_level->display,
1113 last_resize_w = event->xconfigure.width;
1114 last_resize_h = event->xconfigure.height;
1117 cancel_translation = 0;
1119 // Resize history prevents responses to recursive resize requests
1120 for(int i = 0; i < resize_history.total && !cancel_resize; i++)
1122 if(resize_history.values[i]->w == last_resize_w &&
1123 resize_history.values[i]->h == last_resize_h)
1125 delete resize_history.values[i];
1126 resize_history.remove_number(i);
1131 if(last_resize_w == w && last_resize_h == h)
1139 if((last_translate_x == x && last_translate_y == y))
1140 cancel_translation = 1;
1142 if(!cancel_translation)
1144 translation_events = 1;
1147 translation_count++;
1151 get_key_masks(event->xkey.state);
1152 keys_return[0] = 0; keysym = -1;
1153 if(XFilterEvent(event, win)) {
1156 if( keysym_lookup(event) < 0 ) {
1157 printf("keysym %x\n", (uint32_t)keysym);
1161 //printf("BC_WindowBase::dispatch_event %d keysym=0x%x\n",
1165 // block out control keys
1166 if(keysym > 0xffe0 && keysym < 0xffff) break;
1167 // block out Alt_GR key
1168 if(keysym == 0xfe03) break;
1171 printf("BC_WindowBase::dispatch_event %x\n", (uint32_t)keysym);
1173 #ifdef X_HAVE_UTF8_STRING
1174 //It's Ascii or UTF8?
1175 // if (keysym != 0xffff && (keys_return[0] & 0xff) >= 0x7f )
1176 //printf("BC_WindowBase::dispatch_event %d %02x%02x\n", __LINE__, keys_return[0], keys_return[1]);
1178 if( ((keys_return[1] & 0xff) > 0x80) &&
1179 ((keys_return[0] & 0xff) > 0xC0) ) {
1180 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1181 key_pressed = keysym & 0xff;
1185 // shuttle speed codes
1186 if( keysym >= SKEY_MIN && keysym <= SKEY_MAX ) {
1187 key_pressed = keysym;
1189 else switch( keysym ) {
1190 // block out extra keys
1200 // Translate key codes
1201 case XK_Return: key_pressed = RETURN; break;
1202 case XK_Up: key_pressed = UP; break;
1203 case XK_Down: key_pressed = DOWN; break;
1204 case XK_Left: key_pressed = LEFT; break;
1205 case XK_Right: key_pressed = RIGHT; break;
1206 case XK_Next: key_pressed = PGDN; break;
1207 case XK_Prior: key_pressed = PGUP; break;
1208 case XK_BackSpace: key_pressed = BACKSPACE; break;
1209 case XK_Escape: key_pressed = ESC; break;
1212 key_pressed = LEFTTAB;
1216 case XK_ISO_Left_Tab: key_pressed = LEFTTAB; break;
1217 case XK_underscore: key_pressed = '_'; break;
1218 case XK_asciitilde: key_pressed = '~'; break;
1219 case XK_Delete: key_pressed = DELETE; break;
1220 case XK_Home: key_pressed = HOME; break;
1221 case XK_End: key_pressed = END; break;
1224 case XK_KP_Enter: key_pressed = KPENTER; break;
1225 case XK_KP_Add: key_pressed = KPPLUS; break;
1226 case XK_KP_Subtract: key_pressed = KPMINUS; break;
1227 case XK_KP_Multiply: key_pressed = KPSTAR; break;
1228 case XK_KP_Divide: key_pressed = KPSLASH; break;
1230 case XK_KP_End: key_pressed = KP1; break;
1232 case XK_KP_Down: key_pressed = KP2; break;
1234 case XK_KP_Page_Down: key_pressed = KP3; break;
1236 case XK_KP_Left: key_pressed = KP4; break;
1238 case XK_KP_Begin: key_pressed = KP5; break;
1240 case XK_KP_Right: key_pressed = KP6; break;
1242 case XK_KP_Home: key_pressed = KP7; break;
1244 case XK_KP_Up: key_pressed = KP8; break;
1246 case XK_KP_Page_Up: key_pressed = KP9; break;
1248 case XK_KP_Insert: key_pressed = KPINS; break;
1250 case XK_KP_Delete: key_pressed = KPDEL; break;
1252 case XK_F1: key_pressed = KEY_F1; break;
1253 case XK_F2: key_pressed = KEY_F2; break;
1254 case XK_F3: key_pressed = KEY_F3; break;
1255 case XK_F4: key_pressed = KEY_F4; break;
1256 case XK_F5: key_pressed = KEY_F5; break;
1257 case XK_F6: key_pressed = KEY_F6; break;
1258 case XK_F7: key_pressed = KEY_F7; break;
1259 case XK_F8: key_pressed = KEY_F8; break;
1260 case XK_F9: key_pressed = KEY_F9; break;
1261 case XK_F10: key_pressed = KEY_F10; break;
1262 case XK_F11: key_pressed = KEY_F11; break;
1263 case XK_F12: key_pressed = KEY_F12; break;
1265 case XK_Menu: key_pressed = KPMENU; break; /* menu */
1268 key_pressed = keysym & 0xff;
1269 #ifdef X_HAVE_UTF8_STRING
1270 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1275 #ifdef X_HAVE_UTF8_STRING
1277 key_pressed_utf8 = keys_return;
1282 if( top_level == this )
1283 result = BC_KeyboardHandler::run_listeners(this);
1285 //printf("BC_WindowBase::dispatch_event %d %d %x\n", shift_down(), alt_down(), key_pressed);
1287 result = dispatch_keypress_event();
1288 // Handle some default keypresses
1291 if(key_pressed == 'w' ||
1300 XLookupString((XKeyEvent*)event, keys_return, 1, &keysym, 0);
1301 dispatch_keyrelease_event();
1302 // printf("BC_WindowBase::dispatch_event KeyRelease keysym=0x%x keystate=0x%lld\n",
1303 // keysym, event->xkey.state);
1307 if( event->xcrossing.mode != NotifyNormal ) break;
1309 event_win = event->xany.window;
1310 dispatch_cursor_leave();
1314 if( event->xcrossing.mode != NotifyNormal ) break;
1316 if( !cursor_entered ) {
1317 for( int i=0; i<popups.size(); ++i ) { // popups always take focus
1318 if( popups[i]->win == event->xcrossing.window )
1321 if( !cursor_entered && get_resources()->grab_input_focus &&
1322 !event->xcrossing.focus && event->xcrossing.window == win ) {
1325 if( cursor_entered )
1328 event_win = event->xany.window;
1329 cursor_x = event->xcrossing.x;
1330 cursor_y = event->xcrossing.y;
1331 dispatch_cursor_enter();
1337 //printf("100 %s %p %d\n", title, event, event->type);
1338 //if(event->type != ClientMessage) dump();
1340 #ifndef SINGLE_THREAD
1343 if( resend_event_window ) {
1344 resend_event_window->put_event(event);
1345 resend_event_window = 0;
1351 // if(done) completion_lock->unlock();
1354 if(debug) printf("BC_WindowBase::dispatch_event this=%p %d\n", this, __LINE__);
1358 int BC_WindowBase::dispatch_expose_event()
1361 for(int i = 0; i < subwindows->total && !result; i++)
1363 result = subwindows->values[i]->dispatch_expose_event();
1366 // Propagate to user
1367 if(!result) expose_event();
1371 int BC_WindowBase::dispatch_resize_event(int w, int h)
1373 // Can't store new w and h until the event is handles
1374 // because bcfilebox depends on the old w and h to
1375 // reposition widgets.
1376 if( window_type == MAIN_WINDOW ) {
1381 pixmap = new BC_Pixmap(this, w, h);
1382 clear_box(0, 0, w, h);
1385 // Propagate to subwindows
1386 for(int i = 0; i < subwindows->total; i++) {
1387 subwindows->values[i]->dispatch_resize_event(w, h);
1390 // Propagate to user
1393 if( window_type == MAIN_WINDOW ) {
1402 int BC_WindowBase::dispatch_flash()
1405 for(int i = 0; i < subwindows->total; i++)
1406 subwindows->values[i]->dispatch_flash();
1410 int BC_WindowBase::dispatch_translation_event()
1412 translation_events = 0;
1413 if(window_type == MAIN_WINDOW)
1417 x = last_translate_x;
1418 y = last_translate_y;
1419 // Correct for window manager offsets
1424 for(int i = 0; i < subwindows->total; i++)
1426 subwindows->values[i]->dispatch_translation_event();
1429 translation_event();
1433 int BC_WindowBase::dispatch_motion_event()
1438 if(top_level == this)
1441 event_win = last_motion_win;
1442 get_key_masks(last_motion_state);
1445 if(get_button_down() && !active_menubar && !active_popup_menu)
1449 cursor_x = last_motion_x;
1450 cursor_y = last_motion_y;
1451 result = dispatch_drag_motion();
1455 (last_motion_x < drag_x1 || last_motion_x >= drag_x2 ||
1456 last_motion_y < drag_y1 || last_motion_y >= drag_y2))
1461 result = dispatch_drag_start();
1465 cursor_x = last_motion_x;
1466 cursor_y = last_motion_y;
1468 // printf("BC_WindowBase::dispatch_motion_event %d %p %p %p\n",
1471 // active_popup_menu,
1472 // active_subwindow);
1474 if(active_menubar && !result) result = active_menubar->dispatch_motion_event();
1475 if(active_popup_menu && !result) result = active_popup_menu->dispatch_motion_event();
1476 if(active_subwindow && !result) result = active_subwindow->dispatch_motion_event();
1479 // Dispatch in stacking order
1480 for(int i = subwindows->size() - 1; i >= 0 && !result; i--)
1482 result = subwindows->values[i]->dispatch_motion_event();
1485 if(!result) result = cursor_motion_event(); // give to user
1489 int BC_WindowBase::dispatch_keypress_event()
1492 if(top_level == this)
1494 if(active_subwindow) result = active_subwindow->dispatch_keypress_event();
1497 for(int i = 0; i < subwindows->total && !result; i++)
1499 result = subwindows->values[i]->dispatch_keypress_event();
1502 if(!result) result = keypress_event();
1507 int BC_WindowBase::dispatch_keyrelease_event()
1510 if(top_level == this)
1512 if(active_subwindow) result = active_subwindow->dispatch_keyrelease_event();
1515 for(int i = 0; i < subwindows->total && !result; i++)
1517 result = subwindows->values[i]->dispatch_keyrelease_event();
1520 if(!result) result = keyrelease_event();
1525 int BC_WindowBase::dispatch_focus_in()
1527 for(int i = 0; i < subwindows->total; i++)
1529 subwindows->values[i]->dispatch_focus_in();
1537 int BC_WindowBase::dispatch_focus_out()
1539 for(int i = 0; i < subwindows->total; i++)
1541 subwindows->values[i]->dispatch_focus_out();
1549 int BC_WindowBase::get_has_focus()
1551 return top_level->has_focus;
1554 int BC_WindowBase::get_deleting()
1556 if(is_deleting) return 1;
1557 if(parent_window && parent_window->get_deleting()) return 1;
1561 int BC_WindowBase::dispatch_button_press()
1566 if(top_level == this)
1568 if(active_menubar) result = active_menubar->dispatch_button_press();
1569 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_press();
1570 if(active_subwindow && !result) result = active_subwindow->dispatch_button_press();
1573 for(int i = 0; i < subwindows->total && !result; i++)
1575 result = subwindows->values[i]->dispatch_button_press();
1578 if(!result) result = button_press_event();
1584 int BC_WindowBase::dispatch_button_release()
1587 if(top_level == this)
1589 if(active_menubar) result = active_menubar->dispatch_button_release();
1590 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_release();
1591 if(active_subwindow && !result) result = active_subwindow->dispatch_button_release();
1592 if(!result && button_number != 4 && button_number != 5)
1593 result = dispatch_drag_stop();
1596 for(int i = 0; i < subwindows->total && !result; i++)
1598 result = subwindows->values[i]->dispatch_button_release();
1603 result = button_release_event();
1610 int BC_WindowBase::dispatch_repeat_event(int64_t duration)
1613 // all repeat event handlers get called and decide based on activity and duration
1614 // whether to respond
1615 for(int i = 0; i < subwindows->total; i++)
1617 subwindows->values[i]->dispatch_repeat_event(duration);
1621 repeat_event(duration);
1625 // Unlock next repeat signal
1626 if(window_type == MAIN_WINDOW)
1628 #ifdef SINGLE_THREAD
1629 BC_Display::display_global->unlock_repeaters(duration);
1631 for(int i = 0; i < repeaters.total; i++)
1633 if(repeaters.values[i]->delay == duration)
1635 repeaters.values[i]->repeat_lock->unlock();
1643 void BC_WindowBase::unhide_cursor()
1648 if(top_level->is_hourglass)
1649 set_cursor(HOURGLASS_CURSOR, 1, 0);
1651 set_cursor(current_cursor, 1, 0);
1653 cursor_timer->update();
1657 void BC_WindowBase::update_video_cursor()
1659 if(video_on && !is_transparent)
1661 if(cursor_timer->get_difference() > VIDEO_CURSOR_TIMEOUT && !is_transparent)
1664 set_cursor(TRANSPARENT_CURSOR, 1, 1);
1665 cursor_timer->update();
1670 cursor_timer->update();
1675 int BC_WindowBase::dispatch_cursor_leave()
1679 for(int i = 0; i < subwindows->total; i++)
1681 subwindows->values[i]->dispatch_cursor_leave();
1684 cursor_leave_event();
1688 int BC_WindowBase::dispatch_cursor_enter()
1694 if(active_menubar) result = active_menubar->dispatch_cursor_enter();
1695 if(!result && active_popup_menu) result = active_popup_menu->dispatch_cursor_enter();
1696 if(!result && active_subwindow) result = active_subwindow->dispatch_cursor_enter();
1698 for(int i = 0; !result && i < subwindows->total; i++)
1700 result = subwindows->values[i]->dispatch_cursor_enter();
1703 if(!result) result = cursor_enter_event();
1707 int BC_WindowBase::cursor_enter_event()
1712 int BC_WindowBase::cursor_leave_event()
1717 int BC_WindowBase::close_event()
1723 int BC_WindowBase::dispatch_drag_start()
1726 if(active_menubar) result = active_menubar->dispatch_drag_start();
1727 if(!result && active_popup_menu) result = active_popup_menu->dispatch_drag_start();
1728 if(!result && active_subwindow) result = active_subwindow->dispatch_drag_start();
1730 for(int i = 0; i < subwindows->total && !result; i++)
1732 result = subwindows->values[i]->dispatch_drag_start();
1735 if(!result) result = is_dragging = drag_start_event();
1739 int BC_WindowBase::dispatch_drag_stop()
1743 for(int i = 0; i < subwindows->total && !result; i++)
1745 result = subwindows->values[i]->dispatch_drag_stop();
1748 if(is_dragging && !result)
1758 int BC_WindowBase::dispatch_drag_motion()
1761 for(int i = 0; i < subwindows->total && !result; i++)
1763 result = subwindows->values[i]->dispatch_drag_motion();
1766 if(is_dragging && !result)
1768 drag_motion_event();
1776 int BC_WindowBase::show_tooltip(const char *text, int x, int y, int w, int h)
1779 int forced = !text ? force_tooltip : 1;
1780 if( !text ) text = tooltip_text;
1781 if( !text || (!forced && !get_resources()->tooltips_enabled) ) {
1782 top_level->hide_tooltip();
1786 if(w < 0) w = get_text_width(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1787 if(h < 0) h = get_text_height(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1788 // default x,y (win relative)
1789 if( x < 0 ) x = get_w();
1790 if( y < 0 ) y = get_h();
1792 get_root_coordinates(x, y, &wx, &wy);
1793 // keep the tip inside the window/display
1794 int x0 = top_level->get_x(), x1 = x0 + top_level->get_w();
1795 int x2 = top_level->get_screen_x(0, -1) + top_level->get_screen_w(0, -1);
1796 if( x1 > x2 ) x1 = x2;
1797 if( wx < x0 ) wx = x0;
1798 if( wx >= (x1-=w) ) wx = x1;
1799 int y0 = top_level->get_y(), y1 = y0 + top_level->get_h();
1800 int y2 = top_level->get_root_h(0);
1801 if( y1 > y2 ) y1 = y2;
1802 if( wy < y0 ) wy = y0;
1803 if( wy >= (y1-=h) ) wy = y1;
1804 // avoid tip under cursor (flickers)
1806 get_abs_cursor(abs_x,abs_y, 0);
1807 if( wx < abs_x && abs_x < wx+w && wy < abs_y && abs_y < wy+h ) {
1808 if( wx-abs_x < wy-abs_y )
1815 tooltip_popup = new BC_Popup(top_level, wx, wy, w, h,
1816 get_resources()->tooltip_bg_color);
1819 tooltip_popup->reposition_window(wx, wy, w, h);
1822 tooltip_popup->flash();
1823 tooltip_popup->flush();
1827 int BC_WindowBase::hide_tooltip()
1830 for(int i = 0; i < subwindows->total; i++)
1832 subwindows->values[i]->hide_tooltip();
1838 delete tooltip_popup;
1844 const char *BC_WindowBase::get_tooltip()
1846 return tooltip_text;
1849 int BC_WindowBase::set_tooltip(const char *text)
1851 tooltip_text = text;
1853 // Update existing tooltip if it is visible
1857 tooltip_popup->flash();
1861 // signal the event handler to repeat
1862 int BC_WindowBase::set_repeat(int64_t duration)
1866 printf("BC_WindowBase::set_repeat duration=%jd\n", duration);
1869 if(window_type != MAIN_WINDOW) return top_level->set_repeat(duration);
1871 #ifdef SINGLE_THREAD
1872 BC_Display::display_global->set_repeat(this, duration);
1874 // test repeater database for duplicates
1875 for(int i = 0; i < repeaters.total; i++)
1878 if(repeaters.values[i]->delay == duration)
1880 repeaters.values[i]->start_repeating(this);
1885 BC_Repeater *repeater = new BC_Repeater(this, duration);
1886 repeater->initialize();
1887 repeaters.append(repeater);
1888 repeater->start_repeating();
1893 int BC_WindowBase::unset_repeat(int64_t duration)
1895 if(window_type != MAIN_WINDOW) return top_level->unset_repeat(duration);
1897 #ifdef SINGLE_THREAD
1898 BC_Display::display_global->unset_repeat(this, duration);
1900 for(int i = 0; i < repeaters.total; i++)
1902 if(repeaters.values[i]->delay == duration)
1904 repeaters.values[i]->stop_repeating();
1912 int BC_WindowBase::unset_all_repeaters()
1914 #ifdef SINGLE_THREAD
1915 BC_Display::display_global->unset_all_repeaters(this);
1917 for(int i = 0; i < repeaters.total; i++)
1919 repeaters.values[i]->stop_repeating();
1921 repeaters.remove_all_objects();
1926 // long BC_WindowBase::get_repeat_id()
1928 // return top_level->next_repeat_id++;
1931 XEvent *BC_WindowBase::new_xevent()
1933 XEvent *event = new XEvent;
1934 memset(event, 0, sizeof(*event));
1938 #ifndef SINGLE_THREAD
1939 int BC_WindowBase::arm_repeat(int64_t duration)
1941 XEvent *event = new_xevent();
1942 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
1943 ptr->type = ClientMessage;
1944 ptr->message_type = RepeaterXAtom;
1946 ptr->data.l[0] = duration;
1948 // Couldn't use XSendEvent since it locked up randomly.
1954 int BC_WindowBase::receive_custom_xatoms(xatom_event *event)
1959 int BC_WindowBase::send_custom_xatom(xatom_event *event)
1961 #ifndef SINGLE_THREAD
1962 XEvent *myevent = new_xevent();
1963 XClientMessageEvent *ptr = (XClientMessageEvent*)myevent;
1964 ptr->type = ClientMessage;
1965 ptr->message_type = event->message_type;
1966 ptr->format = event->format;
1967 ptr->data.l[0] = event->data.l[0];
1968 ptr->data.l[1] = event->data.l[1];
1969 ptr->data.l[2] = event->data.l[2];
1970 ptr->data.l[3] = event->data.l[3];
1971 ptr->data.l[4] = event->data.l[4];
1980 Atom BC_WindowBase::create_xatom(const char *atom_name)
1982 return XInternAtom(display, atom_name, False);
1985 int BC_WindowBase::get_atoms()
1987 SetDoneXAtom = XInternAtom(display, "BC_REPEAT_EVENT", False);
1988 RepeaterXAtom = XInternAtom(display, "BC_CLOSE_EVENT", False);
1989 DestroyAtom = XInternAtom(display, "BC_DESTROY_WINDOW", False);
1990 DelWinXAtom = XInternAtom(display, "WM_DELETE_WINDOW", False);
1991 if( (ProtoXAtom = XInternAtom(display, "WM_PROTOCOLS", False)) != 0 )
1992 XChangeProperty(display, win, ProtoXAtom, XA_ATOM, 32,
1993 PropModeReplace, (unsigned char *)&DelWinXAtom, True);
1999 void BC_WindowBase::init_cursors()
2001 arrow_cursor = XCreateFontCursor(display, XC_top_left_arrow);
2002 cross_cursor = XCreateFontCursor(display, XC_crosshair);
2003 ibeam_cursor = XCreateFontCursor(display, XC_xterm);
2004 vseparate_cursor = XCreateFontCursor(display, XC_sb_v_double_arrow);
2005 hseparate_cursor = XCreateFontCursor(display, XC_sb_h_double_arrow);
2006 move_cursor = XCreateFontCursor(display, XC_fleur);
2007 left_cursor = XCreateFontCursor(display, XC_sb_left_arrow);
2008 right_cursor = XCreateFontCursor(display, XC_sb_right_arrow);
2009 upright_arrow_cursor = XCreateFontCursor(display, XC_arrow);
2010 upleft_resize_cursor = XCreateFontCursor(display, XC_top_left_corner);
2011 upright_resize_cursor = XCreateFontCursor(display, XC_top_right_corner);
2012 downleft_resize_cursor = XCreateFontCursor(display, XC_bottom_left_corner);
2013 downright_resize_cursor = XCreateFontCursor(display, XC_bottom_right_corner);
2014 hourglass_cursor = XCreateFontCursor(display, XC_watch);
2015 grabbed_cursor = create_grab_cursor();
2017 static char cursor_data[] = { 0,0,0,0, 0,0,0,0 };
2018 Colormap colormap = DefaultColormap(display, screen);
2019 Pixmap pixmap_bottom = XCreateBitmapFromData(display,
2020 rootwin, cursor_data, 8, 8);
2021 XColor black, dummy;
2022 XAllocNamedColor(display, colormap, "black", &black, &dummy);
2023 transparent_cursor = XCreatePixmapCursor(display,
2024 pixmap_bottom, pixmap_bottom, &black, &black, 0, 0);
2025 // XDefineCursor(display, win, transparent_cursor);
2026 XFreePixmap(display, pixmap_bottom);
2029 int BC_WindowBase::evaluate_color_model(int client_byte_order, int server_byte_order, int depth)
2031 int color_model = BC_TRANSPARENCY;
2035 color_model = BC_RGB8;
2038 color_model = (server_byte_order == client_byte_order) ? BC_RGB565 : BC_BGR565;
2041 color_model = server_byte_order ? BC_BGR888 : BC_RGB888;
2044 color_model = server_byte_order ? BC_BGR8888 : BC_ARGB8888;
2050 int BC_WindowBase::init_colors()
2053 current_color_value = current_color_pixel = 0;
2055 // Get the real depth
2058 ximage = XCreateImage(top_level->display,
2059 top_level->vis, top_level->default_depth,
2060 ZPixmap, 0, data, 16, 16, 8, 0);
2061 bits_per_pixel = ximage->bits_per_pixel;
2062 XDestroyImage(ximage);
2064 color_model = evaluate_color_model(client_byte_order,
2067 // Get the color model
2072 cmap = XCreateColormap(display, rootwin, vis, AllocNone);
2073 create_private_colors();
2076 cmap = DefaultColormap(display, screen);
2077 create_shared_colors();
2080 allocate_color_table();
2084 //cmap = DefaultColormap(display, screen);
2085 cmap = XCreateColormap(display, rootwin, vis, AllocNone );
2091 int BC_WindowBase::create_private_colors()
2096 for(int i = 0; i < 255; i++)
2098 color = (i & 0xc0) << 16;
2099 color += (i & 0x38) << 10;
2100 color += (i & 0x7) << 5;
2101 color_table[i][0] = color;
2103 create_shared_colors(); // overwrite the necessary colors on the table
2108 int BC_WindowBase::create_color(int color)
2110 if(total_colors == 256)
2112 // replace the closest match with an exact match
2113 color_table[get_color_rgb8(color)][0] = color;
2117 // add the color to the table
2118 color_table[total_colors][0] = color;
2124 int BC_WindowBase::create_shared_colors()
2126 create_color(BLACK);
2127 create_color(WHITE);
2129 create_color(LTGREY);
2130 create_color(MEGREY);
2131 create_color(MDGREY);
2132 create_color(DKGREY);
2134 create_color(LTCYAN);
2135 create_color(MECYAN);
2136 create_color(MDCYAN);
2137 create_color(DKCYAN);
2139 create_color(LTGREEN);
2140 create_color(GREEN);
2141 create_color(DKGREEN);
2143 create_color(LTPINK);
2147 create_color(LTBLUE);
2149 create_color(DKBLUE);
2151 create_color(LTYELLOW);
2152 create_color(MEYELLOW);
2153 create_color(MDYELLOW);
2154 create_color(DKYELLOW);
2156 create_color(LTPURPLE);
2157 create_color(MEPURPLE);
2158 create_color(MDPURPLE);
2159 create_color(DKPURPLE);
2161 create_color(FGGREY);
2162 create_color(MNBLUE);
2163 create_color(ORANGE);
2164 create_color(FTGREY);
2169 Cursor BC_WindowBase::create_grab_cursor()
2171 int iw = 23, iw1 = iw-1, iw2 = iw/2;
2172 int ih = 23, ih1 = ih-1, ih2 = ih/2;
2173 VFrame grab(iw,ih,BC_RGB888);
2175 grab.set_pixel_color(RED); // fg
2176 grab.draw_smooth(iw2,0, iw1,0, iw1,ih2);
2177 grab.draw_smooth(iw1,ih2, iw1,ih1, iw2,ih1);
2178 grab.draw_smooth(iw2,ih1, 0,ih1, 0,ih2);
2179 grab.draw_smooth(0,ih2, 0,0, iw2,0);
2180 grab.set_pixel_color(WHITE); // bg
2181 grab.draw_line(0,ih2, iw2-2,ih2);
2182 grab.draw_line(iw2+2,ih2, iw1,ih2);
2183 grab.draw_line(iw2,0, iw2,ih2-2);
2184 grab.draw_line(iw2,ih2+2, iw2,ih1);
2186 int bpl = (iw+7)/8, isz = bpl * ih;
2187 char img[isz]; memset(img, 0, isz);
2188 char msk[isz]; memset(msk, 0, isz);
2189 unsigned char **rows = grab.get_rows();
2190 for( int iy=0; iy<ih; ++iy ) {
2191 char *op = img + iy*bpl;
2192 char *mp = msk + iy*bpl;
2193 unsigned char *ip = rows[iy];
2194 for( int ix=0; ix<iw; ++ix,ip+=3 ) {
2195 if( ip[0] ) mp[ix>>3] |= (1<<(ix&7));
2196 if( !ip[1] ) op[ix>>3] |= (1<<(ix&7));
2199 unsigned long white_pix = WhitePixel(display, screen);
2200 unsigned long black_pix = BlackPixel(display, screen);
2201 Pixmap img_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2202 img, iw,ih, white_pix,black_pix, 1);
2203 Pixmap msk_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2204 msk, iw,ih, white_pix,black_pix, 1);
2207 fc.flags = bc.flags = DoRed | DoGreen | DoBlue;
2208 fc.red = 0xffff; fc.green = fc.blue = 0; // fg
2209 bc.red = 0xffff; bc.green = 0xffff; bc.blue = 0x0000; // bg
2210 Cursor cursor = XCreatePixmapCursor(display, img_xpm,msk_xpm, &fc,&bc, iw2,ih2);
2211 XFreePixmap(display, img_xpm);
2212 XFreePixmap(display, msk_xpm);
2216 int BC_WindowBase::allocate_color_table()
2218 int red, green, blue, color;
2221 for(int i = 0; i < total_colors; i++)
2223 color = color_table[i][0];
2224 red = (color & 0xFF0000) >> 16;
2225 green = (color & 0x00FF00) >> 8;
2226 blue = color & 0xFF;
2228 col.flags = DoRed | DoGreen | DoBlue;
2229 col.red = red<<8 | red;
2230 col.green = green<<8 | green;
2231 col.blue = blue<<8 | blue;
2233 XAllocColor(display, cmap, &col);
2234 color_table[i][1] = col.pixel;
2237 XInstallColormap(display, cmap);
2241 int BC_WindowBase::init_window_shape()
2243 if(bg_pixmap && bg_pixmap->use_alpha())
2245 XShapeCombineMask(top_level->display,
2246 this->win, ShapeBounding, 0, 0,
2247 bg_pixmap->get_alpha(), ShapeSet);
2253 int BC_WindowBase::init_gc()
2255 unsigned long gcmask;
2256 gcmask = GCFont | GCGraphicsExposures;
2259 gcvalues.font = mediumfont->fid; // set the font
2260 gcvalues.graphics_exposures = 0; // prevent expose events for every redraw
2261 gc = XCreateGC(display, rootwin, gcmask, &gcvalues);
2263 // gcmask = GCCapStyle | GCJoinStyle;
2264 // XGetGCValues(display, gc, gcmask, &gcvalues);
2265 // printf("BC_WindowBase::init_gc %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2269 int BC_WindowBase::init_fonts()
2271 if( !(smallfont = XLoadQueryFont(display, _(resources->small_font))) )
2272 if( !(smallfont = XLoadQueryFont(display, _(resources->small_font2))) )
2273 smallfont = XLoadQueryFont(display, "fixed");
2274 if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font))) )
2275 if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font2))) )
2276 mediumfont = XLoadQueryFont(display, "fixed");
2277 if( !(largefont = XLoadQueryFont(display, _(resources->large_font))) )
2278 if( !(largefont = XLoadQueryFont(display, _(resources->large_font2))) )
2279 largefont = XLoadQueryFont(display, "fixed");
2280 if( !(bigfont = XLoadQueryFont(display, _(resources->big_font))) )
2281 if( !(bigfont = XLoadQueryFont(display, _(resources->big_font2))) )
2282 bigfont = XLoadQueryFont(display, "fixed");
2284 if((clockfont = XLoadQueryFont(display, _(resources->clock_font))) == NULL)
2285 if((clockfont = XLoadQueryFont(display, _(resources->clock_font2))) == NULL)
2286 clockfont = XLoadQueryFont(display, "fixed");
2289 if(get_resources()->use_fontset)
2294 // FIXME: should check the m,d,n values
2295 smallfontset = XCreateFontSet(display, resources->small_fontset, &m, &n, &d);
2297 smallfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2298 mediumfontset = XCreateFontSet(display, resources->medium_fontset, &m, &n, &d);
2299 if( !mediumfontset )
2300 mediumfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2301 largefontset = XCreateFontSet(display, resources->large_fontset, &m, &n, &d);
2303 largefontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2304 bigfontset = XCreateFontSet(display, resources->big_fontset, &m, &n, &d);
2306 bigfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2307 clockfontset = XCreateFontSet(display, resources->clock_fontset, &m, &n, &d);
2309 clockfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2310 if(clockfontset && bigfontset && largefontset && mediumfontset && smallfontset) {
2311 curr_fontset = mediumfontset;
2312 get_resources()->use_fontset = 1;
2316 get_resources()->use_fontset = 0;
2323 void BC_WindowBase::init_xft()
2326 if( !get_resources()->use_xft ) return;
2327 // apparently, xft is not reentrant, more than this is needed
2328 static Mutex xft_init_lock("BC_WindowBase::xft_init_lock", 0);
2329 xft_init_lock.lock("BC_WindowBase::init_xft");
2330 if(!(smallfont_xft =
2331 (resources->small_font_xft[0] == '-' ?
2332 xftFontOpenXlfd(display, screen, resources->small_font_xft) :
2333 xftFontOpenName(display, screen, resources->small_font_xft))) )
2334 if(!(smallfont_xft =
2335 xftFontOpenXlfd(display, screen, resources->small_font_xft2)))
2336 smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2337 if(!(mediumfont_xft =
2338 (resources->medium_font_xft[0] == '-' ?
2339 xftFontOpenXlfd(display, screen, resources->medium_font_xft) :
2340 xftFontOpenName(display, screen, resources->medium_font_xft))) )
2341 if(!(mediumfont_xft =
2342 xftFontOpenXlfd(display, screen, resources->medium_font_xft2)))
2343 mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2344 if(!(largefont_xft =
2345 (resources->large_font_xft[0] == '-' ?
2346 xftFontOpenXlfd(display, screen, resources->large_font_xft) :
2347 xftFontOpenName(display, screen, resources->large_font_xft))) )
2348 if(!(largefont_xft =
2349 xftFontOpenXlfd(display, screen, resources->large_font_xft2)))
2350 largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2352 (resources->big_font_xft[0] == '-' ?
2353 xftFontOpenXlfd(display, screen, resources->big_font_xft) :
2354 xftFontOpenName(display, screen, resources->big_font_xft))) )
2356 xftFontOpenXlfd(display, screen, resources->big_font_xft2)))
2357 bigfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2358 if(!(clockfont_xft =
2359 (resources->clock_font_xft[0] == '-' ?
2360 xftFontOpenXlfd(display, screen, resources->clock_font_xft) :
2361 xftFontOpenName(display, screen, resources->clock_font_xft))) )
2362 clockfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2365 if(!(bold_smallfont_xft =
2366 (resources->small_b_font_xft[0] == '-' ?
2367 xftFontOpenXlfd(display, screen, resources->small_b_font_xft) :
2368 xftFontOpenName(display, screen, resources->small_b_font_xft))) )
2369 bold_smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2370 if(!(bold_mediumfont_xft =
2371 (resources->medium_b_font_xft[0] == '-' ?
2372 xftFontOpenXlfd(display, screen, resources->medium_b_font_xft) :
2373 xftFontOpenName(display, screen, resources->medium_b_font_xft))) )
2374 bold_mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2375 if(!(bold_largefont_xft =
2376 (resources->large_b_font_xft[0] == '-' ?
2377 xftFontOpenXlfd(display, screen, resources->large_b_font_xft) :
2378 xftFontOpenName(display, screen, resources->large_b_font_xft))) )
2379 bold_largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2381 if( !smallfont_xft || !mediumfont_xft || !largefont_xft || !bigfont_xft ||
2382 !bold_largefont_xft || !bold_mediumfont_xft || !bold_largefont_xft ||
2384 printf("BC_WindowBase::init_fonts: no xft fonts found:"
2385 " %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n",
2386 resources->small_font_xft, smallfont_xft,
2387 resources->medium_font_xft, mediumfont_xft,
2388 resources->large_font_xft, largefont_xft,
2389 resources->big_font_xft, bigfont_xft,
2390 resources->clock_font_xft, clockfont_xft,
2391 resources->small_b_font_xft, bold_smallfont_xft,
2392 resources->medium_b_font_xft, bold_mediumfont_xft,
2393 resources->large_b_font_xft, bold_largefont_xft);
2394 get_resources()->use_xft = 0;
2397 // _XftDisplayInfo needs a lock.
2398 xftDefaultHasRender(display);
2399 xft_init_lock.unlock();
2403 void BC_WindowBase::init_glyphs()
2405 // draw all ascii char glyphs
2406 // There are problems with some/my graphics boards/drivers
2407 // which cause some glyphs to be munged if draws occur while
2408 // the font is being loaded. This code fills the font caches
2409 // by drawing all the ascii glyphs before the system starts.
2410 // Not a fix, but much better than nothing.
2411 static int inited = 0;
2412 if( inited ) return;
2413 XGrabServer(display);
2416 int cur_font = current_font;
2417 // locale encodings, needed glyphs to be preloaded
2418 const char *text = _( // ascii 0x20...0x7e
2419 " !\"#$%&'()*+,-./0123456789:;<=>?"
2420 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
2421 "`abcdefghijklmnopqrstuvwxyz{|}~");
2422 for( int font=SMALLFONT; font<=LARGEFONT; ++font ) {
2424 draw_text(5,5, text, 0);
2427 XUngrabServer(display);
2430 void BC_WindowBase::init_im()
2432 XIMStyles *xim_styles;
2435 if(!(input_method = XOpenIM(display, NULL, NULL, NULL)))
2437 printf("BC_WindowBase::init_im: Could not open input method.\n");
2440 if(XGetIMValues(input_method, XNQueryInputStyle, &xim_styles, NULL) ||
2443 printf("BC_WindowBase::init_im: Input method doesn't support any styles.\n");
2444 XCloseIM(input_method);
2449 for(int z = 0; z < xim_styles->count_styles; z++)
2451 if(xim_styles->supported_styles[z] == (XIMPreeditNothing | XIMStatusNothing))
2453 xim_style = xim_styles->supported_styles[z];
2461 printf("BC_WindowBase::init_im: Input method doesn't support the style we need.\n");
2462 XCloseIM(input_method);
2466 input_context = XCreateIC(input_method, XNInputStyle, xim_style,
2467 XNClientWindow, win, XNFocusWindow, win, NULL);
2470 printf("BC_WindowBase::init_im: Failed to create input context.\n");
2471 XCloseIM(input_method);
2476 void BC_WindowBase::finit_im()
2478 if( input_context ) {
2479 XDestroyIC(input_context);
2482 if( input_method ) {
2483 XCloseIM(input_method);
2489 int BC_WindowBase::get_color(int64_t color)
2491 // return pixel of color
2492 // use this only for drawing subwindows not for bitmaps
2493 int i, test, difference;
2499 return get_color_rgb8(color);
2500 // test last color looked up
2501 if(current_color_value == color)
2502 return current_color_pixel;
2505 current_color_value = color;
2506 for(i = 0; i < total_colors; i++)
2508 if(color_table[i][0] == color)
2510 current_color_pixel = color_table[i][1];
2511 return current_color_pixel;
2515 // find nearest match
2516 difference = 0xFFFFFF;
2518 for(i = 0; i < total_colors; i++)
2520 test = abs((int)(color_table[i][0] - color));
2522 if(test < difference)
2524 current_color_pixel = color_table[i][1];
2528 return current_color_pixel;
2531 return get_color_rgb16(color);
2534 return get_color_bgr16(color);
2538 return client_byte_order == server_byte_order ?
2539 color : get_color_bgr24(color);
2547 int BC_WindowBase::get_color_rgb8(int color)
2551 pixel = (color & 0xc00000) >> 16;
2552 pixel += (color & 0xe000) >> 10;
2553 pixel += (color & 0xe0) >> 5;
2557 int64_t BC_WindowBase::get_color_rgb16(int color)
2560 result = (color & 0xf80000) >> 8;
2561 result += (color & 0xfc00) >> 5;
2562 result += (color & 0xf8) >> 3;
2567 int64_t BC_WindowBase::get_color_bgr16(int color)
2570 result = (color & 0xf80000) >> 19;
2571 result += (color & 0xfc00) >> 5;
2572 result += (color & 0xf8) << 8;
2577 int64_t BC_WindowBase::get_color_bgr24(int color)
2580 result = (color & 0xff) << 16;
2581 result += (color & 0xff00);
2582 result += (color & 0xff0000) >> 16;
2586 void BC_WindowBase::start_video()
2588 cursor_timer->update();
2590 // set_color(BLACK);
2591 // draw_box(0, 0, get_w(), get_h());
2595 void BC_WindowBase::stop_video()
2603 int64_t BC_WindowBase::get_color()
2605 return top_level->current_color;
2608 void BC_WindowBase::set_color(int64_t color)
2610 top_level->current_color = color;
2611 XSetForeground(top_level->display,
2613 top_level->get_color(color));
2616 void BC_WindowBase::set_opaque()
2618 XSetFunction(top_level->display, top_level->gc, GXcopy);
2621 void BC_WindowBase::set_inverse()
2623 XSetFunction(top_level->display, top_level->gc, GXxor);
2626 void BC_WindowBase::set_line_width(int value)
2628 this->line_width = value;
2629 XSetLineAttributes(top_level->display, top_level->gc, value, /* line_width */
2630 line_dashes == 0 ? LineSolid : LineOnOffDash, /* line_style */
2631 line_dashes == 0 ? CapRound : CapNotLast, /* cap_style */
2632 JoinMiter); /* join_style */
2634 if(line_dashes > 0) {
2635 const char dashes = line_dashes;
2636 XSetDashes(top_level->display, top_level->gc, 0, &dashes, 1);
2639 // XGCValues gcvalues;
2640 // unsigned long gcmask;
2641 // gcmask = GCCapStyle | GCJoinStyle;
2642 // XGetGCValues(top_level->display, top_level->gc, gcmask, &gcvalues);
2643 // printf("BC_WindowBase::set_line_width %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2646 void BC_WindowBase::set_line_dashes(int value)
2648 line_dashes = value;
2649 // call XSetLineAttributes
2650 set_line_width(line_width);
2654 Cursor BC_WindowBase::get_cursor_struct(int cursor)
2658 case ARROW_CURSOR: return top_level->arrow_cursor;
2659 case CROSS_CURSOR: return top_level->cross_cursor;
2660 case IBEAM_CURSOR: return top_level->ibeam_cursor;
2661 case VSEPARATE_CURSOR: return top_level->vseparate_cursor;
2662 case HSEPARATE_CURSOR: return top_level->hseparate_cursor;
2663 case MOVE_CURSOR: return top_level->move_cursor;
2664 case LEFT_CURSOR: return top_level->left_cursor;
2665 case RIGHT_CURSOR: return top_level->right_cursor;
2666 case UPRIGHT_ARROW_CURSOR: return top_level->upright_arrow_cursor;
2667 case UPLEFT_RESIZE: return top_level->upleft_resize_cursor;
2668 case UPRIGHT_RESIZE: return top_level->upright_resize_cursor;
2669 case DOWNLEFT_RESIZE: return top_level->downleft_resize_cursor;
2670 case DOWNRIGHT_RESIZE: return top_level->downright_resize_cursor;
2671 case HOURGLASS_CURSOR: return top_level->hourglass_cursor;
2672 case TRANSPARENT_CURSOR: return top_level->transparent_cursor;
2673 case GRABBED_CURSOR: return top_level->grabbed_cursor;
2678 void BC_WindowBase::set_cursor(int cursor, int override, int flush)
2680 // inherit cursor from parent
2683 XUndefineCursor(top_level->display, win);
2684 current_cursor = cursor;
2687 // don't change cursor if overridden
2688 if((!top_level->is_hourglass && !is_transparent) ||
2691 XDefineCursor(top_level->display, win, get_cursor_struct(cursor));
2692 if(flush) this->flush();
2695 if(!override) current_cursor = cursor;
2698 void BC_WindowBase::set_x_cursor(int cursor)
2700 temp_cursor = XCreateFontCursor(top_level->display, cursor);
2701 XDefineCursor(top_level->display, win, temp_cursor);
2702 current_cursor = cursor;
2706 int BC_WindowBase::get_cursor()
2708 return current_cursor;
2711 void BC_WindowBase::start_hourglass()
2713 top_level->start_hourglass_recursive();
2717 void BC_WindowBase::stop_hourglass()
2719 top_level->stop_hourglass_recursive();
2723 void BC_WindowBase::start_hourglass_recursive()
2725 if(this == top_level)
2733 set_cursor(HOURGLASS_CURSOR, 1, 0);
2734 for(int i = 0; i < subwindows->total; i++)
2736 subwindows->values[i]->start_hourglass_recursive();
2741 void BC_WindowBase::stop_hourglass_recursive()
2743 if(this == top_level)
2745 if(hourglass_total == 0) return;
2746 top_level->hourglass_total--;
2749 if(!top_level->hourglass_total)
2751 top_level->is_hourglass = 0;
2753 // Cause set_cursor to perform change
2755 set_cursor(current_cursor, 1, 0);
2757 for(int i = 0; i < subwindows->total; i++)
2759 subwindows->values[i]->stop_hourglass_recursive();
2767 XFontStruct* BC_WindowBase::get_font_struct(int font)
2769 // Clear out unrelated flags
2770 if(font & BOLDFACE) font ^= BOLDFACE;
2773 case SMALLFONT: return top_level->smallfont; break;
2774 case MEDIUMFONT: return top_level->mediumfont; break;
2775 case LARGEFONT: return top_level->largefont; break;
2776 case BIGFONT: return top_level->bigfont; break;
2777 case CLOCKFONT: return top_level->clockfont; break;
2782 XFontSet BC_WindowBase::get_fontset(int font)
2786 if(get_resources()->use_fontset)
2788 switch(font & 0xff) {
2789 case SMALLFONT: fs = top_level->smallfontset; break;
2790 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2791 case LARGEFONT: fs = top_level->largefontset; break;
2792 case BIGFONT: fs = top_level->bigfontset; break;
2793 case CLOCKFONT: fs = top_level->clockfontset; break;
2801 XftFont* BC_WindowBase::get_xft_struct(int font)
2804 case SMALLFONT: return (XftFont*)top_level->smallfont_xft;
2805 case MEDIUMFONT: return (XftFont*)top_level->mediumfont_xft;
2806 case LARGEFONT: return (XftFont*)top_level->largefont_xft;
2807 case BIGFONT: return (XftFont*)top_level->bigfont_xft;
2808 case CLOCKFONT: return (XftFont*)top_level->clockfont_xft;
2809 case MEDIUMFONT_3D: return (XftFont*)top_level->bold_mediumfont_xft;
2810 case SMALLFONT_3D: return (XftFont*)top_level->bold_smallfont_xft;
2811 case LARGEFONT_3D: return (XftFont*)top_level->bold_largefont_xft;
2819 int BC_WindowBase::get_current_font()
2821 return top_level->current_font;
2824 void BC_WindowBase::set_font(int font)
2826 top_level->current_font = font;
2829 if(get_resources()->use_xft) {}
2832 if(get_resources()->use_fontset) {
2836 if(get_font_struct(font))
2838 XSetFont(top_level->display, top_level->gc, get_font_struct(font)->fid);
2844 void BC_WindowBase::set_fontset(int font)
2848 if(get_resources()->use_fontset) {
2850 case SMALLFONT: fs = top_level->smallfontset; break;
2851 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2852 case LARGEFONT: fs = top_level->largefontset; break;
2853 case BIGFONT: fs = top_level->bigfontset; break;
2854 case CLOCKFONT: fs = top_level->clockfontset; break;
2862 XFontSet BC_WindowBase::get_curr_fontset(void)
2864 if(get_resources()->use_fontset)
2865 return curr_fontset;
2869 int BC_WindowBase::get_single_text_width(int font, const char *text, int length)
2872 if(get_resources()->use_xft && get_xft_struct(font))
2875 #ifdef X_HAVE_UTF8_STRING
2876 if(get_resources()->locale_utf8)
2878 xftTextExtentsUtf8(top_level->display,
2879 get_xft_struct(font),
2880 (const XftChar8 *)text,
2887 xftTextExtents8(top_level->display,
2888 get_xft_struct(font),
2889 (const XftChar8 *)text,
2893 return extents.xOff;
2897 if(get_resources()->use_fontset && top_level->get_fontset(font))
2898 return XmbTextEscapement(top_level->get_fontset(font), text, length);
2900 if(get_font_struct(font))
2901 return XTextWidth(get_font_struct(font), text, length);
2907 case MEDIUM_7SEGMENT:
2908 return get_resources()->medium_7segment[0]->get_w() * length;
2918 int BC_WindowBase::get_text_width(int font, const char *text, int length)
2920 int i, j, w = 0, line_w = 0;
2921 if(length < 0) length = strlen(text);
2923 for(i = 0, j = 0; i <= length; i++)
2928 line_w = get_single_text_width(font, &text[j], i - j);
2934 line_w = get_single_text_width(font, &text[j], length - j);
2936 if(line_w > w) w = line_w;
2939 if(i > length && w == 0)
2941 w = get_single_text_width(font, text, length);
2947 int BC_WindowBase::get_text_width(int font, const wchar_t *text, int length)
2950 if( length < 0 ) length = wcslen(text);
2952 for( i=j=0; i<length && text[i]; ++i ) {
2953 if( text[i] != '\n' ) continue;
2955 int lw = get_single_text_width(font, &text[j], i-j);
2956 if( w < lw ) w = lw;
2961 int lw = get_single_text_width(font, &text[j], length-j);
2962 if( w < lw ) w = lw;
2968 int BC_WindowBase::get_text_ascent(int font)
2972 if( (fstruct = get_xft_struct(font)) != 0 )
2973 return fstruct->ascent;
2975 if(get_resources()->use_fontset && top_level->get_fontset(font))
2977 XFontSetExtents *extents;
2979 extents = XExtentsOfFontSet(top_level->get_fontset(font));
2980 return -extents->max_logical_extent.y;
2983 if(get_font_struct(font))
2984 return top_level->get_font_struct(font)->ascent;
2987 case MEDIUM_7SEGMENT:
2988 return get_resources()->medium_7segment[0]->get_h();
2993 int BC_WindowBase::get_text_descent(int font)
2997 if( (fstruct = get_xft_struct(font)) != 0 )
2998 return fstruct->descent;
3000 if(get_resources()->use_fontset && top_level->get_fontset(font)) {
3001 XFontSetExtents *extents;
3002 extents = XExtentsOfFontSet(top_level->get_fontset(font));
3003 return (extents->max_logical_extent.height
3004 + extents->max_logical_extent.y);
3007 if(get_font_struct(font))
3008 return top_level->get_font_struct(font)->descent;
3013 int BC_WindowBase::get_text_height(int font, const char *text)
3018 if( (fstruct = get_xft_struct(font)) != 0 )
3019 rowh = fstruct->height;
3022 rowh = get_text_ascent(font) + get_text_descent(font);
3024 if(!text) return rowh;
3026 // Add height of lines
3027 int h = 0, i, length = strlen(text);
3028 for(i = 0; i <= length; i++)
3039 // truncate the text with ... & return a new string
3040 char *BC_WindowBase::get_truncated_text(int font, const char *text, int max_w)
3042 char *result = cstrdup(text);
3043 int text_w = get_text_width(font, text);
3044 int ci = -1, len = strlen(text);
3045 if( text_w > max_w ) {
3046 // get center of string
3047 int cx = text_w/2, best = INT_MAX;
3048 for( int i=1; i<=len; ++i ) {
3049 int cw = get_text_width(font, text, i);
3050 if( abs(cw-cx) < abs(best-cx) ) {
3055 if( ci > 0 && ci < len-1 ) {
3056 // insert ... in the center
3057 result[ci-1] = result[ci] = result[ci+1] = '.';
3059 while( ci-2>=0 && ci+2<(int)strlen(result) &&
3060 get_text_width(font, result) > max_w ) {
3061 // take away a character from the longer side
3062 int left_w = get_text_width(font, result, ci-2);
3063 int right_w = get_text_width(font, result + ci+3);
3064 int i = left_w > right_w ? --ci-1 : ci+2;
3065 while( (result[i]=result[i+1])!=0 ) ++i;
3072 BC_Bitmap* BC_WindowBase::new_bitmap(int w, int h, int color_model)
3074 if(color_model < 0) color_model = top_level->get_color_model();
3075 return new BC_Bitmap(top_level, w, h, color_model);
3078 void BC_WindowBase::init_wait()
3080 #ifndef SINGLE_THREAD
3081 if(window_type != MAIN_WINDOW)
3082 top_level->init_wait();
3083 init_lock->lock("BC_WindowBase::init_wait");
3084 init_lock->unlock();
3088 int BC_WindowBase::accel_available(int color_model, int lock_it)
3090 if( window_type != MAIN_WINDOW )
3091 return top_level->accel_available(color_model, lock_it);
3093 lock_window("BC_WindowBase::accel_available");
3095 switch(color_model) {
3097 grab_port_id(color_model);
3101 grab_port_id(color_model);
3110 //printf("BC_WindowBase::accel_available %d %d\n", color_model, xvideo_port_id);
3111 return xvideo_port_id >= 0 ? 1 : 0;
3115 int BC_WindowBase::grab_port_id(int color_model)
3117 if( !get_resources()->use_xvideo || // disabled
3118 !get_resources()->use_shm ) // Only local server is fast enough.
3120 if( xvideo_port_id >= 0 )
3121 return xvideo_port_id;
3123 unsigned int ver, rev, reqBase, eventBase, errorBase;
3124 if( Success != XvQueryExtension(display, // XV extension is available
3125 &ver, &rev, &reqBase, &eventBase, &errorBase) )
3128 // XV adaptors are available
3129 unsigned int numAdapt = 0;
3130 XvAdaptorInfo *info = 0;
3131 XvQueryAdaptors(display, DefaultRootWindow(display), &numAdapt, &info);
3135 // Translate from color_model to X color model
3136 int x_color_model = BC_CModels::bc_to_x(color_model);
3138 // Get adaptor with desired color model
3139 for( int i = 0; i < (int)numAdapt && xvideo_port_id == -1; i++) {
3140 if( !(info[i].type & XvImageMask) || !info[i].num_ports ) continue;
3141 // adaptor supports XvImages
3142 int numFormats = 0, numPorts = info[i].num_ports;
3143 XvImageFormatValues *formats =
3144 XvListImageFormats(display, info[i].base_id, &numFormats);
3145 if( !formats ) continue;
3147 for( int j=0; j<numFormats && xvideo_port_id<0; ++j ) {
3148 if( formats[j].id != x_color_model ) continue;
3149 // this adaptor supports the desired format, grab a port
3150 for( int k=0; k<numPorts; ++k ) {
3151 if( Success == XvGrabPort(top_level->display,
3152 info[i].base_id+k, CurrentTime) ) {
3153 //printf("BC_WindowBase::grab_port_id %llx\n", info[i].base_id);
3154 xvideo_port_id = info[i].base_id + k;
3162 XvFreeAdaptorInfo(info);
3164 return xvideo_port_id;
3168 int BC_WindowBase::show_window(int flush)
3170 for(int i = 0; i < subwindows->size(); i++)
3172 subwindows->get(i)->show_window(0);
3175 XMapWindow(top_level->display, win);
3176 if(flush) XFlush(top_level->display);
3177 // XSync(top_level->display, 0);
3182 int BC_WindowBase::hide_window(int flush)
3184 for(int i = 0; i < subwindows->size(); i++)
3186 subwindows->get(i)->hide_window(0);
3189 XUnmapWindow(top_level->display, win);
3190 if(flush) this->flush();
3195 BC_MenuBar* BC_WindowBase::add_menubar(BC_MenuBar *menu_bar)
3197 subwindows->append((BC_SubWindow*)menu_bar);
3199 menu_bar->parent_window = this;
3200 menu_bar->top_level = this->top_level;
3201 menu_bar->initialize();
3205 BC_WindowBase* BC_WindowBase::add_popup(BC_WindowBase *window)
3207 //printf("BC_WindowBase::add_popup window=%p win=%p\n", window, window->win);
3208 if(this != top_level) return top_level->add_popup(window);
3209 popups.append(window);
3213 void BC_WindowBase::remove_popup(BC_WindowBase *window)
3215 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3216 if(this != top_level)
3217 top_level->remove_popup(window);
3219 popups.remove(window);
3220 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3224 BC_WindowBase* BC_WindowBase::add_subwindow(BC_WindowBase *subwindow)
3226 subwindows->append(subwindow);
3228 if(subwindow->bg_color == -1) subwindow->bg_color = this->bg_color;
3230 // parent window must be set before the subwindow initialization
3231 subwindow->parent_window = this;
3232 subwindow->top_level = this->top_level;
3234 // Execute derived initialization
3235 subwindow->initialize();
3240 BC_WindowBase* BC_WindowBase::add_tool(BC_WindowBase *subwindow)
3242 return add_subwindow(subwindow);
3245 int BC_WindowBase::flash(int x, int y, int w, int h, int flush)
3247 if( !top_level->flash_enabled ) return 0;
3248 //printf("BC_WindowBase::flash %d %d %d %d %d\n", __LINE__, w, h, this->w, this->h);
3250 XSetWindowBackgroundPixmap(top_level->display, win, pixmap->opaque_pixmap);
3253 XClearArea(top_level->display, win, x, y, w, h, 0);
3257 XClearWindow(top_level->display, win);
3265 int BC_WindowBase::flash(int flush)
3267 flash(-1, -1, -1, -1, flush);
3271 void BC_WindowBase::flush()
3273 //if(!get_window_lock())
3274 // printf("BC_WindowBase::flush %s not locked\n", top_level->title);
3275 // X gets hosed if Flush/Sync are not user locked (at libX11-1.1.5 / libxcb-1.1.91)
3276 // _XReply deadlocks in condition_wait waiting for xlib lock when waiters!=-1
3277 int locked = get_window_lock();
3278 if( !locked ) lock_window("BC_WindowBase::flush");
3279 XFlush(top_level->display);
3280 if( !locked ) unlock_window();
3283 void BC_WindowBase::sync_display()
3285 int locked = get_window_lock();
3286 if( !locked ) lock_window("BC_WindowBase::sync_display");
3287 XSync(top_level->display, False);
3288 if( !locked ) unlock_window();
3291 int BC_WindowBase::get_window_lock()
3293 #ifdef SINGLE_THREAD
3294 return BC_Display::display_global->get_display_locked();
3296 return top_level->window_lock;
3300 int BC_WindowBase::lock_window(const char *location)
3302 if(top_level && top_level != this)
3304 top_level->lock_window(location);
3309 SET_LOCK(this, title, location);
3310 #ifdef SINGLE_THREAD
3311 BC_Display::lock_display(location);
3313 XLockDisplay(top_level->display);
3314 top_level->display_lock_owner = pthread_self();
3317 ++top_level->window_lock;
3321 printf("BC_WindowBase::lock_window top_level NULL\n");
3326 int BC_WindowBase::unlock_window()
3328 if(top_level && top_level != this)
3330 top_level->unlock_window();
3336 if( !top_level->window_lock ) {
3337 printf("BC_WindowBase::unlock_window %s not locked\n", title);
3340 if( top_level->window_lock > 0 )
3341 if( --top_level->window_lock == 0 )
3342 top_level->display_lock_owner = 0;
3343 #ifdef SINGLE_THREAD
3344 BC_Display::unlock_display();
3346 XUnlockDisplay(top_level->display);
3351 printf("BC_WindowBase::unlock_window top_level NULL\n");
3356 int BC_WindowBase::break_lock()
3358 if( !top_level ) return 0;
3359 if( top_level != this ) return top_level->break_lock();
3360 if( top_level->display_lock_owner != pthread_self() ) return 0;
3361 if( top_level->window_lock != 1 ) return 0;
3364 display_lock_owner = 0;
3365 #ifdef SINGLE_THREAD
3366 BC_Display::unlock_display();
3368 XUnlockDisplay(display);
3373 void BC_WindowBase::set_done(int return_value)
3375 if(done_set) return;
3377 if(window_type != MAIN_WINDOW)
3378 top_level->set_done(return_value);
3381 #ifdef SINGLE_THREAD
3382 this->return_value = return_value;
3383 BC_Display::display_global->arm_completion(this);
3384 completion_lock->unlock();
3385 #else // SINGLE_THREAD
3387 if( !event_thread ) return;
3388 XEvent *event = new_xevent();
3389 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
3390 event->type = ClientMessage;
3391 ptr->message_type = SetDoneXAtom;
3393 this->return_value = return_value;
3394 // May lock up here because XSendEvent doesn't work too well
3395 // asynchronous with XNextEvent.
3396 // This causes BC_WindowEvents to forward a copy of the event to run_window where
3398 // Deletion of event_thread is done at the end of BC_WindowBase::run_window() - by calling the destructor
3404 void BC_WindowBase::close(int return_value)
3406 hide_window(); flush();
3407 set_done(return_value);
3410 int BC_WindowBase::grab(BC_WindowBase *window)
3412 if( window->active_grab && this != window->active_grab ) return 0;
3413 window->active_grab = this;
3414 this->grab_active = window;
3417 int BC_WindowBase::ungrab(BC_WindowBase *window)
3419 if( window->active_grab && this != window->active_grab ) return 0;
3420 window->active_grab = 0;
3421 this->grab_active = 0;
3424 int BC_WindowBase::grab_event_count()
3427 #ifndef SINGLE_THREAD
3428 result = grab_active->get_event_count();
3432 int BC_WindowBase::grab_buttons()
3434 XSync(top_level->display, False);
3435 if( XGrabButton(top_level->display, AnyButton, AnyModifier,
3436 top_level->rootwin, True, ButtonPressMask | ButtonReleaseMask,
3437 GrabModeAsync, GrabModeSync, None, None) == GrabSuccess ) {
3438 set_active_subwindow(this);
3443 void BC_WindowBase::ungrab_buttons()
3445 XUngrabButton(top_level->display, AnyButton, AnyModifier, top_level->rootwin);
3446 set_active_subwindow(0);
3449 void BC_WindowBase::grab_cursor()
3451 Cursor cursor_grab = get_cursor_struct(GRABBED_CURSOR);
3452 XGrabPointer(top_level->display, top_level->rootwin, True,
3453 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
3454 GrabModeAsync, GrabModeAsync, None, cursor_grab, CurrentTime);
3456 void BC_WindowBase::ungrab_cursor()
3458 XUngrabPointer(top_level->display, CurrentTime);
3462 // WidthOfScreen/HeightOfScreen of XDefaultScreenOfDisplay
3463 // this is the bounding box of all the screens
3465 int BC_WindowBase::get_root_w(int lock_display)
3467 if(lock_display) lock_window("BC_WindowBase::get_root_w");
3468 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3469 int result = WidthOfScreen(def_screen);
3470 if(lock_display) unlock_window();
3474 int BC_WindowBase::get_root_h(int lock_display)
3476 if(lock_display) lock_window("BC_WindowBase::get_root_h");
3477 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3478 int result = HeightOfScreen(def_screen);
3479 if(lock_display) unlock_window();
3483 XineramaScreenInfo *
3484 BC_WindowBase::get_xinerama_info(int screen)
3486 if( !xinerama_info || !xinerama_screens ) return 0;
3488 for( int i=0; i<xinerama_screens; ++i )
3489 if( xinerama_info[i].screen_number == screen )
3490 return &xinerama_info[i];
3493 int top_x = get_x(), top_y = get_y();
3494 if( BC_DisplayInfo::left_border >= 0 ) top_x += BC_DisplayInfo::left_border;
3495 if( BC_DisplayInfo::top_border >= 0 ) top_y += BC_DisplayInfo::top_border;
3496 for( int i=0; i<xinerama_screens; ++i ) {
3497 int scr_y = top_y - xinerama_info[i].y_org;
3498 if( scr_y < 0 || scr_y >= xinerama_info[i].height ) continue;
3499 int scr_x = top_x - xinerama_info[i].x_org;
3500 if( scr_x >= 0 && scr_x < xinerama_info[i].width )
3501 return &xinerama_info[i];
3506 void BC_WindowBase::get_fullscreen_geometry(int &wx, int &wy, int &ww, int &wh)
3508 XineramaScreenInfo *info = top_level->get_xinerama_info(-1);
3510 wx = info->x_org; wy = info->y_org;
3511 ww = info->width; wh = info->height;
3514 wx = get_screen_x(0, -1);
3515 wy = get_screen_y(0, -1);
3516 int scr_w0 = get_screen_w(0, 0);
3517 int root_w = get_root_w(0);
3518 int root_h = get_root_h(0);
3519 if( root_w > scr_w0 ) { // multi-headed
3520 if( wx >= scr_w0 ) {
3521 // assumes right side is the big one
3522 ww = root_w - scr_w0;
3526 // use same aspect ratio to compute left height
3528 wh = (w*root_h) / (root_w-scr_w0);
3538 int BC_WindowBase::get_screen_x(int lock_display, int screen)
3541 if(lock_display) lock_window("BC_WindowBase::get_screen_x");
3542 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3545 int root_w = get_root_w(0);
3546 int root_h = get_root_h(0);
3547 // Shift X based on position of current window if dual head
3548 if( (float)root_w/root_h > 1.8 ) {
3549 root_w = get_screen_w(0, 0);
3550 if( top_level->get_x() >= root_w )
3555 result = info->x_org;
3556 if(lock_display) unlock_window();
3560 int BC_WindowBase::get_screen_y(int lock_display, int screen)
3562 if(lock_display) lock_window("BC_WindowBase::get_screen_y");
3563 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3564 int result = !info ? 0 : info->y_org;
3565 if(lock_display) unlock_window();
3569 int BC_WindowBase::get_screen_w(int lock_display, int screen)
3572 if(lock_display) lock_window("BC_WindowBase::get_screen_w");
3573 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3575 int width = get_root_w(0);
3576 int height = get_root_h(0);
3577 if( (float)width/height > 1.8 ) {
3578 // If dual head, the screen width is > 16x9
3579 // but we only want to fill one screen
3580 // this code assumes the "big" screen is on the right
3581 int scr_w0 = width / 2;
3583 case 600: scr_w0 = 800; break;
3584 case 720: scr_w0 = 1280; break;
3585 case 1024: scr_w0 = 1280; break;
3586 case 1200: scr_w0 = 1600; break;
3587 case 1080: scr_w0 = 1920; break;
3589 int scr_w1 = width - scr_w0;
3590 result = screen > 0 ? scr_w1 :
3591 screen == 0 ? scr_w0 :
3592 top_level->get_x() < scr_w0 ? scr_w0 : scr_w1;
3598 result = info->width;
3599 if(lock_display) unlock_window();
3603 int BC_WindowBase::get_screen_h(int lock_display, int screen)
3605 if(lock_display) lock_window("BC_WindowBase::get_screen_h");
3606 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3607 int result = info ? info->height : get_root_h(0);
3608 if(lock_display) unlock_window();
3612 // Bottom right corner
3613 int BC_WindowBase::get_x2()
3618 int BC_WindowBase::get_y2()
3623 int BC_WindowBase::get_video_on()
3628 int BC_WindowBase::get_hidden()
3630 return top_level->hidden;
3633 int BC_WindowBase::cursor_inside()
3635 return (top_level->cursor_x >= 0 &&
3636 top_level->cursor_y >= 0 &&
3637 top_level->cursor_x < w &&
3638 top_level->cursor_y < h);
3641 BC_WindowBase* BC_WindowBase::get_top_level()
3646 BC_WindowBase* BC_WindowBase::get_parent()
3648 return parent_window;
3651 int BC_WindowBase::get_color_model()
3653 return top_level->color_model;
3656 BC_Resources* BC_WindowBase::get_resources()
3658 return BC_WindowBase::resources;
3661 BC_Synchronous* BC_WindowBase::get_synchronous()
3663 return BC_WindowBase::resources->get_synchronous();
3666 int BC_WindowBase::get_bg_color()
3671 void BC_WindowBase::set_bg_color(int color)
3673 this->bg_color = color;
3676 BC_Pixmap* BC_WindowBase::get_bg_pixmap()
3681 void BC_WindowBase::set_active_subwindow(BC_WindowBase *subwindow)
3683 top_level->active_subwindow = subwindow;
3686 int BC_WindowBase::activate()
3691 int BC_WindowBase::deactivate()
3693 if(window_type == MAIN_WINDOW)
3695 if( top_level->active_menubar ) {
3696 top_level->active_menubar->deactivate();
3697 top_level->active_menubar = 0;
3699 if( top_level->active_popup_menu ) {
3700 top_level->active_popup_menu->deactivate();
3701 top_level->active_popup_menu = 0;
3703 if( top_level->active_subwindow ) {
3704 top_level->active_subwindow->deactivate();
3705 top_level->active_subwindow = 0;
3707 if( top_level->motion_events && top_level->last_motion_win == this->win )
3708 top_level->motion_events = 0;
3714 int BC_WindowBase::cycle_textboxes(int amount)
3717 BC_WindowBase *new_textbox = 0;
3721 BC_WindowBase *first_textbox = 0;
3722 find_next_textbox(&first_textbox, &new_textbox, result);
3723 if(!new_textbox) new_textbox = first_textbox;
3729 BC_WindowBase *last_textbox = 0;
3730 find_prev_textbox(&last_textbox, &new_textbox, result);
3731 if(!new_textbox) new_textbox = last_textbox;
3735 if(new_textbox != active_subwindow)
3738 new_textbox->activate();
3744 int BC_WindowBase::find_next_textbox(BC_WindowBase **first_textbox, BC_WindowBase **next_textbox, int &result)
3746 // Search subwindows for textbox
3747 for(int i = 0; i < subwindows->total && result < 2; i++)
3749 BC_WindowBase *test_subwindow = subwindows->values[i];
3750 test_subwindow->find_next_textbox(first_textbox, next_textbox, result);
3757 if(!*first_textbox) *first_textbox = this;
3761 if(top_level->active_subwindow == this)
3767 *next_textbox = this;
3774 int BC_WindowBase::find_prev_textbox(BC_WindowBase **last_textbox, BC_WindowBase **prev_textbox, int &result)
3780 if(!*last_textbox) *last_textbox = this;
3784 if(top_level->active_subwindow == this)
3790 *prev_textbox = this;
3795 // Search subwindows for textbox
3796 for(int i = subwindows->total - 1; i >= 0 && result < 2; i--)
3798 BC_WindowBase *test_subwindow = subwindows->values[i];
3799 test_subwindow->find_prev_textbox(last_textbox, prev_textbox, result);
3804 BC_Clipboard* BC_WindowBase::get_clipboard()
3806 #ifdef SINGLE_THREAD
3807 return BC_Display::display_global->clipboard;
3809 return top_level->clipboard;
3813 Atom BC_WindowBase::to_clipboard(const char *data, long len, int clipboard_num)
3815 return get_clipboard()->to_clipboard(this, data, len, clipboard_num);
3818 long BC_WindowBase::from_clipboard(char *data, long maxlen, int clipboard_num)
3820 return get_clipboard()->from_clipboard(data, maxlen, clipboard_num);
3823 long BC_WindowBase::clipboard_len(int clipboard_num)
3825 return get_clipboard()->clipboard_len(clipboard_num);
3828 int BC_WindowBase::do_selection_clear(Window win)
3830 top_level->event_win = win;
3831 return dispatch_selection_clear();
3834 int BC_WindowBase::dispatch_selection_clear()
3837 for( int i=0; i<subwindows->total && !result; ++i )
3838 result = subwindows->values[i]->dispatch_selection_clear();
3840 result = selection_clear_event();
3845 void BC_WindowBase::get_relative_cursor(int &x, int &y, int lock_window)
3847 int abs_x, abs_y, win_x, win_y;
3848 unsigned int temp_mask;
3851 if(lock_window) this->lock_window("BC_WindowBase::get_relative_cursor");
3852 XQueryPointer(top_level->display, top_level->win,
3853 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3856 XTranslateCoordinates(top_level->display, top_level->rootwin,
3857 win, abs_x, abs_y, &x, &y, &temp_win);
3858 if(lock_window) this->unlock_window();
3860 int BC_WindowBase::get_relative_cursor_x(int lock_window)
3863 get_relative_cursor(x, y, lock_window);
3866 int BC_WindowBase::get_relative_cursor_y(int lock_window)
3869 get_relative_cursor(x, y, lock_window);
3873 void BC_WindowBase::get_abs_cursor(int &abs_x, int &abs_y, int lock_window)
3876 unsigned int temp_mask;
3879 if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor");
3880 XQueryPointer(top_level->display, top_level->win,
3881 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3883 if(lock_window) this->unlock_window();
3885 int BC_WindowBase::get_abs_cursor_x(int lock_window)
3888 get_abs_cursor(abs_x, abs_y, lock_window);
3891 int BC_WindowBase::get_abs_cursor_y(int lock_window)
3894 get_abs_cursor(abs_x, abs_y, lock_window);
3898 void BC_WindowBase::get_pop_cursor(int &px, int &py, int lock_window)
3900 int xmargin = xS(100), ymargin = yS(100);
3901 get_abs_cursor(px, py, lock_window);
3902 if( px < xmargin ) px = xmargin;
3903 if( py < ymargin ) py = ymargin;
3904 int wd = get_screen_w(lock_window,-1) - xmargin;
3905 if( px > wd ) px = wd;
3906 int ht = get_screen_h(lock_window,-1) - ymargin;
3907 if( py > ht ) py = ht;
3909 int BC_WindowBase::get_pop_cursor_x(int lock_window)
3912 get_pop_cursor(px, py, lock_window);
3915 int BC_WindowBase::get_pop_cursor_y(int lock_window)
3918 get_pop_cursor(px, py, lock_window);
3922 int BC_WindowBase::match_window(Window win)
3924 if (this->win == win) return 1;
3926 for(int i = 0; i < subwindows->total; i++) {
3927 result = subwindows->values[i]->match_window(win);
3928 if (result) return result;
3934 int BC_WindowBase::get_cursor_over_window()
3936 int abs_x, abs_y, win_x, win_y;
3937 unsigned int mask_return;
3938 Window root_return, child_return;
3940 int ret = XQueryPointer(top_level->display, top_level->rootwin,
3941 &root_return, &child_return, &abs_x, &abs_y,
3942 &win_x, &win_y, &mask_return);
3943 if( ret && child_return == None ) ret = 0;
3944 if( ret && win != child_return )
3945 ret = top_level->match_window(child_return);
3946 // query pointer can return a window manager window with this top_level as a child
3947 // for kde this can be two levels deep
3948 unsigned int nchildren_return = 0;
3949 Window parent_return, *children_return = 0;
3950 Window top_win = top_level->win;
3951 while( !ret && top_win != top_level->rootwin && top_win != root_return &&
3952 XQueryTree(top_level->display, top_win, &root_return,
3953 &parent_return, &children_return, &nchildren_return) ) {
3954 if( children_return ) XFree(children_return);
3955 if( (top_win=parent_return) == child_return ) ret = 1;
3960 int BC_WindowBase::cursor_above()
3963 get_relative_cursor(rx, ry);
3964 return rx < 0 || rx >= get_w() ||
3965 ry < 0 || ry >= get_h() ? 0 : 1;
3968 int BC_WindowBase::get_drag_x()
3970 return top_level->drag_x;
3973 int BC_WindowBase::get_drag_y()
3975 return top_level->drag_y;
3978 int BC_WindowBase::get_cursor_x()
3980 return top_level->cursor_x;
3983 int BC_WindowBase::get_cursor_y()
3985 return top_level->cursor_y;
3988 int BC_WindowBase::dump_windows()
3990 printf("\tBC_WindowBase::dump_windows window=%p win=%p '%s', %dx%d+%d+%d %s\n",
3991 this, (void*)this->win, title, w,h,x,y, typeid(*this).name());
3992 for(int i = 0; i < subwindows->size(); i++)
3993 subwindows->get(i)->dump_windows();
3994 for(int i = 0; i < popups.size(); i++) {
3995 BC_WindowBase *p = popups[i];
3996 printf("\tBC_WindowBase::dump_windows popup=%p win=%p '%s', %dx%d+%d+%d %s\n",
3997 p, (void*)p->win, p->title, p->w,p->h,p->x,p->y, typeid(*p).name());
4002 int BC_WindowBase::is_event_win()
4004 return this->win == top_level->event_win;
4007 void BC_WindowBase::set_dragging(int value)
4009 is_dragging = value;
4012 int BC_WindowBase::get_dragging()
4017 int BC_WindowBase::get_buttonpress()
4019 return top_level->button_number;
4022 int BC_WindowBase::get_button_down()
4024 return top_level->button_down;
4027 int BC_WindowBase::alt_down()
4029 return top_level->alt_mask;
4032 int BC_WindowBase::shift_down()
4034 return top_level->shift_mask;
4037 int BC_WindowBase::ctrl_down()
4039 return top_level->ctrl_mask;
4042 wchar_t* BC_WindowBase::get_wkeystring(int *length)
4045 *length = top_level->wkey_string_length;
4046 return top_level->wkey_string;
4049 #ifdef X_HAVE_UTF8_STRING
4050 char* BC_WindowBase::get_keypress_utf8()
4052 return top_level->key_pressed_utf8;
4057 int BC_WindowBase::get_keypress()
4059 return top_level->key_pressed;
4062 int BC_WindowBase::get_double_click()
4064 return top_level->double_click;
4067 int BC_WindowBase::get_triple_click()
4069 return top_level->triple_click;
4072 int BC_WindowBase::get_bgcolor()
4077 int BC_WindowBase::resize_window(int w, int h)
4079 if(this->w == w && this->h == h) return 0;
4081 if(window_type == MAIN_WINDOW && !allow_resize)
4083 XSizeHints size_hints;
4084 size_hints.flags = PSize | PMinSize | PMaxSize;
4085 size_hints.width = w;
4086 size_hints.height = h;
4087 size_hints.min_width = w;
4088 size_hints.max_width = w;
4089 size_hints.min_height = h;
4090 size_hints.max_height = h;
4091 if( this->x > -BC_INFINITY && this->x < BC_INFINITY ) {
4092 size_hints.flags |= PPosition;
4093 size_hints.x = this->x;
4094 size_hints.y = this->y;
4096 XSetNormalHints(top_level->display, win, &size_hints);
4098 XResizeWindow(top_level->display, win, w, h);
4103 pixmap = new BC_Pixmap(this, w, h);
4105 // Propagate to menubar
4106 for(int i = 0; i < subwindows->total; i++)
4108 subwindows->values[i]->dispatch_resize_event(w, h);
4111 draw_background(0, 0, w, h);
4112 if(top_level == this && get_resources()->recursive_resizing)
4113 resize_history.append(new BC_ResizeCall(w, h));
4117 // The only way for resize events to be propagated is by updating the internal w and h
4118 int BC_WindowBase::resize_event(int w, int h)
4120 if(window_type == MAIN_WINDOW)
4128 int BC_WindowBase::reposition_window(int x, int y)
4130 reposition_window(x, y, -1, -1);
4135 int BC_WindowBase::reposition_window(int x, int y, int w, int h)
4139 // Some tools set their own dimensions before calling this, causing the
4140 // resize check to skip.
4144 if(w > 0 && w != this->w)
4150 if(h > 0 && h != this->h)
4156 //printf("BC_WindowBase::reposition_window %d %d %d\n", translation_count, x_correction, y_correction);
4159 printf("BC_WindowBase::reposition_window this->w == %d\n", this->w);
4161 printf("BC_WindowBase::reposition_window this->h == %d\n", this->h);
4163 if(translation_count && window_type == MAIN_WINDOW)
4165 // KDE shifts window right and down.
4166 // FVWM leaves window alone and adds border around it.
4167 XMoveResizeWindow(top_level->display, win,
4168 x - BC_DisplayInfo::auto_reposition_x,
4169 y - BC_DisplayInfo::auto_reposition_y,
4174 XMoveResizeWindow(top_level->display, win, x, y,
4181 pixmap = new BC_Pixmap(this, this->w, this->h);
4182 clear_box(0,0, this->w, this->h);
4183 // Propagate to menubar
4184 for(int i = 0; i < subwindows->total; i++)
4186 subwindows->values[i]->dispatch_resize_event(this->w, this->h);
4189 // draw_background(0, 0, w, h);
4195 int BC_WindowBase::reposition_window_relative(int dx, int dy, int w, int h)
4197 return reposition_window(get_x()+dx, get_y()+dy, w, h);
4200 int BC_WindowBase::reposition_window_relative(int dx, int dy)
4202 return reposition_window_relative(dx, dy, -1, -1);
4205 void BC_WindowBase::set_tooltips(int v)
4207 get_resources()->tooltips_enabled = v;
4210 void BC_WindowBase::set_force_tooltip(int v)
4215 int BC_WindowBase::raise_window(int do_flush)
4217 XRaiseWindow(top_level->display, win);
4218 if(do_flush) XFlush(top_level->display);
4222 int BC_WindowBase::lower_window(int do_flush)
4224 XLowerWindow(top_level->display, win);
4225 if(do_flush) XFlush(top_level->display);
4229 void BC_WindowBase::set_background(VFrame *bitmap)
4231 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
4233 bg_pixmap = new BC_Pixmap(this, bitmap, PIXMAP_OPAQUE);
4234 shared_bg_pixmap = 0;
4235 draw_background(0, 0, w, h);
4238 void BC_WindowBase::put_title(const char *text)
4240 char *cp = this->title, *ep = cp+sizeof(this->title)-1;
4241 for( const unsigned char *bp = (const unsigned char *)text; *bp && cp<ep; ++bp )
4242 *cp++ = *bp >= ' ' ? *bp : ' ';
4246 void BC_WindowBase::set_title(const char *text, int utf8)
4248 // utf8>0: wm + net_wm, utf8=0: wm only, utf<0: net_wm only
4250 const unsigned char *wm_title = (const unsigned char *)title;
4251 int title_len = strlen((const char *)title);
4253 Atom xa_wm_name = XA_WM_NAME;
4254 Atom xa_icon_name = XA_WM_ICON_NAME;
4255 Atom xa_string = XA_STRING;
4256 XChangeProperty(display, win, xa_wm_name, xa_string, 8,
4257 PropModeReplace, wm_title, title_len);
4258 XChangeProperty(display, win, xa_icon_name, xa_string, 8,
4259 PropModeReplace, wm_title, title_len);
4262 Atom xa_net_wm_name = XInternAtom(display, "_NET_WM_NAME", True);
4263 Atom xa_net_icon_name = XInternAtom(display, "_NET_WM_ICON_NAME", True);
4264 Atom xa_utf8_string = XInternAtom(display, "UTF8_STRING", True);
4265 XChangeProperty(display, win, xa_net_wm_name, xa_utf8_string, 8,
4266 PropModeReplace, wm_title, title_len);
4267 XChangeProperty(display, win, xa_net_icon_name, xa_utf8_string, 8,
4268 PropModeReplace, wm_title, title_len);
4274 void BC_WindowBase::set_net_icon(VFrame *data)
4276 int width = data->get_w(), height = data->get_h();
4277 int size = 2 + width * height;
4278 unsigned long *icon_data = new unsigned long[size];
4279 unsigned long *lp = icon_data;
4280 *lp++ = width; *lp++ = height;
4281 uint8_t **rows = data->get_rows();
4282 for( int y=0; y<height; ++y ) {
4283 unsigned *up = (unsigned *)rows[y];
4284 for( int x=0; x<width; ++x )
4285 *lp++ = *(unsigned *)up++;
4287 Atom NetWMIcon = XInternAtom(display, "_NET_WM_ICON", True);
4288 XChangeProperty(top_level->display, top_level->win, NetWMIcon,
4289 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)icon_data, size);
4290 delete [] icon_data;
4293 const char *BC_WindowBase::get_title()
4298 int BC_WindowBase::get_toggle_value()
4300 return toggle_value;
4303 int BC_WindowBase::get_toggle_drag()
4308 int BC_WindowBase::set_icon(VFrame *data)
4310 if(icon_pixmap) delete icon_pixmap;
4311 icon_pixmap = new BC_Pixmap(top_level, data, PIXMAP_ALPHA, 1);
4313 if(icon_window) delete icon_window;
4314 icon_window = new BC_Popup(this, 0, 0,
4315 icon_pixmap->get_w(), icon_pixmap->get_h(),
4316 -1, 1, // All windows are hidden initially
4319 XWMHints wm_hints; memset(&wm_hints, 0, sizeof(wm_hints));
4320 wm_hints.flags = IconPixmapHint; // | IconMaskHint | IconWindowHint;
4321 wm_hints.icon_pixmap = icon_pixmap->get_pixmap();
4322 wm_hints.icon_mask = icon_pixmap->get_alpha();
4323 wm_hints.icon_window = icon_window->win;
4324 if( XGroupLeader ) {
4325 wm_hints.flags |= WindowGroupHint;
4326 wm_hints.window_group = XGroupLeader;
4329 // for(int i = 0; i < 1000; i++)
4330 // printf("02x ", icon_pixmap->get_alpha()->get_row_pointers()[0][i]);
4333 XSetWMHints(top_level->display, top_level->win, &wm_hints);
4336 XSync(top_level->display, 0);
4340 void BC_WindowBase::init_resources(float scale)
4342 if( resources ) return;
4344 const char *env = getenv("BC_SCALE");
4345 if( env ) scale = atof(env);
4346 float x_scale = 1, y_scale = 1;
4348 BC_DisplayInfo info;
4350 int cins = info.xinerama_big_screen();
4351 if( !info.xinerama_geometry(cins, wx, wy, ww, wh) ) {
4352 if( (x_scale = ww/1920.) < 1 ) x_scale = 1;
4353 if( (y_scale = wh/1080.) < 1 ) y_scale = 1;
4357 x_scale = y_scale = scale;
4358 // constructor sets BC_WindowBase::resources
4359 new BC_Resources(x_scale, y_scale);
4361 void BC_WindowBase::finit_resources()
4363 delete resources; resources = 0;
4366 int BC_WindowBase::set_w(int w)
4372 int BC_WindowBase::set_h(int h)
4378 int BC_WindowBase::load_defaults(BC_Hash *defaults)
4380 char string[BCTEXTLEN];
4381 int newest_id = - 1;
4382 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4384 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4385 resources->filebox_history[i].path[0] = 0;
4386 defaults->get(string, resources->filebox_history[i].path);
4387 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4388 resources->filebox_history[i].id = defaults->get(string, resources->get_id());
4389 if(resources->filebox_history[i].id > newest_id)
4390 newest_id = resources->filebox_history[i].id;
4393 resources->filebox_id = newest_id + 1;
4394 resources->filebox_mode = defaults->get("FILEBOX_MODE", get_resources()->filebox_mode);
4395 resources->filebox_w = defaults->get("FILEBOX_W", get_resources()->filebox_w);
4396 resources->filebox_h = defaults->get("FILEBOX_H", get_resources()->filebox_h);
4397 resources->filebox_columntype[0] = defaults->get("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4398 resources->filebox_columntype[1] = defaults->get("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4399 resources->filebox_columntype[2] = defaults->get("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4400 resources->filebox_columntype[3] = defaults->get("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4401 resources->filebox_columnwidth[0] = defaults->get("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4402 resources->filebox_columnwidth[1] = defaults->get("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4403 resources->filebox_columnwidth[2] = defaults->get("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4404 resources->filebox_columnwidth[3] = defaults->get("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4405 resources->filebox_size_format = defaults->get("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4406 defaults->get("FILEBOX_FILTER", resources->filebox_filter);
4410 int BC_WindowBase::save_defaults(BC_Hash *defaults)
4412 char string[BCTEXTLEN];
4413 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4415 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4416 defaults->update(string, resources->filebox_history[i].path);
4417 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4418 defaults->update(string, resources->filebox_history[i].id);
4420 defaults->update("FILEBOX_MODE", resources->filebox_mode);
4421 defaults->update("FILEBOX_W", resources->filebox_w);
4422 defaults->update("FILEBOX_H", resources->filebox_h);
4423 defaults->update("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4424 defaults->update("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4425 defaults->update("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4426 defaults->update("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4427 defaults->update("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4428 defaults->update("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4429 defaults->update("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4430 defaults->update("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4431 defaults->update("FILEBOX_FILTER", resources->filebox_filter);
4432 defaults->update("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4438 // For some reason XTranslateCoordinates can take a long time to return.
4439 // We work around this by only calling it when the event windows are different.
4440 void BC_WindowBase::translate_coordinates(Window src_w, Window dest_w,
4441 int src_x, int src_y, int *dest_x_return, int *dest_y_return)
4448 *dest_x_return = src_x;
4449 *dest_y_return = src_y;
4453 XTranslateCoordinates(top_level->display, src_w, dest_w,
4454 src_x, src_y, dest_x_return, dest_y_return, &tempwin);
4455 //printf("BC_WindowBase::translate_coordinates 1 %lld\n", timer.get_difference());
4459 void BC_WindowBase::get_root_coordinates(int x, int y, int *abs_x, int *abs_y)
4461 translate_coordinates(win, top_level->rootwin, x, y, abs_x, abs_y);
4464 void BC_WindowBase::get_win_coordinates(int abs_x, int abs_y, int *x, int *y)
4466 translate_coordinates(top_level->rootwin, win, abs_x, abs_y, x, y);
4470 #ifdef HAVE_LIBXXF86VM
4471 void BC_WindowBase::closest_vm(int *vm, int *width, int *height)
4475 if(XF86VidModeQueryExtension(top_level->display,&foo,&bar)) {
4477 XF86VidModeModeInfo **vm_modelines;
4478 XF86VidModeGetAllModeLines(top_level->display,
4479 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4480 for( i = 0; i < vm_count; i++ ) {
4481 if( vm_modelines[i]->hdisplay < vm_modelines[*vm]->hdisplay &&
4482 vm_modelines[i]->hdisplay >= *width )
4485 display = top_level->display;
4486 if( vm_modelines[*vm]->hdisplay == *width )
4489 *width = vm_modelines[*vm]->hdisplay;
4490 *height = vm_modelines[*vm]->vdisplay;
4495 void BC_WindowBase::scale_vm(int vm)
4497 int foo,bar,dotclock;
4498 if( XF86VidModeQueryExtension(top_level->display,&foo,&bar) ) {
4500 XF86VidModeModeInfo **vm_modelines;
4501 XF86VidModeModeLine vml;
4502 XF86VidModeGetAllModeLines(top_level->display,
4503 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4504 XF86VidModeGetModeLine(top_level->display,
4505 XDefaultScreen(top_level->display), &dotclock,&vml);
4506 orig_modeline.dotclock = dotclock;
4507 orig_modeline.hdisplay = vml.hdisplay;
4508 orig_modeline.hsyncstart = vml.hsyncstart;
4509 orig_modeline.hsyncend = vml.hsyncend;
4510 orig_modeline.htotal = vml.htotal;
4511 orig_modeline.vdisplay = vml.vdisplay;
4512 orig_modeline.vsyncstart = vml.vsyncstart;
4513 orig_modeline.vsyncend = vml.vsyncend;
4514 orig_modeline.vtotal = vml.vtotal;
4515 orig_modeline.flags = vml.flags;
4516 orig_modeline.privsize = vml.privsize;
4517 // orig_modeline.private = vml.private;
4518 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),vm_modelines[vm]);
4519 XF86VidModeSetViewPort(top_level->display,XDefaultScreen(top_level->display),0,0);
4520 XFlush(top_level->display);
4524 void BC_WindowBase::restore_vm()
4526 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),&orig_modeline);
4527 XFlush(top_level->display);
4532 #ifndef SINGLE_THREAD
4533 int BC_WindowBase::get_event_count()
4535 event_lock->lock("BC_WindowBase::get_event_count");
4536 int result = common_events.total;
4537 event_lock->unlock();
4541 XEvent* BC_WindowBase::get_event()
4544 while(!done && !result)
4546 event_condition->lock("BC_WindowBase::get_event");
4547 event_lock->lock("BC_WindowBase::get_event");
4549 if(common_events.total && !done)
4551 result = common_events.values[0];
4552 common_events.remove_number(0);
4555 event_lock->unlock();
4560 void BC_WindowBase::put_event(XEvent *event)
4562 event_lock->lock("BC_WindowBase::put_event");
4563 common_events.append(event);
4564 event_lock->unlock();
4565 event_condition->unlock();
4568 void BC_WindowBase::dequeue_events(Window win)
4570 event_lock->lock("BC_WindowBase::dequeue_events");
4572 int out = 0, total = common_events.size();
4573 for( int in=0; in<total; ++in ) {
4574 if( common_events[in]->xany.window == win ) continue;
4575 common_events[out++] = common_events[in];
4577 common_events.total = out;
4579 event_lock->unlock();
4582 int BC_WindowBase::resend_event(BC_WindowBase *window)
4584 if( resend_event_window ) return 1;
4585 resend_event_window = window;
4591 int BC_WindowBase::resend_event(BC_WindowBase *window)
4596 #endif // SINGLE_THREAD
4598 int BC_WindowBase::get_id()
4604 BC_Pixmap *BC_WindowBase::create_pixmap(VFrame *vframe)
4606 int w = vframe->get_w(), h = vframe->get_h();
4607 BC_Pixmap *icon = new BC_Pixmap(this, w, h);
4608 icon->draw_vframe(vframe, 0,0, w,h, 0,0);
4613 void BC_WindowBase::flicker(int n, int ms)
4615 int color = get_bg_color();
4616 for( int i=2*n; --i>=0; ) {
4617 set_inverse(); set_bg_color(WHITE);
4618 clear_box(0,0, w,h); flash(1);
4619 sync_display(); Timer::delay(ms);
4621 set_bg_color(color);
4625 void BC_WindowBase::focus()
4627 XWindowAttributes xwa;
4628 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4629 if( xwa.map_state == IsViewable )
4630 XSetInputFocus(top_level->display, top_level->win, RevertToParent, CurrentTime);