summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-10-09 07:04:11 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-10-09 07:04:11 +0300
commitbb7bc6fac4fec804846d11c7d77e1b553ba2be6a (patch)
treec170f134b5ac01c29195589cc77ae4598a524eb3
parent5b58cc76bd08d0e061c5f14506d97ee8dc3b7174 (diff)
Fixed memory leak on tab close
The DocumentWidget was not actually deleted when a tab was closed, only hidden.
-rw-r--r--src/app.c10
-rw-r--r--src/app.h5
-rw-r--r--src/audio/player.c6
-rw-r--r--src/audio/player.h2
-rw-r--r--src/media.c4
-rw-r--r--src/ui/documentwidget.c40
-rw-r--r--src/ui/util.c3
-rw-r--r--src/ui/widget.c4
8 files changed, 62 insertions, 12 deletions
diff --git a/src/app.c b/src/app.c
index ff5ec9b7..0916919e 100644
--- a/src/app.c
+++ b/src/app.c
@@ -649,12 +649,17 @@ iAny *findWidget_App(const char *id) {
649 return findChild_Widget(app_.window->root, id); 649 return findChild_Widget(app_.window->root, id);
650} 650}
651 651
652void addTicker_App(void (*ticker)(iAny *), iAny *context) { 652void addTicker_App(iTickerFunc ticker, iAny *context) {
653 iApp *d = &app_; 653 iApp *d = &app_;
654 insert_SortedArray(&d->tickers, &(iTicker){ context, ticker }); 654 insert_SortedArray(&d->tickers, &(iTicker){ context, ticker });
655 postRefresh_App(); 655 postRefresh_App();
656} 656}
657 657
658void removeTicker_App(iTickerFunc ticker, iAny *context) {
659 iApp *d = &app_;
660 remove_SortedArray(&d->tickers, &(iTicker){ context, ticker });
661}
662
658iGmCerts *certs_App(void) { 663iGmCerts *certs_App(void) {
659 return app_.certs; 664 return app_.certs;
660} 665}
@@ -737,7 +742,8 @@ iDocumentWidget *newTab_App(const iDocumentWidget *duplicateOf, iBool switchToNe
737 doc = new_DocumentWidget(); 742 doc = new_DocumentWidget();
738 } 743 }
739 setId_Widget(as_Widget(doc), format_CStr("document%03d", ++d->tabEnum)); 744 setId_Widget(as_Widget(doc), format_CStr("document%03d", ++d->tabEnum));
740 appendTabPage_Widget(tabs, iClob(doc), "", 0, 0); 745 appendTabPage_Widget(tabs, as_Widget(doc), "", 0, 0);
746 iRelease(doc); /* now owned by the tabs */
741 addChild_Widget(findChild_Widget(tabs, "tabs.buttons"), iClob(newTabButton)); 747 addChild_Widget(findChild_Widget(tabs, "tabs.buttons"), iClob(newTabButton));
742 if (switchToNew) { 748 if (switchToNew) {
743 postCommandf_App("tabs.switch page:%p", doc); 749 postCommandf_App("tabs.switch page:%p", doc);
diff --git a/src/app.h b/src/app.h
index db22230e..bf310d98 100644
--- a/src/app.h
+++ b/src/app.h
@@ -73,8 +73,11 @@ iObjectList * listDocuments_App (void);
73iDocumentWidget * document_Command (const char *cmd); 73iDocumentWidget * document_Command (const char *cmd);
74iDocumentWidget * newTab_App (const iDocumentWidget *duplicateOf, iBool switchToNew); 74iDocumentWidget * newTab_App (const iDocumentWidget *duplicateOf, iBool switchToNew);
75 75
76typedef void (*iTickerFunc)(iAny *);
77
76iAny * findWidget_App (const char *id); 78iAny * findWidget_App (const char *id);
77void addTicker_App (void (*ticker)(iAny *), iAny *context); 79void addTicker_App (iTickerFunc ticker, iAny *context);
80void removeTicker_App (iTickerFunc ticker, iAny *context);
78void postRefresh_App (void); 81void postRefresh_App (void);
79void postCommand_App (const char *command); 82void postCommand_App (const char *command);
80void postCommandf_App (const char *command, ...); 83void postCommandf_App (const char *command, ...);
diff --git a/src/audio/player.c b/src/audio/player.c
index 5b9d0103..07f41f01 100644
--- a/src/audio/player.c
+++ b/src/audio/player.c
@@ -563,3 +563,9 @@ float streamProgress_Player(const iPlayer *d) {
563 } 563 }
564 return 0; 564 return 0;
565} 565}
566
567iString *metadataLabel_Player(const iPlayer *d) {
568 return newFormat_String("%d-bit %s %d Hz", SDL_AUDIO_BITSIZE(d->decoder->inputFormat),
569 SDL_AUDIO_ISFLOAT(d->decoder->inputFormat) ? "float" : "integer",
570 d->spec.freq);
571}
diff --git a/src/audio/player.h b/src/audio/player.h
index c3552640..fe6717b0 100644
--- a/src/audio/player.h
+++ b/src/audio/player.h
@@ -45,3 +45,5 @@ iBool isPaused_Player (const iPlayer *);
45float time_Player (const iPlayer *); 45float time_Player (const iPlayer *);
46float duration_Player (const iPlayer *); 46float duration_Player (const iPlayer *);
47float streamProgress_Player (const iPlayer *); /* normalized 0...1 */ 47float streamProgress_Player (const iPlayer *); /* normalized 0...1 */
48
49iString * metadataLabel_Player (const iPlayer *);
diff --git a/src/media.c b/src/media.c
index 253893fc..c447704b 100644
--- a/src/media.c
+++ b/src/media.c
@@ -75,8 +75,8 @@ void deinit_GmImage(iGmImage *d) {
75} 75}
76 76
77void makeTexture_GmImage(iGmImage *d) { 77void makeTexture_GmImage(iGmImage *d) {
78 iBlock *data = &d->partialData; 78 iBlock *data = &d->partialData;
79 d->numBytes = size_Block(data); 79 d->numBytes = size_Block(data);
80 uint8_t *imgData = stbi_load_from_memory( 80 uint8_t *imgData = stbi_load_from_memory(
81 constData_Block(data), size_Block(data), &d->size.x, &d->size.y, NULL, 4); 81 constData_Block(data), size_Block(data), &d->size.x, &d->size.y, NULL, 4);
82 if (!imgData) { 82 if (!imgData) {
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 9d94f200..bbe5ccba 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -191,6 +191,7 @@ struct Impl_DocumentWidget {
191 iAnim outlineOpacity; 191 iAnim outlineOpacity;
192 iArray outline; 192 iArray outline;
193 iWidget * menu; 193 iWidget * menu;
194 iWidget * playerMenu;
194 iVisBuf * visBuf; 195 iVisBuf * visBuf;
195 iPtrSet * invalidRuns; 196 iPtrSet * invalidRuns;
196}; 197};
@@ -241,6 +242,7 @@ void init_DocumentWidget(iDocumentWidget *d) {
241 init_Click(&d->click, d, SDL_BUTTON_LEFT); 242 init_Click(&d->click, d, SDL_BUTTON_LEFT);
242 addChild_Widget(w, iClob(d->scroll = new_ScrollWidget())); 243 addChild_Widget(w, iClob(d->scroll = new_ScrollWidget()));
243 d->menu = NULL; /* created when clicking */ 244 d->menu = NULL; /* created when clicking */
245 d->playerMenu = NULL;
244#if !defined (iPlatformApple) /* in system menu */ 246#if !defined (iPlatformApple) /* in system menu */
245 addAction_Widget(w, reload_KeyShortcut, "navigate.reload"); 247 addAction_Widget(w, reload_KeyShortcut, "navigate.reload");
246 addAction_Widget(w, SDLK_w, KMOD_PRIMARY, "tabs.close"); 248 addAction_Widget(w, SDLK_w, KMOD_PRIMARY, "tabs.close");
@@ -249,7 +251,10 @@ void init_DocumentWidget(iDocumentWidget *d) {
249 addAction_Widget(w, navigateForward_KeyShortcut, "navigate.forward"); 251 addAction_Widget(w, navigateForward_KeyShortcut, "navigate.forward");
250} 252}
251 253
254static void animatePlayingAudio_DocumentWidget_(void *);
255
252void deinit_DocumentWidget(iDocumentWidget *d) { 256void deinit_DocumentWidget(iDocumentWidget *d) {
257 removeTicker_App(animatePlayingAudio_DocumentWidget_, d);
253 delete_VisBuf(d->visBuf); 258 delete_VisBuf(d->visBuf);
254 delete_PtrSet(d->invalidRuns); 259 delete_PtrSet(d->invalidRuns);
255 deinit_Array(&d->outline); 260 deinit_Array(&d->outline);
@@ -1626,7 +1631,7 @@ static void drawPlayerButton_(iPaint *p, iRect rect, const char *label) {
1626 adjusted_Rect(shrunk_Rect(frameRect, divi_I2(gap2_UI, 2)), zero_I2(), one_I2()), 1631 adjusted_Rect(shrunk_Rect(frameRect, divi_I2(gap2_UI, 2)), zero_I2(), one_I2()),
1627 frame); 1632 frame);
1628 } 1633 }
1629 const int fg = isPressed ? uiBackground_ColorId : frame; 1634 const int fg = isPressed ? (permanent_ColorId | uiBackground_ColorId) : uiHeading_ColorId;
1630 drawCentered_Text(uiContent_FontId, frameRect, iTrue, fg, "%s", label); 1635 drawCentered_Text(uiContent_FontId, frameRect, iTrue, fg, "%s", label);
1631} 1636}
1632 1637
@@ -1704,6 +1709,11 @@ static iBool processAudioPlayerEvents_DocumentWidget_(iDocumentWidget *d, const
1704 ev->type != SDL_MOUSEMOTION) { 1709 ev->type != SDL_MOUSEMOTION) {
1705 return iFalse; 1710 return iFalse;
1706 } 1711 }
1712 if (ev->type == SDL_MOUSEBUTTONDOWN || ev->type == SDL_MOUSEBUTTONUP) {
1713 if (ev->button.button != SDL_BUTTON_LEFT) {
1714 return iFalse;
1715 }
1716 }
1707 const iInt2 mouse = init_I2(ev->button.x, ev->button.y); 1717 const iInt2 mouse = init_I2(ev->button.x, ev->button.y);
1708 iConstForEach(PtrArray, i, &d->visiblePlayers) { 1718 iConstForEach(PtrArray, i, &d->visiblePlayers) {
1709 const iGmRun *run = i.ptr; 1719 const iGmRun *run = i.ptr;
@@ -1722,12 +1732,34 @@ static iBool processAudioPlayerEvents_DocumentWidget_(iDocumentWidget *d, const
1722 return iTrue; 1732 return iTrue;
1723 } 1733 }
1724 else if (contains_Rect(ui.rewindRect, mouse)) { 1734 else if (contains_Rect(ui.rewindRect, mouse)) {
1725 stop_Player(plr); 1735 if (isStarted_Player(plr) && time_Player(plr) > 0.5f) {
1726 start_Player(plr); 1736 stop_Player(plr);
1727 setPaused_Player(plr, iTrue); 1737 start_Player(plr);
1738 setPaused_Player(plr, iTrue);
1739 }
1728 refresh_Widget(d); 1740 refresh_Widget(d);
1729 return iTrue; 1741 return iTrue;
1730 } 1742 }
1743 else if (contains_Rect(ui.menuRect, mouse)) {
1744 /* TODO: Add menu items for:
1745 - output device
1746 - Save to Downloads
1747 */
1748 if (d->playerMenu) {
1749 destroy_Widget(d->playerMenu);
1750 d->playerMenu = NULL;
1751 return iTrue;
1752 }
1753 d->playerMenu = makeMenu_Widget(
1754 as_Widget(d),
1755 (iMenuItem[]){
1756 { cstrCollect_String(metadataLabel_Player(plr)), 0, 0, NULL },
1757 },
1758 1);
1759 openMenu_Widget(d->playerMenu,
1760 localCoord_Widget(constAs_Widget(d), bottomLeft_Rect(ui.menuRect)));
1761 return iTrue;
1762 }
1731 } 1763 }
1732 } 1764 }
1733 return iFalse; 1765 return iFalse;
diff --git a/src/ui/util.c b/src/ui/util.c
index 13a7a7a2..89f71da2 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -498,9 +498,8 @@ iWidget *removeTabPage_Widget(iWidget *tabs, size_t index) {
498 iWidget *button = removeChild_Widget(buttons, child_Widget(buttons, index)); 498 iWidget *button = removeChild_Widget(buttons, child_Widget(buttons, index));
499 iRelease(button); 499 iRelease(button);
500 iWidget *page = child_Widget(pages, index); 500 iWidget *page = child_Widget(pages, index);
501 ref_Object(page);
502 setFlags_Widget(page, hidden_WidgetFlag | disabled_WidgetFlag, iFalse); 501 setFlags_Widget(page, hidden_WidgetFlag | disabled_WidgetFlag, iFalse);
503 removeChild_Widget(pages, page); 502 removeChild_Widget(pages, page); /* `page` is now ours */
504 if (tabCount_Widget(tabs) <= 1 && flags_Widget(buttons) & collapse_WidgetFlag) { 503 if (tabCount_Widget(tabs) <= 1 && flags_Widget(buttons) & collapse_WidgetFlag) {
505 setFlags_Widget(buttons, hidden_WidgetFlag, iTrue); 504 setFlags_Widget(buttons, hidden_WidgetFlag, iTrue);
506 } 505 }
diff --git a/src/ui/widget.c b/src/ui/widget.c
index 459c2ae1..ea2e3fe2 100644
--- a/src/ui/widget.c
+++ b/src/ui/widget.c
@@ -55,7 +55,6 @@ iPtrArray *onTop_RootData_(void) {
55void destroyPending_Widget(void) { 55void destroyPending_Widget(void) {
56 iForEach(PtrSet, i, rootData_.pendingDestruction) { 56 iForEach(PtrSet, i, rootData_.pendingDestruction) {
57 iWidget *widget = *i.value; 57 iWidget *widget = *i.value;
58 removeOne_PtrArray(onTop_RootData_(), widget);
59 if (widget->parent) { 58 if (widget->parent) {
60 iRelease(removeChild_Widget(widget->parent, widget)); 59 iRelease(removeChild_Widget(widget->parent, widget));
61 } 60 }
@@ -90,6 +89,9 @@ static void aboutToBeDestroyed_Widget_(iWidget *d) {
90 setFocus_Widget(NULL); 89 setFocus_Widget(NULL);
91 return; 90 return;
92 } 91 }
92 if (flags_Widget(d) & keepOnTop_WidgetFlag) {
93 removeOne_PtrArray(onTop_RootData_(), d);
94 }
93 if (isHover_Widget(d)) { 95 if (isHover_Widget(d)) {
94 rootData_.hover = NULL; 96 rootData_.hover = NULL;
95 } 97 }