Skip to content

Commit 3e85689

Browse files
committed
[[ Bug 18293 ]] Use MCObjectHandle for button menu
1 parent 321f110 commit 3e85689

File tree

7 files changed

+133
-82
lines changed

7 files changed

+133
-82
lines changed

docs/notes/bugfix-18293.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Crash when deleting a stack that is used as a popup menu

engine/src/button.cpp

Lines changed: 94 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,6 @@ MCButton::MCButton()
314314
menucontrol = MENUCONTROL_NONE;
315315
menulines = DEFAULT_MENU_LINES;
316316
menuhasitemtags = false;
317-
menu = NULL; //stack based menu
318317
m_system_menu = NULL;
319318
entry = NULL;
320319
tabs = MCValueRetain(kMCEmptyArray);
@@ -354,7 +353,6 @@ MCButton::MCButton(const MCButton &bref) : MCControl(bref)
354353
menucontrol = bref.menucontrol;
355354
menuhasitemtags = bref.menuhasitemtags;
356355
menustring = MCValueRetain(bref.menustring);
357-
menu = NULL;
358356
m_system_menu = NULL;
359357
entry = NULL;
360358
tabs = MCValueRetain(kMCEmptyArray);
@@ -412,8 +410,11 @@ MCButton::~MCButton()
412410

413411
void MCButton::removelink(MCObject *optr)
414412
{
415-
if (optr == menu)
416-
menu = NULL;
413+
if (menu.IsBound() && optr == menu)
414+
{
415+
MCValueAssign(menuname, kMCEmptyName);
416+
menu = nil;
417+
}
417418
}
418419

419420
bool MCButton::imagechanged(MCImage *p_image, bool p_deleting)
@@ -497,8 +498,8 @@ void MCButton::open()
497498
break;
498499
default:
499500
findmenu(true);
500-
if (!MCNameIsEmpty(menuname) && menu != NULL)
501-
menu->installaccels(getstack());
501+
if (!MCNameIsEmpty(menuname) && menu.IsValid())
502+
menu.GetAs<MCStack>()->installaccels(getstack());
502503
break;
503504
}
504505
}
@@ -715,15 +716,15 @@ Boolean MCButton::kdown(MCStringRef p_string, KeySym key)
715716
case XK_WheelUp:
716717
case XK_WheelLeft:
717718
case XK_WheelRight:
718-
if (menu -> getcontrols() -> gettype() == CT_FIELD)
719-
if (menu -> getcontrols() -> kdown(p_string, key))
719+
if (menu.GetAs<MCStack>() -> getcontrols() -> gettype() == CT_FIELD)
720+
if (menu.GetAs<MCStack>() -> getcontrols() -> kdown(p_string, key))
720721
return True;
721722
break;
722723
case XK_space:
723724
case XK_Return:
724725
case XK_KP_Enter:
725726
closemenu(False, True);
726-
menu->menukdown(p_string, key, &t_pick, menuhistory);
727+
menu.GetAs<MCStack>()->menukdown(p_string, key, &t_pick, menuhistory);
727728

728729
// This check must be for null (not empty) because an empty pick
729730
// indicates that the function succeeded while a null pick means
@@ -757,7 +758,7 @@ Boolean MCButton::kdown(MCStringRef p_string, KeySym key)
757758
MCmenuobjectptr = NULL;
758759
return True;
759760
default:
760-
MCButton *mbptr = menu->findmnemonic(t_char);
761+
MCButton *mbptr = menu.GetAs<MCStack>()->findmnemonic(t_char);
761762
if (mbptr != NULL)
762763
{
763764
closemenu(False, True);
@@ -771,7 +772,7 @@ Boolean MCButton::kdown(MCStringRef p_string, KeySym key)
771772
else
772773
t_label = mbptr->getlabeltext();
773774

774-
menu->menukdown(p_string, key, &t_pick, menuhistory);
775+
menu.GetAs<MCStack>()->menukdown(p_string, key, &t_pick, menuhistory);
775776
Exec_stat es = handlemenupick(t_label, nil);
776777
if (es == ES_NOT_HANDLED || es == ES_PASS)
777778
message_with_args(MCM_mouse_up, menubutton);
@@ -856,7 +857,10 @@ Boolean MCButton::mfocus(int2 x, int2 y)
856857
if ( sptr == NULL)
857858
return False;
858859

859-
sptr->translatecoords(menu, tx, ty);
860+
if (!(menu.IsValid()))
861+
return False;
862+
863+
sptr->translatecoords(menu.GetAs<MCStack>(), tx, ty);
860864
MCRectangle trect = sptr->getrect();
861865
Boolean handled = menu->mfocus(tx, ty);
862866
tx = x + trect.x;
@@ -936,7 +940,7 @@ Boolean MCButton::mfocus(int2 x, int2 y)
936940
{
937941
uint2 fheight;
938942
fheight = gettextheight();
939-
MCField *fptr = (MCField *)menu->getcontrols();
943+
MCField *fptr = (MCField *)menu.GetAs<MCStack>()->getcontrols();
940944
fptr->vscroll(my < rect.y + rect.height ? -fheight : fheight, True);
941945
fptr->resetscrollbars(True);
942946
}
@@ -1140,6 +1144,9 @@ Boolean MCButton::mdown(uint2 which)
11401144
state |= CS_MFOCUSED;
11411145
if (state & CS_SUBMENU && (menubutton == 0 || (uint1)which == menubutton))
11421146
{
1147+
if (!(menu.IsValid()))
1148+
return False;
1149+
11431150
// SN-2014-08-26: [[ Bug 13201 ]] mx/my are now related to the button's rectangle,
11441151
// not the stack's rectangle anymore.
11451152
// SN-2014-10-17: [[ Bug 13675 ]] mx/my refer to the button's rectangle on Mac only
@@ -1164,7 +1171,7 @@ Boolean MCButton::mdown(uint2 which)
11641171
return mfocus(mx, my);
11651172
}
11661173
}
1167-
if ((!MCNameIsEmpty(menuname) || menu != NULL || getstyleint(flags) == F_MENU)
1174+
if ((!MCNameIsEmpty(menuname) || menu.IsValid() || getstyleint(flags) == F_MENU)
11681175
&& (menubutton == 0 || (uint1)which == menubutton)
11691176
&& (entry == NULL || !MCU_point_in_rect(entry->getrect(), mx, my))
11701177
&& (getstack()->gettool(this) == T_BROWSE
@@ -1294,7 +1301,11 @@ Boolean MCButton::mup(uint2 which, bool p_release)
12941301
}
12951302

12961303
state &= ~CS_MFOCUSED;
1297-
if (state & CS_FIELD_GRAB)
1304+
1305+
if (!(menu.IsValid()))
1306+
return False;
1307+
1308+
if (state & CS_FIELD_GRAB)
12981309
{
12991310
state &= ~CS_FIELD_GRAB;
13001311
if (state & CS_SUBMENU)
@@ -1343,7 +1354,7 @@ Boolean MCButton::mup(uint2 which, bool p_release)
13431354
// MW-2008-03-27; [[ Bug 6225 ]] Make sure we send a mouseUp in this case
13441355
// by setting the menupoppedup global.
13451356
MCmenupoppedup = true;
1346-
menu->menumup(which, &t_pick, menuhistory);
1357+
menu.GetAs<MCStack>()->menumup(which, &t_pick, menuhistory);
13471358
MCmenupoppedup = false;
13481359
if (state & CS_IGNORE_MENU)
13491360
closemenu(True, True);
@@ -1601,7 +1612,7 @@ Boolean MCButton::doubledown(uint2 which)
16011612
{
16021613
int2 tx = mx;
16031614
int2 ty = my;
1604-
if (menu)
1615+
if (menu.IsValid())
16051616
{
16061617
MCStack *sptr = MCmousestackptr;
16071618
MCRectangle trect = sptr->getrect();
@@ -1618,7 +1629,7 @@ Boolean MCButton::doubledown(uint2 which)
16181629
state |= CS_FIELD_GRAB;
16191630
return entry->doubledown(which);
16201631
}
1621-
else if (state & CS_SUBMENU && menu && MCU_point_in_rect(menu->getrect(), tx, ty))
1632+
else if (state & CS_SUBMENU && menu.IsValid() && MCU_point_in_rect(menu->getrect(), tx, ty))
16221633
{
16231634
state |= CS_FIELD_GRAB;
16241635
return menu->doubledown(which);
@@ -1637,7 +1648,7 @@ Boolean MCButton::doubleup(uint2 which)
16371648
state &= ~CS_FIELD_GRAB;
16381649
if (entry != NULL)
16391650
return entry->doubleup(which);
1640-
else if (state & CS_SUBMENU && menu)
1651+
else if (state & CS_SUBMENU && menu.IsValid())
16411652
return menu -> doubleup(which);
16421653
}
16431654
return MCControl::doubleup(which);
@@ -1710,7 +1721,7 @@ void MCButton::applyrect(const MCRectangle &nrect)
17101721

17111722
// MW-2010-06-07: [[ Bug 8746 ]] Make sure we rebuild the menu after freeing it,
17121723
// thus ensuring accelerators are not lost.
1713-
if (menu != NULL)
1724+
if (menu.IsValid())
17141725
{
17151726
freemenu(False);
17161727
findmenu(true);
@@ -1740,19 +1751,22 @@ void MCButton::closemenu(Boolean kfocus, Boolean disarm)
17401751
}
17411752
// MW-2011-08-18: [[ Layers ]] Invalidate the whole object.
17421753
layer_redrawall();
1743-
if (kfocus && !(state & CS_MFOCUSED))
1744-
{
1745-
menu->setstate(True, CS_KFOCUSED); // override state
1746-
menu->kunfocus();
1747-
}
1748-
MCButton *focused = (MCButton *)menu->getcurcard()->getmfocused();
1749-
if (focused != NULL && focused->gettype() == CT_BUTTON
1750-
&& focused->getmenumode() == WM_CASCADE)
1751-
focused->closemenu(kfocus, disarm);
1752-
1753-
menu -> mode_closeasmenu();
1754-
menu->close();
1754+
if (menu.IsValid())
1755+
{
1756+
if (kfocus && !(state & CS_MFOCUSED))
1757+
{
1758+
menu->setstate(True, CS_KFOCUSED); // override state
1759+
menu->kunfocus();
1760+
}
1761+
1762+
MCButton *focused = (MCButton *)menu.GetAs<MCStack>()->getcurcard()->getmfocused();
1763+
if (focused != NULL && focused->gettype() == CT_BUTTON
1764+
&& focused->getmenumode() == WM_CASCADE)
1765+
focused->closemenu(kfocus, disarm);
17551766

1767+
menu.GetAs<MCStack>() -> mode_closeasmenu();
1768+
menu->close();
1769+
}
17561770
state &= ~(CS_SUBMENU | CS_MOUSE_UP_MENU);
17571771
menudepth--;
17581772
}
@@ -1942,8 +1956,8 @@ void MCButton::activate(Boolean notify, KeySym p_key)
19421956
t_disabled = false;
19431957
MCAutoStringRef t_pick;
19441958

1945-
if (menu != NULL)
1946-
menu->findaccel(p_key, &t_pick, t_disabled);
1959+
if (menu.IsValid())
1960+
menu.GetAs<MCStack>()->findaccel(p_key, &t_pick, t_disabled);
19471961
#ifdef _MAC_DESKTOP
19481962
else if (m_system_menu != nil)
19491963
getmacmenuitemtextfromaccelerator(m_system_menu, p_key, MCmodifierstate, &t_pick, false);
@@ -2336,10 +2350,15 @@ void MCButton::makemenu(sublist *bstack, int2 &stackdepth, uint2 menuflags, MCFo
23362350
newmenu->menuwindow = True;
23372351
MCdispatcher->appendpanel(newmenu);
23382352
if (m->parent == this)
2339-
menu = newmenu;
2353+
{
2354+
menu = newmenu->GetHandle();
2355+
newmenu -> addneed(this);
2356+
}
23402357
else
23412358
{
2342-
m->parent->menu = newmenu;
2359+
m->parent->menu = newmenu->GetHandle();
2360+
newmenu -> addneed(m->parent);
2361+
23432362
m->parent->menumode = WM_CASCADE;
23442363
if (getstyleint(menuflags) == F_CHECK || getstyleint(menuflags) == F_RADIO)
23452364
m->parent->leftmargin += CHECK_SIZE + leftmargin;
@@ -2560,13 +2579,16 @@ Boolean MCButton::findmenu(bool p_just_for_accel)
25602579
Boolean isunicode = hasunicode();
25612580
if (!MCNameIsEmpty(menuname))
25622581
{
2563-
if (menu == NULL)
2582+
if (!(menu.IsValid()))
25642583
{
25652584
MCerrorlock++;
2566-
menu = getstack()->findstackname(menuname);
2567-
MCerrorlock--;
2568-
if (menu != NULL)
2569-
menu->addneed(this);
2585+
MCStack * t_stack = getstack()->findstackname(menuname);
2586+
MCerrorlock--;
2587+
if (t_stack != nil)
2588+
{
2589+
menu = t_stack->GetHandle();
2590+
t_stack->addneed(this);
2591+
}
25702592
}
25712593
}
25722594
else if (!MCStringIsEmpty(menustring) && getstyleint(flags) == F_MENU)
@@ -2576,7 +2598,7 @@ Boolean MCButton::findmenu(bool p_just_for_accel)
25762598
MCValueRelease(tabs);
25772599
/* UNCHECKED */ MCStringSplit(menustring, MCSTR("\n"), nil, kMCStringOptionCompareExact, tabs);
25782600
}
2579-
else if (menu == NULL)
2601+
else if (!(menu.IsValid()))
25802602
{
25812603
uint2 fheight;
25822604
fheight = gettextheight();
@@ -2603,11 +2625,15 @@ Boolean MCButton::findmenu(bool p_just_for_accel)
26032625
MCU_set_rect(trect, 0, 0, rect.width, height + 4);
26042626
trect = MCU_reduce_rect(trect, MClook == LF_MOTIF ? DEFAULT_BORDER : 1);
26052627
fptr->setrect(trect);
2606-
/* UNCHECKED */ MCStackSecurityCreateStack(menu);
2607-
2608-
menu->setparent(this);
2609-
menu->createmenu(fptr, rect.width, height + 4);
2610-
MCdispatcher->appendpanel(menu);
2628+
MCStack * t_menu;
2629+
if (!MCStackSecurityCreateStack(t_menu))
2630+
return False;
2631+
2632+
t_menu->setparent(this);
2633+
t_menu->createmenu(fptr, rect.width, height + 4);
2634+
MCdispatcher->appendpanel(t_menu);
2635+
menu = t_menu->GetHandle();
2636+
t_menu -> addneed(this);
26112637
}
26122638
else
26132639
{
@@ -2653,7 +2679,7 @@ Boolean MCButton::findmenu(bool p_just_for_accel)
26532679
MCValueAssign(tabs, kMCEmptyArray);
26542680
}
26552681
}
2656-
return menu != NULL;
2682+
return menu.IsValid();
26572683
}
26582684

26592685
void MCButton::setmenuhandler(MCButtonMenuHandler *p_handler)
@@ -2734,7 +2760,7 @@ void MCButton::openmenu(Boolean grab)
27342760
&& cascade_sptr->getmode() < WM_PULLDOWN)
27352761
{
27362762
MCmousestackptr->kfocusset(this);
2737-
if (menu == NULL && !findmenu())
2763+
if (!(menu.IsValid()) && !findmenu())
27382764
return;
27392765
}
27402766
if (IsMacLFAM() &&
@@ -2785,17 +2811,17 @@ void MCButton::openmenu(Boolean grab)
27852811
}
27862812
rel.x += labelwidth;
27872813
rel.width -= labelwidth;
2788-
menu->menuset(menuhistory, rect.height >> 1);
2814+
menu.GetAs<MCStack>()->menuset(menuhistory, rect.height >> 1);
27892815
}
27902816

2791-
menu->openrect(rel, (Window_mode)menumode, NULL, WP_DEFAULT, OP_NONE);
2792-
menu -> mode_openasmenu(t_did_grab ? sptr : NULL);
2817+
menu.GetAs<MCStack>()->openrect(rel, (Window_mode)menumode, NULL, WP_DEFAULT, OP_NONE);
2818+
menu.GetAs<MCStack>() -> mode_openasmenu(t_did_grab ? sptr : NULL);
27932819

27942820
// MW-2014-03-11: [[ Bug 11893 ]] Make sure we don't do anything to a stack panel.
27952821
if (menumode == WM_OPTION && MCNameIsEmpty(menuname))
27962822
{
27972823
MCField *t_field = NULL;
2798-
MCObjptr *t_obj = menu->getcurcard()->getrefs();
2824+
MCObjptr *t_obj = menu.GetAs<MCStack>()->getcurcard()->getrefs();
27992825
MCObjptr *t_iter = t_obj;
28002826
do
28012827
{
@@ -2816,9 +2842,9 @@ void MCButton::openmenu(Boolean grab)
28162842
}
28172843
int2 tx = mx;
28182844
int2 ty = my;
2819-
sptr->translatecoords(menu, tx, ty);
2845+
sptr->translatecoords(menu.GetAs<MCStack>(), tx, ty);
28202846
menu->mfocus(tx, ty);
2821-
menu->resetcursor(True);
2847+
menu.GetAs<MCStack>()->resetcursor(True);
28222848
if (!(state & CS_MFOCUSED))
28232849
menu->kfocusnext(True);
28242850
// MW-2011-08-18: [[ Layers ]] Invalidate the whole object.
@@ -2833,24 +2859,23 @@ void MCButton::freemenu(Boolean force)
28332859
#ifdef _MAC_DESKTOP
28342860
macfreemenu();
28352861
#endif
2836-
if (menu != NULL && !(state & CS_SUBMENU))
2862+
if (menu.IsValid() && !(state & CS_SUBMENU))
28372863
{
28382864
if (!MCNameIsEmpty(menuname))
28392865
{
2840-
menu->removeaccels(getstack());
2841-
menu->removeneed(this);
2842-
menu = NULL;
2866+
menu.GetAs<MCStack>()->removeaccels(getstack());
2867+
menu.GetAs<MCStack>()->removeneed(this);
2868+
menu = nil;
28432869
}
28442870
else
28452871
{
28462872
if (!MCStringIsEmpty(menustring) || force)
28472873
{
28482874
closemenu(False, True);
2849-
MCdispatcher->removepanel(menu);
2875+
MCdispatcher->removepanel(menu.GetAs<MCStack>());
28502876
MCstacks->deleteaccelerator(this, NULL);
2851-
menu->removeneed(this);
2852-
delete menu;
2853-
menu = NULL;
2877+
menu.GetAs<MCStack>()->removeneed(this);
2878+
menu = nil;
28542879
}
28552880
}
28562881
}
@@ -2918,7 +2943,7 @@ bool MCButton::menuisopen()
29182943
#ifdef _MAC_DESKTOP
29192944
return macmenuisopen();
29202945
#else
2921-
return menu != nil && menu->getopened();
2946+
return menu.IsValid() && menu->getopened();
29222947
#endif
29232948
}
29242949

@@ -3865,6 +3890,11 @@ IO_stat MCButton::load(IO_handle stream, uint32_t version)
38653890
return IO_NORMAL;
38663891
}
38673892

3893+
MCStack * MCButton::getmenu()
3894+
{
3895+
return menu.GetAs<MCStack>();
3896+
}
3897+
38683898
////////////////////////////////////////////////////////////////////////////////
38693899

38703900
MCPlatformControlType MCButton::getcontroltype()

0 commit comments

Comments
 (0)