summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-06-17 22:19:33 +0200
committerBram Moolenaar <Bram@vim.org>2019-06-17 22:19:33 +0200
commit9b283523f2f75b45feef902b8713808e883d9c19 (patch)
tree83a7c31221221362b997e6938381d4de61db52d3 /src
parent394c5d8870b15150fc91a4c058dc571fd5eaa97e (diff)
downloadvim-git-9b283523f2f75b45feef902b8713808e883d9c19.tar.gz
patch 8.1.1565: MS-Windows: no sound supportv8.1.1565
Problem: MS-Windows: no sound support. Solution: Add sound support for MS-Windows. (Yasuhiro Matsumoto, Ken Takata, closes #4522)
Diffstat (limited to 'src')
-rw-r--r--src/Make_cyg_ming.mak19
-rw-r--r--src/Make_mvc.mak32
-rw-r--r--src/sound.c196
-rw-r--r--src/testdir/test_sound.vim4
-rw-r--r--src/version.c2
5 files changed, 239 insertions, 14 deletions
diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak
index f47981216..3c0c92ba1 100644
--- a/src/Make_cyg_ming.mak
+++ b/src/Make_cyg_ming.mak
@@ -106,6 +106,13 @@ else
TERMINAL=no
endif
+# Set to yes to enable sound support.
+ifneq ($(findstring $(FEATURES),BIG HUGE),)
+SOUND=yes
+else
+SOUND=no
+endif
+
ifndef CTAGS
# this assumes ctags is Exuberant ctags
CTAGS = ctags -I INIT+ --fields=+S
@@ -633,6 +640,10 @@ TERM_DEPS = \
libvterm/src/vterm_internal.h
endif
+ifeq ($(SOUND),yes)
+DEFINES += -DFEAT_SOUND
+endif
+
# DirectWrite (DirectX)
ifeq ($(DIRECTX),yes)
# Only allow DirectWrite for a GUI build.
@@ -849,6 +860,10 @@ OBJ += $(OUTDIR)/terminal.o \
$(OUTDIR)/vterm.o
endif
+ifeq ($(SOUND),yes)
+OBJ += $(OUTDIR)/sound.o
+endif
+
# Include xdiff
OBJ += $(OUTDIR)/xdiffi.o \
$(OUTDIR)/xemit.o \
@@ -957,6 +972,10 @@ CFLAGS += -I$(ICONV)
DEFINES+=-DDYNAMIC_ICONV
endif
+ifeq (yes, $(SOUND))
+LIB += -lwinmm
+endif
+
ifeq (yes, $(USE_STDCPLUS))
LINK = $(CXX)
ifeq (yes, $(STATIC_STDCPLUS))
diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak
index c6f9b25a0..54740d7f8 100644
--- a/src/Make_mvc.mak
+++ b/src/Make_mvc.mak
@@ -38,7 +38,9 @@
# is yes)
# Global IME support: GIME=yes (requires GUI=yes)
#
-# Terminal support: TERMINAL=yes (default is yes)
+# Terminal support: TERMINAL=yes (default is yes)
+#
+# Sound support: SOUND=yes (default is yes)
#
# DLL support (EXPERIMENTAL): VIMDLL=yes (default is no)
# Creates vim{32,64}.dll, and stub gvim.exe and vim.exe.
@@ -381,6 +383,14 @@ TERM_DEPS = \
libvterm/src/vterm_internal.h
!endif
+!ifndef SOUND
+! if "$(FEATURES)"=="HUGE" || "$(FEATURES)"=="BIG"
+SOUND = yes
+! else
+SOUND = no
+! endif
+!endif
+
!ifndef NETBEANS
NETBEANS = $(GUI)
!endif
@@ -454,6 +464,13 @@ XPM_INC = -I $(XPM)\include -I $(XPM)\..\include
! endif
!endif # GUI
+!if "$(SOUND)" == "yes"
+SOUND_PRO = proto/sound.pro
+SOUND_OBJ = $(OBJDIR)/sound.obj
+SOUND_DEFS = -DFEAT_SOUND
+SOUND_LIB = winmm.lib
+!endif
+
!if "$(CHANNEL)" == "yes"
CHANNEL_PRO = proto/channel.pro
CHANNEL_OBJ = $(OBJDIR)/channel.obj
@@ -494,7 +511,7 @@ WINVER = 0x0501
#VIMRUNTIMEDIR = somewhere
CFLAGS = -c /W3 /nologo $(CVARS) -I. -Iproto -DHAVE_PATHDEF -DWIN32 \
- $(CSCOPE_DEFS) $(TERM_DEFS) $(NETBEANS_DEFS) $(CHANNEL_DEFS) \
+ $(CSCOPE_DEFS) $(TERM_DEFS) $(SOUND_DEFS) $(NETBEANS_DEFS) $(CHANNEL_DEFS) \
$(NBDEBUG_DEFS) $(XPM_DEFS) \
$(DEFINES) -DWINVER=$(WINVER) -D_WIN32_WINNT=$(WINVER)
@@ -1217,7 +1234,7 @@ conflags = $(conflags) /map /mapinfo:lines
LINKARGS1 = $(linkdebug) $(conflags)
LINKARGS2 = $(CON_LIB) $(GUI_LIB) $(NODEFAULTLIB) $(LIBC) $(OLE_LIB) user32.lib \
$(LUA_LIB) $(MZSCHEME_LIB) $(PERL_LIB) $(PYTHON_LIB) $(PYTHON3_LIB) $(RUBY_LIB) \
- $(TCL_LIB) $(NETBEANS_LIB) $(XPM_LIB) $(LINK_PDB)
+ $(TCL_LIB) $(SOUND_LIB) $(NETBEANS_LIB) $(XPM_LIB) $(LINK_PDB)
# Report link time code generation progress if used.
!ifdef NODEBUG
@@ -1253,12 +1270,12 @@ all: $(MAIN_TARGET) \
$(VIMDLLBASE).dll: $(OUTDIR) $(OBJ) $(XDIFF_OBJ) $(GUI_OBJ) $(CUI_OBJ) $(OLE_OBJ) $(OLE_IDL) $(MZSCHEME_OBJ) \
$(LUA_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(PYTHON3_OBJ) $(RUBY_OBJ) $(TCL_OBJ) \
- $(CSCOPE_OBJ) $(TERM_OBJ) $(NETBEANS_OBJ) $(CHANNEL_OBJ) $(XPM_OBJ) \
+ $(CSCOPE_OBJ) $(TERM_OBJ) $(SOUND_OBJ) $(NETBEANS_OBJ) $(CHANNEL_OBJ) $(XPM_OBJ) \
version.c version.h
$(CC) $(CFLAGS_OUTDIR) version.c
$(link) $(LINKARGS1) /dll -out:$(VIMDLLBASE).dll $(OBJ) $(XDIFF_OBJ) $(GUI_OBJ) $(CUI_OBJ) $(OLE_OBJ) \
$(LUA_OBJ) $(MZSCHEME_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(PYTHON3_OBJ) $(RUBY_OBJ) \
- $(TCL_OBJ) $(CSCOPE_OBJ) $(TERM_OBJ) $(NETBEANS_OBJ) $(CHANNEL_OBJ) \
+ $(TCL_OBJ) $(CSCOPE_OBJ) $(TERM_OBJ) $(SOUND_OBJ) $(NETBEANS_OBJ) $(CHANNEL_OBJ) \
$(XPM_OBJ) $(OUTDIR)\version.obj $(LINKARGS2)
$(GVIM).exe: $(OUTDIR) $(EXEOBJG) $(VIMDLLBASE).dll
@@ -1273,12 +1290,12 @@ $(VIM).exe: $(OUTDIR) $(EXEOBJC) $(VIMDLLBASE).dll
$(VIM).exe: $(OUTDIR) $(OBJ) $(XDIFF_OBJ) $(GUI_OBJ) $(CUI_OBJ) $(OLE_OBJ) $(OLE_IDL) $(MZSCHEME_OBJ) \
$(LUA_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(PYTHON3_OBJ) $(RUBY_OBJ) $(TCL_OBJ) \
- $(CSCOPE_OBJ) $(TERM_OBJ) $(NETBEANS_OBJ) $(CHANNEL_OBJ) $(XPM_OBJ) \
+ $(CSCOPE_OBJ) $(TERM_OBJ) $(SOUND_OBJ) $(NETBEANS_OBJ) $(CHANNEL_OBJ) $(XPM_OBJ) \
version.c version.h
$(CC) $(CFLAGS_OUTDIR) version.c
$(link) $(LINKARGS1) /subsystem:$(SUBSYSTEM) -out:$(VIM).exe $(OBJ) $(XDIFF_OBJ) $(GUI_OBJ) $(CUI_OBJ) $(OLE_OBJ) \
$(LUA_OBJ) $(MZSCHEME_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(PYTHON3_OBJ) $(RUBY_OBJ) \
- $(TCL_OBJ) $(CSCOPE_OBJ) $(TERM_OBJ) $(NETBEANS_OBJ) $(CHANNEL_OBJ) \
+ $(TCL_OBJ) $(CSCOPE_OBJ) $(TERM_OBJ) $(SOUND_OBJ) $(NETBEANS_OBJ) $(CHANNEL_OBJ) \
$(XPM_OBJ) $(OUTDIR)\version.obj $(LINKARGS2)
if exist $(VIM).exe.manifest mt.exe -nologo -manifest $(VIM).exe.manifest -updateresource:$(VIM).exe;1
@@ -1766,6 +1783,7 @@ proto.h: \
proto/usercmd.pro \
proto/userfunc.pro \
proto/window.pro \
+ $(SOUND_PRO) \
$(NETBEANS_PRO) \
$(CHANNEL_PRO)
diff --git a/src/sound.c b/src/sound.c
index e28ccff90..70f4425e9 100644
--- a/src/sound.c
+++ b/src/sound.c
@@ -13,17 +13,18 @@
#include "vim.h"
-#if (defined(FEAT_SOUND) && defined(HAVE_CANBERRA)) || defined(PROTO)
-
-#include <canberra.h>
+#if defined(FEAT_SOUND) || defined(PROTO)
static long sound_id = 0;
-static ca_context *context = NULL;
typedef struct soundcb_S soundcb_T;
struct soundcb_S {
callback_T snd_callback;
+#ifdef MSWIN
+ MCIDEVICEID snd_device_id;
+ long snd_id;
+#endif
soundcb_T *snd_next;
};
@@ -75,6 +76,15 @@ delete_sound_callback(soundcb_T *soundcb)
}
}
+#if defined(HAVE_CANBERRA) || defined(PROTO)
+
+/*
+ * Sound implementation for Linux/Unix/Mac using libcanberra.
+ */
+# include <canberra.h>
+
+static ca_context *context = NULL;
+
static void
sound_callback(
ca_context *c UNUSED,
@@ -188,7 +198,7 @@ f_sound_clear(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
}
}
-#if defined(EXITFREE) || defined(PROTO)
+# if defined(EXITFREE) || defined(PROTO)
void
sound_free(void)
{
@@ -197,6 +207,178 @@ sound_free(void)
while (first_callback != NULL)
delete_sound_callback(first_callback);
}
-#endif
+# endif
+
+#elif defined(MSWIN)
+
+/*
+ * Sound implementation for MS-Windows.
+ */
+
+static HWND g_hWndSound = NULL;
+
+ static LRESULT CALLBACK
+sound_wndproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ soundcb_T *p;
+
+ switch (message)
+ {
+ case MM_MCINOTIFY:
+ for (p = first_callback; p != NULL; p = p->snd_next)
+ if (p->snd_device_id == (MCIDEVICEID) lParam)
+ {
+ typval_T argv[3];
+ typval_T rettv;
+ int dummy;
+ char buf[32];
+
+ vim_snprintf(buf, sizeof(buf), "close sound%06ld",
+ p->snd_id);
+ mciSendString(buf, NULL, 0, 0);
+
+ argv[0].v_type = VAR_NUMBER;
+ argv[0].vval.v_number = p->snd_id;
+ argv[1].v_type = VAR_NUMBER;
+ argv[1].vval.v_number =
+ wParam == MCI_NOTIFY_SUCCESSFUL ? 0
+ : wParam == MCI_NOTIFY_ABORTED ? 1 : 2;
+ argv[2].v_type = VAR_UNKNOWN;
+
+ call_callback(&p->snd_callback, -1,
+ &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
+ clear_tv(&rettv);
+
+ delete_sound_callback(p);
+ redraw_after_callback(TRUE);
+
+ }
+ break;
+ }
+
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+ static HWND
+sound_window()
+{
+ if (g_hWndSound == NULL)
+ {
+ LPCSTR clazz = "VimSound";
+ WNDCLASS wndclass = {
+ 0, sound_wndproc, 0, 0, g_hinst, NULL, 0, 0, NULL, clazz };
+ RegisterClass(&wndclass);
+ g_hWndSound = CreateWindow(clazz, NULL, 0, 0, 0, 0, 0,
+ HWND_MESSAGE, NULL, g_hinst, NULL);
+ }
+
+ return g_hWndSound;
+}
+
+ void
+f_sound_playevent(typval_T *argvars, typval_T *rettv)
+{
+ WCHAR *wp;
+
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = 0;
+
+ wp = enc_to_utf16(tv_get_string(&argvars[0]), NULL);
+ if (wp == NULL)
+ return;
+
+ PlaySoundW(wp, NULL, SND_ASYNC | SND_ALIAS);
+ free(wp);
+
+ rettv->vval.v_number = ++sound_id;
+}
+
+ void
+f_sound_playfile(typval_T *argvars, typval_T *rettv)
+{
+ long newid = sound_id + 1;
+ size_t len;
+ char_u *p, *esc;
+ WCHAR *wp;
+ soundcb_T *soundcb;
+ char buf[32];
+ MCIERROR err;
+
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = 0;
+
+ esc = vim_strsave_shellescape(tv_get_string(&argvars[0]), FALSE, FALSE);
+
+ len = STRLEN(esc) + 5 + 18 + 1;
+ p = alloc(len);
+ if (p == NULL)
+ {
+ free(esc);
+ return;
+ }
+ vim_snprintf((char *)p, len, "open %s alias sound%06ld", esc, newid);
+ free(esc);
+
+ wp = enc_to_utf16((char_u *)p, NULL);
+ free(p);
+ if (wp == NULL)
+ return;
+
+ err = mciSendStringW(wp, NULL, 0, sound_window());
+ free(wp);
+ if (err != 0)
+ return;
+
+ vim_snprintf(buf, sizeof(buf), "play sound%06ld notify", newid);
+ err = mciSendString(buf, NULL, 0, sound_window());
+ if (err != 0)
+ goto failure;
+
+ sound_id = newid;
+ rettv->vval.v_number = sound_id;
+
+ soundcb = get_sound_callback(&argvars[1]);
+ if (soundcb != NULL)
+ {
+ vim_snprintf(buf, sizeof(buf), "sound%06ld", newid);
+ soundcb->snd_id = newid;
+ soundcb->snd_device_id = mciGetDeviceID(buf);
+ }
+ return;
+
+failure:
+ vim_snprintf(buf, sizeof(buf), "close sound%06ld", newid);
+ mciSendString(buf, NULL, 0, NULL);
+}
+
+ void
+f_sound_stop(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ long id = tv_get_number(&argvars[0]);
+ char buf[32];
+
+ vim_snprintf(buf, sizeof(buf), "stop sound%06ld", id);
+ mciSendString(buf, NULL, 0, NULL);
+}
+
+ void
+f_sound_clear(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+ PlaySound(NULL, NULL, 0);
+ mciSendString("close all", NULL, 0, NULL);
+}
+
+# if defined(EXITFREE)
+ void
+sound_free(void)
+{
+ CloseWindow(g_hWndSound);
+
+ while (first_callback != NULL)
+ delete_sound_callback(first_callback);
+}
+# endif
+
+#endif // MSWIN
-#endif // FEAT_SOUND && HAVE_CANBERRA
+#endif // FEAT_SOUND
diff --git a/src/testdir/test_sound.vim b/src/testdir/test_sound.vim
index 1e2c455e6..e74aa132d 100644
--- a/src/testdir/test_sound.vim
+++ b/src/testdir/test_sound.vim
@@ -10,6 +10,10 @@ func PlayCallback(id, result)
endfunc
func Test_play_event()
+ if has('win32')
+ throw 'Skipped: Playing event with callback is not supported on Windows'
+ endif
+
let id = sound_playevent('bell', 'PlayCallback')
if id == 0
throw 'Skipped: bell event not available'
diff --git a/src/version.c b/src/version.c
index 5831e336d..ee07b9619 100644
--- a/src/version.c
+++ b/src/version.c
@@ -778,6 +778,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1565,
+/**/
1564,
/**/
1563,