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;
2440 XGrabServer(display);
2443 int cur_font = current_font;
2444 // locale encodings, needed glyphs to be preloaded
2445 const char *text = _( // ascii 0x20...0x7e
2446 " !\"#$%&'()*+,-./0123456789:;<=>?"
2447 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
2448 "`abcdefghijklmnopqrstuvwxyz{|}~");
2449 for( int font=SMALLFONT; font<=LARGEFONT; ++font ) {
2451 draw_text(5,5, text, 0);
2454 XUngrabServer(display);
2457 void BC_WindowBase::init_im()
2459 XIMStyles *xim_styles;
2462 if(!(input_method = XOpenIM(display, NULL, NULL, NULL)))
2464 printf("BC_WindowBase::init_im: Could not open input method.\n");
2467 if(XGetIMValues(input_method, XNQueryInputStyle, &xim_styles, NULL) ||
2470 printf("BC_WindowBase::init_im: Input method doesn't support any styles.\n");
2471 XCloseIM(input_method);
2476 for(int z = 0; z < xim_styles->count_styles; z++)
2478 if(xim_styles->supported_styles[z] == (XIMPreeditNothing | XIMStatusNothing))
2480 xim_style = xim_styles->supported_styles[z];
2488 printf("BC_WindowBase::init_im: Input method doesn't support the style we need.\n");
2489 XCloseIM(input_method);
2493 input_context = XCreateIC(input_method, XNInputStyle, xim_style,
2494 XNClientWindow, win, XNFocusWindow, win, NULL);
2497 printf("BC_WindowBase::init_im: Failed to create input context.\n");
2498 XCloseIM(input_method);
2503 void BC_WindowBase::finit_im()
2505 if( input_context ) {
2506 XDestroyIC(input_context);
2509 if( input_method ) {
2510 XCloseIM(input_method);
2516 int BC_WindowBase::get_color(int64_t color)
2518 // return pixel of color
2519 // use this only for drawing subwindows not for bitmaps
2520 int i, test, difference;
2526 return get_color_rgb8(color);
2527 // test last color looked up
2528 if(current_color_value == color)
2529 return current_color_pixel;
2532 current_color_value = color;
2533 for(i = 0; i < total_colors; i++)
2535 if(color_table[i][0] == color)
2537 current_color_pixel = color_table[i][1];
2538 return current_color_pixel;
2542 // find nearest match
2543 difference = 0xFFFFFF;
2545 for(i = 0; i < total_colors; i++)
2547 test = abs((int)(color_table[i][0] - color));
2549 if(test < difference)
2551 current_color_pixel = color_table[i][1];
2555 return current_color_pixel;
2558 return get_color_rgb16(color);
2561 return get_color_bgr16(color);
2565 return client_byte_order == server_byte_order ?
2566 color : get_color_bgr24(color);
2574 int BC_WindowBase::get_color_rgb8(int color)
2578 pixel = (color & 0xc00000) >> 16;
2579 pixel += (color & 0xe000) >> 10;
2580 pixel += (color & 0xe0) >> 5;
2584 int64_t BC_WindowBase::get_color_rgb16(int color)
2587 result = (color & 0xf80000) >> 8;
2588 result += (color & 0xfc00) >> 5;
2589 result += (color & 0xf8) >> 3;
2594 int64_t BC_WindowBase::get_color_bgr16(int color)
2597 result = (color & 0xf80000) >> 19;
2598 result += (color & 0xfc00) >> 5;
2599 result += (color & 0xf8) << 8;
2604 int64_t BC_WindowBase::get_color_bgr24(int color)
2607 result = (color & 0xff) << 16;
2608 result += (color & 0xff00);
2609 result += (color & 0xff0000) >> 16;
2613 void BC_WindowBase::start_video()
2615 cursor_timer->update();
2617 // set_color(BLACK);
2618 // draw_box(0, 0, get_w(), get_h());
2622 void BC_WindowBase::stop_video()
2630 int64_t BC_WindowBase::get_color()
2632 return top_level->current_color;
2635 void BC_WindowBase::set_color(int64_t color)
2637 top_level->current_color = color;
2638 XSetForeground(top_level->display,
2640 top_level->get_color(color));
2643 void BC_WindowBase::set_opaque()
2645 XSetFunction(top_level->display, top_level->gc, GXcopy);
2648 void BC_WindowBase::set_inverse()
2650 XSetFunction(top_level->display, top_level->gc, GXxor);
2653 void BC_WindowBase::set_line_width(int value)
2655 this->line_width = value;
2656 XSetLineAttributes(top_level->display, top_level->gc, value, /* line_width */
2657 line_dashes == 0 ? LineSolid : LineOnOffDash, /* line_style */
2658 line_dashes == 0 ? CapRound : CapNotLast, /* cap_style */
2659 JoinMiter); /* join_style */
2661 if(line_dashes > 0) {
2662 const char dashes = line_dashes;
2663 XSetDashes(top_level->display, top_level->gc, 0, &dashes, 1);
2666 // XGCValues gcvalues;
2667 // unsigned long gcmask;
2668 // gcmask = GCCapStyle | GCJoinStyle;
2669 // XGetGCValues(top_level->display, top_level->gc, gcmask, &gcvalues);
2670 // printf("BC_WindowBase::set_line_width %d %d %d\n", __LINE__, gcvalues.cap_style, gcvalues.join_style);
2673 void BC_WindowBase::set_line_dashes(int value)
2675 line_dashes = value;
2676 // call XSetLineAttributes
2677 set_line_width(line_width);
2681 Cursor BC_WindowBase::get_cursor_struct(int cursor)
2685 case ARROW_CURSOR: return top_level->arrow_cursor;
2686 case CROSS_CURSOR: return top_level->cross_cursor;
2687 case IBEAM_CURSOR: return top_level->ibeam_cursor;
2688 case VSEPARATE_CURSOR: return top_level->vseparate_cursor;
2689 case HSEPARATE_CURSOR: return top_level->hseparate_cursor;
2690 case MOVE_CURSOR: return top_level->move_cursor;
2691 case LEFT_CURSOR: return top_level->left_cursor;
2692 case RIGHT_CURSOR: return top_level->right_cursor;
2693 case UPRIGHT_ARROW_CURSOR: return top_level->upright_arrow_cursor;
2694 case UPLEFT_RESIZE: return top_level->upleft_resize_cursor;
2695 case UPRIGHT_RESIZE: return top_level->upright_resize_cursor;
2696 case DOWNLEFT_RESIZE: return top_level->downleft_resize_cursor;
2697 case DOWNRIGHT_RESIZE: return top_level->downright_resize_cursor;
2698 case HOURGLASS_CURSOR: return top_level->hourglass_cursor;
2699 case TRANSPARENT_CURSOR: return top_level->transparent_cursor;
2700 case GRABBED_CURSOR: return top_level->grabbed_cursor;
2705 void BC_WindowBase::set_cursor(int cursor, int override, int flush)
2707 // inherit cursor from parent
2710 XUndefineCursor(top_level->display, win);
2711 current_cursor = cursor;
2714 // don't change cursor if overridden
2715 if((!top_level->is_hourglass && !is_transparent) ||
2718 XDefineCursor(top_level->display, win, get_cursor_struct(cursor));
2719 if(flush) this->flush();
2722 if(!override) current_cursor = cursor;
2725 void BC_WindowBase::set_x_cursor(int cursor)
2727 temp_cursor = XCreateFontCursor(top_level->display, cursor);
2728 XDefineCursor(top_level->display, win, temp_cursor);
2729 current_cursor = cursor;
2733 int BC_WindowBase::get_cursor()
2735 return current_cursor;
2738 void BC_WindowBase::start_hourglass()
2740 top_level->start_hourglass_recursive();
2744 void BC_WindowBase::stop_hourglass()
2746 top_level->stop_hourglass_recursive();
2750 void BC_WindowBase::start_hourglass_recursive()
2752 if(this == top_level)
2760 set_cursor(HOURGLASS_CURSOR, 1, 0);
2761 for(int i = 0; i < subwindows->total; i++)
2763 subwindows->values[i]->start_hourglass_recursive();
2768 void BC_WindowBase::stop_hourglass_recursive()
2770 if(this == top_level)
2772 if(hourglass_total == 0) return;
2773 top_level->hourglass_total--;
2776 if(!top_level->hourglass_total)
2778 top_level->is_hourglass = 0;
2780 // Cause set_cursor to perform change
2782 set_cursor(current_cursor, 1, 0);
2784 for(int i = 0; i < subwindows->total; i++)
2786 subwindows->values[i]->stop_hourglass_recursive();
2794 XFontStruct* BC_WindowBase::get_font_struct(int font)
2796 // Clear out unrelated flags
2797 if(font & BOLDFACE) font ^= BOLDFACE;
2800 case SMALLFONT: return top_level->smallfont; break;
2801 case MEDIUMFONT: return top_level->mediumfont; break;
2802 case LARGEFONT: return top_level->largefont; break;
2803 case BIGFONT: return top_level->bigfont; break;
2804 case CLOCKFONT: return top_level->clockfont; break;
2809 XFontSet BC_WindowBase::get_fontset(int font)
2813 if(get_resources()->use_fontset)
2815 switch(font & 0xff) {
2816 case SMALLFONT: fs = top_level->smallfontset; break;
2817 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2818 case LARGEFONT: fs = top_level->largefontset; break;
2819 case BIGFONT: fs = top_level->bigfontset; break;
2820 case CLOCKFONT: fs = top_level->clockfontset; break;
2828 XftFont* BC_WindowBase::get_xft_struct(int font)
2831 case SMALLFONT: return (XftFont*)top_level->smallfont_xft;
2832 case MEDIUMFONT: return (XftFont*)top_level->mediumfont_xft;
2833 case LARGEFONT: return (XftFont*)top_level->largefont_xft;
2834 case BIGFONT: return (XftFont*)top_level->bigfont_xft;
2835 case CLOCKFONT: return (XftFont*)top_level->clockfont_xft;
2836 case MEDIUMFONT_3D: return (XftFont*)top_level->bold_mediumfont_xft;
2837 case SMALLFONT_3D: return (XftFont*)top_level->bold_smallfont_xft;
2838 case LARGEFONT_3D: return (XftFont*)top_level->bold_largefont_xft;
2846 int BC_WindowBase::get_current_font()
2848 return top_level->current_font;
2851 void BC_WindowBase::set_font(int font)
2853 top_level->current_font = font;
2856 if(get_resources()->use_xft) {}
2859 if(get_resources()->use_fontset) {
2863 if(get_font_struct(font))
2865 XSetFont(top_level->display, top_level->gc, get_font_struct(font)->fid);
2871 void BC_WindowBase::set_fontset(int font)
2875 if(get_resources()->use_fontset) {
2877 case SMALLFONT: fs = top_level->smallfontset; break;
2878 case MEDIUMFONT: fs = top_level->mediumfontset; break;
2879 case LARGEFONT: fs = top_level->largefontset; break;
2880 case BIGFONT: fs = top_level->bigfontset; break;
2881 case CLOCKFONT: fs = top_level->clockfontset; break;
2889 XFontSet BC_WindowBase::get_curr_fontset(void)
2891 if(get_resources()->use_fontset)
2892 return curr_fontset;
2896 int BC_WindowBase::get_single_text_width(int font, const char *text, int length)
2899 if(get_resources()->use_xft && get_xft_struct(font))
2902 #ifdef X_HAVE_UTF8_STRING
2903 if(get_resources()->locale_utf8)
2905 xftTextExtentsUtf8(top_level->display,
2906 get_xft_struct(font),
2907 (const XftChar8 *)text,
2914 xftTextExtents8(top_level->display,
2915 get_xft_struct(font),
2916 (const XftChar8 *)text,
2920 return extents.xOff;
2924 if(get_resources()->use_fontset && top_level->get_fontset(font))
2925 return XmbTextEscapement(top_level->get_fontset(font), text, length);
2927 if(get_font_struct(font))
2928 return XTextWidth(get_font_struct(font), text, length);
2934 case MEDIUM_7SEGMENT:
2935 return get_resources()->medium_7segment[0]->get_w() * length;
2945 int BC_WindowBase::get_text_width(int font, const char *text, int length)
2947 int i, j, w = 0, line_w = 0;
2948 if(length < 0) length = strlen(text);
2950 for(i = 0, j = 0; i <= length; i++)
2955 line_w = get_single_text_width(font, &text[j], i - j);
2961 line_w = get_single_text_width(font, &text[j], length - j);
2963 if(line_w > w) w = line_w;
2966 if(i > length && w == 0)
2968 w = get_single_text_width(font, text, length);
2974 int BC_WindowBase::get_text_width(int font, const wchar_t *text, int length)
2977 if( length < 0 ) length = wcslen(text);
2979 for( i=j=0; i<length && text[i]; ++i ) {
2980 if( text[i] != '\n' ) continue;
2982 int lw = get_single_text_width(font, &text[j], i-j);
2983 if( w < lw ) w = lw;
2988 int lw = get_single_text_width(font, &text[j], length-j);
2989 if( w < lw ) w = lw;
2995 int BC_WindowBase::get_text_ascent(int font)
2999 if( (fstruct = get_xft_struct(font)) != 0 )
3000 return fstruct->ascent;
3002 if(get_resources()->use_fontset && top_level->get_fontset(font))
3004 XFontSetExtents *extents;
3006 extents = XExtentsOfFontSet(top_level->get_fontset(font));
3007 return -extents->max_logical_extent.y;
3010 if(get_font_struct(font))
3011 return top_level->get_font_struct(font)->ascent;
3014 case MEDIUM_7SEGMENT:
3015 return get_resources()->medium_7segment[0]->get_h();
3020 int BC_WindowBase::get_text_descent(int font)
3024 if( (fstruct = get_xft_struct(font)) != 0 )
3025 return fstruct->descent;
3027 if(get_resources()->use_fontset && top_level->get_fontset(font)) {
3028 XFontSetExtents *extents;
3029 extents = XExtentsOfFontSet(top_level->get_fontset(font));
3030 return (extents->max_logical_extent.height
3031 + extents->max_logical_extent.y);
3034 if(get_font_struct(font))
3035 return top_level->get_font_struct(font)->descent;
3040 int BC_WindowBase::get_text_height(int font, const char *text)
3045 if( (fstruct = get_xft_struct(font)) != 0 )
3046 rowh = fstruct->height;
3049 rowh = get_text_ascent(font) + get_text_descent(font);
3051 if(!text) return rowh;
3053 // Add height of lines
3054 int h = 0, i, length = strlen(text);
3055 for(i = 0; i <= length; i++)
3066 // truncate the text with ... & return a new string
3067 char *BC_WindowBase::get_truncated_text(int font, const char *text, int max_w)
3069 char *result = cstrdup(text);
3070 int text_w = get_text_width(font, text);
3071 int ci = -1, len = strlen(text);
3072 if( text_w > max_w ) {
3073 // get center of string
3074 int cx = text_w/2, best = INT_MAX;
3075 for( int i=1; i<=len; ++i ) {
3076 int cw = get_text_width(font, text, i);
3077 if( abs(cw-cx) < abs(best-cx) ) {
3082 if( ci > 0 && ci < len-1 ) {
3083 // insert ... in the center
3084 result[ci-1] = result[ci] = result[ci+1] = '.';
3086 while( ci-2>=0 && ci+2<(int)strlen(result) &&
3087 get_text_width(font, result) > max_w ) {
3088 // take away a character from the longer side
3089 int left_w = get_text_width(font, result, ci-2);
3090 int right_w = get_text_width(font, result + ci+3);
3091 int i = left_w > right_w ? --ci-1 : ci+2;
3092 while( (result[i]=result[i+1])!=0 ) ++i;
3099 BC_Bitmap* BC_WindowBase::new_bitmap(int w, int h, int color_model)
3101 if(color_model < 0) color_model = top_level->get_color_model();
3102 return new BC_Bitmap(top_level, w, h, color_model);
3105 void BC_WindowBase::init_wait()
3107 #ifndef SINGLE_THREAD
3108 if(window_type != MAIN_WINDOW)
3109 top_level->init_wait();
3110 init_lock->lock("BC_WindowBase::init_wait");
3111 init_lock->unlock();
3115 int BC_WindowBase::accel_available(int color_model, int lock_it)
3117 if( window_type != MAIN_WINDOW )
3118 return top_level->accel_available(color_model, lock_it);
3120 lock_window("BC_WindowBase::accel_available");
3122 switch(color_model) {
3124 grab_port_id(color_model);
3128 grab_port_id(color_model);
3137 //printf("BC_WindowBase::accel_available %d %d\n", color_model, xvideo_port_id);
3138 return xvideo_port_id >= 0 ? 1 : 0;
3142 int BC_WindowBase::grab_port_id(int color_model)
3144 if( !get_resources()->use_xvideo || // disabled
3145 !get_resources()->use_shm ) // Only local server is fast enough.
3147 if( xvideo_port_id >= 0 )
3148 return xvideo_port_id;
3150 unsigned int ver, rev, reqBase, eventBase, errorBase;
3151 if( Success != XvQueryExtension(display, // XV extension is available
3152 &ver, &rev, &reqBase, &eventBase, &errorBase) )
3155 // XV adaptors are available
3156 unsigned int numAdapt = 0;
3157 XvAdaptorInfo *info = 0;
3158 XvQueryAdaptors(display, DefaultRootWindow(display), &numAdapt, &info);
3162 // Translate from color_model to X color model
3163 int x_color_model = BC_CModels::bc_to_x(color_model);
3165 // Get adaptor with desired color model
3166 for( int i = 0; i < (int)numAdapt && xvideo_port_id == -1; i++) {
3167 if( !(info[i].type & XvImageMask) || !info[i].num_ports ) continue;
3168 // adaptor supports XvImages
3169 int numFormats = 0, numPorts = info[i].num_ports;
3170 XvImageFormatValues *formats =
3171 XvListImageFormats(display, info[i].base_id, &numFormats);
3172 if( !formats ) continue;
3174 for( int j=0; j<numFormats && xvideo_port_id<0; ++j ) {
3175 if( formats[j].id != x_color_model ) continue;
3176 // this adaptor supports the desired format, grab a port
3177 for( int k=0; k<numPorts; ++k ) {
3178 if( Success == XvGrabPort(top_level->display,
3179 info[i].base_id+k, CurrentTime) ) {
3180 //printf("BC_WindowBase::grab_port_id %llx\n", info[i].base_id);
3181 xvideo_port_id = info[i].base_id + k;
3189 XvFreeAdaptorInfo(info);
3191 return xvideo_port_id;
3195 int BC_WindowBase::show_window(int flush)
3197 for(int i = 0; i < subwindows->size(); i++)
3199 subwindows->get(i)->show_window(0);
3202 XMapWindow(top_level->display, win);
3203 if(flush) XFlush(top_level->display);
3204 // XSync(top_level->display, 0);
3209 int BC_WindowBase::hide_window(int flush)
3211 for(int i = 0; i < subwindows->size(); i++)
3213 subwindows->get(i)->hide_window(0);
3216 XUnmapWindow(top_level->display, win);
3217 if(flush) this->flush();
3222 BC_MenuBar* BC_WindowBase::add_menubar(BC_MenuBar *menu_bar)
3224 subwindows->append((BC_SubWindow*)menu_bar);
3226 menu_bar->parent_window = this;
3227 menu_bar->top_level = this->top_level;
3228 menu_bar->initialize();
3232 BC_WindowBase* BC_WindowBase::add_popup(BC_WindowBase *window)
3234 //printf("BC_WindowBase::add_popup window=%p win=%p\n", window, window->win);
3235 if(this != top_level) return top_level->add_popup(window);
3236 popups.append(window);
3240 void BC_WindowBase::remove_popup(BC_WindowBase *window)
3242 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3243 if(this != top_level)
3244 top_level->remove_popup(window);
3246 popups.remove(window);
3247 //printf("BC_WindowBase::remove_popup %d size=%d window=%p win=%p\n", __LINE__, popups.size(), window, window->win);
3251 BC_WindowBase* BC_WindowBase::add_subwindow(BC_WindowBase *subwindow)
3253 subwindows->append(subwindow);
3255 if(subwindow->bg_color == -1) subwindow->bg_color = this->bg_color;
3257 // parent window must be set before the subwindow initialization
3258 subwindow->parent_window = this;
3259 subwindow->top_level = this->top_level;
3261 // Execute derived initialization
3262 subwindow->initialize();
3267 BC_WindowBase* BC_WindowBase::add_tool(BC_WindowBase *subwindow)
3269 return add_subwindow(subwindow);
3272 int BC_WindowBase::flash(int x, int y, int w, int h, int flush)
3274 if( !top_level->flash_enabled ) return 0;
3275 //printf("BC_WindowBase::flash %d %d %d %d %d\n", __LINE__, w, h, this->w, this->h);
3277 XSetWindowBackgroundPixmap(top_level->display, win, pixmap->opaque_pixmap);
3280 XClearArea(top_level->display, win, x, y, w, h, 0);
3284 XClearWindow(top_level->display, win);
3292 int BC_WindowBase::flash(int flush)
3294 flash(-1, -1, -1, -1, flush);
3298 void BC_WindowBase::flush()
3300 //if(!get_window_lock())
3301 // printf("BC_WindowBase::flush %s not locked\n", top_level->title);
3302 // X gets hosed if Flush/Sync are not user locked (at libX11-1.1.5 / libxcb-1.1.91)
3303 // _XReply deadlocks in condition_wait waiting for xlib lock when waiters!=-1
3304 int locked = get_window_lock();
3305 if( !locked ) lock_window("BC_WindowBase::flush");
3306 XFlush(top_level->display);
3307 if( !locked ) unlock_window();
3310 void BC_WindowBase::sync_display()
3312 int locked = get_window_lock();
3313 if( !locked ) lock_window("BC_WindowBase::sync_display");
3314 XSync(top_level->display, False);
3315 if( !locked ) unlock_window();
3318 int BC_WindowBase::get_window_lock()
3320 #ifdef SINGLE_THREAD
3321 return BC_Display::display_global->get_display_locked();
3323 return top_level->window_lock;
3327 int BC_WindowBase::lock_window(const char *location)
3329 if(top_level && top_level != this)
3331 top_level->lock_window(location);
3336 SET_LOCK(this, title, location);
3337 #ifdef SINGLE_THREAD
3338 BC_Display::lock_display(location);
3340 XLockDisplay(top_level->display);
3341 top_level->display_lock_owner = pthread_self();
3344 ++top_level->window_lock;
3348 printf("BC_WindowBase::lock_window top_level NULL\n");
3353 int BC_WindowBase::unlock_window()
3355 if(top_level && top_level != this)
3357 top_level->unlock_window();
3363 if( !top_level->window_lock ) {
3364 printf("BC_WindowBase::unlock_window %s not locked\n", title);
3367 if( top_level->window_lock > 0 )
3368 if( --top_level->window_lock == 0 )
3369 top_level->display_lock_owner = 0;
3370 #ifdef SINGLE_THREAD
3371 BC_Display::unlock_display();
3373 XUnlockDisplay(top_level->display);
3378 printf("BC_WindowBase::unlock_window top_level NULL\n");
3383 int BC_WindowBase::break_lock()
3385 if( !top_level ) return 0;
3386 if( top_level != this ) return top_level->break_lock();
3387 if( top_level->display_lock_owner != pthread_self() ) return 0;
3388 if( top_level->window_lock != 1 ) return 0;
3391 display_lock_owner = 0;
3392 #ifdef SINGLE_THREAD
3393 BC_Display::unlock_display();
3395 XUnlockDisplay(display);
3400 void BC_WindowBase::set_done(int return_value)
3402 if(done_set) return;
3404 if(window_type != MAIN_WINDOW)
3405 top_level->set_done(return_value);
3408 #ifdef SINGLE_THREAD
3409 this->return_value = return_value;
3410 BC_Display::display_global->arm_completion(this);
3411 completion_lock->unlock();
3412 #else // SINGLE_THREAD
3414 if( !event_thread ) return;
3415 XEvent *event = new_xevent();
3416 XClientMessageEvent *ptr = (XClientMessageEvent*)event;
3417 event->type = ClientMessage;
3418 ptr->message_type = SetDoneXAtom;
3420 this->return_value = return_value;
3421 // May lock up here because XSendEvent doesn't work too well
3422 // asynchronous with XNextEvent.
3423 // This causes BC_WindowEvents to forward a copy of the event to run_window where
3425 // Deletion of event_thread is done at the end of BC_WindowBase::run_window() - by calling the destructor
3431 void BC_WindowBase::close(int return_value)
3433 hide_window(); flush();
3434 set_done(return_value);
3437 int BC_WindowBase::grab(BC_WindowBase *window)
3439 if( window->active_grab && this != window->active_grab ) return 0;
3440 window->active_grab = this;
3441 this->grab_active = window;
3444 int BC_WindowBase::ungrab(BC_WindowBase *window)
3446 if( window->active_grab && this != window->active_grab ) return 0;
3447 window->active_grab = 0;
3448 this->grab_active = 0;
3451 int BC_WindowBase::grab_event_count()
3454 #ifndef SINGLE_THREAD
3455 result = grab_active->get_event_count();
3459 int BC_WindowBase::grab_buttons()
3461 XSync(top_level->display, False);
3462 if( XGrabButton(top_level->display, AnyButton, AnyModifier,
3463 top_level->rootwin, True, ButtonPressMask | ButtonReleaseMask,
3464 GrabModeAsync, GrabModeSync, None, None) == GrabSuccess ) {
3465 set_active_subwindow(this);
3470 void BC_WindowBase::ungrab_buttons()
3472 XUngrabButton(top_level->display, AnyButton, AnyModifier, top_level->rootwin);
3473 set_active_subwindow(0);
3476 void BC_WindowBase::grab_cursor()
3478 Cursor cursor_grab = get_cursor_struct(GRABBED_CURSOR);
3479 XGrabPointer(top_level->display, top_level->rootwin, True,
3480 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
3481 GrabModeAsync, GrabModeAsync, None, cursor_grab, CurrentTime);
3483 void BC_WindowBase::ungrab_cursor()
3485 XUngrabPointer(top_level->display, CurrentTime);
3489 // WidthOfScreen/HeightOfScreen of XDefaultScreenOfDisplay
3490 // this is the bounding box of all the screens
3492 int BC_WindowBase::get_root_w(int lock_display)
3494 if(lock_display) lock_window("BC_WindowBase::get_root_w");
3495 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3496 int result = WidthOfScreen(def_screen);
3497 if(lock_display) unlock_window();
3501 int BC_WindowBase::get_root_h(int lock_display)
3503 if(lock_display) lock_window("BC_WindowBase::get_root_h");
3504 Screen *def_screen = XDefaultScreenOfDisplay(top_level->display);
3505 int result = HeightOfScreen(def_screen);
3506 if(lock_display) unlock_window();
3510 XineramaScreenInfo *
3511 BC_WindowBase::get_xinerama_info(int screen)
3513 if( !xinerama_info || !xinerama_screens ) return 0;
3515 for( int i=0; i<xinerama_screens; ++i )
3516 if( xinerama_info[i].screen_number == screen )
3517 return &xinerama_info[i];
3520 int top_x = get_x(), top_y = get_y();
3521 if( BC_DisplayInfo::left_border >= 0 ) top_x += BC_DisplayInfo::left_border;
3522 if( BC_DisplayInfo::top_border >= 0 ) top_y += BC_DisplayInfo::top_border;
3523 for( int i=0; i<xinerama_screens; ++i ) {
3524 int scr_y = top_y - xinerama_info[i].y_org;
3525 if( scr_y < 0 || scr_y >= xinerama_info[i].height ) continue;
3526 int scr_x = top_x - xinerama_info[i].x_org;
3527 if( scr_x >= 0 && scr_x < xinerama_info[i].width )
3528 return &xinerama_info[i];
3533 void BC_WindowBase::get_fullscreen_geometry(int &wx, int &wy, int &ww, int &wh)
3535 XineramaScreenInfo *info = top_level->get_xinerama_info(-1);
3537 wx = info->x_org; wy = info->y_org;
3538 ww = info->width; wh = info->height;
3541 wx = get_screen_x(0, -1);
3542 wy = get_screen_y(0, -1);
3543 int scr_w0 = get_screen_w(0, 0);
3544 int root_w = get_root_w(0);
3545 int root_h = get_root_h(0);
3546 if( root_w > scr_w0 ) { // multi-headed
3547 if( wx >= scr_w0 ) {
3548 // assumes right side is the big one
3549 ww = root_w - scr_w0;
3553 // use same aspect ratio to compute left height
3555 wh = (w*root_h) / (root_w-scr_w0);
3565 int BC_WindowBase::get_screen_x(int lock_display, int screen)
3568 if(lock_display) lock_window("BC_WindowBase::get_screen_x");
3569 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3572 int root_w = get_root_w(0);
3573 int root_h = get_root_h(0);
3574 // Shift X based on position of current window if dual head
3575 if( (float)root_w/root_h > 1.8 ) {
3576 root_w = get_screen_w(0, 0);
3577 if( top_level->get_x() >= root_w )
3582 result = info->x_org;
3583 if(lock_display) unlock_window();
3587 int BC_WindowBase::get_screen_y(int lock_display, int screen)
3589 if(lock_display) lock_window("BC_WindowBase::get_screen_y");
3590 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3591 int result = !info ? 0 : info->y_org;
3592 if(lock_display) unlock_window();
3596 int BC_WindowBase::get_screen_w(int lock_display, int screen)
3599 if(lock_display) lock_window("BC_WindowBase::get_screen_w");
3600 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3602 int width = get_root_w(0);
3603 int height = get_root_h(0);
3604 if( (float)width/height > 1.8 ) {
3605 // If dual head, the screen width is > 16x9
3606 // but we only want to fill one screen
3607 // this code assumes the "big" screen is on the right
3608 int scr_w0 = width / 2;
3610 case 600: scr_w0 = 800; break;
3611 case 720: scr_w0 = 1280; break;
3612 case 1024: scr_w0 = 1280; break;
3613 case 1200: scr_w0 = 1600; break;
3614 case 1080: scr_w0 = 1920; break;
3616 int scr_w1 = width - scr_w0;
3617 result = screen > 0 ? scr_w1 :
3618 screen == 0 ? scr_w0 :
3619 top_level->get_x() < scr_w0 ? scr_w0 : scr_w1;
3625 result = info->width;
3626 if(lock_display) unlock_window();
3630 int BC_WindowBase::get_screen_h(int lock_display, int screen)
3632 if(lock_display) lock_window("BC_WindowBase::get_screen_h");
3633 XineramaScreenInfo *info = top_level->get_xinerama_info(screen);
3634 int result = info ? info->height : get_root_h(0);
3635 if(lock_display) unlock_window();
3639 // Bottom right corner
3640 int BC_WindowBase::get_x2()
3645 int BC_WindowBase::get_y2()
3650 int BC_WindowBase::get_video_on()
3655 int BC_WindowBase::get_hidden()
3657 return top_level->hidden;
3660 int BC_WindowBase::cursor_inside()
3662 return (top_level->cursor_x >= 0 &&
3663 top_level->cursor_y >= 0 &&
3664 top_level->cursor_x < w &&
3665 top_level->cursor_y < h);
3668 BC_WindowBase* BC_WindowBase::get_top_level()
3673 BC_WindowBase* BC_WindowBase::get_parent()
3675 return parent_window;
3678 int BC_WindowBase::get_color_model()
3680 return top_level->color_model;
3683 BC_Resources* BC_WindowBase::get_resources()
3685 return BC_WindowBase::resources;
3688 BC_Synchronous* BC_WindowBase::get_synchronous()
3690 return BC_WindowBase::resources->get_synchronous();
3693 int BC_WindowBase::get_bg_color()
3698 void BC_WindowBase::set_bg_color(int color)
3700 this->bg_color = color;
3703 BC_Pixmap* BC_WindowBase::get_bg_pixmap()
3708 void BC_WindowBase::set_active_subwindow(BC_WindowBase *subwindow)
3710 top_level->active_subwindow = subwindow;
3713 int BC_WindowBase::activate()
3718 int BC_WindowBase::deactivate()
3720 if(window_type == MAIN_WINDOW)
3722 if( top_level->active_menubar ) {
3723 top_level->active_menubar->deactivate();
3724 top_level->active_menubar = 0;
3726 if( top_level->active_popup_menu ) {
3727 top_level->active_popup_menu->deactivate();
3728 top_level->active_popup_menu = 0;
3730 if( top_level->active_subwindow ) {
3731 top_level->active_subwindow->deactivate();
3732 top_level->active_subwindow = 0;
3734 if( top_level->motion_events && top_level->last_motion_win == this->win )
3735 top_level->motion_events = 0;
3741 int BC_WindowBase::cycle_textboxes(int amount)
3744 BC_WindowBase *new_textbox = 0;
3748 BC_WindowBase *first_textbox = 0;
3749 find_next_textbox(&first_textbox, &new_textbox, result);
3750 if(!new_textbox) new_textbox = first_textbox;
3756 BC_WindowBase *last_textbox = 0;
3757 find_prev_textbox(&last_textbox, &new_textbox, result);
3758 if(!new_textbox) new_textbox = last_textbox;
3762 if(new_textbox != active_subwindow)
3765 new_textbox->activate();
3771 int BC_WindowBase::find_next_textbox(BC_WindowBase **first_textbox, BC_WindowBase **next_textbox, int &result)
3773 // Search subwindows for textbox
3774 for(int i = 0; i < subwindows->total && result < 2; i++)
3776 BC_WindowBase *test_subwindow = subwindows->values[i];
3777 test_subwindow->find_next_textbox(first_textbox, next_textbox, result);
3784 if(!*first_textbox) *first_textbox = this;
3788 if(top_level->active_subwindow == this)
3794 *next_textbox = this;
3801 int BC_WindowBase::find_prev_textbox(BC_WindowBase **last_textbox, BC_WindowBase **prev_textbox, int &result)
3807 if(!*last_textbox) *last_textbox = this;
3811 if(top_level->active_subwindow == this)
3817 *prev_textbox = this;
3822 // Search subwindows for textbox
3823 for(int i = subwindows->total - 1; i >= 0 && result < 2; i--)
3825 BC_WindowBase *test_subwindow = subwindows->values[i];
3826 test_subwindow->find_prev_textbox(last_textbox, prev_textbox, result);
3831 BC_Clipboard* BC_WindowBase::get_clipboard()
3833 #ifdef SINGLE_THREAD
3834 return BC_Display::display_global->clipboard;
3836 return top_level->clipboard;
3840 Atom BC_WindowBase::to_clipboard(const char *data, long len, int clipboard_num)
3842 return get_clipboard()->to_clipboard(this, data, len, clipboard_num);
3845 long BC_WindowBase::from_clipboard(char *data, long maxlen, int clipboard_num)
3847 return get_clipboard()->from_clipboard(data, maxlen, clipboard_num);
3850 long BC_WindowBase::clipboard_len(int clipboard_num)
3852 return get_clipboard()->clipboard_len(clipboard_num);
3855 int BC_WindowBase::do_selection_clear(Window win)
3857 top_level->event_win = win;
3858 return dispatch_selection_clear();
3861 int BC_WindowBase::dispatch_selection_clear()
3864 for( int i=0; i<subwindows->total && !result; ++i )
3865 result = subwindows->values[i]->dispatch_selection_clear();
3867 result = selection_clear_event();
3872 void BC_WindowBase::get_relative_cursor(int &x, int &y, int lock_window)
3874 int abs_x, abs_y, win_x, win_y;
3875 unsigned int temp_mask;
3878 if(lock_window) this->lock_window("BC_WindowBase::get_relative_cursor");
3879 XQueryPointer(top_level->display, top_level->win,
3880 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3883 XTranslateCoordinates(top_level->display, top_level->rootwin,
3884 win, abs_x, abs_y, &x, &y, &temp_win);
3885 if(lock_window) this->unlock_window();
3887 int BC_WindowBase::get_relative_cursor_x(int lock_window)
3890 get_relative_cursor(x, y, lock_window);
3893 int BC_WindowBase::get_relative_cursor_y(int lock_window)
3896 get_relative_cursor(x, y, lock_window);
3900 void BC_WindowBase::get_abs_cursor(int &abs_x, int &abs_y, int lock_window)
3903 unsigned int temp_mask;
3906 if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor");
3907 XQueryPointer(top_level->display, top_level->win,
3908 &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
3910 if(lock_window) this->unlock_window();
3912 int BC_WindowBase::get_abs_cursor_x(int lock_window)
3915 get_abs_cursor(abs_x, abs_y, lock_window);
3918 int BC_WindowBase::get_abs_cursor_y(int lock_window)
3921 get_abs_cursor(abs_x, abs_y, lock_window);
3925 void BC_WindowBase::get_pop_cursor(int &px, int &py, int lock_window)
3927 int xmargin = xS(100), ymargin = yS(100);
3928 get_abs_cursor(px, py, lock_window);
3929 if( px < xmargin ) px = xmargin;
3930 if( py < ymargin ) py = ymargin;
3931 int wd = get_screen_w(lock_window,-1) - xmargin;
3932 if( px > wd ) px = wd;
3933 int ht = get_screen_h(lock_window,-1) - ymargin;
3934 if( py > ht ) py = ht;
3936 int BC_WindowBase::get_pop_cursor_x(int lock_window)
3939 get_pop_cursor(px, py, lock_window);
3942 int BC_WindowBase::get_pop_cursor_y(int lock_window)
3945 get_pop_cursor(px, py, lock_window);
3949 int BC_WindowBase::match_window(Window win)
3951 if (this->win == win) return 1;
3953 for(int i = 0; i < subwindows->total; i++) {
3954 result = subwindows->values[i]->match_window(win);
3955 if (result) return result;
3961 int BC_WindowBase::get_cursor_over_window()
3963 int abs_x, abs_y, win_x, win_y;
3964 unsigned int mask_return;
3965 Window root_return, child_return;
3967 int ret = XQueryPointer(top_level->display, top_level->rootwin,
3968 &root_return, &child_return, &abs_x, &abs_y,
3969 &win_x, &win_y, &mask_return);
3970 if( ret && child_return == None ) ret = 0;
3971 if( ret && win != child_return )
3972 ret = top_level->match_window(child_return);
3973 // query pointer can return a window manager window with this top_level as a child
3974 // for kde this can be two levels deep
3975 unsigned int nchildren_return = 0;
3976 Window parent_return, *children_return = 0;
3977 Window top_win = top_level->win;
3978 while( !ret && top_win != top_level->rootwin && top_win != root_return &&
3979 XQueryTree(top_level->display, top_win, &root_return,
3980 &parent_return, &children_return, &nchildren_return) ) {
3981 if( children_return ) XFree(children_return);
3982 if( (top_win=parent_return) == child_return ) ret = 1;
3987 int BC_WindowBase::cursor_above()
3990 get_relative_cursor(rx, ry);
3991 return rx < 0 || rx >= get_w() ||
3992 ry < 0 || ry >= get_h() ? 0 : 1;
3995 int BC_WindowBase::get_drag_x()
3997 return top_level->drag_x;
4000 int BC_WindowBase::get_drag_y()
4002 return top_level->drag_y;
4005 int BC_WindowBase::get_cursor_x()
4007 return top_level->cursor_x;
4010 int BC_WindowBase::get_cursor_y()
4012 return top_level->cursor_y;
4015 int BC_WindowBase::dump_windows()
4017 printf("\tBC_WindowBase::dump_windows window=%p win=%p '%s', %dx%d+%d+%d %s\n",
4018 this, (void*)this->win, title, w,h,x,y, typeid(*this).name());
4019 for(int i = 0; i < subwindows->size(); i++)
4020 subwindows->get(i)->dump_windows();
4021 for(int i = 0; i < popups.size(); i++) {
4022 BC_WindowBase *p = popups[i];
4023 printf("\tBC_WindowBase::dump_windows popup=%p win=%p '%s', %dx%d+%d+%d %s\n",
4024 p, (void*)p->win, p->title, p->w,p->h,p->x,p->y, typeid(*p).name());
4029 int BC_WindowBase::is_event_win()
4031 return this->win == top_level->event_win;
4034 void BC_WindowBase::set_dragging(int value)
4036 is_dragging = value;
4039 int BC_WindowBase::get_dragging()
4044 int BC_WindowBase::get_buttonpress()
4046 return top_level->button_number;
4049 int BC_WindowBase::get_button_down()
4051 return top_level->button_down;
4054 int BC_WindowBase::alt_down()
4056 return top_level->alt_mask;
4059 int BC_WindowBase::shift_down()
4061 return top_level->shift_mask;
4064 int BC_WindowBase::ctrl_down()
4066 return top_level->ctrl_mask;
4069 wchar_t* BC_WindowBase::get_wkeystring(int *length)
4072 *length = top_level->wkey_string_length;
4073 return top_level->wkey_string;
4076 #ifdef X_HAVE_UTF8_STRING
4077 char* BC_WindowBase::get_keypress_utf8()
4079 return top_level->key_pressed_utf8;
4084 int BC_WindowBase::get_keypress()
4086 return top_level->key_pressed;
4089 int BC_WindowBase::get_double_click()
4091 return top_level->double_click;
4094 int BC_WindowBase::get_triple_click()
4096 return top_level->triple_click;
4099 int BC_WindowBase::get_bgcolor()
4104 int BC_WindowBase::resize_window(int w, int h)
4106 if(this->w == w && this->h == h) return 0;
4108 if(window_type == MAIN_WINDOW && !allow_resize)
4110 XSizeHints size_hints;
4111 size_hints.flags = PSize | PMinSize | PMaxSize;
4112 size_hints.width = w;
4113 size_hints.height = h;
4114 size_hints.min_width = w;
4115 size_hints.max_width = w;
4116 size_hints.min_height = h;
4117 size_hints.max_height = h;
4118 if( this->x > -BC_INFINITY && this->x < BC_INFINITY ) {
4119 size_hints.flags |= PPosition;
4120 size_hints.x = this->x;
4121 size_hints.y = this->y;
4123 XSetNormalHints(top_level->display, win, &size_hints);
4125 XResizeWindow(top_level->display, win, w, h);
4130 pixmap = new BC_Pixmap(this, w, h);
4132 // Propagate to menubar
4133 for(int i = 0; i < subwindows->total; i++)
4135 subwindows->values[i]->dispatch_resize_event(w, h);
4138 draw_background(0, 0, w, h);
4139 if(top_level == this && get_resources()->recursive_resizing)
4140 resize_history.append(new BC_ResizeCall(w, h));
4144 // The only way for resize events to be propagated is by updating the internal w and h
4145 int BC_WindowBase::resize_event(int w, int h)
4147 if(window_type == MAIN_WINDOW)
4155 int BC_WindowBase::reposition_window(int x, int y)
4157 reposition_window(x, y, -1, -1);
4162 int BC_WindowBase::reposition_window(int x, int y, int w, int h)
4166 // Some tools set their own dimensions before calling this, causing the
4167 // resize check to skip.
4171 if(w > 0 && w != this->w)
4177 if(h > 0 && h != this->h)
4183 //printf("BC_WindowBase::reposition_window %d %d %d\n", translation_count, x_correction, y_correction);
4186 printf("BC_WindowBase::reposition_window this->w == %d\n", this->w);
4188 printf("BC_WindowBase::reposition_window this->h == %d\n", this->h);
4190 if(translation_count && window_type == MAIN_WINDOW)
4192 // KDE shifts window right and down.
4193 // FVWM leaves window alone and adds border around it.
4194 XMoveResizeWindow(top_level->display, win,
4195 x - BC_DisplayInfo::auto_reposition_x,
4196 y - BC_DisplayInfo::auto_reposition_y,
4201 XMoveResizeWindow(top_level->display, win, x, y,
4208 pixmap = new BC_Pixmap(this, this->w, this->h);
4209 clear_box(0,0, this->w, this->h);
4210 // Propagate to menubar
4211 for(int i = 0; i < subwindows->total; i++)
4213 subwindows->values[i]->dispatch_resize_event(this->w, this->h);
4216 // draw_background(0, 0, w, h);
4222 int BC_WindowBase::reposition_window_relative(int dx, int dy, int w, int h)
4224 return reposition_window(get_x()+dx, get_y()+dy, w, h);
4227 int BC_WindowBase::reposition_window_relative(int dx, int dy)
4229 return reposition_window_relative(dx, dy, -1, -1);
4232 void BC_WindowBase::set_tooltips(int v)
4234 get_resources()->tooltips_enabled = v;
4237 void BC_WindowBase::set_force_tooltip(int v)
4242 int BC_WindowBase::raise_window(int do_flush)
4244 XRaiseWindow(top_level->display, win);
4245 if(do_flush) XFlush(top_level->display);
4249 int BC_WindowBase::lower_window(int do_flush)
4251 XLowerWindow(top_level->display, win);
4252 if(do_flush) XFlush(top_level->display);
4256 void BC_WindowBase::set_background(VFrame *bitmap)
4258 if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
4260 bg_pixmap = new BC_Pixmap(this, bitmap, PIXMAP_OPAQUE);
4261 shared_bg_pixmap = 0;
4262 draw_background(0, 0, w, h);
4265 void BC_WindowBase::put_title(const char *text)
4267 char *cp = this->title, *ep = cp+sizeof(this->title)-1;
4268 for( const unsigned char *bp = (const unsigned char *)text; *bp && cp<ep; ++bp )
4269 *cp++ = *bp >= ' ' ? *bp : ' ';
4273 void BC_WindowBase::set_title(const char *text, int utf8)
4275 // utf8>0: wm + net_wm, utf8=0: wm only, utf<0: net_wm only
4277 const unsigned char *wm_title = (const unsigned char *)title;
4278 int title_len = strlen((const char *)title);
4280 Atom xa_wm_name = XA_WM_NAME;
4281 Atom xa_icon_name = XA_WM_ICON_NAME;
4282 Atom xa_string = XA_STRING;
4283 XChangeProperty(display, win, xa_wm_name, xa_string, 8,
4284 PropModeReplace, wm_title, title_len);
4285 XChangeProperty(display, win, xa_icon_name, xa_string, 8,
4286 PropModeReplace, wm_title, title_len);
4289 Atom xa_net_wm_name = XInternAtom(display, "_NET_WM_NAME", True);
4290 Atom xa_net_icon_name = XInternAtom(display, "_NET_WM_ICON_NAME", True);
4291 Atom xa_utf8_string = XInternAtom(display, "UTF8_STRING", True);
4292 XChangeProperty(display, win, xa_net_wm_name, xa_utf8_string, 8,
4293 PropModeReplace, wm_title, title_len);
4294 XChangeProperty(display, win, xa_net_icon_name, xa_utf8_string, 8,
4295 PropModeReplace, wm_title, title_len);
4301 void BC_WindowBase::set_net_icon(VFrame *data)
4303 int width = data->get_w(), height = data->get_h();
4304 int size = 2 + width * height;
4305 unsigned long *icon_data = new unsigned long[size];
4306 unsigned long *lp = icon_data;
4307 *lp++ = width; *lp++ = height;
4308 uint8_t **rows = data->get_rows();
4309 for( int y=0; y<height; ++y ) {
4310 unsigned *up = (unsigned *)rows[y];
4311 for( int x=0; x<width; ++x )
4312 *lp++ = *(unsigned *)up++;
4314 Atom NetWMIcon = XInternAtom(display, "_NET_WM_ICON", True);
4315 XChangeProperty(top_level->display, top_level->win, NetWMIcon,
4316 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)icon_data, size);
4317 delete [] icon_data;
4320 const char *BC_WindowBase::get_title()
4325 int BC_WindowBase::get_toggle_value()
4327 return toggle_value;
4330 int BC_WindowBase::get_toggle_drag()
4335 int BC_WindowBase::set_icon(VFrame *data)
4337 if(icon_pixmap) delete icon_pixmap;
4338 icon_pixmap = new BC_Pixmap(top_level, data, PIXMAP_ALPHA, 1);
4340 if(icon_window) delete icon_window;
4341 icon_window = new BC_Popup(this, 0, 0,
4342 icon_pixmap->get_w(), icon_pixmap->get_h(),
4343 -1, 1, // All windows are hidden initially
4346 XWMHints wm_hints; memset(&wm_hints, 0, sizeof(wm_hints));
4347 wm_hints.flags = IconPixmapHint; // | IconMaskHint | IconWindowHint;
4348 wm_hints.icon_pixmap = icon_pixmap->get_pixmap();
4349 wm_hints.icon_mask = icon_pixmap->get_alpha();
4350 wm_hints.icon_window = icon_window->win;
4351 if( XGroupLeader ) {
4352 wm_hints.flags |= WindowGroupHint;
4353 wm_hints.window_group = XGroupLeader;
4356 // for(int i = 0; i < 1000; i++)
4357 // printf("02x ", icon_pixmap->get_alpha()->get_row_pointers()[0][i]);
4360 XSetWMHints(top_level->display, top_level->win, &wm_hints);
4363 XSync(top_level->display, 0);
4367 void BC_WindowBase::init_resources(float scale)
4369 if( resources ) return;
4371 const char *env = getenv("BC_SCALE");
4372 if( env ) scale = atof(env);
4373 float x_scale = 1, y_scale = 1;
4375 BC_DisplayInfo info;
4377 int cins = info.xinerama_big_screen();
4378 if( !info.xinerama_geometry(cins, wx, wy, ww, wh) ) {
4379 if( (x_scale = ww/1920.) < 1 ) x_scale = 1;
4380 if( (y_scale = wh/1080.) < 1 ) y_scale = 1;
4384 x_scale = y_scale = scale;
4385 // constructor sets BC_WindowBase::resources
4386 new BC_Resources(x_scale, y_scale);
4388 void BC_WindowBase::finit_resources()
4390 delete resources; resources = 0;
4393 int BC_WindowBase::set_w(int w)
4399 int BC_WindowBase::set_h(int h)
4405 int BC_WindowBase::load_defaults(BC_Hash *defaults)
4407 char string[BCTEXTLEN];
4408 int newest_id = - 1;
4409 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4411 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4412 resources->filebox_history[i].path[0] = 0;
4413 defaults->get(string, resources->filebox_history[i].path);
4414 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4415 resources->filebox_history[i].id = defaults->get(string, resources->get_id());
4416 if(resources->filebox_history[i].id > newest_id)
4417 newest_id = resources->filebox_history[i].id;
4420 resources->filebox_id = newest_id + 1;
4421 resources->filebox_mode = defaults->get("FILEBOX_MODE", get_resources()->filebox_mode);
4422 resources->filebox_w = defaults->get("FILEBOX_W", get_resources()->filebox_w);
4423 resources->filebox_h = defaults->get("FILEBOX_H", get_resources()->filebox_h);
4424 resources->filebox_columntype[0] = defaults->get("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4425 resources->filebox_columntype[1] = defaults->get("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4426 resources->filebox_columntype[2] = defaults->get("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4427 resources->filebox_columntype[3] = defaults->get("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4428 resources->filebox_columnwidth[0] = defaults->get("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4429 resources->filebox_columnwidth[1] = defaults->get("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4430 resources->filebox_columnwidth[2] = defaults->get("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4431 resources->filebox_columnwidth[3] = defaults->get("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4432 resources->filebox_size_format = defaults->get("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4433 defaults->get("FILEBOX_FILTER", resources->filebox_filter);
4437 int BC_WindowBase::save_defaults(BC_Hash *defaults)
4439 char string[BCTEXTLEN];
4440 for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++)
4442 sprintf(string, "FILEBOX_HISTORY_PATH%d", i);
4443 defaults->update(string, resources->filebox_history[i].path);
4444 sprintf(string, "FILEBOX_HISTORY_ID%d", i);
4445 defaults->update(string, resources->filebox_history[i].id);
4447 defaults->update("FILEBOX_MODE", resources->filebox_mode);
4448 defaults->update("FILEBOX_W", resources->filebox_w);
4449 defaults->update("FILEBOX_H", resources->filebox_h);
4450 defaults->update("FILEBOX_TYPE0", resources->filebox_columntype[0]);
4451 defaults->update("FILEBOX_TYPE1", resources->filebox_columntype[1]);
4452 defaults->update("FILEBOX_TYPE2", resources->filebox_columntype[2]);
4453 defaults->update("FILEBOX_TYPE3", resources->filebox_columntype[3]);
4454 defaults->update("FILEBOX_WIDTH0", resources->filebox_columnwidth[0]);
4455 defaults->update("FILEBOX_WIDTH1", resources->filebox_columnwidth[1]);
4456 defaults->update("FILEBOX_WIDTH2", resources->filebox_columnwidth[2]);
4457 defaults->update("FILEBOX_WIDTH3", resources->filebox_columnwidth[3]);
4458 defaults->update("FILEBOX_FILTER", resources->filebox_filter);
4459 defaults->update("FILEBOX_SIZE_FORMAT", get_resources()->filebox_size_format);
4465 // For some reason XTranslateCoordinates can take a long time to return.
4466 // We work around this by only calling it when the event windows are different.
4467 void BC_WindowBase::translate_coordinates(Window src_w, Window dest_w,
4468 int src_x, int src_y, int *dest_x_return, int *dest_y_return)
4475 *dest_x_return = src_x;
4476 *dest_y_return = src_y;
4480 XTranslateCoordinates(top_level->display, src_w, dest_w,
4481 src_x, src_y, dest_x_return, dest_y_return, &tempwin);
4482 //printf("BC_WindowBase::translate_coordinates 1 %lld\n", timer.get_difference());
4486 void BC_WindowBase::get_root_coordinates(int x, int y, int *abs_x, int *abs_y)
4488 translate_coordinates(win, top_level->rootwin, x, y, abs_x, abs_y);
4491 void BC_WindowBase::get_win_coordinates(int abs_x, int abs_y, int *x, int *y)
4493 translate_coordinates(top_level->rootwin, win, abs_x, abs_y, x, y);
4497 #ifdef HAVE_LIBXXF86VM
4498 void BC_WindowBase::closest_vm(int *vm, int *width, int *height)
4502 if(XF86VidModeQueryExtension(top_level->display,&foo,&bar)) {
4504 XF86VidModeModeInfo **vm_modelines;
4505 XF86VidModeGetAllModeLines(top_level->display,
4506 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4507 for( i = 0; i < vm_count; i++ ) {
4508 if( vm_modelines[i]->hdisplay < vm_modelines[*vm]->hdisplay &&
4509 vm_modelines[i]->hdisplay >= *width )
4512 display = top_level->display;
4513 if( vm_modelines[*vm]->hdisplay == *width )
4516 *width = vm_modelines[*vm]->hdisplay;
4517 *height = vm_modelines[*vm]->vdisplay;
4522 void BC_WindowBase::scale_vm(int vm)
4524 int foo,bar,dotclock;
4525 if( XF86VidModeQueryExtension(top_level->display,&foo,&bar) ) {
4527 XF86VidModeModeInfo **vm_modelines;
4528 XF86VidModeModeLine vml;
4529 XF86VidModeGetAllModeLines(top_level->display,
4530 XDefaultScreen(top_level->display), &vm_count,&vm_modelines);
4531 XF86VidModeGetModeLine(top_level->display,
4532 XDefaultScreen(top_level->display), &dotclock,&vml);
4533 orig_modeline.dotclock = dotclock;
4534 orig_modeline.hdisplay = vml.hdisplay;
4535 orig_modeline.hsyncstart = vml.hsyncstart;
4536 orig_modeline.hsyncend = vml.hsyncend;
4537 orig_modeline.htotal = vml.htotal;
4538 orig_modeline.vdisplay = vml.vdisplay;
4539 orig_modeline.vsyncstart = vml.vsyncstart;
4540 orig_modeline.vsyncend = vml.vsyncend;
4541 orig_modeline.vtotal = vml.vtotal;
4542 orig_modeline.flags = vml.flags;
4543 orig_modeline.privsize = vml.privsize;
4544 // orig_modeline.private = vml.private;
4545 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),vm_modelines[vm]);
4546 XF86VidModeSetViewPort(top_level->display,XDefaultScreen(top_level->display),0,0);
4547 XFlush(top_level->display);
4551 void BC_WindowBase::restore_vm()
4553 XF86VidModeSwitchToMode(top_level->display,XDefaultScreen(top_level->display),&orig_modeline);
4554 XFlush(top_level->display);
4559 #ifndef SINGLE_THREAD
4560 int BC_WindowBase::get_event_count()
4562 event_lock->lock("BC_WindowBase::get_event_count");
4563 int result = common_events.total;
4564 event_lock->unlock();
4568 XEvent* BC_WindowBase::get_event()
4571 while(!done && !result)
4573 event_condition->lock("BC_WindowBase::get_event");
4574 event_lock->lock("BC_WindowBase::get_event");
4576 if(common_events.total && !done)
4578 result = common_events.values[0];
4579 common_events.remove_number(0);
4582 event_lock->unlock();
4587 void BC_WindowBase::put_event(XEvent *event)
4589 event_lock->lock("BC_WindowBase::put_event");
4590 common_events.append(event);
4591 event_lock->unlock();
4592 event_condition->unlock();
4595 void BC_WindowBase::dequeue_events(Window win)
4597 event_lock->lock("BC_WindowBase::dequeue_events");
4599 int out = 0, total = common_events.size();
4600 for( int in=0; in<total; ++in ) {
4601 if( common_events[in]->xany.window == win ) continue;
4602 common_events[out++] = common_events[in];
4604 common_events.total = out;
4606 event_lock->unlock();
4609 int BC_WindowBase::resend_event(BC_WindowBase *window)
4611 if( resend_event_window ) return 1;
4612 resend_event_window = window;
4618 int BC_WindowBase::resend_event(BC_WindowBase *window)
4623 #endif // SINGLE_THREAD
4625 int BC_WindowBase::get_id()
4631 BC_Pixmap *BC_WindowBase::create_pixmap(VFrame *vframe)
4633 int w = vframe->get_w(), h = vframe->get_h();
4634 BC_Pixmap *icon = new BC_Pixmap(this, w, h);
4635 icon->draw_vframe(vframe, 0,0, w,h, 0,0);
4640 void BC_WindowBase::flicker(int n, int ms)
4642 int color = get_bg_color();
4643 for( int i=2*n; --i>=0; ) {
4644 set_inverse(); set_bg_color(WHITE);
4645 clear_box(0,0, w,h); flash(1);
4646 sync_display(); Timer::delay(ms);
4648 set_bg_color(color);
4652 void BC_WindowBase::focus()
4654 XWindowAttributes xwa;
4655 XGetWindowAttributes(top_level->display, top_level->win, &xwa);
4656 if( xwa.map_state == IsViewable )
4657 XSetInputFocus(top_level->display, top_level->win, RevertToParent, CurrentTime);