Rewrite Fl_Window::hide() under the driver model.

git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3-porting@11402 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Manolo Gouy 2016-03-23 07:08:17 +00:00
parent bf7e4de688
commit 270b437500
12 changed files with 159 additions and 142 deletions

View File

@ -83,6 +83,8 @@ public:
virtual void show();
virtual void show_menu();
virtual void resize(int X,int Y,int W,int H) {}
virtual void hide() {}
int hide_common();
// --- window shape stuff
void shape_pixmap_(Fl_Image* pixmap); // TODO: check

View File

@ -1450,147 +1450,6 @@ int Fl::handle_(int e, Fl_Window* window)
return send_handlers(e);
}
////////////////////////////////////////////////////////////////
// hide() destroys the X window, it does not do unmap!
#if defined(WIN32)
extern void fl_clipboard_notify_retarget(HWND wnd);
extern void fl_update_clipboard(void);
#elif USE_XFT
extern void fl_destroy_xft_draw(Window);
#endif
void Fl_Window::hide() {
#ifdef WIN32 // platform fix
// STR#3079: if there remains a window and a non-modal window, and the window is deleted,
// the app remains running without any apparent window.
// Bug mechanism: hiding an owner window unmaps the owned (non-modal) window(s)
// but does not delete it(them) in FLTK.
// Fix for it:
// when hiding a window, build list of windows it owns, and do hide/show on them.
int count = 0;
Fl_Window *win, **doit = NULL;
for (win = Fl::first_window(); win && i; win = Fl::next_window(win)) {
if (win->non_modal() && GetWindow(fl_xid(win), GW_OWNER) == i->xid) {
count++;
}
}
if (count) {
doit = new Fl_Window*[count];
count = 0;
for (win = Fl::first_window(); win && i; win = Fl::next_window(win)) {
if (win->non_modal() && GetWindow(fl_xid(win), GW_OWNER) == i->xid) {
doit[count++] = win;
}
}
}
#endif
clear_visible();
if (!shown()) return;
// remove from the list of windows:
Fl_X* ip = i;
Fl_X** pp = &Fl_X::first;
for (; *pp != ip; pp = &(*pp)->next) if (!*pp) return;
*pp = ip->next;
#ifdef __APPLE__ // platform fix
// MacOS X manages a single pointer per application. Make sure that hiding
// a toplevel window will not leave us with some random pointer shape, or
// worst case, an invisible pointer
if (!parent()) cursor(FL_CURSOR_DEFAULT);
#endif
i = 0;
// recursively remove any subwindows:
for (Fl_X *wi = Fl_X::first; wi;) {
Fl_Window* W = wi->w;
if (W->window() == this) {
W->hide();
W->set_visible();
wi = Fl_X::first;
} else wi = wi->next;
}
if (this == Fl::modal_) { // we are closing the modal window, find next one:
Fl_Window* W;
for (W = Fl::first_window(); W; W = Fl::next_window(W))
if (W->modal()) break;
Fl::modal_ = W;
}
// Make sure no events are sent to this window:
fl_throw_focus(this);
handle(FL_HIDE);
#if defined(WIN32)
// make sure any custom icons get freed
icons(NULL, 0);
// this little trick keeps the current clipboard alive, even if we are about
// to destroy the window that owns the selection.
if (GetClipboardOwner()==ip->xid)
fl_update_clipboard();
// Make sure we unlink this window from the clipboard chain
fl_clipboard_notify_retarget(ip->xid);
// Send a message to myself so that I'll get out of the event loop...
PostMessage(ip->xid, WM_APP, 0, 0);
if (ip->private_dc) fl_release_dc(ip->xid, ip->private_dc);
if (ip->xid == fl_window && fl_graphics_driver->gc()) {
fl_release_dc(fl_window, (HDC)fl_graphics_driver->gc());
fl_window = (HWND)-1;
fl_graphics_driver->gc(0);
# ifdef FLTK_USE_CAIRO
if (Fl::cairo_autolink_context()) Fl::cairo_make_current((Fl_Window*) 0);
# endif
}
#elif defined(__APPLE_QUARTZ__) // PORTME: Fl_Window_Driver - platform window unmapping
Fl_X::q_release_context(ip);
if ( ip->xid == fl_window )
fl_window = 0;
#endif
if (ip->region) XDestroyRegion(ip->region);
#if defined(USE_X11)
# if USE_XFT
fl_destroy_xft_draw(ip->xid);
# endif
// this test makes sure ip->xid has not been destroyed already
if (ip->xid) XDestroyWindow(fl_display, ip->xid);
#elif defined(WIN32)
// this little trickery seems to avoid the popup window stacking problem
HWND p = GetForegroundWindow();
if (p==GetParent(ip->xid)) {
ShowWindow(ip->xid, SW_HIDE);
ShowWindow(p, SW_SHOWNA);
}
XDestroyWindow(fl_display, ip->xid);
// end of fix for STR#3079
if (count) {
int ii;
for (ii = 0; ii < count; ii++) doit[ii]->hide();
for (ii = 0; ii < count; ii++) {
if (ii != 0) doit[0]->show(); // Fix for STR#3165
doit[ii]->show();
}
delete[] doit;
}
#elif defined(__APPLE_QUARTZ__) // PORTME: Fl_Window_Driver - platform window unmapping
ip->destroy();
#elif defined(FL_PORTING)
# pragma message "FL_PORTING: code to destroy a window on screen"
#else
# error unsupported platform
#endif
#ifdef WIN32
// Try to stop the annoying "raise another program" behavior
if (non_modal() && Fl::first_window() && Fl::first_window()->shown())
Fl::first_window()->show();
#endif
delete ip;
}
// FL_SHOW and FL_HIDE are called whenever the visibility of this widget
// or any parent changes. We must correctly map/unmap the system's window.

View File

@ -510,6 +510,10 @@ void Fl_Window::resize(int X,int Y,int W,int H) {
pWindowDriver->resize(X, Y, W, H);
}
void Fl_Window::hide() {
pWindowDriver->hide();
}
//
// End of "$Id$".
//

View File

@ -21,7 +21,9 @@
#include <config.h>
#include <FL/Fl_Window_Driver.H>
#include <FL/fl_draw.H>
#include <FL/Fl.H>
extern void fl_throw_focus(Fl_Widget *o);
Fl_Window_Driver::Fl_Window_Driver(Fl_Window *win) :
pWindow(win)
@ -151,6 +153,44 @@ void Fl_Window_Driver::capture_titlebar_and_borders(Fl_Shared_Image*& top, Fl_Sh
top = left = bottom = right = NULL;
}
// This function is available for use by platform-specific, Fl_Window_Driver-derived classes
int Fl_Window_Driver::hide_common() {
pWindow->clear_visible();
if (!pWindow->shown()) return 1;
// remove from the list of windows:
Fl_X* ip = Fl_X::i(pWindow);
Fl_X** pp = &Fl_X::first;
for (; *pp != ip; pp = &(*pp)->next) if (!*pp) return 1;
*pp = ip->next;
pWindow->i = 0;
// recursively remove any subwindows:
for (Fl_X *wi = Fl_X::first; wi;) {
Fl_Window* W = wi->w;
if (W->window() == pWindow) {
W->hide();
W->set_visible();
wi = Fl_X::first;
} else wi = wi->next;
}
if (pWindow == Fl::modal_) { // we are closing the modal window, find next one:
Fl_Window* W;
for (W = Fl::first_window(); W; W = Fl::next_window(W))
if (W->modal()) break;
Fl::modal_ = W;
}
// Make sure no events are sent to this window:
fl_throw_focus(pWindow);
pWindow->handle(FL_HIDE);
return 0;
}
//
// End of "$Id$".
//

View File

@ -77,6 +77,7 @@ public:
virtual void label(const char *name, const char *mininame);
virtual void show();
virtual void resize(int X,int Y,int W,int H);
virtual void hide();
virtual void shape(const Fl_Image* img);
// that one is implemented in Fl_Cocoa.mm because it uses Objective-c

View File

@ -223,6 +223,22 @@ void Fl_Cocoa_Window_Driver::shape(const Fl_Image* img) {
#endif
}
void Fl_Cocoa_Window_Driver::hide() {
Fl_X* ip = Fl_X::i(pWindow);
// MacOS X manages a single pointer per application. Make sure that hiding
// a toplevel window will not leave us with some random pointer shape, or
// worst case, an invisible pointer
if (ip && !pWindow->parent()) pWindow->cursor(FL_CURSOR_DEFAULT);
if ( hide_common() ) return;
Fl_X::q_release_context(ip);
if ( ip->xid == fl_window )
fl_window = 0;
if (ip->region) XDestroyRegion(ip->region);
ip->destroy();
delete ip;
}
//
// End of "$Id$".
//

View File

@ -82,6 +82,7 @@ public:
virtual void show();
virtual void label(const char *name,const char *iname);
virtual void resize(int X,int Y,int W,int H);
virtual void hide();
virtual void shape(const Fl_Image* img);
virtual void icons(const Fl_RGB_Image *icons[], int count);

View File

@ -445,6 +445,82 @@ void Fl_WinAPI_Window_Driver::label(const char *name,const char *iname) {
}
}
extern void fl_clipboard_notify_retarget(HWND wnd);
extern void fl_update_clipboard(void);
void Fl_WinAPI_Window_Driver::hide() {
Fl_X* ip = Fl_X::i(pWindow);
// STR#3079: if there remains a window and a non-modal window, and the window is deleted,
// the app remains running without any apparent window.
// Bug mechanism: hiding an owner window unmaps the owned (non-modal) window(s)
// but does not delete it(them) in FLTK.
// Fix for it:
// when hiding a window, build list of windows it owns, and do hide/show on them.
int count = 0;
Fl_Window *win, **doit = NULL;
for (win = Fl::first_window(); win && ip; win = Fl::next_window(win)) {
if (win->non_modal() && GetWindow(fl_xid(win), GW_OWNER) == ip->xid) {
count++;
}
}
if (count) {
doit = new Fl_Window*[count];
count = 0;
for (win = Fl::first_window(); win && ip; win = Fl::next_window(win)) {
if (win->non_modal() && GetWindow(fl_xid(win), GW_OWNER) == ip->xid) {
doit[count++] = win;
}
}
}
if (hide_common()) return;
// make sure any custom icons get freed
icons(NULL, 0);
// this little trick keeps the current clipboard alive, even if we are about
// to destroy the window that owns the selection.
if (GetClipboardOwner()==ip->xid)
fl_update_clipboard();
// Make sure we unlink this window from the clipboard chain
fl_clipboard_notify_retarget(ip->xid);
// Send a message to myself so that I'll get out of the event loop...
PostMessage(ip->xid, WM_APP, 0, 0);
if (ip->private_dc) fl_release_dc(ip->xid, ip->private_dc);
if (ip->xid == fl_window && fl_graphics_driver->gc()) {
fl_release_dc(fl_window, (HDC)fl_graphics_driver->gc());
fl_window = (HWND)-1;
fl_graphics_driver->gc(0);
# ifdef FLTK_USE_CAIRO
if (Fl::cairo_autolink_context()) Fl::cairo_make_current((Fl_Window*) 0);
# endif
}
if (ip->region) XDestroyRegion(ip->region);
// this little trickery seems to avoid the popup window stacking problem
HWND p = GetForegroundWindow();
if (p==GetParent(ip->xid)) {
ShowWindow(ip->xid, SW_HIDE);
ShowWindow(p, SW_SHOWNA);
}
XDestroyWindow(fl_display, ip->xid);
// end of fix for STR#3079
if (count) {
int ii;
for (ii = 0; ii < count; ii++) doit[ii]->hide();
for (ii = 0; ii < count; ii++) {
if (ii != 0) doit[0]->show(); // Fix for STR#3165
doit[ii]->show();
}
delete[] doit;
}
// Try to stop the annoying "raise another program" behavior
if (pWindow->non_modal() && Fl::first_window() && Fl::first_window()->shown())
Fl::first_window()->show();
delete ip;
}
//
// End of "$Id$".
//

View File

@ -91,6 +91,7 @@ public:
virtual void resize(int X,int Y,int W,int H);
virtual void label(const char *name, const char *mininame);
virtual void destroy_double_buffer();
virtual void hide();
virtual void shape(const Fl_Image* img);
virtual void icons(const Fl_RGB_Image *icons[], int count);

View File

@ -19,6 +19,7 @@
#include "../../config_lib.h"
#include "Fl_X11_Window_Driver.H"
#include "Fl_Xlib_Graphics_Driver.H"
#include <FL/Fl_Shared_Image.H>
#include <FL/Fl_Overlay_Window.H>
@ -461,6 +462,19 @@ void Fl_X11_Window_Driver::show_menu()
pWindow->Fl_Window::show();
}
void Fl_X11_Window_Driver::hide() {
Fl_X* ip = Fl_X::i(pWindow);
if (hide_common()) return;
if (ip->region) XDestroyRegion(ip->region);
# if USE_XFT
Fl_Xlib_Graphics_Driver::destroy_xft_draw(ip->xid);
# endif
// this test makes sure ip->xid has not been destroyed already
if (ip->xid) XDestroyWindow(fl_display, ip->xid);
delete ip;
}
//
// End of "$Id$".
//

View File

@ -44,6 +44,9 @@ public:
virtual void *gc() { return gc_; }
virtual void gc(void *value);
char can_do_alpha_blending();
#if USE_XFT
static void destroy_xft_draw(Window id);
#endif
// --- bitmap stuff
Fl_Bitmask create_bitmask(int w, int h, const uchar *array);

View File

@ -958,7 +958,7 @@ static XftDraw* draw_overlay;
static Window draw_overlay_window;
#endif
void fl_destroy_xft_draw(Window id) {
void Fl_Xlib_Graphics_Driver::destroy_xft_draw(Window id) {
if (id == draw_window)
XftDrawChange(draw_, draw_window = fl_message_window);
#if USE_OVERLAY