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 */
1267 // above case XK_KP_Enter: key_pressed = KPENTER; break; /* check */
1268 case XF86XK_MenuKB: key_pressed = KPMENU; break; /* menu */
1269 // intercepted case XF86XK_PowerDown: key_pressed = KPPOWER; break; /* Power */
1270 case XF86XK_Launch1: key_pressed = KPTV; break; /* TV */
1271 case XF86XK_Launch2: key_pressed = KPDVD; break; /* DVD */
1272 // intercepted case XF86XK_WWW: key_pressed = KPWWEB; break; /* WEB */
1273 case XF86XK_Launch3: key_pressed = KPBOOK; break; /* book */
1274 case XF86XK_Launch4: key_pressed = KPHAND; break; /* hand */
1275 case XF86XK_Reply: key_pressed = KPTMR; break; /* timer */
1276 case SunXK_Front: key_pressed = KPMAXW; break; /* max */
1277 // above case XK_Left: key_pressed = LEFT; break; /* left */
1278 // above case XK_Right: key_pressed = RIGHT; break; /* right */
1279 // above case XK_Down: key_pressed = DOWN; break; /* down */
1280 // above case XK_Up: key_pressed = UP; break; /* up */
1281 // above case XK_SPACE: key_pressed = KPSPACE; break; /* ok */
1282 // intercepted case XF86XK_AudioRaiseVolume: key_pressed = KPVOLU; break; /* VOL + */
1283 // intercepted case XF86XK_AudioMute: key_pressed = KPMUTE; break; /* MUTE */
1284 // intercepted case XF86XK_AudioLowerVolume: key_pressed = KPVOLD; break; /* VOL - */
1285 case XF86XK_ScrollUp: key_pressed = KPCHUP; break; /* CH + */
1286 case XF86XK_ScrollDown: key_pressed = KPCHDN; break; /* CH - */
1287 case XF86XK_AudioRecord: key_pressed = KPRECD; break; /* ( o) red */
1288 case XF86XK_Forward: key_pressed = KPPLAY; break; /* ( >) */
1289 case XK_Redo: key_pressed = KPFWRD; break; /* (>>) */
1290 case XF86XK_Back: key_pressed = KPBACK; break; /* (<<) */
1291 case XK_Cancel: key_pressed = KPSTOP; break; /* ([]) */
1292 case XK_Pause: key_pressed = KPAUSE; break; /* ('') */
1295 key_pressed = keysym & 0xff;
1296 #ifdef X_HAVE_UTF8_STRING
1297 //printf("BC_WindowBase::dispatch_event %d\n", __LINE__);
1302 #ifdef X_HAVE_UTF8_STRING
1304 key_pressed_utf8 = keys_return;
1309 if( top_level == this )
1310 result = BC_KeyboardHandler::run_listeners(this);
1312 //printf("BC_WindowBase::dispatch_event %d %d %x\n", shift_down(), alt_down(), key_pressed);
1314 result = dispatch_keypress_event();
1315 // Handle some default keypresses
1318 if(key_pressed == 'w' ||
1327 XLookupString((XKeyEvent*)event, keys_return, 1, &keysym, 0);
1328 dispatch_keyrelease_event();
1329 // printf("BC_WindowBase::dispatch_event KeyRelease keysym=0x%x keystate=0x%lld\n",
1330 // keysym, event->xkey.state);
1334 if( event->xcrossing.mode != NotifyNormal ) break;
1336 event_win = event->xany.window;
1337 dispatch_cursor_leave();
1341 if( event->xcrossing.mode != NotifyNormal ) break;
1343 if( !cursor_entered ) {
1344 for( int i=0; i<popups.size(); ++i ) { // popups always take focus
1345 if( popups[i]->win == event->xcrossing.window )
1348 if( !cursor_entered && get_resources()->grab_input_focus &&
1349 !event->xcrossing.focus && event->xcrossing.window == win ) {
1352 if( cursor_entered )
1355 event_win = event->xany.window;
1356 cursor_x = event->xcrossing.x;
1357 cursor_y = event->xcrossing.y;
1358 dispatch_cursor_enter();
1364 //printf("100 %s %p %d\n", title, event, event->type);
1365 //if(event->type != ClientMessage) dump();
1367 #ifndef SINGLE_THREAD
1370 if( resend_event_window ) {
1371 resend_event_window->put_event(event);
1372 resend_event_window = 0;
1378 // if(done) completion_lock->unlock();
1381 if(debug) printf("BC_WindowBase::dispatch_event this=%p %d\n", this, __LINE__);
1385 int BC_WindowBase::dispatch_expose_event()
1388 for(int i = 0; i < subwindows->total && !result; i++)
1390 result = subwindows->values[i]->dispatch_expose_event();
1393 // Propagate to user
1394 if(!result) expose_event();
1398 int BC_WindowBase::dispatch_resize_event(int w, int h)
1400 // Can't store new w and h until the event is handles
1401 // because bcfilebox depends on the old w and h to
1402 // reposition widgets.
1403 if( window_type == MAIN_WINDOW ) {
1408 pixmap = new BC_Pixmap(this, w, h);
1409 clear_box(0, 0, w, h);
1412 // Propagate to subwindows
1413 for(int i = 0; i < subwindows->total; i++) {
1414 subwindows->values[i]->dispatch_resize_event(w, h);
1417 // Propagate to user
1420 if( window_type == MAIN_WINDOW ) {
1429 int BC_WindowBase::dispatch_flash()
1432 for(int i = 0; i < subwindows->total; i++)
1433 subwindows->values[i]->dispatch_flash();
1437 int BC_WindowBase::dispatch_translation_event()
1439 translation_events = 0;
1440 if(window_type == MAIN_WINDOW)
1444 x = last_translate_x;
1445 y = last_translate_y;
1446 // Correct for window manager offsets
1451 for(int i = 0; i < subwindows->total; i++)
1453 subwindows->values[i]->dispatch_translation_event();
1456 translation_event();
1460 int BC_WindowBase::dispatch_motion_event()
1465 if(top_level == this)
1468 event_win = last_motion_win;
1469 get_key_masks(last_motion_state);
1472 if(get_button_down() && !active_menubar && !active_popup_menu)
1476 cursor_x = last_motion_x;
1477 cursor_y = last_motion_y;
1478 result = dispatch_drag_motion();
1482 (last_motion_x < drag_x1 || last_motion_x >= drag_x2 ||
1483 last_motion_y < drag_y1 || last_motion_y >= drag_y2))
1488 result = dispatch_drag_start();
1492 cursor_x = last_motion_x;
1493 cursor_y = last_motion_y;
1495 // printf("BC_WindowBase::dispatch_motion_event %d %p %p %p\n",
1498 // active_popup_menu,
1499 // active_subwindow);
1501 if(active_menubar && !result) result = active_menubar->dispatch_motion_event();
1502 if(active_popup_menu && !result) result = active_popup_menu->dispatch_motion_event();
1503 if(active_subwindow && !result) result = active_subwindow->dispatch_motion_event();
1506 // Dispatch in stacking order
1507 for(int i = subwindows->size() - 1; i >= 0 && !result; i--)
1509 result = subwindows->values[i]->dispatch_motion_event();
1512 if(!result) result = cursor_motion_event(); // give to user
1516 int BC_WindowBase::dispatch_keypress_event()
1519 if(top_level == this)
1521 if(active_subwindow) result = active_subwindow->dispatch_keypress_event();
1524 for(int i = 0; i < subwindows->total && !result; i++)
1526 result = subwindows->values[i]->dispatch_keypress_event();
1529 if(!result) result = keypress_event();
1534 int BC_WindowBase::dispatch_keyrelease_event()
1537 if(top_level == this)
1539 if(active_subwindow) result = active_subwindow->dispatch_keyrelease_event();
1542 for(int i = 0; i < subwindows->total && !result; i++)
1544 result = subwindows->values[i]->dispatch_keyrelease_event();
1547 if(!result) result = keyrelease_event();
1552 int BC_WindowBase::dispatch_focus_in()
1554 for(int i = 0; i < subwindows->total; i++)
1556 subwindows->values[i]->dispatch_focus_in();
1564 int BC_WindowBase::dispatch_focus_out()
1566 for(int i = 0; i < subwindows->total; i++)
1568 subwindows->values[i]->dispatch_focus_out();
1576 int BC_WindowBase::get_has_focus()
1578 return top_level->has_focus;
1581 int BC_WindowBase::get_deleting()
1583 if(is_deleting) return 1;
1584 if(parent_window && parent_window->get_deleting()) return 1;
1588 int BC_WindowBase::dispatch_button_press()
1593 if(top_level == this)
1595 if(active_menubar) result = active_menubar->dispatch_button_press();
1596 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_press();
1597 if(active_subwindow && !result) result = active_subwindow->dispatch_button_press();
1600 for(int i = 0; i < subwindows->total && !result; i++)
1602 result = subwindows->values[i]->dispatch_button_press();
1605 if(!result) result = button_press_event();
1611 int BC_WindowBase::dispatch_button_release()
1614 if(top_level == this)
1616 if(active_menubar) result = active_menubar->dispatch_button_release();
1617 if(active_popup_menu && !result) result = active_popup_menu->dispatch_button_release();
1618 if(active_subwindow && !result) result = active_subwindow->dispatch_button_release();
1619 if(!result && button_number != 4 && button_number != 5)
1620 result = dispatch_drag_stop();
1623 for(int i = 0; i < subwindows->total && !result; i++)
1625 result = subwindows->values[i]->dispatch_button_release();
1630 result = button_release_event();
1637 int BC_WindowBase::dispatch_repeat_event(int64_t duration)
1640 // all repeat event handlers get called and decide based on activity and duration
1641 // whether to respond
1642 for(int i = 0; i < subwindows->total; i++)
1644 subwindows->values[i]->dispatch_repeat_event(duration);
1648 repeat_event(duration);
1652 // Unlock next repeat signal
1653 if(window_type == MAIN_WINDOW)
1655 #ifdef SINGLE_THREAD
1656 BC_Display::display_global->unlock_repeaters(duration);
1658 for(int i = 0; i < repeaters.total; i++)
1660 if(repeaters.values[i]->delay == duration)
1662 repeaters.values[i]->repeat_lock->unlock();
1670 void BC_WindowBase::unhide_cursor()
1675 if(top_level->is_hourglass)
1676 set_cursor(HOURGLASS_CURSOR, 1, 0);
1678 set_cursor(current_cursor, 1, 0);
1680 cursor_timer->update();
1684 void BC_WindowBase::update_video_cursor()
1686 if(video_on && !is_transparent)
1688 if(cursor_timer->get_difference() > VIDEO_CURSOR_TIMEOUT && !is_transparent)
1691 set_cursor(TRANSPARENT_CURSOR, 1, 1);
1692 cursor_timer->update();
1697 cursor_timer->update();
1702 int BC_WindowBase::dispatch_cursor_leave()
1706 for(int i = 0; i < subwindows->total; i++)
1708 subwindows->values[i]->dispatch_cursor_leave();
1711 cursor_leave_event();
1715 int BC_WindowBase::dispatch_cursor_enter()
1721 if(active_menubar) result = active_menubar->dispatch_cursor_enter();
1722 if(!result && active_popup_menu) result = active_popup_menu->dispatch_cursor_enter();
1723 if(!result && active_subwindow) result = active_subwindow->dispatch_cursor_enter();
1725 for(int i = 0; !result && i < subwindows->total; i++)
1727 result = subwindows->values[i]->dispatch_cursor_enter();
1730 if(!result) result = cursor_enter_event();
1734 int BC_WindowBase::cursor_enter_event()
1739 int BC_WindowBase::cursor_leave_event()
1744 int BC_WindowBase::close_event()
1750 int BC_WindowBase::dispatch_drag_start()
1753 if(active_menubar) result = active_menubar->dispatch_drag_start();
1754 if(!result && active_popup_menu) result = active_popup_menu->dispatch_drag_start();
1755 if(!result && active_subwindow) result = active_subwindow->dispatch_drag_start();
1757 for(int i = 0; i < subwindows->total && !result; i++)
1759 result = subwindows->values[i]->dispatch_drag_start();
1762 if(!result) result = is_dragging = drag_start_event();
1766 int BC_WindowBase::dispatch_drag_stop()
1770 for(int i = 0; i < subwindows->total && !result; i++)
1772 result = subwindows->values[i]->dispatch_drag_stop();
1775 if(is_dragging && !result)
1785 int BC_WindowBase::dispatch_drag_motion()
1788 for(int i = 0; i < subwindows->total && !result; i++)
1790 result = subwindows->values[i]->dispatch_drag_motion();
1793 if(is_dragging && !result)
1795 drag_motion_event();
1803 int BC_WindowBase::show_tooltip(const char *text, int x, int y, int w, int h)
1806 int forced = !text ? force_tooltip : 1;
1807 if( !text ) text = tooltip_text;
1808 if( !text || (!forced && !get_resources()->tooltips_enabled) ) {
1809 top_level->hide_tooltip();
1813 if(w < 0) w = get_text_width(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1814 if(h < 0) h = get_text_height(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
1815 // default x,y (win relative)
1816 if( x < 0 ) x = get_w();
1817 if( y < 0 ) y = get_h();
1819 get_root_coordinates(x, y, &wx, &wy);
1820 // keep the tip inside the window/display
1821 int x0 = top_level->get_x(), x1 = x0 + top_level->get_w();
1822 int x2 = top_level->get_screen_x(0, -1) + top_level->get_screen_w(0, -1);
1823 if( x1 > x2 ) x1 = x2;
1824 if( wx < x0 ) wx = x0;
1825 if( wx >= (x1-=w) ) wx = x1;
1826 int y0 = top_level->get_y(), y1 = y0 + top_level->get_h();
1827 int y2 = top_level->get_root_h(0);
1828 if( y1 > y2 ) y1 = y2;
1829 if( wy < y0 ) wy = y0;
1830 if( wy >= (y1-=h) ) wy = y1;
1831 // avoid tip under cursor (flickers)
1833 get_abs_cursor(abs_x,abs_y, 0);
1834 if( wx < abs_x && abs_x < wx+w && wy < abs_y && abs_y < wy+h ) {
1835 if( wx-abs_x < wy-abs_y )
1842 tooltip_popup = new BC_Popup(top_level, wx, wy, w, h,
1843 get_resources()->tooltip_bg_color);
1846 tooltip_popup->reposition_window(wx, wy, w, h);
1849 tooltip_popup->flash();
1850 tooltip_popup->flush();
1854 int BC_WindowBase::hide_tooltip()
1857 for(int i = 0; i < subwindows->total; i++)
1859 subwindows->values[i]->hide_tooltip();
1865 delete tooltip_popup;
1871 const char *BC_WindowBase::get_tooltip()
1873 return tooltip_text;
1876 int BC_WindowBase::set_tooltip(const char *text)
1878 tooltip_text = text;
1880 // Update existing tooltip if it is visible
1884 tooltip_popup->flash();
1888 // signal the event handler to repeat
1889 int BC_WindowBase::set_repeat(int64_t duration)
1893 printf("BC_WindowBase::set_repeat duration=%jd\n", duration);
1896 if(window_type != MAIN_WINDOW) return top_level->set_repeat(duration);
1898 #ifdef SINGLE_THREAD
1899 BC_Display::display_global->set_repeat(this, duration);
1901 // test repeater database for duplicates
1902 for(int i = 0; i < repeaters.total; i++)
1905 if(repeaters.values[i]->delay == duration)
1907 repeaters.values[i]->start_repeating(this);
1912 BC_Repeater *repeater = new BC_Repeater(this, duration);
1913 repeater->initialize();
1914 repeaters.append(repeater);
1915 repeater->start_repeating();
1920 int BC_WindowBase::unset_repeat(int64_t duration)
1922 if(window_type != MAIN_WINDOW) return top_level->unset_repeat(duration);
1924 #ifdef SINGLE_THREAD
1925 BC_Display::display_global->unset_repeat(this, duration);
1927 for(int i = 0; i < repeaters.total; i++)
1929 if(repeaters.values[i]->delay == duration)
1931 repeaters.values[i]->stop_repeating();
1939 int BC_WindowBase::unset_all_repeaters()
1941 #ifdef SINGLE_THREAD
1942 BC_Display::display_global->unset_all_repeaters(this);
1944 for(int i = 0; i < repeaters.total; i++)
1946 repeaters.values[i]->stop_repeating();
1948 repeaters.remove_all_objects();
1953 // long BC_WindowBase::get_repeat_id()
1955 // return top_level->next_repeat_id++;
1958 XEvent *BC_WindowBase::new_xevent()
1960 XEvent *event = new XEvent;
1961 memset(event, 0, sizeof(*event));
1965 #ifndef SINGLE_THREAD
1966 int BC_WindowBase::arm_repeat(int64_t duration)
1968 XEvent *event = new_xevent();
1969 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
1970 ptr->type = ClientMessage;
1971 ptr->message_type = RepeaterXAtom;
1973 ptr->data.l[0] = duration;
1975 // Couldn't use XSendEvent since it locked up randomly.
1981 int BC_WindowBase::receive_custom_xatoms(xatom_event *event)
1986 int BC_WindowBase::send_custom_xatom(xatom_event *event)
1988 #ifndef SINGLE_THREAD
1989 XEvent *myevent = new_xevent();
1990 XClientMessageEvent *ptr = (XClientMessageEvent*)myevent;
1991 ptr->type = ClientMessage;
1992 ptr->message_type = event->message_type;
1993 ptr->format = event->format;
1994 ptr->data.l[0] = event->data.l[0];
1995 ptr->data.l[1] = event->data.l[1];
1996 ptr->data.l[2] = event->data.l[2];
1997 ptr->data.l[3] = event->data.l[3];
1998 ptr->data.l[4] = event->data.l[4];
2007 Atom BC_WindowBase::create_xatom(const char *atom_name)
2009 return XInternAtom(display, atom_name, False);
2012 int BC_WindowBase::get_atoms()
2014 SetDoneXAtom = XInternAtom(display, "BC_REPEAT_EVENT", False);
2015 RepeaterXAtom = XInternAtom(display, "BC_CLOSE_EVENT", False);
2016 DestroyAtom = XInternAtom(display, "BC_DESTROY_WINDOW", False);
2017 DelWinXAtom = XInternAtom(display, "WM_DELETE_WINDOW", False);
2018 if( (ProtoXAtom = XInternAtom(display, "WM_PROTOCOLS", False)) != 0 )
2019 XChangeProperty(display, win, ProtoXAtom, XA_ATOM, 32,
2020 PropModeReplace, (unsigned char *)&DelWinXAtom, True);
2026 void BC_WindowBase::init_cursors()
2028 arrow_cursor = XCreateFontCursor(display, XC_top_left_arrow);
2029 cross_cursor = XCreateFontCursor(display, XC_crosshair);
2030 ibeam_cursor = XCreateFontCursor(display, XC_xterm);
2031 vseparate_cursor = XCreateFontCursor(display, XC_sb_v_double_arrow);
2032 hseparate_cursor = XCreateFontCursor(display, XC_sb_h_double_arrow);
2033 move_cursor = XCreateFontCursor(display, XC_fleur);
2034 left_cursor = XCreateFontCursor(display, XC_sb_left_arrow);
2035 right_cursor = XCreateFontCursor(display, XC_sb_right_arrow);
2036 upright_arrow_cursor = XCreateFontCursor(display, XC_arrow);
2037 upleft_resize_cursor = XCreateFontCursor(display, XC_top_left_corner);
2038 upright_resize_cursor = XCreateFontCursor(display, XC_top_right_corner);
2039 downleft_resize_cursor = XCreateFontCursor(display, XC_bottom_left_corner);
2040 downright_resize_cursor = XCreateFontCursor(display, XC_bottom_right_corner);
2041 hourglass_cursor = XCreateFontCursor(display, XC_watch);
2042 grabbed_cursor = create_grab_cursor();
2044 static char cursor_data[] = { 0,0,0,0, 0,0,0,0 };
2045 Colormap colormap = DefaultColormap(display, screen);
2046 Pixmap pixmap_bottom = XCreateBitmapFromData(display,
2047 rootwin, cursor_data, 8, 8);
2048 XColor black, dummy;
2049 XAllocNamedColor(display, colormap, "black", &black, &dummy);
2050 transparent_cursor = XCreatePixmapCursor(display,
2051 pixmap_bottom, pixmap_bottom, &black, &black, 0, 0);
2052 // XDefineCursor(display, win, transparent_cursor);
2053 XFreePixmap(display, pixmap_bottom);
2056 int BC_WindowBase::evaluate_color_model(int client_byte_order, int server_byte_order, int depth)
2058 int color_model = BC_TRANSPARENCY;
2062 color_model = BC_RGB8;
2065 color_model = (server_byte_order == client_byte_order) ? BC_RGB565 : BC_BGR565;
2068 color_model = server_byte_order ? BC_BGR888 : BC_RGB888;
2071 color_model = server_byte_order ? BC_BGR8888 : BC_ARGB8888;
2077 int BC_WindowBase::init_colors()
2080 current_color_value = current_color_pixel = 0;
2082 // Get the real depth
2085 ximage = XCreateImage(top_level->display,
2086 top_level->vis, top_level->default_depth,
2087 ZPixmap, 0, data, 16, 16, 8, 0);
2088 bits_per_pixel = ximage->bits_per_pixel;
2089 XDestroyImage(ximage);
2091 color_model = evaluate_color_model(client_byte_order,
2094 // Get the color model
2099 cmap = XCreateColormap(display, rootwin, vis, AllocNone);
2100 create_private_colors();
2103 cmap = DefaultColormap(display, screen);
2104 create_shared_colors();
2107 allocate_color_table();
2111 //cmap = DefaultColormap(display, screen);
2112 cmap = XCreateColormap(display, rootwin, vis, AllocNone );
2118 int BC_WindowBase::create_private_colors()
2123 for(int i = 0; i < 255; i++)
2125 color = (i & 0xc0) << 16;
2126 color += (i & 0x38) << 10;
2127 color += (i & 0x7) << 5;
2128 color_table[i][0] = color;
2130 create_shared_colors(); // overwrite the necessary colors on the table
2135 int BC_WindowBase::create_color(int color)
2137 if(total_colors == 256)
2139 // replace the closest match with an exact match
2140 color_table[get_color_rgb8(color)][0] = color;
2144 // add the color to the table
2145 color_table[total_colors][0] = color;
2151 int BC_WindowBase::create_shared_colors()
2153 create_color(BLACK);
2154 create_color(WHITE);
2156 create_color(LTGREY);
2157 create_color(MEGREY);
2158 create_color(MDGREY);
2159 create_color(DKGREY);
2161 create_color(LTCYAN);
2162 create_color(MECYAN);
2163 create_color(MDCYAN);
2164 create_color(DKCYAN);
2166 create_color(LTGREEN);
2167 create_color(GREEN);
2168 create_color(DKGREEN);
2170 create_color(LTPINK);
2174 create_color(LTBLUE);
2176 create_color(DKBLUE);
2178 create_color(LTYELLOW);
2179 create_color(MEYELLOW);
2180 create_color(MDYELLOW);
2181 create_color(DKYELLOW);
2183 create_color(LTPURPLE);
2184 create_color(MEPURPLE);
2185 create_color(MDPURPLE);
2186 create_color(DKPURPLE);
2188 create_color(FGGREY);
2189 create_color(MNBLUE);
2190 create_color(ORANGE);
2191 create_color(FTGREY);
2196 Cursor BC_WindowBase::create_grab_cursor()
2198 int iw = 23, iw1 = iw-1, iw2 = iw/2;
2199 int ih = 23, ih1 = ih-1, ih2 = ih/2;
2200 VFrame grab(iw,ih,BC_RGB888);
2202 grab.set_pixel_color(RED); // fg
2203 grab.draw_smooth(iw2,0, iw1,0, iw1,ih2);
2204 grab.draw_smooth(iw1,ih2, iw1,ih1, iw2,ih1);
2205 grab.draw_smooth(iw2,ih1, 0,ih1, 0,ih2);
2206 grab.draw_smooth(0,ih2, 0,0, iw2,0);
2207 grab.set_pixel_color(WHITE); // bg
2208 grab.draw_line(0,ih2, iw2-2,ih2);
2209 grab.draw_line(iw2+2,ih2, iw1,ih2);
2210 grab.draw_line(iw2,0, iw2,ih2-2);
2211 grab.draw_line(iw2,ih2+2, iw2,ih1);
2213 int bpl = (iw+7)/8, isz = bpl * ih;
2214 char img[isz]; memset(img, 0, isz);
2215 char msk[isz]; memset(msk, 0, isz);
2216 unsigned char **rows = grab.get_rows();
2217 for( int iy=0; iy<ih; ++iy ) {
2218 char *op = img + iy*bpl;
2219 char *mp = msk + iy*bpl;
2220 unsigned char *ip = rows[iy];
2221 for( int ix=0; ix<iw; ++ix,ip+=3 ) {
2222 if( ip[0] ) mp[ix>>3] |= (1<<(ix&7));
2223 if( !ip[1] ) op[ix>>3] |= (1<<(ix&7));
2226 unsigned long white_pix = WhitePixel(display, screen);
2227 unsigned long black_pix = BlackPixel(display, screen);
2228 Pixmap img_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2229 img, iw,ih, white_pix,black_pix, 1);
2230 Pixmap msk_xpm = XCreatePixmapFromBitmapData(display, rootwin,
2231 msk, iw,ih, white_pix,black_pix, 1);
2234 fc.flags = bc.flags = DoRed | DoGreen | DoBlue;
2235 fc.red = 0xffff; fc.green = fc.blue = 0; // fg
2236 bc.red = 0xffff; bc.green = 0xffff; bc.blue = 0x0000; // bg
2237 Cursor cursor = XCreatePixmapCursor(display, img_xpm,msk_xpm, &fc,&bc, iw2,ih2);
2238 XFreePixmap(display, img_xpm);
2239 XFreePixmap(display, msk_xpm);
2243 int BC_WindowBase::allocate_color_table()
2245 int red, green, blue, color;
2248 for(int i = 0; i < total_colors; i++)
2250 color = color_table[i][0];
2251 red = (color & 0xFF0000) >> 16;
2252 green = (color & 0x00FF00) >> 8;
2253 blue = color & 0xFF;
2255 col.flags = DoRed | DoGreen | DoBlue;
2256 col.red = red<<8 | red;
2257 col.green = green<<8 | green;
2258 col.blue = blue<<8 | blue;
2260 XAllocColor(display, cmap, &col);
2261 color_table[i][1] = col.pixel;
2264 XInstallColormap(display, cmap);
2268 int BC_WindowBase::init_window_shape()
2270 if(bg_pixmap && bg_pixmap->use_alpha())
2272 XShapeCombineMask(top_level->display,
2273 this->win, ShapeBounding, 0, 0,
2274 bg_pixmap->get_alpha(), ShapeSet);
2280 int BC_WindowBase::init_gc()
2282 unsigned long gcmask;
2283 gcmask = GCFont | GCGraphicsExposures;
2286 gcvalues.font = mediumfont->fid; // set the font
2287 gcvalues.graphics_exposures = 0; // prevent expose events for every redraw
2288 gc = XCreateGC(display, rootwin, gcmask, &gcvalues);
2290 // gcmask = GCCapStyle | GCJoinStyle;
2291 // XGetGCValues(display, gc, gcmask, &gcvalues);
2292 // printf("BC_WindowBase::init_gc %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2296 int BC_WindowBase::init_fonts()
2298 if( !(smallfont = XLoadQueryFont(display, _(resources->small_font))) )
2299 if( !(smallfont = XLoadQueryFont(display, _(resources->small_font2))) )
2300 smallfont = XLoadQueryFont(display, "fixed");
2301 if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font))) )
2302 if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font2))) )
2303 mediumfont = XLoadQueryFont(display, "fixed");
2304 if( !(largefont = XLoadQueryFont(display, _(resources->large_font))) )
2305 if( !(largefont = XLoadQueryFont(display, _(resources->large_font2))) )
2306 largefont = XLoadQueryFont(display, "fixed");
2307 if( !(bigfont = XLoadQueryFont(display, _(resources->big_font))) )
2308 if( !(bigfont = XLoadQueryFont(display, _(resources->big_font2))) )
2309 bigfont = XLoadQueryFont(display, "fixed");
2311 if((clockfont = XLoadQueryFont(display, _(resources->clock_font))) == NULL)
2312 if((clockfont = XLoadQueryFont(display, _(resources->clock_font2))) == NULL)
2313 clockfont = XLoadQueryFont(display, "fixed");
2316 if(get_resources()->use_fontset)
2321 // FIXME: should check the m,d,n values
2322 smallfontset = XCreateFontSet(display, resources->small_fontset, &m, &n, &d);
2324 smallfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2325 mediumfontset = XCreateFontSet(display, resources->medium_fontset, &m, &n, &d);
2326 if( !mediumfontset )
2327 mediumfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2328 largefontset = XCreateFontSet(display, resources->large_fontset, &m, &n, &d);
2330 largefontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2331 bigfontset = XCreateFontSet(display, resources->big_fontset, &m, &n, &d);
2333 bigfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2334 clockfontset = XCreateFontSet(display, resources->clock_fontset, &m, &n, &d);
2336 clockfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d);
2337 if(clockfontset && bigfontset && largefontset && mediumfontset && smallfontset) {
2338 curr_fontset = mediumfontset;
2339 get_resources()->use_fontset = 1;
2343 get_resources()->use_fontset = 0;
2350 void BC_WindowBase::init_xft()
2353 if( !get_resources()->use_xft ) return;
2354 // apparently, xft is not reentrant, more than this is needed
2355 static Mutex xft_init_lock("BC_WindowBase::xft_init_lock", 0);
2356 xft_init_lock.lock("BC_WindowBase::init_xft");
2357 if(!(smallfont_xft =
2358 (resources->small_font_xft[0] == '-' ?
2359 xftFontOpenXlfd(display, screen, resources->small_font_xft) :
2360 xftFontOpenName(display, screen, resources->small_font_xft))) )
2361 if(!(smallfont_xft =
2362 xftFontOpenXlfd(display, screen, resources->small_font_xft2)))
2363 smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2364 if(!(mediumfont_xft =
2365 (resources->medium_font_xft[0] == '-' ?
2366 xftFontOpenXlfd(display, screen, resources->medium_font_xft) :
2367 xftFontOpenName(display, screen, resources->medium_font_xft))) )
2368 if(!(mediumfont_xft =
2369 xftFontOpenXlfd(display, screen, resources->medium_font_xft2)))
2370 mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2371 if(!(largefont_xft =
2372 (resources->large_font_xft[0] == '-' ?
2373 xftFontOpenXlfd(display, screen, resources->large_font_xft) :
2374 xftFontOpenName(display, screen, resources->large_font_xft))) )
2375 if(!(largefont_xft =
2376 xftFontOpenXlfd(display, screen, resources->large_font_xft2)))
2377 largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2379 (resources->big_font_xft[0] == '-' ?
2380 xftFontOpenXlfd(display, screen, resources->big_font_xft) :
2381 xftFontOpenName(display, screen, resources->big_font_xft))) )
2383 xftFontOpenXlfd(display, screen, resources->big_font_xft2)))
2384 bigfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2385 if(!(clockfont_xft =
2386 (resources->clock_font_xft[0] == '-' ?
2387 xftFontOpenXlfd(display, screen, resources->clock_font_xft) :
2388 xftFontOpenName(display, screen, resources->clock_font_xft))) )
2389 clockfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2392 if(!(bold_smallfont_xft =
2393 (resources->small_b_font_xft[0] == '-' ?
2394 xftFontOpenXlfd(display, screen, resources->small_b_font_xft) :
2395 xftFontOpenName(display, screen, resources->small_b_font_xft))) )
2396 bold_smallfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2397 if(!(bold_mediumfont_xft =
2398 (resources->medium_b_font_xft[0] == '-' ?
2399 xftFontOpenXlfd(display, screen, resources->medium_b_font_xft) :
2400 xftFontOpenName(display, screen, resources->medium_b_font_xft))) )
2401 bold_mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed");
2402 if(!(bold_largefont_xft =
2403 (resources->large_b_font_xft[0] == '-' ?
2404 xftFontOpenXlfd(display, screen, resources->large_b_font_xft) :
2405 xftFontOpenName(display, screen, resources->large_b_font_xft))) )
2406 bold_largefont_xft = xftFontOpenXlfd(display, screen, "fixed");
2408 if( !smallfont_xft || !mediumfont_xft || !largefont_xft || !bigfont_xft ||
2409 !bold_largefont_xft || !bold_mediumfont_xft || !bold_largefont_xft ||
2411 printf("BC_WindowBase::init_fonts: no xft fonts found:"
2412 " %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n",
2413 resources->small_font_xft, smallfont_xft,
2414 resources->medium_font_xft, mediumfont_xft,
2415 resources->large_font_xft, largefont_xft,
2416 resources->big_font_xft, bigfont_xft,
2417 resources->clock_font_xft, clockfont_xft,
2418 resources->small_b_font_xft, bold_smallfont_xft,
2419 resources->medium_b_font_xft, bold_mediumfont_xft,
2420 resources->large_b_font_xft, bold_largefont_xft);
2421 get_resources()->use_xft = 0;
2424 // _XftDisplayInfo needs a lock.
2425 xftDefaultHasRender(display);
2426 xft_init_lock.unlock();
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 BC_Bitmap* BC_WindowBase::new_bitmap(int w, int h, int color_model)
3041 if(color_model < 0) color_model = top_level->get_color_model();
3042 return new BC_Bitmap(top_level, w, h, color_model);
3045 void BC_WindowBase::init_wait()
3047 #ifndef SINGLE_THREAD
3048 if(window_type != MAIN_WINDOW)
3049 top_level->init_wait();
3050 init_lock->lock("BC_WindowBase::init_wait");
3051 init_lock->unlock();
3055 int BC_WindowBase::accel_available(int color_model, int lock_it)
3057 if( window_type != MAIN_WINDOW )
3058 return top_level->accel_available(color_model, lock_it);
3060 lock_window("BC_WindowBase::accel_available");
3062 switch(color_model) {
3064 grab_port_id(color_model);
3068 grab_port_id(color_model);
3077 //printf("BC_WindowBase::accel_available %d %d\n", color_model, xvideo_port_id);
3078 return xvideo_port_id >= 0 ? 1 : 0;
3082 int BC_WindowBase::grab_port_id(int color_model)
3084 if( !get_resources()->use_xvideo || // disabled
3085 !get_resources()->use_shm ) // Only local server is fast enough.
3087 if( xvideo_port_id >= 0 )
3088 return xvideo_port_id;
3090 unsigned int ver, rev, reqBase, eventBase, errorBase;
3091 if( Success != XvQueryExtension(display, // XV extension is available
3092 &ver, &rev, &reqBase, &eventBase, &errorBase) )
3095 // XV adaptors are available
3096 unsigned int numAdapt = 0;
3097 XvAdaptorInfo *info = 0;
3098 XvQueryAdaptors(display, DefaultRootWindow(display), &numAdapt, &info);
3102 // Translate from color_model to X color model
3103 int x_color_model = BC_CModels::bc_to_x(color_model);
3105 // Get adaptor with desired color model
3106 for( int i = 0; i < (int)numAdapt && xvideo_port_id == -1; i++) {
3107 if( !(info[i].type & XvImageMask) || !info[i].num_ports ) continue;
3108 // adaptor supports XvImages
3109 int numFormats = 0, numPorts = info[i].num_ports;
3110 XvImageFormatValues *formats =
3111 XvListImageFormats(display, info[i].base_id, &numFormats);
3112 if( !formats ) continue;
3114 for( int j=0; j<numFormats && xvideo_port_id<0; ++j ) {
3115 if( formats[j].id != x_color_model ) continue;
3116 // this adaptor supports the desired format, grab a port
3117 for( int k=0; k<numPorts; ++k ) {
3118 if( Success == XvGrabPort(top_level->display,
3119 info[i].base_id+k, CurrentTime) ) {
3120 //printf("BC_WindowBase::grab_port_id %llx\n", info[i].base_id);
3121 xvideo_port_id = info[i].base_id + k;
3129 XvFreeAdaptorInfo(info);
3131 return xvideo_port_id;
3135 int BC_WindowBase::show_window(int flush)
3137 for(int i = 0; i < subwindows->size(); i++)
3139 subwindows->get(i)->show_window(0);
3142 XMapWindow(top_level->display, win);
3143 if(flush) XFlush(top_level->display);
3144 // XSync(top_level->display, 0);
3149 int BC_WindowBase::hide_window(int flush)
3151 for(int i = 0; i < subwindows->size(); i++)
3153 subwindows->get(i)->hide_window(0);
3156 XUnmapWindow(top_level->display, win);
3157 if(flush) this->flush();
3162 BC_MenuBar* BC_WindowBase::add_menubar(BC_MenuBar *menu_bar)
3164 subwindows->append((BC_SubWindow*)menu_bar);
3166 menu_bar->parent_window = this;
3167 menu_bar->top_level = this->top_level;
3168 menu_bar->initialize();
3172 BC_WindowBase* BC_WindowBase::add_popup(BC_WindowBase *window)
3174 //printf("BC_WindowBase::add_popup window=%p win=%p\n", window, window->win);
3175 if(this != top_level) return top_level->add_popup(window);
3176 popups.append(window);
3180 void BC_WindowBase::remove_popup(BC_WindowBase *window)
3182 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3183 if(this != top_level)
3184 top_level->remove_popup(window);
3186 popups.remove(window);
3187 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3191 BC_WindowBase* BC_WindowBase::add_subwindow(BC_WindowBase *subwindow)
3193 subwindows->append(subwindow);
3195 if(subwindow->bg_color == -1) subwindow->bg_color = this->bg_color;
3197 // parent window must be set before the subwindow initialization
3198 subwindow->parent_window = this;
3199 subwindow->top_level = this->top_level;
3201 // Execute derived initialization
3202 subwindow->initialize();
3207 BC_WindowBase* BC_WindowBase::add_tool(BC_WindowBase *subwindow)
3209 return add_subwindow(subwindow);
3212 int BC_WindowBase::flash(int x, int y, int w, int h, int flush)
3214 if( !top_level->flash_enabled ) return 0;
3215 //printf("BC_WindowBase::flash %d %d %d %d %d\n", __LINE__, w, h, this->w, this->h);
3217 XSetWindowBackgroundPixmap(top_level->display, win, pixmap->opaque_pixmap);
3220 XClearArea(top_level->display, win, x, y, w, h, 0);
3224 XClearWindow(top_level->display, win);
3232 int BC_WindowBase::flash(int flush)
3234 flash(-1, -1, -1, -1, flush);
3238 void BC_WindowBase::flush()
3240 //if(!get_window_lock())
3241 // printf("BC_WindowBase::flush %s not locked\n", top_level->title);
3242 // X gets hosed if Flush/Sync are not user locked (at libX11-1.1.5 / libxcb-1.1.91)
3243 // _XReply deadlocks in condition_wait waiting for xlib lock when waiters!=-1
3244 int locked = get_window_lock();
3245 if( !locked ) lock_window("BC_WindowBase::flush");
3246 XFlush(top_level->display);
3247 if( !locked ) unlock_window();
3250 void BC_WindowBase::sync_display()
3252 int locked = get_window_lock();
3253 if( !locked ) lock_window("BC_WindowBase::sync_display");
3254 XSync(top_level->display, False);
3255 if( !locked ) unlock_window();
3258 int BC_WindowBase::get_window_lock()
3260 #ifdef SINGLE_THREAD
3261 return BC_Display::display_global->get_display_locked();
3263 return top_level->window_lock;
3267 int BC_WindowBase::lock_window(const char *location)
3269 if(top_level && top_level != this)
3271 top_level->lock_window(location);
3276 SET_LOCK(this, title, location);
3277 #ifdef SINGLE_THREAD
3278 BC_Display::lock_display(location);
3280 XLockDisplay(top_level->display);
3281 top_level->display_lock_owner = pthread_self();
3284 ++top_level->window_lock;
3288 printf("BC_WindowBase::lock_window top_level NULL\n");
3293 int BC_WindowBase::unlock_window()
3295 if(top_level && top_level != this)
3297 top_level->unlock_window();
3303 if( !top_level->window_lock ) {
3304 printf("BC_WindowBase::unlock_window %s not locked\n", title);
3307 if( top_level->window_lock > 0 )
3308 if( --top_level->window_lock == 0 )
3309 top_level->display_lock_owner = 0;
3310 #ifdef SINGLE_THREAD
3311 BC_Display::unlock_display();
3313 XUnlockDisplay(top_level->display);
3318 printf("BC_WindowBase::unlock_window top_level NULL\n");
3323 int BC_WindowBase::break_lock()
3325 if( !top_level ) return 0;
3326 if( top_level != this ) return top_level->break_lock();
3327 if( top_level->display_lock_owner != pthread_self() ) return 0;
3328 if( top_level->window_lock != 1 ) return 0;
3331 display_lock_owner = 0;
3332 #ifdef SINGLE_THREAD
3333 BC_Display::unlock_display();
3335 XUnlockDisplay(display);
3340 void BC_WindowBase::set_done(int return_value)
3342 if(done_set) return;
3344 if(window_type != MAIN_WINDOW)
3345 top_level->set_done(return_value);
3348 #ifdef SINGLE_THREAD
3349 this->return_value = return_value;
3350 BC_Display::display_global->arm_completion(this);
3351 completion_lock->unlock();
3352 #else // SINGLE_THREAD
3354 if( !event_thread ) return;
3355 XEvent *event = new_xevent();
3356 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
3357 event->type = ClientMessage;
3358 ptr->message_type = SetDoneXAtom;
3360 this->return_value = return_value;
3361 // May lock up here because XSendEvent doesn't work too well
3362 // asynchronous with XNextEvent.
3363 // This causes BC_WindowEvents to forward a copy of the event to run_window where
3365 // Deletion of event_thread is done at the end of BC_WindowBase::run_window() - by calling the destructor
3371 void BC_WindowBase::close(int return_value)
3373 hide_window(); flush();
3374 set_done(return_value);
3377 int BC_WindowBase::grab(BC_WindowBase *window)
3379 if( window->active_grab && this != window->active_grab ) return 0;
3380 window->active_grab = this;
3381 this->grab_active = window;
3384 int BC_WindowBase::ungrab(BC_WindowBase *window)
3386 if( window->active_grab && this != window->active_grab ) return 0;
3387 window->active_grab = 0;
3388 this->grab_active = 0;
3391 int BC_WindowBase::grab_event_count()
3394 #ifndef SINGLE_THREAD
3395 result = grab_active->get_event_count();
3399 int BC_WindowBase::grab_buttons()
3401 XSync(top_level->display, False);
3402 if( XGrabButton(top_level->display, AnyButton, AnyModifier,
3403 top_level->rootwin, True, ButtonPressMask | ButtonReleaseMask,
3404 GrabModeAsync, GrabModeSync, None, None) == GrabSuccess ) {
3405 set_active_subwindow(this);
3410 void BC_WindowBase::ungrab_buttons()
3412 XUngrabButton(top_level->display, AnyButton, AnyModifier, top_level->rootwin);
3413 set_active_subwindow(0);
3416 void BC_WindowBase::grab_cursor()
3418 Cursor cursor_grab = get_cursor_struct(GRABBED_CURSOR);
3419 XGrabPointer(top_level->display, top_level->rootwin, True,
3420 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
3421 GrabModeAsync, GrabModeAsync, None, cursor_grab, CurrentTime);
3423 void BC_WindowBase::ungrab_cursor()
3425 XUngrabPointer(top_level->display, CurrentTime);
3429 // WidthOfScreen/HeightOfScreen of XDefaultScreenOfDisplay
3430 // this is the bounding box of all the screens
3432 int BC_WindowBase::get_root_w(int lock_display)
3434 if(lock_display) lock_window("BC_WindowBase::get_root_w");
3435 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3436 int result = WidthOfScreen(def_screen);
3437 if(lock_display) unlock_window();
3441 int BC_WindowBase::get_root_h(int lock_display)
3443 if(lock_display) lock_window("BC_WindowBase::get_root_h");
3444 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3445 int result = HeightOfScreen(def_screen);
3446 if(lock_display) unlock_window();
3450 XineramaScreenInfo *
3451 BC_WindowBase::get_xinerama_info(int screen)
3453 if( !xinerama_info || !xinerama_screens ) return 0;
3455 for( int i=0; i<xinerama_screens; ++i )
3456 if( xinerama_info[i].screen_number == screen )
3457 return &xinerama_info[i];
3460 int top_x = get_x(), top_y = get_y();
3461 if( BC_DisplayInfo::left_border >= 0 ) top_x += BC_DisplayInfo::left_border;
3462 if( BC_DisplayInfo::top_border >= 0 ) top_y += BC_DisplayInfo::top_border;
3463 for( int i=0; i<xinerama_screens; ++i ) {
3464 int scr_y = top_y - xinerama_info[i].y_org;
3465 if( scr_y < 0 || scr_y >= xinerama_info[i].height ) continue;
3466 int scr_x = top_x - xinerama_info[i].x_org;
3467 if( scr_x >= 0 && scr_x < xinerama_info[i].width )
3468 return &xinerama_info[i];
3473 void BC_WindowBase::get_fullscreen_geometry(int &wx, int &wy, int &ww, int &wh)
3475 XineramaScreenInfo *info = top_level->get_xinerama_info(-1);
3477 wx = info->x_org; wy = info->y_org;
3478 ww = info->width; wh = info->height;
3481 wx = get_screen_x(0, -1);
3482 wy = get_screen_y(0, -1);
3483 int scr_w0 = get_screen_w(0, 0);
3484 int root_w = get_root_w(0);
3485 int root_h = get_root_h(0);
3486 if( root_w > scr_w0 ) { // multi-headed
3487 if( wx >= scr_w0 ) {
3488 // assumes right side is the big one
3489 ww = root_w - scr_w0;
3493 // use same aspect ratio to compute left height
3495 wh = (w*root_h) / (root_w-scr_w0);
3505 int BC_WindowBase::get_screen_x(int lock_display, int screen)
3508 if(lock_display) lock_window("BC_WindowBase::get_screen_x");
3509 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3512 int root_w = get_root_w(0);
3513 int root_h = get_root_h(0);
3514 // Shift X based on position of current window if dual head
3515 if( (float)root_w/root_h > 1.8 ) {
3516 root_w = get_screen_w(0, 0);
3517 if( top_level->get_x() >= root_w )
3522 result = info->x_org;
3523 if(lock_display) unlock_window();
3527 int BC_WindowBase::get_screen_y(int lock_display, int screen)
3529 if(lock_display) lock_window("BC_WindowBase::get_screen_y");
3530 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3531 int result = !info ? 0 : info->y_org;
3532 if(lock_display) unlock_window();
3536 int BC_WindowBase::get_screen_w(int lock_display, int screen)
3539 if(lock_display) lock_window("BC_WindowBase::get_screen_w");
3540 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3542 int width = get_root_w(0);
3543 int height = get_root_h(0);
3544 if( (float)width/height > 1.8 ) {
3545 // If dual head, the screen width is > 16x9
3546 // but we only want to fill one screen
3547 // this code assumes the "big" screen is on the right
3548 int scr_w0 = width / 2;
3550 case 600: scr_w0 = 800; break;
3551 case 720: scr_w0 = 1280; break;
3552 case 1024: scr_w0 = 1280; break;
3553 case 1200: scr_w0 = 1600; break;
3554 case 1080: scr_w0 = 1920; break;
3556 int scr_w1 = width - scr_w0;
3557 result = screen > 0 ? scr_w1 :
3558 screen == 0 ? scr_w0 :
3559 top_level->get_x() < scr_w0 ? scr_w0 : scr_w1;
3565 result = info->width;
3566 if(lock_display) unlock_window();
3570 int BC_WindowBase::get_screen_h(int lock_display, int screen)
3572 if(lock_display) lock_window("BC_WindowBase::get_screen_h");
3573 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3574 int result = info ? info->height : get_root_h(0);
3575 if(lock_display) unlock_window();
3579 // Bottom right corner
3580 int BC_WindowBase::get_x2()
3585 int BC_WindowBase::get_y2()
3590 int BC_WindowBase::get_video_on()
3595 int BC_WindowBase::get_hidden()
3597 return top_level->hidden;
3600 int BC_WindowBase::cursor_inside()
3602 return (top_level->cursor_x >= 0 &&
3603 top_level->cursor_y >= 0 &&
3604 top_level->cursor_x < w &&
3605 top_level->cursor_y < h);
3608 BC_WindowBase* BC_WindowBase::get_top_level()
3613 BC_WindowBase* BC_WindowBase::get_parent()
3615 return parent_window;
3618 int BC_WindowBase::get_color_model()
3620 return top_level->color_model;
3623 BC_Resources* BC_WindowBase::get_resources()
3625 return BC_WindowBase::resources;
3628 BC_Synchronous* BC_WindowBase::get_synchronous()
3630 return BC_WindowBase::resources->get_synchronous();
3633 int BC_WindowBase::get_bg_color()
3638 void BC_WindowBase::set_bg_color(int color)
3640 this->bg_color = color;
3643 BC_Pixmap* BC_WindowBase::get_bg_pixmap()
3648 void BC_WindowBase::set_active_subwindow(BC_WindowBase *subwindow)
3650 top_level->active_subwindow = subwindow;
3653 int BC_WindowBase::activate()
3658 int BC_WindowBase::deactivate()
3660 if(window_type == MAIN_WINDOW)
3662 if( top_level->active_menubar ) {
3663 top_level->active_menubar->deactivate();
3664 top_level->active_menubar = 0;
3666 if( top_level->active_popup_menu ) {
3667 top_level->active_popup_menu->deactivate();
3668 top_level->active_popup_menu = 0;
3670 if( top_level->active_subwindow ) {
3671 top_level->active_subwindow->deactivate();
3672 top_level->active_subwindow = 0;
3674 if( top_level->motion_events && top_level->last_motion_win == this->win )
3675 top_level->motion_events = 0;
3681 int BC_WindowBase::cycle_textboxes(int amount)
3684 BC_WindowBase *new_textbox = 0;
3688 BC_WindowBase *first_textbox = 0;
3689 find_next_textbox(&first_textbox, &new_textbox, result);
3690 if(!new_textbox) new_textbox = first_textbox;
3696 BC_WindowBase *last_textbox = 0;
3697 find_prev_textbox(&last_textbox, &new_textbox, result);
3698 if(!new_textbox) new_textbox = last_textbox;
3702 if(new_textbox != active_subwindow)
3705 new_textbox->activate();
3711 int BC_WindowBase::find_next_textbox(BC_WindowBase **first_textbox, BC_WindowBase **next_textbox, int &result)
3713 // Search subwindows for textbox
3714 for(int i = 0; i < subwindows->total && result < 2; i++)
3716 BC_WindowBase *test_subwindow = subwindows->values[i];
3717 test_subwindow->find_next_textbox(first_textbox, next_textbox, result);
3724 if(!*first_textbox) *first_textbox = this;
3728 if(top_level->active_subwindow == this)
3734 *next_textbox = this;
3741 int BC_WindowBase::find_prev_textbox(BC_WindowBase **last_textbox, BC_WindowBase **prev_textbox, int &result)
3747 if(!*last_textbox) *last_textbox = this;
3751 if(top_level->active_subwindow == this)
3757 *prev_textbox = this;
3762 // Search subwindows for textbox
3763 for(int i = subwindows->total - 1; i >= 0 && result < 2; i--)
3765 BC_WindowBase *test_subwindow = subwindows->values[i];
3766 test_subwindow->find_prev_textbox(last_textbox, prev_textbox, result);
3771 BC_Clipboard* BC_WindowBase::get_clipboard()
3773 #ifdef SINGLE_THREAD
3774 return BC_Display::display_global->clipboard;
3776 return top_level->clipboard;
3780 Atom BC_WindowBase::to_clipboard(const char *data, long len, int clipboard_num)
3782 return get_clipboard()->to_clipboard(this, data, len, clipboard_num);
3785 long BC_WindowBase::from_clipboard(char *data, long maxlen, int clipboard_num)
3787 return get_clipboard()->from_clipboard(data, maxlen, clipboard_num);
3790 long BC_WindowBase::clipboard_len(int clipboard_num)
3792 return get_clipboard()->clipboard_len(clipboard_num);
3795 int BC_WindowBase::do_selection_clear(Window win)
3797 top_level->event_win = win;
3798 return dispatch_selection_clear();
3801 int BC_WindowBase::dispatch_selection_clear()
3804 for( int i=0; i<subwindows->total && !result; ++i )
3805 result = subwindows->values[i]->dispatch_selection_clear();
3807 result = selection_clear_event();
3812 void BC_WindowBase::get_relative_cursor(int &x, int &y, int lock_window)
3814 int abs_x, abs_y, win_x, win_y;
3815 unsigned int temp_mask;
3818 if(lock_window) this->lock_window("BC_WindowBase::get_relative_cursor");
3819 XQueryPointer(top_level->display, top_level->win,
3820 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3823 XTranslateCoordinates(top_level->display, top_level->rootwin,
3824 win, abs_x, abs_y, &x, &y, &temp_win);
3825 if(lock_window) this->unlock_window();
3827 int BC_WindowBase::get_relative_cursor_x(int lock_window)
3830 get_relative_cursor(x, y, lock_window);
3833 int BC_WindowBase::get_relative_cursor_y(int lock_window)
3836 get_relative_cursor(x, y, lock_window);
3840 void BC_WindowBase::get_abs_cursor(int &abs_x, int &abs_y, int lock_window)
3843 unsigned int temp_mask;
3846 if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor");
3847 XQueryPointer(top_level->display, top_level->win,
3848 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3850 if(lock_window) this->unlock_window();
3852 int BC_WindowBase::get_abs_cursor_x(int lock_window)
3855 get_abs_cursor(abs_x, abs_y, lock_window);
3858 int BC_WindowBase::get_abs_cursor_y(int lock_window)
3861 get_abs_cursor(abs_x, abs_y, lock_window);
3865 void BC_WindowBase::get_pop_cursor(int &px, int &py, int lock_window)
3867 int xmargin = xS(100), ymargin = yS(100);
3868 get_abs_cursor(px, py, lock_window);
3869 if( px < xmargin ) px = xmargin;
3870 if( py < ymargin ) py = ymargin;
3871 int wd = get_screen_w(lock_window,-1) - xmargin;
3872 if( px > wd ) px = wd;
3873 int ht = get_screen_h(lock_window,-1) - ymargin;
3874 if( py > ht ) py = ht;
3876 int BC_WindowBase::get_pop_cursor_x(int lock_window)
3879 get_pop_cursor(px, py, lock_window);
3882 int BC_WindowBase::get_pop_cursor_y(int lock_window)
3885 get_pop_cursor(px, py, lock_window);
3889 int BC_WindowBase::match_window(Window win)
3891 if (this->win == win) return 1;
3893 for(int i = 0; i < subwindows->total; i++) {
3894 result = subwindows->values[i]->match_window(win);
3895 if (result) return result;
3901 int BC_WindowBase::get_cursor_over_window()
3903 int abs_x, abs_y, win_x, win_y;
3904 unsigned int mask_return;
3905 Window root_return, child_return;
3907 int ret = XQueryPointer(top_level->display, top_level->rootwin,
3908 &root_return, &child_return, &abs_x, &abs_y,
3909 &win_x, &win_y, &mask_return);
3910 if( ret && child_return == None ) ret = 0;
3911 if( ret && win != child_return )
3912 ret = top_level->match_window(child_return);
3913 // query pointer can return a window manager window with this top_level as a child
3914 // for kde this can be two levels deep
3915 unsigned int nchildren_return = 0;
3916 Window parent_return, *children_return = 0;
3917 Window top_win = top_level->win;
3918 while( !ret && top_win != top_level->rootwin && top_win != root_return &&
3919 XQueryTree(top_level->display, top_win, &root_return,
3920 &parent_return, &children_return, &nchildren_return) ) {
3921 if( children_return ) XFree(children_return);
3922 if( (top_win=parent_return) == child_return ) ret = 1;
3927 int BC_WindowBase::cursor_above()
3930 get_relative_cursor(rx, ry);
3931 return rx < 0 || rx >= get_w() ||
3932 ry < 0 || ry >= get_h() ? 0 : 1;
3935 int BC_WindowBase::get_drag_x()
3937 return top_level->drag_x;
3940 int BC_WindowBase::get_drag_y()
3942 return top_level->drag_y;
3945 int BC_WindowBase::get_cursor_x()
3947 return top_level->cursor_x;
3950 int BC_WindowBase::get_cursor_y()
3952 return top_level->cursor_y;
3955 int BC_WindowBase::dump_windows()
3957 printf("\tBC_WindowBase::dump_windows window=%p win=%p '%s', %dx%d+%d+%d %s\n",
3958 this, (void*)this->win, title, w,h,x,y, typeid(*this).name());
3959 for(int i = 0; i < subwindows->size(); i++)
3960 subwindows->get(i)->dump_windows();
3961 for(int i = 0; i < popups.size(); i++) {
3962 BC_WindowBase *p = popups[i];
3963 printf("\tBC_WindowBase::dump_windows popup=%p win=%p '%s', %dx%d+%d+%d %s\n",
3964 p, (void*)p->win, p->title, p->w,p->h,p->x,p->y, typeid(*p).name());
3969 int BC_WindowBase::is_event_win()
3971 return this->win == top_level->event_win;
3974 void BC_WindowBase::set_dragging(int value)
3976 is_dragging = value;
3979 int BC_WindowBase::get_dragging()
3984 int BC_WindowBase::get_buttonpress()
3986 return top_level->button_number;
3989 int BC_WindowBase::get_button_down()
3991 return top_level->button_down;
3994 int BC_WindowBase::alt_down()
3996 return top_level->alt_mask;
3999 int BC_WindowBase::shift_down()
4001 return top_level->shift_mask;
4004 int BC_WindowBase::ctrl_down()
4006 return top_level->ctrl_mask;
4009 wchar_t* BC_WindowBase::get_wkeystring(int *length)
4012 *length = top_level->wkey_string_length;
4013 return top_level->wkey_string;
4016 #ifdef X_HAVE_UTF8_STRING
4017 char* BC_WindowBase::get_keypress_utf8()
4019 return top_level->key_pressed_utf8;
4024 int BC_WindowBase::get_keypress()
4026 return top_level->key_pressed;
4029 int BC_WindowBase::get_double_click()
4031 return top_level->double_click;
4034 int BC_WindowBase::get_triple_click()
4036 return top_level->triple_click;
4039 int BC_WindowBase::get_bgcolor()
4044 int BC_WindowBase::resize_window(int w, int h)
4046 if(this->w == w && this->h == h) return 0;
4048 if(window_type == MAIN_WINDOW && !allow_resize)
4050 XSizeHints size_hints;
4051 size_hints.flags = PSize | PMinSize | PMaxSize;
4052 size_hints.width = w;
4053 size_hints.height = h;
4054 size_hints.min_width = w;
4055 size_hints.max_width = w;
4056 size_hints.min_height = h;
4057 size_hints.max_height = h;
4058 if( this->x > -BC_INFINITY && this->x < BC_INFINITY ) {
4059 size_hints.flags |= PPosition;
4060 size_hints.x = this->x;
4061 size_hints.y = this->y;
4063 XSetNormalHints(top_level->display, win, &size_hints);
4065 XResizeWindow(top_level->display, win, w, h);
4070 pixmap = new BC_Pixmap(this, w, h);
4072 // Propagate to menubar
4073 for(int i = 0; i < subwindows->total; i++)
4075 subwindows->values[i]->dispatch_resize_event(w, h);
4078 draw_background(0, 0, w, h);
4079 if(top_level == this && get_resources()->recursive_resizing)
4080 resize_history.append(new BC_ResizeCall(w, h));
4084 // The only way for resize events to be propagated is by updating the internal w and h
4085 int BC_WindowBase::resize_event(int w, int h)
4087 if(window_type == MAIN_WINDOW)
4095 int BC_WindowBase::reposition_window(int x, int y)
4097 reposition_window(x, y, -1, -1);
4102 int BC_WindowBase::reposition_window(int x, int y, int w, int h)
4106 // Some tools set their own dimensions before calling this, causing the
4107 // resize check to skip.
4111 if(w > 0 && w != this->w)
4117 if(h > 0 && h != this->h)
4123 //printf("BC_WindowBase::reposition_window %d %d %d\n", translation_count, x_correction, y_correction);
4126 printf("BC_WindowBase::reposition_window this->w == %d\n", this->w);
4128 printf("BC_WindowBase::reposition_window this->h == %d\n", this->h);
4130 if(translation_count && window_type == MAIN_WINDOW)
4132 // KDE shifts window right and down.
4133 // FVWM leaves window alone and adds border around it.
4134 XMoveResizeWindow(top_level->display, win,
4135 x - BC_DisplayInfo::auto_reposition_x,
4136 y - BC_DisplayInfo::auto_reposition_y,
4141 XMoveResizeWindow(top_level->display, win, x, y,
4148 pixmap = new BC_Pixmap(this, this->w, this->h);
4149 clear_box(0,0, this->w, this->h);
4150 // Propagate to menubar
4151 for(int i = 0; i < subwindows->total; i++)
4153 subwindows->values[i]->dispatch_resize_event(this->w, this->h);
4156 // draw_background(0, 0, w, h);
4162 int BC_WindowBase::reposition_window_relative(int dx, int dy, int w, int h)
4164 return reposition_window(get_x()+dx, get_y()+dy, w, h);
4167 int BC_WindowBase::reposition_window_relative(int dx, int dy)
4169 return reposition_window_relative(dx, dy, -1, -1);
4172 void BC_WindowBase::set_tooltips(int v)
4174 get_resources()->tooltips_enabled = v;
4177 void BC_WindowBase::set_force_tooltip(int v)
4182 int BC_WindowBase::raise_window(int do_flush)
4184 XRaiseWindow(top_level->display, win);
4185 if(do_flush) XFlush(top_level->display);
4189 int BC_WindowBase::lower_window(int do_flush)
4191 XLowerWindow(top_level->display, win);
4192 if(do_flush) XFlush(top_level->display);
4196 void BC_WindowBase::set_background(VFrame *bitmap)
4198 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
4200 bg_pixmap = new BC_Pixmap(this, bitmap, PIXMAP_OPAQUE);
4201 shared_bg_pixmap = 0;
4202 draw_background(0, 0, w, h);
4205 void BC_WindowBase::put_title(const char *text)
4207 char *cp = this->title, *ep = cp+sizeof(this->title)-1;
4208 for( const unsigned char *bp = (const unsigned char *)text; *bp && cp<ep; ++bp )
4209 *cp++ = *bp >= ' ' ? *bp : ' ';
4213 void BC_WindowBase::set_title(const char *text, int utf8)
4215 // utf8>0: wm + net_wm, utf8=0: wm only, utf<0: net_wm only
4217 const unsigned char *wm_title = (const unsigned char *)title;
4218 int title_len = strlen((const char *)title);
4220 Atom xa_wm_name = XA_WM_NAME;
4221 Atom xa_icon_name = XA_WM_ICON_NAME;
4222 Atom xa_string = XA_STRING;
4223 XChangeProperty(display, win, xa_wm_name, xa_string, 8,
4224 PropModeReplace, wm_title, title_len);
4225 XChangeProperty(display, win, xa_icon_name, xa_string, 8,
4226 PropModeReplace, wm_title, title_len);
4229 Atom xa_net_wm_name = XInternAtom(display, "_NET_WM_NAME", True);
4230 Atom xa_net_icon_name = XInternAtom(display, "_NET_WM_ICON_NAME", True);
4231 Atom xa_utf8_string = XInternAtom(display, "UTF8_STRING", True);
4232 XChangeProperty(display, win, xa_net_wm_name, xa_utf8_string, 8,
4233 PropModeReplace, wm_title, title_len);
4234 XChangeProperty(display, win, xa_net_icon_name, xa_utf8_string, 8,
4235 PropModeReplace, wm_title, title_len);
4240 const char *BC_WindowBase::get_title()
4245 int BC_WindowBase::get_toggle_value()
4247 return toggle_value;
4250 int BC_WindowBase::get_toggle_drag()
4255 int BC_WindowBase::set_icon(VFrame *data)
4257 if(icon_pixmap) delete icon_pixmap;
4258 icon_pixmap = new BC_Pixmap(top_level, data, PIXMAP_ALPHA, 1);
4260 if(icon_window) delete icon_window;
4261 icon_window = new BC_Popup(this,
4264 icon_pixmap->get_w(),
4265 icon_pixmap->get_h(),
4267 1, // All windows are hidden initially
4271 wm_hints.flags = WindowGroupHint | IconPixmapHint | IconMaskHint | IconWindowHint;
4272 wm_hints.icon_pixmap = icon_pixmap->get_pixmap();
4273 wm_hints.icon_mask = icon_pixmap->get_alpha();
4274 wm_hints.icon_window = icon_window->win;
4275 wm_hints.window_group = XGroupLeader;
4277 // for(int i = 0; i < 1000; i++)
4278 // printf("02x ", icon_pixmap->get_alpha()->get_row_pointers()[0][i]);
4281 XSetWMHints(top_level->display, top_level->win, &wm_hints);
4282 XSync(top_level->display, 0);
4286 void BC_WindowBase::init_resources(float scale)
4288 if( resources ) return;
4290 const char *env = getenv("BC_SCALE");
4291 if( env ) scale = atof(env);
4292 float x_scale = 1, y_scale = 1;
4294 BC_DisplayInfo info;
4296 int cins = info.xinerama_big_screen();
4297 if( !info.xinerama_geometry(cins, wx, wy, ww, wh) ) {
4298 if( (x_scale = ww/1920.) < 1 ) x_scale = 1;
4299 if( (y_scale = wh/1080.) < 1 ) y_scale = 1;
4303 x_scale = y_scale = scale;
4304 // constructor sets BC_WindowBase::resources
4305 new BC_Resources(x_scale, y_scale);
4307 void BC_WindowBase::finit_resources()
4309 delete resources; resources = 0;
4312 int BC_WindowBase::set_w(int w)
4318 int BC_WindowBase::set_h(int h)
4324 int BC_WindowBase::load_defaults(BC_Hash *defaults)
4326 char string[BCTEXTLEN];
4327 int newest_id = - 1;
4328 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4330 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4331 resources->filebox_history[i].path[0] = 0;
4332 defaults->get(string, resources->filebox_history[i].path);
4333 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4334 resources->filebox_history[i].id = defaults->get(string, resources->get_id());
4335 if(resources->filebox_history[i].id > newest_id)
4336 newest_id = resources->filebox_history[i].id;
4339 resources->filebox_id = newest_id + 1;
4340 resources->filebox_mode = defaults->get("FILEBOX_MODE", get_resources()->filebox_mode);
4341 resources->filebox_w = defaults->get("FILEBOX_W", get_resources()->filebox_w);
4342 resources->filebox_h = defaults->get("FILEBOX_H", get_resources()->filebox_h);
4343 resources->filebox_columntype[0] = defaults->get("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4344 resources->filebox_columntype[1] = defaults->get("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4345 resources->filebox_columntype[2] = defaults->get("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4346 resources->filebox_columntype[3] = defaults->get("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4347 resources->filebox_columnwidth[0] = defaults->get("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4348 resources->filebox_columnwidth[1] = defaults->get("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4349 resources->filebox_columnwidth[2] = defaults->get("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4350 resources->filebox_columnwidth[3] = defaults->get("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4351 resources->filebox_size_format = defaults->get("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4352 defaults->get("FILEBOX_FILTER", resources->filebox_filter);
4356 int BC_WindowBase::save_defaults(BC_Hash *defaults)
4358 char string[BCTEXTLEN];
4359 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4361 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4362 defaults->update(string, resources->filebox_history[i].path);
4363 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4364 defaults->update(string, resources->filebox_history[i].id);
4366 defaults->update("FILEBOX_MODE", resources->filebox_mode);
4367 defaults->update("FILEBOX_W", resources->filebox_w);
4368 defaults->update("FILEBOX_H", resources->filebox_h);
4369 defaults->update("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4370 defaults->update("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4371 defaults->update("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4372 defaults->update("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4373 defaults->update("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4374 defaults->update("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4375 defaults->update("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4376 defaults->update("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4377 defaults->update("FILEBOX_FILTER", resources->filebox_filter);
4378 defaults->update("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4384 // For some reason XTranslateCoordinates can take a long time to return.
4385 // We work around this by only calling it when the event windows are different.
4386 void BC_WindowBase::translate_coordinates(Window src_w, Window dest_w,
4387 int src_x, int src_y, int *dest_x_return, int *dest_y_return)
4394 *dest_x_return = src_x;
4395 *dest_y_return = src_y;
4399 XTranslateCoordinates(top_level->display, src_w, dest_w,
4400 src_x, src_y, dest_x_return, dest_y_return, &tempwin);
4401 //printf("BC_WindowBase::translate_coordinates 1 %lld\n", timer.get_difference());
4405 void BC_WindowBase::get_root_coordinates(int x, int y, int *abs_x, int *abs_y)
4407 translate_coordinates(win, top_level->rootwin, x, y, abs_x, abs_y);
4410 void BC_WindowBase::get_win_coordinates(int abs_x, int abs_y, int *x, int *y)
4412 translate_coordinates(top_level->rootwin, win, abs_x, abs_y, x, y);
4416 #ifdef HAVE_LIBXXF86VM
4417 void BC_WindowBase::closest_vm(int *vm, int *width, int *height)
4421 if(XF86VidModeQueryExtension(top_level->display,&foo,&bar)) {
4423 XF86VidModeModeInfo **vm_modelines;
4424 XF86VidModeGetAllModeLines(top_level->display,
4425 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4426 for( i = 0; i < vm_count; i++ ) {
4427 if( vm_modelines[i]->hdisplay < vm_modelines[*vm]->hdisplay &&
4428 vm_modelines[i]->hdisplay >= *width )
4431 display = top_level->display;
4432 if( vm_modelines[*vm]->hdisplay == *width )
4435 *width = vm_modelines[*vm]->hdisplay;
4436 *height = vm_modelines[*vm]->vdisplay;
4441 void BC_WindowBase::scale_vm(int vm)
4443 int foo,bar,dotclock;
4444 if( XF86VidModeQueryExtension(top_level->display,&foo,&bar) ) {
4446 XF86VidModeModeInfo **vm_modelines;
4447 XF86VidModeModeLine vml;
4448 XF86VidModeGetAllModeLines(top_level->display,
4449 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4450 XF86VidModeGetModeLine(top_level->display,
4451 XDefaultScreen(top_level->display), &dotclock,&vml);
4452 orig_modeline.dotclock = dotclock;
4453 orig_modeline.hdisplay = vml.hdisplay;
4454 orig_modeline.hsyncstart = vml.hsyncstart;
4455 orig_modeline.hsyncend = vml.hsyncend;
4456 orig_modeline.htotal = vml.htotal;
4457 orig_modeline.vdisplay = vml.vdisplay;
4458 orig_modeline.vsyncstart = vml.vsyncstart;
4459 orig_modeline.vsyncend = vml.vsyncend;
4460 orig_modeline.vtotal = vml.vtotal;
4461 orig_modeline.flags = vml.flags;
4462 orig_modeline.privsize = vml.privsize;
4463 // orig_modeline.private = vml.private;
4464 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),vm_modelines[vm]);
4465 XF86VidModeSetViewPort(top_level->display,XDefaultScreen(top_level->display),0,0);
4466 XFlush(top_level->display);
4470 void BC_WindowBase::restore_vm()
4472 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),&orig_modeline);
4473 XFlush(top_level->display);
4478 #ifndef SINGLE_THREAD
4479 int BC_WindowBase::get_event_count()
4481 event_lock->lock("BC_WindowBase::get_event_count");
4482 int result = common_events.total;
4483 event_lock->unlock();
4487 XEvent* BC_WindowBase::get_event()
4490 while(!done && !result)
4492 event_condition->lock("BC_WindowBase::get_event");
4493 event_lock->lock("BC_WindowBase::get_event");
4495 if(common_events.total && !done)
4497 result = common_events.values[0];
4498 common_events.remove_number(0);
4501 event_lock->unlock();
4506 void BC_WindowBase::put_event(XEvent *event)
4508 event_lock->lock("BC_WindowBase::put_event");
4509 common_events.append(event);
4510 event_lock->unlock();
4511 event_condition->unlock();
4514 void BC_WindowBase::dequeue_events(Window win)
4516 event_lock->lock("BC_WindowBase::dequeue_events");
4518 int out = 0, total = common_events.size();
4519 for( int in=0; in<total; ++in ) {
4520 if( common_events[in]->xany.window == win ) continue;
4521 common_events[out++] = common_events[in];
4523 common_events.total = out;
4525 event_lock->unlock();
4528 int BC_WindowBase::resend_event(BC_WindowBase *window)
4530 if( resend_event_window ) return 1;
4531 resend_event_window = window;
4537 int BC_WindowBase::resend_event(BC_WindowBase *window)
4542 #endif // SINGLE_THREAD
4544 int BC_WindowBase::get_id()
4550 BC_Pixmap *BC_WindowBase::create_pixmap(VFrame *vframe)
4552 int w = vframe->get_w(), h = vframe->get_h();
4553 BC_Pixmap *icon = new BC_Pixmap(this, w, h);
4554 icon->draw_vframe(vframe, 0,0, w,h, 0,0);
4559 void BC_WindowBase::flicker(int n, int ms)
4561 int color = get_bg_color();
4562 for( int i=2*n; --i>=0; ) {
4563 set_inverse(); set_bg_color(WHITE);
4564 clear_box(0,0, w,h); flash(1);
4565 sync_display(); Timer::delay(ms);
4567 set_bg_color(color);
4571 void BC_WindowBase::focus()
4573 XWindowAttributes xwa;
4574 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4575 if( xwa.map_state == IsViewable )
4576 XSetInputFocus(top_level->display, top_level->win, RevertToParent, CurrentTime);