summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMatthias Melcher <fltk@matthiasm.com>2005-09-12 23:03:34 +0000
committerMatthias Melcher <fltk@matthiasm.com>2005-09-12 23:03:34 +0000
commit2b6586f64d4c49a3a3858ce52182610d5b77fbd0 (patch)
treee11963920650a6269ad6c911b026f39ecc4024ec /src
parent55380298b5cda84acb862ef5b87023d8f6b51232 (diff)
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
Diffstat (limited to 'src')
-rw-r--r--src/Fl.cxx24
-rw-r--r--src/Fl_Bitmap.cxx4
-rw-r--r--src/Fl_Double_Window.cxx4
-rw-r--r--src/Fl_Gl_Choice.cxx5
-rw-r--r--src/Fl_Image.cxx5
-rw-r--r--src/Fl_Menu.cxx1
-rw-r--r--src/Fl_Pixmap.cxx6
-rw-r--r--src/Fl_win32.cxx153
-rw-r--r--src/fl_color_win32.cxx43
-rw-r--r--src/fl_line_style.cxx1
10 files changed, 212 insertions, 34 deletions
diff --git a/src/Fl.cxx b/src/Fl.cxx
index a708f2ffb..6245a50df 100644
--- a/src/Fl.cxx
+++ b/src/Fl.cxx
@@ -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
diff --git a/src/Fl_Bitmap.cxx b/src/Fl_Bitmap.cxx
index 372578633..3b39ce472 100644
--- a/src/Fl_Bitmap.cxx
+++ b/src/Fl_Bitmap.cxx
@@ -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);
diff --git a/src/Fl_Double_Window.cxx b/src/Fl_Double_Window.cxx
index c0d5c005d..add438801 100644
--- a/src/Fl_Double_Window.cxx
+++ b/src/Fl_Double_Window.cxx
@@ -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__)
diff --git a/src/Fl_Gl_Choice.cxx b/src/Fl_Gl_Choice.cxx
index 90840dae8..ad7cc6d64 100644
--- a/src/Fl_Gl_Choice.cxx
+++ b/src/Fl_Gl_Choice.cxx
@@ -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);
diff --git a/src/Fl_Image.cxx b/src/Fl_Image.cxx
index fc398a6fa..01f7bcbbc 100644
--- a/src/Fl_Image.cxx
+++ b/src/Fl_Image.cxx
@@ -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);
diff --git a/src/Fl_Menu.cxx b/src/Fl_Menu.cxx
index 9457e8f66..16ea170f2 100644
--- a/src/Fl_Menu.cxx
+++ b/src/Fl_Menu.cxx
@@ -319,6 +319,7 @@ menuwindow::menuwindow(const Fl_Menu_Item* m, int X, int Y, int Wp, int Hp,
}
menuwindow::~menuwindow() {
+ hide();
delete title;
}
diff --git a/src/Fl_Pixmap.cxx b/src/Fl_Pixmap.cxx
index 9b2cfcdd2..a3fad728a 100644
--- a/src/Fl_Pixmap.cxx
+++ b/src/Fl_Pixmap.cxx
@@ -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);
diff --git a/src/Fl_win32.cxx b/src/Fl_win32.cxx
index 43217d3a0..266073f12 100644
--- a/src/Fl_win32.cxx
+++ b/src/Fl_win32.cxx
@@ -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$".
//
diff --git a/src/fl_color_win32.cxx b/src/fl_color_win32.cxx
index e09718df9..b0ff67451 100644
--- a/src/fl_color_win32.cxx
+++ b/src/fl_color_win32.cxx
@@ -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;
}
diff --git a/src/fl_line_style.cxx b/src/fl_line_style.cxx
index c50c2a19c..a0be2894d 100644
--- a/src/fl_line_style.cxx
+++ b/src/fl_line_style.cxx
@@ -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.