STR #1007: Applied second patch by hand. OP: could you please check if all changes were made correctly? Thanks!

git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@4563 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Matthias Melcher 2005-09-12 23:03:34 +00:00
parent 55380298b5
commit 2b6586f64d
12 changed files with 221 additions and 36 deletions

View File

@ -3,6 +3,7 @@ CHANGES IN FLTK 1.1.7
- Documentation fixes (STR #571, STR #648, STR #692, STR
#730, STR #744, STR #745, STR #931, STR #942, STR #960,
STR #969)
- Fixed handling of Win32 Device Contexts (STR #1007)
- Fixed C Plus Plus style comments in C files (STR #997)
- Fixed signednes of scanf argument (STR #996)
- Fixed cross-compiling (host: *-linux-* , target: *-mingw32)

View File

@ -70,6 +70,7 @@ inline void XClipBox(Fl_Region r,XRectangle* rect) {
// Warning: this object is highly subject to change!
class FL_EXPORT Fl_X {
public:
// member variables - add new variables only at the end of this block
Window xid;
HBITMAP other_xid; // for double-buffered windows
Fl_Window* w;
@ -78,6 +79,8 @@ public:
int wait_for_expose;
HDC private_dc; // used for OpenGL
HCURSOR cursor;
HDC saved_hdc; // saves the handle of the DC currently loaded
// static variables, static functions and member functions
static Fl_X* first;
static Fl_X* i(const Fl_Window* w) {return w->i;}
static int fake_X_wm(const Fl_Window* w,int &X, int &Y,
@ -104,6 +107,7 @@ extern FL_EXPORT struct Fl_XMap {
inline COLORREF fl_RGB() {return fl_current_xmap->rgb;}
inline HPEN fl_pen() {return fl_current_xmap->pen;}
FL_EXPORT HBRUSH fl_brush(); // allocates a brush if necessary
FL_EXPORT HBRUSH fl_brush_action(int); // now does the real work
extern FL_EXPORT HINSTANCE fl_display;
extern FL_EXPORT Window fl_window;
@ -111,6 +115,8 @@ extern FL_EXPORT HDC fl_gc;
extern FL_EXPORT HPALETTE fl_palette; // non-zero only on 8-bit displays!
extern FL_EXPORT HDC fl_GetDC(Window);
extern FL_EXPORT MSG fl_msg;
extern FL_EXPORT void fl_release_dc(HWND w, HDC dc);
extern FL_EXPORT void fl_save_dc( HWND w, HDC dc);
// off-screen pixmaps: create, destroy, draw into, copy to window
typedef HBITMAP Fl_Offscreen;
@ -119,10 +125,10 @@ typedef HBITMAP Fl_Offscreen;
extern FL_EXPORT HDC fl_makeDC(HBITMAP);
#define fl_begin_offscreen(b) \
HDC _sgc=fl_gc; Window _sw=fl_window; \
fl_gc=fl_makeDC(b); fl_window=(HWND)b; fl_push_no_clip()
fl_gc=fl_makeDC(b); int _savedc = SaveDC(fl_gc); fl_window=(HWND)b; fl_push_no_clip()
#define fl_end_offscreen() \
fl_pop_clip(); DeleteDC(fl_gc); fl_window=_sw; fl_gc = _sgc
fl_pop_clip(); RestoreDC(fl_gc, _savedc); DeleteDC(fl_gc); fl_window=_sw; fl_gc = _sgc
FL_EXPORT void fl_copy_offscreen(int x,int y,int w,int h,HBITMAP pixmap,int srcx,int srcy);
#define fl_delete_offscreen(bitmap) DeleteObject(bitmap);

View File

@ -42,6 +42,14 @@
# include <stdio.h>
#endif // DEBUG
#ifdef WIN32
# include <ole2.h>
void fl_free_fonts(void);
HBRUSH fl_brush_action(int action);
void fl_cleanup_pens(void);
void fl_release_dc(HWND,HDC);
void fl_cleanup_dc_list(void);
#endif // WIN32
//
// Globals...
@ -298,6 +306,13 @@ double Fl::wait(double time_to_wait) {
int Fl::run() {
while (Fl_X::first) wait(FOREVER);
#ifdef WIN32
fl_free_fonts(); // do some WIN32 cleanup
fl_cleanup_pens();
OleUninitialize();
fl_brush_action(1);
fl_cleanup_dc_list();
#endif
return 0;
}
@ -836,9 +851,9 @@ void Fl_Window::hide() {
#ifdef WIN32
// 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) ReleaseDC(ip->xid,ip->private_dc);
if (ip->xid == fl_window && fl_gc) {
ReleaseDC(fl_window, fl_gc);
if (ip->private_dc) fl_release_dc(ip->xid, ip->private_dc);
if (ip->xid == fl_window && fl_gc) {
fl_release_dc(fl_window, fl_gc);
fl_window = (HWND)-1;
fl_gc = 0;
}
@ -871,6 +886,9 @@ void Fl_Window::hide() {
# if USE_XFT
fl_destroy_xft_draw(ip->xid);
# endif
#ifdef WIN32
fl_release_dc(ip->xid, fl_gc);
#endif
XDestroyWindow(fl_display, ip->xid);
#endif

View File

@ -11,7 +11,7 @@
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// but WITHOUT ANY WARRANTY; without even 79the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
@ -372,10 +372,12 @@ void Fl_Bitmap::draw(int XP, int YP, int WP, int HP, int cx, int cy) {
if (!id) id = fl_create_bitmap(w(), h(), array);
HDC tempdc = CreateCompatibleDC(fl_gc);
int save = SaveDC(tempdc);
SelectObject(tempdc, (HGDIOBJ)id);
SelectObject(fl_gc, fl_brush());
// secret bitblt code found in old MSWindows reference manual:
BitBlt(fl_gc, X, Y, W, H, tempdc, cx, cy, 0xE20746L);
RestoreDC(tempdc, save);
DeleteDC(tempdc);
#elif defined(__APPLE_QD__)
if (!id) id = fl_create_bitmask(w(), h(), array);

View File

@ -89,8 +89,10 @@ HDC fl_makeDC(HBITMAP bitmap) {
void fl_copy_offscreen(int x,int y,int w,int h,HBITMAP bitmap,int srcx,int srcy) {
HDC new_gc = CreateCompatibleDC(fl_gc);
int save = SaveDC(new_gc);
SelectObject(new_gc, bitmap);
BitBlt(fl_gc, x, y, w, h, new_gc, srcx, srcy, SRCCOPY);
RestoreDC(new_gc, save);
DeleteDC(new_gc);
}
@ -303,8 +305,10 @@ void Fl_Double_Window::flush(int eraseoverlay) {
#ifdef WIN32
HDC _sgc = fl_gc;
fl_gc = fl_makeDC(myi->other_xid);
int save = SaveDC(fl_gc);
fl_restore_clip(); // duplicate region into new gc
draw();
RestoreDC(fl_gc, save);
DeleteDC(fl_gc);
fl_gc = _sgc;
#elif defined(__APPLE__)

View File

@ -39,6 +39,10 @@
# include <FL/Fl_Window.H>
# endif
# ifdef WIN32
void fl_save_dc(HWND, HDC);
# endif
static Fl_Gl_Choice *first;
// this assummes one of the two arguments is zero:
@ -311,6 +315,7 @@ GLContext fl_create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int lay
HDC hdc = i->private_dc;
if (!hdc) {
hdc = i->private_dc = GetDCEx(i->xid, 0, DCX_CACHE);
fl_save_dc(i->xid, hdc);
SetPixelFormat(hdc, g->pixelformat, (PIXELFORMATDESCRIPTOR*)(&g->pfd));
# if USE_COLORMAP
if (fl_palette) SelectPalette(hdc, fl_palette, FALSE);

View File

@ -33,6 +33,9 @@
#include <FL/Fl_Image.H>
#include "flstring.h"
#ifdef WIN32
void fl_release_dc(HWND, HDC); // from Fl_win32.cxx
#endif
void fl_restore_clip(); // from fl_rect.cxx
@ -347,10 +350,12 @@ void Fl_RGB_Image::draw(int XP, int YP, int WP, int HP, int cx, int cy) {
#ifdef WIN32
if (mask) {
HDC new_gc = CreateCompatibleDC(fl_gc);
int save = SaveDC(new_gc);
SelectObject(new_gc, (void*)mask);
BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCAND);
SelectObject(new_gc, (void*)id);
BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCPAINT);
RestoreDC(new_gc,save);
DeleteDC(new_gc);
} else {
fl_copy_offscreen(X, Y, W, H, (Fl_Offscreen)id, cx, cy);

View File

@ -319,6 +319,7 @@ menuwindow::menuwindow(const Fl_Menu_Item* m, int X, int Y, int Wp, int Hp,
}
menuwindow::~menuwindow() {
hide();
delete title;
}

View File

@ -43,6 +43,10 @@
#include "flstring.h"
#include <ctype.h>
#ifdef WIN32
extern void fl_release_dc(HWND, HDC); // located in Fl_win32.cxx
#endif
#ifdef __APPLE_QUARTZ__
extern Fl_Offscreen fl_create_offscreen_with_alpha(int w, int h);
#endif
@ -108,10 +112,12 @@ void Fl_Pixmap::draw(int XP, int YP, int WP, int HP, int cx, int cy) {
#ifdef WIN32
if (mask) {
HDC new_gc = CreateCompatibleDC(fl_gc);
int save = SaveDC(new_gc);
SelectObject(new_gc, (void*)mask);
BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCAND);
SelectObject(new_gc, (void*)id);
BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCPAINT);
RestoreDC(new_gc,save);
DeleteDC(new_gc);
} else {
fl_copy_offscreen(X, Y, W, H, (Fl_Offscreen)id, cx, cy);

View File

@ -34,6 +34,7 @@
#include <FL/Fl_Window.H>
#include <FL/Enumerations.H>
#include "flstring.h"
#include "Fl_Font.H"
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
@ -1101,6 +1102,7 @@ char fl_show_iconic; // hack for Fl_Window::iconic()
HCURSOR fl_default_cursor;
UINT fl_wake_msg = 0;
int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR
WNDCLASSEX wc;
Fl_X* Fl_X::make(Fl_Window* w) {
Fl_Group::current(0); // get rid of very common user bug: forgot end()
@ -1115,26 +1117,38 @@ Fl_X* Fl_X::make(Fl_Window* w) {
const char* message_name = "FLTK::ThreadWakeup";
WNDCLASSEX wc;
// Documentation states a device context consumes about 800 bytes
// of memory... so who cares? If 800 bytes per window is what it
// takes to speed things up, I'm game.
//wc.style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC | CS_DBLCLKS;
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = wc.cbWndExtra = 0;
wc.hInstance = fl_display;
if (!w->icon())
w->icon((void *)LoadIcon(NULL, IDI_APPLICATION));
wc.hIcon = wc.hIconSm = (HICON)w->icon();
wc.hCursor = fl_default_cursor = LoadCursor(NULL, IDC_ARROW);
//uchar r,g,b; Fl::get_color(FL_GRAY,r,g,b);
//wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(r,g,b));
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = class_name;
wc.cbSize = sizeof(WNDCLASSEX);
RegisterClassEx(&wc);
// Register the first (or default FLTK) class only once.
// If the user creates mutiple new windows using other class names, they will
// be registered multiple times. This is not correct and should be fixed by
// keeping a list of registered window classes. Anyway, Windows is
// quite forgiving here,
static int first_time = 1;
if (first_time || strcmp(class_name, first_class_name)) {
WNDCLASSEX lwc;
// Documentation states a device context consumes about 800 bytes
// of memory... so who cares? If 800 bytes per window is what it
// takes to speed things up, I'm game.
//wc.style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC | CS_DBLCLKS;
lwc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
lwc.lpfnWndProc = (WNDPROC)WndProc;
lwc.cbClsExtra = wc.cbWndExtra = 0;
lwc.hInstance = fl_display;
if (!w->icon())
w->icon((void *)LoadIcon(NULL, IDI_APPLICATION));
lwc.hIcon = lwc.hIconSm = (HICON)w->icon();
lwc.hCursor = fl_default_cursor = LoadCursor(NULL, IDC_ARROW);
//uchar r,g,b; Fl::get_color(FL_GRAY,r,g,b);
//wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(r,g,b));
lwc.hbrBackground = NULL;
lwc.lpszMenuName = NULL;
lwc.lpszClassName = class_name;
lwc.cbSize = sizeof(WNDCLASSEX);
RegisterClassEx(&lwc);
if (first_time) {
memcpy(&wc, &lwc, lwc.cbSize);
first_time = 0;
}
}
if (!fl_wake_msg) fl_wake_msg = RegisterWindowMessage(message_name);
HWND parent;
@ -1346,9 +1360,10 @@ HWND fl_window = NULL;
HDC fl_GetDC(HWND w) {
if (fl_gc) {
if (w == fl_window && fl_window != NULL) return fl_gc;
ReleaseDC(fl_window, fl_gc);
if (fl_window) fl_release_dc(fl_window, fl_gc); // ReleaseDC
}
fl_gc = GetDC(w);
fl_save_dc(w, fl_gc);
fl_window = w;
// calling GetDC seems to always reset these: (?)
SetTextAlign(fl_gc, TA_BASELINE|TA_LEFT);
@ -1373,6 +1388,102 @@ void Fl_Window::make_current() {
fl_clip_region(0);
}
/* Make sure that all allocated fonts are released. This works only if
Fl::run() is allowed to exit by closing all windows. Calling 'exit(int)'
will not automatically free any fonts. */
void fl_free_fonts(void)
{
// remove the Fl_FontSize chains
int i;
Fl_Fontdesc * s;
Fl_FontSize * f;
Fl_FontSize * ff;
for (i=0; i<FL_FREE_FONT; i++) {
s = fl_fonts + i;
for (f=s->first; f; f=ff) {
ff = f->next;
delete(f);
s->first = ff;
}
}
}
///////////////////////////////////////////////////////////////////////
//
// The following routines help fix a problem with the leaking of Windows
// Device Context (DC) objects. The 'proper' protocol is for a program to
// acquire a DC, save its state, do the modifications needed for drawing,
// perform the drawing, restore the initial state, and release the DC. In
// FLTK, the save and restore steps have previously been omitted and DCs are
// not properly released, leading to a great number of DC leaks. As some
// Windows "OSs" will hang when any process exceeds roughly 10,000 GDI objects,
// it is important to control GDI leaks, which are much more important than memory
// leaks. The following struct, global variable, and routines help implement
// the above protocol for those cases where the GetDC and RestoreDC are not in
// the same routine. For each GetDC, fl_save_dc is used to create an entry in
// a linked list that saves the window handle, the DC handle, and the initial
// state. When the DC is to be released, 'fl_release_dc' is called. It restores
// the initial state and releases the DC. When the program exits, 'fl_cleanup_dc_list'
// frees any remaining nodes in the list.
struct Win_DC_List { // linked list
HWND window; // window handle
HDC dc; // device context handle
int saved_dc; // initial state of DC
Win_DC_List * next; // pointer to next item
};
static Win_DC_List * win_DC_list = 0;
void fl_save_dc( HWND w, HDC dc) {
Win_DC_List * t;
t = new Win_DC_List;
t->window = w;
t->dc = dc;
t->saved_dc = SaveDC(dc);
if (win_DC_list)
t->next = win_DC_list;
else
t->next = NULL;
win_DC_list = t;
}
void fl_release_dc(HWND w, HDC dc) {
Win_DC_List * t= win_DC_list;
Win_DC_List * prev = 0;
if (!t)
return;
do {
if (t->dc == dc) {
RestoreDC(dc, t->saved_dc);
ReleaseDC(w, dc);
if (!prev) {
win_DC_list = t->next; // delete first item
} else {
prev->next = t->next; // one in the middle
}
delete (t);
return;
}
prev = t;
t = t->next;
} while (t);
}
void fl_cleanup_dc_list(void) { // clean up the list
Win_DC_List * t = win_DC_list;
if (!t)return;
do {
RestoreDC(t->dc, t->saved_dc);
ReleaseDC(t->window, t->dc);
win_DC_list = t->next;
delete (t);
t = win_DC_list;
} while(t);
}
//
// End of "$Id$".
//

View File

@ -49,10 +49,15 @@ Fl_XMap fl_xmap[256];
Fl_XMap* fl_current_xmap;
HPALETTE fl_palette;
static HPEN tmppen=0;
static HBRUSH tmpbrush=0;
static HGDIOBJ tmppen=0;
static HPEN savepen=0;
void fl_cleanup_pens(void) {
for (int i=0; i<256; i++) {
if (fl_xmap[i].pen) DeleteObject(fl_xmap[i].pen);
}
}
void fl_save_pen(void) {
if(!tmppen) tmppen = CreatePen(PS_SOLID, 1, 0);
savepen = (HPEN)SelectObject(fl_gc, tmppen);
@ -60,17 +65,16 @@ void fl_save_pen(void) {
void fl_restore_pen(void) {
if (savepen) SelectObject(fl_gc, savepen);
DeleteObject(tmppen);
tmppen = 0;
savepen = 0;
}
static void clear_xmap(Fl_XMap& xmap) {
if (xmap.pen) {
if(!tmppen) tmppen = CreatePen(PS_SOLID, 1, 0);
if(!tmpbrush) tmpbrush = CreateSolidBrush(0);
HPEN oldpen = (HPEN)SelectObject(fl_gc, tmppen); // Push out the current pen of the gc
HGDIOBJ tmppen = GetStockObject(BLACK_PEN);
HGDIOBJ oldpen = SelectObject(fl_gc, tmppen); // Push out the current pen of the gc
if(oldpen != xmap.pen) SelectObject(fl_gc, oldpen); // Put it back if it is not the one we are about to delete
SelectObject(fl_gc, tmpbrush); // Push out the old pen of the gc
//fl_current_xmap = 0;
DeleteObject((HGDIOBJ)(xmap.pen));
xmap.pen = 0;
xmap.brush = -1;
@ -79,7 +83,12 @@ static void clear_xmap(Fl_XMap& xmap) {
static void set_xmap(Fl_XMap& xmap, COLORREF c) {
xmap.rgb = c;
xmap.pen = CreatePen(PS_SOLID, 1, xmap.rgb);
if (xmap.pen) {
HGDIOBJ oldpen = SelectObject(fl_gc,GetStockObject(BLACK_PEN)); // replace current pen with safe one
if (oldpen != xmap.pen)SelectObject(fl_gc,oldpen); // if old one not xmap.pen, need to put it back
DeleteObject(xmap.pen); // delete pen
}
xmap.pen = CreatePen(PS_SOLID, 1, xmap.rgb); // get a pen into xmap.pen
xmap.brush = -1;
}
@ -122,6 +131,10 @@ void fl_color(uchar r, uchar g, uchar b) {
}
HBRUSH fl_brush() {
return fl_brush_action(0);
}
HBRUSH fl_brush_action(int action) {
Fl_XMap *xmap = fl_current_xmap;
// Wonko: we use some statistics to cache only a limited number
// of brushes:
@ -132,6 +145,15 @@ HBRUSH fl_brush() {
Fl_XMap* backref;
} brushes[FL_N_BRUSH];
if (action) {
SelectObject(fl_gc, GetStockObject(BLACK_BRUSH)); // Load stock object
for (int i=0; i<FL_N_BRUSH; i++) {
if (brushes[i].brush)
DeleteObject(brushes[i].brush); // delete all brushes in array
}
return NULL;
}
int i = xmap->brush; // find the associated brush
if (i != -1) { // if the brush was allready allocated
if (brushes[i].brush == NULL) goto CREATE_BRUSH;
@ -154,7 +176,10 @@ HBRUSH fl_brush() {
}
}
i = imin;
DeleteObject(brushes[i].brush);
HGDIOBJ tmpbrush = GetStockObject(BLACK_BRUSH); // get a stock brush
HGDIOBJ oldbrush = SelectObject(fl_gc,tmpbrush); // load in into current context
if (oldbrush != brushes[i].brush) SelectObject(fl_gc,oldbrush); // reload old one
DeleteObject(brushes[i].brush); // delete the one in list
brushes[i].brush = NULL;
brushes[i].backref->brush = -1;
}

View File

@ -69,6 +69,7 @@ void fl_line_style(int style, int width, char* dashes) {
}
HPEN oldpen = (HPEN)SelectObject(fl_gc, newpen);
DeleteObject(oldpen);
DeleteObject(fl_current_xmap->pen);
fl_current_xmap->pen = newpen;
#elif defined(__APPLE_QD__)
// QuickDraw supports pen size and pattern, but no arbitrary line styles.