X-Git-Url: https://git.cinelerra-gg.org/git/?p=goodguy%2Fcinelerra.git;a=blobdiff_plain;f=cinelerra-5.1%2Fguicast%2Fbcwindowbase.C;h=c57cd6203c8f6569a1b24b6feb7c2cfbb7d9f6a9;hp=f9e49e22aa897e2059dd1973cbf04885298a68b5;hb=0c48864cab7b37268025485c6a227f36b3420030;hpb=2778975bea06a53d8165a5e37bdacde1ae5f3320 diff --git a/cinelerra-5.1/guicast/bcwindowbase.C b/cinelerra-5.1/guicast/bcwindowbase.C index f9e49e22..c57cd620 100644 --- a/cinelerra-5.1/guicast/bcwindowbase.C +++ b/cinelerra-5.1/guicast/bcwindowbase.C @@ -57,7 +57,9 @@ #include #include +#ifdef HAVE_XV #include +#endif #include #include #include @@ -69,17 +71,8 @@ BC_ResizeCall::BC_ResizeCall(int w, int h) } - - - - - int BC_WindowBase::shm_completion_event = -1; - - - -BC_Resources BC_WindowBase::resources; - +BC_Resources *BC_WindowBase::resources = 0; Window XGroupLeader = 0; Mutex BC_KeyboardHandlerLock::keyboard_listener_mutex("keyboard_listener",0); @@ -149,7 +142,11 @@ BC_WindowBase::~BC_WindowBase() //printf("delete glx=%08x, win=%08x %s\n", (unsigned)glx_win, (unsigned)win, title); #ifdef HAVE_GL if( get_resources()->get_synchronous() && glx_win != 0 ) { + if( window_type == MAIN_WINDOW ) + unlock_window(); get_resources()->get_synchronous()->delete_window(this); + if( window_type == MAIN_WINDOW ) + lock_window("BC_WindowBase::delete_window"); } #endif XDestroyWindow(top_level->display, win); @@ -210,9 +207,10 @@ BC_WindowBase::~BC_WindowBase() XFree(xinerama_info); xinerama_screens = 0; xinerama_info = 0; +#ifdef HAVE_XV if( xvideo_port_id >= 0 ) XvUngrabPort(display, xvideo_port_id, CurrentTime); - +#endif unlock_window(); // Must be last reference to display. // _XftDisplayInfo needs a lock. @@ -226,6 +224,7 @@ BC_WindowBase::~BC_WindowBase() } resize_history.remove_all_objects(); + delete grab_lock; #ifndef SINGLE_THREAD common_events.remove_all_objects(); @@ -255,6 +254,7 @@ int BC_WindowBase::initialize() display_lock_owner = 0; test_keypress = 0; keys_return[0] = 0; + context_help_keyword[0] = 0; is_deleting = 0; window_lock = 0; resend_event_window = 0; @@ -348,6 +348,7 @@ int BC_WindowBase::initialize() event_condition = new Condition(0, "BC_WindowBase::event_condition"); init_lock = new Condition(0, "BC_WindowBase::init_lock"); #endif + grab_lock = new Mutex("BC_WindowBase::grab_lock"); cursor_timer = new Timer; event_thread = 0; @@ -456,8 +457,19 @@ int BC_WindowBase::create_window(BC_WindowBase *parent_window, const char *title vis = get_glx_visual(display); if( !vis ) #endif + { + int mask = VisualDepthMask | VisualClassMask; + static XVisualInfo vinfo; + memset(&vinfo, 0, sizeof(vinfo)); + vinfo.depth = 24; + vinfo.c_class = TrueColor; + int nitems = 0; + XVisualInfo *vis_info = XGetVisualInfo(display, mask, &vinfo, &nitems); + vis = vis_info && nitems>0 ? vis_info[0].visual : 0; + if( vis_info ) XFree(vis_info); + } + if( !vis ) vis = DefaultVisual(display, screen); - default_depth = DefaultDepth(display, screen); client_byte_order = (*(const u_int32_t*)"a ") & 0x00000001; @@ -467,7 +479,7 @@ int BC_WindowBase::create_window(BC_WindowBase *parent_window, const char *title // This must be done before fonts to know if antialiasing is available. init_colors(); // get the resources - if(resources.use_shm < 0) resources.initialize_display(this); + if(resources->use_shm < 0) resources->initialize_display(this); x_correction = BC_DisplayInfo::get_left_border(); y_correction = BC_DisplayInfo::get_top_border(); @@ -480,7 +492,7 @@ int BC_WindowBase::create_window(BC_WindowBase *parent_window, const char *title if(this->y < 0) this->y = 0; if(this->bg_color == -1) - this->bg_color = resources.get_bg_color(); + this->bg_color = resources->get_bg_color(); // printf("bcwindowbase 1 %s\n", title); // if(window_type == MAIN_WINDOW) sleep(1); @@ -566,12 +578,11 @@ int BC_WindowBase::create_window(BC_WindowBase *parent_window, const char *title mask = CWEventMask | CWBackPixel | CWColormap | CWOverrideRedirect | CWSaveUnder | CWCursor; - attr.event_mask = DEFAULT_EVENT_MASKS | - KeyPressMask | - KeyReleaseMask; + attr.event_mask = DEFAULT_EVENT_MASKS | ExposureMask | + KeyPressMask | KeyReleaseMask; if(this->bg_color == -1) - this->bg_color = resources.get_bg_color(); + this->bg_color = resources->get_bg_color(); attr.background_pixel = top_level->get_color(bg_color); attr.colormap = top_level->cmap; if(top_level->is_hourglass) @@ -619,7 +630,7 @@ int BC_WindowBase::create_window(BC_WindowBase *parent_window, const char *title } if(!hidden) show_window(); - + init_glyphs(); } draw_background(0, 0, this->w, this->h); @@ -729,9 +740,8 @@ int BC_WindowBase::run_window() init_lock->unlock(); // Handle common events - while(!done) - { - dispatch_event(0); + while( !done ) { + dispatch_event(); } unset_all_repeaters(); @@ -865,8 +875,11 @@ int BC_WindowBase::keysym_lookup(XEvent *event) wkey_string_length = 0; if( input_context ) { + wchar_t wkey[4]; wkey_string_length = XwcLookupString(input_context, - (XKeyEvent*)event, wkey_string, 4, &keysym, 0); + (XKeyEvent*)event, wkey, 4, &keysym, 0); + for( int i=0; ixclient.message_type; -//static const char *event_names[] = { -// "Reply", "Error", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease", "MotionNotify", -// "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut", "KeymapNotify", "Expose", "GraphicsExpose", -// "NoExpose", "VisibilityNotify", "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", -// "MapRequest", "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify", -// "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear", -// "SelectionRequest", "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", -// "GenericEvent", "LASTEvent", -//}; -// -//if(debug) -//if(event->type != ClientMessage) { -// printf("BC_WindowBase::dispatch_event %d %s %p %d (%s)\n", -//__LINE__, title, event, event->type, -// event->type>=0 && event->typetype] : "Unknown"); -//} +if( debug && event->type != ClientMessage ) { + static const char *event_names[] = { + "Reply", "Error", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease", "MotionNotify", + "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut", "KeymapNotify", "Expose", "GraphicsExpose", + "NoExpose", "VisibilityNotify", "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", + "MapRequest", "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify", + "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear", + "SelectionRequest", "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", + "GenericEvent", "LASTEvent", + }; + const int nevents = sizeof(event_names)/sizeof(event_names[0]); + + printf("BC_WindowBase::dispatch_event %d %s %p %d (%s)\n", __LINE__, + title, event, event->type, event->type>=0 && event->typetype] : "Unknown"); +} if( active_grab ) { + grab_lock->lock("BC_WindowBase::dispatch_event 3"); unlock_window(); - active_grab->lock_window("BC_WindowBase::dispatch_event 3"); - result = active_grab->grab_event(event); - active_grab->unlock_window(); + result = 0; + if( active_grab ) { + active_grab->lock_window("BC_WindowBase::dispatch_event 3"); + result = active_grab->grab_event(event); + active_grab->unlock_window(); + } + grab_lock->unlock(); if( result ) return result; lock_window("BC_WindowBase::dispatch_event 4"); } @@ -960,42 +978,25 @@ locking_message = event->xclient.message_type; switch(event->type) { case ClientMessage: // Clear the resize buffer - if(resize_events) dispatch_resize_event(last_resize_w, last_resize_h); + if( resize_events ) + dispatch_resize_event(last_resize_w, last_resize_h); // Clear the motion buffer since this can clear the window - if(motion_events) - { + if( motion_events ) dispatch_motion_event(); - } ptr = (XClientMessageEvent*)event; - - - if(ptr->message_type == ProtoXAtom && - (Atom)ptr->data.l[0] == DelWinXAtom) - { + if( ptr->message_type == ProtoXAtom && + (Atom)ptr->data.l[0] == DelWinXAtom ) { close_event(); } - else - if(ptr->message_type == RepeaterXAtom) - { + else if( ptr->message_type == RepeaterXAtom ) { dispatch_repeat_event(ptr->data.l[0]); -// Make sure the repeater still exists. -// for(int i = 0; i < repeaters.total; i++) -// { -// if(repeaters.values[i]->repeat_id == ptr->data.l[0]) -// { -// dispatch_repeat_event_master(ptr->data.l[0]); -// break; -// } -// } } - else - if(ptr->message_type == SetDoneXAtom) - { + else if( ptr->message_type == SetDoneXAtom ) { done = 1; - } else - { // We currently use X marshalling for xatom events, we can switch to something else later - receive_custom_xatoms((xatom_event *)ptr); + } + else { + receive_custom_xatoms((xatom_event *)ptr); } break; @@ -1029,8 +1030,8 @@ locking_message = event->xclient.message_type; //printf("BC_WindowBase::dispatch_event %d %d\n", __LINE__, button_number); event_win = event->xany.window; - if (button_number < 6) { - if(button_number < 4) + if( button_number < 6 ) { + if( button_number < 4 ) button_down = 1; button_pressed = event->xbutton.button; button_time1 = button_time2; @@ -1043,23 +1044,20 @@ locking_message = event->xclient.message_type; drag_x2 = cursor_x + get_resources()->drag_radius; drag_y1 = cursor_y - get_resources()->drag_radius; drag_y2 = cursor_y + get_resources()->drag_radius; - - if((long)(button_time3 - button_time1) < resources.double_click * 2) - { - triple_click = 1; - button_time3 = button_time2 = button_time1 = 0; - } - if((long)(button_time3 - button_time2) < resources.double_click) - { - double_click = 1; -// button_time3 = button_time2 = button_time1 = 0; - } - else - { - triple_click = 0; - double_click = 0; + if( button_number < 4 ) { + if((long)(button_time3 - button_time1) < resources->double_click * 2) { + triple_click = 1; + button_time3 = button_time2 = button_time1 = 0; + } + if((long)(button_time3 - button_time2) < resources->double_click) { + double_click = 1; +// button_time3 = button_time2 = button_time1 = 0; + } + else { + triple_click = 0; + double_click = 0; + } } - dispatch_button_press(); } break; @@ -1084,7 +1082,13 @@ locking_message = event->xclient.message_type; case Expose: event_win = event->xany.window; - dispatch_expose_event(); + result = 0; + for( int i=0; !result && iwin == event_win ) + result = popups[i]->dispatch_expose_event(); + } + if( !result ) + result = dispatch_expose_event(); break; case MotionNotify: @@ -1268,35 +1272,8 @@ locking_message = event->xclient.message_type; case XK_F10: key_pressed = KEY_F10; break; case XK_F11: key_pressed = KEY_F11; break; case XK_F12: key_pressed = KEY_F12; break; - +// activates remote case XK_Menu: key_pressed = KPMENU; break; /* menu */ -// remote control -// above case XK_KP_Enter: key_pressed = KPENTER; break; /* check */ - case XF86XK_MenuKB: key_pressed = KPMENU; break; /* menu */ -// intercepted case XF86XK_PowerDown: key_pressed = KPPOWER; break; /* Power */ - case XF86XK_Launch1: key_pressed = KPTV; break; /* TV */ - case XF86XK_Launch2: key_pressed = KPDVD; break; /* DVD */ -// intercepted case XF86XK_WWW: key_pressed = KPWWEB; break; /* WEB */ - case XF86XK_Launch3: key_pressed = KPBOOK; break; /* book */ - case XF86XK_Launch4: key_pressed = KPHAND; break; /* hand */ - case XF86XK_Reply: key_pressed = KPTMR; break; /* timer */ - case SunXK_Front: key_pressed = KPMAXW; break; /* max */ -// above case XK_Left: key_pressed = LEFT; break; /* left */ -// above case XK_Right: key_pressed = RIGHT; break; /* right */ -// above case XK_Down: key_pressed = DOWN; break; /* down */ -// above case XK_Up: key_pressed = UP; break; /* up */ -// above case XK_SPACE: key_pressed = KPSPACE; break; /* ok */ -// intercepted case XF86XK_AudioRaiseVolume: key_pressed = KPVOLU; break; /* VOL + */ -// intercepted case XF86XK_AudioMute: key_pressed = KPMUTE; break; /* MUTE */ -// intercepted case XF86XK_AudioLowerVolume: key_pressed = KPVOLD; break; /* VOL - */ - case XF86XK_ScrollUp: key_pressed = KPCHUP; break; /* CH + */ - case XF86XK_ScrollDown: key_pressed = KPCHDN; break; /* CH - */ - case XF86XK_AudioRecord: key_pressed = KPRECD; break; /* ( o) red */ - case XF86XK_Forward: key_pressed = KPPLAY; break; /* ( >) */ - case XK_Redo: key_pressed = KPFWRD; break; /* (>>) */ - case XF86XK_Back: key_pressed = KPBACK; break; /* (<<) */ - case XK_Cancel: key_pressed = KPSTOP; break; /* ([]) */ - case XK_Pause: key_pressed = KPAUSE; break; /* ('') */ default: key_pressed = keysym & 0xff; @@ -1754,6 +1731,90 @@ int BC_WindowBase::close_event() return 1; } +// *** CONTEXT_HELP *** +// This basic implementation serves solely for context help. +// We are handling Alt/H only. Any subclass requiring more sophisticated +// processing of keystrokes has to provide its own overloaded handler. +int BC_WindowBase::keypress_event() +{ +// printf("BC_WindowBase::keypress_event: %d\n", get_keypress()); + return context_help_check_and_show(); +} + +// The stuff up to END_CONTEXT_HELP serves solely for context help +void BC_WindowBase::context_help_set_keyword(const char *keyword) +{ + if (keyword) strcpy(context_help_keyword, keyword); +} + +const char *BC_WindowBase::context_help_get_keyword() +{ +// If we have context_help_keyword defined here, return it. +// Otherwise recursively track widget hierarchy up to top_level +// and return the nearest found nonempty keyword. +// If nothing found, the special keyword "TOC" is returned. + if (context_help_keyword[0] || this == top_level || + this == parent_window || ! parent_window) { + if (! context_help_keyword[0] && this == top_level) + context_help_set_keyword("TOC"); + return context_help_keyword; + } + return parent_window->context_help_get_keyword(); +} + +void BC_WindowBase::context_help_show(const char *keyword) +{ + char cmd[BCTEXTLEN]; + + if (! keyword) return; + + sprintf(cmd, "\"%s/doc/ContextManual.pl\" \"%s\"", getenv("CIN_DAT"), + keyword); +// printf("BC_WindowBase::context_help_show(%s):\n%s\n", keyword, cmd); + +// ContextManual.pl starts browser in background, so system() should not block + system(cmd); +} + +void BC_WindowBase::context_help_show() +{ + context_help_show(context_help_get_keyword()); +} + +int BC_WindowBase::context_help_check_and_show(const char *keyword) +{ + if (! keyword) return 0; + if (! keyword[0]) return 0; + +// We are handling Alt/H only + if (get_keypress() != 'h' || ! alt_down()) return 0; + +// Restrict cursor location to that widget keystroke occured in + if (! is_tooltip_event_win() || ! cursor_inside()) return 0; + + context_help_show(keyword); + return 1; +} + +int BC_WindowBase::context_help_check_and_show() +{ + const char *keyword; + +// We are handling Alt/H only + if (get_keypress() != 'h' || ! alt_down()) return 0; + +// Restrict cursor location, so any subwindow can define its own help keyword + if (! is_tooltip_event_win() || ! cursor_inside()) return 0; + +// If a widget has not defined its own help keyword, the parent can provide it + keyword = context_help_get_keyword(); + if (! keyword[0]) return 0; + + context_help_show(keyword); + return 1; +} +// *** END_CONTEXT_HELP *** + int BC_WindowBase::dispatch_drag_start() { int result = 0; @@ -2090,15 +2151,8 @@ int BC_WindowBase::init_colors() char *data = 0; XImage *ximage; ximage = XCreateImage(top_level->display, - top_level->vis, - top_level->default_depth, - ZPixmap, - 0, - data, - 16, - 16, - 8, - 0); + top_level->vis, top_level->default_depth, + ZPixmap, 0, data, 16, 16, 8, 0); bits_per_pixel = ximage->bits_per_pixel; XDestroyImage(ximage); @@ -2309,21 +2363,21 @@ int BC_WindowBase::init_gc() int BC_WindowBase::init_fonts() { - if( !(smallfont = XLoadQueryFont(display, _(resources.small_font))) ) - if( !(smallfont = XLoadQueryFont(display, _(resources.small_font2))) ) + if( !(smallfont = XLoadQueryFont(display, _(resources->small_font))) ) + if( !(smallfont = XLoadQueryFont(display, _(resources->small_font2))) ) smallfont = XLoadQueryFont(display, "fixed"); - if( !(mediumfont = XLoadQueryFont(display, _(resources.medium_font))) ) - if( !(mediumfont = XLoadQueryFont(display, _(resources.medium_font2))) ) + if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font))) ) + if( !(mediumfont = XLoadQueryFont(display, _(resources->medium_font2))) ) mediumfont = XLoadQueryFont(display, "fixed"); - if( !(largefont = XLoadQueryFont(display, _(resources.large_font))) ) - if( !(largefont = XLoadQueryFont(display, _(resources.large_font2))) ) + if( !(largefont = XLoadQueryFont(display, _(resources->large_font))) ) + if( !(largefont = XLoadQueryFont(display, _(resources->large_font2))) ) largefont = XLoadQueryFont(display, "fixed"); - if( !(bigfont = XLoadQueryFont(display, _(resources.big_font))) ) - if( !(bigfont = XLoadQueryFont(display, _(resources.big_font2))) ) + if( !(bigfont = XLoadQueryFont(display, _(resources->big_font))) ) + if( !(bigfont = XLoadQueryFont(display, _(resources->big_font2))) ) bigfont = XLoadQueryFont(display, "fixed"); - if((clockfont = XLoadQueryFont(display, _(resources.clock_font))) == NULL) - if((clockfont = XLoadQueryFont(display, _(resources.clock_font2))) == NULL) + if((clockfont = XLoadQueryFont(display, _(resources->clock_font))) == NULL) + if((clockfont = XLoadQueryFont(display, _(resources->clock_font2))) == NULL) clockfont = XLoadQueryFont(display, "fixed"); init_xft(); @@ -2333,19 +2387,19 @@ int BC_WindowBase::init_fonts() int n; // FIXME: should check the m,d,n values - smallfontset = XCreateFontSet(display, resources.small_fontset, &m, &n, &d); + smallfontset = XCreateFontSet(display, resources->small_fontset, &m, &n, &d); if( !smallfontset ) smallfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d); - mediumfontset = XCreateFontSet(display, resources.medium_fontset, &m, &n, &d); + mediumfontset = XCreateFontSet(display, resources->medium_fontset, &m, &n, &d); if( !mediumfontset ) mediumfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d); - largefontset = XCreateFontSet(display, resources.large_fontset, &m, &n, &d); + largefontset = XCreateFontSet(display, resources->large_fontset, &m, &n, &d); if( !largefontset ) largefontset = XCreateFontSet(display, "fixed,*", &m, &n, &d); - bigfontset = XCreateFontSet(display, resources.big_fontset, &m, &n, &d); + bigfontset = XCreateFontSet(display, resources->big_fontset, &m, &n, &d); if( !bigfontset ) bigfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d); - clockfontset = XCreateFontSet(display, resources.clock_fontset, &m, &n, &d); + clockfontset = XCreateFontSet(display, resources->clock_fontset, &m, &n, &d); if( !clockfontset ) clockfontset = XCreateFontSet(display, "fixed,*", &m, &n, &d); if(clockfontset && bigfontset && largefontset && mediumfontset && smallfontset) { @@ -2369,54 +2423,54 @@ void BC_WindowBase::init_xft() static Mutex xft_init_lock("BC_WindowBase::xft_init_lock", 0); xft_init_lock.lock("BC_WindowBase::init_xft"); if(!(smallfont_xft = - (resources.small_font_xft[0] == '-' ? - xftFontOpenXlfd(display, screen, resources.small_font_xft) : - xftFontOpenName(display, screen, resources.small_font_xft))) ) + (resources->small_font_xft[0] == '-' ? + xftFontOpenXlfd(display, screen, resources->small_font_xft) : + xftFontOpenName(display, screen, resources->small_font_xft))) ) if(!(smallfont_xft = - xftFontOpenXlfd(display, screen, resources.small_font_xft2))) + xftFontOpenXlfd(display, screen, resources->small_font_xft2))) smallfont_xft = xftFontOpenXlfd(display, screen, "fixed"); if(!(mediumfont_xft = - (resources.medium_font_xft[0] == '-' ? - xftFontOpenXlfd(display, screen, resources.medium_font_xft) : - xftFontOpenName(display, screen, resources.medium_font_xft))) ) + (resources->medium_font_xft[0] == '-' ? + xftFontOpenXlfd(display, screen, resources->medium_font_xft) : + xftFontOpenName(display, screen, resources->medium_font_xft))) ) if(!(mediumfont_xft = - xftFontOpenXlfd(display, screen, resources.medium_font_xft2))) + xftFontOpenXlfd(display, screen, resources->medium_font_xft2))) mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed"); if(!(largefont_xft = - (resources.large_font_xft[0] == '-' ? - xftFontOpenXlfd(display, screen, resources.large_font_xft) : - xftFontOpenName(display, screen, resources.large_font_xft))) ) + (resources->large_font_xft[0] == '-' ? + xftFontOpenXlfd(display, screen, resources->large_font_xft) : + xftFontOpenName(display, screen, resources->large_font_xft))) ) if(!(largefont_xft = - xftFontOpenXlfd(display, screen, resources.large_font_xft2))) + xftFontOpenXlfd(display, screen, resources->large_font_xft2))) largefont_xft = xftFontOpenXlfd(display, screen, "fixed"); if(!(bigfont_xft = - (resources.big_font_xft[0] == '-' ? - xftFontOpenXlfd(display, screen, resources.big_font_xft) : - xftFontOpenName(display, screen, resources.big_font_xft))) ) + (resources->big_font_xft[0] == '-' ? + xftFontOpenXlfd(display, screen, resources->big_font_xft) : + xftFontOpenName(display, screen, resources->big_font_xft))) ) if(!(bigfont_xft = - xftFontOpenXlfd(display, screen, resources.big_font_xft2))) + xftFontOpenXlfd(display, screen, resources->big_font_xft2))) bigfont_xft = xftFontOpenXlfd(display, screen, "fixed"); if(!(clockfont_xft = - (resources.clock_font_xft[0] == '-' ? - xftFontOpenXlfd(display, screen, resources.clock_font_xft) : - xftFontOpenName(display, screen, resources.clock_font_xft))) ) + (resources->clock_font_xft[0] == '-' ? + xftFontOpenXlfd(display, screen, resources->clock_font_xft) : + xftFontOpenName(display, screen, resources->clock_font_xft))) ) clockfont_xft = xftFontOpenXlfd(display, screen, "fixed"); if(!(bold_smallfont_xft = - (resources.small_b_font_xft[0] == '-' ? - xftFontOpenXlfd(display, screen, resources.small_b_font_xft) : - xftFontOpenName(display, screen, resources.small_b_font_xft))) ) + (resources->small_b_font_xft[0] == '-' ? + xftFontOpenXlfd(display, screen, resources->small_b_font_xft) : + xftFontOpenName(display, screen, resources->small_b_font_xft))) ) bold_smallfont_xft = xftFontOpenXlfd(display, screen, "fixed"); if(!(bold_mediumfont_xft = - (resources.medium_b_font_xft[0] == '-' ? - xftFontOpenXlfd(display, screen, resources.medium_b_font_xft) : - xftFontOpenName(display, screen, resources.medium_b_font_xft))) ) + (resources->medium_b_font_xft[0] == '-' ? + xftFontOpenXlfd(display, screen, resources->medium_b_font_xft) : + xftFontOpenName(display, screen, resources->medium_b_font_xft))) ) bold_mediumfont_xft = xftFontOpenXlfd(display, screen, "fixed"); if(!(bold_largefont_xft = - (resources.large_b_font_xft[0] == '-' ? - xftFontOpenXlfd(display, screen, resources.large_b_font_xft) : - xftFontOpenName(display, screen, resources.large_b_font_xft))) ) + (resources->large_b_font_xft[0] == '-' ? + xftFontOpenXlfd(display, screen, resources->large_b_font_xft) : + xftFontOpenName(display, screen, resources->large_b_font_xft))) ) bold_largefont_xft = xftFontOpenXlfd(display, screen, "fixed"); if( !smallfont_xft || !mediumfont_xft || !largefont_xft || !bigfont_xft || @@ -2424,14 +2478,14 @@ xft_init_lock.lock("BC_WindowBase::init_xft"); !clockfont_xft ) { printf("BC_WindowBase::init_fonts: no xft fonts found:" " %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n %s=%p\n", - resources.small_font_xft, smallfont_xft, - resources.medium_font_xft, mediumfont_xft, - resources.large_font_xft, largefont_xft, - resources.big_font_xft, bigfont_xft, - resources.clock_font_xft, clockfont_xft, - resources.small_b_font_xft, bold_smallfont_xft, - resources.medium_b_font_xft, bold_mediumfont_xft, - resources.large_b_font_xft, bold_largefont_xft); + resources->small_font_xft, smallfont_xft, + resources->medium_font_xft, mediumfont_xft, + resources->large_font_xft, largefont_xft, + resources->big_font_xft, bigfont_xft, + resources->clock_font_xft, clockfont_xft, + resources->small_b_font_xft, bold_smallfont_xft, + resources->medium_b_font_xft, bold_mediumfont_xft, + resources->large_b_font_xft, bold_largefont_xft); get_resources()->use_xft = 0; exit(1); } @@ -2441,6 +2495,33 @@ xft_init_lock.unlock(); #endif // HAVE_XFT } +void BC_WindowBase::init_glyphs() +{ +// draw all ascii char glyphs +// There are problems with some/my graphics boards/drivers +// which cause some glyphs to be munged if draws occur while +// the font is being loaded. This code fills the font caches +// by drawing all the ascii glyphs before the system starts. +// Not a fix, but much better than nothing. + static int inited = 0; + if( inited ) return; + XGrabServer(display); + XSync(display, 0); + inited = 1; + int cur_font = current_font; +// locale encodings, needed glyphs to be preloaded + const char *text = _( // ascii 0x20...0x7e + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~"); + for( int font=SMALLFONT; font<=LARGEFONT; ++font ) { + set_font(font); + draw_text(5,5, text); + } + set_font(cur_font); + XUngrabServer(display); +} + void BC_WindowBase::init_im() { XIMStyles *xim_styles; @@ -2449,7 +2530,11 @@ void BC_WindowBase::init_im() if(!(input_method = XOpenIM(display, NULL, NULL, NULL))) { printf("BC_WindowBase::init_im: Could not open input method.\n"); + XSetLocaleModifiers("@im=local"); + if(!(input_method = XOpenIM(display, NULL, NULL, NULL))) { + printf("BC_WindowBase::init_im: Could not open input method local.\n"); exit(1); + } } if(XGetIMValues(input_method, XNQueryInputStyle, &xim_styles, NULL) || xim_styles == NULL) @@ -2958,10 +3043,10 @@ int BC_WindowBase::get_text_width(int font, const char *text, int length) return w; } -int BC_WindowBase::get_text_width(int font, const wchar_t *text, int length) +int BC_WindowBase::get_text_width(int font, const wchr_t *text, int length) { int i, j, w = 0; - if( length < 0 ) length = wcslen(text); + if( length < 0 ) length = wstrlen(text); for( i=j=0; i max_w ) { +// get center of string + int cx = text_w/2, best = INT_MAX; + for( int i=1; i<=len; ++i ) { + int cw = get_text_width(font, text, i); + if( abs(cw-cx) < abs(best-cx) ) { + best = cw; ci = i; + } + } + } + if( ci > 0 && ci < len-1 ) { +// insert ... in the center + result[ci-1] = result[ci] = result[ci+1] = '.'; + + while( ci-2>=0 && ci+2<(int)strlen(result) && + get_text_width(font, result) > max_w ) { +// take away a character from the longer side + int left_w = get_text_width(font, result, ci-2); + int right_w = get_text_width(font, result + ci+3); + int i = left_w > right_w ? --ci-1 : ci+2; + while( (result[i]=result[i+1])!=0 ) ++i; + } + } + + return result; +} + BC_Bitmap* BC_WindowBase::new_bitmap(int w, int h, int color_model) { if(color_model < 0) color_model = top_level->get_color_model(); @@ -3095,6 +3213,7 @@ int BC_WindowBase::accel_available(int color_model, int lock_it) int BC_WindowBase::grab_port_id(int color_model) { +#ifdef HAVE_XV if( !get_resources()->use_xvideo || // disabled !get_resources()->use_shm ) // Only local server is fast enough. return -1; @@ -3141,8 +3260,10 @@ int BC_WindowBase::grab_port_id(int color_model) } XvFreeAdaptorInfo(info); - return xvideo_port_id; +#else + return -1; +#endif } @@ -3334,6 +3455,23 @@ int BC_WindowBase::unlock_window() return 0; } +int BC_WindowBase::break_lock() +{ + if( !top_level ) return 0; + if( top_level != this ) return top_level->break_lock(); + if( top_level->display_lock_owner != pthread_self() ) return 0; + if( top_level->window_lock != 1 ) return 0; + UNSET_LOCK(this); + window_lock = 0; + display_lock_owner = 0; +#ifdef SINGLE_THREAD + BC_Display::unlock_display(); +#else + XUnlockDisplay(display); +#endif + return 1; +} + void BC_WindowBase::set_done(int return_value) { if(done_set) return; @@ -3373,17 +3511,36 @@ void BC_WindowBase::close(int return_value) int BC_WindowBase::grab(BC_WindowBase *window) { - if( window->active_grab && this != window->active_grab ) return 0; - window->active_grab = this; - this->grab_active = window; - return 1; + int ret = 0; + BC_WindowBase *grab_window = window->active_grab; + if( grab_window ) { + int locked = get_window_lock(); + if( locked ) unlock_window(); + grab_window->lock_window("BC_WindowBase::grab(BC_WindowBase"); + grab_window->handle_ungrab(); + grab_window->unlock_window(); + if( locked ) lock_window("BC_WindowBase::grab(BC_WindowBase"); + } + window->grab_lock->lock("BC_WindowBase::grab"); + if( !window->active_grab ) { + window->active_grab = this; + this->grab_active = window; + ret = 1; + } + window->grab_lock->unlock(); + return ret; } int BC_WindowBase::ungrab(BC_WindowBase *window) { - if( window->active_grab && this != window->active_grab ) return 0; - window->active_grab = 0; - this->grab_active = 0; - return 1; + int ret = 0; + window->grab_lock->lock("BC_WindowBase::ungrab"); + if( this == window->active_grab ) { + window->active_grab = 0; + this->grab_active = 0; + ret = 1; + } + window->grab_lock->unlock(); + return ret; } int BC_WindowBase::grab_event_count() { @@ -3619,12 +3776,12 @@ int BC_WindowBase::get_color_model() BC_Resources* BC_WindowBase::get_resources() { - return &BC_WindowBase::resources; + return BC_WindowBase::resources; } BC_Synchronous* BC_WindowBase::get_synchronous() { - return BC_WindowBase::resources.get_synchronous(); + return BC_WindowBase::resources->get_synchronous(); } int BC_WindowBase::get_bg_color() @@ -3861,13 +4018,13 @@ int BC_WindowBase::get_abs_cursor_y(int lock_window) void BC_WindowBase::get_pop_cursor(int &px, int &py, int lock_window) { - int margin = 100; + int xmargin = xS(100), ymargin = yS(100); get_abs_cursor(px, py, lock_window); - if( px < margin ) px = margin; - if( py < margin ) py = margin; - int wd = get_screen_w(lock_window,-1) - margin; + if( px < xmargin ) px = xmargin; + if( py < ymargin ) py = ymargin; + int wd = get_screen_x(lock_window,-1) + get_screen_w(lock_window,-1) - xmargin; if( px > wd ) px = wd; - int ht = get_screen_h(lock_window,-1) - margin; + int ht = get_screen_y(lock_window,-1) + get_screen_h(lock_window,-1) - ymargin; if( py > ht ) py = ht; } int BC_WindowBase::get_pop_cursor_x(int lock_window) @@ -3968,6 +4125,12 @@ int BC_WindowBase::is_event_win() return this->win == top_level->event_win; } +int BC_WindowBase::is_tooltip_event_win() +{ + return this->win == top_level->event_win || + tooltip_popup && tooltip_popup->win == top_level->event_win; +} + void BC_WindowBase::set_dragging(int value) { is_dragging = value; @@ -4003,7 +4166,7 @@ int BC_WindowBase::ctrl_down() return top_level->ctrl_mask; } -wchar_t* BC_WindowBase::get_wkeystring(int *length) +wchr_t* BC_WindowBase::get_wkeystring(int *length) { if(length) *length = top_level->wkey_string_length; @@ -4052,6 +4215,11 @@ int BC_WindowBase::resize_window(int w, int h) size_hints.max_width = w; size_hints.min_height = h; size_hints.max_height = h; + if( this->x > -BC_INFINITY && this->x < BC_INFINITY ) { + size_hints.flags |= PPosition; + size_hints.x = this->x; + size_hints.y = this->y; + } XSetNormalHints(top_level->display, win, &size_hints); } XResizeWindow(top_level->display, win, w, h); @@ -4123,21 +4291,15 @@ int BC_WindowBase::reposition_window(int x, int y, int w, int h) { // KDE shifts window right and down. // FVWM leaves window alone and adds border around it. - XMoveResizeWindow(top_level->display, - win, + XMoveResizeWindow(top_level->display, win, x - BC_DisplayInfo::auto_reposition_x, y - BC_DisplayInfo::auto_reposition_y, - this->w, - this->h); + this->w, this->h); } else { - XMoveResizeWindow(top_level->display, - win, - x, - y, - this->w, - this->h); + XMoveResizeWindow(top_level->display, win, x, y, + this->w, this->h); } if(resize) @@ -4179,6 +4341,8 @@ void BC_WindowBase::set_force_tooltip(int v) int BC_WindowBase::raise_window(int do_flush) { + if( hidden ) return 1; + if( wait_viewable(500) ) return 1; XRaiseWindow(top_level->display, win); if(do_flush) XFlush(top_level->display); return 0; @@ -4235,6 +4399,26 @@ void BC_WindowBase::set_title(const char *text, int utf8) flush(); } +// must be RGBA8888 +void BC_WindowBase::set_net_icon(VFrame *data) +{ + int width = data->get_w(), height = data->get_h(); + int size = 2 + width * height; + unsigned long *icon_data = new unsigned long[size]; + unsigned long *lp = icon_data; + *lp++ = width; *lp++ = height; + uint8_t **rows = data->get_rows(); + for( int y=0; ydisplay, top_level->win, NetWMIcon, + XA_CARDINAL, 32, PropModeReplace, (unsigned char *)icon_data, size); + delete [] icon_data; +} + const char *BC_WindowBase::get_title() { return title; @@ -4256,31 +4440,62 @@ int BC_WindowBase::set_icon(VFrame *data) icon_pixmap = new BC_Pixmap(top_level, data, PIXMAP_ALPHA, 1); if(icon_window) delete icon_window; - icon_window = new BC_Popup(this, - (int)BC_INFINITY, - (int)BC_INFINITY, - icon_pixmap->get_w(), - icon_pixmap->get_h(), - -1, - 1, // All windows are hidden initially + icon_window = new BC_Popup(this, 0, 0, + icon_pixmap->get_w(), icon_pixmap->get_h(), + -1, 1, // All windows are hidden initially icon_pixmap); - XWMHints wm_hints; - wm_hints.flags = WindowGroupHint | IconPixmapHint | IconMaskHint | IconWindowHint; + XWMHints wm_hints; memset(&wm_hints, 0, sizeof(wm_hints)); + wm_hints.flags = IconPixmapHint; // | IconMaskHint | IconWindowHint; wm_hints.icon_pixmap = icon_pixmap->get_pixmap(); wm_hints.icon_mask = icon_pixmap->get_alpha(); wm_hints.icon_window = icon_window->win; - wm_hints.window_group = XGroupLeader; + if( XGroupLeader ) { + wm_hints.flags |= WindowGroupHint; + wm_hints.window_group = XGroupLeader; + } // for(int i = 0; i < 1000; i++) // printf("02x ", icon_pixmap->get_alpha()->get_row_pointers()[0][i]); // printf("\n"); XSetWMHints(top_level->display, top_level->win, &wm_hints); + + set_net_icon(data); XSync(top_level->display, 0); return 0; } +void BC_WindowBase::init_resources(float scale) +{ + if( resources ) return; + XInitThreads(); + const char *env = getenv("BC_SCALE"); + if( env ) scale = atof(env); + float x_scale = 1, y_scale = 1; + if( scale <= 0 ) { + BC_DisplayInfo info; + int wx, wy, ww, wh; + int cins = info.xinerama_big_screen(); + if( !info.xinerama_geometry(cins, wx, wy, ww, wh) ) { + int sh = ww * 9 / 16; + int sw = wh * 16 / 9; + if( sw < ww ) ww = sw; + if( sh < wh ) wh = sh; + if( (x_scale = ww/1920.) < 1 ) x_scale = 1; + if( (y_scale = wh/1080.) < 1 ) y_scale = 1; + } + } + else + x_scale = y_scale = scale; + // constructor sets BC_WindowBase::resources + new BC_Resources(x_scale, y_scale); +} +void BC_WindowBase::finit_resources() +{ + delete resources; resources = 0; +} + int BC_WindowBase::set_w(int w) { this->w = w; @@ -4295,7 +4510,6 @@ int BC_WindowBase::set_h(int h) int BC_WindowBase::load_defaults(BC_Hash *defaults) { - BC_Resources *resources = get_resources(); char string[BCTEXTLEN]; int newest_id = - 1; for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++) @@ -4328,7 +4542,6 @@ int BC_WindowBase::load_defaults(BC_Hash *defaults) int BC_WindowBase::save_defaults(BC_Hash *defaults) { - BC_Resources *resources = get_resources(); char string[BCTEXTLEN]; for(int i = 0; i < FILEBOX_HISTORY_SIZE; i++) { @@ -4357,12 +4570,8 @@ int BC_WindowBase::save_defaults(BC_Hash *defaults) // For some reason XTranslateCoordinates can take a long time to return. // We work around this by only calling it when the event windows are different. -void BC_WindowBase::translate_coordinates(Window src_w, - Window dest_w, - int src_x, - int src_y, - int *dest_x_return, - int *dest_y_return) +void BC_WindowBase::translate_coordinates(Window src_w, Window dest_w, + int src_x, int src_y, int *dest_x_return, int *dest_y_return) { Window tempwin = 0; //Timer timer; @@ -4374,14 +4583,8 @@ void BC_WindowBase::translate_coordinates(Window src_w, } else { - XTranslateCoordinates(top_level->display, - src_w, - dest_w, - src_x, - src_y, - dest_x_return, - dest_y_return, - &tempwin); + XTranslateCoordinates(top_level->display, src_w, dest_w, + src_x, src_y, dest_x_return, dest_y_return, &tempwin); //printf("BC_WindowBase::translate_coordinates 1 %lld\n", timer.get_difference()); } } @@ -4397,10 +4600,6 @@ void BC_WindowBase::get_win_coordinates(int abs_x, int abs_y, int *x, int *y) } - - - - #ifdef HAVE_LIBXXF86VM void BC_WindowBase::closest_vm(int *vm, int *width, int *height) { @@ -4564,3 +4763,15 @@ void BC_WindowBase::focus() XSetInputFocus(top_level->display, top_level->win, RevertToParent, CurrentTime); } +int BC_WindowBase::wait_viewable(int ms) +{ + Timer timer; + XWindowAttributes xwa; + do { + XGetWindowAttributes(top_level->display, top_level->win, &xwa); + if( xwa.map_state == IsViewable ) return 0; + usleep(10000); + } while( timer.get_difference() < ms ); + return 1; +} +