diff options
| author | Matthias Melcher <fltk@matthiasm.com> | 2005-09-12 23:03:34 +0000 |
|---|---|---|
| committer | Matthias Melcher <fltk@matthiasm.com> | 2005-09-12 23:03:34 +0000 |
| commit | 2b6586f64d4c49a3a3858ce52182610d5b77fbd0 (patch) | |
| tree | e11963920650a6269ad6c911b026f39ecc4024ec /src | |
| parent | 55380298b5cda84acb862ef5b87023d8f6b51232 (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.cxx | 24 | ||||
| -rw-r--r-- | src/Fl_Bitmap.cxx | 4 | ||||
| -rw-r--r-- | src/Fl_Double_Window.cxx | 4 | ||||
| -rw-r--r-- | src/Fl_Gl_Choice.cxx | 5 | ||||
| -rw-r--r-- | src/Fl_Image.cxx | 5 | ||||
| -rw-r--r-- | src/Fl_Menu.cxx | 1 | ||||
| -rw-r--r-- | src/Fl_Pixmap.cxx | 6 | ||||
| -rw-r--r-- | src/Fl_win32.cxx | 153 | ||||
| -rw-r--r-- | src/fl_color_win32.cxx | 43 | ||||
| -rw-r--r-- | src/fl_line_style.cxx | 1 |
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. |
