Skip to content

Commit 50dd037

Browse files
committed
Implement getcellpixels() for MacVim
Don't use `gui.char_width` / `char_height` unlike the other GVim implementations. Those are used for deriving screen pixel sizes and MacVim has been hard-coding them to 1 for simplicity since the actual GUI functionality is handled out of the Vim process anyway. Changing those values would require some refactoring. Instead, just use a new variable to store them. Note that there is a delay with this method, as we only update Vim's knowledge of cell size after MacVim has received the font change message. This means if a user wants to immediately query getcellpixels() in vimrc or after changing guifont this will not work. This is a deliberate design choice to avoid having to add synchronous state query APIs to MacVim, but it's possible to change it in the future. The handling of this message did get placed in `processInput:` which means it will be picked up whenever we sleep or process messages in Vim, instead of only when waiting for keys (where most of other MacVim messages are handled in `processInputQueue`). Related: vim/vim#16004
1 parent e2f0b24 commit 50dd037

10 files changed

+88
-1
lines changed

src/MacVim/MMBackend.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
#endif
5858
}
5959

60+
@property (nonatomic, readonly) NSSize cellSize;
61+
6062
+ (MMBackend *)sharedInstance;
6163

6264
- (void)setBackgroundColor:(int)color;

src/MacVim/MMBackend.m

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,6 +1328,9 @@ - (oneway void)processInput:(int)msgid data:(in bycopy NSData *)data
13281328
// modified files when we get here.
13291329
isTerminating = YES;
13301330
getout(0);
1331+
} else if (UpdateCellSizeMsgID == msgid) {
1332+
// Immediately handle simple state updates to they can be reflected in Vim.
1333+
[self handleCellSize:data];
13311334
} else {
13321335
// First remove previous instances of this message from the input
13331336
// queue, else the input queue may fill up as a result of Vim not being
@@ -2705,6 +2708,18 @@ - (void)handleSetFont:(NSData *)data
27052708
CONVERT_FROM_UTF8_FREE(s);
27062709
}
27072710

2711+
- (void)handleCellSize:(NSData *)data
2712+
{
2713+
if (!data) return;
2714+
2715+
const void *bytes = [data bytes];
2716+
2717+
// Don't use gui.char_width/height because for simplicity we set those to
2718+
// 1. We store the cell size separately (it's only used for
2719+
// getcellpixels()).
2720+
memcpy(&_cellSize, bytes, sizeof(NSSize));
2721+
}
2722+
27082723
- (void)handleDropFiles:(NSData *)data
27092724
{
27102725
// TODO: Get rid of this method; instead use Vim script directly. At the

src/MacVim/MMVimController.m

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,14 @@ - (void)handleMessage:(int)msgid data:(NSData *)data
10121012
}
10131013

10141014
[windowController setFont:font];
1015+
1016+
// Notify Vim of updated cell size for getcellpixels(). Note that
1017+
// this is asynchronous, which means getcellpixels() will not be
1018+
// immediately reflected after setting guifont.
1019+
NSSize cellsize = windowController.vimView.textView.cellSize;
1020+
[self sendMessage:UpdateCellSizeMsgID
1021+
data:[NSData dataWithBytes:&cellsize length:sizeof(cellsize)]];
1022+
10151023
[name release];
10161024
}
10171025
break;

src/MacVim/MacVim.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ extern const char * const MMVimMsgIDStrings[];
300300
MSG(ScrollbarEventMsgID) \
301301
MSG(SetFontMsgID) \
302302
MSG(SetWideFontMsgID) \
303+
MSG(UpdateCellSizeMsgID) \
303304
MSG(VimShouldCloseMsgID) \
304305
MSG(SetDefaultColorsMsgID) \
305306
MSG(SetTablineColorsMsgID) \

src/MacVim/gui_macvim.m

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,9 @@
247247
// correspondence (assuming all characters have the same dimensions).
248248
gui.scrollbar_width = gui.scrollbar_height = 0;
249249

250+
// For simplicity we just set char width/height to 1 as the GUI is
251+
// decoupled from Vim anyway so Vim doesn't need to know the accurate
252+
// pixel sizes.
250253
gui.char_height = 1;
251254
gui.char_width = 1;
252255
gui.char_ascent = 0;
@@ -1664,6 +1667,14 @@
16641667
return OK;
16651668
}
16661669

1670+
void
1671+
gui_mch_calc_cell_size(struct cellsize *cs_out)
1672+
{
1673+
NSSize cellsize = [MMBackend sharedInstance].cellSize;
1674+
cs_out->cs_xpixel = round(cellsize.width);
1675+
cs_out->cs_ypixel = round(cellsize.height);
1676+
}
1677+
16671678

16681679
void
16691680
gui_mch_beep(void)

src/evalfunc.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5425,8 +5425,15 @@ f_getcellpixels(typval_T *argvars UNUSED, typval_T *rettv)
54255425
if (gui.in_use)
54265426
{
54275427
// success pixel size and no gui.
5428+
#ifdef FEAT_GUI_MACVIM
5429+
struct cellsize cs;
5430+
gui_mch_calc_cell_size(&cs);
5431+
list_append_number(rettv->vval.v_list, (varnumber_T)cs.cs_xpixel);
5432+
list_append_number(rettv->vval.v_list, (varnumber_T)cs.cs_ypixel);
5433+
#else
54285434
list_append_number(rettv->vval.v_list, (varnumber_T)gui.char_width);
54295435
list_append_number(rettv->vval.v_list, (varnumber_T)gui.char_height);
5436+
#endif
54305437
}
54315438
else
54325439
#endif

src/os_unix.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4442,7 +4442,16 @@ mch_report_winsize(int fd, int rows, int cols)
44424442

44434443
// calcurate and set tty pixel size
44444444
struct cellsize cs;
4445-
mch_calc_cell_size(&cs);
4445+
#if defined(FEAT_GUI) && defined(FEAT_GUI_MACVIM)
4446+
if (gui.in_use)
4447+
{
4448+
gui_mch_calc_cell_size(&cs);
4449+
}
4450+
else
4451+
#endif
4452+
{
4453+
mch_calc_cell_size(&cs);
4454+
}
44464455

44474456
if (cs.cs_xpixel == -1)
44484457
{

src/proto/gui_macvim.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ void gui_mch_set_font(GuiFont font);
4343
void gui_mch_expand_font(optexpand_T *args, void *param, int (*add_match)(char_u *val));
4444
int gui_mch_adjust_charheight(void);
4545
int gui_mch_adjust_charwidth(void);
46+
void gui_mch_calc_cell_size(struct cellsize *cs_out);
4647
void gui_mch_beep(void);
4748
char_u *gui_mch_browse(int saving, char_u *title, char_u *dflt, char_u *ext, char_u *initdir, char_u *filter);
4849
char_u *gui_mch_browsedir(char_u *title, char_u *initdir);

src/terminal.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4831,8 +4831,15 @@ parse_csi(
48314831
#ifdef FEAT_GUI
48324832
if (gui.in_use)
48334833
{
4834+
#ifdef FEAT_GUI_MACVIM
4835+
struct cellsize cs;
4836+
gui_mch_calc_cell_size(&cs);
4837+
x += wp->w_wincol * cs.cs_xpixel;
4838+
y += W_WINROW(wp) * cs.cs_ypixel;
4839+
#else
48344840
x += wp->w_wincol * gui.char_width;
48354841
y += W_WINROW(wp) * gui.char_height;
4842+
#endif
48364843
}
48374844
else
48384845
#endif

src/testdir/test_functions.vim

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4338,6 +4338,32 @@ func Test_getcellpixels_gui()
43384338
endif
43394339
endfunc
43404340

4341+
" Test for getcellpixels() for MacVim
4342+
func Test_getcellpixels_macvim()
4343+
CheckGui
4344+
CheckRunVimInTerminal
4345+
if has("gui_running") && has('gui_macvim')
4346+
" MacVim works asynchronously and getcellpixels() does not immediately
4347+
" work either at launch or after guifont has been changed. It's a
4348+
" deliberate design decision. Right now the caller has to wait for MacVim
4349+
" to update the state before getcellpixels() will reflect the correct
4350+
" value, hence the need for multiple wait's here.
4351+
call WaitForAssert({-> assert_notequal(0, getcellpixels()[0], 'Uninitialized getcellpixels')})
4352+
call assert_equal([7, 13], getcellpixels()) " Default font is Menlo:h11
4353+
set guifont=Menlo:h13
4354+
call WaitForAssert({-> assert_equal([8, 15], getcellpixels())})
4355+
4356+
" Also test hosting a terminal and have that be updated
4357+
let buf = RunVimInTerminal('', #{})
4358+
call term_sendkeys(buf, ":redi @\"\<CR>")
4359+
call term_sendkeys(buf, ":echo getcellpixels()\<CR>")
4360+
call term_sendkeys(buf, ":redi END\<CR>")
4361+
call term_sendkeys(buf, "P")
4362+
call WaitForAssert({-> assert_equal(string(getcellpixels()), term_getline(buf, 3))}, 1000)
4363+
call StopVimInTerminal(buf)
4364+
endif
4365+
endfunc
4366+
43414367
func Str2Blob(s)
43424368
return list2blob(str2list(a:s))
43434369
endfunc

0 commit comments

Comments
 (0)