rework bcresources static vframe initializers, add CIN_XSYNCH
[goodguy/history.git] / cinelerra-5.1 / guicast / bcwindowbase.C
index 7d4fa2b56185dd047d93dc101f5d58546828d810..fae98cb186b9315572190fa6abd940e3d2f84a0b 100644 (file)
@@ -113,17 +113,23 @@ BC_WindowBase::~BC_WindowBase()
        {
 // stop event input
                XSelectInput(top_level->display, this->win, 0);
-               motion_events = resize_events = translation_events = 0;
+               XSync(top_level->display,0);
 #ifndef SINGLE_THREAD
                top_level->dequeue_events(win);
 #endif
+// drop active window refs to this
                if(top_level->active_menubar == this) top_level->active_menubar = 0;
                if(top_level->active_popup_menu == this) top_level->active_popup_menu = 0;
                if(top_level->active_subwindow == this) top_level->active_subwindow = 0;
+// drop motion window refs to this
+               if(top_level->motion_events && top_level->last_motion_win == this->win)
+                       top_level->motion_events = 0;
+
 // Remove pointer from parent window to this
                parent_window->subwindows->remove(this);
        }
 
+       if(grab_active) grab_active->active_grab = 0;
        if(icon_window) delete icon_window;
        if(window_type == POPUP_WINDOW)
                parent_window->remove_popup(this);
@@ -175,9 +181,10 @@ BC_WindowBase::~BC_WindowBase()
                for( int i=sizeof(xfont)/sizeof(xfont[0]); --i>=0; )
                        XFreeFont(display, this->*xfont[i]);
 
-// bug in X causes XRenderExtensionInfo to be damaged if this is done here
-//  left to be done in XCloseDisplay by Xlib.
-#if defined(HAVE_XFT) && 0
+// past bug in X caused XRenderExtensionInfo to be damaged
+// if this is done here. left to be done in XCloseDisplay by Xlib.
+// works in more modern systems, and needed for leak testing.
+#if defined(HAVE_XFT) && defined(VALGRIND)
                static void *BC_WindowBase::*xft_font[] = {
                         &BC_WindowBase::smallfont_xft,
                         &BC_WindowBase::mediumfont_xft,
@@ -284,6 +291,8 @@ int BC_WindowBase::initialize()
        event_win = 0;
        last_motion_win = 0;
        key_pressed = 0;
+       active_grab = 0;
+       grab_active = 0;
        active_menubar = 0;
        active_popup_menu = 0;
        active_subwindow = 0;
@@ -294,7 +303,6 @@ int BC_WindowBase::initialize()
        force_tooltip = 0;
 //     next_repeat_id = 0;
        tooltip_popup = 0;
-       tooltip_done = 0;
        current_font = MEDIUMFONT;
        current_color = BLACK;
        current_cursor = ARROW_CURSOR;
@@ -676,6 +684,15 @@ Display* BC_WindowBase::init_display(const char *display_name)
                        }
                }
        }
+
+       static int xsynch = -1;
+       if( xsynch < 0 ) {
+               const char *cp = getenv("CIN_XSYNCH");
+               xsynch = !cp ? 0 : atoi(cp);
+       }
+       if( xsynch > 0 )
+               XSynchronize(display, True);
+
        return display;
 }
 
@@ -955,8 +972,14 @@ locking_message = event->xclient.message_type;
 //   event_names[event->type] : "Unknown");
 //}
 
-
-
+       if( active_grab ) {
+               unlock_window();
+               active_grab->lock_window("BC_WindowBase::dispatch_event 3");
+               result = active_grab->grab_event(event);
+               active_grab->unlock_window();
+               if( result ) return result;
+               lock_window("BC_WindowBase::dispatch_event 4");
+       }
 
        switch(event->type) {
        case ClientMessage:
@@ -1760,69 +1783,54 @@ int BC_WindowBase::dispatch_drag_motion()
 }
 
 
-
-
-
-int BC_WindowBase::show_tooltip(int w, int h)
+int BC_WindowBase::show_tooltip(const char *text, int x, int y, int w, int h)
 {
-       Window tempwin;
-
-       if(tooltip_text && !tooltip_on &&
-               (force_tooltip || get_resources()->tooltips_enabled))
-       {
-               int x, y;
+// default text
+       int forced = !text ? force_tooltip : 1;
+       if( !text ) text = tooltip_text;
+       if( !text || (!forced && !get_resources()->tooltips_enabled) ) {
                top_level->hide_tooltip();
-
+               return 1;
+       }
+// default w,h
+       if(w < 0) w = get_text_width(MEDIUMFONT, text)  + TOOLTIP_MARGIN * 2;
+       if(h < 0) h = get_text_height(MEDIUMFONT, text) + TOOLTIP_MARGIN * 2;
+// default x,y (win relative)
+       if( x < 0 ) x = get_w();
+       if( y < 0 ) y = get_h();
+       int wx, wy;
+       get_root_coordinates(x, y, &wx, &wy);
+// keep the tip inside the window/display
+       int x0 = top_level->get_x(), x1 = x0 + top_level->get_w();
+       int x2 = top_level->get_screen_x(0, -1) + top_level->get_screen_w(0, -1);
+       if( x1 > x2 ) x1 = x2;
+       if( wx < x0 ) wx = x0;
+       if( wx >= (x1-=w) ) wx = x1;
+       int y0 = top_level->get_y(), y1 = y0 + top_level->get_h();
+       int y2 = top_level->get_root_h(0);
+       if( y1 > y2 ) y1 = y2;
+       if( wy < y0 ) wy = y0;
+       if( wy >= (y1-=h) ) wy = y1;
+// avoid tip under cursor (flickers)
+       int abs_x, abs_y;
+       get_abs_cursor_xy(abs_x,abs_y, 0);
+       if( wx < abs_x && abs_x < wx+w && wy < abs_y && abs_y < wy+h ) {
+               if( wx-abs_x < wy-abs_y )
+                       wx = abs_x+1;
+               else
+                       wy = abs_y+1;
+       }
+       if( !tooltip_on ) {
                tooltip_on = 1;
-               if(w < 0)
-                       w = get_text_width(MEDIUMFONT, tooltip_text);
-
-               if(h < 0)
-                       h = get_text_height(MEDIUMFONT, tooltip_text);
-
-               w += TOOLTIP_MARGIN * 2;
-               h += TOOLTIP_MARGIN * 2;
-
-               XTranslateCoordinates(top_level->display, win,
-                               top_level->rootwin, get_w(), get_h(),
-                               &x, &y, &tempwin);
-               // keep the tip inside the window/display
-               int top_x = top_level->get_x();
-               if( x < top_x ) x = top_x;
-               int top_w = top_x + top_level->get_w();
-               int lmt_w = top_level->get_screen_x(0, -1) + top_level->get_screen_w(0, -1);
-               if( top_w < lmt_w ) lmt_w = top_w;
-               if( x+w > lmt_w ) x = lmt_w-w;
-               if( x < 0 ) x = 0;
-               int top_y = top_level->get_y();
-               if( y < top_y ) y = top_y;
-               int top_h = top_y + top_level->get_h();
-               int lmt_h = top_level->get_root_h(0);
-               if( top_h < lmt_h ) lmt_h = top_h;
-               if( y+h > lmt_h ) y = lmt_h-h;
-               if( y < 0 ) y = 0;
-               int abs_x, abs_y, win_x, win_y;
-               unsigned int temp_mask;
-               Window temp_win;
-               XQueryPointer(top_level->display, top_level->win,
-                       &temp_win, &temp_win, &abs_x, &abs_y,
-                       &win_x, &win_y, &temp_mask);
-               // check for cursor inside popup
-               if( x < abs_x && abs_x < x+w && y < abs_y && abs_y < y+h )
-               {
-                       if( x-abs_x < y-abs_y )
-                               x = abs_x+1;
-                       else
-                               y = abs_y+1;
-               }
-               tooltip_popup = new BC_Popup(top_level, x, y, w, h,
-                                       get_resources()->tooltip_bg_color);
-
-               draw_tooltip();
-               tooltip_popup->set_font(MEDIUMFONT);
-               tooltip_popup->flash();
-               tooltip_popup->flush();
+               tooltip_popup = new BC_Popup(top_level, wx, wy, w, h,
+                               get_resources()->tooltip_bg_color);
        }
+       else
+               tooltip_popup->reposition_window(wx, wy, w, h);
+
+       draw_tooltip(text);
+       tooltip_popup->flash();
+       tooltip_popup->flush();
        return 0;
 }
 
@@ -1860,7 +1868,6 @@ int BC_WindowBase::set_tooltip(const char *text)
        }
        return 0;
 }
-
 // signal the event handler to repeat
 int BC_WindowBase::set_repeat(int64_t duration)
 {
@@ -2015,9 +2022,9 @@ void BC_WindowBase::init_cursors()
        downleft_resize_cursor = XCreateFontCursor(display, XC_bottom_left_corner);
        downright_resize_cursor = XCreateFontCursor(display, XC_bottom_right_corner);
        hourglass_cursor = XCreateFontCursor(display, XC_watch);
+       grabbed_cursor = create_grab_cursor();
 
-
-       char cursor_data[] = { 0,0,0,0, 0,0,0,0 };
+       static char cursor_data[] = { 0,0,0,0, 0,0,0,0 };
        Colormap colormap = DefaultColormap(display, screen);
        Pixmap pixmap_bottom = XCreateBitmapFromData(display,
                rootwin, cursor_data, 8, 8);
@@ -2178,6 +2185,53 @@ int BC_WindowBase::create_shared_colors()
        return 0;
 }
 
+Cursor BC_WindowBase::create_grab_cursor()
+{
+       int iw = 23, iw1 = iw-1, iw2 = iw/2;
+       int ih = 23, ih1 = ih-1, ih2 = ih/2;
+       VFrame grab(iw,ih,BC_RGB888);
+       grab.clear_frame();
+       grab.set_pixel_color(RED);   // fg
+       grab.draw_smooth(iw2,0,   iw1,0,   iw1,ih2);
+       grab.draw_smooth(iw1,ih2, iw1,ih1, iw2,ih1);
+       grab.draw_smooth(iw2,ih1, 0,ih1,   0,ih2);
+       grab.draw_smooth(0,ih2,   0,0,     iw2,0);
+       grab.set_pixel_color(WHITE); // bg
+       grab.draw_line(0,ih2,     iw2-2,ih2);
+       grab.draw_line(iw2+2,ih2, iw1,ih2);
+       grab.draw_line(iw2,0,     iw2,ih2-2);
+       grab.draw_line(iw2,ih2+2, iw2,ih1);
+
+       int bpl = (iw+7)/8, isz = bpl * ih;
+       char img[isz];  memset(img, 0, isz);
+       char msk[isz];  memset(msk, 0, isz);
+       unsigned char **rows = grab.get_rows();
+       for( int iy=0; iy<ih; ++iy ) {
+               char *op = img + iy*bpl;
+               char *mp = msk + iy*bpl;
+               unsigned char *ip = rows[iy];
+               for( int ix=0; ix<iw; ++ix,ip+=3 ) {
+                       if( ip[0] ) mp[ix>>3] |= (1<<(ix&7));
+                       if( !ip[1] ) op[ix>>3] |= (1<<(ix&7));
+               }
+       }
+       unsigned long white_pix = WhitePixel(display, screen);
+       unsigned long black_pix = BlackPixel(display, screen);
+       Pixmap img_xpm = XCreatePixmapFromBitmapData(display, rootwin,
+               img, iw,ih, white_pix,black_pix, 1);
+       Pixmap msk_xpm = XCreatePixmapFromBitmapData(display, rootwin,
+               msk, iw,ih, white_pix,black_pix, 1);
+
+       XColor fc, bc;
+       fc.flags = bc.flags = DoRed | DoGreen | DoBlue;
+       fc.red = 0xffff; fc.green = fc.blue = 0;  // fg
+       bc.red = bc.green = bc.blue = 0x0000;     // bg
+       Cursor cursor = XCreatePixmapCursor(display, img_xpm,msk_xpm, &fc,&bc, iw2,ih2);
+       XFreePixmap(display, img_xpm);
+       XFreePixmap(display, msk_xpm);
+       return cursor;
+}
+
 int BC_WindowBase::allocate_color_table()
 {
        int red, green, blue, color;
@@ -2573,21 +2627,22 @@ Cursor BC_WindowBase::get_cursor_struct(int cursor)
 {
        switch(cursor)
        {
-               case ARROW_CURSOR:         return top_level->arrow_cursor;                 break;
+               case ARROW_CURSOR:         return top_level->arrow_cursor;
                case CROSS_CURSOR:         return top_level->cross_cursor;
-               case IBEAM_CURSOR:         return top_level->ibeam_cursor;                 break;
-               case VSEPARATE_CURSOR:     return top_level->vseparate_cursor;             break;
-               case HSEPARATE_CURSOR:     return top_level->hseparate_cursor;             break;
-               case MOVE_CURSOR:              return top_level->move_cursor;                  break;
-               case LEFT_CURSOR:          return top_level->left_cursor;                  break;
-               case RIGHT_CURSOR:         return top_level->right_cursor;                 break;
-               case UPRIGHT_ARROW_CURSOR: return top_level->upright_arrow_cursor;         break;
-               case UPLEFT_RESIZE:        return top_level->upleft_resize_cursor;         break;
-               case UPRIGHT_RESIZE:       return top_level->upright_resize_cursor;        break;
-               case DOWNLEFT_RESIZE:      return top_level->downleft_resize_cursor;       break;
-               case DOWNRIGHT_RESIZE:     return top_level->downright_resize_cursor;      break;
-               case HOURGLASS_CURSOR:     return top_level->hourglass_cursor;                 break;
-               case TRANSPARENT_CURSOR:   return top_level->transparent_cursor;               break;
+               case IBEAM_CURSOR:         return top_level->ibeam_cursor;
+               case VSEPARATE_CURSOR:     return top_level->vseparate_cursor;
+               case HSEPARATE_CURSOR:     return top_level->hseparate_cursor;
+               case MOVE_CURSOR:          return top_level->move_cursor;
+               case LEFT_CURSOR:          return top_level->left_cursor;
+               case RIGHT_CURSOR:         return top_level->right_cursor;
+               case UPRIGHT_ARROW_CURSOR: return top_level->upright_arrow_cursor;
+               case UPLEFT_RESIZE:        return top_level->upleft_resize_cursor;
+               case UPRIGHT_RESIZE:       return top_level->upright_resize_cursor;
+               case DOWNLEFT_RESIZE:      return top_level->downleft_resize_cursor;
+               case DOWNRIGHT_RESIZE:     return top_level->downright_resize_cursor;
+               case HOURGLASS_CURSOR:     return top_level->hourglass_cursor;
+               case TRANSPARENT_CURSOR:   return top_level->transparent_cursor;
+               case GRABBED_CURSOR:       return top_level->grabbed_cursor;
        }
        return 0;
 }
@@ -2835,26 +2890,6 @@ int BC_WindowBase::get_single_text_width(int font, const char *text, int length)
        }
 }
 
-int BC_WindowBase::get_single_text_width(int font, const wchar_t *text, int length)
-{
-#ifdef HAVE_XFT
-       if(get_resources()->use_xft && get_xft_struct(font)) {
-               XGlyphInfo extents;
-
-               XftTextExtents32(top_level->display, get_xft_struct(font),
-                       (const FcChar32*)text, length, &extents);
-               return extents.xOff;
-       }
-#endif
-       if(!get_font_struct(font)) return 0;
-       XChar2b xtext[length], *xp = xtext;
-       for( int i=0; i<length; ++i,++xp ) {
-               xp->byte1 = (unsigned char) (text[i] >> 8);
-               xp->byte2 = (unsigned char) (text[i] & 0xff);
-       }
-       return XTextWidth16(get_font_struct(font), xtext, length);
-}
-
 int BC_WindowBase::get_text_width(int font, const char *text, int length)
 {
        int i, j, w = 0, line_w = 0;
@@ -3300,24 +3335,47 @@ void BC_WindowBase::close(int return_value)
        set_done(return_value);
 }
 
-int BC_WindowBase::get_w()
+int BC_WindowBase::grab(BC_WindowBase *window)
 {
-       return w;
+       if( window->active_grab && this != window->active_grab ) return 0;
+       window->active_grab = this;
+       this->grab_active = window;
+       return 1;
 }
-
-int BC_WindowBase::get_h()
+int BC_WindowBase::ungrab(BC_WindowBase *window)
 {
-       return h;
+       if( window->active_grab && this != window->active_grab ) return 0;
+       window->active_grab = 0;
+       this->grab_active = 0;
+       return 1;
 }
-
-int BC_WindowBase::get_x()
+int BC_WindowBase::grab_buttons()
 {
-       return x;
+       XSync(top_level->display, False);
+       if( XGrabButton(top_level->display, AnyButton, AnyModifier,
+                       top_level->rootwin, True, ButtonPressMask | ButtonReleaseMask,
+                       GrabModeAsync, GrabModeSync, None, None) == GrabSuccess ) {
+               set_active_subwindow(this);
+               return 0;
+       }
+       return 1;
 }
-
-int BC_WindowBase::get_y()
+void BC_WindowBase::ungrab_buttons()
 {
-       return y;
+       XUngrabButton(top_level->display, AnyButton, AnyModifier, top_level->rootwin);
+       set_active_subwindow(0);
+       unhide_cursor();
+}
+void BC_WindowBase::grab_cursor()
+{
+       Cursor cursor_grab = get_cursor_struct(GRABBED_CURSOR);
+       XGrabPointer(top_level->display, top_level->rootwin, True,
+               PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
+               GrabModeAsync, GrabModeAsync, None, cursor_grab, CurrentTime);
+}
+void BC_WindowBase::ungrab_cursor()
+{
+       XUngrabPointer(top_level->display, CurrentTime);
 }
 
 // for get_root_w/h
@@ -3520,13 +3578,21 @@ int BC_WindowBase::deactivate()
 {
        if(window_type == MAIN_WINDOW)
        {
-               if(top_level->active_menubar) top_level->active_menubar->deactivate();
-               if(top_level->active_popup_menu) top_level->active_popup_menu->deactivate();
-               if(top_level->active_subwindow) top_level->active_subwindow->deactivate();
+               if( top_level->active_menubar ) {
+                       top_level->active_menubar->deactivate();
+                       top_level->active_menubar = 0;
+               }
+               if( top_level->active_popup_menu ) {
+                       top_level->active_popup_menu->deactivate();
+                       top_level->active_popup_menu = 0;
+               }
+               if( top_level->active_subwindow ) {
+                       top_level->active_subwindow->deactivate();
+                       top_level->active_subwindow = 0;
+               }
+               if( top_level->motion_events && top_level->last_motion_win == this->win )
+                       top_level->motion_events = 0;
 
-               top_level->active_menubar = 0;
-               top_level->active_popup_menu = 0;
-               top_level->active_subwindow = 0;
        }
        return 0;
 }
@@ -3630,83 +3696,80 @@ BC_Clipboard* BC_WindowBase::get_clipboard()
 #endif
 }
 
-int BC_WindowBase::get_relative_cursor_x()
+void BC_WindowBase::get_relative_cursor_xy(int &x, int &y, int lock_window)
 {
-       int abs_x, abs_y, x, y, win_x, win_y;
+       int abs_x, abs_y, win_x, win_y;
        unsigned int temp_mask;
        Window temp_win;
 
+       if(lock_window) this->lock_window("BC_WindowBase::get_relative_cursor_xy");
        XQueryPointer(top_level->display, top_level->win,
           &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
           &temp_mask);
 
        XTranslateCoordinates(top_level->display, top_level->rootwin,
           win, abs_x, abs_y, &x, &y, &temp_win);
-
+       if(lock_window) this->unlock_window();
+}
+int BC_WindowBase::get_relative_cursor_x(int lock_window)
+{
+       int x, y;
+       get_relative_cursor_xy(x, y, lock_window);
        return x;
 }
-
-int BC_WindowBase::get_relative_cursor_y()
+int BC_WindowBase::get_relative_cursor_y(int lock_window)
 {
-       int abs_x, abs_y, x, y, win_x, win_y;
-       unsigned int temp_mask;
-       Window temp_win;
-
-       XQueryPointer(top_level->display, top_level->win,
-          &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
-          &temp_mask);
-
-       XTranslateCoordinates(top_level->display,
-          top_level->rootwin, win, abs_x, abs_y, &x, &y, &temp_win);
-
+       int x, y;
+       get_relative_cursor_xy(x, y, lock_window);
        return y;
 }
 
-int BC_WindowBase::get_abs_cursor_x(int lock_window)
+void BC_WindowBase::get_abs_cursor_xy(int &abs_x, int &abs_y, int lock_window)
 {
-       int abs_x, abs_y, win_x, win_y;
+       int win_x, win_y;
        unsigned int temp_mask;
        Window temp_win;
 
-       if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor_x");
+       if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor_xy");
        XQueryPointer(top_level->display, top_level->win,
                &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
                &temp_mask);
        if(lock_window) this->unlock_window();
+}
+int BC_WindowBase::get_abs_cursor_x(int lock_window)
+{
+       int abs_x, abs_y;
+       get_abs_cursor_xy(abs_x, abs_y, lock_window);
        return abs_x;
 }
-
 int BC_WindowBase::get_abs_cursor_y(int lock_window)
 {
-       int abs_x, abs_y, win_x, win_y;
-       unsigned int temp_mask;
-       Window temp_win;
-
-       if(lock_window) this->lock_window("BC_WindowBase::get_abs_cursor_y");
-       XQueryPointer(top_level->display, top_level->win,
-               &temp_win, &temp_win, &abs_x, &abs_y, &win_x, &win_y,
-               &temp_mask);
-       if(lock_window) this->unlock_window();
+       int abs_x, abs_y;
+       get_abs_cursor_xy(abs_x, abs_y, lock_window);
        return abs_y;
 }
 
-int BC_WindowBase::get_pop_cursor_x(int lock_window)
+void BC_WindowBase::get_pop_cursor_xy(int &px, int &py, int lock_window)
 {
        int margin = 100;
-       int px = get_abs_cursor_x(lock_window);
+       get_abs_cursor_xy(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 > wd ) px = wd;
+       int ht = get_screen_h(lock_window,-1) - margin;
+       if( py > ht ) py = ht;
+}
+int BC_WindowBase::get_pop_cursor_x(int lock_window)
+{
+       int px, py;
+       get_pop_cursor_xy(px, py, lock_window);
        return px;
 }
-
 int BC_WindowBase::get_pop_cursor_y(int lock_window)
 {
-       int margin = 100;
-       int py = get_abs_cursor_y(lock_window);
-       if( py < margin ) py = margin;
-       int ht = get_screen_h(lock_window,-1) - margin;
-       if( py > ht ) py = ht;
+       int px, py;
+       get_pop_cursor_xy(px, py, lock_window);
        return py;
 }
 
@@ -3743,11 +3806,10 @@ int BC_WindowBase::get_cursor_over_window()
 
 int BC_WindowBase::cursor_above()
 {
-       int rx = get_relative_cursor_x();
-       if( rx < 0 || rx >= get_w() ) return 0;
-       int ry = get_relative_cursor_y();
-       if( ry < 0 || ry >= get_h() ) return 0;
-       return 1;
+       int rx, ry;
+       get_relative_cursor_xy(rx, ry);
+       return rx < 0 || rx >= get_w() ||
+               ry < 0 || ry >= get_h() ? 0 : 1;
 }
 
 int BC_WindowBase::get_drag_x()