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_glyphs()
2432 // draw all ascii char glyphs
2433 // There are problems with some/my graphics boards/drivers
2434 // which cause some glyphs to be munged if draws occur while
2435 // the font is being loaded. This code fills the font caches
2436 // by drawing all the ascii glyphs before the system starts.
2437 // Not a fix, but much better than nothing.
2438 static int inited = 0;
2439 if( inited ) return;
2441 int cur_font = current_font;
2442 // locale encodings, needed glyphs to be preloaded
2443 const char *text = _( // ascii 0x20...0x7e
2444 " !\"#$%&'()*+,-./0123456789:;<=>?"
2445 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
2446 "`abcdefghijklmnopqrstuvwxyz{|}~");
2447 for( int font=SMALLFONT; font<=LARGEFONT; ++font ) {
2449 draw_text(5,5, text, 0);
2454 void BC_WindowBase::init_im()
2456 XIMStyles *xim_styles;
2459 if(!(input_method = XOpenIM(display, NULL, NULL, NULL)))
2461 printf("BC_WindowBase::init_im: Could not open input method.\n");
2464 if(XGetIMValues(input_method, XNQueryInputStyle, &xim_styles, NULL) ||
2467 printf("BC_WindowBase::init_im: Input method doesn't support any styles.\n");
2468 XCloseIM(input_method);
2473 for(int z = 0; z < xim_styles->count_styles; z++)
2475 if(xim_styles->supported_styles[z] == (XIMPreeditNothing | XIMStatusNothing))
2477 xim_style = xim_styles->supported_styles[z];
2485 printf("BC_WindowBase::init_im: Input method doesn't support the style we need.\n");
2486 XCloseIM(input_method);
2490 input_context = XCreateIC(input_method, XNInputStyle, xim_style,
2491 XNClientWindow, win, XNFocusWindow, win, NULL);
2494 printf("BC_WindowBase::init_im: Failed to create input context.\n");
2495 XCloseIM(input_method);
2500 void BC_WindowBase::finit_im()
2502 if( input_context ) {
2503 XDestroyIC(input_context);
2506 if( input_method ) {
2507 XCloseIM(input_method);
2513 int BC_WindowBase::get_color(int64_t color)
2515 // return pixel of color
2516 // use this only for drawing subwindows not for bitmaps
2517 int i, test, difference;
2523 return get_color_rgb8(color);
2524 // test last color looked up
2525 if(current_color_value == color)
2526 return current_color_pixel;
2529 current_color_value = color;
2530 for(i = 0; i < total_colors; i++)
2532 if(color_table[i][0] == color)
2534 current_color_pixel = color_table[i][1];
2535 return current_color_pixel;
2539 // find nearest match
2540 difference = 0xFFFFFF;
2542 for(i = 0; i < total_colors; i++)
2544 test = abs((int)(color_table[i][0] - color));
2546 if(test < difference)
2548 current_color_pixel = color_table[i][1];
2552 return current_color_pixel;
2555 return get_color_rgb16(color);
2558 return get_color_bgr16(color);
2562 return client_byte_order == server_byte_order ?
2563 color : get_color_bgr24(color);
2571 int BC_WindowBase::get_color_rgb8(int color)
2575 pixel = (color & 0xc00000) >> 16;
2576 pixel += (color & 0xe000) >> 10;
2577 pixel += (color & 0xe0) >> 5;
2581 int64_t BC_WindowBase::get_color_rgb16(int color)
2584 result = (color & 0xf80000) >> 8;
2585 result += (color & 0xfc00) >> 5;
2586 result += (color & 0xf8) >> 3;
2591 int64_t BC_WindowBase::get_color_bgr16(int color)
2594 result = (color & 0xf80000) >> 19;
2595 result += (color & 0xfc00) >> 5;
2596 result += (color & 0xf8) << 8;
2601 int64_t BC_WindowBase::get_color_bgr24(int color)
2604 result = (color & 0xff) << 16;
2605 result += (color & 0xff00);
2606 result += (color & 0xff0000) >> 16;
2610 void BC_WindowBase::start_video()
2612 cursor_timer->update();
2614 // set_color(BLACK);
2615 // draw_box(0, 0, get_w(), get_h());
2619 void BC_WindowBase::stop_video()
2627 int64_t BC_WindowBase::get_color()
2629 return top_level->current_color;
2632 void BC_WindowBase::set_color(int64_t color)
2634 top_level->current_color = color;
2635 XSetForeground(top_level->display,
2637 top_level->get_color(color));
2640 void BC_WindowBase::set_opaque()
2642 XSetFunction(top_level->display, top_level->gc, GXcopy);
2645 void BC_WindowBase::set_inverse()
2647 XSetFunction(top_level->display, top_level->gc, GXxor);
2650 void BC_WindowBase::set_line_width(int value)
2652 this->line_width = value;
2653 XSetLineAttributes(top_level->display, top_level->gc, value, /* line_width */
2654 line_dashes == 0 ? LineSolid : LineOnOffDash, /* line_style */
2655 line_dashes == 0 ? CapRound : CapNotLast, /* cap_style */
2656 JoinMiter); /* join_style */
2658 if(line_dashes > 0) {
2659 const char dashes = line_dashes;
2660 XSetDashes(top_level->display, top_level->gc, 0, &dashes, 1);
2663 // XGCValues gcvalues;
2664 // unsigned long gcmask;
2665 // gcmask = GCCapStyle | GCJoinStyle;
2666 // XGetGCValues(top_level->display, top_level->gc, gcmask, &gcvalues);
2667 // printf("BC_WindowBase::set_line_width %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2670 void BC_WindowBase::set_line_dashes(int value)
2672 line_dashes = value;
2673 // call XSetLineAttributes
2674 set_line_width(line_width);
2678 Cursor BC_WindowBase::get_cursor_struct(int cursor)
2682 case ARROW_CURSOR: return top_level->arrow_cursor;
2683 case CROSS_CURSOR: return top_level->cross_cursor;
2684 case IBEAM_CURSOR: return top_level->ibeam_cursor;
2685 case VSEPARATE_CURSOR: return top_level->vseparate_cursor;
2686 case HSEPARATE_CURSOR: return top_level->hseparate_cursor;
2687 case MOVE_CURSOR: return top_level->move_cursor;
2688 case LEFT_CURSOR: return top_level->left_cursor;
2689 case RIGHT_CURSOR: return top_level->right_cursor;
2690 case UPRIGHT_ARROW_CURSOR: return top_level->upright_arrow_cursor;
2691 case UPLEFT_RESIZE: return top_level->upleft_resize_cursor;
2692 case UPRIGHT_RESIZE: return top_level->upright_resize_cursor;
2693 case DOWNLEFT_RESIZE: return top_level->downleft_resize_cursor;
2694 case DOWNRIGHT_RESIZE: return top_level->downright_resize_cursor;
2695 case HOURGLASS_CURSOR: return top_level->hourglass_cursor;
2696 case TRANSPARENT_CURSOR: return top_level->transparent_cursor;
2697 case GRABBED_CURSOR: return top_level->grabbed_cursor;
2702 void BC_WindowBase::set_cursor(int cursor, int override, int flush)
2704 // inherit cursor from parent
2707 XUndefineCursor(top_level->display, win);
2708 current_cursor = cursor;
2711 // don't change cursor if overridden
2712 if((!top_level->is_hourglass && !is_transparent) ||
2715 XDefineCursor(top_level->display, win, get_cursor_struct(cursor));
2716 if(flush) this->flush();
2719 if(!override) current_cursor = cursor;
2722 void BC_WindowBase::set_x_cursor(int cursor)
2724 temp_cursor = XCreateFontCursor(top_level->display, cursor);
2725 XDefineCursor(top_level->display, win, temp_cursor);
2726 current_cursor = cursor;
2730 int BC_WindowBase::get_cursor()
2732 return current_cursor;
2735 void BC_WindowBase::start_hourglass()
2737 top_level->start_hourglass_recursive();
2741 void BC_WindowBase::stop_hourglass()
2743 top_level->stop_hourglass_recursive();
2747 void BC_WindowBase::start_hourglass_recursive()
2749 if(this == top_level)
2757 set_cursor(HOURGLASS_CURSOR, 1, 0);
2758 for(int i = 0; i < subwindows->total; i++)
2760 subwindows->values[i]->start_hourglass_recursive();
2765 void BC_WindowBase::stop_hourglass_recursive()
2767 if(this == top_level)
2769 if(hourglass_total == 0) return;
2770 top_level->hourglass_total--;
2773 if(!top_level->hourglass_total)
2775 top_level->is_hourglass = 0;
2777 // Cause set_cursor to perform change
2779 set_cursor(current_cursor, 1, 0);
2781 for(int i = 0; i < subwindows->total; i++)
2783 subwindows->values[i]->stop_hourglass_recursive();
2791 XFontStruct* BC_WindowBase::get_font_struct(int font)
2793 // Clear out unrelated flags
2794 if(font & BOLDFACE) font ^= BOLDFACE;
2797 case SMALLFONT: return top_level->smallfont; break;
2798 case MEDIUMFONT: return top_level->mediumfont; break;
2799 case LARGEFONT: return top_level->largefont; break;
2800 case BIGFONT: return top_level->bigfont; break;
2801 case CLOCKFONT: return top_level->clockfont; break;
2806 XFontSet BC_WindowBase::get_fontset(int font)
2810 if(get_resources()->use_fontset)
2812 switch(font & 0xff) {
2813 case SMALLFONT: fs = top_level->smallfontset; break;
2814 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2815 case LARGEFONT: fs = top_level->largefontset; break;
2816 case BIGFONT: fs = top_level->bigfontset; break;
2817 case CLOCKFONT: fs = top_level->clockfontset; break;
2825 XftFont* BC_WindowBase::get_xft_struct(int font)
2828 case SMALLFONT: return (XftFont*)top_level->smallfont_xft;
2829 case MEDIUMFONT: return (XftFont*)top_level->mediumfont_xft;
2830 case LARGEFONT: return (XftFont*)top_level->largefont_xft;
2831 case BIGFONT: return (XftFont*)top_level->bigfont_xft;
2832 case CLOCKFONT: return (XftFont*)top_level->clockfont_xft;
2833 case MEDIUMFONT_3D: return (XftFont*)top_level->bold_mediumfont_xft;
2834 case SMALLFONT_3D: return (XftFont*)top_level->bold_smallfont_xft;
2835 case LARGEFONT_3D: return (XftFont*)top_level->bold_largefont_xft;
2843 int BC_WindowBase::get_current_font()
2845 return top_level->current_font;
2848 void BC_WindowBase::set_font(int font)
2850 top_level->current_font = font;
2853 if(get_resources()->use_xft) {}
2856 if(get_resources()->use_fontset) {
2860 if(get_font_struct(font))
2862 XSetFont(top_level->display, top_level->gc, get_font_struct(font)->fid);
2868 void BC_WindowBase::set_fontset(int font)
2872 if(get_resources()->use_fontset) {
2874 case SMALLFONT: fs = top_level->smallfontset; break;
2875 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2876 case LARGEFONT: fs = top_level->largefontset; break;
2877 case BIGFONT: fs = top_level->bigfontset; break;
2878 case CLOCKFONT: fs = top_level->clockfontset; break;
2886 XFontSet BC_WindowBase::get_curr_fontset(void)
2888 if(get_resources()->use_fontset)
2889 return curr_fontset;
2893 int BC_WindowBase::get_single_text_width(int font, const char *text, int length)
2896 if(get_resources()->use_xft && get_xft_struct(font))
2899 #ifdef X_HAVE_UTF8_STRING
2900 if(get_resources()->locale_utf8)
2902 xftTextExtentsUtf8(top_level->display,
2903 get_xft_struct(font),
2904 (const XftChar8 *)text,
2911 xftTextExtents8(top_level->display,
2912 get_xft_struct(font),
2913 (const XftChar8 *)text,
2917 return extents.xOff;
2921 if(get_resources()->use_fontset && top_level->get_fontset(font))
2922 return XmbTextEscapement(top_level->get_fontset(font), text, length);
2924 if(get_font_struct(font))
2925 return XTextWidth(get_font_struct(font), text, length);
2931 case MEDIUM_7SEGMENT:
2932 return get_resources()->medium_7segment[0]->get_w() * length;
2942 int BC_WindowBase::get_text_width(int font, const char *text, int length)
2944 int i, j, w = 0, line_w = 0;
2945 if(length < 0) length = strlen(text);
2947 for(i = 0, j = 0; i <= length; i++)
2952 line_w = get_single_text_width(font, &text[j], i - j);
2958 line_w = get_single_text_width(font, &text[j], length - j);
2960 if(line_w > w) w = line_w;
2963 if(i > length && w == 0)
2965 w = get_single_text_width(font, text, length);
2971 int BC_WindowBase::get_text_width(int font, const wchar_t *text, int length)
2974 if( length < 0 ) length = wcslen(text);
2976 for( i=j=0; i<length && text[i]; ++i ) {
2977 if( text[i] != '\n' ) continue;
2979 int lw = get_single_text_width(font, &text[j], i-j);
2980 if( w < lw ) w = lw;
2985 int lw = get_single_text_width(font, &text[j], length-j);
2986 if( w < lw ) w = lw;
2992 int BC_WindowBase::get_text_ascent(int font)
2996 if( (fstruct = get_xft_struct(font)) != 0 )
2997 return fstruct->ascent;
2999 if(get_resources()->use_fontset && top_level->get_fontset(font))
3001 XFontSetExtents *extents;
3003 extents = XExtentsOfFontSet(top_level->get_fontset(font));
3004 return -extents->max_logical_extent.y;
3007 if(get_font_struct(font))
3008 return top_level->get_font_struct(font)->ascent;
3011 case MEDIUM_7SEGMENT:
3012 return get_resources()->medium_7segment[0]->get_h();
3017 int BC_WindowBase::get_text_descent(int font)
3021 if( (fstruct = get_xft_struct(font)) != 0 )
3022 return fstruct->descent;
3024 if(get_resources()->use_fontset && top_level->get_fontset(font)) {
3025 XFontSetExtents *extents;
3026 extents = XExtentsOfFontSet(top_level->get_fontset(font));
3027 return (extents->max_logical_extent.height
3028 + extents->max_logical_extent.y);
3031 if(get_font_struct(font))
3032 return top_level->get_font_struct(font)->descent;
3037 int BC_WindowBase::get_text_height(int font, const char *text)
3042 if( (fstruct = get_xft_struct(font)) != 0 )
3043 rowh = fstruct->height;
3046 rowh = get_text_ascent(font) + get_text_descent(font);
3048 if(!text) return rowh;
3050 // Add height of lines
3051 int h = 0, i, length = strlen(text);
3052 for(i = 0; i <= length; i++)
3063 // truncate the text with ... & return a new string
3064 char *BC_WindowBase::get_truncated_text(int font, const char *text, int max_w)
3066 char *result = cstrdup(text);
3067 int text_w = get_text_width(font, text);
3068 int ci = -1, len = strlen(text);
3069 if( text_w > max_w ) {
3070 // get center of string
3071 int cx = text_w/2, best = INT_MAX;
3072 for( int i=1; i<=len; ++i ) {
3073 int cw = get_text_width(font, text, i);
3074 if( abs(cw-cx) < abs(best-cx) ) {
3079 if( ci > 0 && ci < len-1 ) {
3080 // insert ... in the center
3081 result[ci-1] = result[ci] = result[ci+1] = '.';
3083 while( ci-2>=0 && ci+2<(int)strlen(result) &&
3084 get_text_width(font, result) > max_w ) {
3085 // take away a character from the longer side
3086 int left_w = get_text_width(font, result, ci-2);
3087 int right_w = get_text_width(font, result + ci+3);
3088 int i = left_w > right_w ? --ci-1 : ci+2;
3089 while( (result[i]=result[i+1])!=0 ) ++i;
3096 BC_Bitmap* BC_WindowBase::new_bitmap(int w, int h, int color_model)
3098 if(color_model < 0) color_model = top_level->get_color_model();
3099 return new BC_Bitmap(top_level, w, h, color_model);
3102 void BC_WindowBase::init_wait()
3104 #ifndef SINGLE_THREAD
3105 if(window_type != MAIN_WINDOW)
3106 top_level->init_wait();
3107 init_lock->lock("BC_WindowBase::init_wait");
3108 init_lock->unlock();
3112 int BC_WindowBase::accel_available(int color_model, int lock_it)
3114 if( window_type != MAIN_WINDOW )
3115 return top_level->accel_available(color_model, lock_it);
3117 lock_window("BC_WindowBase::accel_available");
3119 switch(color_model) {
3121 grab_port_id(color_model);
3125 grab_port_id(color_model);
3134 //printf("BC_WindowBase::accel_available %d %d\n", color_model, xvideo_port_id);
3135 return xvideo_port_id >= 0 ? 1 : 0;
3139 int BC_WindowBase::grab_port_id(int color_model)
3141 if( !get_resources()->use_xvideo || // disabled
3142 !get_resources()->use_shm ) // Only local server is fast enough.
3144 if( xvideo_port_id >= 0 )
3145 return xvideo_port_id;
3147 unsigned int ver, rev, reqBase, eventBase, errorBase;
3148 if( Success != XvQueryExtension(display, // XV extension is available
3149 &ver, &rev, &reqBase, &eventBase, &errorBase) )
3152 // XV adaptors are available
3153 unsigned int numAdapt = 0;
3154 XvAdaptorInfo *info = 0;
3155 XvQueryAdaptors(display, DefaultRootWindow(display), &numAdapt, &info);
3159 // Translate from color_model to X color model
3160 int x_color_model = BC_CModels::bc_to_x(color_model);
3162 // Get adaptor with desired color model
3163 for( int i = 0; i < (int)numAdapt && xvideo_port_id == -1; i++) {
3164 if( !(info[i].type & XvImageMask) || !info[i].num_ports ) continue;
3165 // adaptor supports XvImages
3166 int numFormats = 0, numPorts = info[i].num_ports;
3167 XvImageFormatValues *formats =
3168 XvListImageFormats(display, info[i].base_id, &numFormats);
3169 if( !formats ) continue;
3171 for( int j=0; j<numFormats && xvideo_port_id<0; ++j ) {
3172 if( formats[j].id != x_color_model ) continue;
3173 // this adaptor supports the desired format, grab a port
3174 for( int k=0; k<numPorts; ++k ) {
3175 if( Success == XvGrabPort(top_level->display,
3176 info[i].base_id+k, CurrentTime) ) {
3177 //printf("BC_WindowBase::grab_port_id %llx\n", info[i].base_id);
3178 xvideo_port_id = info[i].base_id + k;
3186 XvFreeAdaptorInfo(info);
3188 return xvideo_port_id;
3192 int BC_WindowBase::show_window(int flush)
3194 for(int i = 0; i < subwindows->size(); i++)
3196 subwindows->get(i)->show_window(0);
3199 XMapWindow(top_level->display, win);
3200 if(flush) XFlush(top_level->display);
3201 // XSync(top_level->display, 0);
3206 int BC_WindowBase::hide_window(int flush)
3208 for(int i = 0; i < subwindows->size(); i++)
3210 subwindows->get(i)->hide_window(0);
3213 XUnmapWindow(top_level->display, win);
3214 if(flush) this->flush();
3219 BC_MenuBar* BC_WindowBase::add_menubar(BC_MenuBar *menu_bar)
3221 subwindows->append((BC_SubWindow*)menu_bar);
3223 menu_bar->parent_window = this;
3224 menu_bar->top_level = this->top_level;
3225 menu_bar->initialize();
3229 BC_WindowBase* BC_WindowBase::add_popup(BC_WindowBase *window)
3231 //printf("BC_WindowBase::add_popup window=%p win=%p\n", window, window->win);
3232 if(this != top_level) return top_level->add_popup(window);
3233 popups.append(window);
3237 void BC_WindowBase::remove_popup(BC_WindowBase *window)
3239 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3240 if(this != top_level)
3241 top_level->remove_popup(window);
3243 popups.remove(window);
3244 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3248 BC_WindowBase* BC_WindowBase::add_subwindow(BC_WindowBase *subwindow)
3250 subwindows->append(subwindow);
3252 if(subwindow->bg_color == -1) subwindow->bg_color = this->bg_color;
3254 // parent window must be set before the subwindow initialization
3255 subwindow->parent_window = this;
3256 subwindow->top_level = this->top_level;
3258 // Execute derived initialization
3259 subwindow->initialize();
3264 BC_WindowBase* BC_WindowBase::add_tool(BC_WindowBase *subwindow)
3266 return add_subwindow(subwindow);
3269 int BC_WindowBase::flash(int x, int y, int w, int h, int flush)
3271 if( !top_level->flash_enabled ) return 0;
3272 //printf("BC_WindowBase::flash %d %d %d %d %d\n", __LINE__, w, h, this->w, this->h);
3274 XSetWindowBackgroundPixmap(top_level->display, win, pixmap->opaque_pixmap);
3277 XClearArea(top_level->display, win, x, y, w, h, 0);
3281 XClearWindow(top_level->display, win);
3289 int BC_WindowBase::flash(int flush)
3291 flash(-1, -1, -1, -1, flush);
3295 void BC_WindowBase::flush()
3297 //if(!get_window_lock())
3298 // printf("BC_WindowBase::flush %s not locked\n", top_level->title);
3299 // X gets hosed if Flush/Sync are not user locked (at libX11-1.1.5 / libxcb-1.1.91)
3300 // _XReply deadlocks in condition_wait waiting for xlib lock when waiters!=-1
3301 int locked = get_window_lock();
3302 if( !locked ) lock_window("BC_WindowBase::flush");
3303 XFlush(top_level->display);
3304 if( !locked ) unlock_window();
3307 void BC_WindowBase::sync_display()
3309 int locked = get_window_lock();
3310 if( !locked ) lock_window("BC_WindowBase::sync_display");
3311 XSync(top_level->display, False);
3312 if( !locked ) unlock_window();
3315 int BC_WindowBase::get_window_lock()
3317 #ifdef SINGLE_THREAD
3318 return BC_Display::display_global->get_display_locked();
3320 return top_level->window_lock;
3324 int BC_WindowBase::lock_window(const char *location)
3326 if(top_level && top_level != this)
3328 top_level->lock_window(location);
3333 SET_LOCK(this, title, location);
3334 #ifdef SINGLE_THREAD
3335 BC_Display::lock_display(location);
3337 XLockDisplay(top_level->display);
3338 top_level->display_lock_owner = pthread_self();
3341 ++top_level->window_lock;
3345 printf("BC_WindowBase::lock_window top_level NULL\n");
3350 int BC_WindowBase::unlock_window()
3352 if(top_level && top_level != this)
3354 top_level->unlock_window();
3360 if( !top_level->window_lock ) {
3361 printf("BC_WindowBase::unlock_window %s not locked\n", title);
3364 if( top_level->window_lock > 0 )
3365 if( --top_level->window_lock == 0 )
3366 top_level->display_lock_owner = 0;
3367 #ifdef SINGLE_THREAD
3368 BC_Display::unlock_display();
3370 XUnlockDisplay(top_level->display);
3375 printf("BC_WindowBase::unlock_window top_level NULL\n");
3380 int BC_WindowBase::break_lock()
3382 if( !top_level ) return 0;
3383 if( top_level != this ) return top_level->break_lock();
3384 if( top_level->display_lock_owner != pthread_self() ) return 0;
3385 if( top_level->window_lock != 1 ) return 0;
3388 display_lock_owner = 0;
3389 #ifdef SINGLE_THREAD
3390 BC_Display::unlock_display();
3392 XUnlockDisplay(display);
3397 void BC_WindowBase::set_done(int return_value)
3399 if(done_set) return;
3401 if(window_type != MAIN_WINDOW)
3402 top_level->set_done(return_value);
3405 #ifdef SINGLE_THREAD
3406 this->return_value = return_value;
3407 BC_Display::display_global->arm_completion(this);
3408 completion_lock->unlock();
3409 #else // SINGLE_THREAD
3411 if( !event_thread ) return;
3412 XEvent *event = new_xevent();
3413 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
3414 event->type = ClientMessage;
3415 ptr->message_type = SetDoneXAtom;
3417 this->return_value = return_value;
3418 // May lock up here because XSendEvent doesn't work too well
3419 // asynchronous with XNextEvent.
3420 // This causes BC_WindowEvents to forward a copy of the event to run_window where
3422 // Deletion of event_thread is done at the end of BC_WindowBase::run_window() - by calling the destructor
3428 void BC_WindowBase::close(int return_value)
3430 hide_window(); flush();
3431 set_done(return_value);
3434 int BC_WindowBase::grab(BC_WindowBase *window)
3436 if( window->active_grab && this != window->active_grab ) return 0;
3437 window->active_grab = this;
3438 this->grab_active = window;
3441 int BC_WindowBase::ungrab(BC_WindowBase *window)
3443 if( window->active_grab && this != window->active_grab ) return 0;
3444 window->active_grab = 0;
3445 this->grab_active = 0;
3448 int BC_WindowBase::grab_event_count()
3451 #ifndef SINGLE_THREAD
3452 result = grab_active->get_event_count();
3456 int BC_WindowBase::grab_buttons()
3458 XSync(top_level->display, False);
3459 if( XGrabButton(top_level->display, AnyButton, AnyModifier,
3460 top_level->rootwin, True, ButtonPressMask | ButtonReleaseMask,
3461 GrabModeAsync, GrabModeSync, None, None) == GrabSuccess ) {
3462 set_active_subwindow(this);
3467 void BC_WindowBase::ungrab_buttons()
3469 XUngrabButton(top_level->display, AnyButton, AnyModifier, top_level->rootwin);
3470 set_active_subwindow(0);
3473 void BC_WindowBase::grab_cursor()
3475 Cursor cursor_grab = get_cursor_struct(GRABBED_CURSOR);
3476 XGrabPointer(top_level->display, top_level->rootwin, True,
3477 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
3478 GrabModeAsync, GrabModeAsync, None, cursor_grab, CurrentTime);
3480 void BC_WindowBase::ungrab_cursor()
3482 XUngrabPointer(top_level->display, CurrentTime);
3486 // WidthOfScreen/HeightOfScreen of XDefaultScreenOfDisplay
3487 // this is the bounding box of all the screens
3489 int BC_WindowBase::get_root_w(int lock_display)
3491 if(lock_display) lock_window("BC_WindowBase::get_root_w");
3492 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3493 int result = WidthOfScreen(def_screen);
3494 if(lock_display) unlock_window();
3498 int BC_WindowBase::get_root_h(int lock_display)
3500 if(lock_display) lock_window("BC_WindowBase::get_root_h");
3501 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3502 int result = HeightOfScreen(def_screen);
3503 if(lock_display) unlock_window();
3507 XineramaScreenInfo *
3508 BC_WindowBase::get_xinerama_info(int screen)
3510 if( !xinerama_info || !xinerama_screens ) return 0;
3512 for( int i=0; i<xinerama_screens; ++i )
3513 if( xinerama_info[i].screen_number == screen )
3514 return &xinerama_info[i];
3517 int top_x = get_x(), top_y = get_y();
3518 if( BC_DisplayInfo::left_border >= 0 ) top_x += BC_DisplayInfo::left_border;
3519 if( BC_DisplayInfo::top_border >= 0 ) top_y += BC_DisplayInfo::top_border;
3520 for( int i=0; i<xinerama_screens; ++i ) {
3521 int scr_y = top_y - xinerama_info[i].y_org;
3522 if( scr_y < 0 || scr_y >= xinerama_info[i].height ) continue;
3523 int scr_x = top_x - xinerama_info[i].x_org;
3524 if( scr_x >= 0 && scr_x < xinerama_info[i].width )
3525 return &xinerama_info[i];
3530 void BC_WindowBase::get_fullscreen_geometry(int &wx, int &wy, int &ww, int &wh)
3532 XineramaScreenInfo *info = top_level->get_xinerama_info(-1);
3534 wx = info->x_org; wy = info->y_org;
3535 ww = info->width; wh = info->height;
3538 wx = get_screen_x(0, -1);
3539 wy = get_screen_y(0, -1);
3540 int scr_w0 = get_screen_w(0, 0);
3541 int root_w = get_root_w(0);
3542 int root_h = get_root_h(0);
3543 if( root_w > scr_w0 ) { // multi-headed
3544 if( wx >= scr_w0 ) {
3545 // assumes right side is the big one
3546 ww = root_w - scr_w0;
3550 // use same aspect ratio to compute left height
3552 wh = (w*root_h) / (root_w-scr_w0);
3562 int BC_WindowBase::get_screen_x(int lock_display, int screen)
3565 if(lock_display) lock_window("BC_WindowBase::get_screen_x");
3566 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3569 int root_w = get_root_w(0);
3570 int root_h = get_root_h(0);
3571 // Shift X based on position of current window if dual head
3572 if( (float)root_w/root_h > 1.8 ) {
3573 root_w = get_screen_w(0, 0);
3574 if( top_level->get_x() >= root_w )
3579 result = info->x_org;
3580 if(lock_display) unlock_window();
3584 int BC_WindowBase::get_screen_y(int lock_display, int screen)
3586 if(lock_display) lock_window("BC_WindowBase::get_screen_y");
3587 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3588 int result = !info ? 0 : info->y_org;
3589 if(lock_display) unlock_window();
3593 int BC_WindowBase::get_screen_w(int lock_display, int screen)
3596 if(lock_display) lock_window("BC_WindowBase::get_screen_w");
3597 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3599 int width = get_root_w(0);
3600 int height = get_root_h(0);
3601 if( (float)width/height > 1.8 ) {
3602 // If dual head, the screen width is > 16x9
3603 // but we only want to fill one screen
3604 // this code assumes the "big" screen is on the right
3605 int scr_w0 = width / 2;
3607 case 600: scr_w0 = 800; break;
3608 case 720: scr_w0 = 1280; break;
3609 case 1024: scr_w0 = 1280; break;
3610 case 1200: scr_w0 = 1600; break;
3611 case 1080: scr_w0 = 1920; break;
3613 int scr_w1 = width - scr_w0;
3614 result = screen > 0 ? scr_w1 :
3615 screen == 0 ? scr_w0 :
3616 top_level->get_x() < scr_w0 ? scr_w0 : scr_w1;
3622 result = info->width;
3623 if(lock_display) unlock_window();
3627 int BC_WindowBase::get_screen_h(int lock_display, int screen)
3629 if(lock_display) lock_window("BC_WindowBase::get_screen_h");
3630 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3631 int result = info ? info->height : get_root_h(0);
3632 if(lock_display) unlock_window();
3636 // Bottom right corner
3637 int BC_WindowBase::get_x2()
3642 int BC_WindowBase::get_y2()
3647 int BC_WindowBase::get_video_on()
3652 int BC_WindowBase::get_hidden()
3654 return top_level->hidden;
3657 int BC_WindowBase::cursor_inside()
3659 return (top_level->cursor_x >= 0 &&
3660 top_level->cursor_y >= 0 &&
3661 top_level->cursor_x < w &&
3662 top_level->cursor_y < h);
3665 BC_WindowBase* BC_WindowBase::get_top_level()
3670 BC_WindowBase* BC_WindowBase::get_parent()
3672 return parent_window;
3675 int BC_WindowBase::get_color_model()
3677 return top_level->color_model;
3680 BC_Resources* BC_WindowBase::get_resources()
3682 return BC_WindowBase::resources;
3685 BC_Synchronous* BC_WindowBase::get_synchronous()
3687 return BC_WindowBase::resources->get_synchronous();
3690 int BC_WindowBase::get_bg_color()
3695 void BC_WindowBase::set_bg_color(int color)
3697 this->bg_color = color;
3700 BC_Pixmap* BC_WindowBase::get_bg_pixmap()
3705 void BC_WindowBase::set_active_subwindow(BC_WindowBase *subwindow)
3707 top_level->active_subwindow = subwindow;
3710 int BC_WindowBase::activate()
3715 int BC_WindowBase::deactivate()
3717 if(window_type == MAIN_WINDOW)
3719 if( top_level->active_menubar ) {
3720 top_level->active_menubar->deactivate();
3721 top_level->active_menubar = 0;
3723 if( top_level->active_popup_menu ) {
3724 top_level->active_popup_menu->deactivate();
3725 top_level->active_popup_menu = 0;
3727 if( top_level->active_subwindow ) {
3728 top_level->active_subwindow->deactivate();
3729 top_level->active_subwindow = 0;
3731 if( top_level->motion_events && top_level->last_motion_win == this->win )
3732 top_level->motion_events = 0;
3738 int BC_WindowBase::cycle_textboxes(int amount)
3741 BC_WindowBase *new_textbox = 0;
3745 BC_WindowBase *first_textbox = 0;
3746 find_next_textbox(&first_textbox, &new_textbox, result);
3747 if(!new_textbox) new_textbox = first_textbox;
3753 BC_WindowBase *last_textbox = 0;
3754 find_prev_textbox(&last_textbox, &new_textbox, result);
3755 if(!new_textbox) new_textbox = last_textbox;
3759 if(new_textbox != active_subwindow)
3762 new_textbox->activate();
3768 int BC_WindowBase::find_next_textbox(BC_WindowBase **first_textbox, BC_WindowBase **next_textbox, int &result)
3770 // Search subwindows for textbox
3771 for(int i = 0; i < subwindows->total && result < 2; i++)
3773 BC_WindowBase *test_subwindow = subwindows->values[i];
3774 test_subwindow->find_next_textbox(first_textbox, next_textbox, result);
3781 if(!*first_textbox) *first_textbox = this;
3785 if(top_level->active_subwindow == this)
3791 *next_textbox = this;
3798 int BC_WindowBase::find_prev_textbox(BC_WindowBase **last_textbox, BC_WindowBase **prev_textbox, int &result)
3804 if(!*last_textbox) *last_textbox = this;
3808 if(top_level->active_subwindow == this)
3814 *prev_textbox = this;
3819 // Search subwindows for textbox
3820 for(int i = subwindows->total - 1; i >= 0 && result < 2; i--)
3822 BC_WindowBase *test_subwindow = subwindows->values[i];
3823 test_subwindow->find_prev_textbox(last_textbox, prev_textbox, result);
3828 BC_Clipboard* BC_WindowBase::get_clipboard()
3830 #ifdef SINGLE_THREAD
3831 return BC_Display::display_global->clipboard;
3833 return top_level->clipboard;
3837 Atom BC_WindowBase::to_clipboard(const char *data, long len, int clipboard_num)
3839 return get_clipboard()->to_clipboard(this, data, len, clipboard_num);
3842 long BC_WindowBase::from_clipboard(char *data, long maxlen, int clipboard_num)
3844 return get_clipboard()->from_clipboard(data, maxlen, clipboard_num);
3847 long BC_WindowBase::clipboard_len(int clipboard_num)
3849 return get_clipboard()->clipboard_len(clipboard_num);
3852 int BC_WindowBase::do_selection_clear(Window win)
3854 top_level->event_win = win;
3855 return dispatch_selection_clear();
3858 int BC_WindowBase::dispatch_selection_clear()
3861 for( int i=0; i<subwindows->total && !result; ++i )
3862 result = subwindows->values[i]->dispatch_selection_clear();
3864 result = selection_clear_event();
3869 void BC_WindowBase::get_relative_cursor(int &x, int &y, int lock_window)
3871 int abs_x, abs_y, win_x, win_y;
3872 unsigned int temp_mask;
3875 if(lock_window) this->lock_window("BC_WindowBase::get_relative_cursor");
3876 XQueryPointer(top_level->display, top_level->win,
3877 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3880 XTranslateCoordinates(top_level->display, top_level->rootwin,
3881 win, abs_x, abs_y, &x, &y, &temp_win);
3882 if(lock_window) this->unlock_window();
3884 int BC_WindowBase::get_relative_cursor_x(int lock_window)
3887 get_relative_cursor(x, y, lock_window);
3890 int BC_WindowBase::get_relative_cursor_y(int lock_window)
3893 get_relative_cursor(x, y, lock_window);
3897 void BC_WindowBase::get_abs_cursor(int &abs_x, int &abs_y, int lock_window)
3900 unsigned int temp_mask;
3903 if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor");
3904 XQueryPointer(top_level->display, top_level->win,
3905 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3907 if(lock_window) this->unlock_window();
3909 int BC_WindowBase::get_abs_cursor_x(int lock_window)
3912 get_abs_cursor(abs_x, abs_y, lock_window);
3915 int BC_WindowBase::get_abs_cursor_y(int lock_window)
3918 get_abs_cursor(abs_x, abs_y, lock_window);
3922 void BC_WindowBase::get_pop_cursor(int &px, int &py, int lock_window)
3924 int xmargin = xS(100), ymargin = yS(100);
3925 get_abs_cursor(px, py, lock_window);
3926 if( px < xmargin ) px = xmargin;
3927 if( py < ymargin ) py = ymargin;
3928 int wd = get_screen_w(lock_window,-1) - xmargin;
3929 if( px > wd ) px = wd;
3930 int ht = get_screen_h(lock_window,-1) - ymargin;
3931 if( py > ht ) py = ht;
3933 int BC_WindowBase::get_pop_cursor_x(int lock_window)
3936 get_pop_cursor(px, py, lock_window);
3939 int BC_WindowBase::get_pop_cursor_y(int lock_window)
3942 get_pop_cursor(px, py, lock_window);
3946 int BC_WindowBase::match_window(Window win)
3948 if (this->win == win) return 1;
3950 for(int i = 0; i < subwindows->total; i++) {
3951 result = subwindows->values[i]->match_window(win);
3952 if (result) return result;
3958 int BC_WindowBase::get_cursor_over_window()
3960 int abs_x, abs_y, win_x, win_y;
3961 unsigned int mask_return;
3962 Window root_return, child_return;
3964 int ret = XQueryPointer(top_level->display, top_level->rootwin,
3965 &root_return, &child_return, &abs_x, &abs_y,
3966 &win_x, &win_y, &mask_return);
3967 if( ret && child_return == None ) ret = 0;
3968 if( ret && win != child_return )
3969 ret = top_level->match_window(child_return);
3970 // query pointer can return a window manager window with this top_level as a child
3971 // for kde this can be two levels deep
3972 unsigned int nchildren_return = 0;
3973 Window parent_return, *children_return = 0;
3974 Window top_win = top_level->win;
3975 while( !ret && top_win != top_level->rootwin && top_win != root_return &&
3976 XQueryTree(top_level->display, top_win, &root_return,
3977 &parent_return, &children_return, &nchildren_return) ) {
3978 if( children_return ) XFree(children_return);
3979 if( (top_win=parent_return) == child_return ) ret = 1;
3984 int BC_WindowBase::cursor_above()
3987 get_relative_cursor(rx, ry);
3988 return rx < 0 || rx >= get_w() ||
3989 ry < 0 || ry >= get_h() ? 0 : 1;
3992 int BC_WindowBase::get_drag_x()
3994 return top_level->drag_x;
3997 int BC_WindowBase::get_drag_y()
3999 return top_level->drag_y;
4002 int BC_WindowBase::get_cursor_x()
4004 return top_level->cursor_x;
4007 int BC_WindowBase::get_cursor_y()
4009 return top_level->cursor_y;
4012 int BC_WindowBase::dump_windows()
4014 printf("\tBC_WindowBase::dump_windows window=%p win=%p '%s', %dx%d+%d+%d %s\n",
4015 this, (void*)this->win, title, w,h,x,y, typeid(*this).name());
4016 for(int i = 0; i < subwindows->size(); i++)
4017 subwindows->get(i)->dump_windows();
4018 for(int i = 0; i < popups.size(); i++) {
4019 BC_WindowBase *p = popups[i];
4020 printf("\tBC_WindowBase::dump_windows popup=%p win=%p '%s', %dx%d+%d+%d %s\n",
4021 p, (void*)p->win, p->title, p->w,p->h,p->x,p->y, typeid(*p).name());
4026 int BC_WindowBase::is_event_win()
4028 return this->win == top_level->event_win;
4031 void BC_WindowBase::set_dragging(int value)
4033 is_dragging = value;
4036 int BC_WindowBase::get_dragging()
4041 int BC_WindowBase::get_buttonpress()
4043 return top_level->button_number;
4046 int BC_WindowBase::get_button_down()
4048 return top_level->button_down;
4051 int BC_WindowBase::alt_down()
4053 return top_level->alt_mask;
4056 int BC_WindowBase::shift_down()
4058 return top_level->shift_mask;
4061 int BC_WindowBase::ctrl_down()
4063 return top_level->ctrl_mask;
4066 wchar_t* BC_WindowBase::get_wkeystring(int *length)
4069 *length = top_level->wkey_string_length;
4070 return top_level->wkey_string;
4073 #ifdef X_HAVE_UTF8_STRING
4074 char* BC_WindowBase::get_keypress_utf8()
4076 return top_level->key_pressed_utf8;
4081 int BC_WindowBase::get_keypress()
4083 return top_level->key_pressed;
4086 int BC_WindowBase::get_double_click()
4088 return top_level->double_click;
4091 int BC_WindowBase::get_triple_click()
4093 return top_level->triple_click;
4096 int BC_WindowBase::get_bgcolor()
4101 int BC_WindowBase::resize_window(int w, int h)
4103 if(this->w == w && this->h == h) return 0;
4105 if(window_type == MAIN_WINDOW && !allow_resize)
4107 XSizeHints size_hints;
4108 size_hints.flags = PSize | PMinSize | PMaxSize;
4109 size_hints.width = w;
4110 size_hints.height = h;
4111 size_hints.min_width = w;
4112 size_hints.max_width = w;
4113 size_hints.min_height = h;
4114 size_hints.max_height = h;
4115 if( this->x > -BC_INFINITY && this->x < BC_INFINITY ) {
4116 size_hints.flags |= PPosition;
4117 size_hints.x = this->x;
4118 size_hints.y = this->y;
4120 XSetNormalHints(top_level->display, win, &size_hints);
4122 XResizeWindow(top_level->display, win, w, h);
4127 pixmap = new BC_Pixmap(this, w, h);
4129 // Propagate to menubar
4130 for(int i = 0; i < subwindows->total; i++)
4132 subwindows->values[i]->dispatch_resize_event(w, h);
4135 draw_background(0, 0, w, h);
4136 if(top_level == this && get_resources()->recursive_resizing)
4137 resize_history.append(new BC_ResizeCall(w, h));
4141 // The only way for resize events to be propagated is by updating the internal w and h
4142 int BC_WindowBase::resize_event(int w, int h)
4144 if(window_type == MAIN_WINDOW)
4152 int BC_WindowBase::reposition_window(int x, int y)
4154 reposition_window(x, y, -1, -1);
4159 int BC_WindowBase::reposition_window(int x, int y, int w, int h)
4163 // Some tools set their own dimensions before calling this, causing the
4164 // resize check to skip.
4168 if(w > 0 && w != this->w)
4174 if(h > 0 && h != this->h)
4180 //printf("BC_WindowBase::reposition_window %d %d %d\n", translation_count, x_correction, y_correction);
4183 printf("BC_WindowBase::reposition_window this->w == %d\n", this->w);
4185 printf("BC_WindowBase::reposition_window this->h == %d\n", this->h);
4187 if(translation_count && window_type == MAIN_WINDOW)
4189 // KDE shifts window right and down.
4190 // FVWM leaves window alone and adds border around it.
4191 XMoveResizeWindow(top_level->display, win,
4192 x - BC_DisplayInfo::auto_reposition_x,
4193 y - BC_DisplayInfo::auto_reposition_y,
4198 XMoveResizeWindow(top_level->display, win, x, y,
4205 pixmap = new BC_Pixmap(this, this->w, this->h);
4206 clear_box(0,0, this->w, this->h);
4207 // Propagate to menubar
4208 for(int i = 0; i < subwindows->total; i++)
4210 subwindows->values[i]->dispatch_resize_event(this->w, this->h);
4213 // draw_background(0, 0, w, h);
4219 int BC_WindowBase::reposition_window_relative(int dx, int dy, int w, int h)
4221 return reposition_window(get_x()+dx, get_y()+dy, w, h);
4224 int BC_WindowBase::reposition_window_relative(int dx, int dy)
4226 return reposition_window_relative(dx, dy, -1, -1);
4229 void BC_WindowBase::set_tooltips(int v)
4231 get_resources()->tooltips_enabled = v;
4234 void BC_WindowBase::set_force_tooltip(int v)
4239 int BC_WindowBase::raise_window(int do_flush)
4241 XRaiseWindow(top_level->display, win);
4242 if(do_flush) XFlush(top_level->display);
4246 int BC_WindowBase::lower_window(int do_flush)
4248 XLowerWindow(top_level->display, win);
4249 if(do_flush) XFlush(top_level->display);
4253 void BC_WindowBase::set_background(VFrame *bitmap)
4255 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
4257 bg_pixmap = new BC_Pixmap(this, bitmap, PIXMAP_OPAQUE);
4258 shared_bg_pixmap = 0;
4259 draw_background(0, 0, w, h);
4262 void BC_WindowBase::put_title(const char *text)
4264 char *cp = this->title, *ep = cp+sizeof(this->title)-1;
4265 for( const unsigned char *bp = (const unsigned char *)text; *bp && cp<ep; ++bp )
4266 *cp++ = *bp >= ' ' ? *bp : ' ';
4270 void BC_WindowBase::set_title(const char *text, int utf8)
4272 // utf8>0: wm + net_wm, utf8=0: wm only, utf<0: net_wm only
4274 const unsigned char *wm_title = (const unsigned char *)title;
4275 int title_len = strlen((const char *)title);
4277 Atom xa_wm_name = XA_WM_NAME;
4278 Atom xa_icon_name = XA_WM_ICON_NAME;
4279 Atom xa_string = XA_STRING;
4280 XChangeProperty(display, win, xa_wm_name, xa_string, 8,
4281 PropModeReplace, wm_title, title_len);
4282 XChangeProperty(display, win, xa_icon_name, xa_string, 8,
4283 PropModeReplace, wm_title, title_len);
4286 Atom xa_net_wm_name = XInternAtom(display, "_NET_WM_NAME", True);
4287 Atom xa_net_icon_name = XInternAtom(display, "_NET_WM_ICON_NAME", True);
4288 Atom xa_utf8_string = XInternAtom(display, "UTF8_STRING", True);
4289 XChangeProperty(display, win, xa_net_wm_name, xa_utf8_string, 8,
4290 PropModeReplace, wm_title, title_len);
4291 XChangeProperty(display, win, xa_net_icon_name, xa_utf8_string, 8,
4292 PropModeReplace, wm_title, title_len);
4297 const char *BC_WindowBase::get_title()
4302 int BC_WindowBase::get_toggle_value()
4304 return toggle_value;
4307 int BC_WindowBase::get_toggle_drag()
4312 int BC_WindowBase::set_icon(VFrame *data)
4314 if(icon_pixmap) delete icon_pixmap;
4315 icon_pixmap = new BC_Pixmap(top_level, data, PIXMAP_ALPHA, 1);
4317 if(icon_window) delete icon_window;
4318 icon_window = new BC_Popup(this,
4321 icon_pixmap->get_w(),
4322 icon_pixmap->get_h(),
4324 1, // All windows are hidden initially
4328 wm_hints.flags = WindowGroupHint | IconPixmapHint | IconMaskHint | IconWindowHint;
4329 wm_hints.icon_pixmap = icon_pixmap->get_pixmap();
4330 wm_hints.icon_mask = icon_pixmap->get_alpha();
4331 wm_hints.icon_window = icon_window->win;
4332 wm_hints.window_group = XGroupLeader;
4334 // for(int i = 0; i < 1000; i++)
4335 // printf("02x ", icon_pixmap->get_alpha()->get_row_pointers()[0][i]);
4338 XSetWMHints(top_level->display, top_level->win, &wm_hints);
4339 XSync(top_level->display, 0);
4343 void BC_WindowBase::init_resources(float scale)
4345 if( resources ) return;
4347 const char *env = getenv("BC_SCALE");
4348 if( env ) scale = atof(env);
4349 float x_scale = 1, y_scale = 1;
4351 BC_DisplayInfo info;
4353 int cins = info.xinerama_big_screen();
4354 if( !info.xinerama_geometry(cins, wx, wy, ww, wh) ) {
4355 if( (x_scale = ww/1920.) < 1 ) x_scale = 1;
4356 if( (y_scale = wh/1080.) < 1 ) y_scale = 1;
4360 x_scale = y_scale = scale;
4361 // constructor sets BC_WindowBase::resources
4362 new BC_Resources(x_scale, y_scale);
4364 void BC_WindowBase::finit_resources()
4366 delete resources; resources = 0;
4369 int BC_WindowBase::set_w(int w)
4375 int BC_WindowBase::set_h(int h)
4381 int BC_WindowBase::load_defaults(BC_Hash *defaults)
4383 char string[BCTEXTLEN];
4384 int newest_id = - 1;
4385 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4387 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4388 resources->filebox_history[i].path[0] = 0;
4389 defaults->get(string, resources->filebox_history[i].path);
4390 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4391 resources->filebox_history[i].id = defaults->get(string, resources->get_id());
4392 if(resources->filebox_history[i].id > newest_id)
4393 newest_id = resources->filebox_history[i].id;
4396 resources->filebox_id = newest_id + 1;
4397 resources->filebox_mode = defaults->get("FILEBOX_MODE", get_resources()->filebox_mode);
4398 resources->filebox_w = defaults->get("FILEBOX_W", get_resources()->filebox_w);
4399 resources->filebox_h = defaults->get("FILEBOX_H", get_resources()->filebox_h);
4400 resources->filebox_columntype[0] = defaults->get("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4401 resources->filebox_columntype[1] = defaults->get("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4402 resources->filebox_columntype[2] = defaults->get("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4403 resources->filebox_columntype[3] = defaults->get("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4404 resources->filebox_columnwidth[0] = defaults->get("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4405 resources->filebox_columnwidth[1] = defaults->get("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4406 resources->filebox_columnwidth[2] = defaults->get("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4407 resources->filebox_columnwidth[3] = defaults->get("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4408 resources->filebox_size_format = defaults->get("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4409 defaults->get("FILEBOX_FILTER", resources->filebox_filter);
4413 int BC_WindowBase::save_defaults(BC_Hash *defaults)
4415 char string[BCTEXTLEN];
4416 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4418 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4419 defaults->update(string, resources->filebox_history[i].path);
4420 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4421 defaults->update(string, resources->filebox_history[i].id);
4423 defaults->update("FILEBOX_MODE", resources->filebox_mode);
4424 defaults->update("FILEBOX_W", resources->filebox_w);
4425 defaults->update("FILEBOX_H", resources->filebox_h);
4426 defaults->update("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4427 defaults->update("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4428 defaults->update("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4429 defaults->update("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4430 defaults->update("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4431 defaults->update("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4432 defaults->update("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4433 defaults->update("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4434 defaults->update("FILEBOX_FILTER", resources->filebox_filter);
4435 defaults->update("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4441 // For some reason XTranslateCoordinates can take a long time to return.
4442 // We work around this by only calling it when the event windows are different.
4443 void BC_WindowBase::translate_coordinates(Window src_w, Window dest_w,
4444 int src_x, int src_y, int *dest_x_return, int *dest_y_return)
4451 *dest_x_return = src_x;
4452 *dest_y_return = src_y;
4456 XTranslateCoordinates(top_level->display, src_w, dest_w,
4457 src_x, src_y, dest_x_return, dest_y_return, &tempwin);
4458 //printf("BC_WindowBase::translate_coordinates 1 %lld\n", timer.get_difference());
4462 void BC_WindowBase::get_root_coordinates(int x, int y, int *abs_x, int *abs_y)
4464 translate_coordinates(win, top_level->rootwin, x, y, abs_x, abs_y);
4467 void BC_WindowBase::get_win_coordinates(int abs_x, int abs_y, int *x, int *y)
4469 translate_coordinates(top_level->rootwin, win, abs_x, abs_y, x, y);
4473 #ifdef HAVE_LIBXXF86VM
4474 void BC_WindowBase::closest_vm(int *vm, int *width, int *height)
4478 if(XF86VidModeQueryExtension(top_level->display,&foo,&bar)) {
4480 XF86VidModeModeInfo **vm_modelines;
4481 XF86VidModeGetAllModeLines(top_level->display,
4482 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4483 for( i = 0; i < vm_count; i++ ) {
4484 if( vm_modelines[i]->hdisplay < vm_modelines[*vm]->hdisplay &&
4485 vm_modelines[i]->hdisplay >= *width )
4488 display = top_level->display;
4489 if( vm_modelines[*vm]->hdisplay == *width )
4492 *width = vm_modelines[*vm]->hdisplay;
4493 *height = vm_modelines[*vm]->vdisplay;
4498 void BC_WindowBase::scale_vm(int vm)
4500 int foo,bar,dotclock;
4501 if( XF86VidModeQueryExtension(top_level->display,&foo,&bar) ) {
4503 XF86VidModeModeInfo **vm_modelines;
4504 XF86VidModeModeLine vml;
4505 XF86VidModeGetAllModeLines(top_level->display,
4506 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4507 XF86VidModeGetModeLine(top_level->display,
4508 XDefaultScreen(top_level->display), &dotclock,&vml);
4509 orig_modeline.dotclock = dotclock;
4510 orig_modeline.hdisplay = vml.hdisplay;
4511 orig_modeline.hsyncstart = vml.hsyncstart;
4512 orig_modeline.hsyncend = vml.hsyncend;
4513 orig_modeline.htotal = vml.htotal;
4514 orig_modeline.vdisplay = vml.vdisplay;
4515 orig_modeline.vsyncstart = vml.vsyncstart;
4516 orig_modeline.vsyncend = vml.vsyncend;
4517 orig_modeline.vtotal = vml.vtotal;
4518 orig_modeline.flags = vml.flags;
4519 orig_modeline.privsize = vml.privsize;
4520 // orig_modeline.private = vml.private;
4521 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),vm_modelines[vm]);
4522 XF86VidModeSetViewPort(top_level->display,XDefaultScreen(top_level->display),0,0);
4523 XFlush(top_level->display);
4527 void BC_WindowBase::restore_vm()
4529 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),&orig_modeline);
4530 XFlush(top_level->display);
4535 #ifndef SINGLE_THREAD
4536 int BC_WindowBase::get_event_count()
4538 event_lock->lock("BC_WindowBase::get_event_count");
4539 int result = common_events.total;
4540 event_lock->unlock();
4544 XEvent* BC_WindowBase::get_event()
4547 while(!done && !result)
4549 event_condition->lock("BC_WindowBase::get_event");
4550 event_lock->lock("BC_WindowBase::get_event");
4552 if(common_events.total && !done)
4554 result = common_events.values[0];
4555 common_events.remove_number(0);
4558 event_lock->unlock();
4563 void BC_WindowBase::put_event(XEvent *event)
4565 event_lock->lock("BC_WindowBase::put_event");
4566 common_events.append(event);
4567 event_lock->unlock();
4568 event_condition->unlock();
4571 void BC_WindowBase::dequeue_events(Window win)
4573 event_lock->lock("BC_WindowBase::dequeue_events");
4575 int out = 0, total = common_events.size();
4576 for( int in=0; in<total; ++in ) {
4577 if( common_events[in]->xany.window == win ) continue;
4578 common_events[out++] = common_events[in];
4580 common_events.total = out;
4582 event_lock->unlock();
4585 int BC_WindowBase::resend_event(BC_WindowBase *window)
4587 if( resend_event_window ) return 1;
4588 resend_event_window = window;
4594 int BC_WindowBase::resend_event(BC_WindowBase *window)
4599 #endif // SINGLE_THREAD
4601 int BC_WindowBase::get_id()
4607 BC_Pixmap *BC_WindowBase::create_pixmap(VFrame *vframe)
4609 int w = vframe->get_w(), h = vframe->get_h();
4610 BC_Pixmap *icon = new BC_Pixmap(this, w, h);
4611 icon->draw_vframe(vframe, 0,0, w,h, 0,0);
4616 void BC_WindowBase::flicker(int n, int ms)
4618 int color = get_bg_color();
4619 for( int i=2*n; --i>=0; ) {
4620 set_inverse(); set_bg_color(WHITE);
4621 clear_box(0,0, w,h); flash(1);
4622 sync_display(); Timer::delay(ms);
4624 set_bg_color(color);
4628 void BC_WindowBase::focus()
4630 XWindowAttributes xwa;
4631 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4632 if( xwa.map_state == IsViewable )
4633 XSetInputFocus(top_level->display, top_level->win, RevertToParent, CurrentTime);