From 5aef501d9c3394599dd2e48ff7ba7bb5f13cd19a Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 14 May 2022 21:18:27 +0800 Subject: [PATCH] Fix processing of dialog box items on NS * src/nsmenu.m (pop_down_menu): Remove old hack and discard menu items. (ns_popup_dialog): ([EmacsDialogPanel initWithContentRect:styleMask:backing:defer:]): ([EmacsDialogPanel windowShouldClose:]): ([EmacsDialogPanel dealloc]): ([EmacsDialogPanel processdialog:]): ([EmacsDialogPanel addButton:value:row:]): ([EmacsDialogPanel addString:row:]): ([EmacsDialogPanel clicked:]): ([EmacsDialogPanel initFromContents:isQuestion:]): ([EmacsDialogPanel timeouthandler:]): ([EmacsDialogPanel runDialogAt:]): Use the regular menu item machinery to parse dialog items instead of the incorrect ad-hoc code used previously. * src/nsterm.h: Update prototypes. --- src/nsmenu.m | 271 +++++++++++++++++++++++++++------------------------ src/nsterm.h | 42 +++++--- 2 files changed, 171 insertions(+), 142 deletions(-) diff --git a/src/nsmenu.m b/src/nsmenu.m index 531f0d3bb6d..1ebaca4e872 100644 --- a/src/nsmenu.m +++ b/src/nsmenu.m @@ -1538,31 +1538,32 @@ pop_down_menu (void *arg) if (popup_activated_flag) { - block_input (); popup_activated_flag = 0; [panel close]; - [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow]; - unblock_input (); + discard_menu_items (); } } - Lisp_Object ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents) { - id dialog; + EmacsDialogPanel *dialog; Lisp_Object tem, title; NSPoint p; - BOOL isQ; + BOOL is_question; + const char *error_name; + specpdl_ref specpdl_count; NSTRACE ("ns_popup_dialog"); + specpdl_count = SPECPDL_INDEX (); - isQ = NILP (header); - + is_question = NILP (header); check_window_system (f); - p.x = (int)f->left_pos + ((int)FRAME_COLUMN_WIDTH (f) * f->text_cols)/2; - p.y = (int)f->top_pos + (FRAME_LINE_HEIGHT (f) * f->text_lines)/2; + p.x = ((int) f->left_pos + + ((int) FRAME_COLUMN_WIDTH (f) * f->text_cols) / 2); + p.y = ((int) f->top_pos + + (FRAME_LINE_HEIGHT (f) * f->text_lines) / 2); title = Fcar (contents); CHECK_STRING (title); @@ -1572,21 +1573,30 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents) the dialog. */ contents = list2 (title, Fcons (build_string ("Ok"), Qt)); - block_input (); - dialog = [[EmacsDialogPanel alloc] initFromContents: contents - isQuestion: isQ]; - - { - specpdl_ref specpdl_count = SPECPDL_INDEX (); + record_unwind_protect_void (unuse_menu_items); + list_of_panes (list1 (contents)); - record_unwind_protect_ptr (pop_down_menu, dialog); - popup_activated_flag = 1; - tem = [dialog runDialogAt: p]; - unbind_to (specpdl_count, Qnil); /* calls pop_down_menu */ - } + block_input (); + dialog = [[EmacsDialogPanel alloc] initWithTitle: SSDATA (title) + isQuestion: is_question]; + [dialog processMenuItems: menu_items + used: menu_items_used + withErrorOutput: &error_name]; + [dialog resizeBoundsPriorToDisplay]; unblock_input (); + if (error_name) + { + discard_menu_items (); + [dialog close]; + error ("%s", error_name); + } + + record_unwind_protect_ptr (pop_down_menu, dialog); + popup_activated_flag = 1; + tem = [dialog runDialogAt: p]; + unbind_to (specpdl_count, Qnil); return tem; } @@ -1627,7 +1637,6 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents) NSImage *img; dialog_return = Qundefined; - button_values = NULL; area.origin.x = 3*SPACER; area.origin.y = 2*SPACER; area.size.width = ICONSIZE; @@ -1711,58 +1720,65 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents) } -- (BOOL)windowShouldClose: (id)sender +- (BOOL)windowShouldClose: (id) sender { window_closed = YES; - [NSApp stop:self]; + [NSApp stop: self]; return NO; } -- (void)dealloc +- (void) dealloc { - xfree (button_values); [super dealloc]; } -- (void)process_dialog: (Lisp_Object) list +- (void) processMenuItems: (Lisp_Object) menu_items + used: (ptrdiff_t) menu_items_used + withErrorOutput: (const char **) error_name { - Lisp_Object item, lst = list; - int row = 0; - int buttons = 0, btnnr = 0; + int i, nb_buttons = 0, row = 0; + Lisp_Object item_name, enable; - for (; CONSP (lst); lst = XCDR (lst)) + i = MENU_ITEMS_PANE_LENGTH; + *error_name = NULL; + + /* Loop over all panes and items, filling in the tree. */ + while (i < menu_items_used) { - item = XCAR (list); - if (CONSP (item)) - ++buttons; - } + item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME); + enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE); - if (buttons > 0) - button_values = xmalloc (buttons * sizeof *button_values); + if (NILP (item_name)) + { + *error_name = "Submenu in dialog items"; + return; + } - for (; CONSP (list); list = XCDR (list)) - { - item = XCAR (list); - if (STRINGP (item)) - { - [self addString: SSDATA (item) row: row++]; - } - else if (CONSP (item)) - { - button_values[btnnr] = XCDR (item); - [self addButton: SSDATA (XCAR (item)) value: btnnr row: row++]; - ++btnnr; - } - else if (NILP (item)) - { - [self addSplit]; - row = 0; - } + if (EQ (item_name, Qquote)) + /* This is the boundary between elements on the left and those + on the right, but that boundary is currently not handled on + NS. */ + continue; + + if (nb_buttons > 9) + { + *error_name = "Too many dialog items"; + return; + } + + [self addButton: SSDATA (item_name) + value: (NSInteger) aref_addr (menu_items, i) + row: row++ + enable: !NILP (enable)]; + + i += MENU_ITEMS_ITEM_LENGTH; + nb_buttons++; } } -- (void)addButton: (char *)str value: (int)tag row: (int)row +- (void) addButton: (char *) str value: (NSInteger) tag + row: (int) row enable: (BOOL) enable { id cell; @@ -1771,7 +1787,8 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents) [matrix addRow]; rows++; } - cell = [matrix cellAtRow: row column: cols-1]; + + cell = [matrix cellAtRow: row column: cols - 1]; [cell setTarget: self]; [cell setAction: @selector (clicked: )]; [cell setTitle: [NSString stringWithUTF8String: str]]; @@ -1781,7 +1798,7 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents) } -- (void)addString: (char *)str row: (int)row +- (void)addString: (char *) str row: (int) row { id cell; @@ -1804,96 +1821,94 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents) } -- (void)clicked: sender +- (void) clicked: sender { NSArray *sellist = nil; - EMACS_INT seltag; + NSUInteger seltag; + Lisp_Object *selarray; sellist = [sender selectedCells]; + if ([sellist count] < 1) return; seltag = [[sellist objectAtIndex: 0] tag]; - dialog_return = button_values[seltag]; - [NSApp stop:self]; + selarray = (void *) seltag; + dialog_return = selarray[MENU_ITEMS_ITEM_VALUE]; + [NSApp stop: self]; } -- (instancetype)initFromContents: (Lisp_Object)contents isQuestion: (BOOL)isQ +- (instancetype) initWithTitle: (char *) title_string + isQuestion: (BOOL) is_question { - Lisp_Object head; [super init]; - if (CONSP (contents)) - { - head = Fcar (contents); - [self process_dialog: Fcdr (contents)]; - } - else - head = contents; - - if (STRINGP (head)) - [title setStringValue: - [NSString stringWithUTF8String: SSDATA (head)]]; - else if (isQ == YES) - [title setStringValue: @"Question"]; + if (title_string) + [title setStringValue: + [NSString stringWithUTF8String: title_string]]; + else if (is_question) + [title setStringValue: @"Question"]; else - [title setStringValue: @"Information"]; + [title setStringValue: @"Information"]; - { - int i; - NSRect r, s, t; + return self; +} - if (cols == 1 && rows > 1) /* Never told where to split. */ - { - [matrix addColumn]; - for (i = 0; i < rows/2; i++) - { - [matrix putCell: [matrix cellAtRow: (rows+1)/2 column: 0] - atRow: i column: 1]; - [matrix removeRow: (rows+1)/2]; - } - } +- (void) resizeBoundsPriorToDisplay +{ + int i; + NSRect r, s, t; + NSSize csize; - [matrix sizeToFit]; + if (cols == 1 && rows > 1) { - NSSize csize = [matrix cellSize]; - if (csize.width < MINCELLWIDTH) - { - csize.width = MINCELLWIDTH; - [matrix setCellSize: csize]; - [matrix sizeToCells]; - } + [matrix addColumn]; + for (i = 0; i < rows / 2; i++) + { + [matrix putCell: [matrix cellAtRow: (rows + 1) /2 + column: 0] + atRow: i column: 1]; + [matrix removeRow: (rows + 1) / 2]; + } } - [title sizeToFit]; - [command sizeToFit]; + [matrix sizeToFit]; - t = [matrix frame]; - r = [title frame]; - if (r.size.width+r.origin.x > t.size.width+t.origin.x) - { - t.origin.x = r.origin.x; - t.size.width = r.size.width; - } - r = [command frame]; - if (r.size.width+r.origin.x > t.size.width+t.origin.x) - { - t.origin.x = r.origin.x; - t.size.width = r.size.width; - } + csize = [matrix cellSize]; + if (csize.width < MINCELLWIDTH) + { + csize.width = MINCELLWIDTH; + [matrix setCellSize: csize]; + [matrix sizeToCells]; + } - r = [self frame]; - s = [(NSView *)[self contentView] frame]; - r.size.width += t.origin.x+t.size.width +2*SPACER-s.size.width; - r.size.height += t.origin.y+t.size.height+SPACER-s.size.height; - [self setFrame: r display: NO]; - } + [title sizeToFit]; + [command sizeToFit]; - return self; -} + t = [matrix frame]; + r = [title frame]; + if (r.size.width + r.origin.x > t.size.width + t.origin.x) + { + t.origin.x = r.origin.x; + t.size.width = r.size.width; + } + r = [command frame]; + if (r.size.width + r.origin.x > t.size.width + t.origin.x) + { + t.origin.x = r.origin.x; + t.size.width = r.size.width; + } + r = [self frame]; + s = [(NSView *) [self contentView] frame]; + r.size.width += (t.origin.x + t.size.width + + 2 * SPACER - s.size.width); + r.size.height += (t.origin.y + t.size.height + + SPACER - s.size.height); + [self setFrame: r display: NO]; +} - (void)timeout_handler: (NSTimer *)timedEntry { @@ -1911,11 +1926,11 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents) /* We use stop because stopModal/abortModal out of the main loop does not seem to work in 10.6. But as we use stop we must send a real event so the stop is seen and acted upon. */ - [NSApp stop:self]; + [NSApp stop: self]; [NSApp postEvent: nxev atStart: NO]; } -- (Lisp_Object)runDialogAt: (NSPoint)p +- (Lisp_Object) runDialogAt: (NSPoint) p { Lisp_Object ret = Qundefined; @@ -1935,13 +1950,17 @@ ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents) [[NSRunLoop currentRunLoop] addTimer: tmo forMode: NSModalPanelRunLoopMode]; } + timer_fired = NO; dialog_return = Qundefined; [NSApp runModalForWindow: self]; ret = dialog_return; - if (! timer_fired) + + if (!timer_fired) { - if (tmo != nil) [tmo invalidate]; /* Cancels timer. */ + if (tmo != nil) + [tmo invalidate]; /* Cancels timer. */ + break; } } diff --git a/src/nsterm.h b/src/nsterm.h index 1135225e7b1..2c46298a937 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -574,22 +574,32 @@ typedef id instancetype; ========================================================================== */ @interface EmacsDialogPanel : NSPanel - { - NSTextField *command; - NSTextField *title; - NSMatrix *matrix; - int rows, cols; - BOOL timer_fired, window_closed; - Lisp_Object dialog_return; - Lisp_Object *button_values; - } -- (instancetype)initFromContents: (Lisp_Object)menu isQuestion: (BOOL)isQ; -- (void)process_dialog: (Lisp_Object)list; -- (void)addButton: (char *)str value: (int)tag row: (int)row; -- (void)addString: (char *)str row: (int)row; -- (void)addSplit; -- (Lisp_Object)runDialogAt: (NSPoint)p; -- (void)timeout_handler: (NSTimer *)timedEntry; +{ + NSTextField *command; + NSTextField *title; + NSMatrix *matrix; + int rows, cols; + BOOL timer_fired, window_closed; + Lisp_Object dialog_return; +} + +- (instancetype) initWithTitle: (char *) title_str + isQuestion: (BOOL) is_question; +- (void) processMenuItems: (Lisp_Object) menu_items + used: (ptrdiff_t) menu_items_used + withErrorOutput: (const char **) error_name; + +- (void) addButton: (char *) str + value: (NSInteger) tag + row: (int) row + enable: (BOOL) enable; +- (void) addString: (char *) str + row: (int) row; +- (void) addSplit; +- (void) resizeBoundsPriorToDisplay; + +- (Lisp_Object) runDialogAt: (NSPoint) p; +- (void) timeout_handler: (NSTimer *) timedEntry; @end #ifdef NS_IMPL_COCOA -- 2.39.2