add browse bg btn in titler, prevent a few badwin signals, titler text popup upgrades
[goodguy/history.git] / cinelerra-5.1 / guicast / bcwindowbase.C
index 389670c338e4dbff8843842cc7a5255589fb8a93..791aa0c856ccfb84252f3f9dced1afd7c0c70ea5 100644 (file)
@@ -53,6 +53,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <wchar.h>
+#include <typeinfo>
 
 #include <X11/extensions/Xinerama.h>
 #include <X11/extensions/Xvlib.h>
@@ -101,27 +102,39 @@ BC_WindowBase::~BC_WindowBase()
 #endif
 
 #ifdef HAVE_LIBXXF86VM
-   if(window_type == VIDMODE_SCALED_WINDOW && vm_switched)
-   {
-          restore_vm();
-   }
+       if(window_type == VIDMODE_SCALED_WINDOW && vm_switched) {
+               restore_vm();
+       }
 #endif
+       is_deleting = 1;
 
        hide_tooltip();
        if(window_type != MAIN_WINDOW)
        {
+// stop event input
+               XSelectInput(top_level->display, this->win, 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_grab == this) top_level->active_grab = 0;
                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(icon_window) delete icon_window;
-       if(window_type == POPUP_WINDOW) parent_window->remove_popup(this);
+       if(window_type == POPUP_WINDOW)
+               parent_window->remove_popup(this);
 
 // Delete the subwindows
-       is_deleting = 1;
        if(subwindows)
        {
                while(subwindows->total)
@@ -193,6 +206,8 @@ BC_WindowBase::~BC_WindowBase()
                        XFree(xinerama_info);
                xinerama_screens = 0;
                xinerama_info = 0;
+               if( xvideo_port_id >= 0 )
+                       XvUngrabPort(display, xvideo_port_id, CurrentTime);
 
                unlock_window();
 // Can't close display if another thread is waiting for events.
@@ -241,6 +256,7 @@ int BC_WindowBase::initialize()
        done = 0;
        done_set = 0;
        window_running = 0;
+       display_lock_owner = 0;
        test_keypress = 0;
        keys_return[0] = 0;
        is_deleting = 0;
@@ -274,6 +290,7 @@ int BC_WindowBase::initialize()
        event_win = 0;
        last_motion_win = 0;
        key_pressed = 0;
+       active_grab = 0;
        active_menubar = 0;
        active_popup_menu = 0;
        active_subwindow = 0;
@@ -338,6 +355,8 @@ int BC_WindowBase::initialize()
        glx_win = 0;
 #endif
 
+       flash_enabled = 1;
+       win = 0;
        return 0;
 }
 
@@ -624,9 +643,6 @@ int BC_WindowBase::create_window(BC_WindowBase *parent_window,
 
        }
 
-
-
-
        draw_background(0, 0, this->w, this->h);
 
        flash(-1, -1, -1, -1, 0);
@@ -881,7 +897,7 @@ int BC_WindowBase::keysym_lookup(XEvent *event)
        return ret;
 }
 
-pthread_t locking_task = -1;
+pthread_t locking_task = (pthread_t)-1L;
 int locking_event = -1;
 int locking_message = -1;
 
@@ -946,7 +962,10 @@ locking_message = event->xclient.message_type;
 //   event_names[event->type] : "Unknown");
 //}
 
-
+       if( active_grab && active_grab->grab_event(event) ) {
+               unlock_window();
+               return 0;
+       }
 
 
        switch(event->type) {
@@ -1351,32 +1370,40 @@ int BC_WindowBase::dispatch_resize_event(int w, int h)
 // Can't store new w and h until the event is handles
 // because bcfilebox depends on the old w and h to
 // reposition widgets.
-       if(window_type == MAIN_WINDOW)
-       {
+       if( window_type == MAIN_WINDOW ) {
+               flash_enabled = 0;
                resize_events = 0;
+
                delete pixmap;
                pixmap = new BC_Pixmap(this, w, h);
-
                clear_box(0, 0, w, h);
        }
 
 // Propagate to subwindows
-       for(int i = 0; i < subwindows->total; i++)
-       {
+       for(int i = 0; i < subwindows->total; i++) {
                subwindows->values[i]->dispatch_resize_event(w, h);
        }
 
 // Propagate to user
        resize_event(w, h);
 
-       if(window_type == MAIN_WINDOW)
-       {
+       if( window_type == MAIN_WINDOW ) {
                this->w = w;
                this->h = h;
+               dispatch_flash();
+               flush();
        }
        return 0;
 }
 
+int BC_WindowBase::dispatch_flash()
+{
+       flash_enabled = 1;
+       for(int i = 0; i < subwindows->total; i++)
+               subwindows->values[i]->dispatch_flash();
+       return flash(0);
+}
+
 int BC_WindowBase::dispatch_translation_event()
 {
        translation_events = 0;
@@ -1914,11 +1941,17 @@ int BC_WindowBase::unset_all_repeaters()
 //     return top_level->next_repeat_id++;
 // }
 
+XEvent *BC_WindowBase::new_xevent()
+{
+       XEvent *event = new XEvent;
+       memset(event, 0, sizeof(*event));
+       return event;
+}
 
 #ifndef SINGLE_THREAD
 int BC_WindowBase::arm_repeat(int64_t duration)
 {
-       XEvent *event = new XEvent;
+       XEvent *event = new_xevent();
        XClientMessageEvent *ptr = (XClientMessageEvent*)event;
        ptr->type = ClientMessage;
        ptr->message_type = RepeaterXAtom;
@@ -1938,7 +1971,8 @@ int BC_WindowBase::recieve_custom_xatoms(xatom_event *event)
 
 int BC_WindowBase::send_custom_xatom(xatom_event *event)
 {
-       XEvent *myevent = new XEvent;
+#ifndef SINGLE_THREAD
+       XEvent *myevent = new_xevent();
        XClientMessageEvent *ptr = (XClientMessageEvent*)myevent;
        ptr->type = ClientMessage;
        ptr->message_type = event->message_type;
@@ -1950,6 +1984,7 @@ int BC_WindowBase::send_custom_xatom(xatom_event *event)
        ptr->data.l[4] = event->data.l[4];
 
        put_event(myevent);
+#endif
        return 0;
 }
 
@@ -1962,12 +1997,9 @@ Atom BC_WindowBase::create_xatom(const char *atom_name)
 
 int BC_WindowBase::get_atoms()
 {
-       SetDoneXAtom =  create_xatom("BC_REPEAT_EVENT");
-       RepeaterXAtom = create_xatom("BC_CLOSE_EVENT");
-       DelWinXAtom = create_xatom("WM_DELETE_WINDOW");
-       ProtoXAtom = create_xatom("WM_PROTOCOLS");
        SetDoneXAtom =  XInternAtom(display, "BC_REPEAT_EVENT", False);
        RepeaterXAtom = XInternAtom(display, "BC_CLOSE_EVENT", False);
+       DestroyAtom =   XInternAtom(display, "BC_DESTROY_WINDOW", False);
        DelWinXAtom =   XInternAtom(display, "WM_DELETE_WINDOW", False);
        if( (ProtoXAtom = XInternAtom(display, "WM_PROTOCOLS", False)) != 0 )
                XChangeProperty(display, win, ProtoXAtom, XA_ATOM, 32,
@@ -2795,7 +2827,7 @@ int BC_WindowBase::get_single_text_width(int font, const char *text, int length)
        if(get_resources()->use_fontset && top_level->get_fontset(font))
                return XmbTextEscapement(top_level->get_fontset(font), text, length);
        else
-       if(get_font_struct(font)) 
+       if(get_font_struct(font))
                return XTextWidth(get_font_struct(font), text, length);
        else
        {
@@ -2864,27 +2896,21 @@ int BC_WindowBase::get_text_width(int font, const char *text, int length)
 
 int BC_WindowBase::get_text_width(int font, const wchar_t *text, int length)
 {
-       int i, j, w = 0, line_w = 0;
-
-       if(length < 0) length = wcslen(text);
+       int i, j, w = 0;
+       if( length < 0 ) length = wcslen(text);
 
-       for(i = 0, j = 0; i <= length; i++)
-       {
-               line_w = 0;
-               if(text[i] == '\n')
-               {
-                       line_w = get_single_text_width(font, &text[j], i - j);
-                       j = i + 1;
+       for( i=j=0; i<length && text[i]; ++i ) {
+               if( text[i] != '\n' ) continue;
+               if( i > j ) {
+                       int lw = get_single_text_width(font, &text[j], i-j);
+                       if( w < lw ) w = lw;
                }
-               else
-               if(text[i] == 0)
-                       line_w = get_single_text_width(font, &text[j], length - j);
-
-               if(line_w > w) w = line_w;
+               j = i + 1;
+       }
+       if( j < length ) {
+               int lw = get_single_text_width(font, &text[j], length-j);
+               if( w < lw ) w = lw;
        }
-
-       if(i > length && w == 0)
-               w = get_single_text_width(font, text, length);
 
        return w;
 }
@@ -2978,119 +3004,76 @@ void BC_WindowBase::init_wait()
 
 int BC_WindowBase::accel_available(int color_model, int lock_it)
 {
-       if(window_type != MAIN_WINDOW)
+       if( window_type != MAIN_WINDOW )
                return top_level->accel_available(color_model, lock_it);
+       if( lock_it )
+               lock_window("BC_WindowBase::accel_available");
 
-       int result = 0;
-
-       if(lock_it) lock_window("BC_WindowBase::accel_available");
-       switch(color_model)
-       {
-               case BC_YUV420P:
-                       result = grab_port_id(this, color_model);
-                       if(result >= 0)
-                       {
-                               xvideo_port_id = result;
-                               result = 1;
-                       }
-                       else
-                               result = 0;
-                       break;
-
-               case BC_YUV422P:
-                       result = 0;
-                       break;
+       switch(color_model) {
+       case BC_YUV420P:
+               grab_port_id(color_model);
+               break;
 
-               case BC_YUV422:
-//printf("BC_WindowBase::accel_available 1\n");
-                       result = grab_port_id(this, color_model);
-//printf("BC_WindowBase::accel_available 2 %d\n", result);
-                       if(result >= 0)
-                       {
-                               xvideo_port_id = result;
-                               result = 1;
-                       }
-                       else
-                               result = 0;
-//printf("BC_WindowBase::accel_available 3 %d\n", xvideo_port_id);
-                       break;
+       case BC_YUV422:
+               grab_port_id(color_model);
+               break;
 
-               default:
-                       result = 0;
-                       break;
+       default:
+               break;
        }
 
-       if(lock_it) unlock_window();
-//printf("BC_WindowBase::accel_available %d %d\n", color_model, result);
-       return result;
+       if( lock_it )
+               unlock_window();
+//printf("BC_WindowBase::accel_available %d %d\n", color_model, xvideo_port_id);
+       return xvideo_port_id >= 0 ? 1 : 0;
 }
 
 
-int BC_WindowBase::grab_port_id(BC_WindowBase *window, int color_model)
+int BC_WindowBase::grab_port_id(int color_model)
 {
-       int numFormats, i, j, k;
-       unsigned int ver, rev, numAdapt, reqBase, eventBase, errorBase;
-       XvAdaptorInfo *info;
-       XvImageFormatValues *formats;
-       int x_color_model;
-
-       if(!get_resources()->use_xvideo) return -1;
-
-// Translate from color_model to X color model
-       x_color_model = BC_CModels::bc_to_x(color_model);
-
-// Only local server is fast enough.
-       if(!resources.use_shm) return -1;
+       if( !get_resources()->use_xvideo ||     // disabled
+           !get_resources()->use_shm )         // Only local server is fast enough.
+               return -1;
+       if( xvideo_port_id >= 0 )
+               return xvideo_port_id;
 
-// XV extension is available
-       if(Success != XvQueryExtension(window->display, &ver, &rev,
-                                 &reqBase, &eventBase, &errorBase)) {
+       unsigned int ver, rev, reqBase, eventBase, errorBase;
+       if( Success != XvQueryExtension(display, // XV extension is available
+                   &ver, &rev, &reqBase, &eventBase, &errorBase) )
                return -1;
-       }
 
 // XV adaptors are available
-       XvQueryAdaptors(window->display,
-               DefaultRootWindow(window->display),
-               &numAdapt, &info);
-
-       if(!numAdapt) {
+       unsigned int numAdapt = 0;
+       XvAdaptorInfo *info = 0;
+       XvQueryAdaptors(display, DefaultRootWindow(display), &numAdapt, &info);
+       if( !numAdapt )
                return -1;
-       }
+
+// Translate from color_model to X color model
+       int x_color_model = BC_CModels::bc_to_x(color_model);
 
 // Get adaptor with desired color model
-       for(i = 0; i < (int)numAdapt && xvideo_port_id == -1; i++) {
-/* adaptor supports XvImages */
-               if(info[i].type & XvImageMask)
-               {
-               formats = XvListImageFormats(window->display,
-                                                       info[i].base_id,
-                                                       &numFormats);
-// for(j = 0; j < numFormats; j++)
-//     printf("%08x\n", formats[j].id);
-
-               int numPorts = info[i].num_ports;
-               for(j = 0; j < (int)numFormats && xvideo_port_id < 0; j++)
-               {
-/* this adaptor supports the desired format */
-                               if(formats[j].id == x_color_model)
-                               {
-/* Try to grab a port */
-                                       for(k = 0; k < numPorts; k++)
-                                       {
-/* Got a port */
-                                               if(Success == XvGrabPort(top_level->display,
-                                                       info[i].base_id + k,
-                                                       CurrentTime))
-                                               {
+       for( int i = 0; i < (int)numAdapt && xvideo_port_id == -1; i++) {
+               if( !(info[i].type & XvImageMask) || !info[i].num_ports ) continue;
+// adaptor supports XvImages
+               int numFormats = 0, numPorts = info[i].num_ports;
+               XvImageFormatValues *formats =
+                       XvListImageFormats(display, info[i].base_id, &numFormats);
+               if( !formats ) continue;
+
+               for( int j=0; j<numFormats && xvideo_port_id<0; ++j ) {
+                       if( formats[j].id != x_color_model ) continue;
+// this adaptor supports the desired format, grab a port
+                       for( int k=0; k<numPorts; ++k ) {
+                               if( Success == XvGrabPort(top_level->display,
+                                       info[i].base_id+k, CurrentTime) ) {
 //printf("BC_WindowBase::grab_port_id %llx\n", info[i].base_id);
-                                                       xvideo_port_id = info[i].base_id + k;
-                                                       break;
-                                               }
-                                       }
+                                       xvideo_port_id = info[i].base_id + k;
+                                       break;
                                }
                        }
-               if(formats) XFree(formats);
                }
+               XFree(formats);
        }
 
        XvFreeAdaptorInfo(info);
@@ -3178,6 +3161,7 @@ BC_WindowBase* BC_WindowBase::add_tool(BC_WindowBase *subwindow)
 
 int BC_WindowBase::flash(int x, int y, int w, int h, int flush)
 {
+       if( !top_level->flash_enabled ) return 0;
 //printf("BC_WindowBase::flash %d %d %d %d %d\n", __LINE__, w, h, this->w, this->h);
        set_opaque();
        XSetWindowBackgroundPixmap(top_level->display, win, pixmap->opaque_pixmap);
@@ -3304,20 +3288,20 @@ void BC_WindowBase::set_done(int return_value)
 #else // SINGLE_THREAD
                init_wait();
                if( !event_thread ) return;
-               XEvent *event = new XEvent;
+               XEvent *event = new_xevent();
                XClientMessageEvent *ptr = (XClientMessageEvent*)event;
                event->type = ClientMessage;
                ptr->message_type = SetDoneXAtom;
                ptr->format = 32;
                this->return_value = return_value;
-// May lock up here because XSendEvent doesn't work too well 
+// May lock up here because XSendEvent doesn't work too well
 // asynchronous with XNextEvent.
-// This causes BC_WindowEvents to forward a copy of the event to run_window where 
+// This causes BC_WindowEvents to forward a copy of the event to run_window where
 // it is deleted.
 // Deletion of event_thread is done at the end of BC_WindowBase::run_window() - by calling the destructor
                put_event(event);
-       }
 #endif
+       }
 }
 
 void BC_WindowBase::close(int return_value)
@@ -3326,6 +3310,19 @@ void BC_WindowBase::close(int return_value)
        set_done(return_value);
 }
 
+int BC_WindowBase::grab(BC_WindowBase *window)
+{
+       if( window->active_grab && this != window->active_grab ) return 0;
+       window->active_grab = this;
+       return 1;
+}
+int BC_WindowBase::ungrab(BC_WindowBase *window)
+{
+       if( window->active_grab && this != window->active_grab ) return 0;
+       window->active_grab = 0;
+       return 1;
+}
+
 int BC_WindowBase::get_w()
 {
        return w;
@@ -3656,66 +3653,83 @@ 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;
 }
 
+void BC_WindowBase::get_pop_cursor_xy(int &px, int &py, int lock_window)
+{
+       int margin = 100;
+       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 px, py;
+       get_pop_cursor_xy(px, py, lock_window);
+       return py;
+}
+
 int BC_WindowBase::match_window(Window win)
 {
        if (this->win == win) return 1;
@@ -3749,11 +3763,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()
@@ -3778,13 +3791,15 @@ int BC_WindowBase::get_cursor_y()
 
 int BC_WindowBase::dump_windows()
 {
-       printf("\tBC_WindowBase::dump_windows window=%p win=%p\n",
-               this, (void*)this->win);
+       printf("\tBC_WindowBase::dump_windows window=%p win=%p '%s', %dx%d+%d+%d %s\n",
+               this, (void*)this->win, title, w,h,x,y, typeid(*this).name());
        for(int i = 0; i < subwindows->size(); i++)
                subwindows->get(i)->dump_windows();
-       for(int i = 0; i < popups.size(); i++)
-               printf("\tBC_WindowBase::dump_windows popup=%p win=%p\n",
-                       popups.get(i), (void*)popups.get(i)->win);
+       for(int i = 0; i < popups.size(); i++) {
+               BC_WindowBase *p = popups[i];
+               printf("\tBC_WindowBase::dump_windows popup=%p win=%p '%s', %dx%d+%d+%d %s\n",
+                       p, (void*)p->win, p->title, p->w,p->h,p->x,p->y, typeid(*p).name());
+       }
        return 0;
 }
 
@@ -3969,6 +3984,7 @@ int BC_WindowBase::reposition_window(int x, int y, int w, int h)
        {
                delete pixmap;
                pixmap = new BC_Pixmap(this, this->w, this->h);
+               clear_box(0,0, this->w, this->h);
 // Propagate to menubar
                for(int i = 0; i < subwindows->total; i++)
                {
@@ -4019,9 +4035,7 @@ void BC_WindowBase::set_background(VFrame *bitmap)
 {
        if(bg_pixmap && !shared_bg_pixmap) delete bg_pixmap;
 
-       bg_pixmap = new BC_Pixmap(this,
-                       bitmap,
-                       PIXMAP_OPAQUE);
+       bg_pixmap = new BC_Pixmap(this, bitmap, PIXMAP_OPAQUE);
        shared_bg_pixmap = 0;
        draw_background(0, 0, w, h);
 }
@@ -4088,10 +4102,7 @@ int BC_WindowBase::get_toggle_drag()
 int BC_WindowBase::set_icon(VFrame *data)
 {
        if(icon_pixmap) delete icon_pixmap;
-       icon_pixmap = new BC_Pixmap(top_level,
-               data,
-               PIXMAP_ALPHA,
-               1);
+       icon_pixmap = new BC_Pixmap(top_level, data, PIXMAP_ALPHA, 1);
 
        if(icon_window) delete icon_window;
        icon_window = new BC_Popup(this,
@@ -4351,6 +4362,20 @@ void BC_WindowBase::put_event(XEvent *event)
        event_condition->unlock();
 }
 
+void BC_WindowBase::dequeue_events(Window win)
+{
+       event_lock->lock("BC_WindowBase::dequeue_events");
+
+       int out = 0, total = common_events.size();
+       for( int in=0; in<total; ++in ) {
+               if( common_events[in]->xany.window == win ) continue;
+               common_events[out++] = common_events[in];
+       }
+       common_events.total = out;
+
+       event_lock->unlock();
+}
+
 #endif // SINGLE_THREAD
 
 int BC_WindowBase::get_id()
@@ -4368,3 +4393,15 @@ BC_Pixmap *BC_WindowBase::create_pixmap(VFrame *vframe)
 }
 
 
+void BC_WindowBase::flicker(int n, int ms)
+{
+       int color = get_bg_color();
+       for( int i=2*n; --i>=0; ) {
+               set_inverse();          set_bg_color(WHITE);
+               clear_box(0,0, w,h);    flash(1);
+               sync_display();         Timer::delay(ms);
+       }
+       set_bg_color(color);
+       set_opaque();
+}
+